We save positional information in the main utility table. Not only
+can we store much more information in but it's also
+more efficient.
+--ldx]]--
+
+local concat, format = table.concat, string.format
+local texprint, ctxcatcodes = tex.print, tex.ctxcatcodes
+local lpegmatch = lpeg.match
+
+jobpositions = jobpositions or { }
+jobpositions.collected = jobpositions.collected or { }
+jobpositions.tobesaved = jobpositions.tobesaved or { }
+
+-- these are global since they are used often at the tex end
+
+-- \the\dimexpr #2\ifnum\positionanchormode=\plusone-\MPx\pageanchor\fi\relax
+-- \the\dimexpr #3\ifnum\positionanchormode=\plusone-\MPy\pageanchor\fi\relax
+
+ptbs, pcol = jobpositions.tobesaved, jobpositions.collected -- global
+
+local dx, dy = "0pt", "0pt"
+
+local function initializer()
+ ptbs, pcol = jobpositions.tobesaved, jobpositions.collected
+ local p = pcol["page:0"] -- page:1
+ if p then
+-- to be checked !
+--~ dx, dy = p[2] or "0pt", p[3] or "0pt"
+ end
+end
+
+job.register('jobpositions.collected', jobpositions.tobesaved, initializer)
+
+function jobpositions.copy(target,source)
+ jobpositions.collected[target] = jobpositions.collected[source] or ptbs[source]
+end
+
+function jobpositions.replace(name,...)
+ jobpositions.collected[name] = {...}
+end
+
+function jobpositions.doifelse(name)
+ commands.testcase(jobpositions.collected[name] or ptbs[name])
+end
+
+function jobpositions.MPp(id) local jpi = pcol[id] or ptbs[id] texprint(ctxcatcodes,(jpi and jpi[1]) or '0' ) end
+function jobpositions.MPx(id) local jpi = pcol[id] or ptbs[id] texprint(ctxcatcodes,(jpi and jpi[2]) or '0pt') end
+function jobpositions.MPy(id) local jpi = pcol[id] or ptbs[id] texprint(ctxcatcodes,(jpi and jpi[3]) or '0pt') end
+function jobpositions.MPw(id) local jpi = pcol[id] or ptbs[id] texprint(ctxcatcodes,(jpi and jpi[4]) or '0pt') end
+function jobpositions.MPh(id) local jpi = pcol[id] or ptbs[id] texprint(ctxcatcodes,(jpi and jpi[5]) or '0pt') end
+function jobpositions.MPd(id) local jpi = pcol[id] or ptbs[id] texprint(ctxcatcodes,(jpi and jpi[6]) or '0pt') end
+
+
+function jobpositions.MPx(id)
+ local jpi = pcol[id] or ptbs[id]
+ local x = jpi and jpi[2]
+ if x then
+ texprint(ctxcatcodes,format('\\the\\dimexpr%s-%s\\relax',x,dx)) -- no space after dimexpr !
+ else
+ texprint(ctxcatcodes,'0pt')
+ end
+end
+
+function jobpositions.MPy(id)
+ local jpi = pcol[id] or ptbs[id]
+ local y = jpi and jpi[3]
+ if y then
+ texprint(ctxcatcodes,format('\\the\\dimexpr%s-%s\\relax',y,dy)) -- no space after dimexpr !
+ else
+ texprint(ctxcatcodes,'0pt')
+ end
+end
+
+-- the following are only for MP so there we can leave out the pt
+
+-- can be writes and no format needed any more
+
+function jobpositions.MPxy(id)
+ local jpi = pcol[id] or ptbs[id]
+ if jpi then
+ texprint(ctxcatcodes,format('(%s-%s,%s-%s)',jpi[2],dx,jpi[3],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'-',dx,',',jpi[3],'-',dy,')')
+ else
+ texprint(ctxcatcodes,'(0,0)')
+ end
+end
+
+function jobpositions.MPll(id)
+ local jpi = pcol[id] or ptbs[id]
+ if jpi then
+ texprint(ctxcatcodes,format('(%s-%s,%s-%s-%s)',jpi[2],dx,jpi[3],jpi[6],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'-',dx,',',jpi[3],'-',jpi[6],'-',dy,')')
+ else
+ texprint(ctxcatcodes,'(0,0)')
+ end
+end
+
+function jobpositions.MPlr(id)
+ local jpi = pcol[id] or ptbs[id]
+ if jpi then
+ texprint(ctxcatcodes,format('(%s+%s-%s,%s-%s-%s)',jpi[2],jpi[4],dx,jpi[3],jpi[6],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'+',jpi[4],'-',dx,',',jpi[3],'-',jpi[6],'-',dy,')')
+ else
+ texprint(ctxcatcodes,'(0,0)')
+ end
+end
+
+function jobpositions.MPur(id)
+ local jpi = pcol[id] or ptbs[id]
+ if jpi then
+ texprint(ctxcatcodes,format('(%s+%s-%s,%s+%s-%s)',jpi[2],jpi[4],dx,jpi[3],jpi[5],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'+',jpi[4],'-',dx,',',jpi[3],'+',jpi[5],'-',dy,')')
+ else
+ texprint(ctxcatcodes,'(0,0)')
+ end
+end
+
+function jobpositions.MPul(id)
+ local jpi = pcol[id] or ptbs[id]
+ if jpi then
+ texprint(ctxcatcodes,format('(%s-%s,%s+%s-%s)',jpi[2],dx,jpi[3],jpi[5],dy))
+--~ texprint(ctxcatcodes,'(',jpi[2],'-',dx,',',jpi[3],'+',jpi[5],'-',dy,')')
+ else
+ texprint(ctxcatcodes,'(0,0)')
+ end
+end
+
+function jobpositions.MPpos(id)
+ local jpi = pcol[id] or ptbs[id]
+ if jpi then
+ texprint(ctxcatcodes,concat(jpi,',',1,6))
+ else
+ texprint(ctxcatcodes,'0,0,0,0,0,0')
+ end
+end
+
+local splitter = lpeg.Ct(lpeg.splitat(","))
+
+function jobpositions.MPplus(id,n,default)
+ local jpi = pcol[id] or ptbs[id]
+ if not jpi then
+ texprint(ctxcatcodes,default)
+ else
+ local split = jpi[0]
+ if not split then
+ split = lpegmatch(splitter,jpi[7])
+ jpi[0] = split
+ end
+ texprint(ctxcatcodes,split[n] or default)
+ end
+end
+
+function jobpositions.MPrest(id,default)
+ local jpi = pcol[id] or ptbs[id]
+ -- texprint(ctxcatcodes,(jpi and jpi[7] and concat(jpi,",",7,#jpi)) or default)
+ texprint(ctxcatcodes,(jpi and jpi[7]) or default)
+end
diff --git a/tex/context/base/anch-pos.mkii b/tex/context/base/anch-pos.mkii
new file mode 100644
index 000000000..589c4aa26
--- /dev/null
+++ b/tex/context/base/anch-pos.mkii
@@ -0,0 +1,877 @@
+%D \module
+%D [ file=anch-pos,
+%D version=1999.08.01,
+%D title=\CONTEXT\ Anchoring Macros,
+%D subtitle=Positioning 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.
+
+% needs a cleanup, things may change; we also need to move the mp
+% related code to meta-pos
+
+% shorter tags, ..:achtergrond:.. etc in pos actions
+
+% dubbele text- * pos's eruit
+
+% class pos -> als gelijk aan vorige, dan niet niet definieren
+% en erven, maw:
+%
+% 1 -> opslaan
+% 2 -> undef, dus == prev
+% 3 -> undef, dus == prev
+% 4 -> opslaan
+
+\writestatus{loading}{ConTeXt Anchoring Macros / Positioning}
+
+% todo: topskip als optie voor eerste regel achtergrond
+% todo: build pos layers on top of layers
+% todo: positionlayer pos van text-1 etc delen
+
+%D Although \TEX\ has a rather powerful channel to the outside
+%D world, called \type {\special}, real communication with
+%D other programs is complicated by the fact that no positional
+%D information is available. Mid 1999, I discussed this with
+%D \THANH, the author of \PDFTEX, and after some experiments,
+%D \PDFTEX\ was extended with a simple but effective mechanism,
+%D that provided positional information. The interesting
+%D thought is that, although \TEX\ is frozen, similar
+%D functionality could have been achieved with \type
+%D {\specials} and an additional \DVI\ postprocessor.
+%D
+%D Since we want to be as compatible as can be, \CONTEXT\ will
+%D support both methods, although the development is primarily
+%D driven by the \PDFTEX\ way of doing things. Since the
+%D mechanism is basically not limited to one application, for
+%D the moment we stick to building the functionality around one
+%D \CONTEXT\ special command, but at the same time we keep our
+%D eyes open for extensions in other directions.
+%D
+%D A question that may arise when one reads this module, is to
+%D what extend these macros are generic, in the sense that they
+%D could be collected in a support module instead of a core
+%D module. Since the mechanism described here will closely
+%D cooperate with the \METAPOST\ support built in \CONTEXT,
+%D which in turn will be tightly integrated with the \CONTEXT\
+%D overlay mechanisms, I decided to write a core module instead
+%D of a support one. This makes even more sense, when one takes
+%D into account that this kind of support depends on special
+%D drivers.
+
+\unprotect
+
+%D The first application of positional information was embedded
+%D graphics. Since we are interacting with text, it made sense
+%D to take the current line height and depth into account too.
+%D This is why we have two basic position macros: one for
+%D simple positions, and one for boxes.
+%D
+%D We could have sticked to one special, and actually did so in
+%D earlier experiments, but for convenience, as well for
+%D clearness, we now have two alternatives. This approach will
+%D save us quite some bytes when storing large quantities of
+%D positional information. We save as less information as
+%D needed, that is, we save no dimensions, in a \METAPOST\
+%D friendly way.
+%D
+%D The three specials involved are:
+%D
+%D \starttyping
+%D \dosetposition {identifier}
+%D \dosetpositionwhd {identifier} {width} {height} {depth}
+%D \dosetpositionplus {identifier} {width} {height} {depth} {list}
+%D \dosetpositionpapersize {width} {height}
+%D \stoptyping
+
+\newbox\positionbox
+\newif \ifpositioning
+
+\def\POSprefix{POS::}
+
+\def\setpospxy#1#2#3#4%
+ {\@EA\xdef\csname\POSprefix#1\endcsname
+ {\number#2,%
+ \the\dimexpr#3\ifnum\positionanchormode=\plusone-\MPx\pageanchor\fi\relax,%
+ \the\dimexpr#4\ifnum\positionanchormode=\plusone-\MPy\pageanchor\fi\relax}}
+
+\def\setpospxywhd#1#2#3#4#5#6#7%
+ {\@EA\xdef\csname\POSprefix#1\endcsname
+ {\number#2,%
+ \the\dimexpr#3\ifnum\positionanchormode=\plusone-\MPx\pageanchor\fi\relax,%
+ \the\dimexpr#4\ifnum\positionanchormode=\plusone-\MPy\pageanchor\fi\relax,%
+ \the\dimexpr#5\relax,%
+ \the\dimexpr#6\relax,%
+ \the\dimexpr#7\relax}}
+
+\def\setpospxyplus#1#2#3#4#5#6#7#8%
+ {\@EA\xdef\csname\POSprefix#1\endcsname
+ {\number#2,%
+ \the\dimexpr#3\ifnum\positionanchormode=\plusone-\MPx\pageanchor\fi\relax,%
+ \the\dimexpr#4\ifnum\positionanchormode=\plusone-\MPy\pageanchor\fi\relax,%
+ \the\dimexpr#5\relax,%
+ \the\dimexpr#6\relax,%
+ \the\dimexpr#7\relax,%
+ #8}}
+
+%D This is real tricky! The page anchor is applied to the
+%D page box and therefore flushed first. So, when present, it
+%D is applied to all positions except itself.
+
+\chardef\positionanchormode=0 % don't relocate page origin
+\chardef\positionanchormode=1 % relocate page origin once
+
+%D The core set macros.
+
+\def\pxypos {\pospxy} % obsolete
+\def\pxyposwhd {\pospxywhd} % obsolete
+\def\pxyposplus{\pospxyplus} % obsolete
+
+\def\resetpositions
+ {\let\pospxy \gobblefourarguments
+ \let\pospxywhd \gobblesevenarguments
+ \let\pospxyplus\gobbleeightarguments}
+
+\def\setpositions
+ {\let\pospxy \setpospxy
+ \let\pospxywhd \setpospxywhd
+ \let\pospxyplus\setpospxyplus}
+
+%D We need to initialize.
+
+\resetpositions
+
+\addutilityreset{positions}
+
+%D Sometimes we want to trick the position handler a bit:
+
+\def\replacepospxywhd#1#2#3#4#5#6#7%
+ {\@EA\xdef\csname\POSprefix#1\endcsname
+ {\number#2,%
+ \the\dimexpr#3\relax,%
+ \the\dimexpr#4\relax,%
+ \the\dimexpr#5\relax,%
+ \the\dimexpr#6\relax,%
+ \the\dimexpr#7\relax}}
+
+%D For postprocessing purposes, we save the number of
+%D positions.
+
+\newcount\currentpositions % current number of positions
+\newcounter\totalnofpositions % total from previous run
+
+\appendtoks
+ \expanded{\savecurrentvalue\noexpand\totalnofpositions{\the\currentpositions}}%
+\to \everybye
+
+%D The next switch can be used to communicate a special
+%D situation. Positioning and associated actions can be
+%D executed any time. However, in for instance backgrounds
+%D they can be collected in a layer, for instance the text
+%D layer (especially the hidden text layer). In the case of
+%D floats, we run into problems, since the page information is
+%D not applicable when the content floats indeed. In such
+%D situations one can treat positions and graphics local.
+
+\newif\iflocalpositioning
+
+%D Watch out: sometimes a pagebreak occurs inside a float
+%D placement, so there we need to disable local mode.
+
+\appendtoks
+ \localpositioningtrue
+\to \everyinsidefloat
+
+\appendtoks
+ \localpositioningfalse
+\to \everypagebody
+
+\def\checkpositions
+ {\startnointerference
+ \protectlabels
+ \doutilities{positions}\jobname\empty\relax\relax
+ \global\let\checkpositions\relax
+ \stopnointerference}
+
+%D Since the positional values are to be fully expandable, we
+%D need to preload them as soon as possible, which is why we
+%D load the data when we start a text.
+
+\appendtoks \checkpositions \to \everystarttext
+
+%D Positions are either generated at a delayed write time
+%D (in \PDFTEX), or derived from the dvi file. The actual
+%D method is implemented in a special driver. If needed, the
+%D driver can fall back on the following macros.
+
+\def\dolazysaveposition#1#2#3#4% tag page x y
+ {\expanded{\writeutilitycommand{\noexpand\pospxy
+ {#1}{#2}{#3}{#4}}}}
+
+\def\dolazysavepositionwhd#1#2#3#4#5#6#7% tag page x y w h d
+ {\expanded{\writeutilitycommand{\noexpand\pospxywhd
+ {#1}{#2}{#3}{#4}{#5}{#6}{#7}}}}
+
+\def\dolazysavepositionplus#1#2#3#4#5#6#7#8% tag page x y w h d list
+ {\expanded{\writeutilitycommand{\noexpand\pospxyplus
+ {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}}}}
+
+\def\dosaveposition#1#2#3#4% tag page x y
+ {\expanded{\immediatewriteutilitycommand{\noexpand\pospxy
+ {#1}{#2}{#3}{#4}}}}
+
+\def\dosavepositionwhd#1#2#3#4#5#6#7% tag page x y w h d
+ {\expanded{\immediatewriteutilitycommand{\noexpand\pospxywhd
+ {#1}{#2}{#3}{#4}{#5}{#6}{#7}}}}
+
+\def\dosavepositionplus#1#2#3#4#5#6#7#8% tag page x y w h d list
+ {\expanded{\immediatewriteutilitycommand{\noexpand\pospxyplus
+ {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}}}}
+
+%D \macros
+%D {MPp, MPx, MPy, MPw, MPh, MPd,
+%D MPxy, MPll, MPlr, MPur, MPul, MPpos}
+%D
+%D Access to the positional information is provided by macros
+%D with short names that are clearly meant for \METAPOST.
+
+\def\MPp {\doMPxyhdwlr\doMPp }
+\def\MPx {\doMPxyhdwlr\doMPx }
+\def\MPy {\doMPxyhdwlr\doMPy }
+\def\MPw {\doMPxyhdwlr\doMPw }
+\def\MPh {\doMPxyhdwlr\doMPh }
+\def\MPd {\doMPxyhdwlr\doMPd }
+\def\MPxy {\doMPxyhdwlr\doMPxy }
+\def\MPll {\doMPxyhdwlr\doMPll }
+\def\MPlr {\doMPxyhdwlr\doMPlr }
+\def\MPur {\doMPxyhdwlr\doMPur }
+\def\MPul {\doMPxyhdwlr\doMPul }
+\def\MPpos{\doMPxyhdwlr\doMPpos}
+
+\def\doMPp #1,#2,#3,#4,#5,#6,#7\relax{#1}
+\def\doMPx #1,#2,#3,#4,#5,#6,#7\relax{#2}
+\def\doMPy #1,#2,#3,#4,#5,#6,#7\relax{#3}
+\def\doMPw #1,#2,#3,#4,#5,#6,#7\relax{#4}
+\def\doMPh #1,#2,#3,#4,#5,#6,#7\relax{#5}
+\def\doMPd #1,#2,#3,#4,#5,#6,#7\relax{#6}
+\def\doMPxy #1,#2,#3,#4,#5,#6,#7\relax{(#2,#3)}
+\def\doMPll #1,#2,#3,#4,#5,#6,#7\relax{(#2,#3-#6)}
+\def\doMPlr #1,#2,#3,#4,#5,#6,#7\relax{(#2+#4,#3-#6)}
+\def\doMPur #1,#2,#3,#4,#5,#6,#7\relax{(#2+#4,#3+#5)}
+\def\doMPul #1,#2,#3,#4,#5,#6,#7\relax{(#2,#3+#5)}
+\def\doMPpos#1,#2,#3,#4,#5,#6,#7\relax{#1,#2,#3,#4,#5,#6}
+
+\def\doMPxyhdwlr#1#2%
+ {\ifcsname\POSprefix#2\endcsname
+ \@EA\@EA\@EA#1\csname\POSprefix#2\endcsname,0pt,0pt,0pt,0pt\relax
+ \else
+ #10,0pt,0pt,0pt,0pt,0pt,0pt\relax
+ \fi}
+
+%D \macros
+%D {MPplus, MPrest, MPv, MPvv}
+%D
+%D Since we will probably keep on extending, we provide a
+%D general extension macro. The plus alternative takes an
+%D extra argument, denoting what additional parameter to pick
+%D up. So, the third extra is fetched with,
+%D
+%D \starttyping
+%D \MPplus{identifier}{3}{default}
+%D \stoptyping
+%D
+%D All extras (comma separated) are fetched with:
+%D
+%D \starttyping
+%D \MPrest{identifier}
+%D \stoptyping
+%D
+%D The extra parameters are not treated.
+
+\def\MPplus {\MPdoplus\doMPplus}
+\def\MPrest#1{\MPdoplus\doMPrest{#1}{}}
+
+\def\MPdoplus#1#2#3#4%
+ {\ifcsname\POSprefix#2\endcsname
+ \@EA\@EA\@EA#1\csname\POSprefix#2\endcsname,,,,,,,,,\relax{#3}%
+ \else
+ #4%
+ \fi}
+
+\def\doMPplus#1,#2,#3,#4,#5,#6,%
+ {\dodoMPplus}
+
+\def\dodoMPplus#1,#2,#3,#4,#5,#6,#7,#8\relax#9%
+ {\ifcase#9\or#1\or#2\or#3\or#4\or#5\or#6\or#7\else\dododoMPplus#8\relax{#9}\fi}
+
+\def\dododoMPplus#1,#2,#3,#4,#5,#6,#7,#8\relax#9%
+ {\ifcase#9\or\or\or\or\or\or\or\or#1\or#2\or#3\or#4\or#5\or#6\or#7\fi}
+
+\def\doMPrest#1,#2,#3,#4,#5,#6,#7,,#8\relax#9%
+ {#7}
+
+%D \macros
+%D {MPanchor}
+%D
+%D For readability we define a few synonyms:
+
+\def\MPanchor{\MPpos}
+
+%D \macros
+%D {POSp, POSx, POSy, POSh, POSd, POSw}
+%D
+%D and:
+
+\def\POSp{\MPp} \def\POSx{\MPx} \def\POSy{\MPy}
+\def\POSh{\MPh} \def\POSd{\MPd} \def\POSw{\MPw}
+
+%D There are two low level positioning macros. Both store the
+%D position as well as execute an action associated with that
+%D position.
+
+\def\initializenextposition
+ {\ifpositioning \else
+ \global\positioningtrue
+ \dosetpositionpapersize
+ {\printpaperwidth }%
+ {\printpaperheight}%
+ \fi
+ \global\advance\currentpositions\plusone}
+
+\def\setpositiononly#1%
+ {\iftrialtypesetting
+ % nothing
+ \else
+ \initializenextposition
+ \def\currentposition{#1}%
+ \dosetposition\currentposition
+ \fi}
+
+\def\setposition#1%
+ {\iftrialtypesetting
+ % nothing
+ \else
+ \initializenextposition
+ \def\currentposition{#1}%
+ \dosetposition\currentposition
+ \traceposstring\llap\green{\currentposition>}%
+ \dopositionaction\currentposition
+ \fi}
+
+\def\setpositiondata#1#2#3#4%
+ {\iftrialtypesetting \else
+ \initializenextposition
+ \hbox
+ {\def\currentposition{#1}%
+ \dosetpositionwhd\currentposition
+ {\the\dimexpr#2\relax}%
+ {\the\dimexpr#3\relax}%
+ {\the\dimexpr#4\relax}%
+ \traceposstring\llap\green{\currentposition>}%
+ \dopositionaction\currentposition
+ \hss}%
+ \fi}
+
+\def\setpositionbox#1%
+ {\dowithnextbox
+ {\iftrialtypesetting
+ \flushnextbox
+ \else
+ \initializenextposition
+ \hbox to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionwhd\currentposition
+ {\the\nextboxwd}%
+ {\the\nextboxht}%
+ {\the\nextboxdp}%
+ \traceposstring\llap\green{\currentposition>}%
+ \setbox\positionbox\flushnextbox
+ \dopositionaction\currentposition
+ \box\positionbox
+ \hss}%
+ \fi}}
+
+\def\setpositiondataplus#1#2#3#4#5%
+ {\iftrialtypesetting \else
+ \initializenextposition
+ \hbox % bug: to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionplus\currentposition
+ {\the\dimexpr#2\relax}%
+ {\the\dimexpr#3\relax}%
+ {\the\dimexpr#4\relax}%
+ {#5}%
+ \traceposstring\rlap\magenta{<\currentposition}%
+ \dopositionaction\currentposition
+ \hss}%
+ \fi}
+
+\def\setpositionplus#1#2%
+ {\dowithnextbox
+ {\iftrialtypesetting
+ \flushnextbox
+ \else
+ \initializenextposition
+ \hbox to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionplus\currentposition
+ {\the\nextboxwd}%
+ {\the\nextboxht}%
+ {\the\nextboxdp}%
+ {#2}%
+ \traceposstring\rlap\magenta{<\currentposition}%
+ \setbox\positionbox\flushnextbox
+ \dopositionaction\currentposition
+ \box\positionbox
+ \hss}%
+ \fi}}
+
+\let\currentposition\s!unknown
+
+%D A few more low level macros take care of defining and
+%D recalling actions. We could save this information in the
+%D position containers themselves, this would save hash
+%D entries, but at the cost of much more time consuming
+%D expansion. Actions are saved globally!
+
+\newtoks\everypositionaction
+
+\let\POSactionprefix\POSprefix
+
+\def\dosetpositionaction#1%
+ {\setgvalue{\POSactionprefix#1::}}
+
+%D The lists can become quite long (also because there can
+%D be lots of parameters passed on) so we provide a hook
+%D to clean up the list afterwards.
+
+\let\cleanuppositionaction\gobbleoneargument
+
+\def\doifpositionaction#1%
+ {\ifcsname\POSactionprefix#1::\endcsname
+ \@EA\firstofoneargument
+ \else
+ \@EA\gobbleoneargument
+ \fi}
+
+\def\doifpositionactionelse#1%
+ {\ifcsname\POSactionprefix#1::\endcsname
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+%D We can copy a position with:
+%D
+%D \starttyping
+%D \copyposition {to} {from}
+%D \stoptyping
+%D
+%D Again, this is a global action.
+
+\def\copyposition#1#2%
+ {\ifcsname\POSprefix#2\endcsname
+ \global\@EA\let\csname\POSprefix#1\@EA\endcsname\csname\POSprefix#2\endcsname
+ \fi}
+
+%D The fact that handling positions is a two pass operation, is
+%D one of the reasons why we need to be able to test for
+%D existence, using:
+%D
+%D \starttyping
+%D \doifpositionelse {identifier} {found action} {not found action}
+%D \stoptyping
+
+\def\doifpositionelse#1%
+ {\ifcsname\POSprefix#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+%D We have now arrived at a few macros that would make sense as
+%D support macros, but ended up in the core.
+
+%D \macros
+%D {xypos}
+%D
+%D We have several macros available to save positions. Later
+%D we will see applications.
+%D
+%D \starttabulate[|l|l||]
+%D \NC \type {\xypos} \NC \NC simple position with no dimensions \NC \NR
+%D \NC \type {\hpos} \NC \NC position and characteristics of a \type {\hbox} \NC \NR
+%D \NC \type {\vpos} \NC \NC position and characteristics of a \type {\vbox} \NC \NR
+%D \NC \type {\bpos} \NC b: \NC begin point in a line \NC \NR
+%D \NC \type {\epos} \NC e: \NC end point in a line \NC \NR
+%D \NC \type {\fpos} \NC f: \NC begin point in a paragraph \NC \NR
+%D \NC \type {\tpos} \NC t: \NC end point in a paragraph \NC \NR
+%D \stoptabulate
+%D
+%D Each macro takes an identifier as argument, and the \type
+%D {\hpos} and \type {\vpos} also expect box content.
+
+% \def\xypos{\initializenextposition\dosetposition}
+
+\let\xypos\setpositiononly
+
+\def\hpos#1{\dontleavehmode\setpositionbox{#1}\hbox}
+\def\vpos#1{\setpositionbox{#1}\vbox}
+
+\def\bpos#1{\hpos{b:#1}{\strut}\ignorespaces}
+\def\epos#1{\removelastspace\hpos{e:#1}{\strut}}
+
+\def\fpos#1%
+ {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut
+ \ignorespaces}
+
+\def\tpos#1%
+ {\removelastspace
+ \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
+
+\def\ffpos#1%
+ {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut\wpos{#1}%
+ \ignorespaces}
+
+\def\ttpos#1%
+ {\removelastspace
+ \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
+
+\def\wpos#1%
+ {\dontleavehmode\vadjust % may disappear if buried
+ {\setbox0\hbox{\raise\strutdp\hbox{\rawwpos{#1}}}%
+ \rlap{\smashedbox0}}}
+
+\def\wwpos#1% \hsmashed{\llap{\rawwpos{#1}}}
+ {\rlap
+ {\setbox0\hbox{\rawwpos{#1}}%
+ \smashedbox0}}
+
+\def\rawwpos#1%
+ {\hpos{w:#1}
+ {\strut
+ \hskip-\leftskip
+ \hskip\hsize
+ \hskip-\rightskip}}
+
+% the next macro disables par positions (in inner boxes) and
+% only registers the width
+
+\def\setinnerparpositions
+ {\let\fpos\ffpos
+ \let\tpos\ttpos
+ \let\wpos\wwpos}
+
+% example of usage: (see for application "techniek")
+%
+% \appendtoks
+% \setinnerparpositions
+% \to \everytabulate
+
+%D When we want to calculate more complex backgrounds, we
+%D need to know what the current indentation scheme is. At
+%D the cost of many positions and memory, we can keep track
+%D of them. This mechanism is activated automatically
+%D based on information collected in the previous pass.
+
+\newcount\parposcounter
+
+\newif\ifpositioningpar
+
+% we can check for used entries, and if not, then not add one
+
+\def\enableparpositions % global
+ {\global\positioningtrue
+ \global\positioningpartrue}
+
+\def\disableparpositions % local
+ {\positioningparfalse}
+
+\def\registerparoptions
+ {\ifpositioningpar \ifpositioning \iftrialtypesetting \else
+ \ifinpagebody \else \ifmmode \else \ifinformula \else
+ \ifprocessingverbatim
+ \iflinepar \doregisterparoptions \fi
+ \else
+ \doregisterparoptions
+ \fi
+ \fi \fi \fi
+ \fi \fi \fi}
+
+\chardef\parposstrut=1 % 0 => no strut data, so fall backs used
+
+\newif\iftracepositions
+
+% \def\doregisterparoptions
+% {\global\advance\parposcounter\plusone
+% \begingroup
+% \leftskip 1\leftskip
+% \rightskip1\rightskip
+% \setpositiondataplus
+% {p:\number\parposcounter}% identifier
+% {\the\zeropoint}%
+% {\the\strutht}%
+% {\the\strutdp}%
+% {\the\hsize ,% 1
+% \the\leftskip ,% 2
+% \the\rightskip ,% 3
+% \the\hangindent,% 4
+% \the\hangafter ,% 5 (num)
+% \the\parindent }% 6
+% %\normalhbox{\registerparsymbol}%
+% \registerparsymbol
+% \endgroup}
+
+\def\doregisterparoptions
+ {\global\advance\parposcounter\plusone
+ \setpositiondataplus
+ {p:\number\parposcounter}% identifier
+ {\the\zeropoint}%
+ {\the\strutht}%
+ {\the\strutdp}%
+ {\the\hsize,\the\dimexpr\leftskip\relax,\the\dimexpr\rightskip\relax,\the\hangindent,\the\hangafter,\the\parindent}%
+ %\normalhbox{\registerparsymbol}%
+ \iftracepositions\registerparsymbol\fi}
+
+\def\traceposstring#1#2#3%
+ {\iftracepositions\smashedhbox{#1{\infofont#2#3}}\fi}
+
+\def\registerparsymbol
+ {\iftracepositions
+ \smashedhbox to \zeropoint
+ {\hss
+ \startcolor[blue]%
+ \llap{\infofont\number\parposcounter}%
+ \scratchdimen\onepoint
+ \vrule
+ \!!width 4\scratchdimen
+ \!!height2\scratchdimen
+ \!!depth 2\scratchdimen
+ \stopcolor
+ \hss}%
+ \fi}
+
+% \appendtoks \registerparoptions \to \everypar
+
+%D Eperimental code, don't use this yet: (must be sped up anyway)
+
+\def\@@noden{node:n:}
+\def\@@nodeo{node:o:}
+\def\@@nodep{node:p:}
+
+\def\doifelsenodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\nextnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname\pluscounter{\@@noden#1}\fi}
+
+\def\newnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \setcounter{\@@noden#1}\zerocount
+ \letgvalue {\@@nodeo#1}\!!zerocount
+ \fi}
+
+\def\tagnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname\xypos{\@@nodep#1:\countervalue{\@@noden#1}}\fi}
+
+\def\getnodelocationp#1{\MPp{\@@nodep#1:\countervalue{\@@noden#1}}}
+\def\getnodelocationx#1{\MPx{\@@nodep#1:\countervalue{\@@noden#1}}}
+\def\getnodelocationy#1{\MPy{\@@nodep#1:\countervalue{\@@noden#1}}}
+
+\def\numnodelocationp#1#2{\MPp{\@@nodep#1:\number#2}}
+\def\numnodelocationx#1#2{\MPx{\@@nodep#1:\number#2}}
+\def\numnodelocationy#1#2{\MPy{\@@nodep#1:\number#2}}
+
+\def\getnodelocationn#1{\countervalue{\@@noden#1}}
+\def\getnodelocationo#1{\getvalue {\@@nodeo#1}}
+
+\chardef\nodelocationmode\plusone
+
+\def\analyzenodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \doanalyzenodelocation{#1}{\getnodelocationn{#1}}\zerocount
+ \fi}
+
+\def\doanalyzenodelocation#1#2#3% class n default
+ {\begingroup
+ \donefalse
+ \ifcase\nodelocationmode
+ % do nothing
+ \else
+ \edef\nodelocationselfn{#2}%
+ \edef\nodelocationselfp{\numnodelocationp{#1}\nodelocationselfn}%
+ \edef\nodelocationselfx{\numnodelocationx{#1}\nodelocationselfn}%
+ \edef\nodelocationselfy{\numnodelocationy{#1}\nodelocationselfn}%
+ \scratchcounter\plusone
+ \doloop
+ {\ifnum\recurselevel=\nodelocationselfn\relax
+ \donetrue
+ \else
+ \edef\nodelocationotherp{\numnodelocationp{#1}\recurselevel}%
+ \edef\nodelocationotherx{\numnodelocationx{#1}\recurselevel}%
+ \edef\nodelocationothery{\numnodelocationy{#1}\recurselevel}%
+ \ifcase\nodelocationmode
+ \or
+ % ok for single column
+ \ifcase\nodelocationotherp\relax
+ \exitloop
+ \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
+ % skip
+ \else\ifdim\nodelocationothery>\nodelocationselfy\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifdim\nodelocationothery<\nodelocationselfy\relax
+ % skip
+ \else\ifdim\nodelocationotherx<\nodelocationselfx\relax
+ \donetrue \advance\scratchcounter\plusone
+ \fi\fi\fi\fi\fi\fi
+ \or
+ % acceptable for double column
+ \ifcase\nodelocationotherp\relax
+ \exitloop
+ \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
+ % skip
+ \else\ifnum\recurselevel>\nodelocationselfn\relax
+ \donetrue \exitloop
+ \else
+ \donetrue \advance\scratchcounter\plusone
+ \fi\fi\fi\fi
+ \else
+ \exitloop
+ \fi
+ \fi}%
+ \fi
+ \ifdone \else
+ \scratchcounter#3\relax
+ \fi
+ \setxvalue{\@@nodeo#1}{\the\scratchcounter}%
+ \endgroup}
+
+\unexpanded\def\shownodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \analyzenodelocation{#1}%
+ (#1,%
+ n:\getnodelocationn{#1},%
+ p:\getnodelocationp{#1},%
+ x:\getnodelocationx{#1},%
+ y:\getnodelocationy{#1},%
+ o:\getnodelocationo{#1})%
+ \fi}
+
+%D \macros
+%D {doifoverlappingelse}
+%D
+%D A first application of positional information, is to
+%D determine if two boxes do overlap:
+%D
+%D \starttyping
+%D \doifoverlappingelse{point a}{point b}
+%D {action when overlapping}
+%D {action when not overlapping}
+%D \stoptyping
+
+\def\overlappingmargin{-2\scaledpoint}
+
+\def\doifoverlappingelse#1#2%
+ {\begingroup
+ \donefalse
+ \edef\!!stringa{#1}\edef\!!stringb{#2}%
+ \ifnum\MPp\!!stringa=\MPp\!!stringb\relax
+ \!!dimena\MPx\!!stringa
+ \!!dimenb\dimexpr\MPx\!!stringa+\MPw\!!stringa\relax
+ \!!dimenc\dimexpr\MPy\!!stringa-\MPd\!!stringa\relax
+ \!!dimend\dimexpr\MPy\!!stringa+\MPh\!!stringa\relax
+ \!!dimene\MPx\!!stringb
+ \!!dimenf\dimexpr\MPx\!!stringb+\MPw\!!stringb\relax
+ \!!dimeng\dimexpr\MPy\!!stringb-\MPd\!!stringb\relax
+ \!!dimenh\dimexpr\MPy\!!stringb+\MPh\!!stringb\relax
+ \ifdim\overlappingmargin=\zeropoint\else
+ \advance\!!dimena-\overlappingmargin
+ \advance\!!dimenb+\overlappingmargin
+ \advance\!!dimenc-\overlappingmargin
+ \advance\!!dimend+\overlappingmargin
+ \advance\!!dimene-\overlappingmargin
+ \advance\!!dimenf+\overlappingmargin
+ \advance\!!dimeng-\overlappingmargin
+ \advance\!!dimenh+\overlappingmargin
+ \fi
+ % more often eh fb eg fg
+ \def\checkone##1##2%
+ {\ifdim##1<\!!dimena \else \ifdim##1>\!!dimenb \else
+ \ifdim##2<\!!dimenc \else \ifdim##2>\!!dimend \else
+ \donetrue
+ \fi\fi
+ \fi\fi}%
+ \def\checktwo##1##2%
+ {\ifdim##1<\!!dimene \else \ifdim##1>\!!dimenf \else
+ \ifdim##2<\!!dimeng \else \ifdim##2>\!!dimenh \else
+ \donetrue
+ \fi\fi
+ \fi\fi}%
+ \checkone\!!dimene\!!dimeng \ifdone \else
+ \checkone\!!dimene\!!dimenh \ifdone \else
+ \checkone\!!dimenf\!!dimeng \ifdone \else
+ \checkone\!!dimenf\!!dimenh \ifdone \else
+ \checktwo\!!dimena\!!dimenc \ifdone \else
+ \checktwo\!!dimena\!!dimend \ifdone \else
+ \checktwo\!!dimenb\!!dimene \ifdone \else
+ \checktwo\!!dimenb\!!dimenc \fi \fi \fi \fi \fi \fi \fi
+ \fi
+ \ifdone
+ \endgroup\expandafter\firstoftwoarguments
+ \else
+ \endgroup\expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {doifpositionsonsamepageelse,
+%D doifpositionsonthispageelse}
+%D
+%D Instead of letting the user handle fuzzy expansion, we
+%D provide a simple test on positione being on the same page.
+%D
+%D \starttyping
+%D \doifpositionsonsamepageelse{point a}{point b}
+%D {action when on same page}
+%D {action when not on same page}
+%D \doifpositionsonthispageelse{point a}{point b}
+%D {action when on this page}
+%D {action when not on this page}
+%D \stoptyping
+
+\def\dodoifpositionsonsamepageelse#1#2#3#4%
+ {\bgroup
+ \scratchcounter#1\donefalse
+ \def\docommand##1%
+ {\ifcase\scratchcounter
+ \scratchcounter\MPp{##1}\donetrue
+ \else
+ \ifnum\scratchcounter=\MPp{##1}\relax\else\donefalse\fi
+ \fi}%
+ \rawprocesscommalist[#2]\docommand
+ \ifdone\egroup#3\else\egroup#4\fi}
+
+\def\doifpositionsonsamepageelse{\dodoifpositionsonsamepageelse\!!zerocount}
+\def\doifpositionsonthispageelse{\dodoifpositionsonsamepageelse\realfolio }
+
+%D Plugins:
+
+\let\MPv \MPplus
+\let\MPvv\MPrest
+
+\let\MPanchor\MPpos
+
+\let\POSp\MPp \let\POSx\MPx \let\POSy\MPy
+\let\POSh\MPh \let\POSd\MPd \let\POSw\MPw
+
+\protect \endinput
diff --git a/tex/context/base/anch-pos.mkiv b/tex/context/base/anch-pos.mkiv
new file mode 100644
index 000000000..e454747da
--- /dev/null
+++ b/tex/context/base/anch-pos.mkiv
@@ -0,0 +1,784 @@
+%D \module
+%D [ file=anch-pos, % was core-pos
+%D version=1999.08.01,
+%D title=\CONTEXT\ Anchoring Macros,
+%D subtitle=Positioning 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.
+
+% needs a cleanup, things may change; we also need to move the mp
+% related code to meta-pos
+
+% shorter tags, ..:achtergrond:.. etc in pos actions
+
+% dubbele text- * pos's eruit
+
+% class pos -> als gelijk aan vorige, dan niet niet definieren
+% en erven, maw:
+%
+% 1 -> opslaan
+% 2 -> undef, dus == prev
+% 3 -> undef, dus == prev
+% 4 -> opslaan
+
+\writestatus{loading}{ConTeXt Anchoring Macros / Positioning}
+
+% saveposition : tag page x y
+% savepositionwhd : tag page x y w h d
+% savepositionplus : tag page x y w h d list
+%
+% at some point (when we no longer share code) we will move to numbers
+% do that we have less garbage collection and hashing
+%
+% the global table ptbs is equivalent to jobpositions.tobesaved
+%
+% btw, using a function is more efficient than passing longer code
+% snippets to ctxlua
+
+\registerctxluafile{anch-pos}{1.001}
+
+% todo: topskip als optie voor eerste regel achtergrond
+% todo: build pos layers on top of layers
+% todo: positionlayer pos van text-1 etc delen
+
+%D Although \TEX\ has a rather powerful channel to the outside
+%D world, called \type {\special}, real communication with
+%D other programs is complicated by the fact that no positional
+%D information is available. Mid 1999, I discussed this with
+%D \THANH, the author of \PDFTEX, and after some experiments,
+%D \PDFTEX\ was extended with a simple but effective mechanism,
+%D that provided positional information. The interesting
+%D thought is that, although \TEX\ is frozen, similar
+%D functionality could have been achieved with \type
+%D {\specials} and an additional \DVI\ postprocessor.
+%D
+%D Since we want to be as compatible as can be, \CONTEXT\ will
+%D support both methods, although the development is primarily
+%D driven by the \PDFTEX\ way of doing things. Since the
+%D mechanism is basically not limited to one application, for
+%D the moment we stick to building the functionality around one
+%D \CONTEXT\ special command, but at the same time we keep our
+%D eyes open for extensions in other directions.
+%D
+%D A question that may arise when one reads this module, is to
+%D what extend these macros are generic, in the sense that they
+%D could be collected in a support module instead of a core
+%D module. Since the mechanism described here will closely
+%D cooperate with the \METAPOST\ support built in \CONTEXT,
+%D which in turn will be tightly integrated with the \CONTEXT\
+%D overlay mechanisms, I decided to write a core module instead
+%D of a support one. This makes even more sense, when one takes
+%D into account that this kind of support depends on special
+%D drivers.
+
+\unprotect
+
+%D The first application of positional information was embedded
+%D graphics. Since we are interacting with text, it made sense
+%D to take the current line height and depth into account too.
+%D This is why we have two basic position macros: one for
+%D simple positions, and one for boxes.
+%D
+%D We could have sticked to one special, and actually did so in
+%D earlier experiments, but for convenience, as well for
+%D clearness, we now have two alternatives. This approach will
+%D save us quite some bytes when storing large quantities of
+%D positional information. We save as less information as
+%D needed, that is, we save no dimensions, in a \METAPOST\
+%D friendly way.
+%D
+%D The three specials involved are:
+%D
+%D \starttyping
+%D \dosetposition {identifier}
+%D \dosetpositionwhd {identifier} {width} {height} {depth}
+%D \dosetpositionplus {identifier} {width} {height} {depth} {list}
+%D \dosetpositionpapersize {width} {height}
+%D \stoptyping
+%D
+%D Positions are either generated at a delayed write time
+%D (in \PDFTEX), or derived from the dvi file. The actual
+%D method is implemented in a special driver. If needed, the
+%D driver can fall back on the following macros.
+
+% are the next 6 still used?
+
+\def\dolazysaveposition #1#2#3#4{\normalexpanded{\ctxlatelua{ptbs['#1']={#2,"#3","#4"}}}}
+\def\dolazysavepositionwhd #1#2#3#4#5#6#7{\normalexpanded{\ctxlatelua{ptbs['#1']={#2,"#3","#4","#5","#6","#7"}}}}
+\def\dolazysavepositionplus#1#2#3#4#5#6#7#8{\normalexpanded{\ctxlatelua{ptbs['#1']={#2,"#3","#4","#5","#6","#7","#8"}}}}
+\def\dosaveposition #1#2#3#4{\normalexpanded{\ctxlua {ptbs['#1']={#2,"#3","#4"}}}}
+\def\dosavepositionwhd #1#2#3#4#5#6#7{\normalexpanded{\ctxlua {ptbs['#1']={#2,"#3","#4","#5","#6","#7"}}}}
+\def\dosavepositionplus #1#2#3#4#5#6#7#8{\normalexpanded{\ctxlua {ptbs['#1']={#2,"#3","#4","#5","#6","#7","#8"}}}}
+
+\def\lastsavedpositionx {\the\dimexpr\pdflastxpos\scaledpoint\relax}
+\def\lastsavedpositiony {\the\dimexpr\pdflastypos\scaledpoint\relax}
+\let\savecurrentposition\pdfsavepos
+
+\def\dosetposition#1%
+ {\savecurrentposition
+ \normalexpanded{\ctxlatelua{ptbs['#1']={%
+ \noexpand\realfolio,"\noexpand\lastsavedpositionx","\noexpand\lastsavedpositiony"}}}}
+
+\def\dosetpositionwhd#1#2#3#4%
+ {\savecurrentposition
+ \normalexpanded{\ctxlatelua{ptbs['#1']={%
+ \noexpand\realfolio,"\noexpand\lastsavedpositionx","\noexpand\lastsavedpositiony","#2","#3","#4"}}}}
+
+\def\dosetpositionplus#1#2#3#4#5%
+ {\savecurrentposition
+ \normalexpanded{\ctxlatelua{ptbs['#1']={%
+ \noexpand\realfolio,"\noexpand\lastsavedpositionx","\noexpand\lastsavedpositiony","#2","#3","#4","#5"}}}}
+
+\let\dosetpositionpapersize\gobbletwoarguments
+
+\newbox\positionbox
+\newif \ifpositioning
+
+\def\POSprefix{POS::}
+
+\let\setpospx \gobblefourarguments % suppress errors with mkii tuo file
+\let\setpospxywhd \gobblesevenarguments % suppress errors with mkii tuo file
+\let\setpospxyplus\gobbleeightarguments % suppress errors with mkii tuo file
+
+%D This is real tricky! The page anchor is applied to the
+%D page box and therefore flushed first. So, when present, it
+%D is applied to all positions except itself.
+
+\chardef\positionanchormode=0 % don't relocate page origin
+\chardef\positionanchormode=1 % relocate page origin once
+
+%D The core set macros.
+
+\let\pospxy \gobblefourarguments
+\let\pospxywhd \gobblesevenarguments
+\let\pospxyplus\gobbleeightarguments
+
+%D Sometimes we want to trick the position handler a bit:
+
+\def\replacepospxywhd#1#2#3#4#5#6#7{\ctxlua{jobpositions.replace('#1',\number#2,"\the\dimexpr#3\relax","\the\dimexpr#4\relax","\the\dimexpr#5\relax","\the\dimexpr#6\relax","\the\dimexpr#7\relax")}}
+
+%D For postprocessing purposes, we save the number of
+%D positions.
+
+\newcount\currentpositions % current number of positions
+
+%D The next switch can be used to communicate a special
+%D situation. Positioning and associated actions can be
+%D executed any time. However, in for instance backgrounds
+%D they can be collected in a layer, for instance the text
+%D layer (especially the hidden text layer). In the case of
+%D floats, we run into problems, since the page information is
+%D not applicable when the content floats indeed. In such
+%D situations one can treat positions and graphics local.
+
+\newif\iflocalpositioning
+
+%D Watch out: sometimes a pagebreak occurs inside a float
+%D placement, so there we need to disable local mode.
+
+\appendtoks
+ \localpositioningtrue
+\to \everyinsidefloat
+
+\appendtoks
+ \localpositioningfalse
+\to \everypagebody
+
+%D Since the positional values are to be fully expandable, we
+%D need to preload them as soon as possible, which is why we
+%D load the data when we start a text.
+
+% \appendtoks \checkpositions \to \everystarttext
+
+%D \macros
+%D {MPp, MPx, MPy, MPw, MPh, MPd,
+%D MPxy, MPll, MPlr, MPur, MPul, MPpos}
+%D
+%D Access to the positional information is provided by macros
+%D with short names that are clearly meant for \METAPOST.
+
+% \the\dimexpr\noexpand\lastsavedpositionx\ifnum\positionanchormode=\plusone-\MPx\pageanchor\fi\relax
+% \the\dimexpr\noexpand\lastsavedpositiony\ifnum\positionanchormode=\plusone-\MPx\pageanchor\fi\relax
+
+\def\MPp #1{\ctxlua{jobpositions.MPp("#1")}}
+\def\MPx #1{\ctxlua{jobpositions.MPx("#1")}}
+\def\MPy #1{\ctxlua{jobpositions.MPy("#1")}}
+\def\MPw #1{\ctxlua{jobpositions.MPw("#1")}}
+\def\MPh #1{\ctxlua{jobpositions.MPh("#1")}}
+\def\MPd #1{\ctxlua{jobpositions.MPd("#1")}}
+\def\MPxy #1{\ctxlua{jobpositions.MPxy("#1")}}
+\def\MPll #1{\ctxlua{jobpositions.MPll("#1")}}
+\def\MPlr #1{\ctxlua{jobpositions.MPlr("#1")}}
+\def\MPur #1{\ctxlua{jobpositions.MPur("#1")}}
+\def\MPul #1{\ctxlua{jobpositions.MPul("#1")}}
+\def\MPpos#1{\ctxlua{jobpositions.MPpos("#1")}}
+
+%D \macros
+%D {MPplus, MPrest, MPv, MPvv}
+%D
+%D Since we will probably keep on extending, we provide a
+%D general extension macro. The plus alternative takes an
+%D extra argument, denoting what additional parameter to pick
+%D up. So, the third extra is fetched with,
+%D
+%D \starttyping
+%D \MPplus{identifier}{3}{default}
+%D \stoptyping
+%D
+%D All extras (comma separated) are fetched with:
+%D
+%D \starttyping
+%D \MPrest{identifier}
+%D \stoptyping
+%D
+%D The extra parameters are not treated.
+
+\def\MPplus#1#2#3{\ctxlua{jobpositions.MPplus("#1",#2,"#3")}} \let\MPv \MPplus
+\def\MPrest #1#2{\ctxlua{jobpositions.MPrest("#1","#2")}} \let\MPvv\MPrest
+
+%D \macros
+%D {MPanchor}
+%D
+%D For readability we define a few synonyms:
+
+\def\MPanchor{\MPpos}
+
+%D \macros
+%D {POSp, POSx, POSy, POSh, POSd, POSw}
+%D
+%D and:
+
+\def\POSp{\MPp} \def\POSx{\MPx} \def\POSy{\MPy}
+\def\POSh{\MPh} \def\POSd{\MPd} \def\POSw{\MPw}
+
+%D There are two low level positioning macros. Both store the
+%D position as well as execute an action associated with that
+%D position.
+
+\def\initializenextposition
+ {\ifpositioning \else
+ \global\positioningtrue
+ \dosetpositionpapersize
+ {\printpaperwidth }%
+ {\printpaperheight}%
+ \fi
+ \global\advance\currentpositions\plusone}
+
+\def\setpositiononly#1%
+ {\iftrialtypesetting
+ % nothing
+ \else
+ \initializenextposition
+ \def\currentposition{#1}%
+ \dosetposition\currentposition
+ \fi}
+
+\def\setposition#1%
+ {\iftrialtypesetting
+ % nothing
+ \else
+ \initializenextposition
+ \def\currentposition{#1}%
+ \dosetposition\currentposition
+ \traceposstring\llap\green{\currentposition>}%
+ \dopositionaction\currentposition
+ \fi}
+
+\def\setpositiondata#1#2#3#4%
+ {\iftrialtypesetting \else
+ \initializenextposition
+ \hbox
+ {\def\currentposition{#1}%
+ \dosetpositionwhd\currentposition
+ {\the\dimexpr#2\relax}%
+ {\the\dimexpr#3\relax}%
+ {\the\dimexpr#4\relax}%
+ \traceposstring\llap\green{\currentposition>}%
+ \dopositionaction\currentposition
+ \hss}%
+ \fi}
+
+\def\setpositionbox#1%
+ {\dowithnextbox
+ {\iftrialtypesetting
+ \flushnextbox
+ \else
+ \initializenextposition
+ \hbox to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionwhd\currentposition
+ {\the\nextboxwd}%
+ {\the\nextboxht}%
+ {\the\nextboxdp}%
+ \traceposstring\llap\green{\currentposition>}%
+ \setbox\positionbox\flushnextbox
+ \dopositionaction\currentposition
+ \box\positionbox
+ \hss}%
+ \fi}}
+
+\def\setpositiondataplus#1#2#3#4#5%
+ {\iftrialtypesetting \else
+ \initializenextposition
+ \hbox % bug: to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionplus\currentposition
+ {\the\dimexpr#2\relax}%
+ {\the\dimexpr#3\relax}%
+ {\the\dimexpr#4\relax}%
+ {#5}%
+ \traceposstring\rlap\magenta{<\currentposition}%
+ \dopositionaction\currentposition
+ \hss}%
+ \fi}
+
+\def\setpositionplus#1#2%
+ {\dowithnextbox
+ {\iftrialtypesetting
+ \flushnextbox
+ \else
+ \initializenextposition
+ \hbox to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionplus\currentposition
+ {\the\nextboxwd}%
+ {\the\nextboxht}%
+ {\the\nextboxdp}%
+ {#2}%
+ \traceposstring\rlap\magenta{<\currentposition}%
+ \setbox\positionbox\flushnextbox
+ \dopositionaction\currentposition
+ \box\positionbox
+ \hss}%
+ \fi}}
+
+\let\currentposition\s!unknown
+
+%D A few more low level macros take care of defining and
+%D recalling actions. We could save this information in the
+%D position containers themselves, this would save hash
+%D entries, but at the cost of much more time consuming
+%D expansion. Actions are saved globally!
+
+\newtoks\everypositionaction
+
+\let\POSactionprefix\POSprefix
+
+\def\dosetpositionaction#1%
+ {\setgvalue{\POSactionprefix#1::}}
+
+%D The lists can become quite long (also because there can
+%D be lots of parameters passed on) so we provide a hook
+%D to clean up the list afterwards.
+
+\let\cleanuppositionaction\gobbleoneargument
+
+\def\doifpositionaction#1%
+ {\ifcsname\POSactionprefix#1::\endcsname
+ \@EA\firstofoneargument
+ \else
+ \@EA\gobbleoneargument
+ \fi}
+
+\def\doifpositionactionelse#1%
+ {\ifcsname\POSactionprefix#1::\endcsname
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+%D We can copy a position with:
+%D
+%D \starttyping
+%D \copyposition {to} {from}
+%D \stoptyping
+%D
+%D Again, this is a global action.
+
+\def\copyposition#1#2{\ctxlua{jobpositions.copy('#1','#2')}}
+
+%D The fact that handling positions is a two pass operation, is
+%D one of the reasons why we need to be able to test for
+%D existence, using:
+%D
+%D \starttyping
+%D \doifpositionelse {identifier} {found action} {not found action}
+%D \stoptyping
+
+\def\doifpositionelse#1{\ctxlua{jobpositions.doifelse('#1')}}
+
+%D We have now arrived at a few macros that would make sense as
+%D support macros, but ended up in the core.
+
+%D \macros
+%D {xypos}
+%D
+%D We have several macros available to save positions. Later
+%D we will see applications.
+%D
+%D \starttabulate[|l|l||]
+%D \NC \type {\xypos} \NC \NC simple position with no dimensions \NC \NR
+%D \NC \type {\hpos} \NC \NC position and characteristics of a \type {\hbox} \NC \NR
+%D \NC \type {\vpos} \NC \NC position and characteristics of a \type {\vbox} \NC \NR
+%D \NC \type {\bpos} \NC b: \NC begin point in a line \NC \NR
+%D \NC \type {\epos} \NC e: \NC end point in a line \NC \NR
+%D \NC \type {\fpos} \NC f: \NC begin point in a paragraph \NC \NR
+%D \NC \type {\tpos} \NC t: \NC end point in a paragraph \NC \NR
+%D \stoptabulate
+%D
+%D Each macro takes an identifier as argument, and the \type
+%D {\hpos} and \type {\vpos} also expect box content.
+
+% \def\xypos{\initializenextposition\dosetposition}
+
+\let\xypos\setpositiononly
+
+\def\hpos#1{\dontleavehmode\setpositionbox{#1}\hbox}
+\def\vpos#1{\setpositionbox{#1}\vbox}
+
+\def\bpos#1{\hpos{b:#1}{\strut}\ignorespaces}
+\def\epos#1{\removelastspace\hpos{e:#1}{\strut}}
+
+\def\fpos#1%
+ {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut
+ \ignorespaces}
+
+\def\tpos#1%
+ {\removelastspace
+ \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
+
+\def\ffpos#1%
+ {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut\wpos{#1}%
+ \ignorespaces}
+
+\def\ttpos#1%
+ {\removelastspace
+ \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
+
+\def\wpos#1%
+ {\dontleavehmode\vadjust % may disappear if buried
+ {\setbox0\hbox{\raise\strutdp\hbox{\rawwpos{#1}}}%
+ \rlap{\smashedbox0}}}
+
+\def\wwpos#1% \hsmashed{\llap{\rawwpos{#1}}}
+ {\rlap
+ {\setbox0\hbox{\rawwpos{#1}}%
+ \smashedbox0}}
+
+\def\rawwpos#1%
+ {\hpos{w:#1}
+ {\strut
+ \hskip-\leftskip
+ \hskip\hsize
+ \hskip-\rightskip}}
+
+% the next macro disables par positions (in inner boxes) and
+% only registers the width
+
+\def\setinnerparpositions
+ {\let\fpos\ffpos
+ \let\tpos\ttpos
+ \let\wpos\wwpos}
+
+% example of usage: (see for application "techniek")
+%
+% \appendtoks
+% \setinnerparpositions
+% \to \everytabulate
+
+%D When we want to calculate more complex backgrounds, we
+%D need to know what the current indentation scheme is. At
+%D the cost of many positions and memory, we can keep track
+%D of them. This mechanism is activated automatically
+%D based on information collected in the previous pass.
+
+\newcount\parposcounter
+\newif \ifpositioningpar
+\chardef \parposstrut = 1 % 0 => no strut data, so fall backs used
+\newif \iftracepositions
+
+% we can check for used entries, and if not, then not add one
+
+\def\enableparpositions % global
+ {\global\let\registerparoptions\doregisterparoptions
+ \global\positioningtrue
+ \global\positioningpartrue}
+
+\def\disableparpositions % local
+ {\positioningparfalse}
+
+\let\registerparoptions\relax
+
+\def\doregisterparoptions
+ {\ifpositioningpar \ifpositioning \iftrialtypesetting \else
+ \ifinpagebody \else \ifmmode \else \ifinformula \else
+ \ifprocessingverbatim
+ \iflinepar \dodoregisterparoptions \fi
+ \else
+ \dodoregisterparoptions
+ \fi
+ \fi \fi \fi
+ \fi \fi \fi}
+
+\def\dodoregisterparoptions
+ {\global\advance\parposcounter\plusone
+ \setpositiondataplus
+ {p:\number\parposcounter}% identifier
+ {\the\zeropoint}%
+ {\the\strutht}%
+ {\the\strutdp}%
+ {\the\hsize,\the\dimexpr\leftskip\relax,\the\dimexpr\rightskip\relax,\the\hangindent,\the\hangafter,\the\parindent}%
+ %\normalhbox{\registerparsymbol}%
+ \iftracepositions\registerparsymbol\fi}
+
+\def\traceposstring#1#2#3%
+ {\iftracepositions\smashedhbox{#1{\infofont#2#3}}\fi}
+
+\def\registerparsymbol
+ {\iftracepositions
+ \smashedhbox to \zeropoint
+ {\hss
+ \startcolor[blue]%
+ \llap{\infofont\number\parposcounter}%
+ \scratchdimen\onepoint
+ \vrule
+ \!!width 4\scratchdimen
+ \!!height2\scratchdimen
+ \!!depth 2\scratchdimen
+ \stopcolor
+ \hss}%
+ \fi}
+
+% \appendtoks \registerparoptions \to \everypar
+
+%D Eperimental code, don't use this yet: (must be sped up anyway)
+
+\def\@@noden{node:n:}
+\def\@@nodeo{node:o:}
+\def\@@nodep{node:p:}
+
+\def\doifelsenodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\nextnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname\pluscounter{\@@noden#1}\fi}
+
+\def\newnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \setcounter{\@@noden#1}\zerocount
+ \letgvalue {\@@nodeo#1}\!!zerocount
+ \fi}
+
+\def\tagnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname\xypos{\@@nodep#1:\countervalue{\@@noden#1}}\fi}
+
+\def\getnodelocationp#1{\MPp{\@@nodep#1:\countervalue{\@@noden#1}}}
+\def\getnodelocationx#1{\MPx{\@@nodep#1:\countervalue{\@@noden#1}}}
+\def\getnodelocationy#1{\MPy{\@@nodep#1:\countervalue{\@@noden#1}}}
+
+\def\numnodelocationp#1#2{\MPp{\@@nodep#1:\number#2}}
+\def\numnodelocationx#1#2{\MPx{\@@nodep#1:\number#2}}
+\def\numnodelocationy#1#2{\MPy{\@@nodep#1:\number#2}}
+
+\def\getnodelocationn#1{\countervalue{\@@noden#1}}
+\def\getnodelocationo#1{\getvalue {\@@nodeo#1}}
+
+\chardef\nodelocationmode\plusone
+
+\def\analyzenodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \doanalyzenodelocation{#1}{\getnodelocationn{#1}}\zerocount
+ \fi}
+
+\def\doanalyzenodelocation#1#2#3% class n default
+ {\begingroup
+ \donefalse
+ \ifcase\nodelocationmode
+ % do nothing
+ \else
+ \edef\nodelocationselfn{#2}%
+ \edef\nodelocationselfp{\numnodelocationp{#1}\nodelocationselfn}%
+ \edef\nodelocationselfx{\numnodelocationx{#1}\nodelocationselfn}%
+ \edef\nodelocationselfy{\numnodelocationy{#1}\nodelocationselfn}%
+ \scratchcounter\plusone
+ \doloop
+ {\ifnum\recurselevel=\nodelocationselfn\relax
+ \donetrue
+ \else
+ \edef\nodelocationotherp{\numnodelocationp{#1}\recurselevel}%
+ \edef\nodelocationotherx{\numnodelocationx{#1}\recurselevel}%
+ \edef\nodelocationothery{\numnodelocationy{#1}\recurselevel}%
+ \ifcase\nodelocationmode
+ \or
+ % ok for single column
+ \ifcase\nodelocationotherp\relax
+ \exitloop
+ \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
+ % skip
+ \else\ifdim\nodelocationothery>\nodelocationselfy\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifdim\nodelocationothery<\nodelocationselfy\relax
+ % skip
+ \else\ifdim\nodelocationotherx<\nodelocationselfx\relax
+ \donetrue \advance\scratchcounter\plusone
+ \fi\fi\fi\fi\fi\fi
+ \or
+ % acceptable for double column
+ \ifcase\nodelocationotherp\relax
+ \exitloop
+ \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
+ % skip
+ \else\ifnum\recurselevel>\nodelocationselfn\relax
+ \donetrue \exitloop
+ \else
+ \donetrue \advance\scratchcounter\plusone
+ \fi\fi\fi\fi
+ \else
+ \exitloop
+ \fi
+ \fi}%
+ \fi
+ \ifdone \else
+ \scratchcounter#3\relax
+ \fi
+ \setxvalue{\@@nodeo#1}{\the\scratchcounter}%
+ \endgroup}
+
+\unexpanded\def\shownodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \analyzenodelocation{#1}%
+ (#1,%
+ n:\getnodelocationn{#1},%
+ p:\getnodelocationp{#1},%
+ x:\getnodelocationx{#1},%
+ y:\getnodelocationy{#1},%
+ o:\getnodelocationo{#1})%
+ \fi}
+
+%D \macros
+%D {doifoverlappingelse}
+%D
+%D A first application of positional information, is to
+%D determine if two boxes do overlap:
+%D
+%D \starttyping
+%D \doifoverlappingelse{point a}{point b}
+%D {action when overlapping}
+%D {action when not overlapping}
+%D \stoptyping
+
+\def\overlappingmargin{-2\scaledpoint}
+
+\def\overlappingcheckone#1#2%
+ {\ifdim#1<\!!dimena \else \ifdim#1>\!!dimenb \else
+ \ifdim#2<\!!dimenc \else \ifdim#2>\!!dimend \else
+ \donetrue
+ \fi\fi
+ \fi\fi}
+
+\def\overlappingchecktwo#1#2%
+ {\ifdim#1<\!!dimene \else \ifdim#1>\!!dimenf \else
+ \ifdim#2<\!!dimeng \else \ifdim#2>\!!dimenh \else
+ \donetrue
+ \fi\fi
+ \fi\fi}
+
+\def\doifoverlappingelse#1#2% maybe do this in lua
+ {\begingroup
+ \donefalse
+ \edef\!!stringa{#1}\edef\!!stringb{#2}%
+ \ifnum\MPp\!!stringa=\MPp\!!stringb\relax
+ \!!dimena\MPx\!!stringa
+ \!!dimenb\dimexpr\MPx\!!stringa+\MPw\!!stringa\relax
+ \!!dimenc\dimexpr\MPy\!!stringa-\MPd\!!stringa\relax
+ \!!dimend\dimexpr\MPy\!!stringa+\MPh\!!stringa\relax
+ \!!dimene\MPx\!!stringb
+ \!!dimenf\dimexpr\MPx\!!stringb+\MPw\!!stringb\relax
+ \!!dimeng\dimexpr\MPy\!!stringb-\MPd\!!stringb\relax
+ \!!dimenh\dimexpr\MPy\!!stringb+\MPh\!!stringb\relax
+ \ifdim\overlappingmargin=\zeropoint\else
+ \advance\!!dimena-\overlappingmargin
+ \advance\!!dimenb+\overlappingmargin
+ \advance\!!dimenc-\overlappingmargin
+ \advance\!!dimend+\overlappingmargin
+ \advance\!!dimene-\overlappingmargin
+ \advance\!!dimenf+\overlappingmargin
+ \advance\!!dimeng-\overlappingmargin
+ \advance\!!dimenh+\overlappingmargin
+ \fi
+ % more often eh fb eg fg
+ \overlappingcheckone\!!dimene\!!dimeng \ifdone \else
+ \overlappingcheckone\!!dimene\!!dimenh \ifdone \else
+ \overlappingcheckone\!!dimenf\!!dimeng \ifdone \else
+ \overlappingcheckone\!!dimenf\!!dimenh \ifdone \else
+ \overlappingchecktwo\!!dimena\!!dimenc \ifdone \else
+ \overlappingchecktwo\!!dimena\!!dimend \ifdone \else
+ \overlappingchecktwo\!!dimenb\!!dimene \ifdone \else
+ \overlappingchecktwo\!!dimenb\!!dimenc \fi \fi \fi \fi \fi \fi \fi
+ \fi
+ \ifdone
+ \endgroup\expandafter\firstoftwoarguments
+ \else
+ \endgroup\expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {doifpositionsonsamepageelse,
+%D doifpositionsonthispageelse}
+%D
+%D Instead of letting the user handle fuzzy expansion, we
+%D provide a simple test on positione being on the same page.
+%D
+%D \starttyping
+%D \doifpositionsonsamepageelse{point a}{point b}
+%D {action when on same page}
+%D {action when not on same page}
+%D \doifpositionsonthispageelse{point a}{point b}
+%D {action when on this page}
+%D {action when not on this page}
+%D \stoptyping
+
+\def\dododoifpositionsonsamepageelse#1%
+ {\ifcase\scratchcounter
+ \scratchcounter\MPp{##}\donetrue
+ \else
+ \ifnum\scratchcounter=\MPp{#1}\relax\else\donefalse\fi
+ \fi}%
+
+\def\dodoifpositionsonsamepageelse#1#2%
+ {\begingroup
+ \scratchcounter#1\donefalse
+ \rawprocesscommalist[#2]\dododoifpositionsonsamepageelse
+ \ifdone
+ \endgroup\expandafter\firstoftwoarguments
+ \else
+ \endgroup\expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifpositionsonsamepageelse{\dodoifpositionsonsamepageelse\!!zerocount}
+\def\doifpositionsonthispageelse{\dodoifpositionsonsamepageelse\realfolio }
+
+%D Plugins:
+
+\let\MPv \MPplus
+\let\MPvv\MPrest
+
+\let\MPanchor\MPpos
+
+\let\POSp\MPp \let\POSx\MPx \let\POSy\MPy
+\let\POSh\MPh \let\POSd\MPd \let\POSw\MPw
+
+\protect \endinput
diff --git a/tex/context/base/anch-snc.mkii b/tex/context/base/anch-snc.mkii
new file mode 100644
index 000000000..cf5b35d69
--- /dev/null
+++ b/tex/context/base/anch-snc.mkii
@@ -0,0 +1,177 @@
+%D \module
+%D [ file=anch-snc,
+%D version=2003.12.01,
+%D title=\CONTEXT\ Anchoring Macros,
+%D subtitle=Synchronization,
+%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 Anchoring Macros / Synchronization}
+
+\unprotect
+
+\ifx\s!set \undefined \def\s!set {set} \fi
+\ifx\s!reset \undefined \def\s!reset {reset} \fi
+\ifx\s!preset \undefined \def\s!preset {preset} \fi
+\ifx\s!syncpos\undefined \def\s!syncpos{syncpos} \fi
+
+\def\definesyncpositions[#1]%
+ {\setcounter{\s!num:\s!syncpos:#1}{0}%
+ \doglobal\appendtoksonce\getvalue {\s!reset:\s!syncpos:#1}\to\resetsyncpositions
+ \doglobal\appendtoksonce\getvalue{\s!preset:\s!syncpos:#1}\to\presetsyncpositions
+ \setgvalue{\s!syncpos:#1}{sync_n[#1] := 0 ;}%
+ \setgvalue{\s!set:\s!syncpos:#1}{\dosetsyncpositions{#1}}}
+
+\def\syncposition
+ {\dodoubleempty\dosyncposition}
+
+\def\dosyncposition[#1][#2]%
+ {\letgvalue{\s!reset:\s!syncpos:#1}\relax
+ \letgvalue{\s!preset:\s!syncpos:#1}\relax
+ \dontleavehmode
+ \dodosyncposition{#1}{#2}\s!set
+ \ignorespaces}
+
+\def\doifelselastsyncposition#1#2%
+ {\doifelse{\lastsyncclass\lastsyncposition}{#1#2}}
+
+\def\dodosyncposition#1#2#3%
+ {\letgvalue{\s!reset:\s!syncpos:#1}\relax
+ \letgvalue{\s!preset:\s!syncpos:#1}\relax
+ \ifundefined{\s!syncpos:#1}%
+ \strut
+ \else
+ \pluscounter{\s!num:\s!syncpos:#1}%
+ \setsyncpositions{#1}%
+ % option: geen w/h, alleen p 0 0 0 data
+ \setpositionplus
+ {\s!syncpos:#1:\countervalue{\s!num:\s!syncpos:#1}}%
+ {#2}%
+ \hbox{\strut\traceposstring\llap\green{#3/\countervalue{\s!num:\s!syncpos:#1}/#1/#2>>}}%
+ \fi}
+
+\def\setsyncpositions#1%
+ {\enabletextarearegistration
+ \getvalue {\s!set:\s!syncpos:#1}%
+ \letgvalue{\s!set:\s!syncpos:#1}\relax}
+
+\def\dosetsyncpositions#1%
+ {\startnointerference % removing out of sync can best be done in mp
+ \!!dimena\maxdimen
+ \!!counta\zerocount
+ \!!countc\zerocount
+ \doloop
+ {\doifpositionelse{\s!syncpos:#1:\recurselevel}
+ {\!!dimenb\MPy{\s!syncpos:#1:\recurselevel}\relax
+ \!!countb\MPp{\s!syncpos:#1:\recurselevel}\relax
+ \ifnum\!!countb=\!!counta % same page
+ \ifdim\!!dimenb>\!!dimena
+ \donefalse % out of order nodes
+ \else
+ \donetrue % nodes in order
+ \fi
+ \else
+ \donetrue % different page
+ \fi
+ \ifdone
+ \!!counta\!!countb
+ \!!dimena\!!dimenb
+ \advance\!!countc\plusone
+ \edef\!!stringa{[#1][\the\!!countc]:=}%
+ \edef\!!stringc{\s!syncpos:#1:\the\!!countc}%
+ \edef\!!stringd{\MPplus\!!stringc{1}{0}}%
+ \setxvalue{\s!syncpos:#1}%
+ {\getsyncpositions{#1}%
+ sync_p \!!stringa \MPp \!!stringc ;
+ sync_xy\!!stringa \MPxy\!!stringc ;
+ sync_w \!!stringa \MPw \!!stringc ;
+ sync_h \!!stringa \MPh \!!stringc ;
+ sync_d \!!stringa \MPd \!!stringc ;
+ \ifx\!!stringd\empty \else sync_t \!!stringa \MPplus\!!stringc{1}{0} ; \fi}%
+ \fi}
+ {\setxvalue{\s!syncpos:#1}%
+ {\getsyncpositions{#1}%
+ sync_n[#1] := \the\!!countc ;}
+ \exitloop}}%
+ \stopnointerference}
+
+\def\getsyncpositions#1%
+ {\getvalue{\s!syncpos:#1}}
+
+\newtoks\resetsyncpositions
+\newtoks\presetsyncpositions
+
+\def\resyncposition {\dodoubleargument\doresyncposition}
+\def\presyncposition{\dodoubleargument\dopresyncposition}
+
+\def\dodoresyncposition #1#2{\dodosyncposition{#1}{#2}\s!reset}
+\def\dodopresyncposition#1#2{\dodosyncposition{#1}{#2}\s!preset}
+
+\def\doresyncposition [#1][#2]{\setxvalue{\s!reset :\s!syncpos:#1}{\noexpand\dodoresyncposition{#1}{#2}}}
+\def\dopresyncposition[#1][#2]{\setxvalue{\s!preset:\s!syncpos:#1}{\noexpand\dodopresyncposition{#1}{#2}}}
+
+\def\flushsyncpositions % this order !
+ {\begingroup
+ \the\presetsyncpositions
+ \the\resetsyncpositions
+ \endgroup}
+
+\def\flushsyncxxsets#1%
+ {\setbox\scratchbox\hbox{\the#1}%
+ \ifvoid\scratchbox\else
+ \prewordbreak \let\prewordbreak\relax % only once
+ \smashbox\scratchbox
+ \box\scratchbox
+ \fi}
+
+\def\flushsyncresets {\flushsyncxxsets\resetsyncpositions }
+\def\flushsyncpresets{\flushsyncxxsets\presetsyncpositions}
+
+% \appendtoks \flushsyncpositions \to \everypar
+% \appendtoks \flushsyncpositions \to \everyheadstart
+
+% \explicitneverypar -> in grid snapper, eerst testen
+%
+% \appendtoks \flushsyncpositions \to \neverypar
+
+\protect \endinput
+
+\starttext
+
+\definesyncpositions[1]
+
+\startuseMPgraphic{sync}
+ StartPage ;
+ \getsyncpositions{1} ;
+ SyncThreshold := 2LineHeight ;
+ SyncLeftOffset := -.5LeftMarginDistance ;
+ % SetSyncThreshold(1,3,3LineHeight) ;
+ SyncWidth := - (BackSpace + SyncLeftOffset) ;
+ SetSyncColor(1,1,\MPcolor{red}) ;
+ SetSyncColor(1,2,\MPcolor{green}) ;
+ SetSyncColor(1,3,\MPcolor{blue}) ;
+ SetSyncColor(1,4,\MPcolor{yellow}) ;
+ PrepareSyncTasks(1,true,true,false) ;
+ for i = 1 upto NOfSyncPaths :
+ fill SyncPaths[i]
+ withcolor TheSyncColor(CurrentSyncClass,sync_t[CurrentSyncClass][SyncTasks[i]]) ;
+ endfor ;
+ setbounds currentpicture to Page ;
+ StopPage ;
+\stopuseMPgraphic
+
+\defineoverlay[tempoverlay][\useMPgraphic{sync}]
+
+\setupbackgrounds[page][background=tempoverlay]
+
+\syncposition[1][1] \input ward \endgraf
+\syncposition[1][2] \input ward \endgraf
+\syncposition[1][3] \input ward \endgraf
+\syncposition[1][4] \input ward \endgraf
+
+\stoptext
diff --git a/tex/context/base/anch-snc.mkiv b/tex/context/base/anch-snc.mkiv
new file mode 100644
index 000000000..f976047c9
--- /dev/null
+++ b/tex/context/base/anch-snc.mkiv
@@ -0,0 +1,185 @@
+%D \module
+%D [ file=anch-snc,
+%D version=2003.12.01,
+%D title=\CONTEXT\ Anchoring Macros,
+%D subtitle=Synchronization,
+%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.
+
+% this can be optimized (will do when used again)
+
+\writestatus{loading}{ConTeXt Anchoring Macros / Synchronization}
+
+\unprotect
+
+\ifx\s!set \undefined \def\s!set {set} \fi
+\ifx\s!reset \undefined \def\s!reset {reset} \fi
+\ifx\s!preset \undefined \def\s!preset {preset} \fi
+\ifx\s!syncpos\undefined \def\s!syncpos{syncpos} \fi
+
+\unexpanded\def\definesyncpositions[#1]%
+ {\global\let\flushsyncpositions\doflushsyncpositions % only when used
+ \setcounter{\s!num:\s!syncpos:#1}{0}%
+ \doglobal\appendtoksonce\csname\s!reset :\s!syncpos:#1\endcsname\to\resetsyncpositions
+ \doglobal\appendtoksonce\csname\s!preset:\s!syncpos:#1\endcsname\to\presetsyncpositions
+% to be tested:
+% \doglobal\expandafter\appendtoksonce\csname\s!reset :\s!syncpos:#1\endcsname\to\resetsyncpositions
+% \doglobal\expandafter\appendtoksonce\csname\s!preset:\s!syncpos:#1\endcsname\to\presetsyncpositions
+ \setgvalue{\s!syncpos:#1}{sync_n[#1] := 0 ;}%
+ \setgvalue{\s!set:\s!syncpos:#1}{\dosetsyncpositions{#1}}}
+
+\def\syncposition
+ {\dodoubleempty\dosyncposition}
+
+\def\dosyncposition[#1][#2]%
+ {\letgvalue{\s!reset :\s!syncpos:#1}\relax
+ \letgvalue{\s!preset:\s!syncpos:#1}\relax
+ \dontleavehmode
+ \dodosyncposition{#1}{#2}\s!set
+ \ignorespaces}
+
+\def\doifelselastsyncposition#1#2%
+ {\doifelse{\lastsyncclass\lastsyncposition}{#1#2}}
+
+\def\dodosyncposition#1#2#3%
+ {\letgvalue{\s!reset:\s!syncpos:#1}\relax
+ \letgvalue{\s!preset:\s!syncpos:#1}\relax
+ \ifcsname\s!syncpos:#1\endcsname
+ \pluscounter{\s!num:\s!syncpos:#1}%
+ \setsyncpositions{#1}%
+ % option: geen w/h, alleen p 0 0 0 data
+ \setpositionplus
+ {\s!syncpos:#1:\countervalue{\s!num:\s!syncpos:#1}}%
+ {#2}%
+ \hbox{\strut\traceposstring\llap\green{#3/\countervalue{\s!num:\s!syncpos:#1}/#1/#2>>}}%
+ \else
+ \strut
+ \fi}
+
+\def\setsyncpositions#1%
+ {\enabletextarearegistration
+ \getvalue {\s!set:\s!syncpos:#1}%
+ \letgvalue{\s!set:\s!syncpos:#1}\relax}
+
+\def\dosetsyncpositions#1%
+ {\startnointerference % removing out of sync can best be done in mp
+ \!!dimena\maxdimen
+ \!!counta\zerocount
+ \!!countc\zerocount
+ \doloop
+ {\doifpositionelse{\s!syncpos:#1:\recurselevel}
+ {\!!dimenb\MPy{\s!syncpos:#1:\recurselevel}\relax
+ \!!countb\MPp{\s!syncpos:#1:\recurselevel}\relax
+ \ifnum\!!countb=\!!counta % same page
+ \ifdim\!!dimenb>\!!dimena
+ \donefalse % out of order nodes
+ \else
+ \donetrue % nodes in order
+ \fi
+ \else
+ \donetrue % different page
+ \fi
+ \ifdone
+ \!!counta\!!countb
+ \!!dimena\!!dimenb
+ \advance\!!countc\plusone
+ \edef\!!stringa{[#1][\the\!!countc]:=}%
+ \edef\!!stringc{\s!syncpos:#1:\the\!!countc}%
+ \edef\!!stringd{\MPplus\!!stringc{1}{0}}%
+ \setxvalue{\s!syncpos:#1}%
+ {\getsyncpositions{#1}%
+ sync_p \!!stringa \MPp \!!stringc ;
+ sync_xy\!!stringa \MPxy\!!stringc ;
+ sync_w \!!stringa \MPw \!!stringc ;
+ sync_h \!!stringa \MPh \!!stringc ;
+ sync_d \!!stringa \MPd \!!stringc ;
+ \ifx\!!stringd\empty \else sync_t \!!stringa \MPplus\!!stringc{1}{0} ; \fi}%
+ \fi}
+ {\setxvalue{\s!syncpos:#1}%
+ {\getsyncpositions{#1}%
+ sync_n[#1] := \the\!!countc ;}
+ \exitloop}}%
+ \stopnointerference}
+
+\def\getsyncpositions#1%
+ {\getvalue{\s!syncpos:#1}}
+
+\newtoks\resetsyncpositions
+\newtoks\presetsyncpositions
+
+\def\resyncposition {\dodoubleargument\doresyncposition}
+\def\presyncposition{\dodoubleargument\dopresyncposition}
+
+\def\dodoresyncposition #1#2{\dodosyncposition{#1}{#2}\s!reset}
+\def\dodopresyncposition#1#2{\dodosyncposition{#1}{#2}\s!preset}
+
+\def\doresyncposition [#1][#2]{\setxvalue{\s!reset :\s!syncpos:#1}{\noexpand\dodoresyncposition{#1}{#2}}}
+\def\dopresyncposition[#1][#2]{\setxvalue{\s!preset:\s!syncpos:#1}{\noexpand\dodopresyncposition{#1}{#2}}}
+
+\let\flushsyncpositions\relax
+
+\def\doflushsyncpositions % this order !
+ {\begingroup
+ \the\presetsyncpositions
+ \the\resetsyncpositions
+ \endgroup}
+
+\def\flushsyncxxsets#1%
+ {\setbox\scratchbox\hbox{\the#1}%
+ \ifvoid\scratchbox\else
+ \prewordbreak \let\prewordbreak\relax % only once
+ \smashbox\scratchbox
+ \box\scratchbox
+ \fi}
+
+\def\flushsyncresets {\flushsyncxxsets\resetsyncpositions }
+\def\flushsyncpresets{\flushsyncxxsets\presetsyncpositions}
+
+% \appendtoks \flushsyncpositions \to \everypar
+% \appendtoks \flushsyncpositions \to \everyheadstart
+
+% \explicitneverypar -> in grid snapper, eerst testen
+%
+% \appendtoks \flushsyncpositions \to \neverypar
+
+\protect \endinput
+
+\starttext
+
+\definesyncpositions[1]
+
+\startuseMPgraphic{sync}
+ StartPage ;
+ \getsyncpositions{1} ;
+ SyncThreshold := 2LineHeight ;
+ SyncLeftOffset := -.5LeftMarginDistance ;
+ % SetSyncThreshold(1,3,3LineHeight) ;
+ SyncWidth := - (BackSpace + SyncLeftOffset) ;
+ SetSyncColor(1,1,\MPcolor{red}) ;
+ SetSyncColor(1,2,\MPcolor{green}) ;
+ SetSyncColor(1,3,\MPcolor{blue}) ;
+ SetSyncColor(1,4,\MPcolor{yellow}) ;
+ PrepareSyncTasks(1,true,true,false) ;
+ for i = 1 upto NOfSyncPaths :
+ fill SyncPaths[i]
+ withcolor TheSyncColor(CurrentSyncClass,sync_t[CurrentSyncClass][SyncTasks[i]]) ;
+ endfor ;
+ setbounds currentpicture to Page ;
+ StopPage ;
+\stopuseMPgraphic
+
+\defineoverlay[tempoverlay][\useMPgraphic{sync}]
+
+\setupbackgrounds[page][background=tempoverlay]
+
+\syncposition[1][1] \input ward \endgraf
+\syncposition[1][2] \input ward \endgraf
+\syncposition[1][3] \input ward \endgraf
+\syncposition[1][4] \input ward \endgraf
+
+\stoptext
diff --git a/tex/context/base/attr-ini.lua b/tex/context/base/attr-ini.lua
new file mode 100644
index 000000000..81c2f4744
--- /dev/null
+++ b/tex/context/base/attr-ini.lua
@@ -0,0 +1,648 @@
+if not modules then modules = { } end modules ['attr-ini'] = {
+ version = 1.001,
+ comment = "companion to attr-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this module is being reconstructed
+-- we can also do the nsnone via a metatable and then also se index 0
+
+local type = type
+local format, gmatch = string.format, string.gmatch
+local concat = table.concat
+local texsprint = tex.sprint
+
+local ctxcatcodes = tex.ctxcatcodes
+local unsetvalue = attributes.unsetvalue
+
+-- todo: document this but first reimplement this as it reflects the early
+-- days of luatex / mkiv and we have better ways now
+
+-- nb: attributes: color etc is much slower than normal (marks + literals) but ...
+-- nb. too many "0 g"s
+
+nodes = nodes or { }
+states = states or { }
+shipouts = shipouts or { }
+
+-- We can distinguish between rules and glyphs but it's not worth the trouble. A
+-- first implementation did that and while it saves a bit for glyphs and rules, it
+-- costs more resourses for transparencies. So why bother.
+
+--
+-- colors
+--
+
+-- we can also collapse the two attributes: n, n+1, n+2 and then
+-- at the tex end add 0, 1, 2, but this is not faster and less
+-- flexible (since sometimes we freeze color attribute values at
+-- the lua end of the game
+--
+-- we also need to store the colorvalues because we need then in mp
+--
+-- This is a compromis between speed and simplicity. We used to store the
+-- values and data in one array, which made in neccessary to store the
+-- converters that need node constructor into strings and evaluate them
+-- at runtime (after reading from storage). Think of:
+--
+-- colors.strings = colors.strings or { }
+--
+-- if environment.initex then
+-- colors.strings[color] = "return colors." .. colorspace .. "(" .. concat({...},",") .. ")"
+-- end
+--
+-- storage.register("colors/data", colors.strings, "colors.data") -- evaluated
+--
+-- We assume that only processcolors are defined in the format.
+
+colors = colors or { }
+colors.data = colors.data or { }
+colors.values = colors.values or { }
+colors.registered = colors.registered or { }
+
+colors.weightgray = true
+colors.attribute = attributes.private('color')
+colors.selector = attributes.private('colormodel')
+colors.default = 1
+colors.main = nil
+colors.triggering = true
+
+storage.register("colors/values", colors.values, "colors.values")
+storage.register("colors/registered", colors.registered, "colors.registered")
+
+local templates = {
+ rgb = "r:%s:%s:%s",
+ cmyk = "c:%s:%s:%s:%s",
+ gray = "s:%s",
+ spot = "p:%s:%s:%s:%s"
+}
+
+local models = {
+ [interfaces.variables.none] = unsetvalue,
+ black = unsetvalue,
+ bw = unsetvalue,
+ all = 1,
+ gray = 2,
+ rgb = 3,
+ cmyk = 4,
+}
+
+colors.model = "all"
+
+local data = colors.data
+local values = colors.values
+local registered = colors.registered
+
+local numbers = attributes.numbers
+local list = attributes.list
+
+local min, max, floor = math.min, math.max, math.floor
+
+local nodeinjections = backends.nodeinjections
+local codeinjections = backends.codeinjections
+local registrations = backends.registrations
+
+local function rgbtocmyk(r,g,b) -- we could reduce
+ return 1-r, 1-g, 1-b, 0
+end
+
+local function cmyktorgb(c,m,y,k)
+ return 1.0 - min(1.0,c+k), 1.0 - min(1.0,m+k), 1.0 - min(1.0,y+k)
+end
+
+local function rgbtogray(r,g,b)
+ if colors.weightgray then
+ return .30*r+.59*g+.11*b
+ else
+ return r/3+g/3+b/3
+ end
+end
+
+local function cmyktogray(c,m,y,k)
+ return rgbtogray(cmyktorgb(c,m,y,k))
+end
+
+-- http://en.wikipedia.org/wiki/HSI_color_space
+-- http://nl.wikipedia.org/wiki/HSV_(kleurruimte)
+
+
+local function hsvtorgb(h,s,v)
+ -- h = h % 360
+ local hd = h/60
+ local hf = floor(hd)
+ local hi = hf % 6
+ -- local f = hd - hi
+ local f = hd - hf
+ local p = v * (1 - s)
+ local q = v * (1 - f * s)
+ local t = v * (1 - (1 - f) * s)
+ if hi == 0 then
+ return v, t, p
+ elseif hi == 1 then
+ return q, v, p
+ elseif hi == 2 then
+ return p, v, t
+ elseif hi == 3 then
+ return p, q, v
+ elseif hi == 4 then
+ return t, p, v
+ elseif hi == 5 then
+ return v, p, q
+ else
+ print("error in hsv -> rgb",hi,h,s,v)
+ end
+end
+
+function rgbtohsv(r,g,b)
+ local offset, maximum, other_1, other_2
+ if r >= g and r >= b then
+ offset, maximum, other_1, other_2 = 0, r, g, b
+ elseif g >= r and g >= b then
+ offset, maximum, other_1, other_2 = 2, g, b, r
+ else
+ offset, maximum, other_1, other_2 = 4, b, r, g
+ end
+ if maximum == 0 then
+ return 0, 0, 0
+ end
+ local minimum = other_1 < other_2 and other_1 or other_2
+ if maximum == minimum then
+ return 0, 0, maximum
+ end
+ local delta = maximum - minimum
+ return (offset + (other_1-other_2)/delta)*60, delta/maximum, maximum
+end
+
+function graytorgb(s) -- unweighted
+ return 1-s, 1-s, 1-s
+end
+
+function hsvtogray(h,s,v)
+ return rgb_to_gray(hsv_to_rgb(h,s,v))
+end
+
+function grayto_hsv(s)
+ return 0, 0, s
+end
+
+colors.rgbtocmyk = rgbtocmyk
+colors.rgbtogray = rgbtogray
+colors.cmyktorgb = cmyktorgb
+colors.cmyktogray = cmyktogray
+colors.rgbtohsv = rgbtohsv
+colors.hsvtorgb = hsvtorgb
+colors.hsvtogray = hsvtogray
+colors.graytohsv = graytohsv
+
+-- we can share some *data by using s, rgb and cmyk hashes, but
+-- normally the amount of colors is not that large; storing the
+-- components costs a bit of extra runtime, but we expect to gain
+-- some back because we have them at hand; the number indicates the
+-- default color space
+
+function colors.gray(s)
+ return { 2, s, s, s, s, 0, 0, 0, 1-s }
+end
+
+function colors.rgb(r,g,b)
+ local s = rgbtogray(r,g,b)
+ local c, m, y, k = rgbtocmyk(r,g,b)
+ return { 3, s, r, g, b, c, m, y, k }
+end
+
+function colors.cmyk(c,m,y,k)
+ local s = cmyktogray(c,m,y,k)
+ local r, g, b = cmyktorgb(c,m,y,k)
+ return { 4, s, r, g, b, c, m, y, k }
+end
+
+--~ function colors.spot(parent,f,d,p)
+--~ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
+--~ end
+
+function colors.spot(parent,f,d,p)
+ if type(p) == "number" then
+ local n = list[numbers.color][parent] -- hard coded ref to color number
+ if n then
+ local v = values[n]
+ if v then
+ -- the via cmyk hack is dirty, but it scales better
+ local c, m, y, k = p*v[6], p*v[7], p*v[8], p*v[8]
+ local r, g, b = cmyktorgb(c,m,y,k)
+ local s = cmyktogray(c,m,y,k)
+ return { 5, s, r, g, b, c, m, y, k, parent, f, d, p }
+ end
+ end
+ else
+ -- todo, multitone (maybe p should be a table)
+ end
+ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
+end
+
+local function graycolor(...) graycolor = nodeinjections.graycolor return graycolor(...) end
+local function rgbcolor (...) rgbcolor = nodeinjections.rgbcolor return rgbcolor (...) end
+local function cmykcolor(...) cmykcolor = nodeinjections.cmykcolor return cmykcolor(...) end
+local function spotcolor(...) spotcolor = nodeinjections.spotcolor return spotcolor(...) end
+
+local function extender(colors,key)
+ if key == "none" then
+ local d = graycolor(0)
+ colors.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ local v = values[n]
+ local d
+ if not v then
+ local gray = graycolor(0)
+ d = { gray, gray, gray, gray }
+ logs.report("attributes","unable to revive color %s",n or "?")
+ else
+ local kind = v[1]
+ if kind == 2 then
+ local gray= graycolor(v[2])
+ d = { gray, gray, gray, gray }
+ elseif kind == 3 then
+ local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9])
+ d = { rgb, gray, rgb, cmyk }
+ elseif kind == 4 then
+ local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9])
+ d = { cmyk, gray, rgb, cmyk }
+ elseif kind == 5 then
+ local spot = spotcolor(v[10],v[11],v[12],v[13])
+ -- d = { spot, gray, rgb, cmyk }
+ d = { spot, spot, spot, spot }
+ end
+ end
+ data[n] = d
+ return d
+end
+
+setmetatable(colors, { __index = extender })
+setmetatable(colors.data, { __index = reviver })
+
+function colors.filter(n)
+ return concat(data[n],":",5)
+end
+
+function colors.setmodel(name,weightgray)
+ colors.model = name
+ colors.default = models[name] or 1
+ colors.weightgray = weightgray ~= false
+ return colors.default
+end
+
+function colors.register(name, colorspace, ...) -- passing 9 vars is faster (but not called that often)
+ local stamp = format(templates[colorspace],...)
+ local color = registered[stamp]
+ if not color then
+ color = #values + 1
+ values[color] = colors[colorspace](...)
+ registered[stamp] = color
+ -- colors.reviver(color)
+ end
+ if name then
+ list[colors.attribute][name] = color -- not grouped, so only global colors
+ end
+ return registered[stamp]
+end
+
+function colors.value(id)
+ return values[id]
+end
+
+shipouts.handle_color = nodes.install_attribute_handler {
+ name = "color",
+ namespace = colors,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.selective,
+ resolver = function() return colors.main end,
+}
+
+function colors.enable()
+ tasks.enableaction("shipouts","shipouts.handle_color")
+end
+
+-- transparencies
+
+transparencies = transparencies or { }
+transparencies.registered = transparencies.registered or { }
+transparencies.data = transparencies.data or { }
+transparencies.values = transparencies.values or { }
+transparencies.triggering = true
+transparencies.attribute = attributes.private('transparency')
+
+storage.register("transparencies/registered", transparencies.registered, "transparencies.registered")
+storage.register("transparencies/values", transparencies.values, "transparencies.values")
+
+local registered = transparencies.registered -- we could use a 2 dimensional table instead
+local data = transparencies.data
+local values = transparencies.values
+local template = "%s:%s"
+
+local function inject_transparency (...)
+ inject_transparency = nodeinjections.transparency
+ return inject_transparency(...)
+end
+
+local function register_transparency(...)
+ register_transparency = registrations.transparency
+ return register_transparency(...)
+end
+
+function transparencies.register(name,a,t,force) -- name is irrelevant here (can even be nil)
+ -- Force needed here for metapost converter. We could always force
+ -- but then we'd end up with transparencies resources even if we
+ -- would not use transparencies (but define them only). This is
+ -- somewhat messy.
+ local stamp = format(template,a,t)
+ local n = registered[stamp]
+ if not n then
+ n = #values + 1
+ values[n] = { a, t }
+ registered[stamp] = n
+ if force then
+ register_transparency(n,a,t)
+ end
+ elseif force and not data[n] then
+ register_transparency(n,a,t)
+ end
+ return registered[stamp]
+end
+
+local function extender(transparencies,key)
+ if key == "none" then
+ local d = inject_transparency(0)
+ transparencies.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ local v = values[n]
+ local d
+ if not v then
+ d = inject_transparency(0)
+ else
+ d = inject_transparency(n)
+ register_transparency(n,v[1],v[2])
+ end
+ data[n] = d
+ return d
+end
+
+setmetatable(transparencies, { __index = extender })
+setmetatable(transparencies.data, { __index = reviver }) -- register if used
+
+-- check if there is an identity
+
+function transparencies.value(id)
+ return values[id]
+end
+
+shipouts.handle_transparency = nodes.install_attribute_handler {
+ name = "transparency",
+ namespace = transparencies,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.process,
+}
+
+function transparencies.enable()
+ tasks.enableaction("shipouts","shipouts.handle_transparency")
+end
+
+--- colorintents: overprint / knockout
+
+colorintents = colorintents or { }
+colorintents.data = colorintents.data or { }
+colorintents.attribute = attributes.private('colorintent')
+
+colorintents.registered = {
+ overprint = 1,
+ knockout = 2,
+}
+
+local data, registered = colorintents.data, colorintents.registered
+
+local function extender(colorintents,key)
+ if key == "none" then
+ local d = data[2]
+ colorintents.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ if n == 1 then
+ local d = nodeinjections.overprint() -- called once
+ data[1] = d
+ return d
+ elseif n == 2 then
+ local d = nodeinjections.knockout() -- called once
+ data[2] = d
+ return d
+ end
+end
+
+setmetatable(colorintents, { __index = extender })
+setmetatable(colorintents.data, { __index = reviver })
+
+function colorintents.register(stamp)
+ return registered[stamp] or registered.overprint
+end
+
+shipouts.handle_colorintent = nodes.install_attribute_handler {
+ name = "colorintent",
+ namespace = colorintents,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.process,
+}
+
+function colorintents.enable()
+ tasks.enableaction("shipouts","shipouts.handle_colorintent")
+end
+
+--- negative / positive
+
+negatives = negatives or { }
+negatives.data = negatives.data or { }
+negatives.attribute = attributes.private("negative")
+
+negatives.registered = {
+ positive = 1,
+ negative = 2,
+}
+
+local data, registered = negatives.data, negatives.registered
+
+local function extender(negatives,key)
+ if key == "none" then
+ local d = data[1]
+ negatives.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ if n == 1 then
+ local d = nodeinjections.positive() -- called once
+ data[1] = d
+ return d
+ elseif n == 2 then
+ local d = nodeinjections.negative() -- called once
+ data[2] = d
+ return d
+ end
+end
+
+setmetatable(negatives, { __index = extender })
+setmetatable(negatives.data, { __index = reviver })
+
+function negatives.register(stamp)
+ return registered[stamp] or registered.positive
+end
+
+shipouts.handle_negative = nodes.install_attribute_handler {
+ name = "negative",
+ namespace = negatives,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.process,
+}
+
+function negatives.enable()
+ tasks.enableaction("shipouts","shipouts.handle_negative")
+end
+
+-- effects -- can be optimized (todo: metatables)
+
+effects = effects or { }
+effects.data = effects.data or { }
+effects.values = effects.values or { }
+effects.registered = effects.registered or { }
+effects.stamp = "%s:%s:%s"
+effects.attribute = attributes.private("effect")
+
+storage.register("effects/registered", effects.registered, "effects.registered")
+storage.register("effects/values", effects.values, "effects.values")
+
+local data, registered, values = effects.data, effects.registered, effects.values
+
+-- valid effects: normal inner outer both hidden (stretch,rulethickness,effect)
+
+local function effect(...) effect = nodeinjections.effect return effect(...) end
+
+local function extender(effects,key)
+ if key == "none" then
+ local d = effect(0,0,0)
+ effects.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ local e = values[n] -- we could nil values[n] now but hardly needed
+ local d = effect(e[1],e[2],e[3])
+ data[n] = d
+ return d
+end
+
+setmetatable(effects, { __index = extender })
+setmetatable(effects.data, { __index = reviver })
+
+function effects.register(effect,stretch,rulethickness)
+ local stamp = format(effects.stamp,effect,stretch,rulethickness)
+ local n = registered[stamp]
+ if not n then
+ n = #values + 1
+ values[n] = { effect, stretch, rulethickness }
+ registered[stamp] = n
+ end
+ return n
+end
+
+shipouts.handle_effect = nodes.install_attribute_handler {
+ name = "effect",
+ namespace = effects,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.process,
+}
+
+function effects.enable()
+ tasks.enableaction("shipouts","shipouts.handle_effect")
+end
+
+-- layers (ugly code, due to no grouping and such); currently we use exclusive layers
+-- but when we need it stacked layers might show up too; the next function based
+-- approach can be replaced by static (metatable driven) resolvers
+
+viewerlayers = viewerlayers or { }
+viewerlayers.data = viewerlayers.data or { }
+viewerlayers.registered = viewerlayers.registered or { }
+viewerlayers.values = viewerlayers.values or { }
+viewerlayers.listwise = viewerlayers.listwise or { }
+viewerlayers.attribute = attributes.private("viewerlayer")
+
+storage.register("viewerlayers/registered", viewerlayers.registered, "viewerlayers.registered")
+storage.register("viewerlayers/values", viewerlayers.values, "viewerlayers.values")
+
+local data = viewerlayers.data
+local values = viewerlayers.values
+local listwise = viewerlayers.listwise
+local registered = viewerlayers.registered
+local template = "%s"
+
+-- stacked
+
+local function extender(viewerlayers,key)
+ if key == "none" then
+ local d = nodeinjections.stoplayer()
+ viewerlayers.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ local d = nodeinjections.startlayer(values[n])
+ data[n] = d
+ return d
+end
+
+setmetatable(viewerlayers, { __index = extender })
+setmetatable(viewerlayers.data, { __index = reviver })
+
+local function initializer(...)
+ return states.initialize(...)
+end
+
+viewerlayers.register = function(name,lw) -- if not inimode redefine data[n] in first call
+ local stamp = format(template,name)
+ local n = registered[stamp]
+ if not n then
+ n = #values + 1
+ values[n] = name
+ registered[stamp] = n
+ listwise[n] = lw or false
+ end
+ return registered[stamp] -- == n
+end
+
+shipouts.handle_viewerlayer = nodes.install_attribute_handler {
+ name = "viewerlayer",
+ namespace = viewerlayers,
+ initializer = initializer,
+ finalizer = states.finalize,
+ processor = states.stacked,
+}
+
+function viewerlayers.enable()
+ tasks.enableaction("shipouts","shipouts.handle_viewerlayer")
+end
diff --git a/tex/context/base/attr-ini.mkiv b/tex/context/base/attr-ini.mkiv
new file mode 100644
index 000000000..87d06c48a
--- /dev/null
+++ b/tex/context/base/attr-ini.mkiv
@@ -0,0 +1,170 @@
+%D \module
+%D [ file=attr-ini,
+%D version=2007.06.06,
+%D title=\CONTEXT\ Attribute Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%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 Attribute Macros / Initialization}
+
+%D Although it's still somewhat experimental, here we introduce code
+%D related to attributes.
+
+\unprotect
+
+\registerctxluafile{attr-ini}{1.001}
+
+%D This might move:
+
+\def\pushattribute#1%
+ {\global\advance\csname\??ae:\string#1\endcsname\plusone
+ \global\expandafter\mathchardef\csname\??ae:\string#1:\number\csname\??ae:\string#1\endcsname\endcsname\attribute#1}
+
+\def\popattribute#1%
+ {\attribute#1\csname\??ae:\string#1:\number\csname\??ae:\string#1\endcsname\endcsname
+ \global\advance\csname\??ae:\string#1\endcsname\minusone}
+
+\def\installattributestack#1%
+ {\expandafter\newcount\csname\??ae:\string#1\endcsname}
+
+%D For the moment we put this here (later it will move to where it's used):
+
+\definesystemattribute[state]
+\definesystemattribute[skip]
+\definesystemattribute[penalty]
+\definesystemattribute[colormodel][global] \chardef\colormodelattribute \dogetattributeid{colormodel}
+\definesystemattribute[color] \chardef\colorattribute \dogetattributeid{color}
+\definesystemattribute[transparency] \chardef\transparencyattribute \dogetattributeid{transparency}
+\definesystemattribute[background] \chardef\backgroundattribute \dogetattributeid{background}
+\definesystemattribute[colorintent] \chardef\colorintentattribute \dogetattributeid{colorintent}
+\definesystemattribute[negative] \chardef\negativeattribute \dogetattributeid{negative}
+\definesystemattribute[effect] \chardef\effectattribute \dogetattributeid{effect}
+\definesystemattribute[viewerlayer] \chardef\viewerlayerattribute \dogetattributeid{viewerlayer}
+\definesystemattribute[layoutcomponent] \chardef\layoutcomponentattribute\dogetattributeid{layoutcomponent}
+\definesystemattribute[reference] \chardef\referenceattribute \dogetattributeid{reference}
+\definesystemattribute[destination] \chardef\destinationattribute \dogetattributeid{destination}
+\definesystemattribute[graphicvadjust] \chardef\graphicvadjustattribute \dogetattributeid{graphicvadjust}
+\definesystemattribute[ruled] \chardef\ruledattribute \dogetattributeid{ruled}
+\definesystemattribute[shifted] \chardef\shiftedattribute \dogetattributeid{shifted}
+
+% \definesystemattribute[ignore]
+%
+% \edef\startignorecontent{\dosetattribute{ignore}\plusone}
+% \edef\stopignorecontent {\doresetattribute{ignore}}
+
+% todo: no need for 'color' argument, we can set that once at startup; currently
+% a bit inconsistent
+
+% 1=off 2=gray 3=spot 4=rgb 5=cmyk 6=cmy % only 1/2/4/5 are supported
+%
+% We could combine this in one attribute but this is not faster and also
+% less flexible because sometimes we want to freeze the attribute bit.
+%
+% Watch out: real color support will be implemented later.
+
+\newcount\currentcolormodel
+
+\def\dosetcolormodel#1%
+ {\currentcolormodel\ctxlua{tex.print(colors.setmodel('#1'))}%
+ \attribute\colormodelattribute\currentcolormodel}
+
+\dosetcolormodel{all}
+
+\appendtoks
+ \dosetcolormodel{all}% redundant?
+\to \everyjob
+
+\def\registerrgbcolor #1#2#3#4{\ctxlua{colors.register('#1','rgb' ,#2,#3,#4)}}
+\def\registercmykcolor#1#2#3#4#5{\ctxlua{colors.register('#1','cmyk',#2,#3,#4,#5)}}
+\def\registergraycolor #1#2{\ctxlua{colors.register('#1','gray',#2)}}
+
+% transparency
+
+\def\registertransparency#1#2#3%
+ {\setevalue{(ts:#1)}{\attribute\transparencyattribute\ctxlua{tex.write(transparencies.register(#2,#3))} }}
+
+\def\sometransparencyswitch#1{\csname(ts:#1)\endcsname}
+
+\def\sometransparencyswitch
+ {\ctxlua{transparencies.enable()}%
+ \gdef\sometransparencyswitch##1{\csname(ts:##1)\endcsname}%
+ \sometransparencyswitch}
+
+% \registertransparency {one} {1} {.5}
+% \registertransparency {two} {1} {.6}
+
+% overprint
+
+\def\registercolorintent#1#2%
+ {\setevalue{(os:#1)}{\attribute\colorintentattribute\ctxlua{tex.write(colorintents.register('#2'))} }}
+
+\def\dotriggercolorintent
+ {\ctxlua{colorintents.enable()}%
+ \gdef\dotriggercolorintent##1{\csname(os:##1)\endcsname}%
+ \dotriggercolorintent}
+
+\registercolorintent{knockout} {knockout}
+\registercolorintent{overprint}{overprint}
+
+\installattributestack\colorintentattribute
+
+\setevalue{(os:#\v!none}{\attribute\colorintentattribute\attributeunsetvalue} % does this work out ok?
+
+% negative
+
+\def\registernegative#1#2%
+ {\setevalue{(ns:#1)}{\attribute\negativeattribute\ctxlua{tex.write(negatives.register('#2'))} }}
+
+\def\dotriggernegative
+ {\ctxlua{negatives.enable()}%
+ \gdef\dotriggernegative##1{\csname(ns:##1)\endcsname}%
+ \dotriggernegative}
+
+\registernegative{positive}{positive}
+\registernegative{negative}{negative}
+
+% effect
+
+\def\registereffect#1#2#3% #2=stretch #3=rulethickness
+ {\setxvalue{(es:#1:#2:\number\dimexpr#3\relax)}%
+ {\attribute\effectattribute\ctxlua{tex.write(effects.register('#1',#2,\number\dimexpr#3\relax))} }}
+
+\def\dotriggereffect
+ {\ctxlua{effects.enable()}%
+ \gdef\dotriggereffect##1##2##3%
+ {\ifcsname(es:##1:##2:\number\dimexpr##3\relax)\endcsname\else\registereffect{##1}{##2}{##3}\fi
+ \csname(es:##1:##2:\number\dimexpr##3\relax)\endcsname}%
+ \dotriggereffect}
+
+% \registereffect{normal}
+% \registereffect{inner}
+% \registereffect{outer}
+% \registereffect{both}
+% \registereffect{hidden}
+
+% viewerlayers (will probably change a bit)
+
+% needs to work over stopitemize grouping etc
+
+\def\registerviewerlayer#1#2% global !
+ {\setxvalue{(vl:#1)}{\global\attribute\viewerlayerattribute\ctxlua{tex.write(viewerlayers.register('#2'))} }}
+
+\setevalue{(vl:)}{\global\attribute\viewerlayerattribute\attributeunsetvalue}
+
+\def\dotriggerviewerlayer
+ {\ctxlua{viewerlayers.enable()}%
+ \gdef\dotriggerviewerlayer##1{\csname(vl:##1)\endcsname}%
+ \dotriggerviewerlayer}
+
+\protect \endinput
+
+% test case
+%
+% {\green \hbox to \hsize{\leaders\hrule \hfill a}\par}
+% {\red \hbox to \hsize{\leaders\hbox{x}\hfill a}\par}
diff --git a/tex/context/base/back-ini.lua b/tex/context/base/back-ini.lua
new file mode 100644
index 000000000..12a487dd4
--- /dev/null
+++ b/tex/context/base/back-ini.lua
@@ -0,0 +1,143 @@
+if not modules then modules = { } end modules ['back-ini'] = {
+ version = 1.001,
+ comment = "companion to back-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+backends = backends or { }
+
+local trace_backend = false
+
+local function nothing() return nil end
+
+backends.nothing = nothing
+
+backends.nodeinjections = {
+ rgbcolor = nothing,
+ cmykcolor = nothing,
+ graycolor = nothing,
+ spotcolor = nothing,
+ transparency = nothing,
+ overprint = nothing,
+ knockout = nothing,
+ positive = nothing,
+ negative = nothing,
+ effect = nothing,
+ startlayer = nothing,
+ stoplayer = nothing,
+ switchlayer = nothing,
+
+ reference = nothing,
+ destination = nothing,
+
+}
+
+backends.codeinjections = {
+
+ prerollreference = nothing,
+
+ insertmovie = nothing,
+ insertsound = nothing,
+
+ presetsymbollist = nothing,
+ registersymbol = nothing,
+ registeredsymbol = nothing,
+
+ registercomment = nothing,
+ embedfile = nothing,
+ attachfile = nothing,
+ adddocumentinfo = nothing,
+ setupidentity = nothing,
+ setpagetransition = nothing,
+ defineviewerlayer = nothing,
+ addbookmarks = nothing,
+ addtransparencygroup = nothing,
+
+ typesetfield = nothing,
+ doiffieldelse = nothing,
+ doiffieldgroupelse = nothing,
+ definefield = nothing,
+ clonefield = nothing,
+ definefieldset = nothing,
+ getfieldgroup = nothing,
+ setformsmethod = nothing,
+ getdefaultfieldvalue = nothing,
+
+ setupcanvas = nothing,
+
+ initializepage = nothing,
+ initializedocument = nothing,
+ finalizepage = nothing,
+ finalizedocument = nothing,
+
+ flushpageactions = nothing,
+ flushdocumentactions = nothing,
+
+ insertrenderingwindow = nothing,
+ processrendering = nothing,
+ kindofrendering = nothing,
+ flushrenderingwindow = nothing,
+
+ setfigurecolorspace = nothing,
+ setfigurealternative = nothing,
+
+}
+
+backends.registrations = {
+ grayspotcolor = nothing,
+ rgbspotcolor = nothing,
+ cmykspotcolor = nothing,
+ grayindexcolor = nothing,
+ rgbindexcolor = nothing,
+ cmykindexcolor = nothing,
+ spotcolorname = nothing,
+ transparency = nothing,
+}
+
+local nodeinjections = backends.nodeinjections
+local codeinjections = backends.codeinjections
+local registrations = backends.registrations
+
+backends.current = "unknown"
+
+function backends.install(what)
+ if type(what) == "string" then
+ local backend = backends[what]
+ if backend then
+ if trace_backend then
+ logs.report("backend", "initializing backend %s (%s)",what,backend.comment or "no comment")
+ end
+ backends.current = what
+ for _, category in next, { "nodeinjections", "codeinjections", "registrations"} do
+ local plugin = backend[category]
+ if plugin then
+ local whereto = backends[category]
+ for name, meaning in next, whereto do
+ if plugin[name] then
+ whereto[name] = plugin[name]
+ -- logs.report("backend", "installing function %s in category %s of %s",name,category,what)
+ elseif trace_backend then
+ logs.report("backend", "no function %s in category %s of %s",name,category,what)
+ end
+ end
+ elseif trace_backend then
+ logs.report("backend", "no category %s in %s",category,what)
+ end
+ end
+ backends.helpers = backend.helpers
+ elseif trace_backend then
+ logs.report("backend", "no backend named %s",what)
+ end
+ end
+end
+
+statistics.register("used backend", function()
+ local bc = backends.current
+ if bc ~= "unknown" then
+ return string.format("%s (%s)",bc,backends[bc].comment or "no comment")
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/back-ini.mkiv b/tex/context/base/back-ini.mkiv
new file mode 100644
index 000000000..b7bbdb56f
--- /dev/null
+++ b/tex/context/base/back-ini.mkiv
@@ -0,0 +1,168 @@
+%D \module
+%D [ file=back-ini,
+%D version=2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Most will go away here as it is replaced by \LUA\ calls to
+%D backend functions.
+
+\writestatus{loading}{ConTeXt Backend Macros / Initialization}
+
+\registerctxluafile{back-ini}{1.001}
+
+%D We currently have a curious mix between tex and lua backend
+%D handling but eventually most will move to lua.
+
+\unprotect
+
+\ifdefined\everybackendshipout \else \newtoks\everybackendshipout \fi
+\ifdefined\everylastbackendshipout \else \newtoks\everylastbackendshipout \fi
+
+%D Right from the start \CONTEXT\ had a backend system based on
+%D runtime pluggable code. As most backend issues involved specials
+%D and since postprocessors had not that much in common, we ended up
+%D with a system where we could switch backend as well as output code
+%D for multiple backends at the same time.
+%D
+%D Because \LUATEX\ has the backend built in, and since some backend
+%D issues have been moved to the frontend I decided to provide new
+%D backend code for \MKIV, starting with what was actually used.
+%D
+%D At this moment \DVI\ is no longer used for advanced document
+%D output and we therefore dropped support for this format. Future
+%D versions might support more backends again, but this has a low
+%D priority.
+%D
+%D The big question is: what is to be considered a backend issue and
+%D what not. For the moment we treat image inclusion, object reuse,
+%D position tracking and color as frontend issues, if only because we
+%D deal with them via \LUA\ code and as such we don't depend too much
+%D on macro calls that need to inject code for the backend.
+%D
+%D Not everything here makes sense and the content of this file will
+%D definitely change.
+
+\let \dostartrotation \gobbleoneargument
+\let \dostoprotation \donothing
+\let \dostartscaling \gobbletwoarguments
+\let \dostopscaling \donothing
+\let \dostartmirroring \donothing
+\let \dostopmirroring \donothing
+
+%D \macros
+%D {doovalbox}
+%D
+%D When we look at the implementation, this is a complicated
+%D one. There are seven arguments.
+%D
+%D \starttyping
+%D \doovalbox {w} {h} {d} {linewidth} {radius} {stroke} {fill} {variant}
+%D \stoptyping
+%D
+%D This command has to return a \type{\vbox} which can be used
+%D to lay over another one (with text). The radius is in
+%D degrees, the stroke and fill are~\type{1} (true) of~\type{0}
+%D (false).
+
+\let \doovalbox \gobbleeightarguments
+
+%D \macros
+%D {dostartclipping,dostopclipping}
+%D
+%D Clipping is implemented in such a way that an arbitrary code
+%D can be fed.
+%D
+%D \starttyping
+%D \dostartclipping {pathname} {width} {height}
+%D \dostopclipping
+%D \stoptyping
+
+\let \dostartclipping \gobblethreearguments
+\let \dostopclipping \donothing
+
+%D \macros
+%D {dostartobject,
+%D dostopobject,
+%D doresetobjects,
+%D doinsertobject}
+%D
+%D Reuse of object can reduce the output filesize
+%D considerably. Reusable objects are implemented with:
+%D
+%D \starttyping
+%D \dostartobject{class}{name}{width}{height}{depth}
+%D some typeset material
+%D \dostopobject
+%D \stoptyping
+%D
+%D \starttyping
+%D \doinsertobject{class}{name}
+%D \stoptyping
+%D
+%D The savings can be huge in interactive texts. The next macro needs
+%D to be called after a graphic is inserted (in order to clean up
+%D global references).
+%D
+%D \starttyping
+%D \doresetobjects
+%D \stoptyping
+
+\let \dostartobject \gobblefourarguments
+\let \dostopobject \donothing
+\let \doinsertobject \gobbletwoarguments
+\let \doresetobjects \donothing
+
+%D From now on, mapfile loading is also a special; we assume the
+%D more or less standard dvips syntax.
+
+\let \doresetmapfilelist \donothing
+\let \doloadmapfile \gobbletwoarguments % + - = | filename
+\let \doloadmapline \gobbletwoarguments % + - = | fileline
+
+%D \macros
+%D {ifusepagedestinations}
+%D
+%D In \PDF\ version 1.0 only page references were supported,
+%D while in \DVIWINDO\ 1.N only named references were accepted.
+%D Therefore \CONTEXT\ supports both methods of referencing. In
+%D \PDF\ version 1.1 named destinations arrived. Lack of
+%D continuous support of version 1.1 viewers for \MSDOS\
+%D therefore sometimes forces us to prefer page references. As
+%D a bonus, they are faster too and have no limitations. How
+%D fortunate we were having both mechanisms available when the
+%D version 3.0 (\PDF\ version 1.2) viewers proved to be too
+%D bugged to support named destinations.
+
+\newif\ifusepagedestinations % not yet interfaced in mkiv
+
+%D \macros
+%D {jobsuffix}
+%D
+%D By default, \TEX\ produces \DVI\ files which can be
+%D converted to other filetypes. Sometimes it is handy to
+%D know what the target file will be. In other driver
+%D modules we wil set \type {\jobsuffix} to \type {pdf}.
+
+\def\jobsuffix{pdf}
+
+\ifdefined\resetsystemmode \else
+ \let\setsystemmode \gobbleoneargument
+ \let\resetsystemmode\gobbleoneargument
+\fi
+
+\def\setjobsuffix#1%
+ {\resetsystemmode\jobsuffix
+ \edef\jobsuffix{#1}%
+ \setsystemmode\jobsuffix}
+
+\unexpanded\def\setupoutput[#1]{} % will be command line switch
+
+\protect \endinput
diff --git a/tex/context/base/back-pdf.lua b/tex/context/base/back-pdf.lua
new file mode 100644
index 000000000..54e22f1a2
--- /dev/null
+++ b/tex/context/base/back-pdf.lua
@@ -0,0 +1,469 @@
+if not modules then modules = { } end modules ['back-pdf'] = {
+ version = 1.001,
+ comment = "companion to back-pdf.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- we will move code to lpdf-* files (second cleanup stage)
+
+--[[ldx--
+
This module implements a couple of cleanup methods. We need these
+in order to meet the specification. Watch the double
+parenthesis; they are needed because otherwise we would pass more
+than one argument to .
+--ldx]]--
+
+local type, next, tostring = type, next, tostring
+local char, byte, format, gsub, rep, gmatch = string.char, string.byte, string.format, string.gsub, string.rep, string.gmatch
+local concat = table.concat
+local round = math.round
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+local texsprint, texwrite = tex.sprint, tex.write
+local ctxcatcodes = tex.ctxcatcodes
+
+local copy_node = node.copy
+
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
+
+local pdfliteral, register = nodes.pdfliteral, nodes.register
+
+local pdfconstant = lpdf.constant
+local pdfstring = lpdf.string
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfverbose = lpdf.verbose
+local pdfflushobject = lpdf.flushobject
+local pdfreserveobject = lpdf.reserveobject
+local pdfannotation = nodes.pdfannotation
+
+local pdfreserveobj = pdf.reserveobj
+local pdfimmediateobj = pdf.immediateobj
+
+function nodeinjections.rgbcolor(r,g,b)
+ return register(pdfliteral(format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b)))
+end
+
+function nodeinjections.cmykcolor(c,m,y,k)
+ return register(pdfliteral(format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k)))
+end
+
+function nodeinjections.graycolor(s) -- caching 0/1 does not pay off
+ return register(pdfliteral(format("%s g %s G",s,s)))
+end
+
+function nodeinjections.spotcolor(n,f,d,p)
+ if type(p) == "string" then
+ p = gsub(p,","," ") -- brr misuse of spot
+ end
+ return register(pdfliteral(format("/%s cs /%s CS %s SCN %s scn",n,n,p,p)))
+end
+
+function nodeinjections.transparency(n)
+ return register(pdfliteral(format("/Tr%s gs",n)))
+end
+
+local effects = {
+ normal = 0,
+ inner = 0,
+ outer = 1,
+ both = 2,
+ hidden = 3,
+}
+
+function nodeinjections.effect(effect,stretch,rulethickness)
+ -- always, no zero test (removed)
+ rulethickness = number.dimenfactors["bp"] * rulethickness
+ effect = effects[effect] or effects['normal']
+ return register(pdfliteral(format("%s Tc %s w %s Tr",stretch,rulethickness,effect))) -- watch order
+end
+
+-- cached ..
+
+local cache = { }
+
+function nodeinjections.startlayer(name)
+ local c = cache[name]
+ if not c then
+ c = register(pdfliteral(format("/OC /%s BDC",name)))
+ cache[name] = c
+ end
+ return copy_node(c)
+end
+
+local stop = register(pdfliteral("EMC"))
+
+function nodeinjections.stoplayer()
+ return copy_node(stop)
+end
+
+local cache = { }
+
+function nodeinjections.switchlayer(name)
+ local c = cache[name]
+ if not c then
+ c = register(pdfliteral(format("EMC /OC /%s BDC",name)))
+ end
+ return copy_node(c)
+end
+
+-- code
+
+function codeinjections.insertmovie(specification)
+ -- managed in figure inclusion: width, height, factor, repeat, controls, preview, label, foundname
+ local width = specification.width
+ local height = specification.height
+ local factor = specification.factor or number.dimenfactors.bp
+ local moviedict = pdfdictionary {
+ F = specification.foundname,
+ Aspect = pdfarray { factor * width, factor * height },
+ Poster = (specification.preview and true) or false,
+ }
+ local controldict = pdfdictionary {
+ ShowControls = (specification.controls and true) or false,
+ Mode = (specification["repeat"] and pdfconstant("Repeat")) or nil,
+ }
+ local action = pdfdictionary {
+ Subtype = pdfconstant("Movie"),
+ Border = pdfarray { 0, 0, 0 },
+ T = format("movie %s",specification.label),
+ Movie = moviedict,
+ A = controldict,
+ }
+ node.write(pdfannotation(width,height,0,action()))
+end
+
+function codeinjections.insertsound(specification)
+ -- rmanaged in interaction: repeat, label, foundname
+ local soundclip = interactions.soundclip(specification.label)
+ if soundclip then
+ local controldict = pdfdictionary {
+ Mode = (specification["repeat"] and pdfconstant("Repeat")) or nil
+ }
+ local sounddict = pdfdictionary {
+ F = soundclip.filename
+ }
+ local action = pdfdictionary {
+ Subtype = pdfconstant("Movie"),
+ Border = pdfarray { 0, 0, 0 },
+ T = format("sound %s",specification.label),
+ Movie = sounddict,
+ A = controldict,
+ }
+ node.write(pdfannotation(0,0,0,action()))
+ end
+end
+
+-- spot- and indexcolors
+
+local pdf_separation = pdfconstant("Separation")
+local pdf_indexed = pdfconstant("Indexed")
+local pdf_device_n = pdfconstant("DeviceN")
+local pdf_device_rgb = pdfconstant("DeviceRGB")
+local pdf_device_cmyk = pdfconstant("DeviceCMYK")
+local pdf_device_gray = pdfconstant("DeviceGray")
+local pdf_extgstate = pdfconstant("ExtGState")
+
+local pdf_rbg_range = pdfarray { 0, 1, 0, 1, 0, 1 }
+local pdf_cmyk_range = pdfarray { 0, 1, 0, 1, 0, 1, 0, 1 }
+local pdf_gray_range = pdfarray { 0, 1 }
+
+local rgb_function = "dup %s mul exch dup %s mul exch %s mul"
+local cmyk_function = "dup %s mul exch dup %s mul exch dup %s mul exch %s mul"
+local gray_function = "%s mul"
+
+local documentcolorspaces = pdfdictionary()
+
+local spotcolorhash = { } -- not needed
+local spotcolornames = { }
+local indexcolorhash = { }
+local delayedindexcolors = { }
+
+function registrations.spotcolorname(name,e)
+ spotcolornames[name] = e or name
+end
+
+local function registersomespotcolor(name,noffractions,names,p,colorspace,range,funct)
+ noffractions = tonumber(noffractions) or 1 -- to be checked
+ if noffractions == 0 then
+ -- can't happen
+ elseif noffractions == 1 then
+ local dictionary = pdfdictionary {
+ FunctionType = 4,
+ Domain = { 0, 1 },
+ Range = range,
+ }
+ local n = pdfimmediateobj("stream",format("{ %s }",funct),dictionary())
+ local array = pdfarray {
+ pdf_separation,
+ pdfconstant(spotcolornames[name] or name),
+ colorspace,
+ pdfreference(n),
+ }
+ local m = pdfimmediateobj(tostring(array))
+ local mr = pdfreference(m)
+ spotcolorhash[name] = m
+ documentcolorspaces[name] = mr
+ lpdf.adddocumentcolorspace(name,mr)
+ else
+ local cnames = pdfarray()
+ local domain = pdfarray()
+ for n in gmatch(names,"[^,]+") do
+ cnames[#cnames+1] = pdfconstant(spotcolornames[n] or n)
+ domain[#domain+1] = 0
+ domain[#domain+1] = 1
+ end
+ local dictionary = pdfdictionary {
+ FunctionType = 4,
+ Domain = domain,
+ Range = range,
+ }
+ local n = pdfimmediateobj("stream",format("{ %s %s }",rep("pop ",noffractions),funct),dictionary())
+ local array = pdfarray {
+ pdf_device_n,
+ cnames,
+ colorspace,
+ pdfreference(n),
+ }
+ local m = pdfimmediateobj(tostring(array))
+ local mr = pdfreference(m)
+ spotcolorhash[name] = m
+ documentcolorspaces[name] = mr
+ lpdf.adddocumentcolorspace(name,mr)
+ end
+end
+
+function registersomeindexcolor(name,noffractions,names,p,colorspace,range,funct)
+ noffractions = tonumber(noffractions) or 1 -- to be checked
+ local cnames = pdfarray()
+ local domain = pdfarray()
+ if names == "" then
+ names = name .. ",None"
+ else
+ names = names .. ",None"
+ end
+ for n in gmatch(names,"[^,]+") do
+ cnames[#cnames+1] = pdfconstant(spotcolornames[n] or n)
+ domain[#domain+1] = 0
+ domain[#domain+1] = 1
+ end
+ local dictionary = pdfdictionary {
+ FunctionType = 4,
+ Domain = domain,
+ Range = range,
+ }
+ local n = pdfimmediateobj("stream",format("{ %s %s }",rep("exch pop ",noffractions),funct),dictionary()) -- exch pop
+ local a = pdfarray {
+ pdf_device_n,
+ cnames,
+ colorspace,
+ pdfreference(n),
+ }
+ if p == "" then
+ p = "1"
+ else
+ p = p .. ",1"
+ end
+ local pi = { }
+ for pp in gmatch(p,"[^,]+") do
+ pi[#pi+1] = tonumber(pp)
+ end
+ local vector, set, n = { }, { }, #pi
+ for i=255,0,-1 do
+ for j=1,n do
+ set[j] = format("%02X",round(pi[j]*i))
+ end
+ vector[#vector+1] = concat(set)
+ end
+ vector = pdfverbose { "<", concat(vector, " "), ">" }
+ local n = pdfimmediateobj(tostring(pdfarray{ pdf_indexed, a, 255, vector }))
+ lpdf.adddocumentcolorspace(format("%s_indexed",name),pdfreference(n))
+ return n
+end
+
+-- actually, names (parent) is the hash
+
+local function delayindexcolor(name,names,func)
+ local hash = (names ~= "" and names) or name
+ -- logs.report("index colors","delaying '%s'",name)
+ delayedindexcolors[hash] = func
+end
+
+local function indexcolorref(name) -- actually, names (parent) is the hash
+ if not indexcolorhash[name] then
+ -- logs.report("index colors","registering '%s'",name)
+ local delayedindexcolor = delayedindexcolors[name]
+ if type(delayedindexcolor) == "function" then
+ indexcolorhash[name] = delayedindexcolor()
+ delayedindexcolors[name] = true
+ end
+ end
+ return indexcolorhash[name]
+end
+
+function registrations.rgbspotcolor(name,noffractions,names,p,r,g,b)
+--~ print(name,noffractions,names,p,r,g,b)
+ if noffractions == 1 then
+ registersomespotcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rbg_range,format(rgb_function,r,g,b))
+ else
+ registersomespotcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rbg_range,format("%s %s %s",r,g,b))
+ end
+ delayindexcolor(name,names,function()
+ return registersomeindexcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rgb_range,format(rgb_function,r,g,b))
+ end)
+end
+
+function registrations.cmykspotcolor(name,noffractions,names,p,c,m,y,k)
+ if noffractions == 1 then
+ registersomespotcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format(cmyk_function,c,m,y,k))
+ else
+ registersomespotcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format("%s %s %s %s",c,m,y,k))
+ end
+ delayindexcolor(name,names,function()
+ return registersomeindexcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format(cmyk_function,c,m,y,k))
+ end)
+end
+
+function registrations.grayspotcolor(name,noffractions,names,p,s)
+ if noffractions == 1 then
+ registersomespotcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,format(gray_function,s))
+ else
+ registersomespotcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,s)
+ end
+ delayindexcolor(name,names,function()
+ return registersomeindexcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,format(gray_function,s))
+ end)
+end
+
+function registrations.rgbindexcolor(name,noffractions,names,p,r,g,b)
+ registersomeindexcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rgb_range,format(rgb_function,r,g,b))
+end
+
+function registrations.cmykindexcolor(name,noffractions,names,p,c,m,y,k)
+ registersomeindexcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format(cmyk_function,c,m,y,k))
+end
+
+function registrations.grayindexcolor(name,noffractions,names,p,s)
+ registersomeindexcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,gray_function)
+end
+
+function codeinjections.setfigurecolorspace(data,figure)
+ local color = data.request.color
+ if color then
+ local ref = indexcolorref(color)
+ if ref then
+ figure.colorspace = ref
+ data.used.color = color
+ end
+ end
+end
+
+-- transparency
+
+local transparencies = { [0] =
+ pdfconstant("Normal"),
+ pdfconstant("Normal"),
+ pdfconstant("Multiply"),
+ pdfconstant("Screen"),
+ pdfconstant("Overlay"),
+ pdfconstant("SoftLight"),
+ pdfconstant("HardLight"),
+ pdfconstant("ColorDodge"),
+ pdfconstant("ColorBurn"),
+ pdfconstant("Darken"),
+ pdfconstant("Lighten"),
+ pdfconstant("Difference"),
+ pdfconstant("Exclusion"),
+ pdfconstant("Compatible"),
+}
+
+local documenttransparencies = { }
+local transparencyhash = { } -- share objects
+
+local done = false
+
+function registrations.transparency(n,a,t)
+ if not done then
+ local d = pdfdictionary {
+ Type = pdf_extgstate,
+ ca = 1,
+ CA = 1,
+ BM = transparencies[1],
+ AIS = false,
+ }
+ local m = pdfimmediateobj(tostring(d))
+ local mr = pdfreference(m)
+ transparencyhash[0] = m
+ documenttransparencies[0] = mr
+ lpdf.adddocumentextgstate("Tr0",mr)
+ done = true
+ end
+ if n > 0 and not transparencyhash[n] then
+ local d = pdfdictionary {
+ Type = pdf_extgstate,
+ ca = tonumber(t),
+ CA = tonumber(t),
+ BM = transparencies[a] or transparencies[0],
+ AIS = false,
+ }
+ local m = pdfimmediateobj(tostring(d))
+ local mr = pdfreference(m)
+ transparencyhash[n] = m
+ documenttransparencies[n] = mr
+ lpdf.adddocumentextgstate(format("Tr%s",n),mr)
+ end
+end
+
+function codeinjections.adddocumentinfo(key,value)
+ lpdf.addtoinfo(key,lpdf.tosixteen(value))
+end
+
+-- graphics
+
+function codeinjections.setfigurealternative(data,figure)
+ local display = data.request.display
+ if display and display ~= "" then
+ local request = data.request
+ figures.push {
+ name = request.display,
+ page = request.page,
+ size = request.size,
+ prefix = request.prefix,
+ cache = request.cache,
+ width = request.width,
+ height = request.height,
+ }
+ figures.identify()
+ local displayfigure = figures.check()
+ if displayfigure then
+ -- figure.aform = true
+ img.immediatewrite(figure)
+ local a = lpdf.array {
+ lpdf.dictionary {
+ Image = lpdf.reference(figure.objnum),
+ DefaultForPrinting = true,
+ }
+ }
+ local d = lpdf.dictionary {
+ Alternates = lpdf.reference(pdf.immediateobj(tostring(a))),
+ }
+ displayfigure.attr = d()
+ return displayfigure, figures.current()
+ end
+ end
+end
+
+-- eventually we need to load this runtime
+--
+-- backends.install((environment and environment.arguments and environment.arguments.backend) or "pdf")
+--
+-- but now we need to force this as we also load the pdf tex part which hooks into all kind of places
+
+codeinjections.finalizepage = lpdf.finalizepage
+codeinjections.finalizedocument = lpdf.finalizedocument
+
+backends.install("pdf")
diff --git a/tex/context/base/back-pdf.mkiv b/tex/context/base/back-pdf.mkiv
new file mode 100644
index 000000000..a10afd5b9
--- /dev/null
+++ b/tex/context/base/back-pdf.mkiv
@@ -0,0 +1,178 @@
+%D \module
+%D [ file=back-pdf,
+%D version=2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=\PDF,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Backend Macros / PDF}
+
+\registerctxluafile{back-pdf}{1.001} % this will change
+
+\unprotect
+
+%D We will minimize the number of calls to \PDF\ specific primitives
+%D and delegate all management and injection of code to the backend.
+%D
+%D Here we initialize some internal quantities.
+
+\pdfoutput = 1
+\pdfhorigin = 1 true in
+\pdfvorigin = 1 true in
+\pdfimageresolution = 300
+\pdfpkresolution = 600
+\pdfdecimaldigits = 10
+\pdfinclusionerrorlevel = 0
+\pdfminorversion = 6 % maybe even 7
+%pdfuniqueresname = 1
+
+%D This one can be consulted by users although the suffix is also
+%D a system mode.
+
+\setjobsuffix{pdf}
+
+%D For the moment we keep these.
+
+\newtoks \pdfbackendeveryximage
+\newtoks \pdfbackendeveryxform
+
+%D These are the only official methods to add stuff to the resources.
+
+\def\pdfbackendsetcatalog #1#2{\ctxlua{lpdf.addtocatalog ("#1",\!!bs#2\!!es)}}
+\def\pdfbackendsetinfo #1#2{\ctxlua{lpdf.addtoinfo ("#1",\!!bs#2\!!es)}}
+\def\pdfbackendsetname #1#2{\ctxlua{lpdf.addtonames ("#1",\!!bs#2\!!es)}}
+
+\def\pdfbackendsetpageattribute #1#2{\ctxlua{lpdf.addtopageattributes ("#1",\!!bs#2\!!es)}}
+\def\pdfbackendsetpagesattribute#1#2{\ctxlua{lpdf.addtopagesattributes("#1",\!!bs#2\!!es)}}
+\def\pdfbackendsetpageresource #1#2{\ctxlua{lpdf.addtopageresources ("#1",\!!bs#2\!!es)}}
+
+\def\pdfbackendsetextgstate #1#2{\ctxlua{lpdf.adddocumentextgstate ("#1",lpdf.verbose(\!!bs#2\!!es))}}
+\def\pdfbackendsetcolorspace #1#2{\ctxlua{lpdf.adddocumentcolorspace("#1",lpdf.verbose(\!!bs#2\!!es))}}
+\def\pdfbackendsetpattern #1#2{\ctxlua{lpdf.adddocumentpattern ("#1",lpdf.verbose(\!!bs#2\!!es))}}
+\def\pdfbackendsetshade #1#2{\ctxlua{lpdf.adddocumentshade ("#1",lpdf.verbose(\!!bs#2\!!es))}}
+
+\def\pdfbackendcurrentresources {\ctxlua{lpdf.collectedresources()}}
+
+%D Let's block these:
+
+\let\pdfcatalog \relax \newtoks\pdfcatalog
+\let\pdfinfo \relax \newtoks\pdfinfo
+\let\pdfnames \relax \newtoks\pdfnames
+\let\pdfpageresources\relax \newtoks\pdfpageresources
+\let\pdfpageattr \relax \newtoks\pdfpageattr
+\let\pdfpagesattr \relax \newtoks\pdfpagesattr
+
+%D An example of usage is:
+
+\appendtoks
+ \pdfbackendsetinfo{ConTeXt.Version}{\contextversion}%
+ \pdfbackendsetinfo{ConTeXt.Time} {\number\normalyear.\twodigits\normalmonth.\twodigits\normalday\space \twodigits\currenthour:\twodigits\currentminute}%
+ \pdfbackendsetinfo{ConTeXt.Jobname}{\jobname}%
+ \pdfbackendsetinfo{ConTeXt.Url} {www.pragma-ade.com}%
+\to \everylastbackendshipout
+
+%D Unfortunately this is still needed (also for \METAPOST\ to
+%D \PDF\ converter):
+
+% \def\doresetmapfilelist
+% {\global\let\doresetmapfilelist\relax
+% \pdfmapfile{original-empty.map}}
+%
+% \appendtoksonce \loadallfontmapfiles \to \pdfbackendeveryxform
+% \appendtoksonce \loadallfontmapfiles \to \pdfbackendeveryximage
+
+%D Transformations. Some day we will use primitives (once they're fixed).
+
+\def\dostartrotation#1% grouped
+ {\forcecolorhack
+ \pdfliteral{q \ctxlua{lpdf.rotationcm(#1)}}}
+
+\def\dostoprotation
+ {\pdfliteral{Q}}
+
+\def\dostartscaling#1#2% the test is needed because acrobat is bugged!
+ {\forcecolorhack
+ \pdfliteral{q \ifdim#1\points=\zeropoint.0001\else#1\fi\space 0 0
+ \ifdim#2\points=\zeropoint.0001\else#2\fi\space 0 0 cm}}
+
+\def\dostopscaling
+ {\pdfliteral{Q}}
+
+\def\dostartmirroring{\pdfliteral{-1 0 0 1 0 0 cm}}
+\def\dostopmirroring {\pdfliteral{-1 0 0 1 0 0 cm}}
+
+\def\dostartclipping#1#2#3% todo (still needed?)
+ {\PointsToBigPoints{#2}\width
+ \PointsToBigPoints{#3}\height
+ \grabMPclippath{#1}{1}\width\height{0 0 m \width\space 0 l \width \height l 0 \height l}%
+ \pdfliteral{q 0 w \MPclippath\space W n}}
+
+\def\dostopclipping
+ {\pdfliteral{Q n}}
+
+%D The following will move to the backend \LUA\ code:
+
+\appendtoks \ctxlua{backends.codeinjections.finalizepage ()}\to \everybackendshipout % is immediate
+\appendtoks \ctxlua{backends.codeinjections.finalizedocument()}\to \everylastbackendshipout % is immediate
+
+%D Temporary hack, will be removed or improved or default.
+
+\def\TransparencyHack{\ctxlua{backends.codeinjections.addtransparencygroup()}}
+
+%D \macros
+%D {dostartobject,dostopobject,doinsertobject}
+
+%D This will change:
+
+\newbox\objectbox
+
+\def\dostartobject#1#2#3#4#5%
+ {\bgroup
+ \setbox\objectbox\vbox\bgroup
+ \def\dodostopobject{\egroup\doregisterobject{#1}{#2}}}
+
+\def\dostopobject
+ {\dodostopobject
+ \egroup}
+
+\def\doregisterobject#1#2%
+ {\the\pdfbackendeveryxform
+ \finalizeobjectbox\objectbox
+ \immediate\pdfxform resources {\pdfbackendcurrentresources}\objectbox
+ \dosetobjectreference{#1}{#2}{\the\pdflastxform}}
+
+\def\doresetobjects
+ {}
+
+\def\doinsertobject#1#2%
+ {\begingroup
+ \doifobjectreferencefoundelse{#1}{#2}
+ {\dogetobjectreference{#1}{#2}\PDFobjectreference\pdfrefxform\PDFobjectreference}%
+ \donothing
+ \endgroup}
+
+\def\doPDFgetobjectpage#1#2#3%
+ {\dogetobjectreferencepage{#1}{#2}#3%
+ \ifx#3\empty\def#3{\realfolio}\fi}
+
+\def\doPDFgetobjectpagereference#1#2#3%
+ {\dogetobjectreferencepage{#1}{#2}#3%
+ \doPDFgetpagereference{\ifx#3\empty\realfolio\else#3\fi}#3}
+
+\let\lastpredefinedsymbol\empty % some day we can do more at the lua end
+
+\def\predefinesymbol[#1]%
+ {\begingroup
+ \xdef\lastpredefinedsymbol{#1}%
+ \settightobject{SYM}{#1}\hbox{\symbol[#1]}% to be checked ... maybe only fitting
+ \dogetobjectreference{SYM}{#1}\lastref
+ \ctxlua{backends.codeinjections.registersymbol("#1",\lastref)}%
+ \endgroup}
+
+\protect \endinput
diff --git a/tex/context/base/back-u3d.mkiv b/tex/context/base/back-u3d.mkiv
new file mode 100644
index 000000000..398159feb
--- /dev/null
+++ b/tex/context/base/back-u3d.mkiv
@@ -0,0 +1,156 @@
+%D \module
+%D [ file=back-u3d,
+%D version=2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=U3D Experiment,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% This is only a placeholder that demonstrates the usage of u3d
+% resources. The user interface is rather messy an might be
+% improved. The files and setup is derived from an example by
+% Michael Vidiassov.
+
+\endinput
+
+\starttext
+
+\startluaparameterset [u3d:myset:controls:1]
+ view = {
+ name = 'default',
+ bg = {1,1,1},
+ mag = 100,
+ coo = {0,0,0},
+ c2c = {0,0,1},
+ rot = {40,0,60},
+ roo = 6,
+ lights = 'CAD'
+ },
+ js = 'cloudq.js'
+\stopluaparameterset
+
+\startluaparameterset [u3d:myset:controls:2]
+ views = {
+ {
+ name = 'AnglePositioning',
+ bg = {1,1,1},
+ azimuth = 45,
+ altitude = 45,
+ roo = 50,
+ aac = 2.5,
+ lights = 'Artwork'
+ },
+ {
+ name = 'RotationPositioning',
+ bg = {1,1,1},
+ rot = {0,45,45},
+ roo = 50,
+ aac = 2.5,
+ lights = 'Artwork'
+ },
+ {
+ name = 'VectorPositioning',
+ bg = {1,0,0},
+ c2c = {1,1,math.sqrt(2)},
+ roo = 50,
+ aac = 2.5,
+ lights = 'CAD'
+ },
+ {
+ name = 'PositionPositioning',
+ bg = {1,0,0},
+ pos = {1+25,1+25,1+50/math.sqrt(2)},
+ aac = 2.5,
+ lights = 'CAD'
+ },
+ {
+ name = 'ortho',
+ bg = {1,1,1},
+ mag = 300,
+ lights = 'CAD',
+ crossection = {}
+ }
+ },
+ view = {
+ name = 'default',
+ bg = {1,1,1},
+ c2c = {-1,-1,0},
+ roo = 50,
+ aac = 2.5,
+ roll = 45,
+ lights = 'CAD',
+ crossection = {
+ normal = {-1,-1,-1},
+ transparent = true
+ },
+ nodes = {
+ {
+ name = 'xlabel',
+ visible = false
+ },
+ {
+ name = 'ylabel',
+ opacity = 0.5
+ },
+ {
+ name = 'zlabel',
+ rendermode = 'Wireframe'
+ }
+ }
+ }
+\stopluaparameterset
+
+\useexternalfigure
+ [cloudq]
+ [cloudq.u3d]
+ [width=0.7\textwidth,
+ height=.7\textwidth,
+ display=u3d:myset:display:1,
+ controls=u3d:myset:controls:1]
+
+\useexternalfigure
+ [axes]
+ [axes.u3d]
+ [width=0.7\textwidth,
+ height=.7\textwidth,
+ controls=u3d:myset:controls:1]
+
+\startluaparameterset[u3d:myset:display:2]
+ toolbar = true,
+ preview = 'cloudq.png'
+\stopluaparameterset
+\startluaparameterset[u3d:myset:display:3]
+ toolbar = true,
+ tree = false,
+ preview = 'area.png'
+\stopluaparameterset
+\startluaparameterset[u3d:myset:display:4]
+ toolbar = true,
+ tree = false,
+ view = {
+ name = 'view',
+ bg = {0.1,0.1,0.1},
+ c2c = {-1,-1,0},
+ roo = 50,
+ aac = 2.5,
+ roll = 45,
+ lights = 'Red'
+ }
+\stopluaparameterset
+\startluaparameterset[u3d:myset:display:5]
+ toolbar = true,
+ tree = false,
+ view = 'ortho'
+\stopluaparameterset
+
+\placefigure[here]{none}{\externalfigure[cloudq][display=u3d:myset:display:2]}
+\placefigure[here]{none}{\externalfigure[axes] [display=u3d:myset:display:3]}
+\placefigure[here]{none}{\externalfigure[axes] [display=u3d:myset:display:4]}
+\placefigure[here]{none}{\externalfigure[axes] [display=u3d:myset:display:5,width=0.5\textwidth,height=.5\textwidth]}
+
+\stoptext
diff --git a/tex/context/base/bibl-bib.lua b/tex/context/base/bibl-bib.lua
new file mode 100644
index 000000000..3c0dad2fa
--- /dev/null
+++ b/tex/context/base/bibl-bib.lua
@@ -0,0 +1,762 @@
+if not modules then modules = { } end modules ['bibl-bib'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+
This is a prelude to integrated bibliography support. This file just loads
+bibtex files and converts them to xml so that the we access the content
+in a convenient way. Actually handling the data takes place elsewhere.
+--ldx]]--
+
+local utf = unicode.utf8
+local lower, format, gsub, concat = string.lower, string.format, string.gsub, table.concat
+local next = next
+local utfchar = utf.char
+local lpegmatch = lpeg.match
+local textoutf = characters and characters.tex.toutf
+local variables = interfaces and interfaces.variables
+
+local finalizers = xml.finalizers.tex
+local xmlfilter, xmltext = xml.filter, xml.text
+
+local trace_bibxml = false trackers.register("publications.bibxml", function(v) trace_bibtex = v end)
+
+bibtex = bibtex or { }
+
+bibtex.size = 0
+bibtex.definitions = 0
+bibtex.shortcuts = 0
+
+local defaultshortcuts = {
+ jan = "1",
+ feb = "2",
+ mar = "3",
+ apr = "4",
+ may = "5",
+ jun = "6",
+ jul = "7",
+ aug = "8",
+ sep = "9",
+ oct = "10",
+ nov = "11",
+ dec = "12",
+}
+
+local shortcuts = { }
+local data = { }
+local entries
+
+-- Currently we expand shortcuts and for large ones (like the acknowledgements
+-- in tugboat.bib this is not that efficient. However, eventually strings get
+-- hashed again.
+
+local function do_shortcut(tag,key,value)
+ bibtex.shortcuts = bibtex.shortcuts + 1
+ if lower(tag) == "@string" then
+ shortcuts[key] = value
+ end
+end
+
+local function do_definition(tag,key,tab) -- maybe check entries here (saves memory)
+ if not entries or entries[key] then
+ bibtex.definitions = bibtex.definitions + 1
+ local t = { }
+ for i=1,#tab,2 do
+ t[tab[i]] = tab[i+1]
+ end
+ local p = data[tag]
+ if not p then
+ data[tag] = { [key] = t }
+ else
+ p[key] = t
+ end
+ end
+end
+
+local function resolve(s)
+ return shortcuts[s] or defaultshortcuts[s] or s -- can be number
+end
+
+local P, R, S, C, Cc, Cs, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct
+
+local percent = P("%")
+local start = P("@")
+local comma = P(",")
+local hash = P("#")
+local escape = P("\\")
+local single = P("'")
+local double = P('"')
+local left = P('{')
+local right = P('}')
+local both = left + right
+local lineending = S("\n\r")
+local space = S(" \t\n\r\f")
+local spacing = space^0
+local equal = P("=")
+local collapsed = (space^1)/ " "
+
+local function add(a,b) if b then return a..b else return a end end
+
+local keyword = C((lpeg.R("az","AZ","09") + S("@_:-"))^1) -- lpeg.C((1-space)^1)
+local s_quoted = ((escape*single) + collapsed + (1-single))^0
+local d_quoted = ((escape*double) + collapsed + (1-double))^0
+local balanced = lpeg.patterns.balanced
+
+local s_value = (single/"") * s_quoted * (single/"")
+local d_value = (double/"") * d_quoted * (double/"")
+local b_value = (left /"") * balanced * (right /"")
+local r_value = keyword/resolve
+
+local somevalue = s_value + d_value + b_value + r_value
+local value = Cs((somevalue * ((spacing * hash * spacing)/"" * somevalue)^0))
+
+local assignment = spacing * keyword * spacing * equal * spacing * value * spacing
+local shortcut = keyword * spacing * left * spacing * (assignment * comma^0)^0 * spacing * right
+local definition = keyword * spacing * left * spacing * keyword * comma * lpeg.Ct((assignment * comma^0)^0) * spacing * right
+local comment = keyword * spacing * left * (1-right)^0 * spacing * right
+local forget = percent^1 * (1-lineending)^0
+
+-- todo \%
+
+local grammar = (space + forget + shortcut/do_shortcut + definition/do_definition + comment + 1)^0
+
+function bibtex.convert(session,content)
+ statistics.starttiming(bibtex)
+ data, shortcuts, entries = session.data, session.shortcuts, session.entries
+ -- session.size = session.size + #content
+ bibtex.size = bibtex.size + #content
+ session.size = session.size + #content
+ lpegmatch(grammar,content or "")
+ statistics.stoptiming(bibtex)
+end
+
+function bibtex.load(session,filename)
+ local filename = resolvers.find_file(filename,"bib")
+ if filename ~= "" then
+ local data = io.loaddata(filename) or ""
+ if data == "" then
+ logs.report("publications","empty file '%s', no conversion to xml",filename)
+ elseif trace_bibxml then
+ logs.report("publications","converting file '%s' to xml",filename)
+ end
+ bibtex.convert(session,data)
+ end
+end
+
+function bibtex.new()
+ return {
+ data = { },
+ shortcuts = { },
+ xml = xml.convert("\n"),
+ size = 0,
+ entries = nil,
+ loaded = false,
+ }
+end
+
+local escaped_pattern = xml.escaped_pattern
+
+local ihatethis = {
+ f = "\\f",
+ n = "\\n",
+ r = "\\r",
+ s = "\\s",
+ t = "\\t",
+ v = "\\v",
+ z = "\\z",
+}
+
+local command = P("\\")/"" * Cc("\\bibtexcommand{") * (R("az","AZ")^1) * Cc("}")
+local any = P(1)
+local done = P(-1)
+local one_l = P("{") / ""
+local one_r = P("}") / ""
+local two_l = P("{{") / ""
+local two_r = P("}}") / ""
+
+local filter = Cs(
+ two_l * (command + any - two_r - done)^0 * two_r * done +
+ one_l * (command + any - one_r - done)^0 * one_r * done +
+ (command + any )^0
+)
+
+function bibtex.toxml(session,options)
+ if session.loaded then
+ return
+ else
+ session.loaded = true
+ end
+ -- we can always speed this up if needed
+ -- format slows down things a bit but who cares
+ statistics.starttiming(bibtex)
+ local result = { }
+ local options = aux.settings_to_hash(options)
+ local convert = options.convert -- todo: interface
+ local strip = options.strip -- todo: interface
+ local entries = session.entries
+ result[#result+1] = format("")
+ result[#result+1] = format("")
+ for id, categories in next, session.data do
+ id = lower(gsub(id,"^@",""))
+ for name, entry in next, categories do
+ if not entries or entries[name] then
+ result[#result+1] = format("",lower(name),id)
+ for key, value in next, entry do
+ value = gsub(value,"\\(.)",ihatethis)
+ value = lpegmatch(escaped_pattern,value)
+
+ if value ~= "" then
+ if convert then
+ value = textoutf(value,true)
+ end
+ if strip then
+ -- as there is no proper namespace in bibtex we need this
+ -- kind of hackery ... bibtex databases are quite unportable
+ value = lpegmatch(filter,value) or value
+ end
+ result[#result+1] = format(" %s",key,value)
+ end
+ end
+ result[#result+1] = format("")
+ end
+ end
+ end
+ result[#result+1] = format("")
+ result = concat(result,"\n")
+ -- alternatively we could use lxml.convert
+ session.xml = xml.convert(result, {
+ resolve_entities = true,
+ resolve_predefined_entities = true, -- in case we have escaped entities
+ -- unify_predefined_entities = true, -- & -> &
+ utfize_entities = true,
+ } )
+ session.data = nil
+ session.shortcuts = nil
+ statistics.stoptiming(bibtex)
+end
+
+statistics.register("bibtex load time", function()
+ local size = bibtex.size
+ if size > 0 then
+ return format("%s seconds (%s bytes, %s definitions, %s shortcuts)",
+ statistics.elapsedtime(bibtex),size,bibtex.definitions,bibtex.shortcuts)
+ else
+ return nil
+ end
+end)
+
+--~ str = [[
+--~ @COMMENT { CRAP }
+--~ @STRING{ hans = "h a n s" }
+--~ @STRING{ taco = "t a c o" }
+--~ @SOMETHING{ key1, abc = "t a c o" , def = "h a n s" }
+--~ @SOMETHING{ key2, abc = hans # taco }
+--~ @SOMETHING{ key3, abc = "hans" # taco }
+--~ @SOMETHING{ key4, abc = hans # "taco" }
+--~ @SOMETHING{ key5, abc = hans # taco # "hans" # "taco"}
+--~ @SOMETHING{ key6, abc = {oeps {oeps} oeps} }
+--~ ]]
+
+--~ local session = bibtex.new()
+--~ bibtex.convert(session,str)
+--~ bibtex.toxml(session)
+--~ print(session.size,statistics.elapsedtime(bibtex))
+
+--~ local session = bibtex.new()
+--~ bibtex.load(session,"IEEEabrv.bib")
+--~ bibtex.load(session,"IEEEfull.bib")
+--~ bibtex.load(session,"IEEEexample.bib")
+--~ bibtex.toxml(session)
+--~ print(session.size,statistics.elapsedtime(bibtex))
+
+--~ local session = bibtex.new()
+--~ bibtex.load(session,"gut.bib")
+--~ bibtex.load(session,"komoedie.bib")
+--~ bibtex.load(session,"texbook1.bib")
+--~ bibtex.load(session,"texbook2.bib")
+--~ bibtex.load(session,"texbook3.bib")
+--~ bibtex.load(session,"texgraph.bib")
+--~ bibtex.load(session,"texjourn.bib")
+--~ bibtex.load(session,"texnique.bib")
+--~ bibtex.load(session,"tugboat.bib")
+--~ bibtex.toxml(session)
+--~ print(session.size,statistics.elapsedtime(bibtex))
+
+--~ print(table.serialize(session.data))
+--~ print(table.serialize(session.shortcuts))
+--~ print(xml.serialize(session.xml))
+
+if not characters then dofile(resolvers.find_file("char-def.lua")) end
+
+local chardata = characters.data
+local concat = table.concat
+
+local P, Ct, lpegmatch = lpeg.P, lpeg.Ct, lpeg.match
+
+local space, comma = P(" "), P(",")
+
+local andsplitter = Ct(lpeg.splitat(space^1 * "and" * space^1))
+local commasplitter = Ct(lpeg.splitat(space^0 * comma * space^0))
+local spacesplitter = Ct(lpeg.splitat(space^1))
+local firstcharacter = lpeg.patterns.utf8byte
+
+function is_upper(str)
+ local first = lpegmatch(firstcharacter,str)
+ local okay = chardata[first]
+ return okay and okay.category == "lu"
+end
+
+local function splitauthors(str)
+ local authors = lpegmatch(andsplitter,str)
+ for i=1,#authors do
+ local firstnames, vons, surnames, initials, juniors, words
+ local author = authors[i]
+ local split = lpegmatch(commasplitter,author)
+ local n = #split
+ if n == 1 then
+ --~ First von Last
+ words = lpegmatch(spacesplitter,author)
+ firstnames, vons, surnames = { }, { }, { }
+ local i, n = 1, #words
+ while i <= n do
+ local w = words[i]
+ if is_upper(w) then
+ firstnames[#firstnames+1], i = w, i + 1
+ else
+ break
+ end
+ end
+ while i <= n do
+ local w = words[i]
+ if is_upper(w) then
+ break
+ else
+ vons[#vons+1], i = w, i + 1
+ end
+ end
+ while i <= n do
+ surnames[#surnames+1], i = words[i], i + 1
+ end
+ elseif n == 2 then
+ --~ von Last, First
+ words = lpegmatch(spacesplitter,split[2])
+ surnames = lpegmatch(spacesplitter,split[1])
+ firstnames, vons = { }, { }
+ local i, n = 1, #words
+ while i <= n do
+ local w = words[i]
+ if is_upper(w) then
+ firstnames[#firstnames+1], i = w, i + 1
+ else
+ break
+ end
+ end
+ while i <= n do
+ vons[#vons+1], i = words[i], i + 1
+ end
+ else
+ --~ von Last, Jr ,First
+ firstnames = lpegmatch(spacesplitter,split[1])
+ juniors = lpegmatch(spacesplitter,split[2])
+ surnames = lpegmatch(spacesplitter,split[3])
+ if n > 3 then
+ -- error
+ end
+ end
+ if #surnames == 0 then
+ surnames[1] = firstnames[#firstnames]
+ firstnames[#firstnames] = nil
+ end
+ if firstnames then
+ initials = { }
+ for i=1,#firstnames do
+ initials[i] = utfchar(lpegmatch(firstcharacter,firstnames[i]))
+ end
+ end
+ authors[i] = {
+ original = author,
+ firstnames = firstnames,
+ vons = vons,
+ surnames = surnames,
+ initials = initials,
+ juniors = juniors,
+ }
+ end
+ authors.original = str
+ return authors
+end
+
+local function the_initials(initials,symbol)
+ local t, symbol = { }, symbol or "."
+ for i=1,#initials do
+ t[i] = initials[i] .. symbol
+ end
+ return t
+end
+
+-- authors
+
+bibtex.authors = bibtex.authors or { }
+
+local authors = bibtex.authors
+
+local defaultsettings = {
+ firstnamesep = " ",
+ vonsep = " ",
+ surnamesep = " ",
+ juniorsep = " ",
+ surnamejuniorsep = ", ",
+ juniorjuniorsep = ", ",
+ surnamefirstnamesep = ", ",
+ surnameinitialsep = ", ",
+ namesep = ", ",
+ lastnamesep = " and ",
+ finalnamesep = " and ",
+}
+
+function authors.normal(author,settings)
+ local firstnames, vons, surnames, juniors = author.firstnames, author.vons, author.surnames, author.juniors
+ local result, settings = { }, settings or defaultsettings
+ if firstnames and #firstnames > 0 then
+ result[#result+1] = concat(firstnames," ")
+ result[#result+1] = settings.firstnamesep or defaultsettings.firstnamesep
+ end
+ if vons and #vons > 0 then
+ result[#result+1] = concat(vons," ")
+ result[#result+1] = settings.vonsep or defaultsettings.vonsep
+ end
+ if surnames then
+ result[#result+1] = concat(surnames," ")
+ end
+ if juniors and #juniors > 0 then
+ result[#result+1] = concat(juniors," ")
+ result[#result+1] = settings.surnamesep or defaultsettings.surnamesep
+ end
+ return concat(result)
+end
+
+function authors.normalshort(author,settings)
+ local firstnames, vons, surnames, juniors = author.firstnames, author.vons, author.surnames, author.juniors
+ local result, settings = { }, settings or defaultsettings
+ if firstnames and #firstnames > 0 then
+ result[#result+1] = concat(firstnames," ")
+ result[#result+1] = settings.firstnamesep or defaultsettings.firstnamesep
+ end
+ if vons and #vons > 0 then
+ result[#result+1] = concat(vons," ")
+ result[#result+1] = settings.vonsep or defaultsettings.vonsep
+ end
+ if surnames then
+ result[#result+1] = concat(surnames," ")
+ end
+ if juniors and #juniors > 0 then
+ result[#result+1] = concat(juniors," ")
+ result[#result+1] = settings.surnamejuniorsep or defaultsettings.surnamejuniorsep
+ end
+ return concat(result)
+end
+
+function authors.inverted(author,settings)
+ local firstnames, vons, surnames, juniors = author.firstnames, author.vons, author.surnames, author.juniors
+ local result, settings = { }, settings or defaultsettings
+ if vons and #vons > 0 then
+ result[#result+1] = concat(vons," ")
+ result[#result+1] = settings.vonsep or defaultsettings.vonsep
+ end
+ if surnames then
+ result[#result+1] = concat(surnames," ")
+ end
+ if juniors and #juniors > 0 then
+ result[#result+1] = settings.juniorjuniorsep or defaultsettings.juniorjuniorsep
+ result[#result+1] = concat(juniors," ")
+ end
+ if firstnames and #firstnames > 0 then
+ result[#result+1] = settings.surnamefirstnamesep or defaultsettings.surnamefirstnamesep
+ result[#result+1] = concat(firstnames," ")
+ end
+ return concat(result)
+end
+
+function authors.invertedshort(author,settings)
+ local vons, surnames, initials, juniors = author.vons, author.surnames, author.initials, author.juniors
+ local result, settings = { }, settings or defaultsettings
+ if vons and #vons > 0 then
+ result[#result+1] = concat(vons," ")
+ result[#result+1] = settings.vonsep or defaultsettings.vonsep
+ end
+ if surnames then
+ result[#result+1] = concat(surnames," ")
+ end
+ if juniors and #juniors > 0 then
+ result[#result+1] = settings.juniorjuniorsep or defaultsettings.juniorjuniorsep
+ result[#result+1] = concat(juniors," ")
+ end
+ if initials and #initials > 0 then
+ result[#result+1] = settings.surnameinitialsep or defaultsettings.surnameinitialsep
+ result[#result+1] = concat(the_initials(initials)," ")
+ end
+ return concat(result)
+end
+
+local lastconcatsize = 1
+
+local function bibtexconcat(t,settings)
+ local namesep = settings.namesep or defaultsettings.namesep or ", "
+ local lastnamesep = settings.lastnamesep or defaultsettings.lastnamesep or namesep
+ local finalnamesep = settings.finalnamesep or defaultsettings.finalnamesep or lastnamesep
+ local lastconcatsize = #t
+ if lastconcatsize > 2 then
+ local s = { }
+ for i=1,lastconcatsize-2 do
+ s[i] = t[i] .. namesep
+ end
+ s[lastconcatsize-1], s[lastconcatsize] = t[lastconcatsize-1] .. finalnamesep, t[lastconcatsize]
+ return concat(s)
+ elseif lastconcatsize > 1 then
+ return concat(t,lastnamesep)
+ elseif lastconcatsize > 0 then
+ return t[1]
+ else
+ return ""
+ end
+end
+
+function authors.concat(author,combiner,what,settings)
+ if type(combiner) == "string" then
+ combiner = authors[combiner or "normal"] or authors.normal
+ end
+ local split = splitauthors(author)
+ local setting = settings[what]
+ local etallimit, etaldisplay, etaltext = 1000, 1000, ""
+ if setting then
+ etallimit = settings.etallimit or 1000
+ etaldisplay = settings.etaldisplay or etallimit
+ etalltext = settings.etaltext or ""
+ end
+ local max = #split
+ if max > etallimit and etaldisplay < max then
+ max = etaldisplay
+ end
+ for i=1,max do
+ split[i] = combiner(split[i],settings)
+ end
+ local result = bibtexconcat(split,settings)
+ if max < #split then
+ return result
+ else
+ return result .. etaltext
+ end
+end
+
+function authors.short(author,year)
+ local result = { }
+ if author then
+ local authors = splitauthors(author)
+ for a=1,#authors do
+ local aa = authors[a]
+ local initials = aa.initials
+ for i=1,#initials do
+ result[#result+1] = initials[i]
+ end
+ local surnames = aa.surnames
+ for s=1,#surnames do
+ result[#result+1] = utfchar(lpegmatch(firstcharacter,surnames[s]))
+ end
+ end
+ end
+ if year then
+ result[#result+1] = year
+ end
+ return concat(result)
+end
+
+-- We can consider creating a hashtable key -> entry but I wonder if
+-- pays off.
+
+local function collectauthoryears(id,list)
+ list = aux.settings_to_hash(list)
+ id = lxml.get_id(id)
+ local found = { }
+ for e in xml.collected(id,"/bibtex/entry") do
+ if list[e.at.tag] then
+ local year = xmlfilter(e,"xml:///field[@name='year']/text()")
+ local author = xmlfilter(e,"xml:///field[@name='author']/text()")
+ if author and year then
+ local a = found[author]
+ if not a then
+ a = { }
+ found[author] = a
+ end
+ local y = a[year]
+ if not y then
+ y = { }
+ a[year] = y
+ end
+ y[#y+1] = e
+ end
+ end
+ end
+ -- found = { author = { year_1 = { e1, e2, e3 } } }
+ local done = { }
+ for author, years in next, found do
+ local yrs = { }
+ for year, entries in next, years do
+ if subyears then
+ -- -- add letters to all entries of an author and if so shouldn't
+ -- -- we tag all years of an author as soon as we do this?
+ -- if #entries > 1 then
+ -- for i=1,#years do
+ -- local entry = years[i]
+ -- -- years[i] = year .. string.char(i + string.byte("0") - 1)
+ -- end
+ -- end
+ else
+ yrs[#yrs+1] = year
+ end
+ end
+ done[author] = yrs
+ end
+ return done
+end
+
+local method, settings = "normal", { }
+
+function authors.setsettings(s)
+ settings = s or settings
+end
+
+if commands then
+
+ local texsprint = tex and tex.sprint
+ local ctxcatcodes = tex and tex.ctxcatcodes
+
+ local sessions = { }
+
+ function commands.definebibtexsession(name)
+ sessions[name] = bibtex.new()
+ end
+
+ function commands.preparebibtexsession(name,xmlname,options)
+ bibtex.toxml(sessions[name],options)
+ lxml.register(xmlname,sessions[name].xml)
+ end
+
+ function commands.registerbibtexfile(name,filename)
+ bibtex.load(sessions[name],filename)
+ end
+
+ function commands.registerbibtexentry(name,entry)
+ local session = sessions[name]
+ local entries = session.entries
+ if not entries then
+ session.entries = { [entry] = true } -- here we can keep more info
+ else
+ entries[entry] = true
+ end
+ end
+
+ -- commands.bibtexconcat = bibtexconcat
+
+ -- finalizers can be rather dumb as we have just text and no embedded xml
+
+ function finalizers.bibtexconcat(collected,method,what)
+ if collected then
+ local author = collected[1].dt[1] or ""
+ if author ~= "" then
+ texsprint(ctxcatcodes,authors.concat(author,method,what,settings))
+ end
+ end
+ end
+
+ function finalizers.bibtexshort(collected)
+ if collected then
+ local c = collected[1]
+ local year = xmlfilter(c,"xml://field[@name='year']/text()")
+ local author = xmlfilter(c,"xml://field[@name='author']/text()")
+ texsprint(ctxcatcodes,authors.short(author,year))
+ end
+ end
+
+ -- experiment:
+
+ --~ -- alternative approach: keep data at the tex end
+
+ --~ local function xbibtexconcat(t,sep,finalsep,lastsep)
+ --~ local n = #t
+ --~ if n > 0 then
+ --~ context(t[1])
+ --~ if n > 1 then
+ --~ if n > 2 then
+ --~ for i=2,n-1 do
+ --~ context.bibtexpublicationsparameter("sep")
+ --~ context(t[i])
+ --~ end
+ --~ context.bibtexpublicationsparameter("finalsep")
+ --~ else
+ --~ context.bibtexpublicationsparameter("lastsep")
+ --~ end
+ --~ context(t[n])
+ --~ end
+ --~ end
+ --~ end
+
+ -- todo : sort
+
+ -- todo: choose between bibtex or commands namespace
+
+ function bibtex.authorref(id,list)
+ local result = collectauthoryears(id,list,method,what)
+ for author, years in next, result do
+ texsprint(ctxcatcodes,authors.concat(author,method,what,settings))
+ end
+ end
+
+ function bibtex.authoryearref(id,list)
+ local result = collectauthoryears(id,list,method,what)
+ for author, years in next, result do
+ texsprint(ctxcatcodes,authors.concat(author,method,what,settings)," (",concat(years,", "),")")
+ end
+ end
+
+ function bibtex.authoryearsref(id,list)
+ local result = collectauthoryears(id,list,method,what)
+ for author, years in next, result do
+ texsprint(ctxcatcodes,"(",authors.concat(author,method,what,settings),", ",concat(years,", "),")")
+ end
+ end
+
+ function bibtex.singular_or_plural(singular,plural)
+ if lastconcatsize and lastconcatsize > 1 then
+ texsprint(ctxcatcodes,plural)
+ else
+ texsprint(ctxcatcodes,singular)
+ end
+ end
+end
+
+
+--~ local function test(sample)
+--~ local authors = splitauthors(sample)
+--~ print(table.serialize(authors))
+--~ for i=1,#authors do
+--~ local author = authors[i]
+--~ print(normalauthor (author,settings))
+--~ print(normalshortauthor (author,settings))
+--~ print(invertedauthor (author,settings))
+--~ print(invertedshortauthor(author,settings))
+--~ end
+--~ print(concatauthors(sample,settings,normalauthor))
+--~ print(concatauthors(sample,settings,normalshortauthor))
+--~ print(concatauthors(sample,settings,invertedauthor))
+--~ print(concatauthors(sample,settings,invertedshortauthor))
+--~ end
+
+--~ local sample_a = "Hagen, Hans and Hoekwater, Taco Whoever T. Ex. and Henkel Hut, Hartmut Harald von der"
+--~ local sample_b = "Hans Hagen and Taco Whoever T. Ex. Hoekwater and Hartmut Harald von der Henkel Hut"
+
+--~ test(sample_a)
+--~ test(sample_b)
diff --git a/tex/context/base/bibl-bib.mkiv b/tex/context/base/bibl-bib.mkiv
new file mode 100644
index 000000000..10abe5cb8
--- /dev/null
+++ b/tex/context/base/bibl-bib.mkiv
@@ -0,0 +1,962 @@
+%D \module
+%D [ file=bibl-bib,
+%D version=2007.08.17,
+%D title=\CONTEXT\ Bibliography Support,
+%D subtitle=Initialization,
+%D author=Hans Hagen \& Taco Hoekwater,
+%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 Bibliography Support / Experimental BibTeX}
+
+\registerctxluafile{bibl-bib}{1.001}
+
+\unprotect
+
+% todo: et al limiters
+% todo: split: citationvariant and publicationvariant
+
+%D This interface is under development. As I don't use \BIBTEX\ myself I need
+%D some motivation to spend time on it, and an occasional question on the
+%D list can be a reason. A few examples. As \BIBTEX\ databases can be poluted
+%D by local commands, we need to catch:
+%D
+%D \startbuffer
+%D \defbibtexcommand\MF {MF}
+%D \defbibtexcommand\MP {MP}
+%D \defbibtexcommand\TUB {TUGboat}
+%D \defbibtexcommand\Mc {Mac}
+%D \defbibtexcommand\sltt{\tt}
+%D \defbibtexcommand\<#1>{\type{#1}}
+%D \defbibtexcommand\acro#1{#1}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Let's define a session and load a few databases. We convert to \UTF\ and
+%D strip commands.
+%D
+%D \startbuffer
+%D \definebibtexsession [somebibtex]
+%D \registerbibtexfile [somebibtex] [tugboat.bib]
+%D \registerbibtexfile [somebibtex] [komoedie.bib]
+%D \preparebibtexsession [somebibtex] [convert,strip]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D This loads an mapping (work in progress):
+%D
+%D \startbuffer
+%D \def\currentbibtexformat{apa} \input bxml-\currentbibtexformat.mkiv
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D There are several ways to handle the \XML. It helps if you're a bit
+%D familiar with \XML\ processing in \MKIV.
+%D
+%D Here we regular setups. Three elements are mapped but only one
+%D is actually used and applied to root element \type {/bibtex}.
+%D
+%D \startbuffer
+%D \startxmlsetups bibtex
+%D \xmlregistereddocumentsetups{#1}{}
+%D \xmlsetsetup{#1}{bibtex|entry|field}{bibtex:*}
+%D \xmlmain{#1}
+%D \stopxmlsetups
+%D
+%D \startxmlsetups bibtex:bibtex
+%D \xmlfilter{#1}{
+%D /entry[@category='article']
+%D /field[@name='author' and (find(text(),'Hagen') or find(text(),'Hoekwater'))]
+%D /../command(bibtex:format)
+%D }
+%D \stopxmlsetups
+%D
+%D \applytobibtexsession[somebibtex][bibtex]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D A simpler setup is given next. Here we just apply a setup to the root
+%D element directly:
+%D
+%D \startbuffer
+%D \startxmlsetups bibtex:list
+%D \xmlfilter{#1}{/bibtex/entry/command(bibtex:format)}
+%D \stopxmlsetups
+%D
+%D \applytobibtexsession[somebibtex][bibtex:list]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D A slightly more complex expression:
+%D
+%D \startbuffer
+%D \startxmlsetups bibtex:filter
+%D \xmlfilter{#1}{
+%D /bibtex
+%D /entry[@category='article']
+%D /field[@name='author' and (find(text(),'Hagen') or find(text(),'Hoekwater'))]
+%D /../command(bibtex:format)
+%D }
+%D \stopxmlsetups
+%D
+%D \applytobibtexsession[somebibtex][bibtex:filter]
+%D \stopbuffer
+%D
+%D \typebuffer
+
+\newtoks \everydefinebibtexsession
+\newtoks \everypreparebibtexsession
+\newtoks \everysetupbibtexsession
+\setfalse \tracebibtexformat
+
+\unexpanded\def\definebibtexsession {\dosingleargument\dodefinebibtexsession}
+\def\preparebibtexsession {\dodoubleempty \dopreparebibtexsession}
+\unexpanded\def\setupbibtexsession {\dodoubleargument\dosetupbibtexsession}
+
+\def\dodefinebibtexsession [#1]{\edef\currentbibtexsession{#1}%
+ \ctxlua{commands.definebibtexsession("#1")}%
+ \the\everydefinebibtexsession}
+
+\def\dopreparebibtexsession[#1][#2]{\edef\currentbibtexsession{#1}%
+ \ctxlua{commands.preparebibtexsession("#1","bibtex:#1","#2")}%
+ \the\everypreparebibtexsession}
+
+\def\dosetupbibtexsession [#1][#2]{\edef\currentbibtexsession{#1}%
+ \getparameters[\??pb#1][#2]%
+ \the\everysetupbibtexsession}
+
+\def\registerbibtexfile {\dodoubleargument\doregisterbibtexfile}
+\def\registerbibtexentry {\dodoubleargument\doregisterbibtexentry}
+\def\applytobibtexsession {\dodoubleargument\doapplytobibtexsession}
+
+\def\doregisterbibtexfile [#1][#2]{\ctxlua{commands.registerbibtexfile("#1","#2")}}
+\def\doregisterbibtexentry [#1][#2]{\ctxlua{commands.registerbibtexentry("#1","#2")}}
+\def\doapplytobibtexsession[#1][#2]{\xmlprocessregistered{bibtex:#1}{#2}{#2}}
+
+\unexpanded\def\bibtexcommand#1%
+ {\ifcsname\??pb:c:#1\endcsname \else
+ \fakebibtexcommand{#1}%
+ \fi
+ \csname\??pb:c:#1\endcsname}
+
+\def\fakebibtexcommand#1%
+ {\ifcsname#1\endcsname
+ \writestatus{bibtex}{unknown command: #1, using built-in context variant}%
+ \setugvalue{\??pb:c:#1}{\dosomebibtexcommand{#1}}%
+ \else
+ \writestatus{bibtex}{unknown command: #1}%
+ \setugvalue{\??pb:c:#1}{\dofakebibtexcommand{#1}}%
+ \fi}
+
+\let\dosomebibtexcommand \getvalue
+\def\dofakebibtexcommand#1{{\tttf#1}}
+
+\def\defbibtexcommand#1%
+ {\setuvalue{\strippedcsname#1}}
+
+\def\bibxmldoifelse#1{\xmldoifelse\currentbibxmlnode{/field[@name='#1']}}
+\def\bibxmldoif #1{\xmldoif \currentbibxmlnode{/field[@name='#1']}}
+\def\bibxmldoifnot #1{\xmldoifnot \currentbibxmlnode{/field[@name='#1']}}
+\def\bibxmlflush #1{\xmlcontext \currentbibxmlnode{/field[@name='#1']}}
+\def\bibxmlsetup {\xmlsetup \currentbibxmlnode} % {#1}
+
+\def\currentbibtexformat{apa} % ho wto interface this, maybe split loading and key
+\def\currentbibxmlnode {unset}
+\def\currentbibxmltag {unset}
+
+\startxmlsetups bibtex
+ \xmlregistereddocumentsetups{#1}{}
+ \xmlsetsetup{#1}{bibtex|entry|field}{bibtex:*}
+ \xmlmain{#1}
+\stopxmlsetups
+
+\startxmlsetups bibtex:format
+ \bibtexpublicationsparameter\c!before\relax % prevents lookahead
+ \edef\currentbibxmlnode {#1}
+ \edef\currentbibxmltag {\xmlatt{#1}{tag}}
+ \edef\currentbibxmlcategory{\xmlatt{#1}{category}}
+ \ifconditional\tracebibtexformat
+ \tracedbibxmlintro\currentbibxmltag
+ \tracedbibxmlintro\currentbibxmlcategory
+ \fi
+ \ignorespaces
+ \xmlcommand{#1}{.}{bibtex:\currentbibtexformat:\currentbibxmlcategory}
+ \removeunwantedspaces
+ \bibtexpublicationsparameter\c!after\relax % prevents lookahead
+\stopxmlsetups
+
+\startxmlsetups bibtex:list
+ \xmlfilter{#1}{/bibtex/entry/command(bibtex:format)}
+\stopxmlsetups
+
+\startxmlsetups bibtex:bibtex
+ \xmlfilter{#1}{/entry/command(bibtex:format)}
+\stopxmlsetups
+
+% formatters
+
+\let\normalbibxmlflush\bibxmlflush
+
+\definecolor[bibtextracecolor:field] [darkred]
+\definecolor[bibtextracecolor:crossref][darkblue]
+\definecolor[bibtextracecolor:key] [darkgreen]
+
+\def\tracedbibxmlintro #1{{\tttf#1 -> }}
+\def\tracedbibxmlflush #1{\color[bibtextracecolor:field] {\tttf[#1]}}
+\def\tracedbibxmltexts #1{\color[bibtextracecolor:field] {\tttf<#1>}}
+\def\tracedbibxmlcrossref#1{\color[bibtextracecolor:crossref]{\tttf#1}}
+\def\tracedbibxmlkey #1{\color[bibtextracecolor:key] {\tttf#1}}
+
+\def\tracedbibxmltext
+ {\ifconditional\tracebibtexformat
+ \expandafter\tracedbibxmltexts % plural
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\def\bibxmlflush
+ {\ifconditional\tracebibtexformat
+ \expandafter\tracedbibxmlflush
+ \else
+ \expandafter\normalbibxmlflush
+ \fi}
+
+\startxmlsetups bibtex:format:crossref
+ \ifconditional\tracebibtexformat
+ \tracedbibxmlcrossref{\xmlfirst\currentbibxmlnode{/field[@name='crossref']/lower()}}
+ \else
+ \cite[\xmlfirst\currentbibxmlnode{/field[@name='crossref']/lower()}]
+ \fi
+\stopxmlsetups
+
+\startxmlsetups bibtex:format:key
+ \ifconditional\tracebibtexformat
+ \tracedbibxmlkey{\normalbibxmlflush{key}}
+ \else
+ \bibxmlflush{key}
+ \fi
+\stopxmlsetups
+
+\startxmlsetups bibtex:format:common:author
+ \ifconditional\tracebibtexformat
+ \bibxmlflush\currentbibtexvariant
+ \else
+ \xmlfilter{#1}{/field[@name='\currentbibtexvariant']/bibtexconcat('\currentbibtexvariant')}
+ \fi
+\stopxmlsetups
+
+\startxmlsetups bibtex:format:author
+ \begingroup
+ \def\currentbibtexvariant{author}
+ \xmlsetup{#1}{bibtex:format:common:author}
+ \endgroup
+\stopxmlsetups
+
+\startxmlsetups bibtex:format:artauthor
+ \begingroup
+ \def\currentbibtexvariant{artauthor}
+ \xmlsetup{#1}{bibtex:format:common:author}
+ \endgroup
+\stopxmlsetups
+
+\startxmlsetups bibtex:format:editor
+ \begingroup
+ \def\currentbibtexvariant{editor}
+ \xmlsetup{#1}{bibtex:format:common:author}
+ \endgroup
+\stopxmlsetups
+
+\startxmlsetups bibtex:format:doi
+% \bibdoifelse{\@@pb@doi}{#1\expanded{\bibgotoDOI{\@@pb@thekey}{\@@pb@doi}}#2}{#3}
+ *doi*
+\stopxmlsetups
+
+
+\startxmlsetups bibtex:format:doi
+% \bibdoifelse{\@@pb@biburl}{#1\expanded{\bibgotoURL{\@@pb@thekey}{\@@pb@biburl}}#2}{#3}
+ *url*
+\stopxmlsetups
+
+\startxmlsetups bibtex:format:month
+% {\bibdoifelse\@@pb@month
+% {#1\doifnumberelse\@@pb@month
+% {\doifconversiondefinedelse\@@pbmonthconversion
+% {\convertnumber\@@pbmonthconversion\@@pb@month}{\@@pb@month}}%
+% {\@@pb@month}#2}%
+% {#3}
+ *month*
+\stopxmlsetups
+
+% lists
+
+\def\bibtexlistprocessor
+ {\ctxlua{bibtex.hacks.add(structure.lists.uservalue("\currentlist",\currentlistindex,"bibref"),\currentlistindex)}}
+
+\appendtoks
+ \definelist[\currentbibtexsession]%
+ \setuplist[\currentbibtexsession][\c!state=\v!start,\c!width=]%
+ \installstructurelistprocessor{\currentbibtexsession:userdata}{\bibtexlistprocessor}%
+\to \everydefinebibtexsession
+
+% \def\installbibtexsorter#1#2%
+% {\setvalue{\??pb:\c!sort:#1}{#2}}
+
+% \installbibtexsorter\v!no {no}
+% \installbibtexsorter\v!author {au}
+% \installbibtexsorter\v!title {ti}
+% \installbibtexsorter\v!short {ab}
+% \installbibtexsorter\empty {no}
+% \installbibtexsorter\s!default{no}
+
+% \setupbibtex
+% [\c!sorttype=\v!cite,
+% \c!sort=no]
+
+% \long\unexpanded\def\startpublication#1\stoppublication
+% {\blank
+% todo
+% \blank}
+
+% \let\stoppublication\relax
+
+\unexpanded\def\bibtexspace {\removeunwantedspaces\space}
+\unexpanded\def\bibtexperiod {\removeunwantedspaces.\space}
+\unexpanded\def\bibtexcomma {\removeunwantedspaces,\space}
+\unexpanded\def\bibtexlparent {\removeunwantedspaces\space(}
+\unexpanded\def\bibtexrparent {\removeunwantedspaces)\space}
+\unexpanded\def\bibtexlbracket{\removeunwantedspaces\space[}
+\unexpanded\def\bibtexrbracket{\removeunwantedspaces]\space}
+
+% interfacing
+
+% todo : lang en language
+% todo : directions
+
+
+% variables
+
+\newcount\bibtexblock \bibtexblock\plusone
+
+\newtoks \everysetupbibtexpublications
+\newtoks \everysetupbibtexcitations
+\newcount\bibtexcounter
+
+\def\bibtexrefprefix{\number\bibtexblock:}
+
+\let\currentbibtexsession\s!default
+\let\currentbibtexvariant\s!default
+
+% parameters: session+variant variant session shared
+
+\def\bibtexpublicationsparameter#1%
+ {\csname
+ \ifcsname\??pb\currentbibtexsession:\currentbibtexvariant#1\endcsname
+ \??pb\currentbibtexsession:\currentbibtexvariant#1%
+ \else\ifcsname\??pb:\currentbibtexvariant#1\endcsname
+ \??pb:\currentbibtexvariant#1%
+ \else\ifcsname\??pb\currentbibtexsession#1\endcsname
+ \??pb\currentbibtexsession#1%
+ \else\ifcsname\??pb#1\endcsname
+ \??pb#1%
+ \else
+ \s!empty
+ \fi\fi\fi\fi
+ \endcsname}
+
+\def\bibtexcitationparameter#1%
+ {\csname
+ \ifcsname\??pv\currentbibtexsession:\currentbibtexvariant#1\endcsname
+ \??pv\currentbibtexsession:\currentbibtexvariant#1%
+ \else\ifcsname\??pv:\currentbibtexvariant#1\endcsname
+ \??pv:\currentbibtexvariant#1%
+ \else\ifcsname\??pv\currentbibtexsession#1\endcsname
+ \??pv\currentbibtexsession#1%
+ \else\ifcsname\??pv#1\endcsname
+ \??pv#1%
+ \else
+ \s!empty
+ \fi\fi\fi\fi
+ \endcsname}
+
+% setup commands
+
+\unexpanded\def\setupbibtexpublications
+ {\let\currentpublicationclass\??pb
+ \let\everysetupbibtexwhatever\everysetupbibtexpublications
+ \dodoubleargument\dosetupbibtexwhatever}
+
+\unexpanded\def\setupbibtexcitations
+ {\let\currentpublicationclass\??pv
+ \let\everysetupbibtexwhatever\everysetupbibtexcitations
+ \dodoubleargument\dosetupbibtexwhatever}
+
+\unexpanded\def\setupbibtexpublicationvariants
+ {\let\currentpublicationclass\??pb
+ \let\everysetupbibtexwhatever\everysetupbibtexpublications
+ \dotripleargument\dosetupbibtexwhatevervariant}
+
+\unexpanded\def\setupbibtexcitationvariants
+ {\let\currentpublicationclass\??pv
+ \let\everysetupbibtexwhatever\everysetupbibtexcitations
+ \dotripleargument\dosetupbibtexwhatevervariant}
+
+\def\dosetupbibtexwhatever[#1][#2]% [sessionlist] [setup]
+ {\ifsecondargument
+ % sessions setups
+ \def\dobtxcommand##1{\getparameters[\currentpublicationclass##1][#2]}%
+ \processcommalist[#1]\dobtxcommand
+ \else
+ % setups
+ \getparameters[\currentpublicationclass][#1]%
+ \the\everysetupbibtexwhatever
+ \fi}
+
+\def\dosetupbibtexwhatevervariant[#1][#2][#3]% [sessionlist] [variantlist] [setup]
+ {\ifthirdargument
+ % sessions variants setups
+ \def\dobtxcommand##1%
+ {\def\dodobtxcommand####1{\getparameters[\currentpublicationclass##1:####1][#3]}%
+ \processcommalist[#2]\dodobtxcommand}%
+ \processcommalist[#1]\docbtxommand
+ \else\ifsecondargument
+ % variants setups
+ \def\dobtxcommand##1{\getparameters[\currentpublicationclass:##1][#2]}%
+ \processcommalist[#1]\dobtxcommand
+ \else
+ % setups
+ \getparameters[\currentpublicationclass][#1]%
+ \the\everysetupbibtexwhatever
+ \fi\fi}
+
+% some initializations
+
+\setupbibtexcitationvariants
+ [author,authoryear,authoryears]
+ [\c!namesep={, }]
+
+% loading alternatives (apa etc)
+
+\def\doloadbibtexpublicationalternative
+ {\ifproductionrun
+ \edef\bibtexpublicationsalternative{\@@pbalternative}% parent
+ \ifx\bibtexpublicationsalternative\empty \else
+ \processcommacommand[\bibtexpublicationsalternative]\dodoloadbibtexpublicationalternative
+ \let\@@pbalternative\empty
+ \fi
+ \fi}
+
+\def\dodoloadbibtexpublicationalternative#1%
+ {\doonlyonce{#1}
+ {\readsysfile{bxml-#1.mkiv}
+ {\showmessage\m!publications{6}{bxml-#1}}
+ {\showmessage\m!publications{1}{bxml-#1}}}}
+
+\appendtoks
+ \doloadbibtexpublicationalternative
+\to \everysetupbibtexpublications
+
+\appendtoks
+ \doloadbibtexpublicationalternative
+\to \everyjob
+
+% whatever, should be key
+
+\def\bibtexleftnumber#1{#1\hfill~}
+
+% testing
+
+% \showmessage\m!publications{5}{#1 is unknown}\secondoftwoarguments}
+
+\let\doifbibreferencefoundelse\secondofthreearguments
+
+% lists
+
+\newtoks\everysetupbibtexlistplacement
+
+% this will change as we need it too often .. we will use context.thebibtexnamesep
+
+\appendtoks
+ \ctxlua {bibtex.authors.setsettings {
+ namesep = \!!bs\bibtexpublicationsparameter\c!namesep\!!es,
+ lastnamesep = \!!bs\bibtexpublicationsparameter\c!lastnamesep\!!es,
+ finalnamesep = \!!bs\bibtexpublicationsparameter\c!finalnamesep\!!es,
+ firstnamesep = \!!bs\bibtexpublicationsparameter\c!firstnamesep\!!es,
+ juniorsep = \!!bs\bibtexpublicationsparameter\c!juniorsep\!!es,
+ vonsep = \!!bs\bibtexpublicationsparameter\c!vonsep\!!es,
+ surnamesep = \!!bs\bibtexpublicationsparameter\c!surnamesep\!!es,
+ namesep = \!!bs\bibtexpublicationsparameter\c!namesep\!!es,
+ lastnamesep = \!!bs\bibtexpublicationsparameter\c!lastnamesep\!!es,
+ finalnamesep = \!!bs\bibtexpublicationsparameter\c!finalnamesep\!!es,
+ author = {
+ etallimit = \!!bs\bibtexpublicationsparameter\c!authoretallimit\!!es,
+ etaldisplay = \!!bs\bibtexpublicationsparameter\c!authoretaldisplay\!!es,
+ etaltext = \!!bs\bibtexpublicationsparameter\c!authoretaltext\!!es,
+ },
+ editor = {
+ etallimit = \!!bs\bibtexpublicationsparameter\c!editoretallimit\!!es,
+ etaldisplay = \!!bs\bibtexpublicationsparameter\c!editoretaldisplay\!!es,
+ etaltext = \!!bs\bibtexpublicationsparameter\c!editoretaltext\!!es,
+ },
+ artauthor = {
+ etallimit = \!!bs\bibtexpublicationsparameter\c!artauthoretallimit\!!es,
+ etaldisplay = \!!bs\bibtexpublicationsparameter\c!artauthoretaldisplay\!!es,
+ etaltext = \!!bs\bibtexpublicationsparameter\c!artauthoretaltext\!!es,
+ },
+ } }%
+\to \everysetupbibtexlistplacement
+
+\def\completebibtexpublications{\dodoubleempty\docompletebibtexpublications}
+\unexpanded\def\placebibtexpublications {\dodoubleempty\doplacebibtexpublications}
+
+\def\docompletebibtexpublications[#1][#2]% title might become obsolete, just headtext
+ {\begingroup
+ \edef\currentbibtexsession{#1}%
+ \let\currentlist\currentbibtexsession
+ \setuplist[\currentbibtexsession][\c!criterium=\v!previous,#2]
+ \doifelsenothing{\namedlistparameter\currentbibtexsession\c!title}
+ {\systemsuppliedchapter[\currentbibtexsession]{\headtext{\currentbibtexsession}}}
+ {\normalexpanded{\systemsuppliedchapter[\currentbibtexsession]{\namedlistparameter\currentbibtexsession\c!title}}}%
+ \dodoplacebibtexpublications}
+
+\def\doplacebibtexpublications[#1][#2]%
+ {\begingroup
+ \edef\currentbibtexsession{#1}%
+ \let\currentlist\currentbibtexsession
+ \setuplist[\currentbibtexsession][\c!criterium=\v!previous,#2]%
+ \dodoplacebibtexpublications}
+
+\def\dodoplacebibtexpublications
+ {\determinelistcharacteristics[\currentbibtexsession]%
+ \the\everysetupbibtexlistplacement
+ \forgetall
+ \typesetbibtexlist
+ \endgroup
+ \global\advance\bibtexblock\plusone}
+
+\setvalue{\??pb:\c!numbering:\v!short}#1% todo var s -> short tag
+ {\bibtexlistnumberbox{\bibtexpublicationsparameter\c!numbercommand{\bibtexgetshort\currentpublicationtag}}}
+
+\setvalue{\??pb:\c!numbering:\v!bib}#1% todo var n -> number
+ {\bibtexlistnumberbox{\bibtexpublicationsparameter\c!numbercommand{\bibtexgetnumber\currentpublicationtag}}}
+
+\setvalue{\??pb:\c!numbering:\s!unknown}#1%
+ {\bibtexlistnumberbox{\bibtexpublicationsparameter\c!numbercommand{#1}}}
+
+\def\@@pblimitednumber % name
+ {\csname\??pb:\c!numbering:%
+ \ifcsname\??pb:\c!numbering:\currentbibtexnumbering\endcsname
+ \currentbibtexnumbering
+ \else
+ \s!unknown
+ \fi
+ \endcsname}
+
+\appendtoks
+ \edef\currentbibtexnumbering{\bibtexpublicationsparameter\c!numbering}%
+ \ifx\currentbibtexnumbering\v!no
+ \setuplist[\currentbibtexsession][\c!numbercommand=,\c!symbol=\v!none,\c!textcommand=\outdented]%
+ \else
+ \setuplist[\currentbibtexsession][\c!numbercommand=\@@pblimitednumber]%
+ \fi
+\to \everysetupbibtexlistplacement
+
+\newdimen\bibtexnumberwidth
+
+\def\bibtexlistnumberbox{\hbox \ifcase\bibtexnumberwidth\else to \bibtexnumberwidth\fi}
+
+\appendtoks
+ \doifelse{\bibtexpublicationsparameter\c!autohang}\v!yes
+ {\ifx\currentbibtexnumbering\v!short
+ \setbox\scratchbox\hbox{\bibtexpublicationsparameter\c!numbercommand{\bibtexpublicationsparameter\c!samplesize}}%
+ \else
+ \setbox\scratchbox\hbox{\bibtexpublicationsparameter\c!numbercommand{\ctxlua{tex.write(structure.lists.size())}}}%
+ \fi
+ \bibtexnumberwidth\wd\scratchbox
+ \setuplist[\currentbibtexsession][\c!distance=\zeropoint]}
+ {\doifelsenothing{\bibtexpublicationsparameter\c!width}
+ {\bibtexnumberwidth\zeropoint}
+ {\bibtexnumberwidth\bibtexpublicationsparameter\c!width}}%
+ \setuplist[\currentbibtexsession][\c!width=\bibtexnumberwidth]%
+\to \everysetupbibtexlistplacement
+
+\appendtoks
+ \let\maybeyear\gobbleoneargument
+ \let\noopsort \gobbleoneargument
+\to \everysetupbibtexlistplacement
+
+\appendtoks
+ \doifelse{\bibtexpublicationsparameter\c!maybeyear}\v!off
+ {\let\maybeyear\gobbleoneargument}
+ {\let\maybeyear\firstofoneargument}%
+\to \everysetupbibtexlistplacement
+
+\appendtoks
+ \doifnot{\bibtexpublicationsparameter\c!option}\v!continue
+ {\global\bibtexcounter\zerocount}%
+\to \everysetupbibtexlistplacement
+
+\appendtoks
+ \edef\currentbibtexcriterium{\namedlistparameter\currentbibtexsession\c!criterium}%
+\to \everysetupbibtexlistplacement
+
+\def\typesetbibtexlist
+ {\dobeginoflist
+ \doif{\namedlistparameter\currentbibtexsession\c!criterium}\v!cite
+ {\setuplist[\currentbibtexsession][\c!criterium=\v!here]}%
+ \doifelse{\bibtexpublicationsparameter\c!method}\v!local
+ {\ctxlua{bibtex.hacks.reset(1)}}% function can take method
+ {\ctxlua{bibtex.hacks.reset(2)}}%
+ \placestructurelist
+ {\currentbibtexsession}
+ {\currentbibtexcriterium}
+ {\namedlistparameter\currentbibtexsession\c!number}%
+ \ctxlua{bibtex.hacks.flush("\bibtexpublicationsparameter\c!sorttype")}%
+ \doendoflist}
+
+\unexpanded\def\typesetbibtexpublication#1%
+ {\edef\currentbibtexsessiontag{#1}%
+ \ifx\currentbibtexsessiontag\empty
+ % can't really happen
+ \else\ifx\currentbibtexcriterium\v!all
+ \doplacepublicationindeed
+ \else
+ \ctxlua{bibtex.hacks.doifalreadyplaced("\currentbibtexsessiontag")}
+ \donothing
+ \dotypesetbibtexpublication
+ \fi\fi}
+
+\def\dotypesetbibtexpublication
+ {\doifbibreferencefoundelse\currentbibtexsessiontag
+ {\global\advance\bibtexcounter\plusone
+ \ctxlua{bibtex.hacks.registerplaced("\currentbibtexsessiontag")}%
+ \dodolistelement{\currentbibtexsession}{}{\number\bibtexcounter}{\thebibtexpublicationlistelement}{}{}}
+ {}} % invalid
+
+\def\thebibtexpublicationlistelement
+ {\strut
+ \expanded{\reference[\bibtexrefprefix\currentbibtexsessiontag]{\number\bibtexcounter}}%
+ \dotypesetabibtexpublication\currentbibtexsessiontag
+ \strut}
+
+\def\dotypesetabibtexpublication#1%
+ {\begingroup
+ \ignorespaces
+ \xmlfilter{bibtex:\currentbibtexsession}{/bibtex/entry[@tag='#1']/command(bibtex:format)}%
+ \removeunwantedspaces
+% \ignorespaces
+% \bibalternative{\bibgetvart{#1}}%
+% \removeunwantedspaces
+ \endgroup}
+
+\def\doprocessbibtexentry#1{\typesetbibtexpublication{#1}}
+
+% citations
+
+\unexpanded\def\bibtexcitation[#1]%
+ {\edef\currentbibtexsession{#1}%
+ \strictdoifnextoptionalelse\dobibtexcitation\dobibtexref}
+
+\def\dobibtexref#1%
+ {\dodobibtexcitation[#1][]}
+
+\def\dobibtexcitation[#1]%
+ {\strictdoifnextoptionalelse{\dodobibtexcitation[#1]}{\dodobibtexcitation[#1][]}}
+
+\def\dodobibtexcitation[#1][#2]%
+ {\dontleavehmode
+ \begingroup
+ \doifelsenothing{#2}\secondargumentfalse\secondargumenttrue
+ \ifsecondargument
+ \dowhateverbibtexcitation{#1}{#2}%
+ \else
+ \donumberedbibtexcitation{#1}%
+ \fi
+ \endgroup}
+
+\def\dowhatevercitation#1#2%
+ {\processcommalist[#2]\dobibtexcitationindeed
+ \setupinteraction[\c!style=]% use flag instead
+ \doifassignmentelse{#1}
+ {\getparameters[\??pb\??pb][\c!alternative=,\c!extras=,#1]%
+ \edef\currentbibtexvariant{\@@pb@@pbalternative}%
+ \ifx\currentbibtexvariant\empty
+ \edef\currentbibtexvariant{\bibtexpublicationparameter\c!refcommand}%
+ \fi
+ \ifx\@@pb@@pbextras\empty
+ \setupcite[\currentbibtexvariant][#1]%
+ \else
+ \edef\@@pb@@pbextras{{\@@pb@@pbextras\ifdefined\@@pb@@pbright\@@pb@@pbright\else\bibtexpublicationparameter\c!right\fi}}%
+ \expanded{\setupcite[\currentbibtexvariant][#1,\c!right=\@@pb@@pbextras]}%
+ \fi}%
+ {\def\currentbibtexvariant{#1}}%
+ \getvalue{bibtex\currentbibtexvariant ref}[#2]}
+
+\def\donumberedbibtexcitation#1%
+ {\processcommalist[#1]\dobibtexcitationindeed
+ \setupinteraction[\c!style=]%
+ \edef\currentbibtexvariant{\bibtexcitationparameter\c!refcommand}%
+ \getvalue{bibtex\currentbibtexvariant ref}[#1]}
+
+\def\dobibtexcitationindeed#1%
+ {\iftrialtypesetting \else
+ \expanded{\writedatatolist[\currentbibtexsession][bibref=#1]}%
+ \fi}
+
+\def\nobibtexcitation[#1]%
+ {\processcommalist[#1]\dobibtexcitationindeed}
+
+\def\bibtexnumref[#1]%
+ {\dontleavehmode
+ \begingroup
+ \bibtexcitationparameter\v!left
+ \penalty\!!tenthousand
+ \ctxlua{bibtex.hacks.resolve("","\number\bibtexblock","#1")}%
+ \bibtexcitationparameter\v!right
+ \endgroup}
+
+\def\dowithbibtexnumrefconnector#1#2%
+ {\ifnum#1>\plusone
+ \ifnum#2>\plusone
+ \ifnum#2=#1\relax
+ \bibtexpublicationsparameter\c!lastpubsep
+ \else
+ \bibtexpublicationsparameter\c!pubsep
+ \fi
+ \fi
+ \fi}
+
+\def\dowithbibtexnumref#1#2#3#4#5% n, i, prefix block ref
+ {\dowithbibtexnumrefconnector{#1}{#2}%
+ \def\bibtexrefprefix{#4:}%
+ \inbiblink[#5]}
+
+\def\dowithbibtexnumrefrange#1#2#3#4#5#6#7% n, i, prefix block ref
+ {\dowithbibtexnumrefconnector{#1}{#2}%
+ \def\bibtexrefprefix{#4:}%
+ \inbiblink[#5]%
+ \endash
+ \def\bibtexrefprefix{#6:}%
+ \inbiblink[#7]}
+
+\def\nobibtexnumref#1%
+ {[#1]}
+
+% hm
+
+% \def\@@pbinumbercommand{\executeifdefined{\??pb:\c!numbercommand:\@@pbnumbering}\firstofoneargument}
+
+% \letvalue{\??pb:\c!numbercommand:\v!yes }\firstofoneargument
+% \letvalue{\??pb:\c!numbercommand:\v!no }\gobbleoneargument
+% \setvalue{\??pb:\c!numbercommand:\v!short}{\bibtexgetshort\currentpublicationtag\gobbleoneargument}
+% \setvalue{\??pb:\c!numbercommand:\v!bib }{\bibtexgetnumber\currentpublicationtag\gobbleoneargument}
+
+% \def\bibalternative#1{\csname\??pv\@@currentalternative#1\endcsname}
+
+% basic setup
+
+% parent -> publicationlist
+%
+% \setuplist
+% [\currentbibtexsession]
+% [\c!samplesize={AA99},
+% \c!alternative=a,
+% \c!interaction=,
+% \c!pagenumber=\v!no,
+% #1,
+% \c!command=]
+
+% \setuppublicationlist
+% [\c!title=,
+% \c!command=\dospecialbibinsert,
+% \c!maybeyear=\v!on]
+
+\setupbibtexpublications
+ [\c!monthconversion=,
+ \c!alternative=apa,
+ \c!method=\v!global,
+ \c!refcommand=num,
+ \c!numbercommand=\bibtexleftnumber]
+
+\setupbibtexcitations % command ?
+ [\c!refcommand=num]
+
+% helpers
+
+\def\doifbibtexinteractionelse
+ {\iflocation
+ \edef\temp{\bibtexcitationparameter\c!interaction}%
+ \ifx\temp\v!stop
+ \@EA@EA@EA\secondoftwoarguments
+ \else
+ \@EA@EA@EA\firstoftwoarguments
+ \fi
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+% variants
+
+% todo: lastsep here
+
+\newconditional\firstbibtexrefsep
+
+\def\bibtexresetrefsep
+ {\settrue\firstbibtexrefsep}
+
+\def\bibtexinsertrefsep
+ {\ifconditional\firstbibtexrefsep
+ \setfalse\firstbibtexrefsep
+ \else
+ \bibtexcitationparameter\c!pubsep
+ \fi}
+
+\def\inbibtexlink#1#2%
+ {\doifreferencefoundelse{\bibtexrefprefix#1}
+ {\goto{#2}[\bibtexrefprefix#1]}
+ {!#1!\unknownreference{#1}}}
+
+\def\dobibtexgotolink#1#2%
+ {\doifreferencefoundelse{\bibtexrefprefix#1}
+ {\goto{#2}[\bibtexrefprefix#1]}
+ {!#1!\unknownreference{#1}}}
+
+\def\dobibattexlink#1#2%
+ {\doifreferencefoundelse{\bibtexrefprefix#1}
+ {\at{#2}[\bibtexrefprefix#1]}
+ {!#1!\unknownreference{#1}}}
+
+\def\dobibtexurllink#1#2%
+ {\expanded{\useURL[bibtex:url:#1][#2]}%
+ \doifbibtexinteractionelse
+ {\goto{\url[bibtex:url:#1]}[url(bibtex:url:#1)]}
+ {\url[bibtex:url:#1]}}
+
+% todo: style, color
+
+\unexpanded\def\bibtexdataref {\dodoubleargument\dobibtexdataref}
+\unexpanded\def\bibtextyperef {\dodoubleargument\dobibtextyperef}
+\unexpanded\def\bibtexkeyref {\dodoubleargument\dobibtexkeyref}
+\unexpanded\def\bibtexserialref {\dodoubleargument\dobibtexserialref}
+\unexpanded\def\bibtexurlref {\dodoubleargument\dobibtexurlref}
+\unexpanded\def\bibtexdoiref {\dodoubleargument\dobibtexdoiref}
+\unexpanded\def\bibtexpageref {\dodoubleargument\dobibtexpageref}
+\unexpanded\def\bibtexnoneref {\dodoubleargument\dobibtexnoneref}
+\unexpanded\def\bibtexshortref {\dodoubleargument\dobibtexshortref}
+\unexpanded\def\bibtexyearref {\dodoubleargument\dobibtexyearref}
+\unexpanded\def\bibtexauthorref {\dodoubleargument\dobibtexauthorref}
+\unexpanded\def\bibtexauthoryearref {\dodoubleargument\dobibtexauthoryearref}
+\unexpanded\def\bibtexauthoryearsref{\dodoubleargument\dobibtexauthoryearsref}
+
+\def\dobibtexdataref {\doprocessbibtexref\dodobibtexdataref {ref}} % [#1][#2]
+\def\dobibtextyperef {\doprocessbibtexref\dodobibtextyperef {type}} % [#1][#2]
+\def\dobibtexkeyref {\doprocessbibtexref\dodobibtexkeyref {key}} % [#1][#2]
+\def\dobibtexserialref {\doprocessbibtexref\dodobibtexserialref {serial}} % [#1][#2]
+\def\dobibtexurlref {\doprocessbibtexref\dodobibtexurlref {url}} % [#1][#2]
+\def\dobibtexdoiref {\doprocessbibtexref\dodobibtexdoiref {doi}} % [#1][#2]
+\def\dobibtexpageref {\doprocessbibtexref\dodobibtexpageref {page}} % [#1][#2]
+\def\dobibtexnoneref {\doprocessbibtexref\dodobibtexnoneref {none}} % [#1][#2]
+\def\dobibtexshortref {\doprocessbibtexref\dodobibtexshortref {short}} % [#1][#2]
+\def\dobibtexyearref {\doprocessbibtexref\dodobibtexyearref {year}} % [#1][#2]
+\def\dobibtexauthorref {\doprocessbibtexref\dodobibtexauthorref {author}} % [#1][#2]
+\def\dobibtexauthoryearref {\doprocessbibtexref\dodobibtexauthoryearref {authoryear}} % [#1][#2]
+\def\dobibtexauthoryearsref{\doprocessbibtexref\dodobibtexauthoryearsref{authoryears}} % [#1][#2]
+
+\def\doprocessbibtexref#1#2[#3][#4]%
+ {\edef\currentbibtexsession{#3}%
+ \edef\currentbibtexvariant{#2}%
+ \def\dodoprocessbibtexref##1%
+ {% test for existence
+ \edef\currentbibtextag{##1}%
+ \bibtexinsertrefsep
+ #1{##1}}%
+ \bibtexresetrefsep
+ \bibtexcitationparameter\v!left
+ \processcommalist[#4]\dodoprocessbibtexref\relax
+ \bibtexcitationparameter\v!right}
+
+\def\dodobibtexdataref#1%
+ {\dotypesetabibtexpublication{#1}}
+
+\def\dodobibtextyperef#1%
+ {\edef\bibtexrefcontent{\xmlfilter{bibtex:\currentbibtexsession}{/bibtex/entry[@tag='#1']/attribute('category')}}%
+ \bibtexrefcontent}
+
+\def\dodobibtexkeyref#1%
+ {\edef\bibtexrefcontent{\xmlfilter{bibtex:\currentbibtexsession}{/bibtex/entry[@tag='key']/context()}}%
+ \dobibtexgotolink{#1}{\bibtexrefcontent}}
+
+\def\dodobibtexserialref#1%
+ {\edef\bibtexrefcontent{\xmlfilter{bibtex:\currentbibtexsession}{/bibtex/entry[@tag='#1']/match()}}%
+ \dobibtexgotolink{#1}{\bibtexrefcontent}}
+
+\def\dodobibtexurlref#1%
+ {\edef\bibtexrefcontent{\xmlfilter{bibtex:\currentbibtexsession}{/bibtex/entry[@tag='#1']/field[@name='url']/context()}}%
+ \dobibtexurllink{#1}{\bibtexrefcontent}}
+
+\def\dodobibtexdoiref#1%
+ {\edef\bibtexrefcontent{\xmlfilter{bibtex:\currentbibtexsession}{/bibtex/entry[@tag='#1']/field[@name='doi']/context()}}%
+ \dobibtexurllink{#1}{http://dx.doi.org/\bibtexrefcontent}}
+
+\def\dodobibtexpageref#1%
+ {\dobibtexatlink{#1}{}} % second argument can become 'page'
+
+\def\dodobibtexnoneref#1%
+ {}
+
+\def\dodobibtexshortref#1%
+ {\edef\bibtexrefcontent{\xmlfilter{bibtex:\currentbibtexsession}{/bibtex/entry[@tag='#1']/bibtexshort()}}%
+ \dobibtexgotolink{#1}{\bibtexrefcontent}}
+
+\def\dodobibtexyearref#1%
+ {\edef\bibtexrefcontent{\xmlfilter{bibtex:\currentbibtexsession}{/bibtex/entry[@tag='#1']/field[@name='year']/context()}}%
+ \bibtexrefcontent}
+
+% \def\bibmaybeinteractive#1#2%
+% {\doifelsevalue{@@pv\@@currentalternative\c!compress}
+% {\ifbibinteractionelse{\gotobiblink{#2}[#1]}{#2}}
+% {#2}}
+
+% \def\bibauthornumref[#1]%
+% {\getcommalistsize[#1]%
+% \global\bibitemcounter\commalistsize
+% \bibresetrefsep
+% \processcommalist[#1]\dobibauthornumref }
+%
+% \def\dobibauthornumref#1%
+% {\bibinsertrefsep
+% \doifbibreferencefoundelse{#1}
+% {\begingroup
+% \bibgetvara{#1}%
+% \bibalternative\c!inbetween
+% \setuppublications[\c!refcommand=num]%
+% \cite[#1]%
+% \endgroup}
+% {\unknownreference{#1}}}
+
+% compress years
+% andtext namesep
+% otherstext authoretallimit
+
+% we will use context.* instead at the lua end because it saves us passing settings
+
+% \def\thebibtexpubsep {\bibtexpublicationsparameter\c!pubsep}
+% \def\thebibtexlastpubsep {\bibtexpublicationsparameter\c!lastpubsep}
+% \def\thebibtexfinalpubseparator{\bibtexpublicationsparameter\c!lastpubsep}
+
+\def\dodobibtexauthorref #1{\ctxlua{bibtex.authorref ("bibtex:\currentbibtexsession","#1","normal","author")}}
+\def\dodobibtexauthoryearref #1{\ctxlua{bibtex.authoryearref ("bibtex:\currentbibtexsession","#1","normal","author")}}
+\def\dodobibtexauthoryearsref#1{\ctxlua{bibtex.authoryearsref("bibtex:\currentbibtexsession","#1","normal","author")}}
+
+\unexpanded\def\bibtexsingularplural#1#2{\ctxlua{bibtex.singular_or_plural(\!!bs#1\!!es,\!!bs#2\!!es)}}
+
+\protect \endinput
+
diff --git a/tex/context/base/bibl-tra.lua b/tex/context/base/bibl-tra.lua
new file mode 100644
index 000000000..442231028
--- /dev/null
+++ b/tex/context/base/bibl-tra.lua
@@ -0,0 +1,194 @@
+if not modules then modules = { } end modules ['bibl-bib'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+bibtex = bibtex or { }
+bibtex.hacks = bibtex.hacks or { }
+
+local match, gmatch, format, concat, sort = string.match, string.gmatch, string.format, table.concat, table.sort
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+local variables, constants = interfaces.variables, interfaces.constants
+
+local trace_bibtex = false trackers.register("publications.bibtex", function(v) trace_bibtex = v end)
+
+local hacks = bibtex.hacks
+
+local list, done, alldone, used, registered, ordered = { }, { }, { }, { }, { }, { }
+local mode = 0
+
+local template = string.striplong([[
+ \citation{*}
+ \bibstyle{cont-%s}
+ \bibdata{%s}
+]])
+
+function hacks.process(settings)
+ local style = settings.style or ""
+ local database = settings.database or ""
+ local jobname = tex.jobname
+ if database ~= "" then
+ interfaces.showmessage("publications",3)
+ io.savedata(file.addsuffix(jobname,"aux"),format(template,style,database))
+ if trace_bibtex then
+ logs.report("publications","processing bibtex file '%s'",jobname)
+ end
+ os.execute(format("bibtex %s",jobname))
+ -- purge 'm
+ end
+end
+
+function hacks.register(str)
+ if trace_bibtex then
+ logs.report("publications","registering bibtex entry '%s'",str)
+ end
+ registered[#registered+1] = str
+ ordered[str] = #registered
+end
+
+function hacks.reset(m)
+ mode, list, done = m, { }, { }
+end
+
+function hacks.add(str,listindex)
+ if not str or mode == 0 then
+ -- skip
+ elseif mode == 1 then
+ -- all locals but no duplicates
+ local sc = structure.sections.currentid()
+ if done[str] ~= sc then
+ done[str], alldone[str] = sc, true
+ list[#list+1] = { str, listindex }
+ end
+ elseif mode == 2 then
+ -- all locals but no preceding
+ local sc = structure.sections.currentid()
+ if not alldone[str] and done[str] ~= sc then
+ done[str], alldone[str] = sc, true
+ list[#list+1] = { str, listindex }
+ end
+ end
+end
+
+local function compare(a,b)
+ local aa, bb = a[1], b[1]
+ if aa and bb then
+ return ordered[aa] < ordered[bb]
+ else
+ return true
+ end
+end
+
+function hacks.flush(sortvariant)
+ if sortvariant == "" or sortvariant == variables.cite or sortvariant == "default" then
+ -- order is cite order i.e. same as list
+ else
+ sort(list,compare)
+ end
+ for i=1,#list do
+ context.doprocessbibtexentry(list[i][1])
+ end
+end
+
+function hacks.registerplaced(str)
+ used[str] = true
+end
+
+function hacks.doifalreadyplaced(str)
+ commands.testcase(used[str])
+end
+
+-- we ask for :tag but when we can't find it we go back
+-- to look for previous definitions, and when not found again
+-- we look forward
+
+local function compare(a,b)
+ return a[3] < b[3]
+end
+
+function hacks.resolve(prefix,block,reference) -- maybe already feed it split
+ local subset = jobreferences.collected[prefix or ""] or jobreferences.collected[""]
+ if subset then
+ local result, done = { }, { }
+ block = tonumber(block)
+ for rest in gmatch(reference,"([^,%s]+)") do
+ local blk, tag, found = block, nil, nil
+ if block then
+ tag = blk .. ":" .. rest
+ found = subset[tag]
+ if not found then
+ for i=block-1,1,-1 do
+ tag = i .. ":" .. rest
+ found = subset[tag]
+ if found then
+ blk = i
+ break
+ end
+ end
+ end
+ end
+ if not found then
+ blk = "*"
+ tag = blk .. ":" .. rest
+ found = subset[tag]
+ end
+ if found then
+ local current = found.entries and found.entries.text
+ if current and not done[current] then
+ result[#result+1] = { blk, rest, current }
+ done[current] = true
+ end
+ end
+ end
+ -- todo: ranges so the interface will change
+ sort(result,compare)
+ local first, last, firsti, lasti, firstr, lastr
+ local collected = { }
+ for i=1,#result do
+ local r = result[i]
+ local current = r[3]
+ if not first then
+ first, last, firsti, lasti, firstr, lastr = current, current, i, i, r, r
+ elseif current == last + 1 then
+ last, lasti, lastr = current, i, r
+ else
+ if last > first + 1 then
+ collected[#collected+1] = { firstr[1], firstr[2], lastr[1], lastr[2] }
+ else
+ collected[#collected+1] = { firstr[1], firstr[2] }
+ if last > first then
+ collected[#collected+1] = { lastr[1], lastr[2] }
+ end
+ end
+ first, last, firsti, lasti, firstr, lastr = current, current, i, i, r, r
+ end
+ end
+ if first then
+ if last > first + 1 then
+ collected[#collected+1] = { firstr[1], firstr[2], lastr[1], lastr[2] }
+ else
+ collected[#collected+1] = { firstr[1], firstr[2] }
+ if last > first then
+ collected[#collected+1] = { lastr[1], lastr[2] }
+ end
+ end
+ end
+ if #collected > 0 then
+ for i=1,#collected do
+ local c = collected[i]
+ if c[3] then
+ context.dowithbibtexnumrefrange(#collected,i,prefix,c[1],c[2],c[3],c[4])
+ else
+ context.dowithbibtexnumref(#collected,i,prefix,c[1],c[2])
+ end
+ end
+ else
+ context.nobibtexnumref("error 1")
+ end
+ else
+ context.nobibtexnumref("error 2")
+ end
+end
diff --git a/tex/context/base/bibl-tra.mkii b/tex/context/base/bibl-tra.mkii
new file mode 100644
index 000000000..087781db9
--- /dev/null
+++ b/tex/context/base/bibl-tra.mkii
@@ -0,0 +1,1778 @@
+%D \module
+%D [ file=bibl-tra,
+%D version=2009.08.13,
+%D title=\CONTEXT\ Publication Module,
+%D subtitle=Publications,
+%D author=Taco Hoekwater,
+%D date=\currentdate,
+%D copyright=Public Domain]
+%C
+%C Donated to the public domain.
+
+%D This used to be module \type {t-bib} but due to the number of differences
+%D in handling structure between \MKII\ and \MKIV\ we now have \BIBTEX\ support
+%D in the kernel. The only patches concerns some namespace issues. Also,
+%D constants and variables are now predefined. When the \MKIV\ code is well
+%D tested I might backport a couple of adaptions to this \MKII\ variant.
+
+\writestatus{loading}{ConTeXt Bibliography Support / BibTeX}
+
+\definefilesynonym[bib][obsolete]
+
+% here starts t-bib.tex
+
+%D The original was developed independantly by Taco Hoekwater while still working for Kluwer
+%D Academic publishers (it still used the dutch interface then). Development continued after
+%D he left Kluwer, and in Januari 2005, the then already internationalized file was merged
+%D with the core distribution by Hans Hagen. The current version is once again by Taco.
+%D
+%D More documentation and additional resources can be found on the contextgarden:
+%D \hyphenatedurl{http://wiki.contextgarden.net//Bibliography}.
+
+%D \subject{DONE (dd/mm/yyyy)}
+%D
+%D \startitemize
+%D \item add author definition (and associated system variable) (26/05/2005)
+%D \item add finalnamesep support for Oxford comma (17/09/2005)
+%D \item add \type{\insert...} for: doi, eprint, howpublished (19/09/2005)
+%D \item allow a defaulted \type{\setupcite} (19/11/2005)
+%D \item renamed citation type 'number' to 'serial' (19/11/2005)
+%D \item better definition of \type{\inverted...author} (19/11/2005)
+%D \item don't reset [numbercommand] in \type {\setuppublication} by default (20/11/2005)
+%D \item don't disable other \type {\setuppublication} keys if alternative is present (20/11/2005)
+%D \item drop \type{\sanitizeaccents} (20/11/2005)
+%D \item added \type{\nocite} and \type{\cite[none]} (21/11/2005)
+%D \item added headtext for it (23/11/2005)
+%D \item make \type{\cite[url]} and \type{\cite[doi]} interactive (23/11/2005)
+%D \item make right-aligned labels in the list work even when autohang=no
+%D \item use 'et al.' instead of 'et.al.'. Pointed out by Peter M�nster (30/12/2005)
+%D \item added headtext for cz (31/12/2005)
+%D \item Keep whitespace after \type{\cite} with single argument (31/12/2005)
+%D \item Fix broken \type{\cite{}} support (31/12/2005)
+%D \item Use \type{\readfile} inside \type{\usepublications} instead of \type{\readsysfile} (12/01/2006)
+%D \item Use \type{\currentbibyear} and \type{\currentbibauthor} instead of \type{\YR} and \type{\AU} (05/02/2006)
+%D \item Fix compressed version of authoryear style (05/02/2006)
+%D \item Rename the clashing data fields \type{\url} and \type{\type} to \type{\biburl} and \type{\bibtype} (05/02/2006)
+%D \item Added two french bibl files from Renaud Aubin (06/02/2006)
+%D \item Five new bib class and eight extra bib fields, for IEEEtran (07/02/2006)
+%D \item French keyword translation, provided by Renaud (08/02/2006)
+%D \item fix underscores in undefined keys (22/02/2006)
+%D \item Destroy interactivity in labels of the publication list (13/03/2006)
+%D \item fix multi-cite list compression (11/4/2006)
+%D \item fix \type{\getcitedata} (11/4/2006)
+%D \item magic for chapter bibs (18-25/4/2006)
+%D \item language setting (25/4/2006)
+%D \item use \type{\hyphenatedurl} for \type{\inserturl} (25/4/2006)
+%D \item Add \type{\docitation} to \type{\nocite}(26/4/2006)
+%D \item patents can have numbers, added to bst files (26/4/2006)
+%D \item \type{\docitation} needs a \type{\iftrialtypesetting} (27/4/2006)
+%D \item \type{\filllocalpublist}'s loop is bound by definedness, not resolvedness (27/4/2006)
+%D \item \type{\setuppublications[monthconversion=]} added (15/5/2006)
+%D \item use \type{\undefinedreference} instead of bare question marks (15/5/2006)
+%D \item add grouping around \type{\placepublications} commands (16/5/2006)
+%D \item fix a bug in \type{\cite{}} (17/5/2006)
+%D \item support \type{\cite[authornum]} (18/5/2006)
+%D \item make \type{\cite} unexpandable (20/6/2006)
+%D \item allow hyperlinks in author\&year combo's
+%D (cite list compression has to be off) (20/6/2006)
+%D \item fix duplicate labels for per-chapter style (20/6/2006)
+%D \item allow \type{\setupcite[interaction=(start|stop)]}
+%D \item fix the item number in the publication list with 'numbering=yes' (22/6/2006)
+%D \item make the default criterium for \type{\placepublications} be \type{previous} (23/6/2006)
+%D \item fix \type{\normalauthor} and \type{\normalshortauthor} spacing (29/6/2006)
+%D \item do not typeset empty arguments to \type{\typesetapublication} (29/6/2006)
+%D \item add \type{symbol=none} to \type{\setuplist} in unnumbered
+%D mode to prevent typesetting of bare numbers (29/6/2006)
+%D \item remove two incorrect spaces from bibl-num.tex (1/7/2006)
+%D \item reset font styles within \type{\cite}, so that font switches
+%D in \type{left} stay in effect (12/7/2006)
+%D \item guard added against loading bbl files multiple times (13/7/2006)
+%D \item fix \type{\cite[num]} with compression is on. (14/7/2006)
+%D \item test \type{\iflocation} before deciding to use the
+%D interactive version of cite (18/7/2006)
+%D \item support \type{\setupcite[authoretallimit=1]} (18/7/2006)
+%D \item support use of \type{\cite} within titles and captions by
+%D saveguarding the list item extraction and reference placement
+%D code (19/7/2006)
+%D \item support \type{\setuppublicationlist[title=\chapter]} (4/8/2006)
+%D \item use the expansion of \type{\headtext{pubs}} (4/8/2006)
+%D \item hook added for repeated authors in publication list
+%D \type{\setuppublicationlist[artauthorcommand=\mythreeargscommand]}
+%D (4/8/2006)
+%D \item make the bracketed arguments of \type{\artauthor}, \type{\author}
+%D and \type{\editor} (bbl commands) optional (4/8/2006)
+%D \item the constants \type{sorttype}, \type{compress} and
+%D \type{autohang} have moved to the core (8/8/2006)
+%D \item bibtex is now registered as a program to be run by texexec (8/8/2006)
+%D \item fix a bug in \type{\setupcite[authoretallimit=1]} (9/8/2006)
+%D \item fix a bug inside citations that prevented lastpubsep from ever being
+%D used due to a volatile \type{\commalistsize} (25/8/2006).
+%D \item added the possibility of \type{\placepublications[option=continue]}
+%D (6/9/2006)
+%D \item Mojca translated Master's Thesis to Masterarbeit (bibl-apa-de.tex)
+%D (12/9/2006)
+%D \item Added \type{\setuppublicationlist[maybeyear=off]} by request from
+%D Thomas Schmitz (15/9/2006)
+%D \item Removed some spurious spaces pointed out by willi egger (19/9/2006)
+%D \item Add configuration of bibtex executable name (4/11/2006)
+%D \item Fix numbering=short and numbering=bib (spotted by Matthias W�chter) (4/11/2006)
+%D \item third attempt to get a correct release (5/11/2006)
+%D \item fix a few missing dots in bibl-num.tex (7/12/2006)
+%D \item Patch for DOI's by Tobias Burnus (17/4/2007)
+%D \item Patch for \type{\insertbiburl} and \type{\insertdoi} for Tobias Burnus (18/4/2007)
+%D \item Added a missing \type{\relax} in \type{\dospecialbibinsert},
+%D that made the space before the {\it et al.} text disappear. (18/4/2007)
+%D \item Attempt to fix percent signs in bbl files. As a side-effect,
+%D this prohibits comments in \tex{startpublication} blocks! (17/4/2008)
+%D \item Patch from Matthias W\"achter that allows arbitrary .bst
+%D files to be used with \tex{setupbibtex} (25/9/2008)
+%D \item Extended for the new multilingual setups for the Oct 2008 current of ConTeXt (23/10/2008)
+%D \item Multilingual setups needed another fix (27/10/2008)
+%D \item Two fixes for bibl-apa by Michael Green (27/10/2008)
+%D \item Catalan translation of 'References' (10/11/2008)
+%D \item 'chapter' -> 'chapitre' in bibl-apa-fr (27/11/2008)
+%D \item Run bibtex via os.execute in mkiv modee (01/12/2008)
+%D \item Small correction in bibl-apa's placement of volume
+%D information in articles (05/01/2009)
+%D \item Handle multi-author (more than two) cases in \type{\cite}
+%D (02/03/2009)
+%D \item Suppress a syntax error in \type{cont-xp} mode. The output is
+%D probably not right, though (02/03/2009)
+%D \item Added a \tex{loadmarkfile} at the end, and two new files
+%D from Hans. The \type{t-bib.mkiv} is needed to make the module
+%D work with the new structure code (17/04/2009)
+%D \item Added a patch to \type{t-bib.mkiv} from Hans to make the
+%D cross referencing between multiple citations an
+%D bibliographies work (27/04/2009)
+%D \item Remove a superfluous \type{\unprotect} in t-bib.mkiv (11/05/2009).
+%D \item Patch of incollection in bibl-ams.tex from Xan (08/06/2009).
+%D \item Patch of unpublished in bibl-ams.tex from Xan (22/07/2009).
+%D \item Modified \type{\bibdogetupsometextprefix} so it works for undefined
+%D language labels, from Hans (13/08/2009).
+%D \item Removed some \MKIV\ hacks as well as some things that are in the
+%D core like variables, constants and messages (HH:22/08/2009).
+%D \item Added \type{bib} in front of \type {insert} macros and initialize
+%D then later on (HH:22/08/2009).
+%D \item Removed test for type {\currentlocationreference} plus associated
+%D code (HH:22/08/2009).
+%D \stopitemize
+%D
+%D \subject{WISHLIST}
+%D
+%D \startitemize
+%D \item link back from publication list to citation
+%D \item export \type {\citation{}}
+%D \item support mlbibtex
+%D \item don't load the whole lot, but filter entries instead
+%D \stopitemize
+
+\unprotect
+
+%D Variables, constants and messages are removed as they are now in the
+%D multilingual interface modules.
+
+\def\biblistname{pubs} % for compatibility
+
+%D how to load the references. There is some new stuff here
+%D to support Idris' (incorrect :-)) use of projects
+
+% \let\preloadbiblist\relax
+%
+% \ifx\currentcomponent\v!text
+% % single file
+% \edef\temp{\the\everystarttext}%
+% \ifx\temp\empty
+% % post-starttext
+% \def\preloadbiblist{\dousepublications\jobname }%
+% \else
+% % pre-starttext
+% \appendtoks \dousepublications\jobname \to \everystarttext
+% \fi
+% %
+% \else \ifx\currentcomponent\v!project
+% % a project file, have to set up the partial products!
+% \def\startproduct #1 %
+% {\doateverystarttext
+% \dousepublications{#1}%
+% \donextlevel\v!product\currentproduct
+% \doexecutefileonce\doexecutefileonce
+% \donotexecutefile\doexecutefile#1\\}%
+% %
+% \else \ifx\currentcomponent\v!product
+% % a product file
+% \def\preloadbiblist{\dousepublications\jobname }%
+% %
+% \else
+% % a component? not sure what to do
+% \def\preloadbiblist{\dousepublications\jobname }%
+% %
+% \fi \fi \fi
+
+\def\preloadbiblist
+ {\globallet\preloadbiblist\relax
+ \dousepublications\jobname}
+
+\definelist[pubs]
+\setuplist[pubs][\c!width=]
+
+%D \macros{bibdoif,bibdoifnot,bibdoifelse}
+%D
+%D Here are a few small helpers that are used a lot
+%D in all the typesetting commands
+%D (\type{\insert...}) we will encounter later.
+
+\long\def\bibdoifelse#1%
+ {\@EA\def\@EA\!!stringa\@EA{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\long\def\bibdoifnot#1%
+ {\@EA\def\@EA\!!stringa\@EA{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\long\def\bibdoif#1%
+ {\@EA\def\@EA\!!stringa\@EA{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+%D Bibtex settings separated out
+
+%D No point in writing the aux file if there is no database...
+
+\def\setupbibtex{\dosingleempty\dosetupbibtex}
+
+\def\dosetupbibtex[#1]%
+ {\let\@@pbdatabase\empty
+ \getparameters[\??pb][\c!sort=\s!default,#1]%
+ \expanded{\processaction[\@@pbsort]}
+ [ \v!no=>\def\bibstyle{cont-no},
+ \v!author=>\def\bibstyle{cont-au},
+ \v!title=>\def\bibstyle{cont-ti},
+ \v!short=>\def\bibstyle{cont-ab},
+ \s!default=>\def\bibstyle{cont-no},
+ \s!unknown=>\def\bibstyle{\@@pbsort}]%
+ \ifx\@@pbdatabase\empty\else \writeauxfile \fi}
+
+\dosetupbibtex[bibtex=bibtex]
+
+%D \macros{writeauxfile}
+%D
+%D Unfortunately, \BIBTEX\ is not the best configurable program
+%D around. The names of the commands it parses as well as the \type{.aux}
+%D extension to the file name are both hardwired.
+%D
+%D This means \CONTEXT\ has to write a \LATEX-style auxiliary file, yuk!
+%D The good news is that it can be rather short. We'll just ask
+%D \BIBTEX\ to output the entire database(s) into the \type{bbl} file.
+%D
+%D The \type{\bibstyle} command controls how the \type{bbl} file will
+%D be sorted. The possibilities are:
+%D
+%D \startitemize[packed]
+%D \item by author (+year, title): cont-au.bst
+%D \item by title (+author, year): cont-ti.bst
+%D \item by short key as in abbrev.bst: cont-ab.bst
+%D \item not sorted at all: cont-no.bst
+%D \stopitemize
+
+\def\writeauxfile
+ {\doifmode{*\v!first}
+ {\openout \scratchwrite \jobname.aux
+ \write \scratchwrite {\string\citation{*}}%
+ \write \scratchwrite {\string\bibstyle{\bibstyle}}%
+ \write \scratchwrite {\string\bibdata{\@@pbdatabase}}%
+ \closeout\scratchwrite
+ \showmessage\m!publications{3}{}%
+ \expanded{\installprogram{\@@pbbibtex\space\jobname}}}}
+
+%D \macros{ifsortbycite,iftypesetall,ifautohang,ifbibcitecompress}
+%D
+%D The module needs some new \type{\if} statements.
+
+%D Default sort order of the reference list is by citation.
+
+\newif\ifsortbycite \sortbycitetrue
+
+%D By default, only referenced publications are typeset
+
+\newif\iftypesetall \typesetallfalse
+
+%D Hanging indentation of the publication list
+%D will not adjust itself according to the width of the label.
+
+\newif\ifautohang \autohangfalse
+
+%D Cite lists are compressed, if possible.
+
+\newif\ifbibcitecompress \bibcitecompresstrue
+
+\def\setuppublications
+ {\dosingleargument\dosetuppublications}
+
+\def\bibleftnumber#1%
+ {#1\hfill~}
+
+\def\dosetuppublications[#1]%
+ {\getparameters
+ [\??pb]
+ [\c!alternative=,#1]%
+ \doifsomething\@@pbalternative
+ {\readsysfile
+ {bibl-\@@pbalternative.tex}
+ {\showmessage\m!publications{6}{bibl-\@@pbalternative}\let\@@pbalternative\empty}
+ {\showmessage\m!publications{1}{bibl-\@@pbalternative}\let\@@pbalternative\empty}}%
+ \getparameters
+ [\??pb]
+ [#1]%
+ \processaction
+ [\@@pbcriterium]
+ [ \v!all=>\typesetalltrue,
+ \s!unknown=>\typesetallfalse]%
+ \processaction
+ [\@@pbautohang]
+ [ \v!yes=>\autohangtrue,
+ \s!unknown=>\autohangfalse]%
+ \processaction
+ [\@@pbsorttype]
+ [ \v!cite=>\sortbycitetrue,
+ \v!bbl=>\sortbycitefalse,
+ \s!default=>\sortbycitetrue,
+ \s!unknown=>\sortbycitefalse]%
+ \processaction
+ [\@@pbnumbering]
+ [ \v!yes=>\let\@@pbinumbercommand\firstofoneargument,
+ \v!no=>\let\@@pbinumbercommand\gobbleoneargument,
+ \v!short=>\def\@@pbinumbercommand##1{\getvalue{pbds-\@@pbk}},
+ \v!bib=>\def\@@pbinumbercommand##1{\getvalue{pbdn-\@@pbk}},
+ \s!unknown=>\let\@@pbinumbercommand\firstofoneargument]%
+ \processaction
+ [\@@pbrefcommand]
+ [\s!default=>\edef\@@citedefault{\@@pbrefcommand},
+ \s!unknown=>\edef\@@citedefault{\@@pbrefcommand}]}
+
+% initialize
+
+\def\@@pbrefcommand{num}
+\def\@@pbnumbercommand{\bibleftnumber}
+
+%D \macros{usepublications}
+%D
+%D We need \type{\usereferences} so that it is possible to
+%D refer to page and/or appearance number for publications
+%D in the other document.
+
+\def\usepublications[#1]%
+ {\usereferences[#1]\processcommalist[#1]\dousepublications}
+
+\def\dousepublications#1%
+ {\doonlyonce
+ {#1.\f!bibextension}
+ {\readfile{#1.\f!bibextension}
+ {\showmessage\m!publications{4}{#1.\f!bibextension}}
+ {\showmessage\m!publications{2}{#1.\f!bibextension}}}}
+
+%D \macros{setuppublicationlist}
+%D
+%D This will be the first command in (\BIBTEX-generated) \type{bbl}
+%D files. `samplesize' is a sample value (in case of \BIBTEX-generated
+%D files, this will be the longest `short' key). `totalnumber'
+%D is the total number of entries that will follow in this
+%D file.
+
+%D Both values are only needed for the label calculation
+%D if `autohang' is `true', so by default the command is
+%D not even needed, and therefore I saw no need to give
+%D it it's own system variable and it just re-uses \type{pb}.
+
+\def\setuppublicationlist
+ {\dosingleempty\dosetuppublicationlist}
+
+\def\dosetuppublicationlist[#1]%
+ {\getparameters[\??pv data][#1]%
+ \setuplist
+ [pubs]
+ [\c!samplesize={AA99},\c!totalnumber={99},
+ \c!alternative=a,\c!interaction=,\c!pagenumber=\v!no,#1]}
+
+\def\setuppublicationlayout[#1]#2%
+ {\setvalue{\??pv data#1}{#2\unskip}}
+
+%D \macros{bibalternative}
+%D
+%D A nice little shorthand that will be used so we don't have to
+%D key in the weird \type{\@@pv} parameter names all the time.
+
+\def\bibalternative#1%
+ {\getvalue{\??pv\@@currentalternative#1}}
+
+%D \macros{simplebibdef,bibcommandlist}
+%D
+%D \type{\simplebibdef} defines \type{bib@#1}, which in turn will
+%D use one argument that is stored in \type{@@pb@#1}.
+%D
+%D \type{\simplebibdef} also defines \type{insert#1}, which can be
+%D used in the argument of \type{\setuppublicationlayout} to fetch
+%D one of the \type{@@pb@} data entries. \type{insert#1} then has
+%D three arguments: \type{#1} are commands to be executed before the
+%D data, \type{#2} are commands to be executed after the data, and
+%D \type{#3} are commands to be executed if the data is not found.
+
+%D \type{\bibcommandlist} is the list of commands that is affected
+%D by this approach. Later on, it will be used to do a series
+%D of assignments from \type{#1} to \type{bib@#1}: e.g
+%D \type{\title} becomes \type{\bib@title} when used within
+%D a publication.
+
+\newtoks\initializebibdefinitions % we need to prevent clashes (HH)
+
+% \def\simplebibdef#1% hh: funny expansion ?
+% {\@EA\long\@EA\def\csname bib@#1\endcsname##1%
+% {\setvalue{\??pb @#1}{##1}%
+% \ignorespaces}%
+% \@EA\def\csname insert#1\endcsname##1##2##3%
+% {\@EA\bibdoifelse
+% \@EA{\csname @@pb@#1\endcsname}%
+% {##1\csname @@pb@#1\endcsname##2}%
+% {##3}%
+% }}
+
+\def\simplebibdef#1% hh: funny expansion ?
+ {\@EA\long\@EA\def\csname bib@#1\endcsname##1%
+ {\setvalue{\??pb @#1}{##1}\ignorespaces}%
+ \expandafter \appendtoks
+ \expandafter\let\csname insert#1\expandafter\endcsname\csname bibinsert#1\endcsname
+ \to \initializebibdefinitions
+ \@EA\unexpanded\@EA\def\csname bibinsert#1\endcsname##1##2##3%
+ {\@EA\bibdoifelse\@EA{\csname\??pb @#1\endcsname}{##1\csname\??pb @#1\endcsname##2}{##3}}}
+
+\def\bibcommandlist
+ {abstract, annotate, arttitle, assignee, bibnumber, bibtype, biburl, chapter, city,
+ comment, country, day, dayfiled, doi, edition, eprint, howpublished, isbn, issn,
+ issue, journal, keyword, keywords, lastchecked, month, monthfiled, names, nationality,
+ note, notes, organization, pages, pubname, pubyear, revision, series, size, thekey,
+ title, volume, yearfiled}
+
+\processcommacommand[\bibcommandlist]\simplebibdef
+
+\def\bibinsertdoi#1#2#3%
+ {{\bibdoifelse{\@@pb@doi}%
+ {\edef\ascii{\@EA\detokenize\@EA{\@@pb@doi}}%
+ #1\expanded{\gotoDOI{\@@pb@thekey}{\ascii}}#2}{#3}}}
+
+\def\bibinsertbiburl#1#2#3%
+ {{\bibdoifelse{\@@pb@biburl}%
+ {\edef\ascii{\@EA\detokenize\@EA{\@@pb@biburl}}%
+ #1\expanded{\gotoURL{\@@pb@thekey}{\ascii}}#2}{#3}}}
+
+\def\bibinsertmonth#1#2#3%
+ {\bibdoifelse{\@@pb@month}%
+ {#1\doifnumberelse{\@@pb@month}%
+ {\doifconversiondefinedelse\@@pbmonthconversion
+ {\convertnumber\@@pbmonthconversion{\@@pb@month}}{\@@pb@month}}%
+ {\@@pb@month}#2}{#3}}
+
+\appendtoks
+ \let\inserturl \bibinsertbiburl % for backward compat.
+ \let\inserttype\bibinsertbibtype % for backward compat.
+\to\initializebibdefinitions
+
+\def\newbibfield[#1]%
+ {\simplebibdef{#1}%
+ \edef\bibcommandlist{\bibcommandlist,#1}}
+
+%D \macros{bib@crossref}
+%D
+%D \type{\crossref} is used in database files to point to another
+%D entry. Because of this special situation, it has to be defined
+%D separately. Since this command will not be seen until at
+%D \type{\placepublications}, it may force extra runs. The same is
+%D true for \type{\cite} commands inside of publications.
+
+\def\bib@crossref#1%
+ {\setvalue{\??pb @crossref}{#1}\ignorespaces}
+
+\def\bibinsertcrossref#1#2#3%
+ {\bibdoifelse{\@@pb@crossref}
+ {#1\@EA\cite\@EA[\@@pb@crossref]#2}
+ {#3}}
+
+\appendtoks\let\insertcrossref\bibinsertcrossref\to\initializebibdefinitions
+
+%D \macros{complexbibdef,specialbibinsert}
+%D
+%D The commands \type{\artauthor}, \type{\author} and
+%D \type{\editor} are more complex than the other commands.
+%D Their argument lists have this form:
+%D
+%D \type{\author[junior]{firstnames}[inits]{von}{surname}}
+%D
+%D (bracketed stuff is optional)
+%D
+%D And not only that, but there also might be more than one of each of
+%D these commands. This is why a special command is needed to insert
+%D them, as well as one extra counter for each command.
+
+%D All of these \type{\@EA}'s and \type{\csnames} make this code
+%D look far more complex than it really is. For example, the argument
+%D \type{author} defines the macro \type{\bib@author} to do two
+%D things: increment the counter \type{\author@num} (let's say to 2)
+%D and next store it's arguments in the macro \type{\@@pb@author2}.
+%D And it defines \type{\insertauthors} to expand into
+%D \starttyping
+%D \specialbibinsert{author}{\author@num}{}{}{}
+%D \stoptyping
+
+\def\docomplexbibdef#1%
+ {\def\currentype{#1}%
+ \dosingleempty\dodocomplexbibdef}
+
+\def\dodocomplexbibdef[#1]#2%
+ {\def\firstarg{#1}\def\secondarg{#2}%
+ \dosingleempty\dododocomplexbibdef}
+
+\def\dododocomplexbibdef[#1]#2#3%
+ {\@EA\increment\csname \currentype @num\endcsname
+ \setevalue{\??pb @\currentype\csname \currentype @num\endcsname}%
+ {{\secondarg}{#2}{#3}{#1}{\firstarg}}\ignorespaces}%
+
+% \def\complexbibdef#1%
+% {\@EA\newcounter\csname #1@num\endcsname
+% \@EA\def\csname bib@#1\endcsname{\docomplexbibdef{#1}}%
+% \@EA\def\csname insert#1s\endcsname##1##2##3%
+% {\specialbibinsert{#1}{\csname #1@num\endcsname}{##1}{\unskip ##2}{##3}}}
+
+\def\complexbibdef#1%
+ {\@EA\newcounter\csname #1@num\endcsname
+ \@EA\def\csname bib@#1\endcsname{\docomplexbibdef{#1}}%
+ \expandafter \appendtoks
+ \expandafter\let\csname insert#1s\expandafter\endcsname\csname bibinsert#1s\endcsname
+ \to \initializebibdefinitions
+ \@EA\def\csname bibinsert#1s\endcsname##1##2##3{\specialbibinsert{#1}{\csname #1@num\endcsname}{##1}{\unskip ##2}{##3}}}
+
+\processcommalist[author,artauthor,editor]\complexbibdef
+
+%D Another level of indirection is needed to control the
+%D typesetting of all of these arguments.
+
+%D Btw, there is a conflict between `author' and the predefined interface
+%D variable `auteur'. The old version is overruled `auteur' is
+%D overruled by the systemconstant definition at the top of this file!
+
+\newcount\etallimitcounter
+\newcount\etaldisplaycounter
+\newcount\todocounter
+
+\def\specialbibinsert#1#2#3#4#5%
+ {\bgroup
+ \ifnum#2>\zerocount
+ \etallimitcounter =0\bibalternative{#1etallimit}\relax
+ \etaldisplaycounter=0\bibalternative{#1etaldisplay}\relax
+ \ifnum #2>\etallimitcounter
+ \todocounter\etaldisplaycounter
+ % just in case ...
+ \ifnum\todocounter>\etallimitcounter
+ \todocounter\etallimitcounter
+ \fi
+ \else
+ \todocounter#2\relax
+ \fi
+ \ifnum\todocounter>\zerocount
+ % find the current author list
+ \let\templist\empty
+ \dorecurse{#2}
+ {\toks0=\@EA\@EA\@EA{\csname @@pb@#1\recurselevel\endcsname}%
+ \ifx\templist\empty \edef\templist{\the\toks0}%
+ \else \edef\templist{\templist,\the\toks0}\fi }%
+ \doifdefinedelse
+ {\??pv data#1\c!command}
+ {\doifemptyelsevalue
+ {\??pv data#1\c!command}
+ {#3\dospecialbibinsert{#1}{\todocounter}{\templist}#4}%
+ {#3\getvalue{\??pv data#1\c!command}{#1}{\todocounter}{\templist}#4}}%
+ {#3\dospecialbibinsert{#1}{\todocounter}{\templist}#4}%
+ \else
+ #5%
+ \fi
+ \else
+ #5%
+ \fi
+ \egroup}
+
+%D This macro does the hard work of inserting a list of people in the
+%D output, with proper regard of all the inbetween strings that can
+%D arise depending on length of the list of people.
+
+%D \#1 = type
+%D \#2 = number of items to be typeset
+%D \#3 = commacommand containing authors
+
+\def\dospecialbibinsert#1#2#3%
+ {\getcommacommandsize[#3]%
+ \scratchcounter 0
+ \def\processauthoritem##1%
+ {\advance\scratchcounter1
+ \ifnum \numexpr\scratchcounter-1\relax<#2\relax
+ \getvalue{\??pv data#1}##1%
+ \ifnum \scratchcounter=#2\relax
+ \ifnum\etallimitcounter<\commalistsize\relax \bibalternative{#1etaltext}\fi
+ \else \ifnum\numexpr\scratchcounter+1 = #2\relax
+ \ifnum \commalistsize > \plustwo \bibalternative\c!finalnamesep
+ \else \bibalternative\c!lastnamesep \fi
+ \else
+ \bibalternative\c!namesep
+ \fi \fi
+ \fi}%
+ \processcommacommand[#3]\processauthoritem }
+
+%D \macros{invertedauthor,normalauthor,invertedshortauthor,normalshortauthor}
+%D
+%D Just some commands that can be used in \type{\setuppublicationparameters}
+%D If you want to write an extension to the styles, you might
+%D as well define some of these commands yourself.
+%D
+%D The argument liust has been reordered here, and the meanings
+%D are:
+%D
+%D {\obeylines\parskip0pt
+%D \type{#1} firstnames
+%D \type{#2} von
+%D \type{#3} surname
+%D \type{#4} inits
+%D \type{#5} junior
+%D }
+%D
+
+\def\normalauthor#1#2#3#4#5%
+ {\bibdoif{#1}{#1\bibalternative\c!firstnamesep}%
+ \bibdoif{#2}{#2\bibalternative\c!vonsep}%
+ #3%
+ \bibdoif{#5}{\bibalternative\c!surnamesep#5\unskip}}
+
+\def\normalshortauthor#1#2#3#4#5%
+ {\bibdoif{#4}{#4\bibalternative\c!firstnamesep}%
+ \bibdoif{#2}{#2\bibalternative\c!vonsep}%
+ #3%
+ \bibdoif{#5}{\bibalternative\c!surnamesep#5\unskip}}
+
+\def\invertedauthor#1#2#3#4#5%
+ {\bibdoif{#2}{#2\bibalternative\c!vonsep}%
+ #3%
+ \bibdoif{#5}{\bibalternative\c!juniorsep #5}%
+ \bibdoif{#1}{\bibalternative\c!surnamesep #1\unskip}}
+
+\def\invertedshortauthor#1#2#3#4#5%
+ {\bibdoif{#2}{#2\bibalternative\c!vonsep}%
+ #3%
+ \bibdoif{#5}{\bibalternative\c!juniorsep #5}%
+ \bibdoif{#4}{\bibalternative\c!surnamesep #4\unskip}}
+
+%D \macros{clearbibitem,clearbibitemtwo,bibitemdefs}
+%D
+%D These are used in \type{\typesetapublication} to do
+%D initializations and cleanups.
+
+\def\clearbibitem#1{\setvalue{\??pb @#1}{}}%
+
+\def\clearbibitemtwo#1%
+ {\letvalue{#1@num}\!!zerocount
+ \scratchcounter\plusone
+ \doloop
+ {\doifdefinedelse{\??pb @#1\the\scratchcounter}
+ {\letvalue{\??pb @#1\the\scratchcounter}\empty
+ \advance\scratchcounter\plusone}%
+ {\exitloop}}}
+
+\def\bibitemdefs#1%
+ {\@EA\let\@EA\tempa \csname bib@#1\endcsname
+ \@EA\let\csname #1\endcsname \tempa }
+
+%D \macros{startpublication}
+%D
+%D We are coming to the end of this module, to the macros that
+%D do typesetting and read the \type{bbl} file.
+
+\newcounter\bibcounter
+
+%D Just a \type{\dosingleempty} is the most friendly
+%D of doing this: there need not even be an argument
+%D to \type{\startpublication}. Of course, then there
+%D is no key either, and it had better be an
+%D article (otherwise the layout will be all screwed up).
+%D
+%D Now prohibits comments, so % can be used for urls
+
+\def\startpublication
+ {\edef\bibmodsavedpercent{\the\catcode`\%}%
+ \catcode`\%=12
+ \dosingleempty\dostartpublication}
+
+\def\stoppublication
+ {} % the \catcode of % is reset below
+
+%D Only specifying the key in the argument is also
+%D legal. In storing this stuff into macros, some trickery with
+%D token registers is needed to fix the expansion problems. Even so,
+%D this appears to not always be 100\% safe, so people are
+%D urgently advised to use \ETEX\ instead of traditional \TEX.
+%D
+%D In \ETEX, all expansion problems are conviniently solved by
+%D the primitive \type{\protected}. To put that another way:
+%D
+%D It's not a bug in this module if it does not appear in \ETEX!
+
+\long\def\dostartpublication[#1]#2\stoppublication%
+ {\increment\bibcounter
+ \bgroup
+ \doifassignmentelse{#1}%
+ {\getparameters[\??pb][k=,t=article,n=,s=,a=,y=,o=,u=,#1]}%
+ {\getparameters[\??pb][k=#1,t=article,n=,s=,a=,y=,o=,u=]}%
+ \@EA\toks\@EA2\@EA{\@@pba}%
+ \@EA\toks\@EA4\@EA{\@@pbs}%
+ \toks0={\ignorespaces #2}%
+ \setxvalue{pbdk-\@@pbk}{\@@pbk}
+ \setxvalue{pbda-\@@pbk}{\the\toks2}
+ \setxvalue{pbdy-\@@pbk}{\@@pby}
+ \setxvalue{pbds-\@@pbk}{\the\toks4}
+ \setxvalue{pbdn-\@@pbk}{\@@pbn}
+ \setxvalue{pbdt-\@@pbk}{\@@pbt}
+ \setxvalue{pbdo-\@@pbk}{\@@pbo}
+ \setxvalue{pbdu-\@@pbk}{\@@pbu}
+ \setxvalue{pbdd-\@@pbk}{\the\toks0}
+ \xdef\allrefs{\allrefs,\@@pbk}%
+ \egroup
+ \catcode`\%=\bibmodsavedpercent\relax }
+
+% intialization of the order-list:
+
+\let\allrefs\empty
+
+%D The next macro is needed because the number command of the
+%D publist sometimes needs to fetch something from the current
+%D item (like the 'short' key). For this, the ID of the current
+%D item is passed in the implict parameter \type{\@@pbk}
+
+\def\makepbkvalue#1{\def\@@pbk{#1}}
+
+\newif\ifinpublist
+
+% from Hans
+
+\def\ignoresectionconversion
+ {\let\@@sectionconversion\secondoftwoarguments}
+
+\let\normaldosetfilterlevel\dosetfilterlevel
+
+\def\patcheddosetfilterlevel#1#2% beware: this one is \let
+ {\bgroup
+ \ignoresectionconversion
+ \edef\askedlevel{#1}%
+ \edef\askedfilter{#2}%
+% \message{ASKD: \meaning\askedlevel}%
+% \message{PREV: \meaning\v!previous}%
+ \ifx\askedlevel\v!current
+ \dosetcurrentlevel\askedlevel
+ \else\ifx\askedlevel\v!previous
+ \dosetpreviouslevel\askedlevel
+ \else\ifx\askedlevel\v!all
+ \global\chardef\alltoclevels\plusone
+ \else\ifx\askedlevel\v!text
+ \global\chardef\alltoclevels\plusone
+ \else
+ \edef\byaskedlevel{\csname\??by\askedlevel\endcsname}%
+ \ifx\byaskedlevel\v!text
+ \dosettextlevel\askedlevel
+ \else
+ \dosetotherlevel\askedlevel
+ \fi
+ \fi\fi\fi\fi
+ % experiment
+ \ifx\askedfilter\empty \else
+ \xdef\currentlevel{\currentlevel\sectionseparator\askedfilter}%
+ \fi
+ \egroup}
+
+\def\filllocalpublist%
+ {\doifdefinedelse{\alltoclevels}
+ {\let\dosetfilterlevel\patcheddosetfilterlevel
+ \dosettoclevel\??li{pubs}%
+ \let\dosetfilterlevel\normaldosetfilterlevel }%
+ {\dosettoclevel\??li{pubs}}%
+ \global\let\glocalpublist\empty
+ \doloop
+ {\doifdefinedelse
+ {\r!cross cite-\jobname-\recurselevel}
+ {\doifreferencefoundelse
+ {cite-\jobname-\recurselevel}
+ {\@EA\doifreglevelelse\@EA[\currentlocationreference]
+ {\@EA\doglobal\@EA\addtocommalist\@EA
+ {\currenttextreference}\glocalpublist}{}}
+ {}}%
+ {\exitloop}}%
+ \let\localpublist\glocalpublist}
+
+\def\typesetpubslist
+ {\dobeginoflist
+% \the\initializebibdefinitions
+ \edef\askedlevel{\csname \??li pubs\c!criterium\endcsname}%
+ \ifx\askedlevel\v!all
+ \def\bibrefprefix{}%
+ \else %
+ \preparebibrefprefix
+ \fi
+ \ifsortbycite
+ \filllocalpublist
+ \iftypesetall
+ \let\localallrefs\allrefs
+ \processcommacommand[\localpublist]\typesetapublication
+ \def\removefromallrefs##1%
+ {\removefromcommalist{##1}\localallrefs }%
+ \processcommacommand[\localpublist]\removefromallrefs
+ \processcommacommand[\localallrefs]\typesetapublication
+ \else
+ \processcommacommand[\localpublist]\typesetapublication
+ \fi
+ \else
+ \iftypesetall
+ \processcommacommand[\allrefs]\typesetapublication
+ \else
+ %
+ \filllocalpublist
+ \processcommacommand[\allrefs]\maybetypesetapublication
+ \fi
+ \fi
+ \doendoflist}
+
+\newif\ifinpublist
+
+\def\maybetypesetapublication#1%
+ {\global\inpublistfalse
+ \def\test{#1}%
+ \def\runtest##1%
+ {\def\tempa{##1}\ifx \test\tempa \global\inpublisttrue \fi}%
+ \processcommacommand[\localpublist]\runtest
+ \ifinpublist \typesetapublication{#1}\fi}
+
+\def\initializepubslist
+ {\edef\@@pbnumbering{\@@pbnumbering}%
+ \ifautohang
+ \ifx\@@pbnumbering\v!short
+ \setbox\scratchbox\hbox{\@@pbnumbercommand{\getvalue{\??li pubs\c!samplesize}}}%
+ \else\iftypesetall
+ \setbox\scratchbox\hbox{\@@pbnumbercommand{\getvalue{\??li pubs\c!totalnumber}}}%
+ \else
+ \setbox\scratchbox\hbox{\@@pbnumbercommand{\numreferred}}%
+ \fi\fi
+ \edef\samplewidth{\the\wd\scratchbox}%
+ \setuplist[pubs][\c!width=\samplewidth,\c!distance=0pt]%
+ \ifx\@@pbnumbering\v!short
+ \def\@@pblimitednumber##1{\hbox to \samplewidth
+ {\@@pbnumbercommand{\getvalue{pbds-\@@pbk}}}}%
+ \else \ifx \@@pbnumbering\v!bib
+ \def\@@pblimitednumber##1{\hbox to \samplewidth
+ {\@@pbnumbercommand{\getvalue{pbdn-\@@pbk}}}}%
+ \else
+ \def\@@pblimitednumber##1{\hbox to \samplewidth{\@@pbnumbercommand{##1}}}%
+ \fi \fi
+ \else
+ \ifx\@@pbnumbering\v!short
+ \doifemptyelse
+ {\getvalue{\??li pubs\c!width}}
+ {\def\@@pblimitednumber##1{\hbox
+ {\@@pbnumbercommand{\getvalue{pbds-\@@pbk}}}}}%
+ {\def\@@pblimitednumber##1{\hbox to \getvalue{\??li pubs\c!width}%
+ {\@@pbnumbercommand{\getvalue{pbds-\@@pbk}}}}}%
+ \else \ifx \@@pbnumbering\v!bib
+ \doifemptyelse
+ {\getvalue{\??li pubs\c!width}}
+ {\def\@@pblimitednumber##1{\hbox
+ {\@@pbnumbercommand{\getvalue{pbdn-\@@pbk}}}}}%
+ {\def\@@pblimitednumber##1{\hbox to \getvalue{\??li pubs\c!width}%
+ {\@@pbnumbercommand{\getvalue{pbdn-\@@pbk}}}}}%
+ \else
+ \doifemptyelse
+ {\getvalue{\??li pubs\c!width}}
+ {\def\@@pblimitednumber##1{\hbox{\@@pbnumbercommand{##1}}}}%
+ {\def\@@pblimitednumber##1{\hbox to \getvalue{\??li pubs\c!width}{\@@pbnumbercommand{##1}}}}%
+ \fi
+ \fi
+ \fi
+ \ifx\@@pbnumbering\v!no
+ \setuplist[pubs][\c!numbercommand=,\c!symbol=\v!none,\c!textcommand=\outdented]%
+ \else
+ \setuplist[pubs][\c!numbercommand=\@@pblimitednumber]%
+ \fi
+ \doifelsevalue
+ {\??pv data\c!maybeyear}{\v!off}{\def\maybeyear##1{}}{\def\maybeyear##1{##1}}%
+ \forgetall} % bugfix 2005/03/18
+
+\def\outdented#1% move to supp-box ?
+ {\hskip -\hangindent #1}
+
+%D The full list of publications
+
+\def\completepublications
+ {\dosingleempty\docompletepublications}
+
+\def\bibdogetupsometextprefix#1#2#3%
+ {\ifcsname#2#1#3\endcsname
+ \csname#2#1#3\endcsname
+ \else\ifcsname\??la#1\c!default\endcsname
+ \@EA\ifx\csname\??la#1\c!default\endcsname\empty
+ \ifcsname#2#3\endcsname
+ \csname#2#3\endcsname
+ \else\ifcsname#2\s!en#3\endcsname
+ \csname#2\s!en#3\endcsname
+ \fi\fi
+ \else
+ \expandafter\bibdogetupsometextprefix
+ \csname\??la#1\c!default\endcsname{#2}{#3}%
+ \fi
+ \else
+ \ifcsname#2#3\endcsname
+ \csname#2#3\endcsname
+ \else\ifcsname#2\s!en#3\endcsname
+ \csname#2\s!en#3\endcsname
+ \fi\fi
+ \fi\fi}
+
+\def\docompletepublications[#1]%
+ {\begingroup
+ \setuplist[pubs][\c!criterium=\v!previous,#1]
+ \begingroup
+ \let\handletextprefix\firstoftwoarguments
+ \edef\headtextpubs{\bibdogetupsometextprefix\headlanguage\c!title{pubs}}%
+ \doifdefinedelse
+ {\??pv data\v!title}
+ {\doifemptyelsevalue
+ {\??pv data\v!title}
+ {\expanded{\systemsuppliedtitle[pubs]{\headtextpubs}}}%
+ {\expanded{\getvalue{\??pv data\v!title}{\headtextpubs}}}%
+ }%
+ {\expanded{\systemsuppliedtitle[pubs]{\headtextpubs}}}%
+ \endgroup
+ \dodoplacepublications }
+
+%D And the portion with the entries only.
+
+\def\placepublications
+ {\dosingleempty\doplacepublications}
+
+\def\doplacepublications[#1]%
+ {%\getparameters[\??pv data][#1]
+ \begingroup
+ \setuplist[pubs][\c!criterium=\v!previous,#1]%
+ \dodoplacepublications }%
+
+\def\dodoplacepublications%
+ {\initializepubslist
+ \doifelsevalue
+ {\??li pubs\c!option}{\v!continue}%
+ {}%
+ {\global\let\bibcounter\!!zerocount }%
+ \inpublisttrue
+ \typesetpubslist
+ \inpublistfalse
+ \endgroup}
+
+%D \subsubject{What's in a publication}
+
+\unexpanded\def\typesetapublication#1%
+ {\doifsomething{#1}
+ {\doglobal\increment\bibcounter
+ \bgroup
+ \the\initializebibdefinitions
+ \makepbkvalue{#1}%
+ \ifgridsnapping
+ \snaptogrid\vbox{\dodolistelement{pubs}{}{\bibcounter}%
+ {\expanded{\reference[\bibrefprefix#1]{\bibcounter}}%
+ \strut \dotypesetapublication{#1}\strut }{}{}}%
+ \else
+ \dodolistelement{pubs}{}{\bibcounter}%
+ {\expanded{\reference[\bibrefprefix#1]{\bibcounter}}%
+ \strut \dotypesetapublication{#1}\strut }{}{}%
+ \fi
+ \egroup}}
+
+\def\dotypesetapublication#1%
+ {\bgroup
+ \def\@@currentalternative{data}%
+ \processcommacommand[\bibcommandlist,crossref]\clearbibitem
+ \processcommalist [artauthor,author,editor]\clearbibitemtwo
+ \processcommacommand[\bibcommandlist]\bibitemdefs
+ \processcommalist [artauthor,author,editor,crossref]\bibitemdefs
+ \let\biblanguage\empty
+ \getvalue{pbdd-#1}%
+ \ifcsname pbdt-#1\endcsname \bibalternative{\getvalue{pbdt-#1}}\fi
+ \egroup }
+
+%D An afterthought:
+
+\def\maybeyear#1{}
+
+%D An another:
+
+\def\noopsort#1{}
+
+%D This is the result of bibtex's `language' field.
+
+\def\setbiblanguage#1#2{\setvalue{\??pb @lang@#1}{#2}}
+
+\def\lang#1%
+ {\def\biblanguage{#1}%
+ \ifcsname \??pb @lang@#1\endcsname
+ \expanded{\language[\getvalue{\??pb @lang@#1}]}%
+ \fi \ignorespaces}
+
+%D \subject{Citations}
+%D
+%D \macros{cite,bibref}
+%D
+%D The indirection with \type{\dobibref} allows \LATEX\ style
+%D \type{\cite} commands with a braced argument (these might appear
+%D in included data from the \type{.bib} file).
+
+% \unexpanded\def\cite
+% {\doifnextcharelse{[}
+% {\dodocite}
+% {\dobibref}}
+% \def\dobibref#1%
+% {\docite[#1][]}
+% \def\dodocite[#1]%
+% {\startstrictinspectnextcharacter
+% \dodoubleempty\dododocite[#1]}
+% \def\dododocite[#1][#2]{%
+% \stopstrictinspectnextcharacter
+% \docite[#1][#2]}
+
+\unexpanded\def\cite
+ {\strictdoifnextoptionalelse\dodocite\dobibref}
+
+\def\dobibref#1%
+ {\docite[#1][]}
+
+\def\dodocite[#1]%
+ {\strictdoifnextoptionalelse{\docite[#1]}{\docite[#1][]}}
+
+\def\docite[#1][#2]%
+ {\begingroup
+ \setupinteraction[\c!style=]%
+ \edef\temp{#2}%
+ \ifx\empty\temp \secondargumentfalse
+ \else \secondargumenttrue \fi
+ \ifsecondargument
+ \processcommalist[#2]\docitation
+ \doifassignmentelse
+ {#1}%
+ {\getparameters[LO][\c!alternative=,\c!extras=,#1]%
+ \edef\@@currentalternative{\LOalternative}%
+ \ifx\@@currentalternative\empty
+ \edef\@@currentalternative{\@@citedefault}%
+ \fi
+ \ifx\LOextras\empty
+ \setupcite[\@@currentalternative][#1]%
+ \else
+ \expandafter\ifx\csname LOright\endcsname \relax
+ \edef\LOextras{{\LOextras\bibalternative\c!right}}%
+ \else
+ \edef\LOextras{{\LOextras\LOright}}%
+ \fi
+ \expanded{\setupcite[\@@currentalternative][#1,\c!right=\LOextras]}%
+ \fi
+ }%
+ {\def\@@currentalternative{#1}}%
+ \expanded{%
+ \processaction[\csname @@pv\@@currentalternative \c!compress\endcsname]}
+ [ \v!yes=>\bibcitecompresstrue,
+ \v!no=>\bibcitecompressfalse,
+ \s!default=>\bibcitecompresstrue,
+ \s!unknown=>\bibcitecompresstrue]%
+ \getvalue{bib\@@currentalternative ref}[#2]%
+ \else
+ \processcommalist[#1]\docitation
+ \expanded{\processaction[\csname @@pv\@@citedefault \c!compress\endcsname]}
+ [ \v!yes=>\bibcitecompresstrue,
+ \v!no=>\bibcitecompressfalse,
+ \s!default=>\bibcitecompresstrue,
+ \s!unknown=>\bibcitecompresstrue]%
+ \edef\@@currentalternative{\@@citedefault}%
+ \getvalue{bib\@@citedefault ref}[#1]%
+ \fi
+ \endgroup}
+
+%D \macros{nocite}
+
+\def\nocite[#1]%
+ {\processcommalist[#1]\addthisref
+ \processcommalist[#1]\docitation }
+
+%D \macros{setupcite}
+
+\def\setupcite{\dodoubleempty\dosetupcite}
+
+\def\dosetupcite[#1][#2]%
+ {\ifsecondargument
+ \def\dodosetupcite##1{\getparameters[\??pv##1][#2]}%
+ \processcommalist[#1]\dodosetupcite
+ \else % default case
+ \getparameters[\??pv\@@citedefault][#1]%
+ \fi }
+
+%D Low-level stuff
+
+\def\getcitedata#1[#2]#3[#4]#5to#6%
+ {\bgroup
+ \addthisref{#4}%
+ \dofetchapublication{#4}%
+ \doifdefinedelse{@@pb@bib#2}%
+ {\xdef#6{\getvalue{@@pb@bib#2}}}%
+ {\xdef#6{\getvalue{@@pb@#2}}}%
+ \egroup}
+
+\def\dofetchapublication#1%
+ {\makepbkvalue{#1}%
+ \processcommacommand[\bibcommandlist,crossref]\clearbibitem
+ \processcommalist [artauthor,author,editor]\clearbibitemtwo
+ \processcommacommand[\bibcommandlist]\bibitemdefs
+ \processcommalist [artauthor,author,editor,crossref]\bibitemdefs
+ \getvalue{pbdd-#1}}
+
+%D This new version writes a reference out to the tui file for every
+%D \type{\cite}. This will allow backlinking.
+%D
+%D Some special care is needed so that references are not added from
+%D weird locations like in the TOC or within a \type{\setbox} command.
+
+\newcounter\citationnumber
+
+\def\docitation#1{%
+ \iftrialtypesetting \else
+ \ifdoinpututilities\else
+ \doglobal\increment\citationnumber
+ \expanded{\rawreference{}{cite-\jobname-\citationnumber}{#1}}%
+ \fi \fi }
+
+%D \macros{numreferred,doifreferredelse,addthisref,publist}
+%D
+%D The interesting command here is \type{\addthisref}, which maintains
+%D the global list of references.
+%D
+%D \type{\numreferred} is needed to do automatic calculations on
+%D the label width, and \type{\doifreferredelse} will be used
+%D to implement \type{criterium=cite}.
+
+\newcounter\numreferred
+
+\long\def\doifreferredelse#1{\doifdefinedelse{pbr-#1}}
+
+\def\addthisref#1%
+ {\doifundefinedelse{pbr-#1}
+ {\setxvalue{pbr-#1}{\citationnumber}%
+ \doglobal\increment\numreferred
+ \ifx\publist\empty \gdef\publist{#1}\else\appended\gdef\publist{,#1}\fi}
+ {\setxvalue{pbr-#1}{\getvalue{pbr-#1},\citationnumber}}}
+
+\let\publist\empty
+
+%D \macros{doifbibreferencefoundelse}
+%D
+%D Some macros to fetch the information provided by
+%D \type{\startpublication}.
+
+\def\doifbibreferencefoundelse#1%
+ {\preloadbiblist
+ \doifdefinedelse{pbdk-#1}
+ {\firstoftwoarguments}
+ {\showmessage\m!publications{5}{#1 is unknown}%
+ \secondoftwoarguments}}
+
+%D \macros{ixbibauthoryear,thebibauthors,thebibyears}
+%D
+%D If compression of \type{\cite}'s argument expansion is on,
+%D the macros that deal with authors and years call this internal
+%D command to do the actual typesetting.
+%D
+%D Two entries with same author but with different years may
+%D be condensed into ``Author (year1,year2)''. This is about the
+%D only optimization that makes sense for the (author,year)
+%D style of citations (years within one author have to be unique
+%D anyway so no need to test for that, and ``Author1, Author2 (year)''
+%D creates more confusion than it does good).
+%D
+%D In the code below,
+%D the macro \type{\thebibauthors} holds the names of the alternative
+%D author info fields for the current list. This is a commalist,
+%D and \type{\thebibyears} holds the (collection of) year(s) that go with
+%D this author (possibly as a nested commalist).
+%D
+%D There had better be an author for all cases, but there
+%D does not have to be year info always. \type{\thebibyears} is
+%D pre-initialized because this makes the insertion macros simpler.
+%D
+%D In `normal' \TeX, of course there are expansion problems again.
+
+\def\ixbibauthoryear#1#2#3#4%
+ {\bgroup
+ \gdef\ixlastcommand {#4}%
+ \gdef\ixsecondcommand{#3}%
+ \gdef\ixfirstcommand {#2}%
+ \glet\thebibauthors \empty
+ \glet\thebibyears \empty
+ \getcommalistsize[#1]%
+ \ifbibcitecompress
+ \dorecurse\commalistsize{\xdef\thebibyears{\thebibyears,}}%
+ \processcommalist[#1]\docompressbibauthoryear
+ \else
+ \processcommalist[#1]\donormalbibauthoryear
+ \fi
+ \egroup
+ \dobibauthoryear}
+
+%D \macros{dodobibauthoryear}
+%D
+%D This macro only has to make sure that the lists
+%D \type{\thebibauthors} and \type{\thebibyears} are printed.
+
+\def\dobibauthoryear
+ {\scratchcounter\zerocount
+ \getcommacommandsize[\thebibauthors]%
+ \edef\authorcount{\commalistsize}%
+ \@EA\processcommalist\@EA[\thebibauthors]\dodobibauthoryear}
+
+\def\dodobibauthoryear#1%
+ {\advance\scratchcounter\plusone
+ \edef\wantednumber{\the\scratchcounter}%
+ \getfromcommacommand[\thebibyears][\wantednumber]%
+ \@EA\def\@EA\currentbibyear\@EA{\commalistelement}%
+ \setcurrentbibauthor{#1}%
+ \ifnum\scratchcounter=\plusone
+ \ixfirstcommand
+ \else\ifnum \scratchcounter=\authorcount\relax
+ \ixlastcommand
+ \else
+ \ixsecondcommand
+ \fi\fi}
+
+\def\setcurrentbibauthor#1%
+ {\getcommacommandsize[#1]%
+ \ifcase\commalistsize
+ % anonymous?
+ \def\currentbibauthor{}%
+ \or
+ \def\currentbibauthor{#1}%
+ \or
+ \expanded{\docurrentbibauthor#1}%
+ \else
+ \handlemultiplebibauthors{\commalistsize}{#1}%
+ \fi }
+
+\newcount\citescratchcounter
+
+\def\handlemultiplebibauthors#1#2%
+ {\citescratchcounter 0
+ \def\currentbibauthor{}%
+ \def\bibprocessauthoritem##1%
+ {\advance\citescratchcounter1
+ \ifnum \citescratchcounter=#1\relax
+ \edef\currentbibauthor{\currentbibauthor##1}%
+ \else \ifnum\numexpr\citescratchcounter+1 = #1\relax
+ \edef\currentbibauthor{\currentbibauthor ##1\bibalternative{andtext}}%
+ \else
+ \edef\currentbibauthor{\currentbibauthor ##1\bibalternative{namesep}}%
+ \fi
+ \fi }%
+ \processcommalist[#2]\bibprocessauthoritem }
+
+\setupcite
+ [author,authoryear,authoryears]
+ [\c!namesep={, }]
+
+%D This discovery of authoretallimit is not the best one,
+%D but it will do for now.
+
+\def\docurrentbibauthor#1,#2%
+ {\doifemptyelse{#2}
+ {\def\currentbibauthor{#1\bibalternative{otherstext}}}
+ {\@EA
+ \ifx\csname \??pv\@@currentalternative authoretallimit\endcsname\relax
+ \edef\currentbibauthor{#1\bibalternative{andtext}#2}%
+ \else
+ \edef\currentbibauthor{#1%
+ \ifcase0\bibalternative{authoretallimit}\relax\or
+ \bibalternative{otherstext}\else\bibalternative{andtext}#2\fi}%
+ \fi}}
+
+%D This is not the one Hans made for me, because I need a global
+%D edef, and the \type{\robustdoifinsetelse} doesn't listen to
+%D \type{\doglobal }
+
+\def\robustaddtocommalist#1#2% {item} \cs
+ {\robustdoifinsetelse{#1}#2\resetglobal
+ {\dodoglobal\xdef#2{\ifx#2\empty\else#2,\fi#1}}}
+
+%D \macros{donormalbibauthoryear}
+%D
+%D Now we get to the macros that fill the two lists.
+%D The `simple' one really is quite simple.
+
+\def\donormalbibauthoryear#1%
+ {\addthisref{#1}%
+ \def\myauthor{Xxxxxxxxxx}%
+ \def\myyear{0000}%
+ \doifbibreferencefoundelse{#1}
+ {\def\myauthor{{\getvalue{pbda-#1}}}%
+ \def\myyear {\getvalue{pbdy-#1}}}%
+ {}%
+ \@EA\doglobal\@EA\appendtocommalist\@EA{\myauthor}\thebibauthors
+ \@EA\doglobal\@EA\appendtocommalist\@EA{\myyear }\thebibyears}
+
+%D \macros{docompressbibauthoryear}
+%D
+%D So much for the easy parts. Nothing at all will be done if
+%D the reference is not found or the reference does not contain
+%D author data. No questions marks o.s.s. (to be fixed later)
+
+\def\docompressbibauthoryear#1%
+ {\addthisref{#1}%
+ \def\myauthor{Xxxxxxxxxx}%
+ \def\myyear {0000}%
+ \doifbibreferencefoundelse{#1}
+ {\xdef\myauthor{\csname pbda-#1\endcsname }%
+ \xdef\myyear {\csname pbdy-#1\endcsname }}
+ {}%
+ \ifx\myauthor\empty\else
+ \checkifmyauthoralreadyexists
+ \findmatchingyear
+ \fi}
+
+%D two temporary counters. One of these two can possibly be replaced
+%D by \type{\scratchcounter}.
+
+\newcount\bibitemcounter
+\newcount\bibitemwanted
+
+%D The first portion is simple enough: if this is the very first author
+%D it is quite straightforward to add it. \type{\bibitemcounter} and
+%D \type{\bibitemwanted} are needed later to insert the year
+%D information in the correct item of \type{\thebibyears}
+
+\def\checkifmyauthoralreadyexists
+ {\doifemptyelsevalue{thebibauthors}
+ {\global\bibitemwanted \plusone
+ \global\bibitemcounter \plusone
+ \xdef\thebibauthors{{\myauthor}}}
+ {% the next weirdness is because according to \getcommalistsize,
+ % the length of \type{[{{},{}}]} is 2.
+ \@EA\getcommalistsize\@EA[\thebibauthors,]%
+ \global\bibitemcounter\commalistsize
+ \global\advance\bibitemcounter\minusone
+ \global\bibitemwanted \zerocount
+ \processcommacommand[\thebibauthors]\docomparemyauthor}}
+
+%D The outer \type{\ifnum} accomplishes the addition of
+%D a new author to \type{\thebibauthors}. The messing about with
+%D the two counters is again to make sure that \type{\thebibyears}
+%D will be updated correctly.If the author {\it was} found,
+%D the counters will stay at their present values and everything
+%D will be setup properly to insert the year info.
+
+\def\docomparemyauthor#1%
+ {\global\advance\bibitemwanted \plusone
+ \def\mytempc{#1}%
+% \message{authors: \myauthor <=>\mytempc \ifx\mytempc\myauthor :Y \else :N
+% \meaning \myauthor, \meaning\mytempc\fi (\the\bibitemwanted = \the\bibitemcounter)}%
+ \ifx\mytempc\myauthor
+ \quitcommalist
+ \else
+ \ifnum\bibitemwanted = \bibitemcounter\relax
+ \global\advance\bibitemwanted \plusone
+ \global\bibitemcounter\bibitemwanted\relax
+ \@EA\doglobal\@EA\robustaddtocommalist\@EA{{\myauthor}}\thebibauthors
+ \fi
+ \fi}
+
+%D This macro should be clear now.
+
+\def\findmatchingyear
+ {\edef\wantednumber{\the\bibitemwanted}%
+ \getfromcommacommand[\thebibyears][\wantednumber]%
+ \ifx\commalistelement\empty
+ \edef\myyear{{\myyear}}%
+ \else
+ \edef\myyear{{\commalistelement, \myyear}}%
+ \fi
+ \edef\newcommalistelement{\myyear}%
+ \doglobal\replaceincommalist \thebibyears \wantednumber}
+
+%D \macros{preparebibrefprefix}
+%D
+%D The reference list only writes bare references when the criterium
+%D is `all'. Otherwise, a prefix is added to make sure that pdfTeX
+%D does not encounter duplicate named references. On the generation
+%D side, this is not a big problem. \type{\preparebibrefprefix}
+%D creates a suitable string to prepend if a prefix is needed.
+%D
+%D Because this macro is used within \type{\cite } that itself
+%D can be used within lists like the table of contents, it needs
+%D to save and restore \type{\savedalltoclevels} and
+%D \type{\currentlevel} (\type{\dosetfilterlevel} needs to change
+%D their values globally).
+
+\def\preparebibrefprefix
+ {\chardef\savedalltoclevels \alltoclevels
+ \let\savedcurrentlevel\currentlevel
+ \let\dosetfilterlevel\patcheddosetfilterlevel
+ \dosettoclevel\??li{pubs}%
+ \edef\bibrefprefix{\@@sectiontype\currentlevel\sectionseparator}%
+ \let\dosetfilterlevel\normaldosetfilterlevel
+ \global\let\currentlevel\savedcurrentlevel
+ \global\chardef\alltoclevels \savedalltoclevels }
+
+%D \macros{preparebibreflist}
+%D
+%D But this optional prefixing is a bit of a problem on the
+%D other side. We would like to do \type{\goto{}[article-full]}
+%D but can't do it like that, because the actual label may be
+%D \type{1:2:0:3:4:article-full]} or so. The problem is solved
+%D by building a commalist that looks like this:
+%D \starttyping
+%D \def\bibreflist%
+%D {1:2:0:3:4:article-full,
+%D 1:2:0:3:article-full,
+%D 1:2:0:article-full,
+%D 1:2:article-full,
+%D 1:article-full,
+%D article-full}
+%D \stoptyping
+
+\def\preparebibreflist#1%
+ {\let\bibreflist\empty
+ \def\storeitem##1%
+ {\ifx\bibreflist\empty
+ \edef\prefix{##1\sectionseparator}%
+ \edef\bibreflist{\prefix#1,#1}%
+ \else
+ \edef\prefix{\prefix##1\sectionseparator}%
+ \edef\bibreflist{\prefix#1,\bibreflist}%
+ \fi}%
+ \expanded{\processseparatedlist[\bibrefprefix][\sectionseparator]}\storeitem }
+
+%D \macros{gotobiblink,inbiblink,atbiblink}
+%D
+%D The final task is looping over that list until a match is found.
+
+\newif\ifbibreffound
+
+\def\gotobiblink#1[#2]%
+ {\bgroup
+ \preparebibrefprefix
+ \preparebibreflist{#2}%
+ \global\bibreffoundfalse
+ \def\setuplink##1%
+ {\ifbibreffound\else
+ \doifreferencefoundelse
+ {##1}
+ {\global\bibreffoundtrue \goto{#1}[##1]}%
+ {}\fi}%
+ \processcommacommand[\bibreflist]\setuplink
+ \ifbibreffound \else \unknownreference{#2}\fi
+ \egroup }
+
+\def\atbiblink[#1]%
+ {\bgroup
+ \preparebibrefprefix
+ \preparebibreflist{#1}%
+ \global\bibreffoundfalse
+ \def\setuplink##1%
+ {\ifbibreffound\else
+ \doifreferencefoundelse
+ {##1}
+ {\global\bibreffoundtrue \at[##1]}%
+ {}\fi}%
+ \processcommacommand[\bibreflist]\setuplink
+ \ifbibreffound \else \unknownreference{#1}\fi
+ \egroup }
+
+\def\inbiblink[#1]%
+ {\bgroup
+ \preparebibrefprefix
+ \preparebibreflist{#1}%
+ \global\bibreffoundfalse
+ \def\setuplink##1%
+ {\ifbibreffound\else
+ \doifreferencefoundelse
+ {##1}
+ {\global\bibreffoundtrue \in[##1]}%
+ {}\fi}%
+ \processcommacommand[\bibreflist]\setuplink
+ \ifbibreffound \else \unknownreference{#1}\fi
+ \egroup }
+
+%D \macros{bibauthoryearref,bibauthoryearsref,bibauthorref,bibyearref}
+%D
+%D Now that all the hard work has been done, these are simple.
+%D \type{\ixbibauthoryearref} stores the data in the macros
+%D \type{\currentbibauthor} and \type{\currentbibyear}.
+
+\def\ifbibinteractionelse%
+ {\iflocation
+ \edef\test{\bibalternative\c!interaction}%
+ \ifx\test\v!stop
+ \@EA\@EA\@EA\secondoftwoarguments
+ \else
+ \@EA\@EA\@EA\firstoftwoarguments
+ \fi
+ \else
+ \@EA\secondoftwoarguments
+ \fi
+ }
+
+\def\bibmaybeinteractive#1#2%
+ {\ifbibcitecompress #2\else
+ \ifbibinteractionelse{\gotobiblink{#2}[#1]}{#2}\fi }
+
+\def\bibauthoryearref[#1]%
+ {\ixbibauthoryear{#1}%
+ {\bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween
+ \bibalternative\v!left{\currentbibyear}\bibalternative\v!right}}
+ {\bibalternative\c!pubsep
+ \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween
+ \bibalternative\v!left {\currentbibyear}\bibalternative\v!right}}
+ {\bibalternative\c!lastpubsep
+ \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween
+ \bibalternative\v!left {\currentbibyear}\bibalternative\v!right}}}
+
+\def\bibauthoryearsref[#1]%
+ {\bibalternative\v!left
+ \ixbibauthoryear{#1}
+ {\bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween{\currentbibyear}}}
+ {\bibalternative\c!pubsep
+ \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween{\currentbibyear}}}
+ {\bibalternative\c!lastpubsep
+ \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween{\currentbibyear}}}%
+ \bibalternative\v!right}
+
+\def\bibauthorref[#1]%
+ {\bibalternative\v!left
+ \ixbibauthoryear{#1}%
+ {\bibmaybeinteractive{#1}{{\currentbibauthor}}}
+ {\bibalternative\c!pubsep \bibmaybeinteractive{#1}{{\currentbibauthor}}}
+ {\bibalternative\c!lastpubsep\bibmaybeinteractive{#1}{{\currentbibauthor}}}%
+ \bibalternative\v!right}
+
+\def\bibyearref[#1]%
+ {\bibalternative\v!left
+ \ixbibauthoryear{#1}%
+ {\bibmaybeinteractive{#1}{{\currentbibyear}}}
+ {\bibalternative\c!pubsep \bibmaybeinteractive{#1}{{\currentbibyear}}}
+ {\bibalternative\c!lastpubsep\bibmaybeinteractive{#1}{{\currentbibyear}}}%
+ \bibalternative\v!right}
+
+%D ML problems:
+
+%D \macros{bibshortref,bibkeyref,bibpageref,bibtyperef,bibserialref}
+%D
+%D There is hardly any point in trying to compress these. The only
+%D thing that needs to be done is making sure that
+%D the separations are inserted correctly. And that is
+%D what \type{\refsep} does.
+
+\newif\iffirstref
+
+\def\refsep{\iffirstref\firstreffalse\else\bibalternative\c!pubsep\fi}
+
+\def\bibshortref[#1]%
+ {\bibalternative\v!left
+ \firstreftrue\processcommalist[#1]\dobibshortref
+ \bibalternative\v!right}
+
+\def\dobibshortref#1%
+ {\addthisref{#1}\refsep
+ \doifbibreferencefoundelse{#1}{\gotobiblink{\getvalue{pbds-#1}}[#1]}
+ {\unknownreference{#1}}}
+
+
+\def\bibserialref[#1]%
+ {\bibalternative\v!left
+ \firstreftrue\processcommalist[#1]\dobibserialref
+ \bibalternative\v!right}
+
+\def\dobibserialref#1%
+ {\addthisref{#1}\refsep
+ \doifbibreferencefoundelse{#1}{\gotobiblink{\getvalue{pbdn-#1}}[#1]}
+ {\unknownreference{#1}}}
+
+\def\bibkeyref[#1]%
+ {\bibalternative\v!left
+ \firstreftrue\processcommalist[#1]\dobibkeyref
+ \bibalternative\v!right}
+
+\def\dobibkeyref#1%
+ {\addthisref{#1}\refsep\gotobiblink{#1}[#1]}
+
+\def\gotoDOI#1#2%
+ {\ifbibinteractionelse
+ {\useURL[bibfooDoi#1][#2]%
+ \useURL[bibfoo#1][http://dx.doi.org/#2]%
+ \goto{\url[bibfooDoi#1]}[url(bibfoo#1)]}
+ {\hyphenatedurl{#2}}}
+
+\def\bibdoiref[#1]%
+ {\bibalternative\v!left
+ \firstreftrue\processcommalist[#1]\dobibdoiref
+ \bibalternative\v!right}
+
+\def\dobibdoiref#1%
+ {\addthisref{#1}\refsep
+ \doifbibreferencefoundelse{#1}{\expanded{\gotoDOI{#1}{\getvalue{pbdo-#1}}}}
+ {\unknownreference{#1}}}
+
+\def\biburlref[#1]%
+ {\bibalternative\v!left
+ \firstreftrue\processcommalist[#1]\dobiburlref
+ \bibalternative\v!right}
+
+\def\gotoURL#1#2%
+ {\ifbibinteractionelse
+ {\useURL[bibfoo#1][#2]\goto{\url[bibfoo#1]}[url(bibfoo#1)]}
+ {\hyphenatedurl{#2}}}
+
+\def\dobiburlref#1%
+ {\addthisref{#1}\refsep
+ \doifbibreferencefoundelse{#1}{\expanded{\gotoURL{#1}{\getvalue{pbdu-#1}}}}
+ {\unknownreference{#1}}}
+
+\def\bibtyperef[#1]%
+ {\bibalternative\v!left
+ \firstreftrue\processcommalist[#1]\dobibtyperef
+ \bibalternative\v!right}
+
+\def\dobibtyperef#1%
+ {\addthisref{#1}\refsep
+ \doifbibreferencefoundelse{#1}{\gotobiblink{\getvalue{pbdt-#1}}[#1]}
+ {\unknownreference{#1}}}
+
+\def\bibpageref[#1]%
+ {\bibalternative\v!left
+ \firstreftrue\processcommalist[#1]\dobibpageref
+ \bibalternative\v!right}
+
+\def\dobibpageref#1%
+ {\addthisref{#1}\refsep
+ \ifbibinteractionelse{\atbiblink[#1]}{{\referencingfalse\at[#1]}}}
+
+\def\bibdataref[#1]%
+ {\bibalternative\v!left
+ \firstreftrue\processcommalist[#1]\dobibdata
+ \bibalternative\v!right}
+
+\def\dobibdata#1%
+ {\addthisref{#1}\refsep
+ \doifbibreferencefoundelse{#1}{\dotypesetapublication{#1}}
+ {\unknownreference{#1}}}
+
+\let\bibnoneref\nocite
+
+%D \macros{bibnumref}
+%D
+%D It makes sense to try and compress the argument list of
+%D \type{\bibnumref}. There are two things involved: the actual
+%D compression, and a sort routine. The idea is to store the
+%D found values in a new commalist called \type{\therefs}.
+
+%D But that is not too straight-forward, because \type{\in} is
+%D not expandable,
+%D so that the macro \type{\expandrefs} is needed.
+
+\def\expandrefs#1%
+ {\bgroup
+ \preparebibrefprefix
+ \preparebibreflist{#1}%
+ \global\bibreffoundfalse
+ \def\setuplink##1%
+ {\ifbibreffound\else
+ \doifreferencefoundelse
+ {##1}
+ {\global\bibreffoundtrue
+ \@EA\doglobal\@EA\addtocommalist\@EA{\reftypet}\therefs }%
+ {}\fi}%
+ \processcommacommand[\bibreflist]\setuplink
+ \ifbibreffound \else \showmessage\m!publications{5}{#1 unknown}%
+ \doglobal\addtocommalist{0}\therefs\fi
+ \egroup }
+
+%D But at least the actual sorting code is simple (note that sorting
+%D a list with exactly one entry fails to return anything, which
+%D is why the \type{\ifx} is needed).
+
+\def\bibnumref[#1]%
+ {\bibalternative\v!left
+ \penalty\!!tenthousand
+ \processcommalist[#1]\addthisref
+ \firstreftrue
+ \ifbibcitecompress
+ \glet\therefs\empty
+ \processcommalist[#1]\expandrefs
+ \sortcommacommand[\therefs]\donumericcompare
+ \ifx\empty\sortedcommalist\else
+ \let\therefs\sortedcommalist
+ \fi
+ \compresscommacommandnrs[\therefs]%
+ \processcommacommand[\compressedlist]\verysimplebibnumref
+ \else
+ \processcommalist[#1]\dosimplebibnumref
+ \fi
+ \bibalternative\v!right}
+
+\def\dosimplebibnumref #1%
+ {\refsep\ifbibinteractionelse
+ {\inbiblink[#1]}{{\referencingfalse\inbiblink[#1]}}}
+
+\def\verysimplebibnumref#1{\doverysimplebibnumref#1}
+
+\def\doverysimplebibnumref#1#2%
+ {\refsep
+ \ifcase#1\relax \unknownreference{#1}\else
+ \def\tempa{#2}\ifx\empty\tempa#1\else#1\bibalternative\c!inbetween#2\fi
+ \fi}
+
+%D By request from Sanjoy. This makes it easier to implement
+%D \type{\citeasnoun}.
+
+\def\bibauthornumref[#1]%
+ {\getcommalistsize[#1]%
+ \global\bibitemcounter\commalistsize
+ \firstreftrue
+ \processcommalist[#1]\dobibauthornumref }
+
+\def\dobibauthornumref#1%
+ {\addthisref{#1}\refsep
+ \doifbibreferencefoundelse{#1}
+ {\getvalue{pbda-#1}%
+ \bibalternative\c!inbetween
+ \bibalternative\v!left
+ \ifbibinteractionelse{\inbiblink[#1]}
+ {{\referencingfalse\inbiblink[#1]}}%
+ \bibalternative\v!right}
+ {\unknownreference{#1}}}
+
+%D And some defaults are loaded from bibl-apa:
+
+\setuppublications
+ [\v!month\v!conversion=,
+ \c!alternative=apa]
+
+\appendtoks
+ \preloadbiblist
+\to \everystarttext
+
+\protect \endinput
diff --git a/tex/context/base/bibl-tra.mkiv b/tex/context/base/bibl-tra.mkiv
new file mode 100644
index 000000000..519af0c6f
--- /dev/null
+++ b/tex/context/base/bibl-tra.mkiv
@@ -0,0 +1,1552 @@
+%D \module
+%D [ file=bibl-tra,
+%D version=2009.08.22,
+%D title=\CONTEXT\ Publication Module,
+%D subtitle=Publications,
+%D author=Taco Hoekwater,
+%D date=\currentdate,
+%D copyright=Public Domain]
+%C
+%C Donated to the public domain.
+
+%D This module has been adapted to \MKIV\ by Hans Hagen so if things go wrong,
+%D he is to blame. The changes concern references and lists but teh rendering
+%D itself is unchanged. Future versions might provide variants as we have plans
+%D for an upgrade.
+%D
+%D We use a still somewhat experimental extension to the list
+%D mechanism. Eventually the bibtex module will use the bibl loader
+%D and access the data by means of lpath expressions. In that case we
+%D don't need to process the bibliography but still need to track
+%D usage as done here.
+%D
+%D A bit ongoing: make more local macros prefixed with bib, i.e. the bib
+%D namespace is reserved.
+
+\writestatus{loading}{ConTeXt Bibliography Support / BibTeX}
+
+\definefilesynonym[bib][obsolete]
+
+\registerctxluafile{bibl-tra}{1.001}
+
+%D The original was developed independantly by Taco Hoekwater while still working for Kluwer
+%D Academic publishers (it still used the dutch interface then). Development continued after
+%D he left Kluwer, and in Januari 2005, the then already internationalized file was merged
+%D with the core distribution by Hans Hagen. The current version is once again by Taco.
+%D
+%D More documentation and additional resources can be found on the contextgarden:
+%D \hyphenatedurl{http://wiki.contextgarden.net//Bibliography}.
+
+%D \subject{DONE (dd/mm/yyyy)}
+%D
+%D \startitemize
+%D \item add author definition (and associated system variable) (26/05/2005)
+%D \item add finalnamesep support for Oxford comma (17/09/2005)
+%D \item add \type{\insert...} for: doi, eprint, howpublished (19/09/2005)
+%D \item allow a defaulted \type{\setupcite} (19/11/2005)
+%D \item renamed citation type 'number' to 'serial' (19/11/2005)
+%D \item better definition of \type{\inverted...author} (19/11/2005)
+%D \item don't reset [numbercommand] in \type {\setuppublication} by default (20/11/2005)
+%D \item don't disable other \type {\setuppublication} keys if alternative is present (20/11/2005)
+%D \item drop \type{\sanitizeaccents} (20/11/2005)
+%D \item added \type{\nocite} and \type{\cite[none]} (21/11/2005)
+%D \item added headtext for it (23/11/2005)
+%D \item make \type{\cite[url]} and \type{\cite[doi]} interactive (23/11/2005)
+%D \item make right-aligned labels in the list work even when autohang=no
+%D \item use 'et al.' instead of 'et.al.'. Pointed out by Peter M\"unster (30/12/2005)
+%D \item added headtext for cz (31/12/2005)
+%D \item Keep whitespace after \type{\cite} with single argument (31/12/2005)
+%D \item Fix broken \type{\cite{}} support (31/12/2005)
+%D \item Use \type{\readfile} inside \type{\usepublications} instead of \type{\readsysfile} (12/01/2006)
+%D \item Use \type{\currentbibyear} and \type{\currentbibauthor} instead of \type{\YR} and \type{\AU} (05/02/2006)
+%D \item Fix compressed version of authoryear style (05/02/2006)
+%D \item Rename the clashing data fields \type{\url} and \type{\type} to \type{\biburl} and \type{\bibtype} (05/02/2006)
+%D \item Added two french bibl files from Renaud Aubin (06/02/2006)
+%D \item Five new bib class and eight extra bib fields, for IEEEtran (07/02/2006)
+%D \item French keyword translation, provided by Renaud (08/02/2006)
+%D \item fix underscores in undefined keys (22/02/2006)
+%D \item Destroy interactivity in labels of the publication list (13/03/2006)
+%D \item fix multi-cite list compression (11/4/2006)
+%D \item fix \type{\getcitedata} (11/4/2006)
+%D \item magic for chapter bibs (18-25/4/2006)
+%D \item language setting (25/4/2006)
+%D \item use \type{\hyphenatedurl} for \type{\inserturl} (25/4/2006)
+%D \item Add \type{\docitation} to \type{\nocite}(26/4/2006)
+%D \item patents can have numbers, added to bst files (26/4/2006)
+%D \item \type{\docitation} needs a \type{\iftrialtypesetting} (27/4/2006)
+%D \item \type{\filllocalpublist}'s loop is bound by definedness, not resolvedness (27/4/2006)
+%D \item \type{\setuppublications[monthconversion=]} added (15/5/2006)
+%D \item use \type{\undefinedreference} instead of bare question marks (15/5/2006)
+%D \item add grouping around \type{\placepublications} commands (16/5/2006)
+%D \item fix a bug in \type{\cite{}} (17/5/2006)
+%D \item support \type{\cite[authornum]} (18/5/2006)
+%D \item make \type{\cite} unexpandable (20/6/2006)
+%D \item allow hyperlinks in author\&year combo's
+%D (cite list compression has to be off) (20/6/2006)
+%D \item fix duplicate labels for per-chapter style (20/6/2006)
+%D \item allow \type{\setupcite[interaction=(start|stop)]}
+%D \item fix the item number in the publication list with 'numbering=yes' (22/6/2006)
+%D \item make the default criterium for \type{\placepublications} be \type{previous} (23/6/2006)
+%D \item fix \type{\normalauthor} and \type{\normalshortauthor} spacing (29/6/2006)
+%D \item do not typeset empty arguments to \type{\typesetapublication} (29/6/2006)
+%D \item add \type{symbol=none} to \type{\setuplist} in unnumbered
+%D mode to prevent typesetting of bare numbers (29/6/2006)
+%D \item remove two incorrect spaces from bibl-num.tex (1/7/2006)
+%D \item reset font styles within \type{\cite}, so that font switches
+%D in \type{left} stay in effect (12/7/2006)
+%D \item guard added against loading bbl files multiple times (13/7/2006)
+%D \item fix \type{\cite[num]} with compression is on. (14/7/2006)
+%D \item test \type{\iflocation} before deciding to use the
+%D interactive version of cite (18/7/2006)
+%D \item support \type{\setupcite[authoretallimit=1]} (18/7/2006)
+%D \item support use of \type{\cite} within titles and captions by
+%D saveguarding the list item extraction and reference placement
+%D code (19/7/2006)
+%D \item support \type{\setuppublicationlist[title=\chapter]} (4/8/2006)
+%D \item use the expansion of \type{\headtext{pubs}} (4/8/2006)
+%D \item hook added for repeated authors in publication list
+%D \type{\setuppublicationlist[artauthorcommand=\mythreeargscommand]}
+%D (4/8/2006)
+%D \item make the bracketed arguments of \type{\artauthor}, \type{\author}
+%D and \type{\editor} (bbl commands) optional (4/8/2006)
+%D \item the constants \type{sorttype}, \type{compress} and
+%D \type{autohang} have moved to the core (8/8/2006)
+%D \item bibtex is now registered as a program to be run by texexec (8/8/2006)
+%D \item fix a bug in \type{\setupcite[authoretallimit=1]} (9/8/2006)
+%D \item fix a bug inside citations that prevented lastpubsep from ever being
+%D used due to a volatile \type{\commalistsize} (25/8/2006).
+%D \item added the possibility of \type{\placepublications[option=continue]}
+%D (6/9/2006)
+%D \item Mojca translated Master's Thesis to Masterarbeit (bibl-apa-de.tex)
+%D (12/9/2006)
+%D \item Added \type{\setuppublicationlist[maybeyear=off]} by request from
+%D Thomas Schmitz (15/9/2006)
+%D \item Removed some spurious spaces pointed out by willi egger (19/9/2006)
+%D \item Add configuration of bibtex executable name (4/11/2006)
+%D \item Fix numbering=short and numbering=bib (spotted by Matthias W\"achter) (4/11/2006)
+%D \item third attempt to get a correct release (5/11/2006)
+%D \item fix a few missing dots in bibl-num.tex (7/12/2006)
+%D \item Patch for DOI's by Tobias Burnus (17/4/2007)
+%D \item Patch for \type{\insertbiburl} and \type{\insertdoi} for Tobias Burnus (18/4/2007)
+%D \item Added a missing \type{\relax} in \type{\dospecialbibinsert},
+%D that made the space before the {\it et al.} text disappear. (18/4/2007)
+%D \item Attempt to fix percent signs in bbl files. As a side-effect,
+%D this prohibits comments in \tex{startpublication} blocks! (17/4/2008)
+%D \item Patch from Matthias W\"achter that allows arbitrary .bst
+%D files to be used with \tex{setupbibtex} (25/9/2008)
+%D \item Extended for the new multilingual setups for the Oct 2008 current of ConTeXt (23/10/2008)
+%D \item Multilingual setups needed another fix (27/10/2008)
+%D \item Two fixes for bibl-apa by Michael Green (27/10/2008)
+%D \item Catalan translation of 'References' (10/11/2008)
+%D \item 'chapter' -> 'chapitre' in bibl-apa-fr (27/11/2008)
+%D \item Run bibtex via os.execute in mkiv modee (01/12/2008)
+%D \item Small correction in bibl-apa's placement of volume
+%D information in articles (05/01/2009)
+%D \item Handle multi-author (more than two) cases in \type{\cite}
+%D (02/03/2009)
+%D \item Suppress a syntax error in \type{cont-xp} mode. The output is
+%D probably not right, though (02/03/2009)
+%D \item Added a \tex{loadmarkfile} at the end, and two new files
+%D from Hans. The \type{t-bib.mkiv} is needed to make the module
+%D work with the new structure code (17/04/2009)
+%D \item Added a patch to \type{t-bib.mkiv} from Hans to make the
+%D cross referencing between multiple citations an
+%D bibliographies work (27/04/2009)
+%D \item Remove a superfluous \type{\unprotect} in t-bib.mkiv (11/05/2009).
+%D \item Patch of incollection in bibl-ams.tex from Xan (08/06/2009).
+%D \item Patch of unpublished in bibl-ams.tex from Xan (22/07/2009).
+%D \item Modified \type{\bibdogetupsometextprefix} so it works for undefined
+%D language labels, from Hans (13/08/2009).
+%D \item Adapt referencing and list insertion to \MKIV. Update some code
+%D to the latest \CONTEXT. Change some names in order to avoid conflicts
+%D with existing core names (like \type {\insertpages}).
+%D \item All constants, variables, message etc.\ are now in the core.
+%D \item Added key: \type {method} (when \type {global}, previous shown entries are
+%D not shown again, when \type {local} they are repeated).
+%D \stopitemize
+%D
+%D \subject{WISHLIST}
+%D
+%D \startitemize
+%D \item link back from publication list to citation
+%D \item export \type {\citation{}}
+%D \item support mlbibtex
+%D \item don't load the whole lot, but filter entries instead
+%D \item 9 vs 10, 19 vs 20 ... prevent extra runs when only subtle changes in wd of reference
+%D \stopitemize
+
+\unprotect
+
+\def\biblistname{pubs} % for compatibility
+
+\definelist
+ [pubs]
+
+\setuplist
+ [pubs]
+ [\c!state=\v!start,
+ \c!width=]
+
+\installstructurelistprocessor{pubs:userdata}%
+ {\ctxlua{bibtex.hacks.add(structure.lists.uservalue("\currentlist",\currentlistindex,"bibref"),\currentlistindex)}}
+
+\newcount\bibtexblock \bibtexblock\plusone
+
+%D \macros{bibdoif,bibdoifnot,bibdoifelse}
+%D
+%D Here are a few small helpers that are used a lot in all the typesetting commands
+%D (\type{\bibinsert...}) we will encounter later.
+
+\long\def\bibdoifelse#1%
+ {\@EA\def\@EA\!!stringa\@EA{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\long\def\bibdoifnot#1%
+ {\@EA\def\@EA\!!stringa\@EA{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\long\def\bibdoif#1%
+ {\@EA\def\@EA\!!stringa\@EA{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+%D Unfortunately, \BIBTEX\ is not the best configurable program
+%D around. The names of the commands it parses as well as the \type{.aux}
+%D extension to the file name are both hardwired.
+%D
+%D This means \CONTEXT\ has to write a \LATEX-style auxiliary file, yuk!
+%D The good news is that it can be rather short. We'll just ask
+%D \BIBTEX\ to output the entire database(s) into the \type{bbl} file.
+%D
+%D The \type{\bibstyle} command controls how the \type{bbl} file will
+%D be sorted. The possibilities are:
+%D
+%D \startitemize[packed]
+%D \item by author (+year, title): cont-au.bst
+%D \item by title (+author, year): cont-ti.bst
+%D \item by short key as in abbrev.bst: cont-ab.bst
+%D \item not sorted at all: cont-no.bst
+%D \stopitemize
+
+\newtoks\everysetupbibtex
+
+\unexpanded\def\setupbibtex
+ {\dosingleempty\dosetupbibtex}
+
+\def\dosetupbibtex[#1]%
+ {\let\@@pbdatabase\empty
+ \getparameters[\??pb][#1]%
+ \the\everysetupbibtex}
+
+\def\installbibtexsorter#1#2%
+ {\setvalue{\??pb:\c!sort:#1}{#2}}
+
+\installbibtexsorter\v!no {no}
+\installbibtexsorter\v!author {au}
+\installbibtexsorter\v!title {ti}
+\installbibtexsorter\v!short {ab}
+\installbibtexsorter\empty {no}
+\installbibtexsorter\s!default{no}
+
+\def\thebibtexsorter{\executeifdefined{\??pb:\c!sort:\@@pbsort}\@@pbsort}
+
+\appendtoks
+ \ifx\@@pbdatabase\empty\else
+ \doifmode{*\v!first}{\ctxlua{bibtex.hacks.process { style="\thebibtexsorter", database="\@@pbdatabase" }}}%
+ \fi
+\to \everysetupbibtex
+
+\setupbibtex
+ [\c!sorttype=\v!cite,
+ \c!sort=no]
+
+%D \macros{iftypesetall,ifbibcitecompress}
+%D
+%D The module needs some new \type{\if} statements.
+
+\newtoks\everysetuppublications
+
+\unexpanded\def\setuppublications
+ {\dosingleargument\dosetuppublications}
+
+\def\dosetuppublications[#1]%
+ {\getparameters[\??pb][\c!alternative=,#1]%
+ \doifsomething\@@pbalternative
+ {\readsysfile{bibl-\@@pbalternative.tex}
+ {\showmessage\m!publications{6}{bibl-\@@pbalternative}}
+ {\showmessage\m!publications{1}{bibl-\@@pbalternative}}%
+ \let\@@pbalternative\empty}%
+ \let\setuppublicationlayout\normalsetuppublicationlayout % overloaded in bibl-num ... vadjust needs to be done with option
+ \getparameters[\??pb][#1]% as bibl-* can have set things back
+ \the\everysetuppublications
+ \ignorespaces}
+
+%D We can omit already shown references (\v!global) or use fresh
+%D lists each time (\v!local).
+
+\chardef\bibtexoncemode\plusone % 0=disable, 1=local, 2=global
+
+\appendtoks
+ \doifelse\@@pbmethod\v!local
+ {\chardef\bibtexoncemode\plusone}%
+ {\chardef\bibtexoncemode\plustwo}%
+\to \everysetuppublications
+
+%D Cite lists are compressed, if possible. This is set later on.
+
+\newif\ifbibcitecompress\bibcitecompresstrue
+
+% \appendtoks
+% \processaction
+% [\@@pbnumbering]
+% [ \v!yes=>\let\@@pbinumbercommand\firstofoneargument,
+% \v!no=>\let\@@pbinumbercommand\gobbleoneargument,
+% \v!short=>\def\@@pbinumbercommand##1{\bibgetvars\currentpublicationkey},
+% \v!bib=>\def\@@pbinumbercommand##1{\bibgetvarn\currentpublicationkey},
+% \s!unknown=>\let\@@pbinumbercommand\firstofoneargument]%
+% \to \everysetuppublications
+
+\def\@@pbinumbercommand{\executeifdefined{\??pb:\c!numbercommand:\@@pbnumbering}\firstofoneargument}
+
+\letvalue{\??pb:\c!numbercommand:\v!yes }\firstofoneargument
+\letvalue{\??pb:\c!numbercommand:\v!no }\gobbleoneargument
+\setvalue{\??pb:\c!numbercommand:\v!short}#1{\bibgetvars\currentpublicationkey}
+\setvalue{\??pb:\c!numbercommand:\v!bib }#1{\bibgetvarn\currentpublicationkey}
+
+% to be tested
+%
+% \setvalue{\??pb:\c!numbercommand:\v!short}{\bibgetvars\currentpublicationkey\firstofoneargument}
+% \setvalue{\??pb:\c!numbercommand:\v!bib }{\bibgetvarn\currentpublicationkey\firstofoneargument}
+
+\appendtoks
+ \processaction
+ [\@@pbrefcommand]
+ [\s!default=>\edef\@@citedefault{\@@pbrefcommand},
+ \s!unknown=>\edef\@@citedefault{\@@pbrefcommand}]%
+\to \everysetuppublications
+
+\def\bibleftnumber#1{#1\hfill~}
+
+%D \macros{usepublications}
+%D
+%D After discussing it with Thomas Schmitz it became clear that using external
+%D references makes no sense as one needs to refer to it in special ways and
+%D because similar numbers can be confusing. So, for the moment this is not
+%D supported in \MKIV. (So no: see reference [3-5,9] in "some other document")
+
+\def\usepublications[#1]%
+ {\processcommalist[#1]\dousepublications}
+
+% \def\dousepublications#1%
+% {\doonlyonce{#1.\f!bibextension}
+% {\readfile{#1.\f!bibextension}
+% {\showmessage\m!publications{4}{#1.\f!bibextension}}
+% {\showmessage\m!publications{2}{#1.\f!bibextension}}}}
+
+\def\dousepublications#1%
+ {\doonlyonce{#1.\f!bibextension}{\dodousepublications{#1}}}
+
+\def\dodousepublications#1%
+ {\let\@@savedpar\par
+ \let\par\ignorespaces
+ \ifhmode\kern\zeropoint\fi
+ \readfile{#1.\f!bibextension}
+ {\showmessage\m!publications{4}{#1.\f!bibextension}}
+ {\showmessage\m!publications{2}{#1.\f!bibextension}}%
+ \ifhmode\removeunwantedspaces\fi
+ \let\par\@@savedpar}
+
+%D \macros{setuppublicationlist}
+%D
+%D This will be the first command in (\BIBTEX-generated) \type{bbl}
+%D files. `samplesize' is a sample value (in case of \BIBTEX-generated
+%D files, this will be the longest `short' key). `totalnumber'
+%D is the total number of entries that will follow in this
+%D file.
+%D
+%D Both values are only needed for the label calculation
+%D if `autohang' is `true', so by default the command is
+%D not even needed, and therefore I saw no need to give
+%D it it's own system variable and it just re-uses \type{pb}.
+
+\def\publicationlistparameter#1{\csname\??pv:l:#1\endcsname}
+
+\unexpanded\def\setuppublicationlist
+ {\dosingleempty\dosetuppublicationlist}
+
+\def\dosetuppublicationlist[#1]%
+ {\getparameters[\??pv:l:][#1]%
+ \setuplist[pubs][\c!samplesize={AA99},\c!alternative=a,\c!interaction=,\c!pagenumber=\v!no,#1,\c!command=]}
+
+\unexpanded\def\setuppublicationlayout[#1]#2%
+ {\setvalue{\??pv:l:#1}{#2}}
+
+\let\normalsetuppublicationlayout\setuppublicationlayout
+
+\setuppublicationlist[\c!title=,\c!command=\dospecialbibinsert,\c!maybeyear=\v!on]
+
+%D \macros{bibalternative}
+%D
+%D A nice little shorthand that will be used so we don't have to
+%D key in the weird \type{\@@pv} parameter names all the time.
+
+\def\bibalternative#1%
+ {\csname\??pv\@@currentalternative#1\endcsname}
+
+%D \macros{simplebibdef,bibcommandlist}
+%D
+%D \type{\simplebibdef} defines \type{bib@#1}, which in turn will
+%D use one argument that is stored in \type{@@pb@#1}.
+%D
+%D \type{\simplebibdef} also defines \type{bibinsert#1}, which can be
+%D used in the argument of \type{\setuppublicationlayout} to fetch
+%D one of the \type{@@pb@} data entries. \type{bibinsert#1} then has
+%D three arguments: \type{#1} are commands to be executed before the
+%D data, \type{#2} are commands to be executed after the data, and
+%D \type{#3} are commands to be executed if the data is not found.
+%D
+%D \type{\bibcommandlist} is the list of commands that is affected
+%D by this approach. Later on, it will be used to do a series
+%D of assignments from \type{#1} to \type{bib@#1}: e.g
+%D \type{\title} becomes \type{\bib@title} when used within
+%D a publication.
+
+\newtoks\initializebibdefinitions % we need to prevent clashes
+
+\def\simplebibdef#1% hh: funny expansion ?
+ {\@EA\long\@EA\def\csname bib@#1\endcsname##1%
+ {\setvalue{\??pb @#1}{##1}\ignorespaces}%
+ \expandafter \appendtoks
+ \expandafter\let\csname insert#1\expandafter\endcsname\csname bibinsert#1\endcsname
+ \to \initializebibdefinitions
+ \@EA\unexpanded\@EA\def\csname bibinsert#1\endcsname##1##2##3%
+ {\@EA\bibdoifelse\@EA{\csname\??pb @#1\endcsname}{##1\csname\??pb @#1\endcsname##2}{##3}}}
+
+\def\bibcommandlist
+ {abstract, annotate, arttitle, assignee, bibnumber, bibtype, biburl, chapter, city,
+ comment, country, day, dayfiled, doi, edition, eprint, howpublished, isbn, issn,
+ issue, journal, keyword, keywords, lastchecked, month, monthfiled, names, nationality,
+ note, notes, organization, pages, pubname, pubyear, revision, series, size, thekey,
+ title, volume, yearfiled}
+
+\processcommacommand[\bibcommandlist]\simplebibdef
+
+% \def\bibinsertdoi#1#2#3%
+% {\begingroup
+% \bibdoifelse{\@@pb@doi}%
+% {\edef\ascii{\detokenize\expandafter{\@@pb@doi}}% probably not ok, to less expansion
+% #1\expanded{\bibgotoDOI{\@@pb@thekey}{\ascii}}#2}{#3}%
+% \endgroup}
+%
+% \def\bibinsertbiburl#1#2#3%
+% {\begingroup
+% \bibdoifelse{\@@pb@biburl}%
+% {\edef\ascii{\detokenize\expandafter{\@@pb@biburl}}% probably not ok, to less expansion
+% #1\expanded{\bibgotoURL{\@@pb@thekey}{\ascii}}#2}{#3}%
+% \endgroup}
+
+\def\bibinsertdoi#1#2#3% let's see how this fails
+ {\bibdoifelse{\@@pb@doi}{#1\expanded{\bibgotoDOI{\@@pb@thekey}{\@@pb@doi}}#2}{#3}}
+
+\def\bibinsertbiburl#1#2#3% let's see how this fails
+ {\bibdoifelse{\@@pb@biburl}{#1\expanded{\bibgotoURL{\@@pb@thekey}{\@@pb@biburl}}#2}{#3}}
+
+\def\bibinsertmonth#1#2#3%
+ {\bibdoifelse\@@pb@month
+ {#1\doifnumberelse\@@pb@month
+ {\doifconversiondefinedelse\@@pbmonthconversion
+ {\convertnumber\@@pbmonthconversion\@@pb@month}{\@@pb@month}}%
+ {\@@pb@month}#2}%
+ {#3}}
+
+\appendtoks
+ \let\inserturl \bibinsertbiburl % for backward compat.
+ \let\inserttype\bibinsertbibtype % for backward compat.
+\to\initializebibdefinitions
+
+\def\newbibfield[#1]%
+ {\simplebibdef{#1}%
+ \edef\bibcommandlist{\bibcommandlist,#1}}
+
+%D \macros{complexbibdef,specialbibinsert}
+%D
+%D The commands \type{\artauthor}, \type{\author} and
+%D \type{\editor} are more complex than the other commands.
+%D Their argument lists have this form:
+%D
+%D \type{\author[junior]{firstnames}[inits]{von}{surname}}
+%D
+%D (bracketed stuff is optional)
+%D
+%D And not only that, but there also might be more than one of each of
+%D these commands. This is why a special command is needed to insert
+%D them, as well as one extra counter for each command.
+
+% todo: instead of \getvalue{bla@num} in specs we should do
+% \bibentrynum{bla} so that we can create a better namespace
+
+%D All of these \type{\@EA}'s and \type{\csnames} make this code
+%D look far more complex than it really is. For example, the argument
+%D \type{author} defines the macro \type{\bib@author} to do two
+%D things: increment the counter \type{\author@num} (let's say to 2)
+%D and next store it's arguments in the macro \type{\@@pb@author2}.
+%D And it defines \type{\bibinsertauthors} to expand into
+%D \starttyping
+%D \specialbibinsert{author}{\author@num}{}{}{}
+%D \stoptyping
+
+% \def\docomplexbibdef#1%
+% {\def\currentype{#1}%
+% \dosingleempty\dodocomplexbibdef}
+
+% \def\dodocomplexbibdef[#1]#2%
+% {\def\firstarg{#1}\def\secondarg{#2}%
+% \dosingleempty\dododocomplexbibdef}
+
+% \def\dododocomplexbibdef[#1]#2#3%
+% {\@EA\increment\csname\currentype @num\endcsname
+% \setevalue{\??pb @\currentype\csname \currentype @num\endcsname}%
+% {{\secondarg}{#2}{#3}{#1}{\firstarg}}\ignorespaces}
+
+\def\docomplexbibdef#1%
+ {\dodoubleempty\dodocomplexbibdef[#1]}
+
+\def\dodocomplexbibdef[#1][#2]#3%
+ {\doquadrupleempty\dododocomplexbibdef[#1][#2][#3]}
+
+\def\dododocomplexbibdef[#1][#2][#3][#4]#5#6%
+ {\@EA\increment\csname#1@num\endcsname % todo: bib in name
+ \setevalue{\??pb @#1\csname#1@num\endcsname}{{#3}{#5}{#6}{#4}{#2}}\ignorespaces}
+
+\def\complexbibdef#1%
+ {\@EA\newcounter\csname #1@num\endcsname
+ \@EA\def\csname bib@#1\endcsname{\docomplexbibdef{#1}}%
+ \expandafter \appendtoks
+ \expandafter\let\csname insert#1s\expandafter\endcsname\csname bibinsert#1s\endcsname
+ \to \initializebibdefinitions
+ \@EA\def\csname bibinsert#1s\endcsname##1##2##3{\specialbibinsert{#1}{\csname #1@num\endcsname}{##1}{\unskip ##2}{##3}}}
+
+\processcommalist[author,artauthor,editor]\complexbibdef
+
+%D Another level of indirection is needed to control the
+%D typesetting of all of these arguments.
+
+\newcount\etallimitcounter
+\newcount\etaldisplaycounter
+\newcount\todocounter
+
+\def\specialbibinsert#1#2#3#4#5%
+ {\bgroup
+ \ifnum#2>\zerocount
+ \etallimitcounter =0\bibalternative{#1etallimit}\relax
+ \etaldisplaycounter=0\bibalternative{#1etaldisplay}\relax
+ \ifnum #2>\etallimitcounter
+ \todocounter\etaldisplaycounter
+ % just in case ...
+ \ifnum\todocounter>\etallimitcounter
+ \todocounter\etallimitcounter
+ \fi
+ \else
+ \todocounter#2\relax
+ \fi
+ \ifnum\todocounter>\zerocount
+ % find the current author list
+ \let\templist\empty
+ \dorecurse{#2}
+ {\scratchtoks\@EA\@EA\@EA{\csname\??pb @#1\recurselevel\endcsname}%
+ \edef\templist{\ifx\templist\empty\else\templist,\fi\the\scratchtoks}}%
+ #3\publicationlistparameter\c!command{#1}{\todocounter}{\templist}#4\relax
+ \else
+ #5%
+ \fi
+ \else
+ #5%
+ \fi
+ \egroup}
+
+%D This macro does the hard work of inserting a list of people in the
+%D output, with proper regard of all the inbetween strings that can
+%D arise depending on length of the list of people.
+
+%D \#1 = type
+%D \#2 = number of items to be typeset
+%D \#3 = commacommand containing authors
+
+% \def\dospecialbibinsert#1#2#3%
+% {\getcommacommandsize[#3]%
+% \scratchcounter\zerocount
+% \def\processauthoritem##1%
+% {\advance\scratchcounter\plusone
+% \ifnum\numexpr\scratchcounter-\plusone\relax<#2\relax
+% \publicationlistparameter{#1}##1%
+% \ifnum\scratchcounter=#2\relax
+% \ifnum\etallimitcounter<\commalistsize\relax
+% \bibalternative{#1etaltext}%
+% \fi
+% \else\ifnum\numexpr\scratchcounter+\plusone\relax=#2\relax
+% \ifnum\commalistsize>\plustwo
+% \bibalternative\c!finalnamesep
+% \else
+% \bibalternative\c!lastnamesep
+% \fi
+% \else
+% \bibalternative\c!namesep
+% \fi\fi
+% \fi}%
+% \processcommacommand[#3]\processauthoritem}
+
+\def\doprocessauthoritem#1#2#3%
+ {\advance\scratchcounter\plusone
+ \ifnum\numexpr\scratchcounter-\plusone\relax<#2\relax
+ \publicationlistparameter{#1}#3%
+ \ifnum\scratchcounter=#2\relax
+ \ifnum\etallimitcounter<\commalistsize\relax
+ \bibalternative{#1etaltext}%
+ \fi
+ \else\ifnum\numexpr\scratchcounter+\plusone\relax=#2\relax
+ \ifnum\commalistsize>\plustwo
+ \bibalternative\c!finalnamesep
+ \else
+ \bibalternative\c!lastnamesep
+ \fi
+ \else
+ \bibalternative\c!namesep
+ \fi\fi
+ \fi}
+
+\def\dospecialbibinsert#1#2#3%
+ {\getcommacommandsize[#3]%
+ \scratchcounter\zerocount
+ \processcommacommand[#3]{\doprocessauthoritem{#1}{#2}}}
+
+%D \macros{invertedauthor,normalauthor,invertedshortauthor,normalshortauthor}
+%D
+%D Just some commands that can be used in \type{\setuppublicationparameters}
+%D If you want to write an extension to the styles, you might
+%D as well define some of these commands yourself.
+%D
+%D The argument list has been reordered here, and the meanings
+%D are:
+%D
+%D \startlines
+%D \type{#1} firstnames
+%D \type{#2} von
+%D \type{#3} surname
+%D \type{#4} inits
+%D \type{#5} junior
+%D \stoplines
+
+\def\normalauthor#1#2#3#4#5%
+ {\bibdoif{#1}{#1\bibalternative\c!firstnamesep}%
+ \bibdoif{#2}{#2\bibalternative\c!vonsep}%
+ #3%
+ \bibdoif{#5}{\bibalternative\c!surnamesep#5\unskip}}
+
+\def\normalshortauthor#1#2#3#4#5%
+ {\bibdoif{#4}{#4\bibalternative\c!firstnamesep}%
+ \bibdoif{#2}{#2\bibalternative\c!vonsep}%
+ #3%
+ \bibdoif{#5}{\bibalternative\c!surnamesep#5\unskip}}
+
+\def\invertedauthor#1#2#3#4#5%
+ {\bibdoif{#2}{#2\bibalternative\c!vonsep}%
+ #3%
+ \bibdoif{#5}{\bibalternative\c!juniorsep#5}%
+ \bibdoif{#1}{\bibalternative\c!surnamesep#1\unskip}}
+
+\def\invertedshortauthor#1#2#3#4#5%
+ {\bibdoif{#2}{#2\bibalternative\c!vonsep}%
+ #3%
+ \bibdoif{#5}{\bibalternative\c!juniorsep#5}%
+ \bibdoif{#4}{\bibalternative\c!surnamesep#4\unskip}}
+
+%D \macros{clearbibitem,clearbibitemtwo,bibitemdefs}
+%D
+%D These are used in \type{\typesetapublication} to do
+%D initializations and cleanups.
+
+\def\clearbibitem#1{\setvalue{\??pb @#1}{}}%
+
+% \def\clearbibitemtwo#1%
+% {\letvalue{#1@num}\!!zerocount
+% \doloop
+% {\doifdefinedelse{\??pb @#1\recurselevel}
+% {\letvalue{\??pb @#1\recurselevel}\empty} % why not undefined?
+% {\exitloop}}}
+
+% \def\clearbibitemtwo#1%
+% {\letvalue{#1@num}\!!zerocount
+% \doloop
+% {\ifcsname\??pb @#1\recurselevel\endcsname
+% \expandafter\let\csname\??pb @#1\recurselevel\undefined
+% \else
+% \exitloop
+% \fi}}
+
+\def\clearbibitemtwo#1% is this reset really needed? after all we reset the counter and we are local
+ {%\dofastrecurse\plusone{\csname#1@num\endcsname}\plusone{\expandafter\let\csname\??pb @#1\recurselevel\undefined}%
+ \letvalue{#1@num}\!!zerocount}
+
+\def\bibitemdefs#1%
+ {\@EA\let\csname#1\expandafter\endcsname\csname bib@#1\endcsname}
+
+\def\presetbibvariables % make a fast resetter (toks)
+ {\processcommacommand[\bibcommandlist,crossref]\clearbibitem
+ \processcommalist [artauthor,author,editor]\clearbibitemtwo
+ \processcommacommand[\bibcommandlist]\bibitemdefs
+ \processcommalist [artauthor,author,editor,crossref]\bibitemdefs}
+
+%D \macros{startpublication}
+%D
+%D We are coming to the end of this module, to the macros that
+%D do typesetting and read the \type{bbl} file.
+
+\newcount\bibtexcounter
+
+%D Just a \type{\dosingleempty} is the most friendly
+%D of doing this: there need not even be an argument
+%D to \type{\startpublication}. Of course, then there
+%D is no key either, and it had better be an
+%D article (otherwise the layout will be all screwed up).
+%D
+%D Only specifying the key in the argument is also
+%D legal. In storing this stuff into macros, some trickery with
+%D token registers is needed to fix the expansion problems. Even so,
+%D this appears to not always be 100\% safe, so people are
+%D urgently advised to use \ETEX\ instead of traditional \TEX.
+%D
+%D In \ETEX, all expansion problems are conveniently solved by
+%D the primitive \type{\protected}. To put that another way:
+%D
+%D It's not a bug in this module if it does not appear in \ETEX!
+%D
+%D Now prohibits comments, so % can be used for urls
+
+\unexpanded\def\startpublication
+ {\begingroup
+ \catcode`\%=\othercatcode
+ \dosingleempty\dostartpublication}
+
+\let\stoppublication\relax
+
+% this is rather memory hungry; some day i will rewrite this so that
+% we use the database instead
+
+%D \macros{doifbibreferencefoundelse}
+%D
+%D Some macros to fetch the information provided by
+%D \type{\startpublication}.
+
+% we can consider a faster variant in the bbl file; we can also consider
+% storing the keys in lua (and then do more in lua) and use calls to
+% fetch the variables
+
+% hm, we can store at the lua end ...
+
+\long\def\dostartpublication[#1]#2\stoppublication
+ {\doifassignmentelse{#1}%
+ {\getparameters[\??pb][k=\s!unknown,t=article,n=,s=,a=,y=,o=,u=,#1]}%
+ {\getparameters[\??pb][k=#1,t=article,n=,s=,a=,y=,o=,u=]}%
+ \ctxlua{bibtex.hacks.register("\@@pbk")}%
+ \setxvalue{pbd:\@@pbk}##1{\noexpand\ifcase##1\noexpand\or
+ \@@pbk\noexpand\or
+ \@@pba\noexpand\or
+ \@@pby\noexpand\or
+ \@@pbs\noexpand\or
+ \@@pbn\noexpand\or
+ \@@pbt\noexpand\or
+ \@@pbo\noexpand\or
+ \@@pbu\noexpand\or
+ \normalunexpanded{#2}\noexpand\fi}%
+ \endgroup
+ \ignorespaces}
+
+\def\bibgetvark#1{\csname pbd:#1\endcsname\plusone }
+\def\bibgetvara#1{\csname pbd:#1\endcsname\plustwo }
+\def\bibgetvary#1{\csname pbd:#1\endcsname\plusthree}
+\def\bibgetvars#1{\csname pbd:#1\endcsname\plusfour }
+\def\bibgetvarn#1{\csname pbd:#1\endcsname\plusfive }
+\def\bibgetvart#1{\csname pbd:#1\endcsname\plussix }
+\def\bibgetvaro#1{\csname pbd:#1\endcsname\plusseven}
+\def\bibgetvaru#1{\csname pbd:#1\endcsname\pluseight}
+\def\bibgetvard#1{\csname pbd:#1\endcsname\plusnine }
+
+\def\doifbibreferencefoundelse#1%
+ {\preloadbiblist
+ \doifdefinedelse{pbd:#1}
+ \firstoftwoarguments
+ {\showmessage\m!publications{5}{#1 is unknown}\secondoftwoarguments}}
+
+%D \macros{bib@crossref}
+%D
+%D \type{\crossref} is used in database files to point to another
+%D entry. Because of this special situation, it has to be defined
+%D separately. Since this command will not be seen until at
+%D \type{\placepublications}, it may force extra runs. The same is
+%D true for \type{\cite} commands inside of publications.
+
+% used in bib self
+
+\def\bib@crossref#1% called via \csname \endcsname
+ {\setvalue{\??pb @crossref}{#1}\ignorespaces}
+
+\def\bibinsertcrossref#1#2#3%
+ {\bibdoifelse\@@pb@crossref{#1\cite[\@@pb@crossref]#2}{#3}}
+
+\appendtoks\let\insertcrossref\bibinsertcrossref\to\initializebibdefinitions
+
+%D The next macro is needed because the number command of the
+%D publist sometimes needs to fetch something from the current
+%D item (like the 'short' key). For this, the ID of the current
+%D item is passed in the implict parameter \type{\currentpublicationkey}
+
+\def\doprocessbibtexentry#1{\typesetapublication{#1}}
+
+\def\typesetpubslist
+ {\dobeginoflist
+ % \the\initializebibdefinitions % COMMENTED
+ \edef\currentlist{pubs}%
+ \doif{\listparameter\c!criterium}\v!cite{\setuplist[pubs][\c!criterium=\v!here]}%
+ \ctxlua{bibtex.hacks.reset(\number\bibtexoncemode)}%
+ \placestructurelist{pubs}{\listparameter\c!criterium}{\listparameter\c!number}%
+ \ctxlua{bibtex.hacks.flush("\@@pbsorttype")}%
+ \doendoflist}
+
+\newif\ifinpublist
+
+\def\initializepubslist
+ {\def\currentlist{pubs}%
+ \edef\@@pbnumbering{\@@pbnumbering}%
+ \doifelse\@@pbautohang\v!yes
+ {\ifx\@@pbnumbering\v!short
+ \setbox\scratchbox\hbox{\@@pbnumbercommand{\listparameter\c!samplesize}}%
+ \else
+ \setbox\scratchbox\hbox{\@@pbnumbercommand{\ctxlua{tex.write(structure.lists.size())}}}%
+ \fi
+ \edef\publistnumberbox{\hbox to \the\wd\scratchbox}%
+ \expanded{\setuplist[pubs][\c!width=\the\wd\scratchbox,\c!distance=\zeropoint]}%
+ \ifx\@@pbnumbering\v!short
+ \def\@@pblimitednumber##1{\publistnumberbox{\@@pbnumbercommand{\bibgetvars\currentpublicationkey}}}%
+ \else\ifx\@@pbnumbering\v!bib
+ \def\@@pblimitednumber##1{\publistnumberbox{\@@pbnumbercommand{\bibgetvarn\currentpublicationkey}}}%
+ \else
+ \def\@@pblimitednumber##1{\publistnumberbox{\@@pbnumbercommand{##1}}}%
+ \fi\fi}
+ {\doifelsenothing{\listparameter\c!width}
+ {\let \publistnumberbox \hbox}
+ {\edef\publistnumberbox{\hbox to \listparameter\c!width}}%
+ \ifx\@@pbnumbering\v!short
+ \def\@@pblimitednumber##1{\publistnumberbox{\@@pbnumbercommand{\bibgetvars\currentpublicationkey}}}%
+ \else\ifx\@@pbnumbering\v!bib
+ \def\@@pblimitednumber##1{\publistnumberbox{\@@pbnumbercommand{\bibgetvarn\currentpublicationkey}}}%
+ \else
+ \def\@@pblimitednumber##1{\publistnumberbox{\@@pbnumbercommand{##1}}}%
+ \fi\fi}%
+ \ifx\@@pbnumbering\v!no
+ \setuplist[pubs][\c!numbercommand=,\c!symbol=\v!none,\c!textcommand=\outdented]%
+ \else
+ \setuplist[pubs][\c!numbercommand=\@@pblimitednumber]%
+ \fi
+ \doifelse{\publicationlistparameter\c!maybeyear}{\v!off}{\def\maybeyear##1{}}{\def\maybeyear##1{##1}}%
+ \forgetall}
+
+\def\outdented#1% move to supp-box ?
+ {\hskip-\hangindent#1\relax}
+
+%D The full list of publications
+
+\def\completepublications
+ {\dosingleempty\docompletepublications}
+
+\def\docompletepublications[#1]%
+ {\begingroup
+ \setuplist[pubs][\c!criterium=\v!previous,#1]
+ \doifelsenothing{\publicationlistparameter\c!title}
+ {\systemsuppliedchapter[pubs]{\headtext{pubs}}}
+ {\normalexpanded{\systemsuppliedchapter[pubs]{\publicationlistparameter\c!title}}}%
+ \dodoplacepublications}
+
+%D And the portion with the entries only.
+
+\def\bibrefprefix{\number\bibtexblock:}
+
+\unexpanded\def\placepublications
+ {\dosingleempty\doplacepublications}
+
+\def\doplacepublications[#1]%
+ {\begingroup
+ \setuplist[pubs][\c!criterium=\v!previous,#1]%
+ \dodoplacepublications}
+
+\def\dodoplacepublications
+ {\determinelistcharacteristics[pubs]%
+ \initializepubslist
+ \doifnot{\namedlistparameter{pubs}\c!option}\v!continue
+ {\global\bibtexcounter\zerocount}%
+ \inpublisttrue
+ \typesetpubslist
+ \inpublistfalse
+ \endgroup
+ \global\advance\bibtexblock\plusone}
+
+%D \subsubject{What's in a publication}
+
+\unexpanded\def\typesetapublication#1%
+ {\doifsomething{#1}
+ {\doifelse{\namedlistparameter{pubs}\c!criterium}\v!all
+ {\doplacepublicationindeed{#1}}%
+ {\ctxlua{bibtex.hacks.doifalreadyplaced("#1")}
+ {}
+ {\doplacepublicationindeed{#1}}}%
+ }}
+
+% for the moment we don't access the data directly but we will do that
+% later when we get away from storing the data and only deal with
+% references
+
+% we'll define proper handlers later
+
+\def\doplacepublicationindeed#1%
+ {\doifbibreferencefoundelse{#1}
+ {\global\advance\bibtexcounter\plusone
+ \def\currentpublicationkey{#1}%
+ \ctxlua{bibtex.hacks.registerplaced("#1")}%
+ \dodolistelement
+ {pubs}%
+ {}%
+ {\number\bibtexcounter}%
+ {\expanded{\reference[\bibrefprefix#1]{\number\bibtexcounter}}%
+ \strut\dotypesetapublication{#1}\strut}%
+ {}%
+ {}}
+ {}} % invalid
+
+\def\dotypesetapublication#1%
+ {\bgroup
+ \the\initializebibdefinitions % NEW
+ \def\@@currentalternative{:l:}%
+ \presetbibvariables
+ \let\biblanguage\empty
+ \ignorespaces
+ \bibgetvard{#1}%
+ \removeunwantedspaces
+ \ignorespaces
+ \bibalternative{\bibgetvart{#1}}%
+ \removeunwantedspaces
+ \egroup}
+
+%D An few afterthoughts:
+
+\let\maybeyear\gobbleoneargument
+\let\noopsort \gobbleoneargument
+
+%D This is the result of bibtex's `language' field.
+
+\def\setbiblanguage#1#2{\setvalue{\??pb\s!language#1}{#2}}
+
+\def\lang#1%
+ {\edef\biblanguage{#1}%
+ \ifcsname\??pb\s!language#1\endcsname
+ \language[\getvalue{\??pb\s!language#1}]%
+ \fi
+ \ignorespaces}
+
+%D \subject{Citations}
+
+%D \macros{cite,bibref}
+%D
+%D The indirection with \type{\dobibref} allows \LATEX\ style
+%D \type{\cite} commands with a braced argument (these might appear
+%D in included data from the \type{.bib} file).
+
+% \unexpanded\def\cite
+% {\doifnextoptionalelse\dodocite\dobibref}
+% \def\dobibref#1%
+% {\docite[#1][]}
+% \def\dodocite[#1]%
+% {\startstrictinspectnextcharacter
+% \dodoubleempty\dododocite[#1]}
+% \def\dododocite % [#1][#2]
+% {\stopstrictinspectnextcharacter
+% \docite}
+
+\unexpanded\def\cite
+ {\strictdoifnextoptionalelse\dodocite\dobibref}
+
+\def\dobibref#1%
+ {\docite[#1][]}
+
+\def\dodocite[#1]%
+ {\strictdoifnextoptionalelse{\docite[#1]}{\docite[#1][]}}
+
+\def\docite[#1][#2]%
+ {\begingroup
+ \doifelsenothing{#2}\secondargumentfalse\secondargumenttrue
+ \ifsecondargument
+ \dowhatevercite{#1}{#2}%
+ \else
+ \donumberedcite{#1}%
+ \fi
+ \endgroup}
+
+\def\dowhatevercite#1#2%
+ {\processcommalist[#2]\docitation
+ \setupinteraction[\c!style=]%
+ \doifassignmentelse
+ {#1}%
+ {\getparameters[LO][\c!alternative=,\c!extras=,#1]%
+ \edef\@@currentalternative{\LOalternative}%
+ \ifx\@@currentalternative\empty
+ \edef\@@currentalternative{\@@citedefault}%
+ \fi
+ \ifx\LOextras\empty
+ \setupcite[\@@currentalternative][#1]%
+ \else
+ \expandafter\ifx\csname LOright\endcsname \relax
+ \edef\LOextras{{\LOextras\bibalternative\c!right}}%
+ \else
+ \edef\LOextras{{\LOextras\LOright}}%
+ \fi
+ \expanded{\setupcite[\@@currentalternative][#1,\c!right=\LOextras]}%
+ \fi}%
+ {\def\@@currentalternative{#1}}%
+ \doifelsevalue{@@pv\@@currentalternative\c!compress}\v!no\bibcitecompressfalse\bibcitecompresstrue
+ \getvalue{bib\@@currentalternative ref}[#2]}
+
+\def\donumberedcite#1%
+ {\processcommalist[#1]\docitation
+ \setupinteraction[\c!style=]%
+ \edef\@@currentalternative{\@@citedefault}%
+ \doifelsevalue{@@pv\@@currentalternative\c!compress}\v!no\bibcitecompressfalse\bibcitecompresstrue
+ \getvalue{bib\@@citedefault ref}[#1]}
+
+%D \macros{nocite}
+
+\def\nocite[#1]%
+ {\processcommalist[#1]\docitation}
+
+%D \macros{setupcite}
+
+\unexpanded\def\setupcite{\dodoubleempty\dosetupcite}
+
+\def\dosetupcite[#1][#2]%
+ {\ifsecondargument
+ \def\dodosetupcite##1{\getparameters[\??pv##1][#2]}%
+ \processcommalist[#1]\dodosetupcite
+ \else % default case
+ \getparameters[\??pv\@@citedefault][#1]%
+ \fi}
+
+%D Low-level stuff
+
+\def\getcitedata#1[#2]#3[#4]#5to#6%
+ {\bgroup
+ \dofetchapublication{#4}%
+ \doifdefinedelse{\??pb @bib#2}%
+ {\xdef#6{\getvalue{\??pb @bib#2}}}%
+ {\xdef#6{\getvalue{\??pb @#2}}}%
+ \egroup}
+
+\def\dofetchapublication#1%
+ {\def\currentpublicationkey{#1}%
+ \presetbibvariables
+ \ignorespaces\bibgetvard{#1}}
+
+\def\docitation#1%
+ {\iftrialtypesetting \else
+ \expanded{\writedatatolist[pubs][bibref=#1]}%
+ \fi}
+
+\let\addthisref\gobbleoneargument % keep this for compatibility
+
+%D \macros{ixbibauthoryear,thebibauthors,thebibyears}
+%D
+%D If compression of \type{\cite}'s argument expansion is on,
+%D the macros that deal with authors and years call this internal
+%D command to do the actual typesetting.
+%D
+%D Two entries with same author but with different years may
+%D be condensed into ``Author (year1,year2)''. This is about the
+%D only optimization that makes sense for the (author,year)
+%D style of citations (years within one author have to be unique
+%D anyway so no need to test for that, and ``Author1, Author2 (year)''
+%D creates more confusion than it does good).
+%D
+%D In the code below,
+%D the macro \type{\thebibauthors} holds the names of the alternative
+%D author info fields for the current list. This is a commalist,
+%D and \type{\thebibyears} holds the (collection of) year(s) that go with
+%D this author (possibly as a nested commalist).
+%D
+%D There had better be an author for all cases, but there
+%D does not have to be year info always. \type{\thebibyears} is
+%D pre-initialized because this makes the insertion macros simpler.
+%D
+%D In `normal' \TeX, of course there are expansion problems again.
+
+\def\ixbibauthoryear#1#2#3#4%
+ {\bgroup
+ \gdef\ixlastcommand {#4}%
+ \gdef\ixsecondcommand{#3}%
+ \gdef\ixfirstcommand {#2}%
+ \glet\thebibauthors \empty
+ \glet\thebibyears \empty
+ \getcommalistsize[#1]%
+ \ifbibcitecompress
+ \dorecurse\commalistsize{\xdef\thebibyears{\thebibyears,}}%
+ \processcommalist[#1]\docompressbibauthoryear
+ \else
+ \processcommalist[#1]\donormalbibauthoryear
+ \fi
+ \egroup
+ \dobibauthoryear}
+
+%D \macros{dodobibauthoryear}
+%D
+%D This macro only has to make sure that the lists
+%D \type{\thebibauthors} and \type{\thebibyears} are printed.
+
+\def\dobibauthoryear
+ {\scratchcounter\zerocount
+ \getcommacommandsize[\thebibauthors]%
+ \edef\authorcount{\commalistsize}%
+ \@EA\processcommalist\@EA[\thebibauthors]\dodobibauthoryear}
+
+\def\dodobibauthoryear#1%
+ {\advance\scratchcounter\plusone
+ \edef\wantednumber{\the\scratchcounter}%
+ \getfromcommacommand[\thebibyears][\wantednumber]%
+ \@EA\def\@EA\currentbibyear\@EA{\commalistelement}%
+ \setcurrentbibauthor{#1}%
+ \ifnum\scratchcounter=\plusone
+ \ixfirstcommand
+ \else\ifnum \scratchcounter=\authorcount\relax
+ \ixlastcommand
+ \else
+ \ixsecondcommand
+ \fi\fi}
+
+\def\setcurrentbibauthor#1%
+ {\getcommacommandsize[#1]%
+ \ifcase\commalistsize
+ % anonymous?
+ \let\currentbibauthor\empty
+ \or
+ \def\currentbibauthor{#1}%
+ \or
+ \expanded{\docurrentbibauthor#1}%
+ \else
+ \handlemultiplebibauthors{\commalistsize}{#1}%
+ \fi}
+
+\newcount\citescratchcounter
+
+\def\handlemultiplebibauthors#1#2%
+ {\citescratchcounter\zerocount
+ \let\currentbibauthor\empty
+ \def\bibprocessauthoritem##1%
+ {\advance\citescratchcounter\plusone
+ \ifnum \citescratchcounter=#1\relax
+ \edef\currentbibauthor{\currentbibauthor##1}%
+ \else\ifnum\numexpr\citescratchcounter+\plusone\relax=#1\relax
+ \edef\currentbibauthor{\currentbibauthor##1\bibalternative{andtext}}%
+ \else
+ \edef\currentbibauthor{\currentbibauthor##1\bibalternative{namesep}}%
+ \fi\fi}%
+ \processcommalist[#2]\bibprocessauthoritem}
+
+\setupcite
+ [author,authoryear,authoryears]
+ [\c!namesep={, }]
+
+%D This discovery of authoretallimit is not the best one,
+%D but it will do for now.
+
+\def\docurrentbibauthor#1,#2%
+ {\doifemptyelse{#2}
+ {\def\currentbibauthor{#1\bibalternative{otherstext}}}
+ {\@EA\ifx\csname\??pv\@@currentalternative authoretallimit\endcsname\relax
+ \edef\currentbibauthor{#1\bibalternative{andtext}#2}%
+ \else
+ \edef\currentbibauthor{#1%
+ \ifcase0\bibalternative{authoretallimit}\relax\or
+ \bibalternative{otherstext}\else\bibalternative{andtext}#2\fi}%
+ \fi}}
+
+%D This is not the one Hans made for me, because I need a global
+%D edef, and the \type{\robustdoifinsetelse} doesn't listen to
+%D \type{\doglobal }
+
+\def\robustaddtocommalist#1#2% {item} \cs
+ {\robustdoifinsetelse{#1}#2\resetglobal
+ {\dodoglobal\xdef#2{\ifx#2\empty\else#2,\fi#1}}}
+
+%D \macros{donormalbibauthoryear}
+%D
+%D Now we get to the macros that fill the two lists.
+%D The `simple' one really is quite simple.
+
+\def\donormalbibauthoryear#1%
+ {\def\myauthor{Xxxxxxxxxx}%
+ \def\myyear{0000}%
+ \doifbibreferencefoundelse{#1}
+ {\def\myauthor{{\bibgetvara{#1}}}%
+ \def\myyear {\bibgetvary{#1}}}%
+ {}%
+ \@EA\doglobal\@EA\appendtocommalist\@EA{\myauthor}\thebibauthors
+ \@EA\doglobal\@EA\appendtocommalist\@EA{\myyear }\thebibyears}
+
+%D \macros{docompressbibauthoryear}
+%D
+%D So much for the easy parts. Nothing at all will be done if
+%D the reference is not found or the reference does not contain
+%D author data. No questions marks o.s.s. (to be fixed later)
+
+\def\docompressbibauthoryear#1%
+ {\def\myauthor{Xxxxxxxxxx}%
+ \def\myyear {0000}%
+ \doifbibreferencefoundelse{#1}
+ {\xdef\myauthor{\bibgetvara{#1}}%
+ \xdef\myyear {\bibgetvary{#1}}}
+ {}%
+ \ifx\myauthor\empty\else
+ \checkifmyauthoralreadyexists
+ \findmatchingyear
+ \fi}
+
+%D two temporary counters. One of these two can possibly be replaced
+%D by \type{\scratchcounter}.
+
+\newcount\bibitemcounter
+\newcount\bibitemwanted
+
+%D The first portion is simple enough: if this is the very first author
+%D it is quite straightforward to add it. \type{\bibitemcounter} and
+%D \type{\bibitemwanted} are needed later to insert the year
+%D information in the correct item of \type{\thebibyears}
+
+\def\checkifmyauthoralreadyexists
+ {\doifemptyelsevalue{thebibauthors}
+ {\global\bibitemwanted \plusone
+ \global\bibitemcounter\plusone
+ \xdef\thebibauthors{{\myauthor}}}
+ {% the next weirdness is because according to \getcommalistsize,
+ % the length of \type{[{{},{}}]} is 2.
+ \@EA\getcommalistsize\@EA[\thebibauthors,]%
+ \global\bibitemcounter\numexpr\commalistsize+\minusone\relax
+ \global\bibitemwanted \zerocount
+ \processcommacommand[\thebibauthors]\docomparemyauthor}}
+
+%D The outer \type{\ifnum} accomplishes the addition of
+%D a new author to \type{\thebibauthors}. The messing about with
+%D the two counters is again to make sure that \type{\thebibyears}
+%D will be updated correctly.If the author {\it was} found,
+%D the counters will stay at their present values and everything
+%D will be setup properly to insert the year info.
+
+\def\docomparemyauthor#1%
+ {\global\advance\bibitemwanted \plusone
+ \def\mytempc{#1}%
+ \ifx\mytempc\myauthor
+ \quitcommalist
+ \else\ifnum\bibitemwanted=\bibitemcounter\relax
+ \global\advance\bibitemwanted \plusone
+ \global\bibitemcounter\bibitemwanted\relax
+ \@EA\doglobal\@EA\robustaddtocommalist\@EA{{\myauthor}}\thebibauthors
+ \fi\fi}
+
+%D This macro should be clear now.
+
+\def\findmatchingyear
+ {\edef\wantednumber{\the\bibitemwanted}%
+ \getfromcommacommand[\thebibyears][\wantednumber]%
+ \ifx\commalistelement\empty
+ \edef\myyear{{\myyear}}%
+ \else
+ \edef\myyear{{\commalistelement,\myyear}}%
+ \fi
+ \edef\newcommalistelement{\myyear}%
+ \doglobal\replaceincommalist \thebibyears \wantednumber}
+
+%D \macros{gotobiblink,inbiblink,atbiblink}
+%D
+%D The final task is looping over that list until a match is found.
+
+\def\gotobiblink#1[#2]{\doifreferencefoundelse{\bibrefprefix#2}{\goto{#1}[\bibrefprefix#2]}{\unknownreference{#2}}}
+\def\atbiblink [#1]{\doifreferencefoundelse{\bibrefprefix#1}{\at [\bibrefprefix#1]}{\unknownreference{#1}}}
+\def\inbiblink [#1]{\doifreferencefoundelse{\bibrefprefix#1}{\expanded{\goto{\currentreferencetext}}[\bibrefprefix#1]}{\unknownreference{#1}}}
+
+%D \macros{bibauthoryearref,bibauthoryearsref,bibauthorref,bibyearref}
+%D
+%D Now that all the hard work has been done, these are simple.
+%D \type{\ixbibauthoryearref} stores the data in the macros
+%D \type{\currentbibauthor} and \type{\currentbibyear}.
+
+\def\ifbibinteractionelse
+ {\iflocation
+ \edef\test{\bibalternative\c!interaction}%
+ \ifx\test\v!stop
+ \@EA\@EA\@EA\secondoftwoarguments
+ \else
+ \@EA\@EA\@EA\firstoftwoarguments
+ \fi
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\def\ifbibinteractionelse
+ {\iflocation
+ \doifelse{\bibalternative\c!interaction}\v!stop
+ {\@EA\secondoftwoarguments}
+ {\@EA\firstoftwoarguments}%
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\def\bibmaybeinteractive#1#2%
+ {\ifbibcitecompress
+ #2%
+ \else
+ \ifbibinteractionelse{\gotobiblink{#2}[#1]}{#2}%
+ \fi}
+
+\def\bibauthoryearref[#1]%
+ {\ixbibauthoryear{#1}%
+ {\bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween
+ \bibalternative\v!left{\currentbibyear}\bibalternative\v!right}}
+ {\bibalternative\c!pubsep
+ \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween
+ \bibalternative\v!left {\currentbibyear}\bibalternative\v!right}}
+ {\bibalternative\c!lastpubsep
+ \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween
+ \bibalternative\v!left {\currentbibyear}\bibalternative\v!right}}}
+
+\def\bibauthoryearsref[#1]%
+ {\bibalternative\v!left
+ \ixbibauthoryear{#1}
+ {\bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween{\currentbibyear}}}
+ {\bibalternative\c!pubsep
+ \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween{\currentbibyear}}}
+ {\bibalternative\c!lastpubsep
+ \bibmaybeinteractive{#1}{{\currentbibauthor}\bibalternative\c!inbetween{\currentbibyear}}}%
+ \bibalternative\v!right}
+
+\def\bibauthorref[#1]%
+ {\bibalternative\v!left
+ \ixbibauthoryear{#1}%
+ {\bibmaybeinteractive{#1}{{\currentbibauthor}}}
+ {\bibalternative\c!pubsep \bibmaybeinteractive{#1}{{\currentbibauthor}}}
+ {\bibalternative\c!lastpubsep\bibmaybeinteractive{#1}{{\currentbibauthor}}}%
+ \bibalternative\v!right}
+
+\def\bibyearref[#1]%
+ {\bibalternative\v!left
+ \ixbibauthoryear{#1}%
+ {\bibmaybeinteractive{#1}{{\currentbibyear}}}
+ {\bibalternative\c!pubsep \bibmaybeinteractive{#1}{{\currentbibyear}}}
+ {\bibalternative\c!lastpubsep\bibmaybeinteractive{#1}{{\currentbibyear}}}%
+ \bibalternative\v!right}
+
+%D \macros{bibshortref,bibkeyref,bibpageref,bibtyperef,bibserialref}
+%D
+%D There is hardly any point in trying to compress these. The only
+%D thing that needs to be done is making sure that
+%D the separations are inserted correctly. And that is
+%D what \type{\bibinsertrefsep} does.
+
+\newconditional\firstbibrefsep
+
+\def\bibresetrefsep
+ {\settrue\firstbibrefsep}
+
+\def\bibinsertrefsep
+ {\ifconditional\firstbibrefsep
+ \setfalse\firstbibrefsep
+ \else
+ \bibalternative\c!pubsep
+ \fi}
+
+\def\bibshortref[#1]%
+ {\bibalternative\v!left
+ \bibresetrefsep\processcommalist[#1]\dobibshortref
+ \bibalternative\v!right}
+
+\def\dobibshortref#1%
+ {\bibinsertrefsep
+ \doifbibreferencefoundelse{#1}
+ {\gotobiblink{\bibgetvars{#1}}[#1]}
+ {\unknownreference{#1}}}
+
+\def\bibserialref[#1]%
+ {\bibalternative\v!left
+ \bibresetrefsep\processcommalist[#1]\dobibserialref
+ \bibalternative\v!right}
+
+\def\dobibserialref#1%
+ {\bibinsertrefsep
+ \doifbibreferencefoundelse{#1}
+ {\gotobiblink{\bibgetvarn{#1}}[#1]}
+ {\unknownreference{#1}}}
+
+\def\bibkeyref[#1]%
+ {\bibalternative\v!left
+ \bibresetrefsep\processcommalist[#1]\dobibkeyref
+ \bibalternative\v!right}
+
+\def\dobibkeyref#1%
+ {\bibinsertrefsep
+ \gotobiblink{#1}[#1]}
+
+\def\bibgotoDOI#1#2%
+ {\ifbibinteractionelse
+ {\useURL[bibfooDoi#1][#2]%
+ \useURL[bibfoo#1][http://dx.doi.org/#2]%
+ \goto{\url[bibfooDoi#1]}[url(bibfoo#1)]}
+ {\hyphenatedurl{#2}}}
+
+\def\bibdoiref[#1]%
+ {\bibalternative\v!left
+ \bibresetrefsep\processcommalist[#1]\dobibdoiref
+ \bibalternative\v!right}
+
+\def\dobibdoiref#1%
+ {\bibinsertrefsep
+ \doifbibreferencefoundelse{#1}
+ {\expanded{\bibgotoDOI{#1}{\bibgetvaro{#1}}}}
+ {\unknownreference{#1}}}
+
+\def\biburlref[#1]%
+ {\bibalternative\v!left
+ \bibresetrefsep\processcommalist[#1]\dobiburlref
+ \bibalternative\v!right}
+
+\def\bibgotoURL#1#2%
+ {\ifbibinteractionelse
+ {\useURL[bibfoo#1][#2]\goto{\url[bibfoo#1]}[url(bibfoo#1)]}
+ {\hyphenatedurl{#2}}}
+
+\def\dobiburlref#1%
+ {\bibinsertrefsep
+ \doifbibreferencefoundelse{#1}
+ {\expanded{\bibgotoURL{#1}{\bibgetvaru{#1}}}}
+ {\unknownreference{#1}}}
+
+\def\bibtyperef[#1]%
+ {\bibalternative\v!left
+ \bibresetrefsep\processcommalist[#1]\dobibtyperef
+ \bibalternative\v!right}
+
+\def\dobibtyperef#1%
+ {\bibinsertrefsep
+ \doifbibreferencefoundelse{#1}
+ {\gotobiblink{\bibgetvart{#1}}[#1]}
+ {\unknownreference{#1}}}
+
+\def\bibpageref[#1]%
+ {\bibalternative\v!left
+ \bibresetrefsep\processcommalist[#1]\dobibpageref
+ \bibalternative\v!right}
+
+\def\dobibpageref#1%
+ {\bibinsertrefsep
+ \ifbibinteractionelse
+ {\atbiblink[#1]}
+ {{\referencingfalse\at[#1]}}}
+
+\def\bibdataref[#1]%
+ {\bibalternative\v!left
+ \bibresetrefsep\processcommalist[#1]\dobibdata
+ \bibalternative\v!right}
+
+\def\dobibdata#1%
+ {\bibinsertrefsep
+ \doifbibreferencefoundelse{#1}
+ {\dotypesetapublication{#1}}
+ {\unknownreference{#1}}}
+
+\let\bibnoneref\nocite
+
+%D \macros{bibnumref}
+
+\def\bibnumref[#1]%
+ {\begingroup
+ \bibalternative\v!left
+ \penalty\!!tenthousand
+ \ctxlua{bibtex.hacks.resolve("","\number\bibtexblock","#1")}%
+ \bibalternative\v!right
+ \endgroup}
+
+\def\dowithbibtexnumrefconnector#1#2%
+ {\ifnum#1>\plusone
+ \ifnum#2>\plusone
+ \ifnum#2=#1\relax
+ \bibalternative{lastpubsep}%
+ \else
+ \bibalternative{pubsep}%
+ \fi
+ \fi
+ \fi}
+
+\def\dowithbibtexnumref#1#2#3#4#5% n, i, prefix block ref
+ {\dowithbibtexnumrefconnector{#1}{#2}%
+ \def\bibrefprefix{#4:}%
+ \inbiblink[#5]}
+
+\def\dowithbibtexnumrefrange#1#2#3#4#5#6#7% n, i, prefix block ref
+ {\dowithbibtexnumrefconnector{#1}{#2}%
+ \def\bibrefprefix{#4:}%
+ \inbiblink[#5]%
+ \endash
+ \def\bibrefprefix{#6:}%
+ \inbiblink[#7]}
+
+%D By request from Sanjoy. This makes it easier to implement
+%D \type{\citeasnoun}.
+
+\def\bibauthornumref[#1]%
+ {\getcommalistsize[#1]%
+ \global\bibitemcounter\commalistsize
+ \bibresetrefsep
+ \processcommalist[#1]\dobibauthornumref }
+
+\def\dobibauthornumref#1%
+ {\bibinsertrefsep
+ \doifbibreferencefoundelse{#1}
+ {\begingroup
+ \bibgetvara{#1}%
+ \bibalternative\c!inbetween
+ \setuppublications[\c!refcommand=num]%
+ \cite[#1]%
+ \endgroup}
+ {\unknownreference{#1}}}
+
+%D And some defaults are loaded from bibl-apa:
+
+\def\c!monthconversion{monthconversion} % todo
+
+\setuppublications
+ [\c!monthconversion=,
+ \c!alternative=apa,
+ \c!method=\v!global,
+ \c!refcommand=num,
+ \c!numbercommand=\bibleftnumber]
+
+\def\preloadbiblist
+ {\globallet\preloadbiblist\relax
+ \dousepublications\jobname}
+
+% \appendtoks \preloadbiblist \to \everysetuppublications
+% \appendtoks \preloadbiblist \to \everystarttext
+
+\protect \endinput
diff --git a/tex/context/base/bibl-tst.lua b/tex/context/base/bibl-tst.lua
new file mode 100644
index 000000000..5ff8f4570
--- /dev/null
+++ b/tex/context/base/bibl-tst.lua
@@ -0,0 +1,21 @@
+dofile("bibl-bib.lua")
+
+local session = bibtex.new()
+
+bibtex.load(session,"gut.bib")
+bibtex.load(session,"komoedie.bib")
+bibtex.load(session,"texbook1.bib")
+bibtex.load(session,"texbook2.bib")
+bibtex.load(session,"texbook3.bib")
+bibtex.load(session,"texgraph.bib")
+bibtex.load(session,"texjourn.bib")
+bibtex.load(session,"texnique.bib")
+bibtex.load(session,"tugboat.bib")
+print(bibtex.size,statistics.elapsedtime(bibtex))
+bibtex.toxml(session)
+print(bibtex.size,statistics.elapsedtime(bibtex))
+
+--~ print(table.serialize(session.data))
+--~ print(table.serialize(session.shortcuts))
+--~ print(xml.serialize(session.xml))
+
diff --git a/tex/context/base/blob-ini.lua b/tex/context/base/blob-ini.lua
new file mode 100644
index 000000000..0f7ccee26
--- /dev/null
+++ b/tex/context/base/blob-ini.lua
@@ -0,0 +1,165 @@
+if not modules then modules = { } end modules ['blob-ini'] = {
+ version = 1.001,
+ comment = "companion to blob-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- later we will consider an OO variant.
+
+-- This module is just a playground. Occasionally we need to typeset
+-- at the lua and and this is one method. In principle we can construct
+-- pages this way too which sometimes makes sense in dumb cases. Actually,
+-- if one only needs this, one does not really need tex, okay maybe the
+-- parbuilder but that one can be simplified as well then.
+
+-- set fonts, attributes
+-- rest already done in packers etc
+-- add local par whatsit (or wait till cleaned up)
+-- collapse or new pars
+-- interline spacing etc
+
+-- DON'T USE THESE FUNCTIONS AS THEY WILL CHANGE!
+
+local type = type
+
+local utfvalues = string.utfvalues
+local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
+
+local fontdata = fonts.identifiers
+
+local new_glyph_node = nodes.glyph
+local new_glue_node = nodes.glyph
+
+local copy_node = node.copy
+local copy_node_list = node.copy_list
+local insert_node_after = node.insert_after
+local flush_node_list = node.flush_list
+local hpack_node_list = node.hpack
+local vpack_node_list = node.vpack
+local write_node = node.write
+
+local current_font = font.current
+
+blobs = blobs or { }
+
+local newline = lpegpatterns.newline
+local space = lpegpatterns.spacer
+local spacing = newline * space^0
+local content = (space^1)/" " + (1-spacing)
+
+local ctxtextcapture = lpeg.Ct ( (
+ space^0 * (
+ newline^2 * space^0 * lpeg.Cc("")
+ + newline * space^0 * lpeg.Cc(" ")
+ + lpeg.Cs(content^1)
+ )
+)^0)
+
+local function tonodes(str,fnt,attr) -- (str,template_glyph)
+ if not str or str == "" then
+ return
+ end
+ local head, tail, space, fnt, template = nil, nil, nil, nil, nil
+ if not fnt then
+ fnt = current_font()
+ elseif type(fnt) ~= "number" and fnt.id == "glyph" then
+ fnt, template = nil, fnt
+ -- else
+ -- already a number
+ end
+ for s in utfvalues(str) do
+ local n
+ if s == 32 then
+ if not space then
+ local parameters = fontdata[fnt].parameters
+ space = new_glue_node(parameters.space,parameters.space_stretch,parameters.space_shrink)
+ n = space
+ else
+ n = copy_node(space)
+ end
+ elseif template then
+ n = copy_node(template)
+ n.char = s
+ else
+ n = new_glyph_node(fnt,s)
+ end
+ if attr then -- normall false when template
+ n.attr = copy_node_list(attr)
+ end
+ if head then
+ insert_node_after(head,tail,n)
+ else
+ head = n
+ end
+ tail = n
+ end
+ return head, tail
+end
+
+blobs.tonodes = tonodes
+
+function blobs.new()
+ return {
+ list = { },
+ }
+end
+
+function blobs.append(t,str)
+ local kind = type(str)
+ local dummy = nil
+ if kind == "string" then
+ local pars = lpegmatch(ctxtextcapture,str)
+ local list = t.list
+ for p=1,#pars do
+ local str = pars[p]
+ if #str == 0 then
+ list[#list+1 ] = { head = nil, tail = nil }
+ else
+ local l = list[#list]
+ if not l then
+ l = { head = nil, tail = nil }
+ list[#list+1 ] = l
+ end
+ local head, tail = tonodes(str,nil,nil)
+ if head then
+ if l.head then
+ l.tail.next = head
+ head.prev = l.tail
+ l.tail = tail
+ else
+ l.head, l.tail = head, tail
+ end
+ end
+ end
+ end
+ end
+end
+
+function blobs.pack(t,how)
+ local list = t.list
+ for i=1,#list do
+ local pack = list[i].pack
+ if pack then
+ flush_node_list(node.pack)
+ end
+ if how == "vertical" then
+ -- we need to prepend a local par node
+ -- list[i].pack = node.vpack(list[i].head,"exactly")
+ logs.report("blobs","vpack not yet supported")
+ else
+ list[i].pack = hpack_node_list(list[i].head,"exactly")
+ end
+ end
+end
+
+function blobs.write(t)
+ local list = t.list
+ for i=1,#list do
+ local pack = list[i].pack
+ if pack then
+ write_node(pack)
+ end
+ end
+end
diff --git a/tex/context/base/blob-ini.mkiv b/tex/context/base/blob-ini.mkiv
new file mode 100644
index 000000000..7f63ec73d
--- /dev/null
+++ b/tex/context/base/blob-ini.mkiv
@@ -0,0 +1,34 @@
+%D \module
+%D [ file=blob-ini,
+%D version=2010.04.06,
+%D title=\CONTEXT\ \LUA\ Typesetting,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Lua Typesetting / Initialization}
+
+%D This is a prelude to typesetting at the \LUA\ end. The code
+%D is already quite old but will only get nice when we are further
+%D down the road (close to version 1.00 of \LUATEX). Typesetting in
+%D pure \LUA\ sometimes makes sense.
+
+\registerctxluafile{blob-ini}{1.001}
+
+\endinput
+
+% \starttext
+%
+% \startluacode
+% local b = blobs.new()
+% blobs.append(b,"Hello world.\n Here we are.\n\n And Again!")
+% blobs.pack(b)
+% blobs.write(b)
+% \stopluacode
+%
+% \stoptext
diff --git a/tex/context/base/buff-ini.lua b/tex/context/base/buff-ini.lua
new file mode 100644
index 000000000..6b1af8f96
--- /dev/null
+++ b/tex/context/base/buff-ini.lua
@@ -0,0 +1,838 @@
+if not modules then modules = { } end modules ['buff-ini'] = {
+ version = 1.001,
+ comment = "companion to core-buf.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- ctx lua reference model / hooks and such
+-- to be optimized
+
+-- redefine buffers.get
+
+buffers = { }
+buffers.data = { }
+buffers.hooks = { }
+buffers.flags = { }
+buffers.commands = { }
+buffers.visualizers = { }
+
+-- if needed we can make 'm local
+
+local trace_run = false trackers.register("buffers.run", function(v) trace_run = v end)
+local trace_visualize = false trackers.register("buffers.visualize", function(v) trace_visualize = v end)
+
+local utf = unicode.utf8
+
+local concat, texsprint, texprint, texwrite = table.concat, tex.sprint, tex.print, tex.write
+local utfbyte, utffind, utfgsub = utf.byte, utf.find, utf.gsub
+local type, next = type, next
+local huge = math.huge
+local byte, sub, find, char, gsub, rep, lower, format, gmatch, match = string.byte, string.sub, string.find, string.char, string.gsub, string.rep, string.lower, string.format, string.gmatch, string.match
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+local ctxcatcodes = tex.ctxcatcodes
+local variables = interfaces.variables
+local lpegmatch = lpeg.match
+
+local data, flags, hooks, visualizers = buffers.data, buffers.flags, buffers.hooks, buffers.visualizers
+
+visualizers.defaultname = variables.typing
+
+function buffers.raw(name)
+ return data[name] or { }
+end
+
+function buffers.erase(name)
+ data[name] = nil
+end
+
+function buffers.set(name, str)
+ data[name] = { str } -- CHECK THIS
+end
+
+function buffers.append(name, str)
+ data[name] = (data[name] or "") .. str
+end
+
+
+buffers.flags.store_as_table = true
+
+-- to be sorted out: crlf + \ ; slow now
+
+local n = 0
+
+function buffers.grab(name,begintag,endtag,bufferdata)
+ local dn = data[name] or ""
+ if dn == "" then
+ buffers.level = 0
+ end
+ buffers.level = buffers.level + bufferdata:count("\\"..begintag) - bufferdata:count("\\"..endtag)
+ local more = buffers.level > 0
+ if more then
+ dn = dn .. bufferdata .. endtag
+ buffers.level = buffers.level - 1
+ else
+ if dn == "" then
+ dn = sub(bufferdata,1,#bufferdata-1)
+ else
+ dn = dn .. "\n" .. sub(bufferdata,1,#bufferdata-1)
+ end
+ dn = gsub(dn,"[\010\013]$","")
+ if flags.store_as_table then
+ dn = dn:splitlines()
+ end
+ end
+ data[name] = dn
+ cs.testcase(more)
+end
+
+function buffers.exists(name)
+ return data[name] ~= nil
+end
+
+function buffers.doifelsebuffer(name)
+ cs.testcase(data[name] ~= nil)
+end
+
+flags.optimize_verbatim = true
+flags.count_empty_lines = false
+
+local no_break_command = "\\doverbatimnobreak"
+local do_break_command = "\\doverbatimgoodbreak"
+local begin_of_line_command = "\\doverbatimbeginofline"
+local end_of_line_command = "\\doverbatimendofline"
+local empty_line_command = "\\doverbatimemptyline"
+
+local begin_of_display_command = "\\doverbatimbeginofdisplay"
+local end_of_display_command = "\\doverbatimendofdisplay"
+local begin_of_inline_command = "\\doverbatimbeginofinline"
+local end_of_inline_command = "\\doverbatimendofinline"
+
+function buffers.verbatimbreak(n,m)
+ if flags.optimize_verbatim then
+ if n == 2 or n == m then
+ texsprint(no_break_command)
+ elseif n > 1 then
+ texsprint(do_break_command)
+ end
+ end
+end
+
+function buffers.strip(lines,first,last)
+ local first, last = first or 1, last or #lines
+ for i=first,last do
+ local li = lines[i]
+ if #li == 0 or find(li,"^%s*$") then
+ first = first + 1
+ else
+ break
+ end
+ end
+ for i=last,first,-1 do
+ local li = lines[i]
+ if #li == 0 or find(li,"^%s*$") then
+ last = last - 1
+ else
+ break
+ end
+ end
+ return first, last, last - first + 1
+end
+
+function buffers.range(lines,first,last,range) -- 1,3 1,+3 fromhere,tothere
+ local first, last = first or 1, last or #lines
+ local what = aux.settings_to_array(range)
+ local r_first, r_last = what[1], what[2]
+ local f, l = tonumber(r_first), tonumber(r_last)
+ if r_first then
+ if f then
+ if f > first then
+ first = f
+ end
+ else
+ for i=first,last do
+ if find(lines[i],r_first) then
+ first, strip = i + 1
+ break
+ end
+ end
+ end
+ end
+ if r_last then
+ if l then
+ if find(r_last,"^[%+]") then -- 1,+3
+ l = first + l
+ end
+ if l < last then
+ last = l
+ end
+ else
+ for i=first,last do
+ if find(lines[i],r_last) then
+ last = i - 1
+ break
+ end
+ end
+ end
+ end
+ return first, last
+end
+
+function buffers.type(name,realign,range)
+ local lines = data[name]
+ local action = buffers.typeline
+ if lines then
+ if type(lines) == "string" then
+ lines = lines:splitlines()
+ data[name] = lines
+ end
+ if realign then
+ lines = buffers.realign(lines,realign)
+ end
+ local line, n = 0, 0
+ local first, last, m = buffers.strip(lines)
+ if range then
+ first, last = buffers.range(lines,first,last,range)
+ first, last = buffers.strip(lines,first,last)
+ end
+ hooks.begin_of_display()
+ for i=first,last do
+ n, line = action(lines[i], n, m, line)
+ end
+ hooks.end_of_display()
+ end
+end
+
+function buffers.loaddata(filename) -- this one might go away
+ -- this will be cleaned up when we have split supp-fil completely
+ -- instead of half-half
+ local ok, str, n = resolvers.loaders.tex(filename)
+ if not str then
+ ok, str, n = resolvers.loaders.tex(file.addsuffix(filename,'tex'))
+ end
+end
+
+function buffers.loaddata(filename) -- this one might go away
+ local foundname = resolvers.findtexfile(filename) or ""
+ if foundname == "" then
+ foundname = resolvers.findtexfile(file.addsuffix(filename,'tex')) or ""
+ end
+ if foundname == "" then
+ return ""
+ else
+ return resolvers.loadtexfile(foundname)
+ end
+end
+
+function buffers.typefile(name,realign,range) -- still somewhat messy, since name can be be suffixless
+ local str = buffers.loaddata(name)
+ if str and str~= "" then
+ local lines = str:splitlines()
+ if realign then
+ lines = buffers.realign(lines,realign)
+ end
+ local line, n, action = 0, 0, buffers.typeline
+ local first, last, m = buffers.strip(lines)
+ hooks.begin_of_display()
+ if range then
+ first, last = buffers.range(lines,first,last,range)
+ first, last = buffers.strip(lines,first,last)
+ end
+ for i=first,last do
+ n, line = action(lines[i], n, m, line)
+ end
+ hooks.end_of_display()
+ end
+end
+
+function buffers.typeline(str,n,m,line)
+ n = n + 1
+ buffers.verbatimbreak(n,m)
+ if find(str,"%S") then
+ line = line + 1
+ hooks.begin_of_line(line)
+ hooks.flush_line(hooks.line(str))
+ hooks.end_of_line()
+ else
+ if flags.count_empty_lines then
+ line = line + 1
+ end
+ hooks.empty_line(line)
+ end
+ return n, line
+end
+
+-- The optional prefix hack is there for the typesetbuffer feature and
+-- in mkii we needed that (this hidden feature is used in a manual).
+
+local function prepared(name,list) -- list is optional
+ if not list or list == "" then
+ list = name
+ end
+ if not name or name == "" then
+ name = tex.jobname .. "-" .. list .. ".tmp"
+ end
+ local content = buffers.collect(list,nil) or ""
+ if content == "" then
+ content = "empty buffer"
+ end
+ return name, content
+end
+
+local capsule = "\\starttext\n%s\n\\stoptext\n"
+local command = "context %s"
+
+function buffers.save(name,list,encapsulate) -- list is optional
+ local name, content = prepared(name,list)
+ io.savedata(name, (encapsulate and format(capsule,content)) or content)
+end
+
+function commands.savebuffer(list,name) -- name is optional
+ buffers.save(name,list)
+end
+
+function buffers.run(name,list,encapsulate)
+ local name, content = prepared(name,list)
+ local data = io.loaddata(name)
+ content = (encapsulate and format(capsule,content)) or content
+ if data ~= content then
+ if trace_run then
+ commands.writestatus("buffers","changes in '%s', processing forced",name)
+ end
+ io.savedata(name,content)
+ os.execute(format(command,name))
+ elseif trace_run then
+ commands.writestatus("buffers","no changes in '%s', not processed",name)
+ end
+end
+
+local printer = (lpeg.patterns.textline/texprint)^0
+
+function buffers.get(name)
+ local b = buffers.data[name]
+ if b then
+ if type(b) == "table" then
+ for i=1,#b do
+ texprint(b[i])
+ end
+ else
+ lpegmatch(printer,b)
+ end
+ end
+end
+
+local function content(name,separator) -- no print
+ local b = data[name]
+ if b then
+ if type(b) == "table" then
+ return concat(b,separator or "\n")
+ else
+ return b
+ end
+ else
+ return ""
+ end
+end
+
+buffers.content = content
+
+function buffers.collect(names,separator) -- no print
+ -- maybe we should always store a buffer as table so
+ -- that we can pass it directly
+ if type(names) == "string" then
+ names = aux.settings_to_array(names)
+ end
+ local t = { }
+ for i=1,#names do
+ local c = content(names[i],separator)
+ if c ~= "" then
+ t[#t+1] = c
+ end
+ end
+ return concat(t,separator or "\r") -- "\n" is safer due to comments and such
+end
+
+function buffers.feedback(names,separator)
+ -- don't change the texprint into texsprint as it fails on mp buffers
+ -- because (penddef) becomes penddef then
+ texprint(ctxcatcodes,string.splitlines(buffers.collect(names,separator)))
+end
+
+local function tobyte(c)
+ return " [" .. utfbyte(c) .. "] "
+end
+
+function buffers.inspect(name)
+ local b = data[name]
+ if b then
+ if type(b) == "table" then
+ for k=1,#b do
+ local v = b[k]
+ if v == "" then
+ texsprint(ctxcatcodes,"[crlf]\\par ") -- space ?
+ else
+ texsprint(ctxcatcodes,(gsub(v,"(.)",tobyte)),"\\par")
+ end
+ end
+ else
+ texsprint(ctxcatcodes,(gsub(b,"(.)",tobyte)))
+ end
+ end
+end
+
+-- maybe just line(n,str) empty(n,str)
+
+visualizers.tablength = 7
+visualizers.enabletab = true -- false
+visualizers.obeyspace = true
+
+function buffers.settablength(tablength)
+ visualizers.tablength = tablength and tonumber(tablength) or 7
+end
+
+visualizers.handlers = visualizers.handlers or { }
+
+local handlers = visualizers.handlers
+
+function buffers.newvisualizer(name)
+ name = lower(name)
+ local handler = { }
+ handlers[name] = handler
+ return handler
+end
+
+function buffers.getvisualizer(name)
+ name = lower(name)
+ return handlers[name] or buffers.loadvisualizer(name)
+end
+
+function buffers.loadvisualizer(name)
+ name = lower(name)
+ local hn = handlers[name]
+ if hn then
+ return hn
+ else
+ environment.loadluafile("pret-" .. name)
+ local hn = handlers[name]
+ if not hn then
+ -- hn = buffers.newvisualizer(name)
+ hn = handlers[visualizers.defaultname]
+ handlers[name] = hn
+ if trace_visualize then
+ logs.report("buffers","mapping '%s' visualizer onto '%s'",name,visualizers.defaultname)
+ end
+ elseif trace_visualize then
+ logs.report("buffers","loading '%s' visualizer",name)
+ end
+ return hn
+ end
+end
+
+-- was "default", should be set at tex end (todo)
+
+local default = buffers.newvisualizer(visualizers.defaultname)
+
+--~ print(variables.typing) os.exit()
+
+-- will become cleaner
+
+local currentvisualizer, currenthandler
+
+function buffers.setvisualizer(str)
+ currentvisualizer = lower(str)
+ currenthandler = handlers[currentvisualizer]
+ if currenthandler then
+ -- if trace_visualize then
+ -- logs.report("buffers","enabling specific '%s' visualizer",currentvisualizer)
+ -- end
+ else
+ currentvisualizer = visualizers.defaultname
+ currenthandler = handlers.default
+ -- if trace_visualize then
+ -- logs.report("buffers","enabling default visualizer '%s'",currentvisualizer)
+ -- end
+ end
+ if currenthandler.reset then
+ currenthandler.reset()
+ end
+end
+
+function buffers.resetvisualizer()
+ currentvisualizer = visualizers.defaultname
+ currenthandler = handlers.default
+ if currenthandler.reset then
+ currenthandler.reset()
+ end
+end
+
+buffers.setvisualizer(visualizers.defaultname)
+
+function visualizers.reset()
+end
+
+function buffers.doifelsevisualizer(str)
+ cs.testcase((str ~= "") and (handlers[lower(str)] ~= nil))
+end
+
+-- calling routines, don't change
+
+function hooks.begin_of_display()
+ (currenthandler.begin_of_display or default.begin_of_display)(currentvisualizer)
+end
+
+function hooks.end_of_display()
+ (currenthandler.end_of_display or default.end_of_display)()
+end
+
+function hooks.begin_of_inline()
+ (currenthandler.begin_of_inline or default.begin_of_inline)(currentvisualizer)
+end
+
+function hooks.end_of_inline()
+ (currenthandler.end_of_inline or default.end_of_inline)()
+end
+
+function hooks.flush_line(str,nesting)
+ local fl = currenthandler.flush_line
+ if fl then
+ str = gsub(str," *[\n\r]+ *"," ") ; -- semi colon needed
+ fl(str,nesting)
+ else
+ -- gsub done later
+ default.flush_line(str,nesting)
+ end
+end
+
+function hooks.flush_inline(str,nesting)
+ hooks.begin_of_inline()
+ hooks.flush_line(str,nesting)
+ hooks.end_of_inline()
+end
+
+function hooks.begin_of_line(n)
+ (currenthandler.begin_of_line or default.begin_of_line)(n)
+end
+
+function hooks.end_of_line()
+ (currenthandler.end_of_line or default.end_of_line)()
+end
+
+function hooks.empty_line()
+ (currenthandler.empty_line or default.empty_line)()
+end
+
+function hooks.line(str)
+ if visualizers.enabletab then
+ str = string.tabtospace(str,visualizers.tablength)
+ else
+ str = gsub(str,"\t"," ")
+ end
+ return (currenthandler.line or default.line)(str)
+end
+
+-- defaults
+
+function default.begin_of_display(currentvisualizer)
+ texsprint(ctxcatcodes,begin_of_display_command,"{",currentvisualizer,"}")
+end
+
+function default.end_of_display()
+ texsprint(ctxcatcodes,end_of_display_command)
+end
+
+function default.begin_of_inline(currentvisualizer)
+ texsprint(ctxcatcodes,begin_of_inline_command,"{",currentvisualizer,"}")
+end
+
+function default.end_of_inline()
+ texsprint(ctxcatcodes,end_of_inline_command)
+end
+
+function default.begin_of_line(n)
+ texsprint(ctxcatcodes, begin_of_line_command,"{",n,"}")
+end
+
+function default.end_of_line()
+ texsprint(ctxcatcodes,end_of_line_command)
+end
+
+function default.empty_line()
+ texsprint(ctxcatcodes,empty_line_command)
+end
+
+function default.line(str)
+ return str
+end
+
+function default.flush_line(str)
+ str = gsub(str," *[\n\r]+ *"," ")
+ if visualizers.obeyspace then
+ for c in utfcharacters(str) do
+ if c == " " then
+ texsprint(ctxcatcodes,"\\obs")
+ else
+ texwrite(c)
+ end
+ end
+ else
+ texwrite(str)
+ end
+end
+
+-- not needed any more
+
+local function escaped_token(c)
+ if utffind(c,"^(%a%d)$") then
+ return c
+ elseif c == " " then
+ return "\\obs "
+ else
+ return "\\char" .. utfbyte(c) .. " "
+ end
+end
+
+buffers.escaped_token = escaped_token
+
+function buffers.escaped(str)
+ -- use the utfcharacters loop
+ return (utfgsub(str,"(.)", escaped_token))
+end
+
+-- special one
+
+buffers.commands.nested = "\\switchslantedtype "
+
+-- todo : utf + faster, direct print and such. no \\char, vrb catcodes, see end
+
+function visualizers.flush_nested(str, enable) -- no utf, kind of obsolete mess
+ str = gsub(str," *[\n\r]+ *"," ")
+ local result, c, nested, i = "", "", 0, 1
+ local commands = buffers.commands -- otherwise wrong commands
+ while i < #str do -- slow
+ c = sub(str,i,i+1)
+ if c == "<<" then
+ nested = nested + 1
+ if enable then
+ result = result .. "{" .. commands.nested
+ else
+ result = result .. "{"
+ end
+ i = i + 2
+ elseif c == ">>" then
+ if nested > 0 then
+ nested = nested - 1
+ result = result .. "}"
+ end
+ i = i + 2
+ else
+ c = sub(str,i,i)
+ if c == " " then
+ result = result .. "\\obs "
+ elseif find(c,"%a") then
+ result = result .. c
+ else
+ result = result .. "\\char" .. byte(c) .. " "
+ end
+ i = i + 1
+ end
+ end
+ result = result .. "\\char" .. byte(sub(str,i,i)) .. " " .. rep("}",nested)
+ texsprint(ctxcatcodes,result)
+end
+
+-- handy helpers
+--
+-- \sop[color] switch_of_pretty
+-- \bop[color] begin_of_pretty
+-- \eop end_of_pretty
+-- \obs obeyedspace
+-- \char special characters
+
+buffers.currentcolors = { }
+
+function buffers.change_state(n, state)
+ if n then
+ if state ~= n then
+ if state > 0 then
+ texsprint(ctxcatcodes,"\\sop[",buffers.currentcolors[n],"]")
+ else
+ texsprint(ctxcatcodes,"\\bop[",buffers.currentcolors[n],"]")
+ end
+ return n
+ end
+ elseif state > 0 then
+ texsprint(ctxcatcodes,"\\eop")
+ return 0
+ end
+ return state
+end
+
+function buffers.finish_state(state)
+ if state > 0 then
+ texsprint(ctxcatcodes,"\\eop")
+ return 0
+ else
+ return state
+ end
+end
+
+buffers.open_nested = rep("\\char"..byte('<').." ",2)
+buffers.close_nested = rep("\\char"..byte('>').." ",2)
+
+function buffers.replace_nested(result)
+ result = gsub(result,buffers.open_nested, "{")
+ result = gsub(result,buffers.close_nested,"}")
+ return result
+end
+
+function buffers.flush_result(result,nested)
+ if nested then
+ texsprint(ctxcatcodes,buffers.replace_nested(concat(result,"")))
+ else
+ texsprint(ctxcatcodes,concat(result,""))
+ end
+end
+
+-- new
+
+function buffers.realign(name,forced_n) -- no, auto,
+ local n, d
+ if type(name) == "string" then
+ d = data[name]
+ if type(d) == "string" then
+ d = d:splitlines()
+ end
+ else
+ d = name -- already a buffer
+ end
+ forced_n = (forced_n == variables.auto and huge) or tonumber(forced_n)
+ if forced_n then
+ for i=1, #d do
+ local spaces = find(d[i],"%S")
+ if not spaces then
+ -- empty line
+ elseif not n then
+ n = spaces
+ elseif spaces == 0 then
+ n = 0
+ break
+ elseif n > spaces then
+ n = spaces
+ end
+ end
+ if n > 0 then
+ if n > forced_n then
+ n = forced_n
+ end
+ for i=1,#d do
+ d[i] = sub(d[i],n)
+ end
+ end
+ end
+ return d
+end
+
+-- escapes: buffers.set_escape("tex","/BTEX","/ETEX")
+
+local function flush_escaped_line(str,pattern,flushline)
+ while true do
+ local a, b, c = match(str,pattern)
+ if a and a ~= "" then
+ flushline(a)
+ end
+ if b and b ~= "" then
+ texsprint(ctxcatcodes,"{",b,"}")
+ end
+ if c then
+ if c == "" then
+ break
+ else
+ str = c
+ end
+ else
+ flushline(str)
+ break
+ end
+ end
+end
+
+function buffers.set_escape(name,pair)
+ if pair and pair ~= "" then
+ local visualizer = buffers.getvisualizer(name)
+ visualizer.normal_flush_line = visualizer.normal_flush_line or visualizer.flush_line
+ if pair == variables.no then
+ visualizer.flush_line = visualizer.normal_flush_line or visualizer.flush_line
+ if trace_visualize then
+ logs.report("buffers","resetting escape range for visualizer '%s'",name)
+ end
+ else
+ local start, stop
+ if pair == variables.yes then
+ start, stop = "/BTEX", "/ETEX"
+ else
+ pair = string.split(pair,",")
+ start, stop = string.esc(pair[1] or ""), string.esc(pair[2] or "")
+ end
+ if start ~= "" then
+ local pattern
+ if stop == "" then
+ pattern = "^(.-)" .. start .. "(.*)(.*)$"
+ else
+ pattern = "^(.-)" .. start .. "(.-)" .. stop .. "(.*)$"
+ end
+ function visualizer.flush_line(str)
+ flush_escaped_line(str,pattern,visualizer.normal_flush_line)
+ end
+ if trace_visualize then
+ logs.report("buffers","setting escape range for visualizer '%s' to %s -> %s",name,start,stop)
+ end
+ elseif trace_visualize then
+ logs.report("buffers","problematic escape specification '%s' for visualizer '%s'",pair,name)
+ end
+ end
+ end
+end
+
+-- THIS WILL BECOME A FRAMEWORK: the problem with prety printing is that
+-- we deal with snippets and therefore we need tolerant parsing
+
+--~ local type = type
+
+--~ visualizers = visualizers or { }
+
+--~ local function fallback(s) return s end
+
+--~ function visualizers.visualize(visualizer,kind,pattern)
+--~ if type(visualizer) == "table" and type(kind) == "string" then
+--~ kind = visualizer[kind] or visualizer.default or fallback
+--~ else
+--~ kind = fallback
+--~ end
+--~ return (lpeg.C(pattern))/kind
+--~ end
+
+--~ local flusher = texio.write
+--~ local format = string.format
+
+--~ local visualizer = {
+--~ word = function(s) return flusher(format("\\bold{%s}",s)) end,
+--~ number = function(s) return flusher(format("\\slanted{%s}",s)) end,
+--~ default = function(s) return flusher(s) end,
+--~ }
+
+--~ local word = lpeg.R("AZ","az")^1
+--~ local number = lpeg.R("09")^1
+--~ local any = lpeg.P(1)
+
+--~ local pattern = lpeg.P { "start",
+--~ start = (
+--~ visualizers.visualize(visualizer,"word",word) +
+--~ visualizers.visualize(visualizer,"number",number) +
+--~ visualizers.visualize(visualizer,"default",any)
+--~ )^1
+--~ }
+
+--~ str = [[test 123 test $oeps$]]
+
+--~ lpegmatch(pattern,str)
diff --git a/tex/context/base/buff-ini.mkii b/tex/context/base/buff-ini.mkii
new file mode 100644
index 000000000..fc147d090
--- /dev/null
+++ b/tex/context/base/buff-ini.mkii
@@ -0,0 +1,348 @@
+%D \module
+%D [ file=buff-ini, % was core-buf % blocks are moved to core-blk
+%D version=2000.01.05,
+%D title=\CONTEXT\ Buffer Macros,
+%D subtitle=Buffers,
+%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 Buffer Macros / Buffers}
+
+\unprotect
+
+% Helpers:
+
+\chardef\buffernestmode\plusone % 0: not nested, 1: startbuffer nested, 2: all buffers nested
+
+\edefconvertedargument\emptybufferline{ }
+
+\ifx\tmpblocks\undefined \newwrite\tmpblocks \fi
+
+\newif\iftmpblockstarted
+
+\long\def\flushbufferline#1%
+ {\iftmpblockstarted
+ \ifsegmentatebuffer
+ \ifemptybufferline
+ \immediate\write\tmpblocks{\string\stopbufferparagraph }%
+ \immediate\write\tmpblocks{\string\startbufferparagraph}%
+ \else
+ \immediate\write\tmpblocks{#1}%
+ \fi
+ \else
+ \immediate\write\tmpblocks{#1}%
+ \fi
+ \else
+ \doifsomething{#1}
+ {\tmpblockstartedtrue
+ \immediate\write\tmpblocks{\string#1}}%
+ \fi}
+
+\long\def\processnextbufferlineA#1%
+ {\relax % checken waarom eerdere macro dit nodig heeft / supp-mps run
+ \defconvertedargument\next{#1 }%
+ \doifinstringelse{\delcharacter\letterpercent}{\delcharacter\next}
+ {\secondoftwoarguments}
+ {\doifincsnameelse\endofblock\next
+ {\ifnum\nestedbufferlevel=\zerocount
+ \expandafter\firstoftwoarguments
+ \else
+ \decrement\nestedbufferlevel\relax
+ \expandafter\secondoftwoarguments
+ \fi}
+ {\doifincsnameelse\beginofblock\next
+ {\increment\nestedbufferlevel\relax
+ \secondoftwoarguments}
+ {\secondoftwoarguments}}}}
+
+\long\def\processnextbufferlineB#1% #2#3%
+ {\defconvertedargument\next{#1 }%
+ \ifx\next\emptybufferline
+ \ifsegmentatebuffer \emptybufferlinetrue \fi
+ \expandafter\secondoftwoarguments% #3%
+ \else
+ \emptybufferlinefalse
+ \doifinstringelse\endofblock\next
+ {\expandafter\firstoftwoarguments }% #2}
+ {\expandafter\secondoftwoarguments}% #3}%
+ \fi}
+
+\bgroup
+\obeylines
+\long\gdef\copybufferline#1
+ {\processnextbufferline{#1}\closebufferfile{\flushbufferline{#1}\copybufferline}}
+\egroup
+
+\newif\ifsegmentatebuffer
+\newif\ifemptybufferline
+
+\def\currentbuffer{\jobname}
+
+\def\setcurrentbuffer#1%
+ {\doifelsenothing{#1}{\edef\currentbuffer{\jobname}}{\edef\currentbuffer{#1}}}
+
+\def\resetbuffer
+ {\dosingleempty\doresetbuffer}
+
+\def\doresetbuffer[#1]%
+ {\begingroup
+ \setcurrentbuffer{#1}%
+ \unlinkfile{\TEXbufferfile\currentbuffer}%
+ \endgroup}
+
+\def\dostartbuffer
+ {\bgroup
+ \obeylines % nodig, anders gaat 't fout als direct \starttable (bv)
+ \doquadrupleempty\dodostartbuffer}
+
+\def\dodostartbuffer[#1][#2][#3][#4]% upward compatible
+ {\iffourthargument
+ \def\next{\dododostartbuffer{#1}{#2}{#3}{#4}}%
+ \else
+ \def\next{\dododostartbuffer {}{#1}{#2}{#3}}%
+ \fi
+ \next}
+
+\def\dododostartbuffer#1#2#3#4%
+ {%\showmessage\m!systems{15}{#2}%
+ \doifelsevalue{\??bu#1\c!paragraph}\v!yes
+ {\segmentatebuffertrue} % todo in mkiv
+ {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}\segmentatebuffertrue\segmentatebufferfalse}%
+ \doifvalue{\??bu#1\c!local}\v!yes
+ {\chardef\buffernestmode\plustwo}% permit nesting
+ \setcurrentbuffer{#2}%
+ \doifelsenothing{#4}
+ {\letbeundefined{\e!stop\v!buffer}% % \let\stopbuffer=\relax % \undefined
+ \edefconvertedargument\beginofblock{\e!start\v!buffer}%
+ \edefconvertedargument\endofblock {\e!stop \v!buffer}%
+ \ifcase\buffernestmode
+ \let\processnextbufferline\processnextbufferlineB
+ \else
+ \let\processnextbufferline\processnextbufferlineA
+ \fi}
+ {\letbeundefined{#4}% \letvalue{#4}=\relax % \undefined
+ \@EA\defconvertedargument\@EA\beginofblock\@EA{\csname#3\endcsname}% we could use defconvertedcommand here (no \@EA)
+ \@EA\defconvertedargument\@EA\endofblock \@EA{\csname#4\endcsname}% we could use defconvertedcommand here (no \@EA)
+ \ifcase\buffernestmode
+ \let\processnextbufferline\processnextbufferlineB
+ \or
+ \let\processnextbufferline\processnextbufferlineB
+ \else
+ \let\processnextbufferline\processnextbufferlineA
+ \fi}%
+ \def\closebufferfile
+ {\ifsegmentatebuffer
+ \immediate\write\tmpblocks{\string\stopbufferparagraph}%
+ \fi
+ \immediate\closeout\tmpblocks
+ \egroup
+ \getvalue{#4}}%
+ \doifelsenothing{#2}
+ {\edef\bufferfilename{\TEXbufferfile\jobname}}%
+ {\edef\bufferfilename{\TEXbufferfile{#2}}}%
+ \immediate\openout\tmpblocks\bufferfilename
+ \ifsegmentatebuffer
+ \immediate\write\tmpblocks{\string\startbufferparagraph}%
+ \fi
+ \newcounter\nestedbufferlevel
+ \recatcodeuppercharacterstrue
+ \setcatcodetable\vrbcatcodes
+ \obeylines
+ \copybufferline}
+
+\letvalue{\e!start\v!buffer}\dostartbuffer
+
+\let\endbuffer\undefined % to please the dep parser
+
+\def\setbuffer
+ {\dosingleempty\dosetbuffer}
+
+\long\def\dosetbuffer[#1]#2\endbuffer % seldom used so we just pass #2
+ {\begingroup
+ \setcurrentbuffer{#1}%
+ \edef\bufferfilename{\TEXbufferfile{\currentbuffer}}%
+ \immediate\openout\tmpblocks\bufferfilename
+ \defconvertedargument\ascii{#2}%
+ \immediate\write\tmpblocks{\ascii}%
+ \immediate\closeout\tmpblocks
+ \endgroup}
+
+\def\setupbuffer
+ {\dodoubleempty\dosetupbuffer}
+
+\def\dosetupbuffer[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??bu#1][#2]%
+ \else
+ \getparameters[\??bu][#1]%
+ \fi}
+
+\def\dodefinebuffer[#1][#2]%
+ {\iffirstargument % else problems
+ \doglobal\increment\nofdefinedbuffers
+ \letvalue{\??bu#1\c!number }\nofdefinedbuffers
+ \letvalue{\??bu#1\c!paragraph}\v!no
+ \setevalue{\e!start#1}{\noexpand\dostartbuffer[#1][def-\nofdefinedbuffers][\e!start#1][\e!stop#1]}%
+ \unexpanded\setevalue{\e!get #1}{\noexpand\dogetbuffer [#1][def-\nofdefinedbuffers]}%
+ \unexpanded\setevalue{\e!type #1}{\noexpand\dotypebuffer [#1][def-\nofdefinedbuffers]}%
+ \getparameters[\??bu#1][#2]%
+ \fi}
+
+\def\definebuffer
+ {\dodoubleempty\dodefinebuffer}
+
+\unexpanded\def\getbuffer
+ {\dodoubleempty\dogetbuffer}
+
+\def\dogetbuffer[#1][#2]%
+ {\ifsecondargument
+ \dodogetbuffer[#1][#2]%
+ \else
+ \dodogetbuffer[][#1]%
+ \fi}
+
+\def\dogetbufferasis{\readjobfile{\TEXbufferfile{\currentbuffer}}\donothing\donothing}%
+
+\def\dodogetbuffer[#1][#2]%
+ {\getvalue{\??bu#1\c!before}%
+ \dobuffer{16}{#2}\dogetbufferasis
+ \getvalue{\??bu#1\c!after}}
+
+\unexpanded\def\typebuffer
+ {\dodoubleempty\dotypebuffer}
+
+\def\dogetfilebuffer{\typefile{\TEXbufferfile{\currentbuffer}}}
+
+\def\dotypebuffer[#1][#2]%
+ {\iffirstargument
+ \dobuffer{17}{#1}\dogetfilebuffer
+ \else
+ \dobuffer{17}{#2}\dogetfilebuffer
+ \fi}
+
+\def\dobuffer#1#2#3%
+ {\doifelsenothing{#2}
+ {\dodobuffer#3\jobname}
+ {\processcommalist[#2]{\dodobuffer#3}}}
+
+\def\dodobuffer#1#2% command name
+ {\pushmacro\currentbuffer
+ \edef\currentbuffer{\ifcsname\??bu#2\c!number\endcsname def-\csname\??bu#2\c!number\endcsname\else#2\fi}%
+ \beginrestorecatcodes
+ #1%
+ \endrestorecatcodes
+ \popmacro\currentbuffer}
+
+\def\processTEXbuffer{\getbuffer} % handy
+
+% seldom used, only in a few projects that demanded more speed
+
+\def\dostartmemorybuffer
+ {\dosingleempty\dostartmemorybuffer}
+
+\long\def\dostartmemorybuffer[#1]#2\stopbuffer
+ {\setbuffer[#1]#2\endbuffer}
+
+\let\dostartfilebuffer\startbuffer
+
+\def\usememorybuffers{\let\startbuffer\dostartmemorybuffer}
+\def\usefilebuffers {\let\startbuffer\dostartfilebuffer}
+
+% this features is soldom used (complex examns where we need to fetch
+% special parts of a text
+%
+% this is not yet supported in mkiv (relatively easy to do but there
+% we don't have the par tags but need to grab 'm
+
+\def\skippedbufferparagraphs{0}
+
+\let\startbufferparagraph\relax
+\let\stopbufferparagraph \par % \relax
+
+\newcount\currentbufferparagraph
+
+\def\getbufferparagraphs
+ {\dodoubleempty\dogetbufferparagraphs}
+
+\def\dosetbufferoffset#1%
+ {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}
+ {\currentbufferparagraph-\getvalue{\??bu#1\c!paragraph}}
+ {\currentbufferparagraph \zerocount}%
+ \relax}
+
+\def\dogetbufferparagraphs[#1][#2]%
+ {\iffirstargument
+ \ifsecondargument
+ \dosetbufferoffset{#1}%
+ \doifelse{#2}\v!all
+ {\def\startbufferparagraph{\normalbufferparagraph{#1}}}
+ {\def\startbufferparagraph{\filterbufferparagraph{#1}{#2}}}%
+ \def\stopbufferparagraph{\dostopbufferparagraph{#1}}%
+ \def\next{\getparagraphedbuffer[#1]}%
+ \else
+ \dosetbufferoffset\empty
+ \def\startbufferparagraph{\filterbufferparagraph{}{#1}}%
+ \def\stopbufferparagraph{\dostopbufferparagraph{}}%
+ \def\next{\getparagraphedbuffer[]}%
+ \fi
+ \else
+ \dosetbufferoffset\empty
+ \def\startbufferparagraph{\normalbufferparagraph{}}%
+ \def\stopbufferparagraph{\dostopbufferparagraph{}}%
+ \def\next{\getparagraphedbuffer[]}%
+ \fi
+ \next}
+
+\def\dogetparagraphbuffer{\readjobfile{\TEXbufferfile{\currentbuffer}}\donothing\donothing}
+
+\def\getparagraphedbuffer[#1]%
+ {\dobuffer{16}{#1}\dogetparagraphbuffer}
+
+\def\dostopbufferparagraph#1%
+ {\getvalue{\??bu#1\c!after}\par}
+
+\def\dostartbufferparagraph#1%
+ {\par\getvalue{\??bu#1\c!before}}
+
+\def\normalbufferparagraph
+ {\advance\currentbufferparagraph \plusone
+ \ifnum\currentbufferparagraph>\zerocount
+ \expandafter\dostartbufferparagraph
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\filterbufferparagraph#1#2%
+ {\advance\currentbufferparagraph \plusone
+ \ifcase\currentbufferparagraph
+ \@EA\gobblebufferparagraph
+ \else
+ \doifinsetelse{\the\currentbufferparagraph}{#2}
+ {\@EA\dostartbufferparagraph}
+ {\@EA\fakebufferparagraph}%
+ \fi
+ {#1}}
+
+\long\def\gobblebufferparagraph#1#2\stopbufferparagraph
+ {}
+
+\def\fakebufferparagraph#1%
+ {\bgroup
+ \def\stopbufferparagraph{\dostopbufferparagraph{#1}\egroup\egroup}%
+ \setbox\scratchbox\vbox\bgroup\dostartbufferparagraph{#1}}
+
+% definitions
+
+\definebuffer[\v!hiding] \setupbuffer[\v!hiding][\c!local=\v!yes]
+
+\setupbuffer
+ [\c!paragraph=\v!no,
+ \c!before=,
+ \c!after=]
+
+\protect \endinput
diff --git a/tex/context/base/buff-ini.mkiv b/tex/context/base/buff-ini.mkiv
new file mode 100644
index 000000000..86b0fa3c5
--- /dev/null
+++ b/tex/context/base/buff-ini.mkiv
@@ -0,0 +1,355 @@
+%D \module
+%D [ file=buff-ini, % was core-buf, % blocks are moved to core-blk
+%D version=2000.01.05,
+%D title=\CONTEXT\ Buffer Macros,
+%D subtitle=Buffers,
+%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 Buffer Macros / Buffers}
+
+\registerctxluafile{buff-ini}{1.001}
+
+% todo:
+%
+% \startluacode
+% local locations = { }
+% function document.set_number(name)
+% locations[name] = {
+% line = status.linenumber,
+% file = status.filename
+% }
+% end
+% function document.add_number(name)
+% local b, l = buffers.raw(name), locations[name]
+% if b and l then
+% for i=1,#b do
+% b[i] = string.gsub(b[i],"# line: ","# line: " .. l.line + 2)
+% end
+% end
+% end
+% \stopluacode
+%
+% \starttext
+%
+% \ctxlua{document.set_number("oeps")}
+% \startbuffer[oeps]
+% # line:
+%
+% test
+% test
+% \stopbuffer
+% \ctxlua{document.add_number("oeps")}
+%
+% \typebuffer[oeps]
+%
+% \stoptext
+
+\ifdefined\doinitializeverbatim \else% temp hack
+ \def\doinitializeverbatim{\tttf}
+\fi
+
+\unprotect
+
+\chardef\buffernestmode\plusone % 0: not nested, 1: startbuffer nested, 2: all buffers nested
+
+\newif\ifsegmentatebuffer
+\newif\ifemptybufferline
+
+\def\currentbuffer{\jobname}
+
+\def\setcurrentbuffer#1%
+ {\doifelsenothing{#1}{\edef\currentbuffer{\jobname}}{\edef\currentbuffer{#1}}}
+
+\def\resetbuffer
+ {\dosingleempty\doresetbuffer}
+
+\def\doresetbuffer[#1]%
+ {\begingroup
+ \setcurrentbuffer{#1}%
+ \ctxlua{buffers.erase("\currentbuffer")}%
+ \endgroup}
+
+\def\dostartbuffer
+ {\bgroup
+ \obeylines % nodig, anders gaat 't fout als direct \starttable (bv)
+ \doquadrupleempty\dodostartbuffer}
+
+\def\dodostartbuffer[#1][#2][#3][#4]% upward compatible
+ {\iffourthargument
+ \def\next{\dododostartbuffer{#1}{#2}{#3}{#4}}%
+ \else
+ \def\next{\dododostartbuffer {}{#1}{#2}{#3}}%
+ \fi
+ \next}
+
+\def\dododostartbuffer#1#2#3#4%
+ {%\showmessage\m!systems{15}{#2}%
+ \doifelsevalue{\??bu#1\c!paragraph}\v!yes
+ {\segmentatebuffertrue} % todo in mkiv
+ {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}\segmentatebuffertrue\segmentatebufferfalse}%
+ \doifvalue{\??bu#1\c!local}\v!yes
+ {\chardef\buffernestmode\plustwo}% permit nesting
+ \setcurrentbuffer{#2}%
+ \doifelsenothing{#4}
+ {\normalexpanded{\noexpand\setbuffercapsules{\e!start\v!buffer}{\e!stop\v!buffer}}%
+ \letvalue\bufferstop\relax}
+ %{\@EA\setbuffercapsules\@EA{\csname#3\@EA\endcsname\@EA}\@EA{\csname#4\endcsname}}% if we strip later
+ {\setbuffercapsules{#3}{#4}}%
+ \normalexpanded{\noexpand\dodowithbuffer
+ {\currentbuffer}
+ {\bufferstart}
+ {\bufferstop}
+ {\donothing}
+ {\egroup
+ \noexpand\getvalue{\bufferstop}}}}
+
+\letvalue{\e!start\v!buffer}\dostartbuffer
+
+\let\endbuffer\undefined % to please the dep parser
+
+\def\dowithbuffer#1#2#3% name, startsequence, stopsequence, before, after
+ {\setbuffercapsules{#2}{#3}%
+ \normalexpanded{\noexpand\dodowithbuffer{#1}{\bufferstart}{\bufferstop}}}
+
+\long\def\dodowithbuffer#1#2#3#4#5% name, startsequence, stopsequence, before, after
+ {#4%
+ \bgroup
+ \setcatcodetable \vrbcatcodes
+ \catcode`\\=12
+ \ctxlua{buffers.erase("#1")}%
+ \long\def\nododowithbuffer
+ {\egroup
+ #5}%
+ \long\def\dododowithbuffer##1#3% is detokenize needed? TEST
+ {\ctxlua
+ {buffers.grab("#1","#2","#3",\!!bs\detokenize{##1}\!!es)}
+ \dododowithbuffer
+ \nododowithbuffer}%
+ \dododowithbuffer}
+
+\def\setbuffercapsules#1#2% \scantextokens not needed (had a reason at some point)
+ {\edef\bufferstart{#1}\edef\bufferstart{\scantextokens\expandafter{\bufferstart}}%
+ \edef\bufferstop {#2}\edef\bufferstop {\scantextokens\expandafter{\bufferstop }}}
+
+\def\setbuffer
+ {\dosingleempty\dosetbuffer}
+
+\long\def\dosetbuffer[#1]#2\endbuffer % seldom used so we just pass #2
+ {\begingroup
+ \setcurrentbuffer{#1}%
+ \ctxlua{buffers.set("\currentbuffer", \!!bs\detokenize{#2}\!!es)}%
+ \endgroup}
+
+\unexpanded\def\setupbuffer
+ {\dodoubleempty\dosetupbuffer}
+
+\def\dosetupbuffer[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??bu#1][#2]%
+ \else
+ \getparameters[\??bu][#1]%
+ \fi}
+
+\def\dodefinebuffer[#1][#2]%
+ {\iffirstargument % else problems
+ \doglobal\increment\nofdefinedbuffers
+ \letvalue{\??bu#1\c!number }\nofdefinedbuffers
+ \letvalue{\??bu#1\c!paragraph}\v!no
+ \setuevalue{\e!start#1}{\noexpand\dostartbuffer[#1][def-\nofdefinedbuffers][\e!start#1][\e!stop#1]}% maybe also relax stop
+ \setuevalue{\e!get #1}{\noexpand\dogetbuffer [#1][def-\nofdefinedbuffers]}%
+ \setuevalue{\e!type #1}{\noexpand\dotypebuffer [#1][def-\nofdefinedbuffers]}%
+ \getparameters[\??bu#1][#2]%
+ \fi}
+
+\unexpanded\def\definebuffer
+ {\dodoubleempty\dodefinebuffer}
+
+\def\thebuffernumber#1%
+ {\csname\??bu#1\c!number\endcsname}
+
+\unexpanded\def\getbuffer
+ {\dodoubleempty\dogetbuffer}
+
+\def\dogetbuffer[#1][#2]%
+ {\ifsecondargument
+ \dodogetbuffer[#1][#2]%
+ \else
+ \dodogetbuffer[][#1]%
+ \fi}
+
+\def\dogetbufferasis{\ctxlua{buffers.get("\currentbuffer")}}
+
+\def\dodogetbuffer[#1][#2]%
+ {\getvalue{\??bu#1\c!before}%
+ \dobuffer{16}{#2}\dogetbufferasis
+ \getvalue{\??bu#1\c!after}}
+
+\unexpanded\def\typebuffer
+ {\dodoubleempty\dotypebuffer}
+
+\def\doprocessbufferverbatim
+ {\doinitializeverbatim
+ \ctxlua{buffers.type("\currentbuffer","\typingparameter\c!strip")}}
+
+\def\doprocessbufferlinesverbatim#1#2#3%
+ {#2%
+ % todo, set up numbers
+ \doinitializeverbatim
+ \ctxlua{buffers.type("\currentbuffer","\typingparameter\c!strip")}
+ #3}
+
+\def\doifelsebuffer#1%
+ {\ctxlua{buffers.doifelsebuffer("#1")}}
+
+\def\dodotypebuffer#1#2#3% see dodotypefile
+ {\doifelsebuffer{#3}
+ {\dosometyping{#1}{#2}{#3}\doprocessbufferverbatim\doprocessbufferlinesverbatim}
+ {\reporttypingerror{#3}}}
+
+\def\dotypefilebuffer{\dodotypebuffer{\v!file}{}{\currentbuffer}}%
+
+\def\dotypebuffer[#1][#2]%
+ {\iffirstargument
+ \dobuffer{17}{#1}\dotypefilebuffer
+ \else
+ \dobuffer{17}{#2}\dotypefilebuffer
+ \fi}
+
+\def\dobuffer#1#2#3%
+ {\doifelsenothing{#2}
+ {\dodobuffer#3\jobname}
+ {\processcommalist[#2]{\dodobuffer#3}}}
+
+\def\dodobuffer#1#2% command name
+ {\pushmacro\currentbuffer
+ \edef\currentbuffer{\ifcsname\??bu#2\c!number\endcsname def-\csname\??bu#2\c!number\endcsname\else#2\fi}%
+ #1%
+ \popmacro\currentbuffer}
+
+\def\processTEXbuffer{\getbuffer} % handy
+
+% extras:
+
+\def\inspectbuffer
+ {\dosingleempty\doinspectbuffer}
+
+\def\doinspectbuffer[#1]%
+ {\setcurrentbuffer{#1}%
+ \ctxlua{buffers.inspect("\currentbuffer")}}
+
+% seldom used, only in a few projects that demanded more speed
+
+\let\usememorybuffers\relax
+\let\usefilebuffers \relax
+
+% this features is soldom used (complex examns where we need to fetch
+% special parts of a text
+%
+% this is not yet supported in mkiv (relatively easy to do but there
+% we don't have the par tags but need to grab 'm
+
+\def\skippedbufferparagraphs{0}
+
+\let\startbufferparagraph\relax
+\let\stopbufferparagraph \par % \relax
+
+\newcount\currentbufferparagraph
+
+\def\getbufferparagraphs
+ {\dodoubleempty\dogetbufferparagraphs}
+
+\def\dosetbufferoffset#1%
+ {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}
+ {\currentbufferparagraph-\getvalue{\??bu#1\c!paragraph}}
+ {\currentbufferparagraph \zerocount}%
+ \relax}
+
+\def\dogetbufferparagraphs[#1][#2]%
+ {\iffirstargument
+ \ifsecondargument
+ \dosetbufferoffset{#1}%
+ \doifelse{#2}\v!all
+ {\unexpanded\def\startbufferparagraph{\normalbufferparagraph{#1}}}
+ {\unexpanded\def\startbufferparagraph{\filterbufferparagraph{#1}{#2}}}%
+ \unexpanded\def\stopbufferparagraph{\dostopbufferparagraph{#1}}%
+ \def\next{\getparagraphedbuffer[#1]}%
+ \else
+ \dosetbufferoffset\empty
+ \unexpanded\def\startbufferparagraph{\filterbufferparagraph{}{#1}}%
+ \unexpanded\def\stopbufferparagraph{\dostopbufferparagraph{}}%
+ \def\next{\getparagraphedbuffer[]}%
+ \fi
+ \else
+ \dosetbufferoffset\empty
+ \unexpanded\def\startbufferparagraph{\normalbufferparagraph{}}%
+ \unexpanded\def\stopbufferparagraph{\dostopbufferparagraph{}}%
+ \def\next{\getparagraphedbuffer[]}%
+ \fi
+ \next}
+
+\def\dotypeparagraphbuffer{\ctxlua{buffers.get("\currentbuffer")}}
+
+\def\getparagraphedbuffer[#1]%
+ {\dobuffer{16}{#1}\dotypeparagraphbuffer}
+
+\def\dostopbufferparagraph#1%
+ {\getvalue{\??bu#1\c!after}\par}
+
+\def\dostartbufferparagraph#1%
+ {\par\getvalue{\??bu#1\c!before}}
+
+\def\normalbufferparagraph
+ {\advance\currentbufferparagraph \plusone
+ \ifnum\currentbufferparagraph>\zerocount
+ \expandafter\dostartbufferparagraph
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\filterbufferparagraph#1#2%
+ {\advance\currentbufferparagraph \plusone
+ \ifcase\currentbufferparagraph
+ \@EA\gobblebufferparagraph
+ \else
+ \doifinsetelse{\the\currentbufferparagraph}{#2}
+ {\@EA\dostartbufferparagraph}
+ {\@EA\fakebufferparagraph}%
+ \fi
+ {#1}}
+
+\long\def\gobblebufferparagraph#1#2\stopbufferparagraph
+ {}
+
+\def\fakebufferparagraph#1%
+ {\bgroup
+ \unexpanded\def\stopbufferparagraph{\dostopbufferparagraph{#1}\egroup\egroup}%
+ \setbox\scratchbox\vbox\bgroup\dostartbufferparagraph{#1}}
+
+% definitions
+
+\definebuffer[\v!hiding] \setupbuffer[\v!hiding][\c!local=\v!yes]
+
+\setupbuffer
+ [\c!paragraph=\v!no,
+ \c!before=,
+ \c!after=]
+
+% only mkiv:
+%
+% \startbuffer[x]
+% x
+% \stopbuffer
+%
+% \savebuffer[x][temp.log]
+
+\unexpanded\def\savebuffer{\dodoubleempty\dosavebuffer}
+
+\def\dosavebuffer[#1][#2]{\ctxlua{commands.savebuffer("#1","#2")}}
+
+\protect \endinput
diff --git a/tex/context/base/buff-ver.mkii b/tex/context/base/buff-ver.mkii
new file mode 100644
index 000000000..e7ad5474f
--- /dev/null
+++ b/tex/context/base/buff-ver.mkii
@@ -0,0 +1,1340 @@
+%D \module
+%D [ file=buff-ver, % was core-ver
+%D version=2000.05.09,
+%D title=\CONTEXT\ Buffer Macros,
+%D subtitle=Verbatim,
+%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 Buffer Macros / Verbatim}
+
+\unprotect
+
+\ifx\startlinenumbering\undefined \let\startlinenumbering\relax \fi
+\ifx\stoplinenumbering \undefined \let\stoplinenumbering\relax \fi
+\ifx\setuplinenumbering\undefined \def\setuplinenumbering[#1]{} \fi
+
+% \type{ char} geeft bagger
+
+%D We are going to embed the general verbatim support macros in
+%D a proper environment. First we show the common setup
+%D macro, so we know what features are supported. The options
+%D are hooked into the support macros via the \type{\obey}
+%D macros.
+
+\newif\ifslantedtypeactivated
+\newif\ifslantedtypepermitted
+
+\def\switchslantedtype
+ {\ifslantedtypepermitted
+ \ifslantedtypeactivated
+ \slantedtypeactivatedfalse\tttf
+ \else
+ \slantedtypeactivatedtrue\ttsl
+ \fi
+ \fi}
+
+\newprettytrue % movet to here from cont-sys.tex
+
+\def\prettyidentifier {TEX}
+\def\prettypalet {}
+
+\def\installprettytype
+ {\dodoubleargument\doinstallprettytype}
+
+\def\doinstallprettytype[#1][#2]% map #1 onto #2
+ {\uppercasestring#1\to\asciia
+ \uppercasestring#2\to\asciib
+ \setevalue{\??ty\??ty\asciia}{\asciib}}
+
+\def\setupprettiesintype#1%
+ {\uppercasestring#1\to\ascii
+ \edef\prettyidentifier{\executeifdefined{\??ty\??ty\ascii}{TEX}}%
+ \doifundefined{setuppretty\prettyidentifier type}%
+ {\startnointerference
+ \restorecatcodes % also needed when loading during \newpretty
+ \startreadingfile % restore < and > if needed
+ \lowercasestring verb-\prettyidentifier\to\filename
+ \readsysfile{\filename.mkii}\donothing\donothing
+ \stopreadingfile
+ \stopnointerference}%
+ \doifdefinedelse{setuppretty\prettyidentifier type}%
+ {\let\uncatcodecharacters\uncatcodeallcharacters % ugly, should be switch / todo
+ \def\dosetupprettytype{\getvalue{setuppretty\prettyidentifier type}}}
+ {\let\dosetupprettytype\relax}}
+
+\def\setupprettytype{\dosetupprettytype}
+
+% \def\setupcommonverbatim
+% {\recatcodeuppercharactersfalse % obey regime / encoding
+% %
+% \let\prettyidentifier\s!default
+% %
+% \doifelse{\typingparameter\c!text}\v!yes
+% \naturaltextexttrue
+% \naturaltextextfalse
+% \def\prettyidentifierfont{\typingparameter\c!icommand}%
+% \def\prettyvariablefont {\typingparameter\c!vcommand}%
+% \def\prettynaturalfont {\typingparameter\c!ccommand}%
+% %
+% \doif{\typingparameter\c!space}\v!on
+% {\def\obeyspaces{\setcontrolspaces}}%
+% \doif{\typingparameter\c!page }\v!no
+% {\def\obeypages {\ignorepages}}%
+% %
+% \doifelse{\typingparameter\c!tab}\v!yes
+% {\def\obeytabs{\settabskips}}%
+% {\doif{\typingparameter\c!tab}\s!ascii
+% {\chardef\tabskipmode\plustwo % quit on >127
+% \def\obeytabs{\settabskips}}}%
+% %
+% \ignorehyphens % default
+% \ExpandFirstAfter\processaction
+% [\typingparameter\c!lines]
+% [ \v!yes=>\obeybreakpoints,
+% \v!hyphenated=>\obeyhyphens]%
+% \processaction
+% [\typingparameter\c!empty]
+% [\v!yes=>\obeyemptylines,
+% \v!all=>\obeyallemptylines]%
+% %
+% \ExpandFirstAfter\processaction
+% [\typingparameter\c!option]
+% [ \v!none=>\let\obeycharacters\relax,
+% \v!color=>\setupprettiesintype{TEX}%
+% \let\obeycharacters\setupprettytype
+% \let\obeytabs\ignoretabs,
+% \v!normal=>\let\obeycharacters\setupgroupedtype,
+% \v!commands=>\def\obeycharacters{\setupcommandsintype}% \let
+% \let\obeytabs\ignoretabs,
+% \v!slanted=>\let\obeycharacters\setupslantedtype
+% \let\obeytabs\ignoretabs,
+% \s!unknown=>\setupprettiesintype{\typingparameter\c!option}%
+% \let\obeycharacters\setupprettytype
+% \let\obeytabs\ignoretabs]%
+% \doifnumberelse{\typingparameter\c!tab}
+% {\def\obeytabs{\setfixedtabskips{\typingparameter\c!tab}}}%
+% \donothing
+% %\def\verbatimfont{\typingparameter\c!style\normalnoligatures\font}%
+% % more generic, but beware of the \redoconvertfont (else no typing in titles and such)
+% \def\verbatimfont{\redoconvertfont\dosetfontattribute{\currenttypingclass\currenttyping}\c!style\normalnoligatures\font}%
+% \setupverbatimcolor}
+
+\setvalue{\??tp:\c!lines:\v!yes }{\obeybreakpoints}
+\setvalue{\??tp:\c!lines:\v!hyphenated}{\obeyhyphens}
+
+\setvalue{\??tp:\c!empty:\v!yes }{\obeyemptylines}
+\setvalue{\??tp:\c!empty:\v!all }{\obeyallemptylines}
+
+\setvalue{\??tp:\c!option:\v!none }{\let\obeycharacters\relax}
+\setvalue{\??tp:\c!option:\v!color }{\setupprettiesintype{TEX}%
+ \let\obeycharacters\setupprettytype
+ \let\obeytabs\ignoretabs}
+\setvalue{\??tp:\c!option:\v!normal }{\let\obeycharacters\setupgroupedtype}
+\setvalue{\??tp:\c!option:\v!commands }{\def\obeycharacters{\setupcommandsintype}%
+ \let\obeytabs\ignoretabs}
+\setvalue{\??tp:\c!option:\v!slanted }{\let\obeycharacters\setupslantedtype
+ \let\obeytabs\ignoretabs}
+\setvalue{\??tp:\c!option:\s!unknown }{\setupprettiesintype{\typingparameter\c!option}%
+ \let\obeycharacters\setupprettytype
+ \let\obeytabs\ignoretabs}
+
+\def\setupcommonverbatim
+ {\recatcodeuppercharactersfalse % obey regime / encoding
+ %
+ \let\prettyidentifier\s!default
+ %
+ \doifelse{\typingparameter\c!text}\v!yes
+ \naturaltextexttrue
+ \naturaltextextfalse
+ \def\prettyidentifierfont{\typingparameter\c!icommand}%
+ \def\prettyvariablefont {\typingparameter\c!vcommand}%
+ \def\prettynaturalfont {\typingparameter\c!ccommand}%
+ %
+ \doif{\typingparameter\c!space}\v!on
+ {\def\obeyspaces{\setcontrolspaces}}%
+ \doif{\typingparameter\c!page }\v!no
+ {\def\obeypages {\ignorepages}}%
+ %
+ \doifelse{\typingparameter\c!tab}\v!yes
+ {\def\obeytabs{\settabskips}}%
+ {\doif{\typingparameter\c!tab}\s!ascii % not needed in mkiv
+ {\chardef\tabskipmode\plustwo % quit on >127
+ \def\obeytabs{\settabskips}}}%
+ %
+ \ignorehyphens % default
+ \getvalue{\??tp:\c!lines:\typingparameter\c!lines}%
+ \getvalue{\??tp:\c!empty:\typingparameter\c!empty}%
+ \getvalue{\??tp:\c!option:\ifcsname\??tp:\c!option:\typingparameter\c!option\endcsname\typingparameter\c!option\else\s!unknown\fi}%
+ \doifnumberelse{\typingparameter\c!tab}
+ {\def\obeytabs{\setfixedtabskips{\typingparameter\c!tab}}}%
+ \donothing
+ %\def\verbatimfont{\typingparameter\c!style\normalnoligatures\font}%
+ % more generic, but beware of the \redoconvertfont (else no typing in titles and such)
+ \def\verbatimfont{\redoconvertfont\dosetfontattribute{\currenttypingclass\currenttyping}\c!style\normalnoligatures\font}%
+ \setupverbatimcolor}
+
+% BEWARE: the noligatures will globally change the verbatim font's behaviour
+
+% test case:
+%
+% \definetype[typeTEX][option=tex]
+%
+% \typeTEX|\example---oeps|. this---ligates---again.
+% \typeTEX{\example---oeps}. this---ligates---again.
+% \type {\example---oeps}. this---ligates---again.
+
+\def\setupcommandsintype % can also be \string\
+ {\setupgroupedtype
+ \edef\\{\typingparameter\c!escape}%
+ \letvalue{\\}=\\% for instance \/=/
+ \@EA\catcode\@EA`\\=\@@escape
+ \def\BTEX##1\ETEX##2% ##2 gobbles active space
+ {\naturaltextext##1\unskip\relax}}
+
+\def\setupslantedtype
+ {\slantedtypepermittedtrue\setupgroupedtype}
+
+\ifx\setupprettytype \undefined \let\setupprettytype \relax \fi
+\ifx\setupslantedtype \undefined \let\setupslantedtype \relax \fi
+\ifx\setupgroupedtype \undefined \let\setupgroupedtype \relax \fi
+\ifx\normalnoligatures\undefined \let\normalnoligatures\gobbleoneargument \fi
+
+%D The verbatim commands have a rather long and turbulent
+%D history. Most users of \CONTEXT\ probably will never use
+%D some of the features, but I've kept in mind that when one is
+%D writing a users manual, about everything can and undoubtly
+%D will be subject to a verbatim treatment.
+%D
+%D Verbatim command are very sensitive to argument processing,
+%D which is a direct result of the \CATCODES\ being fixed at
+%D reading time. With our growing understanding of \TEX,
+%D especially of the mechanism that can be used for looking
+%D ahead and manipulating \CATCODES, the verbatim support
+%D became more and more advanced and natural.
+%D
+%D Typesetting inline verbatim can be accomplished by
+%D \type{\type}, which in this sentence was typeset by saying
+%D just \type{\type{\type}}, which in turn was typeset by
+%D \unknown. Using the normal grouping characters \type{{}} is
+%D the most natural way of using this command.
+%D
+%D A second, more or less redundant, alternative is delimiting
+%D the argument with an own character. This method was
+%D implemented in the context of a publication in the \MAPS,
+%D where this way of delimiting is recognized by \LATEX\ users.
+%D
+%D The third, more original alternative, is the one using
+%D \type{<<} and \type{>>} as delimiters. This alternative can
+%D be used in situations where slanted typeseting is needed.
+
+% todo: we can use \letter... here:
+
+\def\lesscharacter {<}
+\def\morecharacter {>}
+
+\chardef\texescape = `\\
+\chardef\leftargument = `\{
+\chardef\rightargument = `\}
+
+%D \macros
+%D {type}
+%D
+%D We define \type{\type} as a protected command. This command
+%D has several invocations: grouped, wirt boundary characters,
+%D and with font switches.
+
+% \starttyping
+% normal: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \par
+% normal: \par \type{xx<..xx.. >..>xx} \par \type{<....>} \par \type{<....>}
+% \setuptype[option=slanted]
+% slanted: \par \type{xx<<..sl..<> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<>..>> \par
+% slanted: \par \type{xx<<..sl.. xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<....>> \par
+% \setuptype[option=none]
+% none: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \par
+% \stoptyping
+
+%D When writing the manual to \CONTEXT\ and documenting this
+%D source we needed to typeset \type{<<} and \type{>>}. Because
+%D we wanted to do this in the natural way, we've adapted the
+%D original definition a bit. This implementation went through
+%D several live cycles. The final implementation looks a bit
+%D further and treats the lone \type{<<} and \type{>>} a bit
+%D different. The \type {\null} prevents ligatures, which
+%D unfortunately turn up in Lucida fonts.
+
+%D The following lines show what happens when we set
+%D \type {option=commands}.
+%D
+%D \startbuffer
+%D \starttyping
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test test test/BTEX \bf(nota bene)/ETEX test
+%D test test test /BTEX \bf(nota bene)/ETEX test
+%D \stoptyping
+%D \stopbuffer
+%D
+%D % \bgroup\setuptyping[option=commands]\getbuffer\egroup
+%D
+%D this was keyed in as:
+%D
+%D \typebuffer
+
+\unexpanded\def\type{\dotype\empty}
+
+% not that fast but catches \type{\command} % nothing more after \command
+%
+% \setupcolors[state=start]
+% \setuptype[option=TEX]
+% \setupcolors[textcolor=red]
+%
+% The options \type{before=\startsolutionbackground } and
+% \type{after=\stopsolutionbackground} take care of putting a frame,
+% which can
+%
+% {\blue The options \type{before=\startsolutionbackground } and
+% \type{after=\stopsolutionbackground} take care of putting a frame,
+% which} can
+
+\def\resumecoloraftergroup
+ {\localstartcolor[\s!black]%
+ \localstartcolor[\maintextcolor]%
+ \aftergroup\localstopcolor
+ \aftergroup\localstopcolor}
+
+% the rather messy \type command
+
+\def\dotype#1% was \dotype
+ {\bgroup
+ \resumecoloraftergroup % a problem is that we can still be in color mode, tricky hack
+ \begstrut % new, enables leading space in \type { abc } at par start / begstrut else no hyphenation
+ \let\currenttypingclass\??ty
+ \edef\currenttyping{#1}%
+ \catcode`\<=\@@other
+ \catcode`\>=\@@other
+ \futurelet\next\dodotype}
+
+\def\dodotypeA
+ {\initializetype
+ \initializetypegrouping
+ \verbatimfont
+ \verbatimcolor
+ \afterassignment\protectfirsttype\let\next=}
+
+\def\dodotypeB
+ {\initializetype
+ \setupnotypegrouping
+ \verbatimfont
+ \verbatimcolor
+ \let\next=}
+
+\def\dodotypeC<#1%
+ {\initializetype
+ \verbatimfont
+ \verbatimcolor
+ \if#1<%
+ \@EA\setupalternativetypegrouping
+ \else
+ \@EA#1%
+ \fi}
+
+\def\dodotypeD#1%
+ {\initializetype
+ \verbatimfont
+ \verbatimcolor
+ \catcode`#1=\@@endgroup}
+
+\def\dodotype
+ {\ifx\next\bgroup
+ \@EA\dodotypeA
+ \else\if\next<%
+ \doifelse{\typingparameter\c!option}\v!none
+ {\@EAEAEA\dodotypeB}{\@EAEAEA\dodotypeC}%
+ \else
+ \@EAEAEA\dodotypeD
+ \fi\fi}
+
+% The next one is safe for: \def\xx#1{\type{#1}} \xx{\ifx}
+
+\let\protectedfirsttype\string % \relax for special cases
+
+\bgroup
+\catcode`\<=\active
+\catcode`\>=\active
+\gdef\doprotectfirsttype
+ {\normalifx\next<%
+ \endrobusttest \let\next\relax
+ \normalelse\normalifx\next\bgroup
+ \endrobusttest \let\next\relax
+ \normalelse\normalifx\next\egroup % takes care of \type{}
+ \endrobusttest \let\next\relax
+ \normalelse\normalifx\next\activeleftargument
+ \endrobusttest \let\next\relax
+ \normalelse
+ \endrobusttest \let\next\protectedfirsttype
+ \normalfi\normalfi\normalfi\normalfi
+ \next}
+\egroup
+
+\def\protectfirsttype
+ {\beginrobusttest
+ \futurelet\next\doprotectfirsttype}
+
+% Verbatim does not work when passed as an argument, so here is a
+% workaround. Beware, spaces are introduced after a \type {\csname}.
+
+\chardef\recodeverbatimmode\zerocount % 0=nothing 1=rescan 2=autorescan
+
+% \appendtoks \chardef\recodeverbatimmode\plustwo \to \everytabulate
+% \appendtoks \chardef\recodeverbatimmode\plustwo \to \everytable
+
+\def\dodotypeA
+ {\initializetype
+ \initializetypegrouping
+ \verbatimfont
+ \verbatimcolor
+ \ifcase\recodeverbatimmode
+ \@EA\dodotypeAA
+ \or
+ \@EA\dodotypeAB
+ \or
+ \ifnum\catcode`\{=\@@active
+ \@EAEAEA\dodotypeAB
+ \else
+ \@EAEAEA\dodotypeAA
+ \fi
+ \else
+ \@EA\dodotypeAA
+ \fi}
+
+\def\dodotypeAA
+ {\afterassignment\protectfirsttype\let\next=}
+
+\def\dodotypeAB
+ {\bgroup
+ \catcode`\}=\@@endgroup
+ \catcode`\{=\@@begingroup
+ \afterassignment\redotypeAB\global\globalscratchtoks}
+
+\def\redotypeAB
+ {\egroup
+ \expandafter\defconvertedargument\expandafter\ascii\expandafter{\the\globalscratchtoks}% == \edefconvertedargument\ascii{\the\globalscratchtoks}%
+ \ifx\scantokens\undefined\ascii\else\everyeof{\hskip-\spaceskip}\scantokens\expandafter{\ascii}\fi
+ \egroup}
+
+\bgroup
+\catcode`\[=\@@begingroup
+\catcode`\]=\@@endgroup
+\catcode`\{=\@@active
+\catcode`\}=\@@active
+\gdef\initializetypegrouping
+ [\ifnum\catcode`\{=\@@active
+ \let\normalactivebgroup{%
+ \let\normalactiveegroup}%
+ \else
+ \catcode`\{=\@@active
+ \catcode`\}=\@@active
+ \let\normalactivebgroup\leftargument
+ \let\normalactiveegroup\rightargument
+ \fi
+ \def\activeleftargument
+ [\bgroup
+ \catcode`\}=\@@active
+ \let}\activerightargument
+ \normalactivebgroup]%
+ \def\activerightargument
+ [\normalactiveegroup
+ \egroup]%
+ \let{=\activeleftargument
+ % not \let}=\egroup, otherwise things go wrong in alignments (???)
+ \catcode`\}=\@@endgroup]
+\egroup
+
+\bgroup
+\catcode`\<=\@@active
+\catcode`\>=\@@active
+\gdef\setupalternativetypegrouping
+ {\catcode`\<=\@@active
+ \catcode`\>=\@@active
+ \def\doless
+ {\ifx<\next
+ \def\next
+ {\bgroup\switchslantedtype
+ \let\next=}%
+ \else
+ \let\next\lesscharacter
+ \fi
+ \next}%
+ \def\domore
+ {\ifx>\next
+ \def\next
+ {\egroup
+ \let\next=}%
+ \else
+ \let\next\morecharacter
+ \fi
+ \next}%
+ \def<{\futurelet\next\doless}%
+ \def>{\futurelet\next\domore}}
+\egroup
+
+\def\setupnotypegrouping
+ {\catcode`\<=\@@begingroup
+ \catcode`\>=\@@endgroup}
+
+\def\doenterdoublelesstype
+ {\ifx\next\egroup
+ \lesscharacter\null\lesscharacter
+ \else
+ \bgroup\switchslantedtype
+ \let\doenterdoublemoretype\egroup
+ \fi}
+
+\def\doenterdoublemoretype
+ {\def\doenterdoubletype
+ {\ifx\next\egroup
+ \morecharacter\null\morecharacter
+ \fi}}
+
+\bgroup
+\catcode`\<=\@@active
+\catcode`\>=\@@active
+\gdef\setupgroupedtype
+ {\catcode`\<=\@@active
+ \catcode`\>=\@@active
+ \def\doless
+ {\ifx<\next
+ \def\next
+ {\def\enterdoubletype{\futurelet\next\doenterdoublelesstype}%
+ \afterassignment\enterdoubletype
+ \let\next=}%
+ \else
+ \let\next\lesscharacter
+ \fi
+ \next}%
+ \def\domore
+ {\ifx>\next
+ \def\next
+ {\def\enterdoubletype{\futurelet\next\doenterdoublemoretype}%
+ \afterassignment\enterdoubletype
+ \let\next=}%
+ \else
+ \let\next\morecharacter
+ \fi
+ \next}%
+ \def<{\futurelet\next\doless}%
+ \def>{\futurelet\next\domore}}
+\egroup
+
+%D The neccessary initializations are done by calling
+%D \type{\initializetype} which in return calls for the support
+%D macro \type{\setupinlineverbatim}.
+
+\def\initializetype
+ {\let\obeylines\ignorelines
+ \setupcommonverbatim
+ \setupinlineverbatim}
+
+%D \macros
+%D {setuptype}
+%D
+%D Some characteristics of \type{\type} can be set up by:
+
+\def\setuptype
+ {\dodoubleempty\dosetuptype}
+
+\def\dosetuptype[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??ty#1][#2]%
+ \else
+ \getparameters[\??ty][#1]%
+ \fi}
+
+%D \macros
+%D {typ,obeyhyphens,obeybreakpoints}
+%D
+%D Although it's not clear from the macros, one character
+%D trait of this macros, which are build on top of the support
+%D module, is that they don't hyphenate. We therefore offer
+%D the alternative \type{\typ}. The current implementation
+%D works all right, but a decent hyphenation support of
+%D \type{\tt} text will be implemented soon.
+
+\def\obeyhyphens
+ {\def\obeyedspace {\hskip\interwordspace\relax}% better than spaceskip
+ \def\controlspace{\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\relax}%
+ \spaceskip.25em\relax} % hm a bit of stretch !
+
+\def\obeybreakpoints
+ {\ignorehyphens
+ \veryraggedright}
+
+\def\ignorehyphens
+ {% \nohyphens % forgotten when no \par
+ \normallanguage\minusone % fails as the font redoes the language
+ \def\obeyedspace {\hskip\interwordspace\relax}% better than spaceskip
+ \def\controlspace{\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\relax}%
+ \spaceskip.5em\relax}
+
+
+\unexpanded\def\typ
+ {\bgroup
+ \let\@@tylines\v!hyphenated
+ \futurelet\next\dodotype}
+
+%D \macros
+%D {tex,arg,mat,dis}
+%D
+%D Sometimes, for instance when we pass verbatim text as an
+%D argument, the fixed \CATCODES\ interfere with our wishes. An
+%D experimental implementation of character by character
+%D processing of verbatim text did overcome this limitation,
+%D but we've decided not to use that slow and sometimes
+%D troublesome solution. Instead we stick to some 'old'
+%D \CONTEXT\ macros for typesetting typical \TEX\ characters.
+%D
+%D The next implementation is more clear but less versatile,
+%D so we treated it for a beter one.
+%D
+%D \starttyping
+%D \def\dospecialtype#1#2%
+%D {\bgroup
+%D \initializetype
+%D \catcode`\{=\@@begingroup
+%D \catcode`\}=\@@endgroup
+%D \def\dospecialtype%
+%D {\def\dospecialtype{#2\egroup}%
+%D \bgroup
+%D \aftergroup\dospecialtype
+%D #1}%
+%D \afterassignment\dospecialtype
+%D \let\next=}
+%D
+%D \unexpanded\def\tex{\dospecialtype\texescape\relax}
+%D \unexpanded\def\arg{\dospecialtype\leftargument\rightargument}
+%D \unexpanded\def\mat{\dospecialtype\$\$}
+%D \unexpanded\def\dis{\dospecialtype{\$\$}{\$\$}}
+%D \stoptyping
+
+\def\setgroupedtype
+ {\let\currenttypingclass\??ty
+ \initializetype
+ \verbatimcolor
+ %\setcatcodetable \typcatcodesa
+ \catcode`\{=\@@begingroup
+ \catcode`\}=\@@endgroup}
+
+\unexpanded\def\tex{\groupedcommand{\setgroupedtype\texescape}{\relax}}
+\unexpanded\def\arg{\groupedcommand{\setgroupedtype\leftargument}{\rightargument}}
+\unexpanded\def\mat{\groupedcommand{\setgroupedtype\$}{\$}}
+\unexpanded\def\dis{\groupedcommand{\setgroupedtype\$\$}{\$\$}}
+
+\let\normaltexttex\tex
+\let\normaltextarg\arg
+\let\normaltextmat\mat
+\let\normaltextdis\dis
+
+%D \macros
+%D {starttyping}
+%D
+%D Display verbatim is realized far more easy, which is mostly
+%D due to the fact that we use \type{\stop...} as delimiter.
+%D The implementation inherits some features, for instance the
+%D support of linenumbering, which can best be studied in the
+%D documented support module.
+
+\let\currenttyping \empty
+\let\currenttypingclass\??ty % saveguard
+
+% \def\typingparameter#1%
+% {\executeifdefined
+% {\currenttypingclass\currenttyping#1}%
+% {\executeifdefined{\currenttypingclass#1}\empty}}
+
+\def\typingparameter#1%
+ {\ifcsname\currenttypingclass\currenttyping#1\endcsname
+ \csname\currenttypingclass\currenttyping#1\endcsname
+ \else\ifcsname\currenttypingclass#1\endcsname
+ \csname\currenttypingclass#1\endcsname
+ \fi\fi}
+
+\def\settypingparameter#1#2%
+ {\setvalue{\currenttypingclass\currenttyping#1}{#2}}
+
+\def\setxtypingparameter#1#2%
+ {\setxvalue{\currenttypingclass\currenttyping#1}{#2}}
+
+% \def\initializetyping
+% {%\donefalse
+% \switchtobodyfont[\typingparameter\c!bodyfont]%
+% \donefalse
+% \scratchskip\typingparameter\c!oddmargin\relax
+% \ifzeropt\scratchskip\else\donetrue\fi
+% \scratchskip\typingparameter\c!evenmargin\relax
+% \ifzeropt\scratchskip\else\donetrue\fi
+% \ifdone
+% \def\doopenupverbatimline
+% {\getpagestatus
+% \ifrightpage
+% \hskip\typingparameter\c!oddmargin\relax
+% \else
+% \hskip\typingparameter\c!evenmargin\relax
+% \fi}%
+% \else
+% \doadaptleftskip{\typingparameter\c!margin}%
+% \fi
+% \doifdefinedelse{\??bo\typingparameter\c!blank}
+% {\edef\!!stringa{\csname\??bo\typingparameter\c!blank\endcsname}}
+% {\edef\!!stringa{\typingparameter\c!blank}}%
+% \processaction
+% [\!!stringa]
+% [ \v!standard=>\scratchskip\ctxparskip,
+% \v!small=>\scratchskip\blankokleinmaat,
+% \v!medium=>\scratchskip\blankomiddelmaat,
+% \v!big=>\scratchskip\blankogrootmaat,
+% \v!halfline=>\scratchskip.5\baselineskip,
+% \v!line=>\scratchskip\baselineskip,
+% \v!none=>\scratchskip\zeropoint,
+% \s!unknown=>\scratchskip\commalistelement]%
+% \ifgridsnapping
+% \ifdim\scratchskip=.5\baselineskip\relax
+% \edef\verbatimbaselineskip{\the\scratchskip}% new
+% \else
+% \edef\verbatimbaselineskip{\the\baselineskip}%
+% \fi
+% \else
+% \edef\verbatimbaselineskip{\the\scratchskip}%
+% \fi
+% \setupcommonverbatim}
+
+\setvalue{\??tp:\c!blank:\v!standard}{\ctxparskip}
+\setvalue{\??tp:\c!blank:\v!small }{\blankokleinmaat}
+\setvalue{\??tp:\c!blank:\v!medium }{\blankomiddelmaat}
+\setvalue{\??tp:\c!blank:\v!big }{\blankogrootmaat}
+\setvalue{\??tp:\c!blank:\v!halfline}{.5\baselineskip}
+\setvalue{\??tp:\c!blank:\v!line }{\baselineskip}
+\setvalue{\??tp:\c!blank:\v!none }{\zeropoint}
+
+\def\initializetyping
+ {%\donefalse
+ \switchtobodyfont[\typingparameter\c!bodyfont]%
+ \donefalse
+ \scratchskip\typingparameter\c!oddmargin\relax
+ \ifzeropt\scratchskip\else\donetrue\fi
+ \scratchskip\typingparameter\c!evenmargin\relax
+ \ifzeropt\scratchskip\else\donetrue\fi
+ \ifdone
+ \def\doopenupverbatimline
+ {\getpagestatus
+ \ifrightpage
+ \hskip\typingparameter\c!oddmargin\relax
+ \else
+ \hskip\typingparameter\c!evenmargin\relax
+ \fi}%
+ \else
+ \doadaptleftskip{\typingparameter\c!margin}%
+ \fi
+ \edef\!!stringa{\executeifdefined{\??bo\typingparameter\c!blank}{\typingparameter\c!blank}}%
+ \scratchskip\executeifdefined{\??tp:\c!blank:\!!stringa}\!!stringa\relax
+ \ifgridsnapping
+ \ifdim\scratchskip=.5\baselineskip\relax
+ \edef\verbatimbaselineskip{\the\scratchskip}% new
+ \else
+ \edef\verbatimbaselineskip{\the\baselineskip}%
+ \fi
+ \else
+ \edef\verbatimbaselineskip{\the\scratchskip}%
+ \fi
+ \setupcommonverbatim}
+
+%D The basic display verbatim commands are defined in an
+%D indirect way. As we will see, they are a specific case of a
+%D more general mechanism.
+
+% we need this hack because otherwise verbatim skips
+% the first line (everything after the initial command)
+
+\def\dostarttyping#1% tricky non standard lookahead
+ {\bgroup
+ \let\currenttypingclass\??tp
+ \edef\currenttyping{#1}%
+ \obeylines
+ \futurelet\nexttoken\dodostarttyping}
+
+\def\dodostarttyping
+ {\ifx\nexttoken[%
+ \expandafter\dododostarttyping
+ \else
+ \expandafter\nododostarttyping
+ \fi}
+
+\def\nododostarttyping
+ {\dododostarttyping[]}
+
+\def\dododostarttyping[#1]%
+ {\typingparameter\c!before
+ \startpacked % includes \bgroup
+ \dosetuptypelinenumbering{#1}%
+ \initializetyping
+ \startverbatimcolor
+ \expanded{\processdisplayverbatim{\s!stop\currenttyping}}}
+
+\def\dostoptyping#1% hm, currenttyping
+ {\stopverbatimcolor
+ \stoppacked % includes \egroup
+ \typingparameter\c!after
+ \egroup
+ \dochecknextindentation{\??tp#1}%
+ \dorechecknextindentation}
+
+%D Line numbering for files is combined with filtering, while
+%D display verbatim has the ability to continue.
+%D
+%D \starttyping
+%D \typefile[numbering=file,start=10,stop=12]{test.tex}
+%D
+%D \definetyping[code][numbering=line]
+%D
+%D \starttext
+%D \startcode
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[continue]
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[start=10]
+%D ...
+%D \stopcode
+%D \stoptyping
+
+%D \macros
+%D {setuptyping}
+%D
+%D The setup of typing accepts two arguments. The optional
+%D first one identifies the user defined ones. If only one
+%D argument is given, the values apply to both the standard
+%D command \type{\starttyping} and \type{\typefile}.
+
+\def\dosetuptyping[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??tp#1][#2]%
+ \else
+ \getparameters[\??tp][#1]%
+ \fi}
+
+\def\setuptyping
+ {\dodoubleempty\dosetuptyping}
+
+%D \macros
+%D {definetype}
+%D
+%D Specific inline verbatim commands can be defined with the
+%D following command.
+
+\def\definetype
+ {\dodoubleempty\dodefinetype}
+
+\def\dodefinetype[#1][#2]%
+ {\unexpanded\setvalue{#1}{\dotype{#1}}%
+ \getparameters[\??ty#1][#2]}
+
+%D \macros
+%D {definetyping}
+%D
+%D For most users the standard \type{\start}||\type{\stop}||pair
+%D will suffice, but for documentation purposes the next
+%D definition command can be of use:
+%D
+%D \starttyping
+%D \definetyping[extratyping][margin=3em]
+%D
+%D \startextratyping
+%D these extra ones are indented by 1 em
+%D \stopextratyping
+%D \stoptyping
+%D
+%D The definitions default to the standard typing values.
+
+\def\presettyping[#1][#2]%
+ {\copyparameters[\??tp#1][\??tp][\c!color,\c!style]%
+ \getparameters [\??tp#1][#2]}
+
+\def\dodefinetyping[#1][#2]%
+ {\setvalue{\e!start#1}{\dostarttyping{#1}}%
+ \setvalue{\e!stop #1}{\dostoptyping {#1}}%
+ \presettyping[#1][#2]}
+
+\def\definetyping
+ {\dodoubleempty\dodefinetyping}
+
+%D We can use some core color commands. These are faster than
+%D the standard color switching ones and work ok on a line by
+%D line basis.
+%D
+%D \starttyping
+%D \def\setupverbatimcolor%
+%D {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}%
+%D \def\beginofpretty[##1]{\startcolormode{\prettypalet:##1}}%
+%D \def\endofpretty {\stopcolormode}}
+%D \stoptyping
+%D
+%D Since we support a global color too, the folowing
+%D definition is better:
+
+% \def\setupverbatimcolor% fast and local versus slow and global
+% {\doifelsenothing{\typingparameter\c!color}
+% {\def\beginofpretty[##1]{\startcolormode{\prettypalet:##1}}%
+% \let\endofpretty \restorecolormode % \stopcolormode
+% \let\startverbatimcolor \relax
+% \let\stopverbatimcolor \relax
+% \let\verbatimcolor \relax}
+% {\def\beginofpretty[##1]{\startcolor[\prettypalet:##1]}%
+% \let\endofpretty \stopcolor
+% \def\startverbatimcolor{\startcolor[\typingparameter\c!color]}%
+% \let\stopverbatimcolor \stopcolor
+% \def\verbatimcolor {\getvalue{\typingparameter\c!color}}}% command !
+% \doifelsenothing{\typingparameter\c!palet}
+% {\let\prettypalet\empty
+% \let\endofpretty\relax
+% \def\beginofpretty[##1]{}}
+% {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}}}
+%
+% let's forget about this optimization not that we have mkiv
+
+\def\setupverbatimcolor
+ {\def\beginofpretty[##1]{\startcolor[\prettypalet:##1]}%
+ \let\endofpretty \stopcolor
+ \def\startverbatimcolor{\startcolor[\typingparameter\c!color]}%
+ \let\stopverbatimcolor \stopcolor
+ \def\verbatimcolor {\getvalue{\typingparameter\c!color}}% command !
+ \doifelsenothing{\typingparameter\c!palet}
+ {\let\prettypalet\empty
+ \let\endofpretty\relax
+ \def\beginofpretty[##1]{}}
+ {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}}}
+
+\let\prettypalet \empty
+\let\startverbatimcolor\relax
+\let\stopverbatimcolor \relax
+\let\verbatimcolor \relax
+
+%D In the verbatim module, there are some examples given of
+%D the more obscure features of the verbatim environments.
+%D
+%D \startbuffer
+%D \startTEX
+%D \def\mathematics#1% % usage: \type {\mathematics{x^2}}
+%D {\ifmmode#1\else$#1$\fi} % becomes: \mathematics{x^2}
+%D \stopTEX
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D This gives, as can be expected:
+%D
+%D \getbuffer
+%D
+%D When we want to see some typeset \TEX\ too, we can say:
+%D
+%D \startbuffer
+%D \startTEX
+%D \def\mathematics#1% %%\ N usage: \type {\mathematics{x^2}}
+%D {\ifmmode#1\else$#1$\fi} %%\ N becomes: \mathematics{x^2}
+%D \stopTEX
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or:
+%D
+%D \getbuffer
+%D
+%D In a similar way:
+%D
+%D \startbuffer
+%D \startSQL
+%D select * -- indeed, here we {\em do} select
+%D from tableA
+%D where 1 = 2
+%D \stopSQL
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives:
+%D
+%D \getbuffer
+%D
+%D The next examples sow how we can directly call for natural
+%D \TEX\ comments:
+%D
+%D \startbuffer
+%D \setuptyping
+%D [TEX]
+%D [text=yes]
+%D
+%D \startTEX
+%D \def\mathematics#1% % usage: \type {\mathematics{x^2}}
+%D {\ifmmode#1\else$#1$\fi} % becomes: \mathematics{x^2}
+%D \stopTEX
+%D
+%D \setuptyping
+%D [SQL]
+%D [text=yes,palet=,icommand=\bf,vcommand=,ccommand=\it]
+%D
+%D \startSQL
+%D select * -- indeed, here we {\em do} select
+%D from tableA
+%D where 1 = 2
+%D \stopSQL
+%D
+%D \setuptyping
+%D [SQL]
+%D [ccommand=\tf\underbar]
+%D
+%D \startSQL
+%D select * -- indeed, here we {\em do} select
+%D from tableA
+%D where 1 = 2
+%D \stopSQL
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Now watch:
+%D
+%D \getbuffer
+%D
+%D The natural \TEX\ typesetting was introduced when Tobias
+%D and Berend started using verbatim \JAVASCRIPT\ and \SQL.
+
+%D \macros
+%D {EveryPar, EveryLine, iflinepar}
+%D
+%D One of the features of these commands is the support of
+%D \type{\EveryPar}, \type{\EveryLine} and \type{\iflinepar}.
+%D In the documentation of the verbatim support module we give
+%D some examples of line- and paragraph numbering using these
+%D macros.
+
+%D \macros
+%D {typefile}
+%D
+%D Typesetting files verbatim (for the moment) only supports
+%D colorization of \TEX\ sources as valid option. The other
+%D setup values are inherited from display verbatim.
+%D The implementation of \type{\typefile} is straightforward:
+
+% new feature (not yet 100\% ok)
+%
+% \setuptyping[file][numbering=file]
+%
+% \typefile[start=2,nlines=3]{zapf}
+% \typefile[start=continue,nlines=13]{zapf}
+% \typefile{zapf}
+%
+% \setuptyping[file][numbering=line]
+%
+% \typefile[start=4,step=3]{zapf}
+% \typefile{zapf}
+
+\def\typefile
+ {\dodoubleempty\dotypefile}
+
+\def\dotypefile[#1][#2]#3%
+ {\ifsecondargument
+ \dodotypefile[#1][#2]{#3}%
+ \else\iffirstargument
+ \doifassignmentelse{#1}
+ {\dodotypefile[\v!file][#1]{#3}}
+ {\dodotypefile[#1][]{#3}}%
+ \else
+ \dodotypefile[\v!file][]{#3}%
+ \fi\fi}
+
+\def\dosetuptypelinenumbering#1% fuzzy
+ {\doifundefined{\currenttypingclass\currenttyping\c!start}
+ {\setuptyping[\currenttyping][\c!start=1,\c!stop=,\c!step=1,\c!nlines=]}%
+ \setuptyping[\currenttyping][#1]%
+ \doifelse{\typingparameter\c!numbering}\v!file
+ {% kind of special: filters lines !
+ \setuplinenumbering[\c!method=\v!file]%
+ \donetrue}
+ {\doifelse{\typingparameter\c!numbering}\v!line
+ {% \setuplinenumbering defaults start/step to 1/1, so we need
+ \doifinsetelse\v!continue{#1,\typingparameter\c!start}
+ {\scratchcounter0\typingparameter\c!n
+ \setxtypingparameter\c!start{\ifnum\scratchcounter=0 1\else\number\scratchcounter\fi}}%
+ {\doifnothing{\typingparameter\c!start}{\settypingparameter\c!start{1}}}%
+ \doifnothing{\typingparameter\c!step}{\settypingparameter\c!step{1}}%
+ \setuplinenumbering
+ [\c!method=\v!type,
+ \c!start=\typingparameter\c!start,
+ \c!stop=\typingparameter\c!stop,
+ \c!step=\typingparameter\c!step]%
+ \donetrue}
+ {\donefalse}}%
+ \ifdone
+ \ifx\startlinenumbering\undefined \let\startlinenumbering\relax \fi
+ \ifx\stoplinenumbering \undefined \let\stoplinenumbering \relax \fi
+ \def\beginofverbatimlines{\startlinenumbering}%
+ \def\endofverbatimlines {\stoplinenumbering\setxtypingparameter\c!n{\number\linenumber}}%
+ \fi}
+
+\def\reporttypingerror#1% temp hack
+ {\blank
+ \dontleavehmode\hbox\bgroup
+ \expanded{\defconvertedargument\noexpand\ascii{#1}}%
+ \tttf[\makemessage\m!verbatims1\ascii]%
+ \showmessage\m!verbatims1\ascii
+ \egroup
+ \blank}
+
+\def\dosometyping#1#2#3#4#5%
+ {\bgroup
+ \let\currenttypingclass\??tp
+ \edef\currenttyping{#1}%
+ \typingparameter\c!before
+ \startpacked % includes \bgroup
+ \dosetuptypelinenumbering{#2}%
+ \doifinset{\typingparameter\c!option}{\v!commands,\v!slanted,\v!normal}
+ {\setuptyping[#1][\c!option=\v!none]}%
+ \doif{\typingparameter\c!option}\v!color
+ {\expandafter\aftersplitstring#3\at.\to\prettyidentifier
+ \settypingparameter\c!option{\prettyidentifier}}%
+ \initializetyping
+ \startverbatimcolor
+ \doifundefinedelse{\currenttypingclass#3\v!global\c!start}
+ {\scratchcounter\zerocount}
+ {\scratchcounter\getvalue{\currenttypingclass#3\v!global\c!start}}%
+ \advance\scratchcounter\plusone
+ \setxvalue{\currenttypingclass#3\v!global\c!start}{\the\scratchcounter}%
+ \doifelsenothing{\typingparameter\c!start}
+ {#4}
+ {\doif{\typingparameter\c!start}\v!continue
+ {\setevalue{\currenttypingclass#1\c!start}%
+ {\getvalue{\currenttypingclass#3\v!global\c!start}}}%
+ \doifelsenothing{\typingparameter\c!stop}
+ {\doifelsenothing{\typingparameter\c!nlines}
+ {#4}
+ {\setxvalue{\currenttypingclass#3\v!global\c!start}%
+ {\the\numexpr\typingparameter\c!start+\typingparameter\c!nlines+\minusone\relax}%
+ #5{\typingparameter\c!start}{\getvalue{\currenttypingclass#3\v!global\c!start}}}}%
+ {#5{\typingparameter\c!start}{\typingparameter\c!stop}}}%
+ \stopverbatimcolor
+ \stoppacked
+ \typingparameter\c!after
+ \egroup}
+
+\def\doifelsetypingfile#1% sets \readfilename (we will make this proper mkiv i.e. less messy)
+ {\doiflocfileelse{#1}
+ {\firstoftwoarguments}
+ {\doifinputfileelse{#1}
+ {\def\readfilename{\pathplusfile\filepath{#1}}\firstoftwoarguments} % messy, looks wrong too
+ {\secondoftwoarguments}}}
+
+\def\dodotypefile[#1][#2]#3%
+ {\doifelsetypingfile{#3}
+ {\dosometyping{#1}{#2}{#3}{\processfileverbatim\readfilename}{\processfilelinesverbatim\readfilename}}
+ {\reporttypingerror{#3}}}
+
+%D \macros
+%D {filename}
+%D
+%D Typesetting filenames in monospaced fonts is possible with
+%D
+%D \starttyping
+%D \filename{here/there/filename.suffix}
+%D \stoptyping
+%D
+%D The definition is not that spectacular.
+
+\unexpanded\def\filename#1{{\tttf\hyphenatedfilename{#1}}}
+
+%D This leaves some settings:
+
+\permitshiftedendofverbatim
+\optimizeverbatimtrue
+
+%D And a bonus macro:
+
+\def\verbatim#1{\defconvertedargument\ascii{#1}\ascii}
+
+%D The setups for display verbatim and file verbatim are
+%D shared. One can adapt the extra defined typing environments,
+%D but they also default to the values below. Watch the
+%D alternative escape character.
+
+\setuptyping
+ [ \c!before=\blank,
+ \c!after=\blank,
+ \c!bodyfont=,
+ \c!color=,
+ \c!space=\v!off,
+ \c!page=\v!no,
+ \c!tab=\s!ascii,
+ \c!option=\v!none,
+ \c!palet=colorpretty,
+ \c!text=\v!no,
+ \c!style=\tttf,
+ \c!icommand=\ttsl,
+ \c!vcommand=,
+ \c!ccommand=\tttf,
+ \c!indentnext=\v!yes,
+ \c!margin=\!!zeropoint,
+ \c!evenmargin=\!!zeropoint,
+ \c!oddmargin=\!!zeropoint,
+ \c!blank=\v!line,
+ \c!escape=/, % beware \string\ , should also be accepted
+ \c!numbering=\v!no,
+ \c!lines=,
+ \c!empty=,
+ \c!start=1,
+ \c!stop=,
+ \c!step=1,
+ \c!continue=,
+ \c!nlines=]
+
+\definetyping[\v!typing]
+
+\presettyping[\v!file][]
+
+% \setuptyping % not needed
+% [\v!file]
+% [\c!start=1,
+% \c!stop=,
+% \c!step=1,
+% \c!continue=,
+% \c!nlines=]
+
+%D The setups for inline verbatim default to:
+
+\setuptype
+ [ \c!space=\v!off,
+ \c!color=,
+ \c!style=\tt\tf, % \tttf gives problems with {\tx \type...}
+ \c!page=\v!no,
+ \c!tab=\v!yes,
+ \c!palet=colorpretty,
+ \c!option=\v!normal]
+
+\definetyping[RAW] [\c!option=RAW]
+\definetyping[MP] [\c!option=MP]
+\definetyping[PL] [\c!option=PL]
+\definetyping[PM] [\c!option=PL]
+\definetyping[JS] [\c!option=JS]
+\definetyping[JV] [\c!option=JV]
+\definetyping[SQL] [\c!option=SQL]
+\definetyping[TEX] [\c!option=TEX]
+\definetyping[PAS] [\c!option=PAS]
+\definetyping[PASCAL][\c!option=PAS]
+\definetyping[MOD] [\c!option=PAS]
+\definetyping[MODULA][\c!option=PAS]
+\definetyping[DELPHI][\c!option=PAS]
+\definetyping[EIFFEL][\c!option=EIF]
+\definetyping[XML] [\c!option=XML]
+\definetyping[LUA] [\c!option=LUA]
+
+\installprettytype [RAW] [RAW]
+
+\installprettytype [TEX] [TEX]
+
+\installprettytype [PERL] [PL]
+\installprettytype [PL] [PL]
+\installprettytype [PM] [PL]
+
+\installprettytype [METAPOST] [MP]
+\installprettytype [METAFONT] [MP]
+\installprettytype [MP] [MP]
+\installprettytype [MF] [MP]
+
+\installprettytype [JAVASCRIPT] [JS]
+\installprettytype [JAVA] [JV]
+\installprettytype [JS] [JS]
+\installprettytype [JV] [JV]
+
+\installprettytype [SQL] [SQL]
+
+\installprettytype [PASCAL] [PAS]
+\installprettytype [PAS] [PAS]
+\installprettytype [MODULA] [PAS]
+\installprettytype [MOD] [PAS]
+
+\installprettytype [EIFFEL] [EIF]
+\installprettytype [EIF] [EIF]
+\installprettytype [E] [EIF]
+
+\installprettytype [XML] [XML]
+
+\installprettytype [LUA] [LUA]
+
+\installnewpretty M {\setupprettiesintype {MP}\setupprettytype}
+\installnewpretty P {\setupprettiesintype {PL}\setupprettytype}
+\installnewpretty T {\setupprettiesintype{TEX}\setupprettytype}
+\installnewpretty J {\setupprettiesintype {JV}\setupprettytype}
+\installnewpretty S {\setupprettiesintype{SQL}\setupprettytype}
+\installnewpretty W {\setupprettiesintype{PAS}\setupprettytype} % Wirth
+\installnewpretty I {\setupprettiesintype{EIF}\setupprettytype} % E taken
+\installnewpretty X {\setupprettiesintype{XML}\setupprettytype}
+
+%D We use the \CONTEXT\ color system for switching to and from
+%D color mode. We can always redefine these colors afterwards.
+
+\definecolor [colorprettyone] [r=.9, g=.0, b=.0] % red
+\definecolor [colorprettytwo] [r=.0, g=.8, b=.0] % green
+\definecolor [colorprettythree] [r=.0, g=.0, b=.9] % blue
+\definecolor [colorprettyfour] [r=.8, g=.8, b=.6] % yellow
+
+\definecolor [grayprettyone] [s=.30]
+\definecolor [grayprettytwo] [s=.45]
+\definecolor [grayprettythree] [s=.60]
+\definecolor [grayprettyfour] [s=.75]
+
+\definepalet
+ [colorpretty]
+ [ prettyone=colorprettyone,
+ prettytwo=colorprettytwo,
+ prettythree=colorprettythree,
+ prettyfour=colorprettyfour]
+
+\definepalet
+ [graypretty]
+ [ prettyone=grayprettyone,
+ prettytwo=grayprettytwo,
+ prettythree=grayprettythree,
+ prettyfour=grayprettyfour]
+
+\definepalet [TEXcolorpretty] [colorpretty]
+\definepalet [TEXgraypretty] [graypretty]
+\definepalet [PLcolorpretty] [colorpretty]
+\definepalet [PLgraypretty] [graypretty]
+\definepalet [PMcolorpretty] [colorpretty]
+\definepalet [PMgraypretty] [graypretty]
+\definepalet [MPcolorpretty] [colorpretty]
+\definepalet [MPgraypretty] [graypretty]
+\definepalet [JVcolorpretty] [colorpretty]
+\definepalet [JVgraypretty] [graypretty]
+\definepalet [JScolorpretty] [colorpretty]
+\definepalet [JSgraypretty] [graypretty]
+\definepalet [SQLcolorpretty] [colorpretty]
+\definepalet [SQLgraypretty] [graypretty]
+\definepalet [PAScolorpretty] [colorpretty]
+\definepalet [PASgraypretty] [graypretty]
+\definepalet [EIFcolorpretty] [colorpretty]
+\definepalet [EIFgraypretty] [graypretty]
+\definepalet [XMLcolorpretty] [colorpretty]
+\definepalet [XMLgraypretty] [graypretty]
+\definepalet [LUAcolorpretty] [colorpretty]
+\definepalet [LUAgraypretty] [graypretty]
+
+\protect \endinput
diff --git a/tex/context/base/buff-ver.mkiv b/tex/context/base/buff-ver.mkiv
new file mode 100644
index 000000000..dacbdb7ac
--- /dev/null
+++ b/tex/context/base/buff-ver.mkiv
@@ -0,0 +1,1193 @@
+%D \module
+%D [ file=buff-ver, % was core-ver
+%D version=2000.05.09,
+%D title=\CONTEXT\ Buffer Macros,
+%D subtitle=Verbatim,
+%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 Buffer Macros / Verbatim}
+
+%D We can optimize esp the initializations a bit.
+
+\unprotect
+
+\ifdefined\startlinenumbering\else \let\startlinenumbering \relax \fi
+\ifdefined\stoplinenumbering \else \let\stoplinenumbering \relax \fi
+\ifdefined\setuplinenumbering\else \unexpanded\def\setuplinenumbering[#1]{} \fi
+
+% D \macros
+% D {iflinepar}
+% D
+% D A careful reader will see that \type{\linepar} is reset.
+% D This boolean can be used to determine if the current line is
+% D the first line in a pseudo paragraph and this boolean is set
+% D after each empty line. The \type{\relax} can be used to
+% D determine the end of the line when one implements a scanner
+% D routine.
+%
+% will become obsolete
+
+\newif\iflinepar
+
+% \type{ char} geeft bagger
+
+%D We are going to embed the general verbatim support macros in
+%D a proper environment. First we show the common setup
+%D macro, so we know what features are supported. The options
+%D are hooked into the support macros via the \type{\obey}
+%D macros.
+
+\newif\ifslantedtypeactivated
+\newif\ifslantedtypepermitted
+
+\def\switchslantedtype
+ {\ifslantedtypepermitted
+ \ifslantedtypeactivated
+ \slantedtypeactivatedfalse\tttf
+ \else
+ \slantedtypeactivatedtrue\ttsl
+ \fi
+ \fi}
+
+\def\prettyidentifier {TEX}
+\def\prettypalet {}
+
+\def\installprettytype
+ {\dodoubleargument\doinstallprettytype}
+
+\def\doinstallprettytype[#1][#2]% map #1 onto #2
+ {\uppercasestring#1\to\asciia
+ \uppercasestring#2\to\asciib
+ \setevalue{\??ty\??ty\asciia}{\asciib}}
+
+\unexpanded\def\setupprettiesintype#1%
+ {\uppercasestring#1\to\ascii
+ \edef\prettyidentifier{\executeifdefined{\??ty\??ty\ascii}{TEX}}%
+ \begingroup
+ % we can move this to lua
+ % \lowercasestring \f!prettyprefix\prettyidentifier\to\filename
+ % \doonlyonce\filename{\ctxloadluafile\filename\empty}%
+ \ctxlua{buffers.loadvisualizer("\ascii")}%
+ \endgroup}
+
+\unexpanded\def\setupprettytype
+ {\processingverbatimtrue % will move
+ \ctxlua{buffers.visualizers.reset()}}
+
+\def\setverbatimspaceskip
+ {\setbox\scratchbox\hbox{x}%
+ \spaceskip\wd\scratchbox
+ \xspaceskip\spaceskip}
+
+\let\obeycharacters\relax % tab mess can go
+
+\setvalue{\??tp:\c!lines:\v!yes }{\obeybreakpoints}
+\setvalue{\??tp:\c!lines:\v!hyphenated}{\obeyhyphens}
+
+%setvalue{\??tp:\c!empty:\v!yes }{\obeyemptylines}
+%setvalue{\??tp:\c!empty:\v!all }{\obeyallemptylines}
+
+\setvalue{\??tp:\c!option:\v!none }{\let\obeycharacters\relax}
+\setvalue{\??tp:\c!option:\empty }{\let\obeycharacters\relax}
+\setvalue{\??tp:\c!option:\v!color }{\setupprettiesintype{\typingparameter\c!option}%
+ \let\obeycharacters\setupprettytype}
+\setvalue{\??tp:\c!option:\v!normal }{\let\obeycharacters\setupgroupedtype}
+\setvalue{\??tp:\c!option:\v!slanted }{\let\obeycharacters\setupslantedtype}
+\setvalue{\??tp:\c!option:\s!unknown }{\setupprettiesintype{\typingparameter\c!option}%
+ \let\obeycharacters\setupprettytype}
+%setvalue{\??tp:\c!option:\v!commands }{\def\obeycharacters{\setupcommandsintype}}
+
+\def\dosetverbatimfont
+ {\redoconvertfont\dosetfontattribute{\currenttypingclass\currenttyping}\c!style
+ \normalnoligatures\font}
+
+\unexpanded\def\setupcommonverbatim
+ {\let\prettyidentifier\s!default
+ %
+ \def\prettyidentifierfont{\typingparameter\c!icommand}%
+ \def\prettyvariablefont {\typingparameter\c!vcommand}%
+ \def\prettynaturalfont {\typingparameter\c!ccommand}%
+ %
+ \ignorehyphens % default
+ \getvalue{\??tp:\c!lines:\typingparameter\c!lines}%
+ \getvalue{\??tp:\c!empty:\typingparameter\c!empty}%
+ \getvalue{\??tp:\c!option:\ifcsname\??tp:\c!option:\typingparameter\c!option\endcsname\typingparameter\c!option\else\s!unknown\fi}%
+ \setupverbatimcolor}
+
+\newtoks \everyinitializeverbatim
+
+\def\ignorebeginofpretty [#1]{}
+\def\ignoreendofpretty {}
+
+\def\doverbatimbop{\bgroup\beginofpretty}
+\def\doverbatimeop{\endofpretty\egroup}
+\def\doverbatimsop{\endofpretty\egroup\bgroup\beginofpretty}
+
+\let\noverbatimbop\ignorebeginofpretty
+\let\noverbatimeop\ignoreendofpretty
+\let\noverbatimsop\ignorebeginofpretty
+
+\def\doinitializeverbatim % todo: combine all in one call is faster
+ {\ctxlua{buffers.visualizers.reset()}%
+ \doifelse{\typingparameter\c!space}\v!on
+ {\let\obs\fastcontrolspace}%
+ {\let\obs\specialobeyedspace}%
+ \edef\askedverbatimtab{\typingparameter\c!tab}%
+ \doifelse\askedverbatimtab\v!no
+ {\ctxlua{buffers.settablength(1)}}
+ {\doifnumberelse{\askedverbatimtab}
+ {\ctxlua{buffers.settablength(\askedverbatimtab)}}
+ {\ctxlua{buffers.settablength()}}}%
+ \ctxlua{buffers.doifelsevisualizer("\prettyidentifier")}
+ {\ctxlua{buffers.setvisualizer("\prettyidentifier")}%
+ \let\bop\doverbatimbop
+ \let\eop\doverbatimeop
+ \let\sop\doverbatimsop}%
+ {\ctxlua{buffers.setvisualizer("\v!typing")}% or resetdefaultvisualizer
+ \let\bop\noverbatimbop
+ \let\eop\noverbatimeop
+ \let\sop\noverbatimsop}%
+ \relax\the\everyinitializeverbatim\relax}
+
+\appendtoks
+ \resetfontfeature
+ \resetcharacterspacing
+\to \everyinitializeverbatim
+
+% BEWARE: the noligatures will globally change the verbatim font's behaviour
+
+% test case:
+%
+% \definetype[typeTEX][option=tex]
+%
+% \typeTEX|\example---oeps|. this---ligates---again.
+% \typeTEX{\example---oeps}. this---ligates---again.
+% \type {\example---oeps}. this---ligates---again.
+
+%D \startbuffer
+%D \setuptyping[TEX][escape=yes]
+%D
+%D \startTEX
+%D /BTEX\em sometex/ETEX
+%D /BTEX\em sometex/ETEX \after
+%D \before /BTEX\em sometex/ETEX
+%D \before /BTEX\em sometex/ETEX \after
+%D \before /BTEX\em sometex/ETEX \inbetween /BTEX\em sometex/ETEX \after
+%D \before \after
+%D \stopTEX
+%D \stopbuffer
+%D
+%D \typebuffer \start \getbuffer \stop
+%D
+%D \startbuffer
+%D \setuptyping[TEX][escape={[[,]]}]
+%D
+%D \startTEX
+%D [[\em sometex]]
+%D [[\em sometex]] \after
+%D \before [[\em sometex]]
+%D \before [[\em sometex]] \after
+%D \before [[\em sometex]] \inbetween [[\em sometex]] \after
+%D \before \after
+%D \stopTEX
+%D \stopbuffer
+%D
+%D \typebuffer \start \getbuffer \stop
+%D
+%D \startbuffer
+%D \setuptyping[TEX][escape=//]
+%D
+%D \startTEX
+%D //\em sometex
+%D \before //\em sometex
+%D \stopTEX
+%D
+%D \typebuffer \start \getbuffer \stop
+
+\unexpanded\def\setupcommandsintype
+ {\ctxlua{buffers.set_escape("\currenttyping",\!!bs\typingparameter\c!escape\!!es)}}
+
+\appendtoks
+ \setupcommandsintype
+\to \everyinitializeverbatim
+
+\unexpanded\def\setupslantedtype
+ {\slantedtypepermittedtrue}
+
+\ifx\setupprettytype \undefined \let\setupprettytype \relax \fi
+\ifx\setupslantedtype \undefined \let\setupslantedtype \relax \fi
+\ifx\setupgroupedtype \undefined \let\setupgroupedtype \relax \fi
+\ifx\normalnoligatures\undefined \let\normalnoligatures\gobbleoneargument \fi
+
+%D The verbatim commands have a rather long and turbulent
+%D history. Most users of \CONTEXT\ probably will never use
+%D some of the features, but I've kept in mind that when one is
+%D writing a users manual, about everything can and undoubtly
+%D will be subject to a verbatim treatment.
+%D
+%D Verbatim command are very sensitive to argument processing,
+%D which is a direct result of the \CATCODES\ being fixed at
+%D reading time. With our growing understanding of \TEX,
+%D especially of the mechanism that can be used for looking
+%D ahead and manipulating \CATCODES, the verbatim support
+%D became more and more advanced and natural.
+%D
+%D Typesetting inline verbatim can be accomplished by
+%D \type{\type}, which in this sentence was typeset by saying
+%D just \type{\type{\type}}, which in turn was typeset by
+%D \unknown. Using the normal grouping characters \type{{}} is
+%D the most natural way of using this command.
+%D
+%D A second, more or less redundant, alternative is delimiting
+%D the argument with an own character. This method was
+%D implemented in the context of a publication in the \MAPS,
+%D where this way of delimiting is recognized by \LATEX\ users.
+%D
+%D The third, more original alternative, is the one using
+%D \type{<<} and \type{>>} as delimiters. This alternative can
+%D be used in situations where slanted typeseting is needed.
+
+% todo: we can use \letter... here:
+
+\def\lesscharacter {<}
+\def\morecharacter {>}
+
+\chardef\texescape = `\\
+\chardef\leftargument = `\{
+\chardef\rightargument = `\}
+
+%D \macros
+%D {type}
+%D
+%D We define \type{\type} as a protected command. This command
+%D has several invocations: grouped, wirt boundary characters,
+%D and with font switches.
+
+% \starttyping
+% normal: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \par
+% normal: \par \type{xx<..xx.. >..>xx} \par \type{<....>} \par \type{<....>}
+% \setuptype[option=slanted]
+% slanted: \par \type{xx<<..sl..<> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<>..>> \par
+% slanted: \par \type{xx<<..sl.. xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<....>> \par
+% \setuptype[option=none]
+% none: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \par
+% \stoptyping
+
+%D When writing the manual to \CONTEXT\ and documenting this
+%D source we needed to typeset \type{<<} and \type{>>}. Because
+%D we wanted to do this in the natural way, we've adapted the
+%D original definition a bit. This implementation went through
+%D several live cycles. The final implementation looks a bit
+%D further and treats the lone \type{<<} and \type{>>} a bit
+%D different. The \type {\null} prevents ligatures, which
+%D unfortunately turn up in Lucida fonts.
+
+%D The following lines show what happens when we set
+%D \type {option=commands}.
+%D
+%D \startbuffer
+%D \starttyping
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test test test/BTEX \bf(nota bene)/ETEX test
+%D test test test /BTEX \bf(nota bene)/ETEX test
+%D \stoptyping
+%D \stopbuffer
+%D
+%D % \bgroup\setuptyping[option=commands]\getbuffer\egroup
+%D
+%D this was keyed in as:
+%D
+%D \typebuffer
+
+\unexpanded\def\type{\dotype\empty}
+
+\def\dotype#1% was \dotype
+ {\dontleavehmode \bgroup
+ % new, \strut enables leading space in \type { abc } at par start / begstrut
+ % else no hyphenation (replaced by \dontleavehmode which saves unboxing)
+ % \begstrut
+ \let\currenttypingclass\??ty
+ \edef\currenttyping{#1}%
+ \catcode`\<=\@@other
+ \catcode`\>=\@@other
+ \futurelet\next\dodotype}
+
+\def\dodotype
+ {\ifx\next\bgroup
+ \@EA\dodotypeA
+ \else
+ \@EA\dodotypeAD
+ \fi}
+
+\def\dodotypeAD
+ {\if\next<%
+ \doifelse{\typingparameter\c!option}\v!none{\@EA\dodotypeB}{\@EA\dodotypeC}%
+ \else
+ \@EA\dodotypeD
+ \fi}
+
+\def\dodotypeA
+ {\initializetype % probably too much
+ \verbatimcolor
+ \dosetverbatimfont
+ \setcatcodetable \typcatcodesa
+ \dodotypeAA}
+
+\def\dodotypeAA#1%
+ {\doinitializeverbatim
+ \def\obs{\obeyedspace}%
+ \ctxlua{buffers.hooks.flush_inline(\!!bs\detokenize{#1}\!!es)}%
+ \egroup}
+
+\def\dodotypeB#1%
+ {\initializetype
+ \verbatimcolor
+ \dosetverbatimfont
+ \setcatcodetable \typcatcodesb
+ \dodotypeBB}
+
+\def\dodotypeBB#1%
+ {\doinitializeverbatim
+ \ctxlua{buffers.visualizers.flush_nested(\!!bs\detokenize{#1}\!!es,false)}%
+ \egroup
+ \gobbleoneargument} % grab last >
+
+\def\dodotypeC#1%
+ {\initializetype
+ \verbatimcolor
+ \dosetverbatimfont
+ \setcatcodetable \typcatcodesb
+ \dodotypeCC}
+
+\def\dodotypeCC#1%
+ {\doinitializeverbatim
+ \ifx\obeycharacters\setupprettytype % temp hack, we need a proper signal
+ \ctxlua{buffers.hooks.flush_inline([\!!bs\detokenize{#1}\!!es,true)}%
+ \else
+ \def\obs{\obeyedspace}%
+ \ctxlua{buffers.visualizers.flush_nested(\!!bs\detokenize{#1}\!!es,true)}%
+ \fi
+ \egroup
+ \gobbleoneargument} % grab last >
+
+\def\dodotypeD#1%
+ {\initializetype
+ \verbatimcolor
+ \dosetverbatimfont
+ \setcatcodetable \typcatcodesa
+ \def\dodotypeDD##1#1{\dodotypeAA{##1}}%
+ \dodotypeDD}
+
+\def\dodotypeDD#1%
+ {\doinitializeverbatim
+ \ctxlua{buffers.hooks.flush_inline(\!!bs\detokenize{#1}\!!es,true)}%
+ \egroup
+ \gobbleoneargument} % grab last >
+
+%D The neccessary initializations are done by calling
+%D \type{\initializetype} which in return calls for the support
+%D macro \type{\setupinlineverbatim}.
+
+\def\initializetype
+ {\let\obeylines\ignorelines
+ \setupcommonverbatim
+ %\dosetverbatimfont
+ %\setverbatimspaceskip
+ %\setupcopyverbatim % not needed
+ \setcatcodetable\vrbcatcodes}
+
+%D \macros
+%D {setuptype}
+%D
+%D Some characteristics of \type{\type} can be set up by:
+
+\unexpanded\def\setuptype
+ {\dodoubleempty\dosetuptype}
+
+\def\dosetuptype[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??ty#1][#2]%
+ \else
+ \getparameters[\??ty][#1]%
+ \fi}
+
+%D \macros
+%D {typ,obeyhyphens,obeybreakpoints}
+%D
+%D Although it's not clear from the macros, one character
+%D trait of this macros, which are build on top of the support
+%D module, is that they don't hyphenate. We therefore offer
+%D the alternative \type{\typ}. The current implementation
+%D works all right, but a decent hyphenation support of
+%D \type{\tt} text will be implemented soon.
+
+\def\specialobeyedspace {\hskip\interwordspace\relax} % better than spaceskip
+\def\specialcontrolspace{\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\relax}
+
+\def\obeyhyphens
+ {\let\obeyedspace \specialobeyedspace
+ \let\controlspace\specialcontrolspace
+ \spaceskip.25em\relax} % hm a bit of stretch !
+
+\def\obeybreakpoints
+ {\ignorehyphens
+ \veryraggedright}
+
+\def\ignorehyphens
+ {\language\minusone % extra bonus, the \null should do the job too
+ \let\obeyedspace \specialobeyedspace
+ \let\controlspace\specialcontrolspace
+ \spaceskip.5em\relax}
+
+\unexpanded\def\typ
+ {\bgroup
+ \let\@@tylines\v!hyphenated
+ \futurelet\next\dodotype}
+
+%D \macros
+%D {tex,arg,mat,dis}
+%D
+%D Sometimes, for instance when we pass verbatim text as an
+%D argument, the fixed \CATCODES\ interfere with our wishes. An
+%D experimental implementation of character by character
+%D processing of verbatim text did overcome this limitation,
+%D but we've decided not to use that slow and sometimes
+%D troublesome solution. Instead we stick to some 'old'
+%D \CONTEXT\ macros for typesetting typical \TEX\ characters.
+%D
+%D The next implementation is more clear but less versatile,
+%D so we treated it for a beter one.
+%D
+%D \starttyping
+%D \def\dospecialtype#1#2%
+%D {\bgroup
+%D \initializetype
+%D \catcode`\{=\@@begingroup
+%D \catcode`\}=\@@endgroup
+%D \def\dospecialtype%
+%D {\def\dospecialtype{#2\egroup}%
+%D \bgroup
+%D \aftergroup\dospecialtype
+%D #1}%
+%D \afterassignment\dospecialtype
+%D \let\next=}
+%D
+%D \unexpanded\def\tex{\dospecialtype\texescape\relax}
+%D \unexpanded\def\arg{\dospecialtype\leftargument\rightargument}
+%D \unexpanded\def\mat{\dospecialtype\$\$}
+%D \unexpanded\def\dis{\dospecialtype{\$\$}{\$\$}}
+%D \stoptyping
+
+\def\setgroupedtype
+ {\let\currenttypingclass\??ty
+ \initializetype
+ \verbatimcolor
+ \dosetverbatimfont
+ %\setcatcodetable \typcatcodesa
+ \catcode`\{=\@@begingroup
+ \catcode`\}=\@@endgroup}
+
+\unexpanded\def\tex{\groupedcommand{\setgroupedtype\texescape}{\relax}}
+\unexpanded\def\arg{\groupedcommand{\setgroupedtype\leftargument}{\rightargument}}
+\unexpanded\def\mat{\groupedcommand{\setgroupedtype\$}{\$}}
+\unexpanded\def\dis{\groupedcommand{\setgroupedtype\$\$}{\$\$}}
+
+\let\normaltexttex\tex
+\let\normaltextarg\arg
+\let\normaltextmat\mat
+\let\normaltextdis\dis
+
+\def\astype
+ {\groupedcommand\dorawtype\relax}
+
+\def\dorawtype
+ {\let\currenttypingclass\??ty
+ \normalverbatimcolor % \verbatimcolor
+ \dosetverbatimfont}
+
+%D \macros
+%D {starttyping}
+%D
+%D Display verbatim is realized far more easy, which is mostly
+%D due to the fact that we use \type{\stop...} as delimiter.
+%D The implementation inherits some features, for instance the
+%D support of linenumbering, which can best be studied in the
+%D documented support module.
+
+\let\currenttyping \empty
+\let\currenttypingclass\??ty % saveguard
+
+\def\typingparameter#1%
+ {\ifcsname\currenttypingclass\currenttyping#1\endcsname
+ \csname\currenttypingclass\currenttyping#1\endcsname
+ \else\ifcsname\currenttypingclass#1\endcsname
+ \csname\currenttypingclass#1\endcsname
+ \fi\fi}
+
+\def\settypingparameter#1#2%
+ {\setvalue{\currenttypingclass\currenttyping#1}{#2}}
+
+\def\setxtypingparameter#1#2%
+ {\setxvalue{\currenttypingclass\currenttyping#1}{#2}}
+
+\setvalue{\??tp:\c!blank:\v!standard}{\ctxparskip}
+\setvalue{\??tp:\c!blank:\v!small }{\smallskipamount}
+\setvalue{\??tp:\c!blank:\v!medium }{\medskipamount}
+\setvalue{\??tp:\c!blank:\v!big }{\bigskipamount}
+\setvalue{\??tp:\c!blank:\v!halfline}{.5\baselineskip}
+\setvalue{\??tp:\c!blank:\v!line }{\baselineskip}
+\setvalue{\??tp:\c!blank:\v!none }{\zeropoint}
+
+\def\doopenupverbatimlineindeed
+ {\getpagestatus
+ \ifrightpage
+ \hskip\typingparameter\c!oddmargin\relax
+ \else
+ \hskip\typingparameter\c!evenmargin\relax
+ \fi}
+
+\def\initializetyping
+ {%\donefalse
+ \switchtobodyfont[\typingparameter\c!bodyfont]%
+ \donefalse
+ \scratchskip\typingparameter\c!oddmargin\relax
+ \ifzeropt\scratchskip\else\donetrue\fi
+ \scratchskip\typingparameter\c!evenmargin\relax
+ \ifzeropt\scratchskip\else\donetrue\fi
+ \ifdone
+ \let\doopenupverbatimline\doopenupverbatimlineindeed
+ \else
+ \doadaptleftskip{\typingparameter\c!margin}%
+ \fi
+ % no symbolic blanks !
+ \edef\!!stringa{\executeifdefined{\??bo\typingparameter\c!blank}{\typingparameter\c!blank}}%
+ \scratchskip\executeifdefined{\??tp:\c!blank:\!!stringa}\!!stringa\relax
+ \ifgridsnapping
+ % this will be adapted
+ \ifdim\scratchskip=.5\baselineskip\relax
+ \edef\verbatimbaselineskip{\the\scratchskip}% new
+ \else
+ \edef\verbatimbaselineskip{\the\baselineskip}%
+ \fi
+ \else
+ \edef\verbatimbaselineskip{\the\scratchskip}%
+ \fi
+\doifsomething{\typingparameter\c!align}{\setupalign[\typingparameter\c!align]}%
+ \setupcommonverbatim}
+
+%D The basic display verbatim commands are defined in an
+%D indirect way. As we will see, they are a specific case of a
+%D more general mechanism.
+
+\newif\ifoptimizeverbatim \optimizeverbatimtrue
+
+\let \beginofverbatimlines \relax
+\let \endofverbatimlines \relax
+
+\def\doverbatimnobreak
+ {\ifoptimizeverbatim\penalty500 \fi}
+
+\def\doverbatimgoodbreak
+ {\ifoptimizeverbatim\penalty\linepenalty\fi}
+
+% \def\doflushverbatimline
+% {\expandafter\dodoverbatimline\expandafter{\savedverbatimline}}
+% \def\doverbatimbeginofline#1% linenumber (optional provided by mkiv / todo)
+% {\dontleavehmode
+% \strut
+% \the\everyline}
+% \def\doverbatimendofline
+% {\par}
+% \def\doverbatimemptyline
+% {\strut
+% \par}
+% \let\handleverbatimline=\relax
+
+% we need this hack because otherwise verbatim skips
+% the first line (everything after the initial command)
+
+\def\dostarttyping#1% tricky non standard lookahead
+ {\bgroup
+ \let\currenttypingclass\??tp
+ \edef\currenttyping{#1}%
+ \obeylines
+ \futurelet\nexttoken\dodostarttyping}
+
+\def\dodostarttyping
+ {\ifx\nexttoken[%
+ \expandafter\dododostarttyping
+ \else
+ \expandafter\nododostarttyping
+ \fi}
+
+\def\nododostarttyping
+ {\dododostarttyping[]}
+
+\def\dotypefileverbatim
+ {\doinitializeverbatim
+ \beginofverbatimlines
+ \ctxlua{buffers.typefile("\readfilename","\typingparameter\c!strip","\typingparameter\c!range")}%
+ \endofverbatimlines}
+
+\def\dotypefilelinesverbatim#1#2%
+ {#1\dotypefileverbatim#2}
+
+\unexpanded\def\dotypeblockverbatim#1#2%
+ {\dowithbuffer{_typing_}{#1}{#2}
+ {}
+ {\doinitializeverbatim
+ \beginofverbatimlines
+ \ctxlua{buffers.type("_typing_","\typingparameter\c!strip","\typingparameter\c!range")}%
+ \endofverbatimlines
+ \csname#2\endcsname}}
+
+\def\dododostarttyping[#1]%
+ {\typingparameter\c!before
+ \startpacked % includes \bgroup
+ \dosetuptypelinenumbering{#1}%
+ \initializetyping
+ \dosetverbatimfont
+ \startverbatimcolor
+ \normalexpanded{\dotypeblockverbatim{\e!start\currenttyping}{\e!stop\currenttyping}}} % was s!start
+
+\def\dostoptyping#1% hm, currenttyping
+ {\stopverbatimcolor
+ \stoppacked % includes \egroup
+ \typingparameter\c!after
+ \normalexpanded{\egroup\checknextindentation[\typingparameter\c!indentnext]}%
+ \dorechecknextindentation}
+
+%D Line numbering for files is combined with filtering, while
+%D display verbatim has the ability to continue.
+%D
+%D \starttyping
+%D \typefile[numbering=file,start=10,stop=12]{test.tex}
+%D
+%D \definetyping[code][numbering=line]
+%D
+%D \starttext
+%D \startcode
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[start=continue]
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[start=10]
+%D ...
+%D \stopcode
+%D \stoptyping
+
+%D Ranges:
+%D
+%D \starttyping
+%D % label:start:one
+%D
+%D \def\MyMacro
+%D {just an example}
+%D
+%D % label:stop:one
+%D
+%D \starttext
+%D
+%D % \typefile[file][range={3,6}]{whatever.tex}
+%D
+%D % \typefile[file][range={3,+2}]{whatever.tex}
+%D
+%D \typefile[file][range={label:start:one,label:stop:one}]{whatever.tex}
+%D
+%D \stoptext
+%D \stoptyping
+
+%D \macros
+%D {setuptyping}
+%D
+%D The setup of typing accepts two arguments. The optional
+%D first one identifies the user defined ones. If only one
+%D argument is given, the values apply to both the standard
+%D command \type{\starttyping} and \type{\typefile}.
+
+\def\dosetuptyping[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??tp#1][#2]%
+ \else
+ \getparameters[\??tp][#1]%
+ \fi}
+
+\unexpanded\def\setuptyping
+ {\dodoubleempty\dosetuptyping}
+
+%D \macros
+%D {definetype}
+%D
+%D Specific inline verbatim commands can be defined with the
+%D following command.
+
+\unexpanded\def\definetype
+ {\dodoubleempty\dodefinetype}
+
+\def\dodefinetype[#1][#2]%
+ {\setuvalue{#1}{\dotype{#1}}%
+ \getparameters[\??ty#1][#2]}
+
+%D \macros
+%D {definetyping}
+%D
+%D For most users the standard \type{\start}||\type{\stop}||pair
+%D will suffice, but for documentation purposes the next
+%D definition command can be of use:
+%D
+%D \starttyping
+%D \definetyping[extratyping][margin=3em]
+%D
+%D \startextratyping
+%D these extra ones are indented by 1 em
+%D \stopextratyping
+%D \stoptyping
+%D
+%D The definitions default to the standard typing values.
+
+% TODO: parent etc !
+
+\def\presettyping[#1][#2]% brrr also use parent here
+ {\copyparameters[\??tp#1][\??tp][\c!color,\c!style]%
+ \getparameters [\??tp#1][#2]}
+
+\def\dodefinetyping[#1][#2]%
+ {\setvalue{\e!start#1}{\dostarttyping{#1}}%
+ \setvalue{\e!stop #1}{\dostoptyping {#1}}%
+ \presettyping[#1][#2]}
+
+\unexpanded\def\definetyping
+ {\dodoubleempty\dodefinetyping}
+
+%D We can use some core color commands. These are faster than
+%D the standard color switching ones and work ok on a line by
+%D line basis.
+%D
+%D \starttyping
+%D \unexpanded\def\setupverbatimcolor%
+%D {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}%
+%D \def\beginofpretty[##1]{\startcolormode{\prettypalet:##1}}%
+%D \def\endofpretty {\stopcolormode}}
+%D \stoptyping
+%D
+%D Since we support a global color too, the folowing
+%D definition is better:
+
+\def\normalbeginofpretty [#1]{\startcolor[\prettypalet:#1]}%
+\def\normalendofpretty {\stopcolor}
+\def\normalstartverbatimcolor{\startcolor[\typingparameter\c!color]}%
+\def\normalstopverbatimcolor {\stopcolor}
+\def\normalverbatimcolor {\getvalue{\typingparameter\c!color}}% command !
+
+\unexpanded\def\setupnormalprettyverbatim
+ {\edef\prettypalet{\prettyidentifier\prettypalet}%
+ \let\beginofpretty \normalbeginofpretty
+ \let\endofpretty \normalendofpretty
+ \let\startverbatimcolor\normalstartverbatimcolor
+ \let\stopverbatimcolor \normalstopverbatimcolor
+ \let\verbatimcolor \normalverbatimcolor}
+
+\unexpanded\def\setupignoreprettyverbatim
+ {\let\prettypalet \empty
+ \let\beginofpretty \ignorebeginofpretty
+ \let\endofpretty \ignoreendofpretty
+ \let\startverbatimcolor\normalstartverbatimcolor
+ \let\stopverbatimcolor \normalstopverbatimcolor
+ \let\verbatimcolor \normalverbatimcolor}
+
+\unexpanded\def\setupverbatimcolor
+ {\edef\prettypalet{\typingparameter\c!palet}%
+ \ifx\prettypalet\empty
+ \setupignoreprettyverbatim
+ \else
+ \setupnormalprettyverbatim
+ \fi}
+
+\let\beginofpretty \ignorebeginofpretty
+\let\endofpretty \ignoreendofpretty
+\let\prettypalet \empty
+\let\startverbatimcolor\relax
+\let\stopverbatimcolor \relax
+\let\verbatimcolor \relax
+
+%D \macros
+%D {EveryPar, EveryLine, iflinepar}
+%D
+%D One of the features of these commands is the support of
+%D \type{\EveryPar}, \type{\EveryLine} and \type{\iflinepar}.
+%D In the documentation of the verbatim support module we give
+%D some examples of line- and paragraph numbering using these
+%D macros.
+
+%D \macros
+%D {typefile}
+%D
+%D Typesetting files verbatim (for the moment) only supports
+%D colorization of \TEX\ sources as valid option. The other
+%D setup values are inherited from display verbatim.
+%D The implementation of \type{\typefile} is straightforward:
+
+% new feature (not yet 100\% ok)
+%
+% \setuptyping[file][numbering=file]
+%
+% \typefile[start=2,nlines=3]{zapf}
+% \typefile[start=continue,nlines=13]{zapf}
+% \typefile{zapf}
+%
+% \setuptyping[file][numbering=line]
+%
+% \typefile[start=4,step=3]{zapf}
+% \typefile{zapf}
+
+\def\typefile
+ {\dodoubleempty\dotypefile}
+
+\def\dotypefile[#1][#2]#3%
+ {\ifsecondargument
+ \dodotypefile[#1][#2]{#3}%
+ \else\iffirstargument
+ \doifassignmentelse{#1}
+ {\dodotypefile[\v!file][#1]{#3}}
+ {\dodotypefile[#1][]{#3}}%
+ \else
+ \dodotypefile[\v!file][]{#3}%
+ \fi\fi}
+
+\def\dosetuptypelinenumbering#1% fuzzy
+ {%\ifcsname\currenttypingclass\currenttyping\c!start\endcsname \else
+ % \setuptyping[\currenttyping][\c!start=1,\c!stop=,\c!step=1,\c!continue=\v!no,\c!nlines=]%
+ %\fi
+ \doifassignmentelse{#1}{\setuptyping[\currenttyping][#1]}\donothing
+ \doifelse{\typingparameter\c!numbering}\v!file
+ {% kind of special: filters lines !
+ \setuplinenumbering[\currenttyping][\c!method=\v!file]%
+ \donetrue}
+ {\doifelse{\typingparameter\c!numbering}\v!line
+ {\doifinset\v!continue{#1}{\setuptyping[\currenttyping][\c!continue=\v!yes]}% fails: \settypingparameter\c!continue{\v!yes}
+ \donetrue}
+ {\donefalse}}%
+ \ifdone
+ \edef\beginofverbatimlines{\noexpand\startlinenumbering
+ [\currenttyping]%
+ [\c!continue=\typingparameter\c!continue,
+ \c!method=\v!type,
+ \c!start=\typingparameter\c!start,
+ \c!stop=\typingparameter\c!stop, % ?
+ \c!step=\typingparameter\c!step]%
+ }%
+ \def\endofverbatimlines{\stoplinenumbering}%
+ \fi}
+
+\def\reporttypingerror#1% temp hack
+ {\blank
+ \dontleavehmode\hbox\bgroup
+ \expanded{\defconvertedargument\noexpand\ascii{#1}}%
+ \tttf[\makemessage\m!verbatims1\ascii]%
+ \showmessage\m!verbatims1\ascii
+ \egroup
+ \blank}
+
+\def\dosometyping#1#2#3#4#5%
+ {\bgroup
+ \let\currenttypingclass\??tp
+ \edef\currenttyping{#1}%
+ \typingparameter\c!before
+ \startpacked % includes \bgroup
+ \dosetuptypelinenumbering{#2}%
+ \doifinset{\typingparameter\c!option}{\v!commands,\v!slanted,\v!normal}
+ {\setuptyping[#1][\c!option=\v!none]}%
+ \doif{\typingparameter\c!option}\v!color
+ {\expandafter\aftersplitstring#3\at.\to\prettyidentifier
+ \settypingparameter\c!option{\prettyidentifier}}%
+ \initializetyping
+ \dosetverbatimfont
+ \startverbatimcolor
+ \scratchcounter
+ \ifcsname\currenttypingclass#3\v!global\c!start\endcsname
+ \numexpr\csname\currenttypingclass#3\v!global\c!start\endcsname+\plusone\relax
+ \else
+ \plusone
+ \fi
+ \setxvalue{\currenttypingclass#3\v!global\c!start}{\the\scratchcounter}% no direct setxvalue as it defines beforehand
+ \doifelsenothing{\typingparameter\c!start}
+ {#4}
+ {\doif{\typingparameter\c!start}\v!continue
+ {\setevalue{\currenttypingclass#1\c!start}%
+ {\getvalue{\currenttypingclass#3\v!global\c!start}}}%
+ \doifelsenothing{\typingparameter\c!stop}
+ {\doifelsenothing{\typingparameter\c!nlines}
+ {#4}
+ {\setxvalue{\currenttypingclass#3\v!global\c!start}%
+ {\the\numexpr\typingparameter\c!start+\typingparameter\c!nlines+\minusone\relax}%
+ #5{\typingparameter\c!start}{\getvalue{\currenttypingclass#3\v!global\c!start}}}}%
+ {#5{\typingparameter\c!start}{\typingparameter\c!stop}}}%
+ \stopverbatimcolor
+ \stoppacked
+ \typingparameter\c!after
+ \egroup}
+
+\def\doifelsetypingfile#1% sets \readfilename (we will make this proper mkiv i.e. less messy)
+ {\doiflocfileelse{#1}
+ {\firstoftwoarguments}
+ {\doifinputfileelse{#1}
+% {\def\readfilename{\pathplusfile\filepath{#1}}\firstoftwoarguments} % messy, looks wrong too
+ {\def\readfilename{#1}\firstoftwoarguments} % messy, looks wrong too
+ {\secondoftwoarguments}}}
+
+\def\dodotypefile[#1][#2]#3%
+ {\doifelsetypingfile{#3}
+ {\dosometyping{#1}{#2}{#3}\dotypefileverbatim\dotypefilelinesverbatim}
+ {\reporttypingerror{#3}}}
+
+%D \macros
+%D {filename}
+%D
+%D Typesetting filenames in monospaced fonts is possible with
+%D
+%D \starttyping
+%D \filename{here/there/filename.suffix}
+%D \stoptyping
+%D
+%D The definition is not that spectacular.
+
+\unexpanded\def\filename#1{{\tttf\hyphenatedfilename{#1}}}
+
+%D And a bonus macro:
+
+\def\verbatim#1{\defconvertedargument\ascii{#1}\ascii}
+
+%D The setups for display verbatim and file verbatim are
+%D shared. One can adapt the extra defined typing environments,
+%D but they also default to the values below. Watch the
+%D alternative escape character.
+
+\setuptyping
+ [ \c!before=\blank,
+ \c!after=\blank,
+ \c!bodyfont=,
+ \c!color=,
+ \c!space=\v!off,
+ \c!page=\v!no,
+ \c!tab=\s!ascii,
+ \c!option=\v!none,
+ \c!palet=colorpretty,
+ \c!text=\v!no,
+ \c!style=\tttf,
+ \c!icommand=\ttsl,
+ \c!vcommand=,
+ \c!ccommand=\tttf,
+ \c!indentnext=\v!yes,
+ \c!margin=\!!zeropoint,
+ \c!evenmargin=\!!zeropoint,
+ \c!oddmargin=\!!zeropoint,
+ \c!blank=\v!line,
+ \c!escape=, % yes | no | START,STOP BTEX,ETEX
+ \c!numbering=\v!no,
+ \c!lines=,
+ \c!range=,
+ \c!empty=,
+ \c!start=1,
+ \c!stop=,
+ \c!step=1,
+ \c!continue=,
+ \c!strip=\v!no, % auto or number
+ \c!nlines=]
+
+\definetyping[\v!typing]
+
+\presettyping[\v!file][]
+
+% \setuptyping % not needed
+% [\v!file]
+% [\c!start=1,
+% \c!stop=,
+% \c!step=1,
+% \c!continue=,
+% \c!nlines=]
+
+%D The setups for inline verbatim default to:
+
+\setuptype
+ [ \c!space=\v!off,
+ \c!color=,
+ \c!style=\tt\tf, % \tttf gives problems with {\tx \type...}
+ \c!page=\v!no,
+ \c!tab=\v!yes,
+ \c!palet=colorpretty,
+ \c!option=\v!normal]
+
+%D Beware: only a few are currently (re)implemented in \MKIV.
+
+\definetyping[RAW] [\c!option=RAW]
+\definetyping[MP] [\c!option=MP] % done
+\definetyping[PL] [\c!option=PL]
+\definetyping[PM] [\c!option=PL]
+\definetyping[JS] [\c!option=JS]
+\definetyping[JV] [\c!option=JV]
+\definetyping[SQL] [\c!option=SQL]
+\definetyping[TEX] [\c!option=TEX] % done
+\definetyping[PAS] [\c!option=PAS]
+\definetyping[PASCAL][\c!option=PAS]
+\definetyping[MOD] [\c!option=PAS]
+\definetyping[MODULA][\c!option=PAS]
+\definetyping[DELPHI][\c!option=PAS]
+\definetyping[EIFFEL][\c!option=EIF]
+\definetyping[XML] [\c!option=XML]
+\definetyping[LUA] [\c!option=LUA] % done
+
+\installprettytype [RAW] [RAW]
+
+\installprettytype [TEX] [TEX]
+
+\installprettytype [PERL] [PL]
+\installprettytype [PL] [PL]
+\installprettytype [PM] [PL]
+
+\installprettytype [METAPOST] [MP]
+\installprettytype [METAFONT] [MP]
+\installprettytype [MP] [MP]
+\installprettytype [MF] [MP]
+
+\installprettytype [JAVASCRIPT] [JS]
+\installprettytype [JAVA] [JV]
+\installprettytype [JS] [JS]
+\installprettytype [JV] [JV]
+
+\installprettytype [SQL] [SQL]
+
+\installprettytype [PASCAL] [PAS]
+\installprettytype [PAS] [PAS]
+\installprettytype [MODULA] [PAS]
+\installprettytype [MOD] [PAS]
+
+\installprettytype [EIFFEL] [EIF]
+\installprettytype [EIF] [EIF]
+\installprettytype [E] [EIF]
+
+\installprettytype [XML] [XML]
+
+\installprettytype [LUA] [LUA]
+
+%D We use the \CONTEXT\ color system for switching to and from
+%D color mode. We can always redefine these colors afterwards.
+
+\definecolor [colorprettyone] [r=.9, g=.0, b=.0] % red
+\definecolor [colorprettytwo] [r=.0, g=.8, b=.0] % green
+\definecolor [colorprettythree] [r=.0, g=.0, b=.9] % blue
+\definecolor [colorprettyfour] [r=.8, g=.8, b=.6] % yellow
+
+\definecolor [grayprettyone] [s=.30]
+\definecolor [grayprettytwo] [s=.45]
+\definecolor [grayprettythree] [s=.60]
+\definecolor [grayprettyfour] [s=.75]
+
+\definepalet
+ [colorpretty]
+ [ prettyone=colorprettyone,
+ prettytwo=colorprettytwo,
+ prettythree=colorprettythree,
+ prettyfour=colorprettyfour]
+
+\definepalet
+ [graypretty]
+ [ prettyone=grayprettyone,
+ prettytwo=grayprettytwo,
+ prettythree=grayprettythree,
+ prettyfour=grayprettyfour]
+
+\definepalet [TEXcolorpretty] [colorpretty]
+\definepalet [TEXgraypretty] [graypretty]
+\definepalet [PLcolorpretty] [colorpretty]
+\definepalet [PLgraypretty] [graypretty]
+\definepalet [PMcolorpretty] [colorpretty]
+\definepalet [PMgraypretty] [graypretty]
+\definepalet [MPcolorpretty] [colorpretty]
+\definepalet [MPgraypretty] [graypretty]
+\definepalet [JVcolorpretty] [colorpretty]
+\definepalet [JVgraypretty] [graypretty]
+\definepalet [JScolorpretty] [colorpretty]
+\definepalet [JSgraypretty] [graypretty]
+\definepalet [SQLcolorpretty] [colorpretty]
+\definepalet [SQLgraypretty] [graypretty]
+\definepalet [PAScolorpretty] [colorpretty]
+\definepalet [PASgraypretty] [graypretty]
+\definepalet [EIFcolorpretty] [colorpretty]
+\definepalet [EIFgraypretty] [graypretty]
+\definepalet [XMLcolorpretty] [colorpretty]
+\definepalet [XMLgraypretty] [graypretty]
+\definepalet [LUAcolorpretty] [colorpretty]
+\definepalet [LUAgraypretty] [graypretty]
+
+% patched from verb-ini (todo)
+
+% \let\beginverbatimline\relax
+% \let\endverbatimline \relax
+
+% \appendtoks whatever\par\to\everyverbatimbeginofdisplay
+% \appendtoks whatever\to\everyverbatimendofdisplay
+% \appendtoks [\to\everyverbatimbeginofinline
+% \appendtoks ]\to\everyverbatimendofinline
+
+\let\doopenupverbatimline\empty
+
+\newtoks\everyverbatimbeginofdisplay
+\newtoks\everyverbatimendofdisplay
+\newtoks\everyverbatimbeginofinline
+\newtoks\everyverbatimendofinline
+
+\let\currentverbatimpretty\empty
+
+\def\doverbatimbeginofdisplay#1%
+ {\edef\currentverbatimpretty{#1}%
+ \the\everyverbatimbeginofdisplay}
+
+\def\doverbatimendofdisplay
+ {\the\everyverbatimendofdisplay}
+
+\def\doverbatimbeginofinline#1%
+ {\edef\currentverbatimpretty{#1}%
+ \the\everyverbatimbeginofinline}
+
+\def\doverbatimendofinline
+ {\the\everyverbatimendofinline}
+
+\def\doverbatimbeginofline#1% linenumber
+ {\bgroup % due to pretty status
+ \iflinepar\else\EveryPar{}\fi
+ \noindent % was wrong: \dontleavehmode
+ \xdef\dokeepverbatimlinedata % hm, still needed?
+ {\parindent \the\parindent
+ \hangindent\the\hangindent
+ \hangafter \the\hangafter
+ \leftskip \the\leftskip
+ \rightskip \the\rightskip}%
+ \egroup
+ \dokeepverbatimlinedata
+ \doopenupverbatimline
+ \the\everyline\strut
+ }%\beginverbatimline}
+
+\def\doverbatimendofline
+ {%\endverbatimline
+ \global\lineparfalse
+ \obeyedline\par}
+
+\def\doverbatimemptyline
+ {\strut
+ \par
+ \global\linepartrue}
+
+\protect \endinput
diff --git a/tex/context/base/bxml-apa.mkiv b/tex/context/base/bxml-apa.mkiv
new file mode 100644
index 000000000..5fc87e5ef
--- /dev/null
+++ b/tex/context/base/bxml-apa.mkiv
@@ -0,0 +1,613 @@
+%D \module
+%D [ file=bxml-apa,
+%D version=2010.05.14, % based on bibl-apa.tex
+%D title=APA bibliography style,
+%D subtitle=Publications,
+%D author={Taco Hoekwater \& Hans Hagen},
+%D date=\currentdate,
+%D copyright={Hans Hagen \& Taco Hoekwater}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+% helpers (todo)
+
+\let\maybeyear\firstofoneargument
+\let\etalchar \firstofoneargument
+
+\setupbibtexcitationvariants
+ [author,year]
+ [\c!andtext={ and },
+ \c!otherstext={ et al.},
+ \c!pubsep={, },
+ \c!lastpubsep={ and },
+ \c!compress=\v!no,
+ \c!inbetween={ },
+ \c!left={(},
+ \c!right={)}]
+
+\setupbibtexcitationvariants
+ [authoryear]
+ [\c!andtext={ and },
+ \c!otherstext={ et al.},
+ \c!pubsep={, },
+ \c!lastpubsep={ and },
+ \c!compress=\v!yes,
+ \c!inbetween={ },
+ \c!left={(},
+ \c!right={)}]
+
+\setupbibtexcitationvariants
+ [authoryears]
+ [\c!andtext={ and },
+ \c!otherstext={ et al.},
+ \c!pubsep={, },
+ \c!lastpubsep={ and },
+ \c!compress=\v!yes,
+ \c!inbetween={, },
+ \c!left={(},
+ \c!right={)}]
+
+\setupbibtexcitationvariants
+ [key,serial,authornum,page,short,type,doi,url]
+ [\c!andtext={ and },
+ \c!otherstext={ et al.},
+ \c!pubsep={, },
+ \c!lastpubsep={ and },
+ \c!compress=\v!no,
+ \c!inbetween={ },
+ \c!left={[},
+ \c!right={]}]
+
+\setupbibtexcitationvariants
+ [num]
+ [\c!andtext={ and },
+ \c!otherstext={ et al.},
+ \c!pubsep={, },
+ \c!lastpubsep={ and },
+ \c!compress=\v!yes,
+ \c!inbetween={--},
+ \c!left={[},
+ \c!right={]}]
+
+\setupbibtexpublications
+ [\c!sorttype=,
+ \c!criterium=,
+ \c!refcommand=authoryears,
+ \c!numbering=\v!no,
+ \c!autohang=\v!no]
+
+\setupbibtexpublications
+ [\c!width=2em, % 24pt,
+ \c!artauthor=invertedshort,
+ \c!editor=invertedshort,
+ \c!author=invertedshort,
+ \c!namesep={, },
+ \c!lastnamesep={ and },
+ \c!finalnamesep={ and },
+ \c!firstnamesep={, },
+ \c!juniorsep={ },
+ \c!vonsep={ },
+ \c!surnamesep={, },
+ \c!authoretallimit=5,
+ \c!editoretallimit=5,
+ \c!artauthoretallimit=5,
+ \c!authoretaldisplay=5,
+ \c!editoretaldisplay=5,
+ \c!artauthoretaldisplay=5,
+ \c!authoretaltext={ et al.},
+ \c!editoretaltext={ et al.},
+ \c!artauthoretaltext={ et al.}]
+
+% common
+
+\startxmlsetups bibtex:apa:common:wherefrom
+ \bibxmldoifelse {address} {
+ \getvariable{bibtex:temp}{left}
+ \bibxmldoifelse {country} {
+ \bibxmldoifelse {\getvariable{bibtex:temp}{label}} {
+ \bibxmlflush{address}\bibtexcomma\bibxmlflush{country}: \bibxmlflush{\getvariable{bibtex:temp}{label}}
+ } {
+ \bibxmlflush{address}\bibtexcomma\bibxmlflush{country}
+ }
+ } {
+ \bibxmldoifelse {\getvariable{bibtex:temp}{label}} {
+ \bibxmlflush{address}\bibtexcomma\bibxmlflush{\getvariable{bibtex:temp}{label}}
+ } {
+ \bibxmlflush{address}
+ }
+ }
+ \getvariable{bibtex:temp}{right}
+ } {
+ \bibxmldoifelse {country} {
+ \getvariable{bibtex:temp}{left}
+ \bibxmldoifelse {\getvariable{bibtex:temp}{label}} {
+ \bibxmlflush{country}: \bibxmlflush{\getvariable{bibtex:temp}{label}}
+ } {
+ \bibxmlflush{country}
+ }
+ \getvariable{bibtex:temp}{right}
+ } {
+ \bibxmldoifelse {\getvariable{bibtex:temp}{label}} {
+ \getvariable{bibtex:temp}{left}
+ \bibxmlflush{\getvariable{bibtex:temp}{label}}
+ \getvariable{bibtex:temp}{right}
+ } {
+ \getvariable{bibtex:temp}{otherwise}
+ }
+ }
+ }
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:publisher
+ \setvariables[bibtex:temp][label=publisher,left=,right=,otherwise=]\relax
+ \bibxmlsetup{bibtex:apa:common:wherefrom}
+\stopxmlsetups
+\startxmlsetups bibtex:apa:common:organization
+ \setvariables[bibtex:temp][label=organization,left=,right=,otherwise=]\relax
+ \bibxmlsetup{bibtex:apa:common:wherefrom}
+\stopxmlsetups
+\startxmlsetups bibtex:apa:common:school
+ \setvariables[bibtex:temp][label=school,left=,right=,otherwise=]\relax
+ \bibxmlsetup{bibtex:apa:common:wherefrom}
+\stopxmlsetups
+\startxmlsetups bibtex:apa:common:institution
+ \setvariables[bibtex:temp][label=institution,left=,right=,otherwise=]\relax
+ \bibxmlsetup{bibtex:apa:common:wherefrom}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:school:subsentence
+ \setvariables[bibtex:temp][label=school,left=\bibtexcomma,right=\bibtexperiod,otherwise=\bibtexperiod]\relax
+ \bibxmlsetup{bibtex:apa:common:wherefrom}
+\stopxmlsetups
+\startxmlsetups bibtex:apa:common:institution:subsentence
+ \setvariables[bibtex:temp][label=institution,left=\bibtexcomma,right=\bibtexperiod,otherwise=\bibtexperiod]\relax
+ \bibxmlsetup{bibtex:apa:common:wherefrom}
+\stopxmlsetups
+\startxmlsetups bibtex:apa:common:publisher:sentence
+ \setvariables[bibtex:temp][label=publisher,left=\bibtexspace,right=\bibtexperiod,otherwise=]\relax
+ \bibxmlsetup{bibtex:apa:common:wherefrom}
+\stopxmlsetups
+\startxmlsetups bibtex:apa:common:organization:sentence
+ \setvariables[bibtex:temp][label=organization,left=\bibtexspace,right=\bibtexperiod,otherwise=]\relax
+ \bibxmlsetup{bibtex:apa:common:wherefrom}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:title-and-series
+ \bibxmldoif {title} {
+ \bibxmlflush{title}
+ \bibxmldoif {series} {
+ \bibtexlparent\bibxmlflush{series}\bibtexrparent
+ }
+ \bibtexperiod
+ }
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:title-it-and-series
+ \bibxmldoif {title} {
+ \bgroup\it\bibxmlflush{title}\/\egroup
+ \bibxmldoif {series} {
+ \bibtexlparent\bibxmlflush{series}\bibtexrparent
+ }
+ \bibtexperiod
+ }
+\stopxmlsetups
+
+\disablemode[bibtex:apa:edited-book]
+
+\startxmlsetups bibtex:apa:common:author-and-year
+ \bibxmldoif {author} {
+ \bibxmlsetup{bibtex:format:author}
+ }
+ \bibxmldoif {year} {
+ \bibtexlparent\bibxmlflush{year}\bibtexrparent
+ }
+ \bibtexperiod
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:author-or-key-and-year
+ \bibxmldoifelse {author} {
+ \bibxmlsetup{bibtex:format:author}
+ } {
+ \bibxmldoif {key} {
+ \bibtexlbracket\bibxmlsetup{bibtex:format:key}\bibtexrbracket
+ }
+ }
+ \bibxmldoif {year} {
+ \bibtexlparent\bibxmlflush{year}\bibtexrparent
+ }
+ \bibtexperiod
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:author-editors-crossref-year
+ \bibxmldoif {author} {
+ \bibxmlsetup{bibtex:format:author}
+ } {
+ \bibxmldoifelse {editor} {
+ \enablemode[bibtex:apa:edited-book]
+ \xmlsetup{#1}{bibtex:format:editor}
+ \bibtexcomma\bibtexsingularplural{editor}{editors}
+ } {
+ % weird period
+ \bibxmldoif {crossref} {
+ \bibtexlbracket\bibxmlsetup{bibtex:format:crossref}\bibtexrbracket\bibtexperiod
+ }
+ }
+ }
+ \bibxmldoif {year} {
+ \bibtexlparent\bibxmlflush{year}\bibtexrparent
+ }
+ \bibtexperiod
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:editor-or-key-and-year
+ \bibxmldoifelse {editor} {
+ \enablemode[bibtex:apa:edited-book]
+ \xmlsetup{#1}{bibtex:format:editor}
+ \bibtexcomma\bibtexsingularplural{editor}{editors}
+ } {
+ \bibxmldoif {key} {
+ \bibtexlbracket\bibxmlsetup{bibtex:format:key}\bibtexrbracket
+ }
+ }
+ \bibtexspace
+ \bibxmldoif {year} {
+ \bibtexlparent\bibxmlflush{year}\bibtexrparent
+ }
+ \bibtexperiod
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:note
+ \bibxmldoif {note} {
+ \bibtexspace\bibxmlflush{note}\bibtexperiod
+ }
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:comment
+ \bibxmldoif {comment} {
+ \bibtexspace\bibxmlflush{comment}\bibtexperiod
+ }
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:pages:p
+ \bibxmldoif {pages} {
+ \bibtexspace\bibxmlflush{pages}\bibtexspace p\bibtexperiod
+ }
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:pages:pp
+ \bibxmldoif {pages} {
+ \bibtexspace\bibxmlflush{pages}\bibtexspace pp\bibtexperiod
+ }
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:pages:pages
+ \bibxmldoif {pages} {
+ \bibtexcomma pages~\bibxmlflush{pages}
+ }
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:edition:sentense
+ \bibxmldoif {edition} {
+ \bibtexspace\bibxmlflush{edition}\bibtexspace edition\bibtexperiod
+ }
+\stopxmlsetups
+
+% check ewhen the next is used (no period)
+
+% \startxmlsetups bibtex:apa:common:edition
+% \bibxmldoif {edition} {
+% \bibtexspace\bibxmlflush{edition}\bibtexspace edition
+% }
+% \stopxmlsetups
+
+% we can share more, todo
+
+% specific
+
+\startxmlsetups bibtex:apa:article
+ \bibxmlsetup{bibtex:apa:common:author-or-key-and-year}
+ \bibxmldoif {title} {
+ \bibxmlflush{title}\bibtexperiod
+ }
+ \bibxmldoifelse {journal} {
+ \bgroup\it\bibxmlflush{journal}\/\egroup
+ } {
+ \bibxmldoif {crossref} {
+ In\bibtexspace\bibxmlflush{crossref}
+ }
+ }
+ \bibxmldoifelse {volume} {
+ \bibtexcomma\bgroup\it\bibxmlflush{volume}\/\egroup
+ \bibxmldoif {issue} {
+ \bibtexlparent\bibxmlflush{issue}\bibtexlparent
+ }
+ \bibxmldoif {pages} {
+ \bibtexcomma\bibxmlflush{pages}
+ }
+ \bibtexperiod
+ } {
+ \bibxmlsetup{bibtex:apa:common:pages:pp}
+ }
+ \bibxmlsetup{bibtex:apa:common:note}
+ \bibxmlsetup{bibtex:apa:common:comment}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:book
+ \bibxmlsetup{bibtex:apa:common:author-editors-crossref-year}
+ \bibxmldoif {title} {
+ \bgroup\it\bibxmlflush{title}\/\egroup
+ \doifmodeelse {bibtex:apa:edited-book} {
+ \bibxmldoifelse {volume} {
+ \bibtexspace Number\nonbreakablespace\bibxmlflush{volume}
+ \bibxmldoifelse {series} {
+ \bibtexspace in\nonbreakablespace\bibxmlflush{series}\bibtexperiod
+ } {
+ \bibxmldoifelse {crossref} {
+ \bibtexspace in\bibtexlbracket\bibxmlsetup{bibtex:format:crossref}\bibtexrbracket
+ } {
+ \bibtexperiod
+ }
+ }
+ } {
+ \bibxmldoif {series} {
+ \bibtexspace\bibxmlflush{series}
+ }
+ \bibtexperiod
+ }
+ } {
+ \bibxmldoifelse {crossref} {
+ \bibxmldoif {chapter} {
+ \bibtexcomma\bibxmlflush{chapter}
+ }
+ \bibxmlsetup{bibtex:apa:common:pages:pages}
+ \bibtexperiod
+ \bibxmldoif {volume} {
+ Volume\nonbreakablespace\bibxmlflush{volume}\bibtexspace of\nonbreakablespace
+ }
+ } {
+ \bibxmldoif {volume} {
+ \bibtexcomma volume\nonbreakablespace\bibxmlflush{volume}
+ \bibxmldoif {series} {
+ \bibtexspace of\nonbreakablespace\bgroup\it\bibxmlflush{series}\/\egroup
+ }
+ \bibxmldoif {chapter} {
+ \bibtexcomma\bibxmlflush{chapter}
+ }
+ \bibxmlsetup{bibtex:apa:common:pages:pages}
+ \bibtexperiod
+ }
+ }
+ }
+ }
+ \bibxmlsetup{bibtex:apa:common:edition:sentence}
+ \bibxmlsetup{bibtex:apa:common:publisher:sentence}
+ \bibxmlsetup{bibtex:apa:common:pages:p}% twice?
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:inbook
+ \bibxmlsetup{bibtex:apa:common:author-editors-crossref-year}
+ \bibxmldoifelse {title} {
+ \bgroup\it\bibxmlflush{title}\/\egroup
+ } {
+ \doifmodeelse {bibtex:apa:edited-book} {
+ \bibxmldoifelse {volume} {
+ \bibtexspace number\nonbreakablespace\bibxmlflush{volume}
+ \bibxmldoifelse {series} {
+ \bibtexspace in\nonbreakablespace\bibxmlflush{series}\bibtexperiod
+ } {
+ \bibxmldoifelse {crossref} {
+ \bibtexspace in\bibtexlbracket\bibxmlsetup{bibtex:format:crossref}\bibtexrbracket
+ } {
+ \bibtexperiod
+ }
+ }
+ } {
+ \bibxmldoif {series} {
+ \bibtexspace\bibxmlflush{series}\bibtexperiod
+ }
+ }
+ } {
+ \bibxmldoifelse {crossref} {
+ \bibxmldoif {chapter} {
+ \bibtexcomma\bibxmlflush{chapter}
+ }
+ \bibxmlsetup{bibtex:apa:common:pages:pages}
+ \bibxmldoif {volume} {
+ Volume\nonbreakablespace\bibxmlflush{volume}\bibtexspace of\nonbreakablespace
+ }
+ \bibxmldoif {crossref} {
+ \bibtexlbracket\bibxmlsetup{bibtex:format:crossref}\bibtexrbracket
+ }
+ } {
+ \bibxmldoif {volume} {
+ \bibtexcomma volume\nonbreakablespace\bibxmlflush{volume}
+ \bibxmldoif {series} {
+ \bibtexspace of\nonbreakablespace\bgroup\it\bibxmlflush{series}\/\egroup
+ }
+ \bibxmldoif {chapter} {
+ \bibtexcomma\bibxmlflush{chapter}
+ }
+ \bibxmlsetup{bibtex:apa:common:pages:pages}
+ \bibtexperiod
+ }
+ }
+ }
+ }
+ \bibtexspace
+ \bibxmlsetup{bibtex:apa:common:edition:sentence}
+ \bibxmlsetup{bibtex:apa:common:publisher}
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:booklet
+ \bibxmlsetup{bibtex:apa:common:author-or-key-and-year}
+ \bibxmlsetup{bibtex:apa:common:title-it-and-series}
+ \bibxmlsetup{bibtex:apa:common:edition:sentence}
+ \bibxmlsetup{bibtex:apa:common:publication:sentence}
+ \bibxmlsetup{bibtex:apa:common:pages:p}
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:manual
+ \bibxmlsetup{bibtex:apa:common:author-or-key-and-year}
+ \bibxmlsetup{bibtex:apa:common:title-it-and-series}
+ \bibxmlsetup{bibtex:apa:common:edition:sentence}
+ \bibxmlsetup{bibtex:apa:common:organization:sentence}
+ \bibxmlsetup{bibtex:apa:common:pages:p}
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:incollection
+ \bibxmlsetup{bibtex:apa:common:author-and-year}
+ \bibxmldoif {arttitle} {
+ \bibxmlflush{arttitle}\bibtexperiod
+ }
+ In\bibtexspace
+ \bibxmldoifelse {title} {
+ \bibxmlsetup{bibtex:format:editors}\bibtexcomma
+ \bgroup\it\bibxmlflush{title}\/\egroup
+ \bibxmldoif {series} {
+ \bibxmldoif {volume} {
+ \bibtexcomma number\bibtexspace\bibxmlflush{volume}\bibtexspace in
+ }
+ \bibtexspace\bibxmlflush{series}
+ }
+ \bibxmldoif {chapter} {
+ \bibtexcomma\bibxmlflush{chapter}\bibtexspace
+ }
+ \bibxmlsetup{bibtex:apa:common:pages:pages}
+ \bibxmldoif {edition} {
+ \bibtexspace\bibxmlflush{edition}\bibtexspace edition
+ }
+ \bibxmlsetup{bibtex:apa:common:publisher:sentence}
+ } {
+ \bibxmldoif {crossref} {
+ \bibtexlbracket\bibxmlsetup{bibtex:format:crossref}\bibtexrbracket
+ }
+ \bibxmldoif {chapter} {
+ \bibtexcomma\bibxmlflush{chapter}
+ }
+ \bibtexspace
+ \bibxmlsetup{bibtex:apa:common:pages:pages}
+ }
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:inproceedings
+ \bibxmlsetup{bibtex:apa:common:author-and-year}
+ \bibxmldoif {arttitle} {
+ \bibxmlflush{arttitle}\bibtexperiod
+ }
+ In\bibtexspace
+ \bibxmldoifelse {title} {
+ \bibxmldoif {editors} {
+ \bibxmlflush{bibtex:apa:format:editors}
+ \bibtexcomma\bibtexsingularplural{editor}{editors}\bibtexcomma
+ }
+ \bgroup\it\bibxmlflush{title}\/\egroup
+ \bibxmldoif {series} {
+ \bibxmldoif {volume} {
+ \bibtexcomma number~\bibxmlflush{volume} in
+ }
+ \bibtexspace
+ \bibxmlflush{series}
+ }
+ \bibxmldoif {chapter} {
+ \bibtexcomma\bibxmlflush{chapter}\bibtexspace
+ }
+ \bibxmlsetup{bibtex:apa:common:pages:pages}
+ \bibtexperiod
+ \bibxmlsetup{bibtex:apa:common:organization:sentence}
+ } {
+ \bibxmldoif {crossref} {
+ \bibtexlbracket\bibxmlsetup{bibtex:format:crossref}\bibtexrbracket
+ }
+ \bibxmldoif {chapter} {
+ \bibtexcomma\bibxmlflush{chapter}\bibtexspace
+ }
+ \bibxmlsetup{bibtex:apa:common:pages:pages}
+ \bibtexperiod
+ }
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:proceedings
+ \bibxmlsetup{bibtex:apa:common:editor-or-key-and-year}
+ \bibxmldoif {title} {
+ \bgroup\it\bibxmlflush{title}\/\egroup
+ \bibxmldoif {volume} {
+ \bibtexcomma number\bibtexspace\bibxmlflush{volume}\bibtexspace in\bibtexspace
+ }
+ \bibxmldoif {chapter} {
+ \bibtexcomma\bibxmlflush{chapter}\bibtexspace
+ }
+ \bibxmlsetup{bibtex:apa:common:pages:pages}
+ \bibtexperiod
+ \bibxmlsetup{bibtex:apa:common:organization:sentence}
+ }
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:common:thesis
+ \bibxmlsetup{bibtex:apa:common:author-and-year}
+ \bibxmlsetup{bibtex:apa:common:title-it-and-series}
+ \bibxmldoifelse {type} {
+ \bibxmlflush{type}
+ } {
+ \getvariable{bibtex:temp}{label}
+ }
+ \bibxmlsetup{bibtex:apa:common:school:subsentence}
+ \bibxmlsetup{bibtex:apa:common:pages:p}
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:mastersthesis
+ \setvariables[bibtex:temp][label=Master's thesis]
+ \bibxmlsetup{bibtex:apa:common:thesis}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:phdthesis
+ \setvariables[bibtex:temp][label=PhD thesis]
+ \bibxmlsetup{bibtex:apa:common:thesis}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:techreport
+ \bibxmlsetup{bibtex:apa:common:author-and-year}
+ \bibxmlsetup{bibtex:apa:common:title-and-series}
+ \bibxmldoifelse {type} {
+ \bibxmlflush{type}
+ \bibxmldoif {volume} {
+ \bibtexspace\bibxmlflush{volume}
+ }
+ } {
+ \bibtexspace Technical Report
+ }
+ \bibxmlsetup{bibtex:apa:common:institution:subsentence}
+ \bibxmlsetup{bibtex:apa:common:pages:p}
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:misc
+ \bibxmlsetup{bibtex:apa:common:author-and-year}
+ \bibxmlsetup{bibtex:apa:common:title-and-series}
+ \bibxmlsetup{bibtex:apa:common:publisher:sentence}
+ \bibxmlsetup{bibtex:apa:common:pages:p}
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\startxmlsetups bibtex:apa:unpublished
+ \bibxmlsetup{bibtex:apa:common:author-and-year}
+ \bibxmlsetup{bibtex:apa:common:title-and-series}
+ \bibxmlsetup{bibtex:apa:common:pages:p}
+ \bibxmldoif {type} {
+ \bibtexlparent\bibxmlflush{type}\bibtexrparent
+ }
+ \bibxmlsetup{bibtex:apa:common:note}
+\stopxmlsetups
+
+\protect \endinput
diff --git a/tex/context/base/catc-act.tex b/tex/context/base/catc-act.tex
new file mode 100644
index 000000000..bc24562d7
--- /dev/null
+++ b/tex/context/base/catc-act.tex
@@ -0,0 +1,61 @@
+%D \module
+%D [ file=catc-act,
+%D version=2006.09.18,
+%D title=\CONTEXT\ Catcode Macros,
+%D subtitle=Default Catcode Tables,
+%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.
+
+%D This module deals with some active character handling. Use
+%D with care.
+
+%D \macros
+%D {installactivecharacter}
+
+\def\installactivecharacter#1 %
+ {\edef\temp{\detokenize{#1}}%
+ \cctcounterc\expandafter`\temp\relax % relax needed
+ \expandafter\startextendcatcodetable
+ \expandafter\ctxcatcodes\expandafter\catcode\the\cctcounterc\activecatcode
+ \stopextendcatcodetable
+ \letcatcodecommand \ctxcatcodes \cctcounterc \temp \relax
+ \ifnum\currentcatcodetable=\ctxcatcodes \setcatcodetable\ctxcatcodes \fi}
+
+%D \macros
+%D {defineactivecharacter}
+%D
+%D Use this one with care, esp in combination with catcode
+%D vectors. There are better ways now.
+
+\chardef\activehackcode=`~
+
+\def\defineactivecharacter #1#2 #3%
+ {\cctcounterc\uccode\activehackcode
+ \if#1"\uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1#2}\empty #1#2\else
+ \uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1#2}\empty`#1#2\fi
+ \catcode\uccode\activehackcode\activecatcode
+ \uppercase{\def\next{~}}%
+ \uccode\activehackcode\cctcounterc
+ \expandafter\expandafter\expandafter\def\expandafter\next\expandafter
+ {\expandafter\dohandleactivecharacter\next{#3}}}
+
+\chardef\activecharactermode\plusone % overloading still backward compatible
+
+\def\dodohandleactivecharacter#1#2{#2}
+\def\donthandleactivecharacter#1#2{\noexpand#1}
+
+\def\dohandleactivecharacter
+ {\ifcase\activecharactermode
+ \expandafter\donthandleactivecharacter
+ \else
+ \expandafter\dodohandleactivecharacter
+ \fi}
+
+\def\makecharacteractive #1 {\catcode`#1\active}
+
+\endinput
diff --git a/tex/context/base/catc-ctx.tex b/tex/context/base/catc-ctx.tex
new file mode 100644
index 000000000..21e7d0136
--- /dev/null
+++ b/tex/context/base/catc-ctx.tex
@@ -0,0 +1,250 @@
+%D \module
+%D [ file=catc-cys,
+%D version=2006.09.18,
+%D title=\CONTEXT\ Catcode Macros,
+%D subtitle=Extra Tables,
+%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.
+
+%D We prefer to define relevant catcode tables in this file instead
+%D of everywhere around.
+
+\ifdefined \ctxcatcodes \else \newcatcodetable \ctxcatcodes \fi
+\ifdefined \mthcatcodes \else \newcatcodetable \mthcatcodes \fi % math, not used, too tricky
+\ifdefined \xmlcatcodesn \else \newcatcodetable \xmlcatcodesn \fi % normal
+\ifdefined \xmlcatcodese \else \newcatcodetable \xmlcatcodese \fi % entitle
+\ifdefined \xmlcatcodesr \else \newcatcodetable \xmlcatcodesr \fi % reduce
+\ifdefined \typcatcodesa \else \newcatcodetable \typcatcodesa \fi % { }
+\ifdefined \typcatcodesb \else \newcatcodetable \typcatcodesb \fi % < >
+
+\startcatcodetable \ctxcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ % \catcode`\^^J = 10 % new
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+ \catcode`\~ = 13
+ \catcode`\| = 13
+\stopcatcodetable
+
+\startcatcodetable \prtcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+ \catcode`\@ = 11
+ \catcode`\! = 11
+ \catcode`\? = 11
+ \catcode`\~ = 13
+ \catcode`\| = 13
+\stopcatcodetable
+
+\startcatcodetable \mthcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ %\catcode`\^^J = 10 % new
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+ %\catcode`\~ = 13
+ %\catcode`\| = 13
+\stopcatcodetable
+
+\startcatcodetable \xmlcatcodesn
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\& = 13 % entity
+ \catcode`\< = 13 % element
+ \catcode`\> = 12
+ \catcode`\" = 12 % probably not needed any more
+ \catcode`\/ = 12 % probably not needed any more
+ \catcode`\' = 12 % probably not needed any more
+ \catcode`\~ = 12 % probably not needed any more
+ \catcode`\# = 12 % probably not needed any more
+ \catcode`\\ = 12 % probably not needed any more
+\stopcatcodetable
+
+\startcatcodetable \xmlcatcodese
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\& = 13 % entity
+ \catcode`\< = 13 % element
+ \catcode`\> = 12
+ \catcode`\# = 13
+ \catcode`\$ = 13
+ \catcode`\% = 13
+ \catcode`\\ = 13
+ \catcode`\^ = 13
+ \catcode`\_ = 13
+ \catcode`\{ = 13
+ \catcode`\} = 13
+ \catcode`\| = 13
+ \catcode`\~ = 13
+\stopcatcodetable
+
+\startcatcodetable \xmlcatcodesr
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\& = 13 % entity
+ \catcode`\< = 13 % element
+ \catcode`\> = 12
+ \catcode`\# = 13
+ \catcode`\$ = 13
+ \catcode`\% = 13
+ \catcode`\\ = 13
+ \catcode`\^ = 13
+ \catcode`\_ = 13
+ \catcode`\{ = 13
+ \catcode`\} = 13
+ \catcode`\| = 13
+ \catcode`\~ = 13
+\stopcatcodetable
+
+\startcatcodetable \typcatcodesa
+ \catcode`\^^I = 12
+ \catcode`\^^M = 12
+ \catcode`\^^L = 12
+ \catcode`\ = 12
+ \catcode`\^^Z = 12
+ \catcode`\{ = 1
+ \catcode`\} = 2
+\stopcatcodetable
+
+\startcatcodetable \typcatcodesb
+ \catcode`\^^I = 12
+ \catcode`\^^M = 12
+ \catcode`\^^L = 12
+ \catcode`\ = 12
+ \catcode`\^^Z = 12
+ \catcode`\< = 1
+ \catcode`\> = 2
+\stopcatcodetable
+
+\letcatcodecommand \ctxcatcodes `\| \relax
+\letcatcodecommand \ctxcatcodes `\~ \relax
+
+%letcatcodecommand \prtcatcodes `\| \relax % falls back on ctx
+%letcatcodecommand \prtcatcodes `\~ \relax % falls back on ctx
+
+\letcatcodecommand \xmlcatcodesn `\& \relax
+\letcatcodecommand \xmlcatcodesn `\< \relax
+
+\letcatcodecommand \xmlcatcodese `\& \relax
+\letcatcodecommand \xmlcatcodese `\< \relax
+
+\letcatcodecommand \xmlcatcodesr `\& \relax
+\letcatcodecommand \xmlcatcodesr `\< \relax
+
+\letcatcodecommand \xmlcatcodese `\# \relax
+\letcatcodecommand \xmlcatcodese `\$ \relax
+\letcatcodecommand \xmlcatcodese `\% \relax
+\letcatcodecommand \xmlcatcodese `\\ \relax
+\letcatcodecommand \xmlcatcodese `\^ \relax
+\letcatcodecommand \xmlcatcodese `\_ \relax
+\letcatcodecommand \xmlcatcodese `\{ \relax
+\letcatcodecommand \xmlcatcodese `\} \relax
+\letcatcodecommand \xmlcatcodese `\| \relax
+\letcatcodecommand \xmlcatcodese `\~ \relax
+
+\letcatcodecommand \xmlcatcodesr `\# \relax
+\letcatcodecommand \xmlcatcodesr `\$ \relax
+\letcatcodecommand \xmlcatcodesr `\% \relax
+\letcatcodecommand \xmlcatcodesr `\\ \relax
+\letcatcodecommand \xmlcatcodesr `\^ \relax
+\letcatcodecommand \xmlcatcodesr `\_ \relax
+\letcatcodecommand \xmlcatcodesr `\{ \relax
+\letcatcodecommand \xmlcatcodesr `\} \relax
+\letcatcodecommand \xmlcatcodesr `\| \relax
+\letcatcodecommand \xmlcatcodesr `\~ \relax
+
+ \catcodetable \ctxcatcodes
+\let\defaultcatcodetable\ctxcatcodes
+\let\xmlcatcodes \xmlcatcodesn % beware, in mkiv we use \notcatcodes
+
+\endinput
+
+% under consideration:
+%
+% \newcatcodetable\txtcatcodes
+%
+% \startcatcodetable \txtcatcodes
+% \catcode`\^^I = 10
+% \catcode`\^^M = 5
+% \catcode`\^^L = 5
+% \catcode`\ = 10
+% \catcode`\\ = 0
+% \catcode`\{ = 1
+% \catcode`\} = 2
+% \stopcatcodetable
+%
+% \newcount\relaxedcatcodedepth
+%
+% \def\startrelaxedcatcodes
+% {\global\chardef\relaxedcatcodeparent\catcodetable
+% \global\advance\relaxedcatcodedepth\plusone
+% \nonknuthmode\setcatcodetable\txtcatcodes}
+%
+% \def\stoprelaxedcatcodes
+% {\ifcase\relaxedcatcodedepth
+% % error
+% \or
+% \setcatcodetable\relaxedcatcodeparent
+% \global\relaxedcatcodedepth\zerocount
+% \else
+% \global\advance\relaxedcatcodedepth\minusone
+% \setcatcodetable\txtcatcodes
+% \fi}
+%
+% \starttext
+%
+% \startrelaxedcatcodes
+% \startcomment test \stopcomment
+% test $ test 10% whatever|test \mathematics{x^2=1}
+% \stoprelaxedcatcodes
+%
+% $x^2=1$
+%
+% \stoptext
diff --git a/tex/context/base/catc-def.tex b/tex/context/base/catc-def.tex
new file mode 100644
index 000000000..e80cfe125
--- /dev/null
+++ b/tex/context/base/catc-def.tex
@@ -0,0 +1,142 @@
+%D \module
+%D [ file=catc-def,
+%D version=2006.09.18,
+%D title=\CONTEXT\ Catcode Macros,
+%D subtitle=Default Tables,
+%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.
+
+%D The following catcode tables are rather \CONTEXT\ independent.
+
+\ifdefined\nilcatcodes \else \newcatcodetable \nilcatcodes \fi
+\ifdefined\texcatcodes \else \newcatcodetable \texcatcodes \fi
+\ifdefined\luacatcodes \else \newcatcodetable \luacatcodes \fi
+\ifdefined\notcatcodes \else \newcatcodetable \notcatcodes \fi
+\ifdefined\vrbcatcodes \else \newcatcodetable \vrbcatcodes \fi
+\ifdefined\prtcatcodes \else \newcatcodetable \prtcatcodes \fi
+
+\startcatcodetable \nilcatcodes
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+\stopcatcodetable
+
+\startcatcodetable \texcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+\stopcatcodetable
+
+\startcatcodetable \luacatcodes
+ \catcode`\^^I = 12 % ascii tab is a blank space
+ \catcode`\^^M = 12 % ascii return is end-line
+ \catcode`\^^L = 12 % ascii form-feed
+ \catcode`\ = 12 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\\ = 0
+ \catcode`\% = 12
+ \catcode`\# = 12
+ \catcode`\_ = 12
+ \catcode`\^ = 12
+ \catcode`\& = 12
+ \catcode`\| = 12
+ \catcode`\{ = 12
+ \catcode`\} = 12
+ \catcode`\~ = 12
+ \catcode`\$ = 12
+\stopcatcodetable
+
+\startcatcodetable \notcatcodes
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\~ = 12
+ \catcode`\# = 12 % probably too much, in principle
+ \catcode`\$ = 12 % nilcatcodes would be ok too
+ \catcode`\% = 12
+ \catcode`\^ = 12
+ \catcode`\& = 12
+ \catcode`\_ = 12
+ \catcode`\< = 12
+ \catcode`\> = 12
+ \catcode`\{ = 12
+ \catcode`\} = 12
+ \catcode`\" = 12
+ \catcode`\' = 12
+ \catcode`\/ = 12
+ \catcode`\\ = 12
+ \catcode`\| = 12
+\stopcatcodetable
+
+\startcatcodetable \vrbcatcodes % probably less needed
+ \catcode`\^^I = 12
+ \catcode`\^^M = 12
+ \catcode`\^^L = 12
+ \catcode`\ = 12
+ \catcode`\^^Z = 12
+\stopcatcodetable
+
+\startcatcodetable \prtcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+ \catcode`\@ = 11
+ \catcode`\! = 11
+ \catcode`\? = 11
+ \catcode`\~ = 13
+ \catcode`\| = 13
+\stopcatcodetable
+
+%D Because some characters have a special meaning, we provide
+%D shortcuts to their character representation.
+
+\chardef\%=`\%
+\chardef\&=`\&
+\chardef\#=`\#
+\chardef\$=`\$
+\chardef\{=`\{
+\chardef\}=`\}
+\chardef\\=`\\
+\chardef\^=`\^
+\chardef\_=`\_ % but way too wide in lm, so ... until that's fixed:
+
+%def\_{\leavevmode \kern.06em \vbox{\hrule width.3em}}
+\def\_{\dontleavehmode \kern.06em \vbox{\hrule width.3em}}
+
+%D From now on we can use the protection mechanisms.
+
+\def\unprotect {\pushcatcodetable\setcatcodetable\prtcatcodes}
+\def\protect {\popcatcodetable}
+
+\endinput
diff --git a/tex/context/base/catc-ini.lua b/tex/context/base/catc-ini.lua
new file mode 100644
index 000000000..2749f403c
--- /dev/null
+++ b/tex/context/base/catc-ini.lua
@@ -0,0 +1,33 @@
+if not modules then modules = { } end modules ['catc-ini'] = {
+ version = 1.001,
+ comment = "companion to catc-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+catcodes = catcodes or { }
+catcodes.numbers = catcodes.numbers or { }
+catcodes.names = catcodes.names or { }
+
+storage.register("catcodes/numbers", catcodes.numbers, "catcodes.numbers")
+storage.register("catcodes/names", catcodes.names, "catcodes.names")
+
+-- this only happens at initime
+
+function catcodes.register(name,number)
+ catcodes.numbers[name] = number
+ local cnn = catcodes.names[number]
+ if cnn then
+ cnn[#cnn+1] = name
+ else
+ catcodes.names[number] = { name }
+ end
+ tex[name] = number
+end
+
+-- this only happens at runtime
+
+for k, v in next, catcodes.numbers do
+ tex[k] = v
+end
diff --git a/tex/context/base/catc-ini.mkii b/tex/context/base/catc-ini.mkii
new file mode 100644
index 000000000..dee15290a
--- /dev/null
+++ b/tex/context/base/catc-ini.mkii
@@ -0,0 +1,249 @@
+%D \module
+%D [ file=catc-ini,
+%D version=2006.09.18,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Catcode Handling,
+%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.
+
+%D We've split the functionality of syst-cat.* over more files
+%D now so that we can load more selectively.
+
+%D A long standing wish has been the availability of catcode
+%D arrays. Because traditional \TEX\ does ot provide this we
+%D implement a fake method in the Mark II file.
+
+\ifx\zerocount\undefined \chardef \zerocount= 0 \fi
+\ifx\plusone \undefined \chardef \plusone = 1 \fi
+\ifx\minusone \undefined \newcount\minusone \minusone =-1 \fi
+
+\chardef\escapecatcode = 0
+\chardef\begingroupcatcode = 1
+\chardef\endgroupcatcode = 2
+\chardef\mathshiftcatcode = 3
+\chardef\alignmentcatcode = 4
+\chardef\endoflinecatcode = 5
+\chardef\parametercatcode = 6
+\chardef\superscriptcatcode = 7
+\chardef\subscriptcatcode = 8
+\chardef\ignorecatcode = 9
+\chardef\spacecatcode = 10
+\chardef\lettercatcode = 11
+\chardef\othercatcode = 12 \chardef\other = 12
+\chardef\activecatcode = 13 \chardef\active = 13
+\chardef\commentcatcode = 14
+
+\newif \ifrecatcodeuppercharacters % only used in good old tex
+
+% \newcount\cctdefcounter \cctdefcounter\plusone % 0 = signal
+\newcount\cctdefcounter \cctdefcounter\zerocount % 0 = signal, so advance before allocate
+
+\newcount\cctcountera
+\newcount\cctcounterb
+\newcount\cctcounterc
+
+\def\newcatcodetable#1%
+ {\global\advance\cctdefcounter\plusone
+ \global\mathchardef#1\cctdefcounter
+ \expandafter\xdef\csname @@ccn:\number\cctdefcounter\endcsname{\string#1}% logging
+ \expandafter\newtoks\csname @@cct:\number\cctdefcounter\endcsname}
+
+\mathchardef\currentcatcodetable\zerocount
+
+\newtoks \setdefaultlowercatcodes
+\newtoks \setdefaultuppercatcodes
+
+\def\next#1% we don't have a proper loop defined yet
+ {\edef\nextnext{#1{\the#1\catcode\the\cctcountera\space
+ \ifnum\catcode\cctcountera=\lettercatcode \lettercatcode\else\othercatcode\fi}}%
+ \nextnext\ifnum\cctcountera<\cctcounterb \advance\cctcountera\plusone \expandafter\next\expandafter#1\fi}
+
+\cctcountera 0 \cctcounterb 127 \next\setdefaultlowercatcodes
+\cctcountera 128 \cctcounterb 255 \next\setdefaultuppercatcodes
+
+\recatcodeuppercharactersfalse
+
+\def\catcodetable#1%
+ {\mathchardef\currentcatcodetable#1%
+ \the\setdefaultlowercatcodes
+ \ifrecatcodeuppercharacters\the\setdefaultuppercatcodes\fi
+ \the\csname @@cct:\number#1\endcsname}
+
+\long\def\startcatcodetable#1#2\stopcatcodetable
+ {\global\csname @@cct:\number#1\endcsname{#2}}
+
+\long\def\startextendcatcodetable#1#2\stopextendcatcodetable
+ {\global\csname @@cct:\number#1\endcsname\expandafter{\the\csname @@cct:\number#1\endcsname#2}}
+
+%D The next command can be defined in a cleaner way in the
+%D Mk IV file but we want to have a fast one with a minimal
+%D chance for interference.
+
+\chardef\activehackcode=`\~
+
+%D Once a catcode is assigned, the next assignments will happen faster.
+
+% (expandable) let
+
+\def\letcatcodecommand {\afterassignment\letcatcodecommanda\cctcountera}
+\def\letcatcodecommanda{\afterassignment\letcatcodecommandb\cctcounterb}
+
+\def\letcatcodecommandb % each time
+ {\ifcsname CCL:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\letcatcodecommandc
+ \fi}
+
+\def\letcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname\expandafter
+ {\expandafter\let\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname}%
+ \reinstatecatcodecommanda
+ \csname CCL:\number\cctcountera:\number\cctcounterb\endcsname}
+
+% expandable def
+
+\def\defcatcodecommand {\afterassignment\defcatcodecommanda\cctcountera}
+\def\defcatcodecommanda{\afterassignment\defcatcodecommandb\cctcounterb}
+
+\def\defcatcodecommandb % each time
+ {\ifcsname CCD:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\defcatcodecommandc
+ \fi}
+
+\def\defcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter
+ {\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
+ \reinstatecatcodecommanda
+ \csname CCD:\number\cctcountera:\number\cctcounterb\endcsname}
+
+% un expandable def (e.g. used for discretionaries)
+
+\def\uedcatcodecommand {\afterassignment\uedcatcodecommanda\cctcountera}
+\def\uedcatcodecommanda{\afterassignment\uedcatcodecommandb\cctcounterb}
+
+\def\uedcatcodecommandb % each time
+ {\ifcsname CCU:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\uedcatcodecommandc
+ \fi}
+
+\def\uedcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter
+ {\expandafter\unexpanded\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
+ \reinstatecatcodecommanda
+ \csname CCU:\number\cctcountera:\number\cctcounterb\endcsname}
+
+\def\reinstatecatcodecommand{\afterassignment\reinstatecatcodecommanda\cctcounterb}
+
+\def\reinstatecatcodecommanda % can be used when a direct definition has been done
+ {\bgroup % and the selector has been lost
+ \uccode\activehackcode\cctcounterb
+ \catcode\uccode\activehackcode\activecatcode
+ \uppercase{\xdef~{\noexpand\catcodecommand{\number\cctcounterb}}}%
+ \egroup}
+
+\chardef\defaultcatcodetable\zerocount
+
+\def\catcodecommand#1%
+ {\csname CCC:\number
+ \ifcsname CCC:\number\currentcatcodetable:\number#1\endcsname
+ \currentcatcodetable \else \defaultcatcodetable
+ \fi
+ :\number#1\endcsname}
+
+%D \macros
+%D {restorecatcodes,
+%D beginrestorecatcodes,endrestorecatcodes}
+%D
+%D We're not finished dealing \CATCODES\ yet. In \CONTEXT\ we
+%D use only one auxiliary file, which deals with tables of
+%D contents, registers, two pass tracking, references etc. This
+%D file, as well as files concerning graphics, is processed when
+%D needed, which can be in the mid of typesetting verbatim.
+%D However, when reading in data in verbatim mode, we should
+%D temporary restore the normal \CATCODES, and that's exactly
+%D what the next macros do. Saving the catcodes can be
+%D disabled by saying \type{\localcatcodestrue}.
+
+\let\savedcatcodetable\relax
+
+\newcount\catcoderestorelevel
+
+\def\pushcatcodetable
+ {\advance\catcoderestorelevel\plusone
+ \tracepushcatcodetable
+ \expandafter\mathchardef\csname scct:\number\catcoderestorelevel\endcsname\currentcatcodetable}
+
+\def\popcatcodetable
+ {\ifcase\catcoderestorelevel
+ \showcatcodenestingerror
+ \else
+ \expandafter\catcodetable\csname scct:\number\catcoderestorelevel\endcsname
+ \tracepopcatcodetable
+ \advance\catcoderestorelevel\minusone
+ \fi}
+
+\def\showcatcodenestingerror % can be overloaded
+ {\immediate\write16{}%
+ \immediate\write16{Fatal error: catcode push/pop mismatch. Fix this!}\wait\end
+ \immediate\write16{}}
+
+\def\restorecatcodes % takes previous level
+ {\ifnum\catcoderestorelevel>\plusone
+ \expandafter\catcodetable\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname
+ \fi}
+
+\newtoks\everycatcodetable
+
+\def\setcatcodetable#1%
+ {\catcodetable#1%
+ \the\everycatcodetable
+ \tracesetcatcodetable}
+
+\def\dotracecatcodetable#1{\immediate\write16{[#1]}}
+
+\def\tracecatcodetables
+ {\def\tracesetcatcodetable {\dotracecatcodetable{set \catcodetablename\space at \number\catcoderestorelevel}}%
+ \def\tracepushcatcodetable{\dotracecatcodetable{push \catcodetablename\space from \catcodetableprev\space at \number\catcoderestorelevel}}%
+ \def\tracepopcatcodetable {\dotracecatcodetable{pop \catcodetablename\space to \catcodetableprev\space at \number\catcoderestorelevel}}}
+
+\def\catcodetableprev
+ {\ifnum\numexpr\catcoderestorelevel-1\relax>\zerocount
+ \csname @@ccn:\number\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname\endcsname
+ \else
+ -%
+ \fi}
+
+\def\catcodetablename
+ {\ifnum\currentcatcodetable>\zerocount
+ \csname @@ccn:\number\currentcatcodetable\endcsname
+ \else
+ -%
+ \fi}
+
+\ifx\empty\undefined \def\empty{} \fi
+
+\let\tracesetcatcodetable \empty
+\let\tracepushcatcodetable\empty
+\let\tracepopcatcodetable \empty
+
+\def\beginrestorecatcodes{\pushcatcodetable}
+\def\endrestorecatcodes {\popcatcodetable}
+
+%D Handy for debugging:
+
+% \tracecatcodetables
+
+\endinput
+
diff --git a/tex/context/base/catc-ini.mkiv b/tex/context/base/catc-ini.mkiv
new file mode 100644
index 000000000..269330a1b
--- /dev/null
+++ b/tex/context/base/catc-ini.mkiv
@@ -0,0 +1,317 @@
+%D \module
+%D [ file=catc-ini,
+%D version=2006.09.18,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Catcode Handling,
+%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.
+
+%D We've split the functionality of syst-cat.* over more files
+%D now so that we can load more selectively.
+
+\registerctxluafile{catc-ini} {1.001}
+
+%D A long standing wish has been the availability of catcode
+%D arrays. Because traditional \TEX\ does not provide this we
+%D implement a fake method in the \MKII\ file. There is some
+%D overlap in code with \MKII\ but we take that for granted.
+
+\ifx\zerocount\undefined \chardef \zerocount= 0 \fi
+\ifx\plusone \undefined \chardef \plusone = 1 \fi
+\ifx\minusone \undefined \newcount\minusone \minusone =-1 \fi
+
+\chardef\escapecatcode = 0
+\chardef\begingroupcatcode = 1
+\chardef\endgroupcatcode = 2
+\chardef\mathshiftcatcode = 3
+\chardef\alignmentcatcode = 4
+\chardef\endoflinecatcode = 5
+\chardef\parametercatcode = 6
+\chardef\superscriptcatcode = 7
+\chardef\subscriptcatcode = 8
+\chardef\ignorecatcode = 9
+\chardef\spacecatcode = 10
+\chardef\lettercatcode = 11
+\chardef\othercatcode = 12 \chardef\other = 12
+\chardef\activecatcode = 13 \chardef\active = 13
+\chardef\commentcatcode = 14
+
+\ifx\gobbleoneargument\undefined \long\def\gobbleoneargument#1{} \fi
+
+\newif \ifrecatcodeuppercharacters % only used in good old tex
+
+\newcount\cctdefcounter \cctdefcounter\zerocount % 0 = signal, so advance before allocate
+
+\newcount\cctcountera
+\newcount\cctcounterb
+\newcount\cctcounterc
+
+\def\newcatcodetable#1%
+ {\global\advance\cctdefcounter\plusone
+ \expandafter\xdef\csname @@ccn:\number\cctdefcounter\endcsname{\string#1}% logging
+ \global\chardef#1\cctdefcounter
+ \ctxlua{catcodes.register("\expandafter\gobbleoneargument\string#1",\number#1)}%
+ % we have two ways to access catcodetable numbers
+ \startruntimectxluacode tex.\expandafter\gobbleoneargument\string#1 = \number#1 ;\stopruntimectxluacode}
+
+\newcatcodetable \scratchcatcodes \initcatcodetable\scratchcatcodes
+
+\newtoks \setdefaultcatcodes
+
+\setdefaultcatcodes
+ {\catcode`\\ \othercatcode
+ \catcode`\^^M \othercatcode
+ \catcode`\ \othercatcode
+ \catcode`\% \othercatcode
+ \catcode127 \othercatcode}
+
+\long\normalprotected\def\startcatcodetable#1#2\stopcatcodetable
+ {\bgroup
+ \catcodetable\scratchcatcodes
+ \the\setdefaultcatcodes
+ #2%
+ \savecatcodetable#1\relax
+ \egroup}
+
+\newcatcodetable\dummycatcodes
+
+\long\normalprotected\def\startextendcatcodetable#1#2\stopextendcatcodetable
+ {\bgroup
+ \catcodetable#1\relax
+ \globaldefs\plusone
+ #2%
+ \globaldefs\zerocount
+ \egroup}
+
+% ==
+%
+% \long\normalprotected\def\startextendcatcodetable#1#2\stopextendcatcodetable
+% {\bgroup
+% \scratchcounter\the\catcodetable
+% \catcodetable #1 #2
+% \catcodetable\scratchcounter
+% \egroup}
+
+\def\letcatcodecommand
+ {\afterassignment\letcatcodecommanda\cctcountera}
+
+\def\letcatcodecommanda
+ {\afterassignment\letcatcodecommandb\cctcounterb}
+
+\let\currentcatcodetable\catcodetable
+
+%D The next command can be defined in a cleaner way in the
+%D Mk IV file but we want to have a fast one with a minimal
+%D chance for interference. Do we still need this complex
+%D mechanism? Future versions of \MKIV\ might only use
+%D active characters for very special cases.
+
+\chardef\activehackcode=`\~
+
+%D Once a catcode is assigned, the next assignments will happen faster.
+
+% (expandable) let
+
+\def\letcatcodecommand {\afterassignment\letcatcodecommanda\cctcountera}
+\def\letcatcodecommanda{\afterassignment\letcatcodecommandb\cctcounterb}
+
+\def\letcatcodecommandb % each time
+ {\ifcsname CCL:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\letcatcodecommandc
+ \fi}
+
+\def\letcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname\expandafter
+ {\expandafter\let\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname}%
+ \reinstatecatcodecommandua % unexpanded
+ \csname CCL:\number\cctcountera:\number\cctcounterb\endcsname}
+
+% expandable def
+
+\def\defcatcodecommand {\afterassignment\defcatcodecommanda\cctcountera}
+\def\defcatcodecommanda{\afterassignment\defcatcodecommandb\cctcounterb}
+
+\def\defcatcodecommandb % each time
+ {\ifcsname CCD:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\defcatcodecommandc
+ \fi}
+
+\def\defcatcodecommandc % only first time (we could use \normalexpanded here)
+ {\expandafter\gdef\csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter
+ {\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
+ \reinstatecatcodecommanda
+ \csname CCD:\number\cctcountera:\number\cctcounterb\endcsname}
+
+% unexpandable def (e.g. used for discretionaries)
+
+\def\uedcatcodecommand {\afterassignment\uedcatcodecommanda\cctcountera}
+\def\uedcatcodecommanda{\afterassignment\uedcatcodecommandb\cctcounterb}
+
+\def\uedcatcodecommandb % each time
+ {\ifcsname CCU:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\uedcatcodecommandc
+ \fi}
+
+\def\uedcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter
+ {\expandafter\normalprotected\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
+ \reinstatecatcodecommandua % unexpanded
+ \csname CCU:\number\cctcountera:\number\cctcounterb\endcsname}
+
+\def\reinstatecatcodecommand{\afterassignment\reinstatecatcodecommanda\cctcounterb}
+
+\def\reinstatecatcodecommanda % can be used when a direct definition has been done
+ {\bgroup % and the selector has been lost
+ \uccode\activehackcode\cctcounterb
+ \catcode\uccode\activehackcode\activecatcode
+ \uppercase{\xdef~{\noexpand\catcodecommand{\number\cctcounterb}}}%
+ \egroup}
+
+\def\reinstatecatcodecommandua % can be used when a direct definition has been done
+ {\bgroup % and the selector has been lost
+ \uccode\activehackcode\cctcounterb
+ \catcode\uccode\activehackcode\activecatcode
+ \uppercase{\normalprotected\xdef~{\noexpand\catcodecommand{\number\cctcounterb}}}%
+ \egroup}
+
+\chardef\defaultcatcodetable\zerocount
+
+\def\catcodecommand#1%
+ {\csname CCC:\number
+ \ifcsname CCC:\number\currentcatcodetable:\number#1\endcsname
+ \currentcatcodetable \else \defaultcatcodetable
+ \fi
+ :\number#1\endcsname}
+
+%D \macros
+%D {restorecatcodes,
+%D beginrestorecatcodes,endrestorecatcodes}
+%D
+%D We're not finished dealing \CATCODES\ yet. In \CONTEXT\ we
+%D use only one auxiliary file, which deals with tables of
+%D contents, registers, two pass tracking, references etc. This
+%D file, as well as files concerning graphics, is processed when
+%D needed, which can be in the mid of typesetting verbatim.
+%D However, when reading in data in verbatim mode, we should
+%D temporary restore the normal \CATCODES, and that's exactly
+%D what the next macros do. Saving the catcodes can be
+%D disabled by saying \type{\localcatcodestrue}.
+
+\let\savedcatcodetable\relax
+
+\newcount\catcoderestorelevel
+
+\def\pushcatcodetable
+ {\advance\catcoderestorelevel\plusone
+ \tracepushcatcodetable
+ \expandafter\chardef\csname scct:\number\catcoderestorelevel\endcsname\currentcatcodetable}
+
+\def\popcatcodetable
+ {\ifcase\catcoderestorelevel
+ \showcatcodenestingerror
+ \else
+ \expandafter\catcodetable\csname scct:\number\catcoderestorelevel\endcsname
+ \tracepopcatcodetable
+ \advance\catcoderestorelevel\minusone
+ \fi}
+
+\def\showcatcodenestingerror % can be overloaded
+ {\immediate\write16{}%
+ \immediate\write16{Fatal error: catcode push/pop mismatch. Fix this!}\wait\end
+ \immediate\write16{}}
+
+\def\restorecatcodes % takes previous level
+ {\ifnum\catcoderestorelevel>\plusone
+ \expandafter\catcodetable\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname
+ \fi}
+
+\newtoks\everycatcodetable
+
+\def\setcatcodetable#1%
+ {\catcodetable#1%
+ \the\everycatcodetable
+ \tracesetcatcodetable}
+
+\def\dotracecatcodetable#1{\immediate\write16{[#1]}}
+
+\def\tracecatcodetables
+ {\def\tracesetcatcodetable {\dotracecatcodetable{set \catcodetablename\space at \number\catcoderestorelevel}}%
+ \def\tracepushcatcodetable{\dotracecatcodetable{push \catcodetablename\space from \catcodetableprev\space at \number\catcoderestorelevel}}%
+ \def\tracepopcatcodetable {\dotracecatcodetable{pop \catcodetablename\space to \catcodetableprev\space at \number\catcoderestorelevel}}}
+
+\def\catcodetableprev
+ {\ifnum\numexpr\catcoderestorelevel-1\relax>\zerocount
+ \csname @@ccn:\number\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname\endcsname
+ \else
+ -%
+ \fi}
+
+\def\catcodetablename
+ {\ifnum\currentcatcodetable>\zerocount
+ \csname @@ccn:\number\currentcatcodetable\endcsname
+ \else
+ -%
+ \fi}
+
+\ifx\empty\undefined \def\empty{} \fi
+
+\let\tracesetcatcodetable \empty
+\let\tracepushcatcodetable\empty
+\let\tracepopcatcodetable \empty
+
+\def\beginrestorecatcodes{\pushcatcodetable}
+\def\endrestorecatcodes {\popcatcodetable}
+
+%D Handy for debugging:
+
+% \tracecatcodetables
+
+%D Only in \MKIV\ (to be used when crossing pages with changed catcodes
+%D in the current vector):
+%D
+%D \starttyping
+%D \normalprotected\def\startcrap
+%D {\bgroup
+%D \pushcatcodes
+%D \whitespace
+%D \obeylines
+%D \activatespacehandler\v!yes
+%D \strut}
+%D
+%D \normalprotected\def\stopcrap
+%D {\popcatcodes
+%D \egroup}
+%D \stoptyping
+
+\newcount\catcodetablelevel
+
+\def\pushcatcodes
+ {\bgroup
+ \global\advance\catcodetablelevel\plusone
+ \ifcsname @@ccf:\number\catcodetablelevel\endcsname \else
+ \global\advance\cctdefcounter\plusone
+ \expandafter\global\expandafter\chardef\csname @@ccf:\number\catcodetablelevel\endcsname\cctdefcounter
+ \fi
+ \catcodetable\ctxcatcodes
+ \expandafter\savecatcodetable\csname @@ccf:\number\catcodetablelevel\endcsname
+ \egroup
+ \expandafter\catcodetable\csname @@ccf:\number\catcodetablelevel\endcsname}
+
+\def\popcatcodes
+ {\global\advance\catcodetablelevel\minusone}
+
+\endinput
+
diff --git a/tex/context/base/catc-sym.tex b/tex/context/base/catc-sym.tex
new file mode 100644
index 000000000..067e192c8
--- /dev/null
+++ b/tex/context/base/catc-sym.tex
@@ -0,0 +1,187 @@
+%D \module
+%D [ file=catc-sym,
+%D version=1997.01.03, % moved code
+%D title=\CONTEXT\ Catcode Macros,
+%D subtitle=Some Handy Constants,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% we now have loaded syst-* so we have all @@catcode constants
+
+%D We want to have access to the raw alternatives of the
+%D special characters. We use a \type {\xdef} instead of
+%D \type {\let} because we need an expandable token in a
+%D \type {\write}.
+
+\bgroup
+
+\catcode`B=\begingroupcatcode
+\catcode`E=\endgroupcatcode
+\catcode`.=\escapecatcode
+
+.catcode `.{ 12 .xdef .letteropenbrace B.string{E
+.catcode `.} 12 .xdef .letterclosebrace B.string}E
+.catcode `.& 12 .xdef .letterampersand B.string&E
+.catcode `.< 12 .xdef .letterless B.string 12 .xdef .lettermore B.string>E
+.catcode `.# 12 .xdef .letterhash B.string#E
+.catcode `." 12 .xdef .letterdoublequote B.string"E
+.catcode `.' 12 .xdef .lettersinglequote B.string'E
+.catcode `.$ 12 .xdef .letterdollar B.string$E
+.catcode `.% 12 .xdef .letterpercent B.string%E
+.catcode `.^ 12 .xdef .letterhat B.string^E
+.catcode `._ 12 .xdef .letterunderscore B.string_E
+.catcode `.| 12 .xdef .letterbar B.string|E
+.catcode `.~ 12 .xdef .lettertilde B.string~E
+.catcode `.\ 12 .xdef .letterbackslash B.string\E
+.catcode `./ 12 .xdef .letterslash B.string/E
+.catcode `.? 12 .xdef .letterquestionmark B.string?E
+.catcode `.! 12 .xdef .letterexclamationmark B.string!E
+.catcode `.@ 12 .xdef .letterat B.string@E
+.catcode `.: 12 .xdef .lettercolon B.string:E
+
+ .global .let .letterescape .letterbackslash
+ .global .let .letterbgroup .letteropenbrace
+ .global .let .letteregroup .letterclosebrace
+ .global .let .letterleftbrace .letteropenbrace
+ .global .let .letterrightbrace .letterclosebrace
+
+.egroup
+
+%D \macros
+%D {uncatcodespecials,setnaturalcatcodes,setnormalcatcodes,
+%D uncatcodecharacters,uncatcodeallcharacters,
+%D uncatcodespacetokens}
+%D
+%D The following macros are more or less replaced by switching
+%D to a catcode table (which we simulate in \MKII) but we keep
+%D them for convenience and compatibility. Some old engine code
+%D has been removed.
+
+\def\uncatcodespecials {\setcatcodetable\nilcatcodes \uncatcodespacetokens}
+\def\setnaturalcatcodes {\setcatcodetable\nilcatcodes}
+\def\setnormalcatcodes {\setcatcodetable\ctxcatcodes} % maybe \texcatcodes
+\def\uncatcodecharacters {\setcatcodetable\nilcatcodes} % was fast version, gone now
+\def\uncatcodeallcharacters{\setcatcodetable\nilcatcodes} % was slow one, with restore
+
+\def\uncatcodespacetokens
+ {\catcode`\ =\spacecatcode
+ \catcode`\^^L=\ignorecatcode
+ \catcode`\^^M=\endoflinecatcode
+ \catcode`\^^?=\ignorecatcode}
+
+%D \macros
+%D {setverbosecharacter,setverbosecscharacters}
+%D
+%D Next follows a definition that lets some shortcuts expand to
+%D themselves. This macro is meant for \POSTSCRIPT\ and \PDF\
+%D code passed on to the backend.
+
+\newtoks\everyverbosechacters
+
+\def\setverbosecscharacter#1%
+ {\edef#1{\string#1}}
+
+\def\setverbosecscharacters
+ {\the\everyverbosechacters}
+
+\bgroup
+
+ % if used often we can move the code inline
+
+ \catcode`\|=\activecatcode
+ \catcode`\~=\activecatcode
+
+ \global \everyverbosechacters =
+ {\setverbosecscharacter |\setverbosecscharacter ~% context specific
+ \setverbosecscharacter\|\setverbosecscharacter\~%
+ \setverbosecscharacter\:\setverbosecscharacter\;%
+ \setverbosecscharacter\+\setverbosecscharacter\-%
+ \setverbosecscharacter\[\setverbosecscharacter\]%
+ \setverbosecscharacter\.\setverbosecscharacter\\%
+ \setverbosecscharacter\)\setverbosecscharacter\(%
+ \setverbosecscharacter\0\setverbosecscharacter\1%
+ \setverbosecscharacter\2\setverbosecscharacter\3%
+ \setverbosecscharacter\4\setverbosecscharacter\5%
+ \setverbosecscharacter\6\setverbosecscharacter\7%
+ \setverbosecscharacter\8\setverbosecscharacter\9%
+ \setverbosecscharacter\n\setverbosecscharacter\s%
+ \setverbosecscharacter\/}
+
+\egroup
+
+%D (Inspired by a discussion on the \CONTEXT\ mailing list)
+%D
+%D In \TEX\ each character can have one of 16 catcodes. This way the
+%D backslash, dollar, ampersand, hash and some more characters get
+%D their special meaning. If you want to process tokens under a
+%D certain catcode regime, passing arguments can interfere badly.
+%D
+%D \startbuffer[a]
+%D \def\whatever#1{[#1]}
+%D \whatever{whatever \type {\whatever{you want}} $or$ not!}
+%D \stopbuffer
+%D
+%D \typebuffer[a]
+%D
+%D Here we pass an argument to \type {\whatever} but part of that
+%D argument is to be processed under a different catcode regime, i.e.\
+%D all characters that need to be typeset verbatim need to get
+%D the catcode that makes it a letter. This is what we get when we typeset
+%D the text verbatim:
+%D
+%D \starttyping
+%D whatever \type {\whatever{you want}} $or$ not!
+%D \stoptyping
+%D
+%D However, when passed to \type {\whatever} we get:
+%D
+%D \getbuffer[a]
+%D
+%D In \ETEX\ one can use \type {\scantokens} to circumvent this problem.
+%D
+%D \startbuffer[b]
+%D \def\rescan#1{\scantokens{#1}}
+%D \def\whatever#1{[\rescan{#1}]}
+%D \whatever{whatever \type {\whatever{you want}} $or$ not!}
+%D \stopbuffer
+%D
+%D \getbuffer[b] \typebuffer[b]
+%D
+%D This time the \type {\whatever} call gives:
+%D
+%D \getbuffer[b]
+%D
+%D In this example, two spaces have crept in. The first one, after the
+%D macro name, is inserted by \TEX\ and cannot be avoided. The last space
+%D is inserted by \type {\scantokens}, and is the consequence of the fact
+%D that this macro mimics reading from a file. You can avoid the last
+%D space by a slightly different definition:
+%D
+%D \startbuffer[c]
+%D \def\rescan#1{\scantokens{#1\ignorespaces}}
+%D \def\whatever#1{[\rescan{#1}]}
+%D \whatever{whatever \type {\whatever{you want}} $or$ not!}
+%D \stopbuffer
+%D
+%D \typebuffer[c]
+%D
+%D Unfortunately we still keep the first space, but at least it's better than
+%D a failure:
+%D
+%D \getbuffer[c]
+
+\long\def\rescan#1{\scantokens{#1\ignorespaces}}
+\long\def\rescanwithsetup#1#2{\begingroup\directsetup{#1}\scantokens{#2\ignorespaces}\endgroup}
+
+\ifx\scantextokens\undefined \else
+ \long\def\rescan#1{\scantextokens{#1}}
+ \long\def\rescanwithsetup#1#2{\begingroup\directsetup{#1}\scantextokens{#2}\endgroup}
+\fi
+
+\endinput
diff --git a/tex/context/base/char-act.mkiv b/tex/context/base/char-act.mkiv
new file mode 100644
index 000000000..2dc7823f0
--- /dev/null
+++ b/tex/context/base/char-act.mkiv
@@ -0,0 +1,138 @@
+%D \module
+%D [ file=char-act,
+%D version=2006.12.05,
+%D title=\CONTEXT\ Character Support,
+%D subtitle=Active,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 Character Support / Active}
+
+\unprotect
+
+%D \macros
+%D {processingverbatim}
+%D
+%D Typesetting a file in most cases results in more than one
+%D page. Because we don't want problems with files that are
+%D read in during the construction of the page, we set \type
+%D {\ifprocessingverbatim}, so the output routine can adapt
+%D its behavior. Originally we used \type {\scratchread}, but
+%D because we want to support nesting, we decided to use a
+%D separate input file.
+
+\newif\ifprocessingverbatim
+
+%D \macros
+%D {obeyedspace, obeyedtab, obeyedline, obeyedpage}
+%D
+%D We have followed Knuth in naming macros that make \SPACE,
+%D \NEWLINE\ and \NEWPAGE\ active and assigning them
+%D \type{\obeysomething}, but first we set some default values.
+
+\def\obeyedspace {\ifprocessingverbatim\hbox{ }\else\space\fi}
+\def\obeyedtab {\obeyedspace}
+\def\obeyedline {\par}
+\def\obeyedpage {\vfill\eject}
+
+%D \macros
+%D {controlspace,setcontrolspaces}
+%D
+%D First we define \type{\obeyspaces}. When we want visible
+%D spaces (control spaces) we only have to adapt the definition
+%D of \type{\obeyedspace} to:
+
+\def\controlspace{\hbox{\char32}} % rather tex
+\def\normalspace { }
+\def\normalspaces{\catcode`\ =\@@space}
+
+\bgroup
+\catcode`\ =\@@active
+\gdef\obeyspaces{\catcode`\ =\@@active\def {\obeyedspace}}
+\gdef\setcontrolspaces{\catcode`\ =\@@active\def {\controlspace}}
+\egroup
+
+%D \macros
+%D {obeytabs, obeylines, obeypages,ignoretabs, ignorelines, ignorepages}
+%D
+%D Next we take care of \NEWLINE\ and \NEWPAGE\ and because we
+%D want to be able to typeset listings that contain \TAB, we
+%D have to handle those too. Because we have to redefine the
+%D \NEWPAGE\ character locally, we redefine the meaning of
+%D this (often already) active character.
+
+\catcode`\^^L=\@@active \def^^L{\par}
+
+%D The following indirect definitions enable us to implement
+%D all kind of \type{\obeyed} handlers.
+
+\bgroup
+
+\catcode`\^^I=\@@active
+\catcode`\^^M=\@@active
+\catcode`\^^L=\@@active
+
+\gdef\obeytabs {\catcode`\^^I=\@@active\def^^I{\obeyedtab}}
+\gdef\obeylines {\catcode`\^^M=\@@active\def^^M{\obeyedline}}
+\gdef\obeypages {\catcode`\^^L=\@@active\def^^L{\obeyedpage}}
+
+\gdef\ignoretabs {\catcode`\^^I=\@@active\def^^I{\obeyedspace}}
+\gdef\ignorelines {\catcode`\^^M=\@@active\def^^M{\obeyedspace}}
+\gdef\ignorepages {\catcode`\^^L=\@@ignore} % \@@active\def^^L{\obeyedline}}
+\gdef\ignoreeofs {\catcode`\^^Z=\@@ignore}
+
+\egroup
+
+%D \macros
+%D {naturaltextext}
+%D
+%D When one uses \ETEX, switching to normal \TEX\ is possible
+%D too. We also introduce a switch that can be used in the
+%D drivers and set in higher level shell macros.
+
+\def\naturaltextext#1\relax
+ {\bgroup
+ \def\ascii{#1}%
+ \setcatcodetable\ctxcatcodes
+ \prettynaturalfont{\scantextokens\expandafter{\ascii}\ifhmode\unskip\fi}%
+ \egroup}
+
+%D What-a-mess:
+
+% \def\normalspacecodes
+% {\catcode`\^^I = 10
+% \catcode`\^^M = 5
+% \catcode`\^^L = 5
+% \catcode`\ = 10
+% \catcode`\^^Z = 9 }
+
+% \appendtoks
+% \normalspacecodes
+% \to \everybeforeoutput
+
+\endinput \protect
+
+% obsolete (old hack for idris)
+
+%D This is a hack, and only meant for special situations. We don't
+%D support this in for instance verbatim. The active characters map
+%D onto the \CONTEXT\ names and font handling etc. is up to the user.
+
+%D This feature is obsolete.
+
+\registerctxluafile{char-act}{1.001}
+
+\def\enableactiveutf {\ctxlua{characters.active.enable()}}
+\def\disableactiveutf{\ctxlua{characters.active.disable()}}
+\def\testactiveutf #1{\ctxlua{characters.active.test("#1")}}
+
+%D Usage:
+%D
+%D \starttyping
+%D \enableactiveutf \testactiveutf{eacute}
+%D \stoptyping
diff --git a/tex/context/base/char-cmp.lua b/tex/context/base/char-cmp.lua
new file mode 100644
index 000000000..c7deb7901
--- /dev/null
+++ b/tex/context/base/char-cmp.lua
@@ -0,0 +1,268 @@
+if not modules then modules = { } end modules ['char-cmp'] = {
+ version = 1.001,
+ comment = "companion to char-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+local unpack = unpack or table.unpack
+
+characters = characters or { }
+characters.uncomposed = characters.uncomposed or { }
+
+--[[ldx--
+
The code defined here may move to the big character table.
The next three tables can for instance be be used to enhance
+kerning tables that lack kerning pairs for these special characters.
+Of course they may come in handy elsewhere too
The following function is used in the indexing code, where
+we need some sort of default fallback mapping.
+--ldx]]--
+
+function characters.uncompose(n) -- n == string|number, returns string
+ local cdn
+ if type(n) == "string" then
+ cdn = characters.data[utf.byte(n)]
+ else
+ cdn = characters.data[n]
+ end
+ -- return characters.shape(n)
+ if cdn then
+ local shcode = cdn.shcode
+ if not shcode then
+ return characters.uncomposed.both[cdn.contextname] or n
+ elseif type(shcode) == "table" then
+ return utf.char(unpack(cdn.shcode))
+ else
+ return utf.char(cdn.shcode)
+ end
+ end
+ return n
+end
+
+--[[ldx--
+
Only characters with a code smaller than 128 make sense,
+anything larger is encoding dependent. An interesting complication
+is that a character can be in an encoding twice but is hashed
+once.
This module implements some methods and creates additional datastructured
+from the big character table that we use for all kind of purposes:
+char-def.lua.
+
+
We assume that at this point characters.data is already
+loaded!
At this point we assume that the big data table is loaded. From this
+table we derive a few more.
+--ldx]]--
+
+if not characters.fallbacks then
+
+ characters.fallbacks = { }
+ characters.directions = { }
+
+ local fallbacks = characters.fallbacks
+ local directions = characters.directions
+
+ for k,v in next, data do
+ local specials = v.specials
+ if specials and specials[1] == "compat" and specials[2] == 0x0020 and specials[3] then
+ local s = specials[3]
+ fallbacks[k] = s
+ fallbacks[s] = k
+ end
+ directions[k] = v.direction
+ end
+
+end
+
+storage.register("characters.fallbacks", characters.fallbacks, "characters.fallbacks")
+storage.register("characters.directions", characters.directions, "characters.directions")
+
+--[[ldx--
+
The context namespace is used to store methods and data
+which is rather specific to .
+--ldx]]--
+
+--[[ldx--
+
Instead of using a file to define the named glyphs, we
+use the table. After all, we have this information available anyway.
+--ldx]]--
+
+function characters.makeactive(n,name) -- let ?
+ texsprint(ctxcatcodes,format("\\catcode%s=13\\unexpanded\\def %s{\\%s}",n,utfchar(n),name))
+end
+
+function tex.uprint(n)
+ texsprint(ctxcatcodes,utfchar(n))
+end
+
+local template_a = "\\startextendcatcodetable{%s}\\chardef\\l=11\\chardef\\a=13\\let\\c\\catcode%s\\let\\a\\undefined\\let\\l\\undefined\\let\\c\\undefined\\stopextendcatcodetable"
+local template_b = "\\chardef\\l=11\\chardef\\a=13\\let\\c\\catcode%s\\let\\a\\undefined\\let\\l\\undefined\\let\\c\\undefined"
+
+-- we need a function for setting the codes ....
+
+function characters.define(tobelettered, tobeactivated) -- catcodetables
+ local is_character, is_command, is_letter = characters.is_character, characters.is_command, characters.is_letter
+ local lettered, activated = { }, { }
+ for u, chr in next, data do
+ -- we can use a macro instead of direct settings
+ local fallback = chr.fallback
+ if fallback then
+ -- texprint(format("{\\catcode %s=13\\unexpanded\\gdef %s{\\checkedchar{%s}{%s}}}",u,utfchar(u),u,fallback))
+ texsprint("{\\catcode",u,"=13\\unexpanded\\gdef ",utfchar(u),"{\\checkedchar{",u,"}{",fallback,"}}}") -- no texprint
+ activated[#activated+1] = "\\c"..u.."\\a"
+ else
+ local contextname = chr.contextname
+ local category = chr.category
+ if contextname then
+ if is_character[category] then
+ -- by this time, we're still in normal catcode mode
+ -- subtle: not "\\",contextname but "\\"..contextname
+ if chr.unicodeslot < 128 then
+ -- texprint(ctxcatcodes, "\\chardef\\"..contextname,"=",u)
+ texprint(ctxcatcodes,format("\\chardef\\%s=%s",contextname,u))
+ else
+ -- texprint(ctxcatcodes, "\\let\\"..contextname,"=",utfchar(u))
+ texprint(ctxcatcodes,format("\\let\\%s=%s",contextname,utfchar(u)))
+ if is_letter[category] then
+ lettered[#lettered+1] = "\\c"..u.."\\l"
+ end
+ end
+ elseif is_command[category] then
+ -- this might change: contextcommand ipv contextname
+ -- texprint(format("{\\catcode %s=13\\unexpanded\\gdef %s{\\%s}}",u,utfchar(u),contextname))
+ texsprint("{\\catcode",u,"=13\\unexpanded\\gdef ",utfchar(u),"{\\"..contextname,"}}") -- no texprint
+ activated[#activated+1] = "\\c"..u.."\\a"
+ end
+ elseif is_letter[category] then
+ if u >= 128 and u <= 65536 then -- catch private mess
+ lettered[#lettered+1] = "\\c"..u.."\\l"
+ end
+ end
+ end
+ if chr.range then
+ lettered[#lettered+1] = format('\\dofastrecurse{"%05X}{"%05X}{1}{\\c\\fastrecursecounter\\l}',u,chr.range)
+ end
+ end
+ -- if false then
+ lettered[#lettered+1] = "\\c"..0x200C.."\\l" -- non-joiner
+ lettered[#lettered+1] = "\\c"..0x200D.."\\l" -- joiner
+ -- fi
+ if tobelettered then
+ lettered = concat(lettered)
+ if true then
+ texsprint(ctxcatcodes,format(template_b,lettered))
+ else
+ for l=1,#tobelettered do
+ texsprint(ctxcatcodes,format(template_a,tobelettered[l],lettered))
+ end
+ end
+ end
+ if tobeactivated then
+ activated = concat(activated)
+ for a=1,#tobeactivated do
+ texsprint(ctxcatcodes,format(template_a,tobeactivated[a],activated))
+ end
+ end
+end
+
+function characters.charcode(box)
+ local b = tex.box[box]
+ local l = b.list
+ texsprint((l and l.id == node.id('glyph') and l.char) or 0)
+end
+
+--[[ldx--
+
Setting the lccodes is also done in a loop over the data table.
+--ldx]]--
+
+-- we need a function ...
+
+function characters.setcodes()
+ for code, chr in next, data do
+ local cc = chr.category
+ if cc == 'll' or cc == 'lu' or cc == 'lt' then
+ local lc, uc = chr.lccode, chr.uccode
+ if not lc then chr.lccode, lc = code, code end
+ if not uc then chr.uccode, uc = code, code end
+ texsprint(ctxcatcodes,format("\\setcclcuc{%i}{%i}{%i}",code,lc,uc))
+ end
+ if cc == "lu" then
+ texprint(ctxcatcodes,"\\sfcode ",code,"999 ")
+ end
+ if cc == "lo" and chr.range then
+ texsprint(ctxcatcodes,format('\\dofastrecurse{"%05X}{"%05X}{1}{\\setcclcucself\\fastrecursecounter}',code,chr.range))
+ end
+ end
+end
+
+--[[ldx--
+
Next comes a whole series of helper methods. These are (will be) part
+of the official .
+--ldx]]--
+
+--[[ldx--
+
This converts a string (if given) into a number.
+--ldx]]--
+
+function characters.number(n)
+ if type(n) == "string" then return tonumber(n,16) else return n end
+end
+
+--[[ldx--
+
Checking for valid characters.
+--ldx]]--
+
+function characters.is_valid(s)
+ return s or ""
+end
+
+function characters.checked(s, default)
+ return s or default
+end
+
+characters.valid = characters.is_valid
+
+--[[ldx--
+
+--ldx]]--
+-- set a table entry; index is number (can be different from unicodeslot)
+
+function characters.set(n, c)
+ data[characters.number(n)] = c
+end
+
+--[[ldx--
+
Get a table entry happens by number. Keep in mind that the unicodeslot
+can be different (not likely).
+--ldx]]--
+
+function characters.uccode(n) return data[n].uccode or n end
+function characters.lccode(n) return data[n].lccode or n end
+
+function characters.flush(n)
+ local c = data[n]
+ if c and c.contextname then
+ texsprint(texcatcodes, "\\"..c.contextname)
+ else
+ texsprint(utfchar(n))
+ end
+end
+
+function characters.shape(n)
+ local shcode = data[n].shcode
+ if not shcode then
+ return n, nil
+ elseif type(shcode) == "table" then
+ return shcode[1], shcode[#shcode]
+ else
+ return shcode, nil
+ end
+end
+
+--[[ldx--
+
Categories play an important role, so here are some checkers.
When a sequence of characters enters the application, it may
+be neccessary to collapse subsequences into their composed variant.
+
+
This module implements methods for collapsing and expanding
+sequences. We also provide means to deal with characters that are
+special to as well as 8-bit characters that need to end up
+in special kinds of output (for instance ).
+
+
We implement these manipulations as filters. One can run multiple filters
+over a string.
It only makes sense to collapse at runtime, since we don't expect
+source code to depend on collapsing.
+--ldx]]--
+
+function utffilters.initialize()
+ if utffilters.collapsing and not utffilters.initialized then
+ for k,v in next, characters.data do
+ -- using vs and first testing for length is faster (.02->.01 s)
+ local vs = v.specials
+ if vs and #vs == 3 and vs[1] == 'char' then
+ local first, second = utfchar(vs[2]), utfchar(vs[3])
+ local cgf = graphemes[first]
+ if not cgf then
+ cgf = { }
+ graphemes[first] = cgf
+ end
+ cgf[second] = utfchar(k)
+ end
+ end
+ utffilters.initialized = true
+ end
+end
+
+-- utffilters.add_grapheme(utfchar(318),'l','\string~')
+-- utffilters.add_grapheme('c','a','b')
+
+function utffilters.add_grapheme(result,first,second)
+ local r, f, s = tonumber(result), tonumber(first), tonumber(second)
+ if r then result = utfchar(r) end
+ if f then first = utfchar(f) end
+ if s then second = utfchar(s) end
+ if not graphemes[first] then
+ graphemes[first] = { [second] = result }
+ else
+ graphemes[first][second] = result
+ end
+end
+
+function utffilters.collapse(str) -- old one
+ if utffilters.collapsing and str and #str > 1 then
+ if not utffilters.initialized then -- saves a call
+ utffilters.initialize()
+ end
+ local tokens, first, done = { }, false, false
+ for second in utfcharacters(str) do
+ local cgf = graphemes[first]
+ if cgf and cgf[second] then
+ first, done = cgf[second], true
+ elseif first then
+ tokens[#tokens+1] = first
+ first = second
+ else
+ first = second
+ end
+ end
+ if done then
+ tokens[#tokens+1] = first
+ return concat(tokens)
+ end
+ end
+ return str
+end
+
+--[[ldx--
+
In order to deal with 8-bit output, we need to find a way to
+go from to 8-bit. This is handled in the
+ engine itself.
+
+
This leaves us problems with characters that are specific to
+ like {}, $ and alike.
+
+
We can remap some chars that tex input files are sensitive for to
+a private area (while writing to a utility file) and revert then
+to their original slot when we read in such a file. Instead of
+reverting, we can (when we resolve characters to glyphs) map them
+to their right glyph there.
+
+
For this purpose we can use the private planes 0x0F0000 and
+0x100000.
+--ldx]]--
+
+utffilters.private = {
+ high = { },
+ low = { },
+ escapes = { },
+}
+
+local low = utffilters.private.low
+local high = utffilters.private.high
+local escapes = utffilters.private.escapes
+local special = "~#$%^&_{}\\|"
+
+function utffilters.private.set(ch)
+ local cb
+ if type(ch) == "number" then
+ cb, ch = ch, utfchar(ch)
+ else
+ cb = utfbyte(ch)
+ end
+ if cb < 256 then
+ low[ch] = utfchar(0x0F0000 + cb)
+ high[utfchar(0x0F0000 + cb)] = ch
+ escapes[ch] = "\\" .. ch
+ end
+end
+
+function utffilters.private.replace(str) return utfgsub(str,"(.)", low ) end
+function utffilters.private.revert(str) return utfgsub(str,"(.)", high ) end
+function utffilters.private.escape(str) return utfgsub(str,"(.)", escapes) end
+
+local set = utffilters.private.set
+
+for ch in gmatch(special,".") do set(ch) end
+
+--[[ldx--
+
We get a more efficient variant of this when we integrate
+replacements in collapser. This more or less renders the previous
+private code redundant. The following code is equivalent but the
+first snippet uses the relocated dollars.
+
+
+[x] [$x$]
+
+--ldx]]--
+
+local cr = utffilters.private.high -- kan via een lpeg
+local cf = utffilters
+
+--[[ldx--
+
The next variant has lazy token collecting, on a 140 page mk.tex this saves
+about .25 seconds, which is understandable because we have no graphmes and
+not collecting tokens is not only faster but also saves garbage collecting.
+
+--ldx]]--
+
+-- lpeg variant is not faster
+
+function utffilters.collapse(str) -- not really tested (we could preallocate a table)
+ if cf.collapsing and str then
+ if #str > 1 then
+ if not cf.initialized then -- saves a call
+ cf.initialize()
+ end
+ local tokens, first, done, n = { }, false, false, 0
+ for second in utfcharacters(str) do
+ if done then
+ local crs = cr[second]
+ if crs then
+ if first then
+ tokens[#tokens+1] = first
+ end
+ first = crs
+ else
+ local cgf = graphemes[first]
+ if cgf and cgf[second] then
+ first = cgf[second]
+ elseif first then
+ tokens[#tokens+1] = first
+ first = second
+ else
+ first = second
+ end
+ end
+ else
+ local crs = cr[second]
+ if crs then
+ for s in utfcharacters(str) do
+ if n == 1 then
+ break
+ else
+ tokens[#tokens+1], n = s, n - 1
+ end
+ end
+ if first then
+ tokens[#tokens+1] = first
+ end
+ first, done = crs, true
+ else
+ local cgf = graphemes[first]
+ if cgf and cgf[second] then
+ for s in utfcharacters(str) do
+ if n == 1 then
+ break
+ else
+ tokens[#tokens+1], n = s, n -1
+ end
+ end
+ first, done = cgf[second], true
+ else
+ first, n = second, n + 1
+ end
+ end
+ end
+ end
+ if done then
+ tokens[#tokens+1] = first
+ return concat(tokens) -- seldom called
+ end
+ elseif #str > 0 then
+ return cr[str] or str
+ end
+ end
+ return str
+end
+
+--[[ldx--
+
Next we implement some commands that are used in the user interface.
+--ldx]]--
+
+function utf.split(str)
+ local t = { }
+ for snippet in utfcharacters(str) do
+ t[#t+1] = snippet
+ end
+ return t
+end
+
+function utf.each(str,fnc)
+ for snippet in utfcharacters(str) do
+ fnc(snippet)
+ end
+end
diff --git a/tex/context/base/char-utf.mkiv b/tex/context/base/char-utf.mkiv
new file mode 100644
index 000000000..16b4029d8
--- /dev/null
+++ b/tex/context/base/char-utf.mkiv
@@ -0,0 +1,47 @@
+%D \module
+%D [ file=char-utf,
+%D version=2006.12.05,
+%D title=\CONTEXT\ Character Support,
+%D subtitle=Unicode UTF,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 Character Support / Unicode UTF}
+
+%D After a bit of experimenting we reached a clean state where \UTF\
+%D 8, 16 and 32 were supported as well as collapsing (combining
+%D sequences). Writing the code was a relaxed experience, not in the
+%D last place because it was accompanied by listening to those nice
+%D Vienna Teng cd's (who decided that making music was more fun than
+%D programming, but then, she may not know \TEX\ and \LUA).
+
+\unprotect
+
+\registerctxluafile{char-utf}{1.001}
+
+%D We enable collapsing (combining characters) by default, but
+%D since the source files are rather simple, we postpone the
+%D initialization till runtime.
+
+\appendtoks
+ \ctxlua {
+ characters.filters.utf.collapsing = true
+ resolvers.install_text_filter('utf',characters.filters.utf.collapse)
+ }%
+\to \everyjob
+
+%D The next one influences input parsing.
+%D
+%D \starttyping
+%D \definecomposedutf 318 108 126 % lcaron
+%D \stoptyping
+
+\unexpanded\def\definecomposedutf#1 #2 #3 %
+ {\ctxlua{characters.filters.utf.add_grapheme("#1","#2","#3")}}
+
+\protect
diff --git a/tex/context/base/chem-ini.lua b/tex/context/base/chem-ini.lua
new file mode 100644
index 000000000..908749092
--- /dev/null
+++ b/tex/context/base/chem-ini.lua
@@ -0,0 +1,75 @@
+if not modules then modules = { } end modules ['chem-ini'] = {
+ version = 1.001,
+ comment = "companion to chem-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, texsprint = string.format, tex.sprint
+local lpegmatch = lpeg.match
+
+local trace_molecules = false trackers.register("chemistry.molecules", function(v) trace_molecules = v end)
+
+local ctxcatcodes = tex.ctxcatcodes
+
+chemicals = chemicals or { }
+
+--[[
+
The next code is an adaptation of code from Wolfgang Schuster
+as posted on the mailing list. This version supports nested
+braces and unbraced integers as scripts. We could consider
+spaces as terminals for them but first let collect a bunch
+of input then.
+]]--
+
+-- some lpeg, maybe i'll make an syst-lpg module
+
+local lowercase = lpeg.R("az")
+local uppercase = lpeg.R("AZ")
+local backslash = lpeg.P("\\")
+local csname = backslash * lpeg.P(1) * (1-backslash)^0
+local plus = lpeg.P("+") / "\\textplus "
+local minus = lpeg.P("-") / "\\textminus "
+local digit = lpeg.R("09")
+local sign = plus + minus
+local cardinal = digit^1
+local integer = sign^0 * cardinal
+
+local leftbrace = lpeg.P("{")
+local rightbrace = lpeg.P("}")
+local nobrace = 1 - (leftbrace + rightbrace)
+local nested = lpeg.P { leftbrace * (csname + sign + nobrace + lpeg.V(1))^0 * rightbrace }
+local any = lpeg.P(1)
+
+local subscript = lpeg.P("_")
+local superscript = lpeg.P("^")
+local somescript = subscript + superscript
+
+--~ local content = lpeg.Cs(nested + integer + sign + any)
+local content = lpeg.Cs(csname + nested + sign + any)
+
+-- could be made more efficient
+
+local lowhigh = lpeg.Cc("\\lohi{%s}{%s}") * subscript * content * superscript * content / format
+local highlow = lpeg.Cc("\\hilo{%s}{%s}") * superscript * content * subscript * content / format
+local low = lpeg.Cc("\\low{%s}") * subscript * content / format
+local high = lpeg.Cc("\\high{%s}") * superscript * content / format
+local justtext = (1 - somescript)^1
+local parser = lpeg.Cs((csname + lowhigh + highlow + low + high + sign + any)^0)
+
+chemicals.moleculeparser = parser -- can be used to avoid functioncall
+
+function chemicals.molecule(str)
+ return lpegmatch(parser,str)
+end
+
+function commands.molecule(str)
+ if trace_molecules then
+ local rep = lpegmatch(parser,str)
+ logs.report("chemistry", "molecule %s => %s",str,rep)
+ texsprint(ctxcatcodes,rep)
+ else
+ texsprint(ctxcatcodes,lpegmatch(parser,str))
+ end
+end
diff --git a/tex/context/base/chem-ini.mkiv b/tex/context/base/chem-ini.mkiv
new file mode 100644
index 000000000..5184fe1a7
--- /dev/null
+++ b/tex/context/base/chem-ini.mkiv
@@ -0,0 +1,47 @@
+%D \module
+%D [ file=chem-ini,
+%D version=2008.03.06,
+%D subtitle=Chemistry,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Chemistry Macros / Initialization} % might become Inline
+
+\registerctxluafile{chem-ini}{1.001}
+
+\unprotect
+
+%D \macros
+%D {molecule}
+%D
+%D Quick and dirty:
+%D
+%D \starttyping
+%D \def\molecule#1{$\enablesupersub\tf#1$}
+%D \stoptyping
+%D
+%D Using \LUA:
+%D
+%D \startbuffer
+%D \molecule{H_2SO_4^-2}
+%D \molecule{H_2SO_4^{-2}}
+%D \molecule{H_2SO_4^{-2{x}}}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\molecule#1{\ctxlua{commands.molecule(\!!bs#1\!!es)}}
+
+%D For old times sake:
+
+\def\chem#1#2#3%
+ {\dontleavehmode\begingroup#1\lohi{#2}{#3}\endgroup}
+
+\protect \endinput
+
+
diff --git a/tex/context/base/chem-str.lua b/tex/context/base/chem-str.lua
new file mode 100644
index 000000000..ad4cc6c1b
--- /dev/null
+++ b/tex/context/base/chem-str.lua
@@ -0,0 +1,490 @@
+if not modules then modules = { } end modules ['chem-str'] = {
+ version = 1.001,
+ comment = "companion to chem-str.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This module in incomplete and experimental.
+
+-- We can push snippets into an mp instance.
+
+local trace_structure = false trackers.register("chemistry.structure", function(v) trace_structure = v end)
+local trace_textstack = false trackers.register("chemistry.textstack", function(v) trace_textstack = v end)
+
+local format, gmatch, match, lower, gsub = string.format, string.gmatch, string.match, string.lower, string.gsub
+local concat, insert, remove = table.concat, table.insert, table.remove
+local apply = structure.processors.apply
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+local lpegmatch = lpeg.match
+
+local variables = interfaces.variables
+
+chemicals = chemicals or { }
+
+chemicals.instance = "metafun" -- "ppchtex"
+chemicals.format = "metafun"
+chemicals.structures = 0
+
+local remapper = {
+ ["+"] = "p",
+ ["-"] = "m",
+}
+
+local common_keys = {
+ b = "line", eb = "line", db = "line", er = "line", dr = "line", br = "line",
+ sb = "line", msb = "line", psb = "line",
+ r = "line", pr = "line", mr = "line",
+ au = "line", ad = "line",
+ rb = "line", mrb = "line", prb = "line",
+ rd = "line", mrd = "line", prd = "line",
+ sr = "line", msr = "line", psr = "line",
+ c = "line", cc = "line", cd = "line", ccd = "line",
+ rn = "number", rtn = "number", rbn = "number",
+ s = "line", ss = "line", pss = "line", mss = "line",
+ mid = "fixed", mids = "fixed", midz = "text",
+ z = "text", rz = "text", mrz = "text", prz = "text", crz = "text",
+ rt = "text", rtt = "text", rbt = "text", zt = "text", zn = "number",
+ mov = "transform", rot = "transform", adj = "transform", dir = "transform", sub = "transform",
+}
+
+local front_keys = {
+ b = "line", bb= "line",
+ sb = "line", msb = "line", psb = "line",
+ r = "line", pr = "line", mr = "line",
+ z = "text", mrz = "text", prz = "text",
+}
+
+local one_keys = {
+ sb = "line", db = "line", tb = "line",
+ ep = "line", es = "line", ed = "line", et = "line",
+ sd = "line", ldd = "line", rdd = "line",
+ hb = "line", bb = "line", oe = "line", bd = "line", bw = "line",
+ z = "text", cz = "text", zt = "text", zn = "number",
+ zbt = "text", zbn = "number", ztt = "text", ztn = "number",
+ mov = "transform", sub = "transform", dir = "transform", off = "transform",
+}
+
+local front_align = {
+ mrz = { { "b","b","b","b","b","b" } },
+ prz = { { "t","t","t","t","t","t" } },
+}
+
+local syntax = {
+ one = {
+ n = 1, max = 8, keys = one_keys,
+ align = {
+ z = { { "r", "r_b", "b", "l_b", "l", "l_t", "t", "r_t" } },
+--~ z = { { "r", "r", "b", "l", "l", "l", "t", "r" } },
+ }
+ },
+ three = {
+ n = 3, max = 3, keys = common_keys,
+ align = {
+ mrz = { { "r","b","l" }, { "b","l","t" }, { "l","t","r" }, { "t","r","b" } },
+ rz = { { "r","l_b","l_t" }, { "b","l_t","r_t" }, { "l","r_t","r_b" }, { "t","r_b","l_b" } },
+ prz = { { "r","l","t" }, { "b","t","r" }, { "l","r","b" }, { "t","b","l" } },
+ }
+ },
+ four = {
+ n = 4, max = 4, keys = common_keys,
+ align = {
+ mrz = { { "t","r","b","l" }, { "r","b","l","t" }, { "b","l","t","r" }, { "l","t","r","b" } },
+ rz = { { "r_t","r_b","l_b","l_t" }, { "r_b","l_b","l_t","r_t" }, { "l_b","l_t","r_t","r_b" }, { "l_t","r_t","r_b","l_b" } },
+ prz = { { "r","b","l","t" }, { "b","l","t","r" }, { "l","t","r","b" }, { "t","r","b","l" } },
+ }
+ },
+ five = {
+ n = 5, max = 5, keys = common_keys,
+ align = {
+ mrz = { { "t","r","b","b","l" }, { "r","b","l","l","t" }, { "b","l","t","r","r" }, { "l","t","r","r","b" } },
+ rz = { { "r","r","b","l","t" }, { "b","b","l","t","r" }, { "l","l","t","r","b" }, { "t","t","r","b","l" } },
+ prz = { { "r","b","l","t","t" }, { "b","l","t","r","r" }, { "l","t","r","b","b" }, { "t","r","b","l","l" } },
+ }
+ },
+ six = {
+ n = 6, max = 6, keys = common_keys,
+ align = {
+ mrz = { { "t","t","r","b","b","l" }, { "r","b","b","l","t","t" }, { "b","b","l","t","t","r" }, { "l","t","t","r","b","b" } },
+ rz = { { "r","r","b","l","l","t" }, { "b","b","l","t","t","r" }, { "l","l","t","r","r","b" }, { "t","t","r","b","b","l" } },
+ prz = { { "r","b","l","l","t","r" }, { "b","l","t","t","r","b" }, { "l","t","r","r","b","l" }, { "t","r","b","b","l","t" } },
+ }
+ },
+ eight = {
+ n = 8, max = 8, keys = common_keys,
+ align = { -- todo
+ mrz = { { "t","r","r","b","b","l","l","t" }, { "r","b","b","l","l","t","t","r" }, { "b","l","l","t","t","r","r","b" }, { "l","t","t","r","r","b","b","l" } },
+ rz = { { "r","r","b","b","l","l","t","t" }, { "b","b","l","l","t","t","r","r" }, { "l","l","t","t","r","r","b","b" }, { "t","t","r","r","b","b","l","l" } },
+ prz = { { "r","b","b","l","l","t","t","r" }, { "b","l","l","t","t","r","r","b" }, { "l","t","t","r","r","b","b","l" }, { "t","r","r","b","b","l","l","t" } },
+ }
+ },
+ five_front = {
+ n = -5, max = 5, keys = front_keys, align = front_align,
+ },
+ six_front = {
+ n = -6, max = 6, keys = front_keys, align = front_align,
+ },
+ pb = { direct = 'chem_pb ;' },
+ pe = { direct = 'chem_pe ;' },
+ save = { direct = 'chem_save ;' },
+ restore = { direct = 'chem_restore ;' },
+ space = { direct = 'chem_symbol("\\chemicalsymbol[space]") ;' },
+ plus = { direct = 'chem_symbol("\\chemicalsymbol[plus]") ;' },
+ minus = { direct = 'chem_symbol("\\chemicalsymbol[minus]") ;' },
+ gives = { direct = 'chem_symbol("\\chemicalsymbol[gives]{%s}{%s}") ;', arguments = 2 },
+ equilibrium = { direct = 'chem_symbol("\\chemicalsymbol[equilibrium]{%s}{%s}") ;', arguments = 2 },
+ mesomeric = { direct = 'chem_symbol("\\chemicalsymbol[mesomeric]{%s}{%s}") ;', arguments = 2 },
+ opencomplex = { direct = 'chem_symbol("\\chemicalsymbol[opencomplex]") ;' },
+ closecomplex = { direct = 'chem_symbol("\\chemicalsymbol[closecomplex]") ;' },
+}
+
+local definitions = { }
+
+function chemicals.undefine(name)
+ definitions[lower(name)] = nil
+end
+
+function chemicals.define(name,spec,text)
+ name = lower(name)
+ local dn = definitions[name]
+ if not dn then dn = { } definitions[name] = dn end
+ dn[#dn+1] = {
+ spec = aux.settings_to_array(lower(spec)),
+ text = aux.settings_to_array(text),
+ }
+end
+
+local metacode, kind, keys, bonds, max, txt, textsize, rot, pstack
+local molecule = chemicals.molecule -- or use lpegmatch(chemicals.moleculeparser,...)
+
+local function fetch(txt)
+ local st = stack[txt]
+ local t = st.text[st.n]
+--~ st.n = st.n + 1
+ while not t and txt > 1 do
+ txt = txt - 1
+ st = stack[txt]
+ t = st.text[st.n]
+--~ st.n = st.n + 1
+ end
+ if t then
+ if trace_textstack then
+ logs.report("chemical", "fetching from stack %s slot %s: %s",txt,st.n,t)
+ end
+st.n = st.n + 1
+ end
+ return txt, t
+end
+
+local digit = lpeg.R("09")/tonumber
+local colon = lpeg.P(":")
+local equal = lpeg.P("=")
+local other = 1 - digit - colon - equal
+local remapped = lpeg.S("+-") / remapper
+local operation = lpeg.Cs((remapped^0 * other)^1)
+local amount = digit
+local single = digit
+local special = (colon * lpeg.C(other^1)) + lpeg.Cc("")
+local range = digit * lpeg.P("..") * digit
+local set = lpeg.Ct(digit^2)
+local text = (equal * lpeg.C(lpeg.P(1)^0)) + lpeg.Cc(false)
+local pattern =
+ (amount + lpeg.Cc(1)) *
+ operation *
+ special * (
+ range * lpeg.Cc(false) * text +
+ lpeg.Cc(false) * lpeg.Cc(false) * set * text +
+ single * lpeg.Cc(false) * lpeg.Cc(false) * text +
+ lpeg.Cc(false) * lpeg.Cc(false) * lpeg.Cc(false) * text
+ )
+
+--~ local n, operation, index, upto, set, text = lpegmatch(pattern,"RZ1357")
+
+--~ print(lpegmatch(pattern,"RZ=x")) 1 RZ false false false x
+--~ print(lpegmatch(pattern,"RZ1=x")) 1 RZ 1 false false x
+--~ print(lpegmatch(pattern,"RZ1..3=x")) 1 RZ 1 3 false x
+--~ print(lpegmatch(pattern,"RZ13=x")) 1 RZ false false table x
+
+local function process(spec,text,n,rulethickness,rulecolor,offset)
+ insert(stack,{ spec=spec, text=text, n=n })
+ local txt = #stack
+ for i=1,#spec do
+ local s = spec[i]
+ local d = definitions[s]
+ if d then
+ for i=1,#d do
+ local di = d[i]
+ process(di.spec,di.text,1,rulethickness,rulecolor)
+ end
+ else
+ local rep, operation, special, index, upto, set, text = lpegmatch(pattern,s)
+ if operation == "pb" then
+ insert(pstack,kind)
+ metacode[#metacode+1] = syntax.pb.direct
+ if keys[special] == "text" and index then
+ if keys["c"..special] == "text" then -- can be option: auto ...
+ metacode[#metacode+1] = format('chem_c%s(%s,%s,"");',special,bonds,index)
+ else
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"");',special,bonds,index)
+ end
+ end
+ elseif operation == "save" then
+ insert(pstack,kind)
+ metacode[#metacode+1] = syntax.save.direct
+ elseif operation == "pe" or operation == "restore" then
+ kind = remove(pstack)
+ local ss = syntax[kind]
+ local prev = bonds or 6
+ keys, bonds, max, rot = ss.keys, ss.n, ss.max, 1
+ metacode[#metacode+1] = syntax[operation].direct
+ metacode[#metacode+1] = format("chem_set(%s,%s) ;",prev,bonds)
+ elseif operation == "front" then
+ if syntax[kind .. "_front"] then
+ kind = kind .. "_front"
+ local ss = syntax[kind]
+ local prev = bonds or 6
+ keys, bonds, max, rot = ss.keys, ss.n, ss.max, 1
+ metacode[#metacode+1] = format("chem_set(%s,%s) ;",prev,bonds)
+ end
+ elseif operation then
+ local ss = syntax[operation]
+ if ss then
+ local ds = ss.direct
+ if ds then
+ local sa = ss.arguments
+ if sa == 1 then
+ local one ; txt, one = fetch(txt)
+ metacode[#metacode+1] = format(ds,one or "")
+ elseif sa ==2 then
+ local one ; txt, one = fetch(txt)
+ local two ; txt, two = fetch(txt)
+ metacode[#metacode+1] = format(ds,one or "",two or "")
+ else
+ metacode[#metacode+1] = ds
+ end
+ elseif ss.keys then
+ local prev = bonds or 6
+ kind, keys, bonds, max, rot = s, ss.keys, ss.n, ss.max, 1
+ metacode[#metacode+1] = format("chem_set(%s,%s) ;",prev,bonds)
+ end
+ else
+ local what = keys[operation]
+ if what == "line" then
+ if set then
+ for i=1,#set do
+ local si = set[i]
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,si,si,rulethickness,rulecolor)
+ end
+ elseif upto then
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,index,upto,rulethickness,rulecolor)
+ elseif index then
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,index,index,rulethickness,rulecolor)
+ else
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,1,max,rulethickness,rulecolor)
+ end
+ elseif what == "number" then
+ if set then
+ for i=1,#set do
+ local si = set[i]
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"\\dochemicaltext{%s}");',operation,bonds,si,si)
+ end
+ elseif upto then
+ for i=index,upto do
+ local si = set[i]
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"\\dochemicaltext{%s}");',operation,bonds,si,si)
+ end
+ elseif index then
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"\\dochemicaltext{%s}");',operation,bonds,index,index)
+ else
+ for i=1,max do
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"\\dochemicaltext{%s}");',operation,bonds,i,i)
+ end
+ end
+ elseif what == "text" then
+ local align = syntax[kind].align
+ align = align and align[operation]
+ align = align and align[rot]
+ if set then
+ for i=1,#set do
+ local si = set[i]
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ local a = align and align[si]
+ if a then a = "." .. a else a = "" end
+ metacode[#metacode+1] = format('chem_%s%s(%s,%s,"\\dochemicaltext{%s}");',operation,a,bonds,si,molecule(apply(t)))
+ end
+ end
+ elseif upto then
+ for i=index,upto do
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ local s = align and align[i]
+ if s then s = "." .. s else s = "" end
+ metacode[#metacode+1] = format('chem_%s%s(%s,%s,"\\dochemicaltext{%s}");',operation,s,bonds,i,molecule(apply(t)))
+ end
+ end
+ elseif index == 0 then
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ metacode[#metacode+1] = format('chem_%s_zero("\\dochemicaltext{%s}");',operation,molecule(apply(t)))
+ end
+ elseif index then
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ local s = align and align[index]
+ if s then s = "." .. s else s = "" end
+ metacode[#metacode+1] = format('chem_%s%s(%s,%s,"\\dochemicaltext{%s}");',operation,s,bonds,index,molecule(apply(t)))
+ end
+ else
+ for i=1,max do
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ local s = align and align[i]
+ if s then s = "." .. s else s = "" end
+ metacode[#metacode+1] = format('chem_%s%s(%s,%s,"\\dochemicaltext{%s}");',operation,s,bonds,i,molecule(apply(t)))
+ end
+ end
+ end
+ elseif what == "transform" then
+ if index then
+ for r=1,rep do
+ metacode[#metacode+1] = format('chem_%s(%s,%s);',operation,bonds,index)
+ end
+ if operation == "rot" then
+ rot = index
+ end
+ end
+ elseif what == "fixed" then
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s);",operation,bonds,rulethickness,rulecolor)
+ end
+ end
+ end
+ end
+ end
+ remove(stack)
+end
+
+-- the size related values are somewhat special but we want to be
+-- compatible
+--
+-- maybe we should default to fit
+--
+-- rulethickness in points
+
+function chemicals.start(settings)
+ chemicals.structures = chemicals.structures + 1
+ local textsize, rulethickness, rulecolor = settings.size, settings.rulethickness, settings.rulecolor
+ local width, height, scale, offset = settings.width or 0, settings.height or 0, settings.scale or "medium", settings.offset or 0
+ local l, r, t, b = settings.left or 0, settings.right or 0, settings.top or 0, settings.bottom or 0
+ if scale == variables.small then
+ scale = 500
+ elseif scale == variables.medium or scale == 0 then
+ scale = 625
+ elseif scale == variables.big then
+ scale = 750
+ else
+ scale = tonumber(scale)
+ if not scale or scale == 0 then
+ scale = 750
+ elseif scale < 500 then
+ scale = 500
+ end
+ end
+ if width == variables.fit then
+ width = true
+ else
+ width = tonumber(width) or 0
+ if l == 0 then
+ if r == 0 then
+ l = (width == 0 and 2000) or width/2
+ r = l
+ elseif width ~= 0 then
+ l = width - r
+ end
+ elseif r == 0 and width ~= 0 then
+ r = width - l
+ end
+ width = false
+ end
+ if height == variables.fit then
+ height = true
+ else
+ height = tonumber(height) or 0
+ if t == 0 then
+ if b == 0 then
+ t = (height == 0 and 2000) or height/2
+ b = t
+ elseif height ~= 0 then
+ t = height - b
+ end
+ elseif b == 0 and height ~= 0 then
+ b = height - t
+ end
+ height = false
+ end
+ scale = 0.75 * scale/625
+ metacode = { format("chem_start_structure(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ;",
+ chemicals.structures,
+ l/25, r/25, t/25, b/25, scale,
+ tostring(settings.axis == variables.on), tostring(width), tostring(height), tostring(offset)
+ ) }
+ kind, keys, bonds, stack, rot, pstack = "six", { }, 6, { }, 1, { }
+end
+
+function chemicals.stop()
+ metacode[#metacode+1] = "chem_stop_structure ;"
+ local mpcode = concat(metacode,"\n")
+ if trace_structure then
+ logs.report("chemical", "metapost code:\n%s", mpcode)
+ end
+ metapost.graphic(chemicals.instance,chemicals.format,mpcode)
+ metacode = nil
+end
+
+function chemicals.component(spec,text,settings)
+ rulethickness, rulecolor, offset = settings.rulethickness, settings.rulecolor
+ local spec = aux.settings_to_array(lower(spec))
+ local text = aux.settings_to_array(text)
+ metacode[#metacode+1] = "chem_start_component ;"
+ process(spec,text,1,rulethickness,rulecolor)
+ metacode[#metacode+1] = "chem_stop_component ;"
+end
+
+local inline = {
+ ["single"] = "\\chemicalsinglebond", ["-"] = "\\chemicalsinglebond",
+ ["double"] = "\\chemicaldoublebond", ["--"] = "\\chemicaldoublebond",
+ ["triple"] = "\\chemicaltriplebond", ["---"] = "\\chemicaltriplebond",
+ ["gives"] = "\\chemicalgives", ["->"] = "\\chemicalgives",
+ ["equilibrium"] = "\\chemicalequilibrium", ["<->"] = "\\chemicalequilibrium",
+ ["mesomeric"] = "\\chemicalmesomeric", ["<>"] = "\\chemicalmesomeric",
+ ["plus"] = "\\chemicalsplus", ["+"] = "\\chemicalsplus",
+ ["minus"] = "\\chemicalsminus",
+ ["space"] = "\\chemicalsspace",
+}
+
+-- todo: top / bottom
+
+function chemicals.inline(spec)
+ local spec = aux.settings_to_array(spec)
+ for i=1,#spec do
+ local s = spec[i]
+ local inl = inline[lower(s)]
+ if inl then
+ texsprint(ctxcatcodes,inl)
+ else
+ texsprint(ctxcatcodes,format("\\chemicalinline{%s}",molecule(s)))
+ end
+ end
+end
+
+statistics.register("chemical formulas", function()
+ if chemicals.structures > 0 then
+ return format("%s chemical structure formulas",chemicals.structures) -- no timing needed, part of metapost
+ end
+end)
diff --git a/tex/context/base/chem-str.mkiv b/tex/context/base/chem-str.mkiv
new file mode 100644
index 000000000..1e17218c8
--- /dev/null
+++ b/tex/context/base/chem-str.mkiv
@@ -0,0 +1,529 @@
+%D \module
+%D [ file=chem-ini,
+%D version=2009.05.13,
+%D subtitle=Chemistry,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module in incomplete and experimental. Eventually this code
+%D will replace \PPCHTEX.
+
+\writestatus{loading}{ConTeXt Chemistry Macros / Structure}
+
+\registerctxluafile{chem-str}{1.001}
+
+% We have a slightly different interface. This is unchanged:
+%
+% \startchemical[axis=on]
+% \chemical[SIX,ROT2,B,R6,SUB1,FIVE,ROT1,B][1]
+% \stopchemical
+%
+% Here we use chemicalformula instead, so no longer a mix:
+%
+% \startchemicalformula
+% \chemical{H_2}{top}{bottom}
+% \chemical{PLUS}{top}{bottom}
+% \chemical{O}{top}{bottom}
+% \chemical{GIVES}{top}{bottom}
+% \chemical{H_2O}{top}{bottom}
+% \stopchemicalformula
+%
+% \startchemicalformula
+% \chemical{H_2}
+% \chemical{PLUS}
+% \chemical{O}
+% \chemical{GIVES}
+% \chemical{H_2O}
+% \stopchemicalformula
+%
+% The inline variant has only one argument:
+%
+% \chemical{H_2,PLUS,O,GIVES,H_2O}
+
+% todo: seven | eight | frontsix | fontfive | carbon | newmans | chair
+
+\unprotect
+
+\unexpanded\def\setupchemical
+ {\dosingleempty\dosetupchemical}
+
+\def\dosetupchemical
+ {\getparameters[\??cm]}
+
+\let\setupchemicals\setupchemical
+
+\unexpanded\def\setupchemicalframed
+ {\dosingleempty\dosetupchemicalframed}
+
+\def\dosetupchemicalframed
+ {\getparameters[\??cm:\c!frame]}
+
+\def\chemicalparameter#1{\csname\??cm#1\endcsname}
+
+\unexpanded\def\definechemical
+ {\dosingleargument\dodefinechemical} % global
+
+\def\dodefinechemical[#1]#2%
+ {\startnointerference
+ \ctxlua{chemicals.undefine("#1")}%
+ \def\chemical{\dodoubleempty\dostructurechemical}%
+ \def\dostructurechemical[##1][##2]{\ctxlua{chemicals.define("#1",\!!bs##1\!!es,\!!bs\detokenize{##2}\!!es)}}%
+ #2% flush
+ \stopnointerference}
+
+\unexpanded\def\definechemicalsymbol
+ {\dodoubleempty\dodefinechemicalsymbol}
+
+\def\dodefinechemicalsymbol[#1][#2]%
+ {\setvalue{\??cm::#1}{#2}}
+
+\def\chemicalsymbol[#1]%
+ {\getvalue{\??cm::#1}}
+
+% size (small medium big)
+
+\def\dosetchemicaltext
+ {\dosetfontattribute \??cm\c!style
+ \dosetcolorattribute\??cm\c!color}
+
+\def\dochemicaltext#1%
+ {\dosetchemicaltext\strut#1} % maybe also \setstrut
+
+\edef\chemicaltoplocation{t}
+\edef\chemicalbotlocation{b}
+
+\def\dochemicaltext#1% in ppchtex we had a more clever alignment
+ {\dosetchemicaltext\strut#1} % maybe also \setstrut
+
+\def\dochemicaltext#1%
+ {\mathematics{\dosetchemicaltext\strut\ifcase\currentxfontsize\or\scriptstyle\or\scriptscriptstyle\fi#1}}
+
+\newconditional\indisplaychemical
+
+\unexpanded\def\startchemical
+ {\dosingleempty\dostartchemical}
+
+\setvalue{\??cm:\c!size:\v!small }{\txx}
+\setvalue{\??cm:\c!size:\v!medium}{\tx}
+\setvalue{\??cm:\c!size:\v!big }{}
+
+\newtoks \everychemical
+\newtoks \everystructurechemical
+\newtoks \withchemicalbox
+\newbox \chemicalbox
+\newconditional\somechemicaltext
+\newdimen \chemicalwidth
+\newdimen \chemicalheight
+\newdimen \chemicaldepth
+
+\def\dostartchemical[#1]%
+ {\ifmmode\vcenter\else\vbox\fi
+ \bgroup
+ \dontcomplain
+ \settrue\indisplaychemical
+ \forgetall
+ \getparameters[\??cm][#1]%
+ \the\everystructurechemical
+ \setbox\chemicalbox\hbox\bgroup
+ \ctxlua{chemicals.start {
+ width = "\chemicalparameter\c!width",
+ height = "\chemicalparameter\c!height",
+ left = \chemicalparameter\c!left,
+ right = \chemicalparameter\c!right,
+ top = \chemicalparameter\c!top,
+ bottom = \chemicalparameter\c!bottom,
+ scale = "\chemicalparameter\c!scale",
+ axis = "\chemicalparameter\c!axis",
+ offset = "\the\dimexpr.25em\relax",
+ } }%
+ \startnointerference}
+
+\unexpanded\def\stopchemical
+ {\stopnointerference
+ \ctxlua{chemicals.stop()}%
+ \egroup
+ \chemicalwidth \wd\chemicalbox
+ \chemicalheight\ht\chemicalbox
+ \chemicaldepth \dp\chemicalbox
+ \the\withchemicalbox
+ \doifelsenothing{\chemicalparameter\c!frame}\handlechemicalframednop\handlechemicalframedyes
+ \egroup}
+
+\def\handlechemicalframedyes
+ {\localframed%
+ [\??cm:\c!frame]%
+ [\c!frame=\chemicalparameter\c!frame,\c!align=\v!normal,\c!strut=\v!no]{\vbox{\box\chemicalbox\vss}}} % remove depth
+
+\def\handlechemicalframednop
+ {\localframed%
+ [\??cm:\c!frame]%
+ [\c!align=\v!normal,\c!strut=\v!no]{\vbox{\box\chemicalbox\vss}}} % remove depth
+
+\let\startstructurechemical\startchemical
+\let\stopstructurechemical \stopchemical
+
+\unexpanded\def\structurechemical
+ {\dotripleempty\dostructurechemical}
+
+\appendtoks
+ \let\chemical\structurechemical
+\to\everystructurechemical
+
+\def\dostructurechemical
+ {\ifthirdargument
+ \expandafter\dostructurechemicalthree
+ \else
+ \expandafter\dostructurechemicaltwo
+ \fi}
+
+\def\dostructurechemicalthree[#1][#2][#3]%
+ {\writestatus\m!chemicals{hyperlinked chemicals not yet supported}% todo reference, for the moment ignored
+ \ctxlua{chemicals.component(\!!bs#2\!!es, \!!bs\detokenize{#3}\!!es, { % maybe also pass first two args this way
+ rulethickness = "\the\dimexpr\chemicalparameter\c!rulethickness\relax", % todo: scaled points
+ rulecolor = "\MPcolor{\chemicalparameter\c!rulecolor}" % we can precalculate this for speedup
+ } ) }%
+ \ignorespaces}
+
+\def\dostructurechemicaltwo[#1][#2]%
+ {\ctxlua{chemicals.component(\!!bs#1\!!es,\!!bs\detokenize{#2}\!!es, { % maybe also pass first two args this way
+ rulethickness = "\the\dimexpr\chemicalparameter\c!rulethickness\relax", % todo: scaled points
+ rulecolor = "\MPcolor{\chemicalparameter\c!rulecolor}" % we can precalculate this for speedup
+ } ) }%
+ \ignorespaces}
+
+\appendtoks
+ \setbox\chemicalbox\hbox{\raise\MPlly\onebasepoint\box\chemicalbox}%
+ \chemicalwidth \wd\chemicalbox
+ \chemicalheight\ht\chemicalbox
+ \chemicaldepth \dp\chemicalbox
+\to \withchemicalbox
+
+% kind of compatible, but text sizes instead of math sizes (i.e. tx is larger than scriptsize)
+
+\appendtoks
+ \edef\chemicalbodyfont{\chemicalparameter\c!bodyfont}%
+ \doifnot\chemicalbodyfont\fontbody{\switchtobodyfont[\chemicalbodyfont]}% \fontbody is not expanded (yet)
+ \getvalue{\??cm:\c!size:\chemicalparameter\c!size}%
+% \to \everystructurechemical
+\to \everychemical
+
+\def\chemicaltoptext#1{\global\settrue\somechemicaltext\gdef\thetoptext{#1}\ignorespaces}
+\def\chemicalbottext#1{\global\settrue\somechemicaltext\gdef\thebottext{#1}\ignorespaces}
+\def\chemicalmidtext#1{\global\settrue\somechemicaltext\gdef\themidtext{#1}\ignorespaces}
+
+\appendtoks
+ \let\toptext\chemicaltoptext \glet\thetoptext\empty
+ \let\bottext\chemicalbottext \glet\thebottext\empty
+ \let\midtext\chemicalmidtext \glet\themidtext\empty
+ \global\setfalse\somechemicaltext
+\to \everystructurechemical
+
+\def\doaddchemicaltexts
+ {\setbox2\hbox to \chemicalwidth{\strut\hss\hbox{\strut\themidtext}\hss}%
+ \setbox4\hbox to \chemicalwidth{\strut\hss\hbox{\strut\thetoptext}\hss}%
+ \setbox6\hbox to \chemicalwidth{\strut\hss\hbox{\strut\thebottext}\hss}%
+ \setbox\chemicalbox\hbox \bgroup
+ \box\chemicalbox
+ \hskip-\chemicalwidth
+ \raise\chemicalheight\hbox{\lower\ht4\box4}%
+ \hskip-\chemicalwidth
+ \lower.5\dimexpr\ht2-\dp2\relax\box2%
+ \hskip-\chemicalwidth
+ \lower\chemicaldepth \hbox{\raise\dp6\box6}%
+ \hss
+ \egroup} % text on top of chemicals
+
+\appendtoks
+ \ifconditional\somechemicaltext
+ \doaddchemicaltexts
+ \chemicalwidth \wd\chemicalbox
+ \chemicalheight\ht\chemicalbox
+ \chemicaldepth \dp\chemicalbox
+ \fi
+\to \withchemicalbox
+
+% todo: enspace or emspace
+
+\definechemicalsymbol[space] [\enspace\quad\enspace]
+\definechemicalsymbol[plus] [\enspace+\enspace]
+\definechemicalsymbol[minus] [\enspace-\enspace]
+\definechemicalsymbol[gives] [\dochemicalarrow\xrightarrow]
+\definechemicalsymbol[equilibrium] [\dochemicalarrow\xrightoverleftarrow]
+\definechemicalsymbol[mesomeric] [\dochemicalarrow\xleftrightarrow]
+\definechemicalsymbol[opencomplex] [\mathematics{\Bigg[}] % not yet ok
+\definechemicalsymbol[closecomplex][\mathematics{\Bigg]}] % not yet ok
+
+\definechemicalsymbol[SPACE] [{\chemicalsymbol[space]}]
+\definechemicalsymbol[PLUS] [{\chemicalsymbol[plus]}]
+\definechemicalsymbol[MINUS] [{\chemicalsymbol[minus]}]
+\definechemicalsymbol[GIVES] [{\chemicalsymbol[gives]}]
+\definechemicalsymbol[EQUILIBRIUM] [{\chemicalsymbol[equilibrium]}]
+\definechemicalsymbol[MESOMERIC] [{\chemicalsymbol[mesomeric]}]
+\definechemicalsymbol[OPENCOMPLEX] [{\chemicalsymbol[opencomplex]}]
+\definechemicalsymbol[CLOSECOMPLEX][{\chemicalsymbol[closecomplex]}]
+
+\def\dochemicalarrow#1#2#3%
+ {\enspace
+ \mathematics{#1%
+ {\strut\hbox \!!spread 2em{\hss\ctxlua{chemicals.inline(\!!bs#2\!!es)}\hss}}%
+ {\strut\hbox \!!spread 2em{\hss\ctxlua{chemicals.inline(\!!bs#3\!!es)}\hss}}}%
+ \enspace}
+
+% special macros (probably needs some more work)
+
+\def\dochemicaltop#1#2#3#4%
+ {\begingroup
+ \setbox0\hbox{\tx\setstrut\strut#3}%
+ \setbox2\hbox{\setstrut\strut\molecule{#4}}%
+ \setbox0\hbox{\raise\dimexpr\dp0+\ht2\relax\hbox to \wd2{#1\box0#2}}%
+ \smashbox0
+ \hbox{\box0\box2}%
+ \endgroup}%
+
+\def\dochemicalbottom#1#2#3#4%
+ {\begingroup
+ \setbox0\hbox{\tx\setstrut\strut#3}%
+ \setbox2\hbox{\setstrut\strut#4}%
+ \setbox0\hbox{\lower\dimexpr\dp2+\ht0\relax\hbox to \wd2{#1\box0#2}}%
+ \smashbox0
+ \hbox{\box0\box2}%
+ \endgroup}%
+
+\unexpanded\def\chemicalleft#1#2%
+ {\begingroup
+ \hbox{\llap{\tx\setstrut\strut#1}\setstrut\strut#2}%
+ \endgroup}%
+
+\unexpanded\def\chemicalright#1#2%
+ {\begingroup
+ \hbox{\setstrut\strut#2\rlap{\tx\setstrut\strut#1}}%
+ \endgroup}%
+
+\unexpanded\def\chemicaltop {\dochemicaltop \hss \hss }
+\unexpanded\def\chemicallefttop {\dochemicaltop \relax \hss }
+\unexpanded\def\chemicalrighttop {\dochemicaltop \hss \relax}
+\unexpanded\def\chemicalbottom {\dochemicalbottom \hss \hss }
+\unexpanded\def\chemicalleftbottom {\dochemicalbottom \relax \hss }
+\unexpanded\def\chemicalrightbottom {\dochemicalbottom \hss \relax}
+
+\unexpanded\def\chemicaltopleft #1{\chemicalleft {\chemicalrighttop {#1}{}}}
+\unexpanded\def\chemicalbottomleft #1{\chemicalleft {\chemicalrightbottom{#1}{}}}
+\unexpanded\def\chemicaltopright #1{\chemicalright{\chemicallefttop {#1}{}}}
+\unexpanded\def\chemicalbottomright #1{\chemicalright{\chemicalleftbottom {#1}{}}}
+
+\unexpanded\def\chemicalcentered #1{\setbox\scratchbox\hbox{C}\hbox to \wd\scratchbox{\setstrut\strut\hss#1\hss}}
+\unexpanded\def\chemicalleftcentered #1{\setbox\scratchbox\hbox{C}\hbox to \wd\scratchbox{\setstrut\strut #1\hss}}
+\unexpanded\def\chemicalrightcentered#1{\setbox\scratchbox\hbox{C}\hbox to \wd\scratchbox{\setstrut\strut\hss#1}}
+
+\let\chemicalsmashedmiddle\chemicalcentered
+\let\chemicalsmashedleft \chemicalleftcentered
+\let\chemicalsmashedright \chemicalrightcentered
+
+\unexpanded\def\chemicaloxidation#1#2#3%
+ {\chemicaltop{\txx\ifcase#2\relax0\else#1\uppercase\expandafter{\romannumeral#2}\fi}{#3}}
+
+\unexpanded\def\chemicaloxidationplus {\dotriplegroupempty\chemicaloxidation{\textplus }} % {} needed!
+\unexpanded\def\chemicaloxidationminus{\dotriplegroupempty\chemicaloxidation{\textminus}} % {} needed!
+\unexpanded\def\chemicalforeveropen {\dotriplegroupempty\chemicalleft {$\big[$}} % {} needed!
+\unexpanded\def\chemicalforeverclose {\dotriplegroupempty\chemicalright {$\big]$}} % {} needed!
+\unexpanded\def\chemicaloxidationone {\chemicaloxidation\relax1}
+\unexpanded\def\chemicaloxidationtwo {\chemicaloxidation\relax2}
+\unexpanded\def\chemicaloxidationthree{\chemicaloxidation\relax3}
+\unexpanded\def\chemicaloxidationfour {\chemicaloxidation\relax4}
+\unexpanded\def\chemicaloxidationfive {\chemicaloxidation\relax5}
+\unexpanded\def\chemicaloxidationsix {\chemicaloxidation\relax6}
+\unexpanded\def\chemicaloxidationseven{\chemicaloxidation\relax7}
+
+\appendtoks
+ \let \+\chemicaloxidationplus
+ \let \-\chemicaloxidationminus
+ \let \[\chemicalforeveropen
+ \let \]\chemicalforeverclose
+ \let \1\chemicaloxidationone
+ \let \2\chemicaloxidationtwo
+ \let \3\chemicaloxidationthree
+ \let \4\chemicaloxidationfour
+ \let \5\chemicaloxidationfive
+ \let \6\chemicaloxidationsix
+ \let \7\chemicaloxidationseven
+ \let \X\chemicaltighttext
+ \let \T\chemicaltop
+ \let \B\chemicalbottom
+ \let \L\chemicalleft
+ \let\LC\chemicalleftcentered
+ \let \R\chemicalright
+ \let\RC\chemicalrightcentered
+ \let\TL\chemicaltopleft
+ \let\BL\chemicalbottomleft
+ \let\TR\chemicaltopright
+ \let\BR\chemicalbottomright
+ \let\LT\chemicallefttop
+ \let\LB\chemicalleftbottom
+ \let\RT\chemicalrighttop
+ \let\RB\chemicalrightbottom
+ \let\SL\chemicalsmashedleft
+ \let\SM\chemicalsmashedmiddle
+ \let\SR\chemicalsmashedright
+\to \everychemical
+
+\appendtoks
+ \the\everychemical
+\to \everystructurechemical
+
+% inline
+
+\unexpanded\def\chemical
+ {\ifinformula
+ \expandafter\displaychemical
+ \else
+ \expandafter\inlinechemical
+ \fi}
+
+\def\displaychemical
+ {\dotriplegroupempty\dodisplaychemical}
+
+\def\dodisplaychemical#1#2#3% todo:
+ {\the\everychemical \everychemical\emptytoks
+ \quad
+ \vcenter\bgroup
+ \ifthirdargument
+ \ifsecondargument
+ \halign{&\hss##\hss\cr#2\cr\molecule{#1}\cr#3\cr}%
+ \else
+ \halign{&\hss##\hss\cr\molecule{#1}\cr#2\cr}%
+ \fi
+ \else
+ \hbox{\molecule{#1}}%
+ \fi
+ \egroup
+ \quad}
+
+\def\inlinechemical#1%
+ {\dontleavehmode\hbox{\ctxlua{chemicals.inline(\!!bs#1\!!es)}}}
+
+\def\chemicalbondrule{\hbox{\vrule\!!height.75ex\!!depth-\dimexpr.75ex-\linewidth\relax\!!width1em\relax}}
+
+\definechemicalsymbol[i:space] [\enspace\quad\enspace]
+\definechemicalsymbol[i:plus] [\enspace\mathematics{+}\enspace]
+\definechemicalsymbol[i:minus] [\enspace\mathematics{-}\enspace]
+\definechemicalsymbol[i:gives] [\enspace\mathematics{\xrightarrow{}{}}\enspace]
+\definechemicalsymbol[i:equilibrium] [\enspace\mathematics{\xrightpverleftarrow{}{}}\enspace]
+\definechemicalsymbol[i:mesomeric] [\enspace\mathematics{\xleftrightarrow{}{}}\enspace]
+\definechemicalsymbol[i:single] [\chemicalbondrule]
+\definechemicalsymbol[i:tripple] [\hbox{\lower.5ex\chemicalbondrule\hskip-1em\raise.5ex\chemicalbondrule}]
+\definechemicalsymbol[i:double] [\hbox{\chemicalbondrule\hskip-1em\lower.5ex\chemicalbondrule\hskip-1em\raise.5ex\chemicalbondrule}]
+
+\def\chemicalsinglebond {\chemicalsymbol[i:single]}
+\def\chemicaldoublebond {\chemicalsymbol[i:tripple]}
+\def\chemicaltriplebond {\chemicalsymbol[i:double]}
+\def\chemicalgives {\chemicalsymbol[i:gives]}
+\def\chemicalmesomeric {\chemicalsymbol[i:mesomeric]}
+\def\chemicalequilibrium{\chemicalsymbol[i:equilibrium]}
+\def\chemicalsplus {\chemicalsymbol[i:plus]}
+\def\chemicalsminus {\chemicalsymbol[i:minus]}
+\def\chemicalsspace {\chemicalsymbol[i:space]}
+\def\chemicalinline #1{#1}
+
+% display
+
+\newconditional\formulachemicalhastop
+\newconditional\formulachemicalhasbot
+
+\newtoks\formulachemicaltop
+\newtoks\formulachemicalmid
+\newtoks\formulachemicalbot
+
+\newif\ifinchemicalformula
+
+\unexpanded\def\startchemicalformula
+ {\mathortext\vcenter\vbox\bgroup
+ \forgetall
+ \inchemicalformulatrue
+ \the\everychemical
+ \everychemical\emptytoks
+ \formulachemicaltop\emptytoks % not needed
+ \formulachemicalmid\emptytoks % not needed
+ \formulachemicalbot\emptytoks % not needed
+ \let\chemical\formulachemical
+ \setfalse\formulachemicalhastop
+ \setfalse\formulachemicalhasbot }
+
+\unexpanded\def\stopchemicalformula
+ {\tabskip1em\relax
+ \nointerlineskip
+ \ifconditional\formulachemicalhastop
+ \ifconditional\formulachemicalhasbot
+ \halign{&\hss##\hss\cr\the\formulachemicaltop\cr\the\formulachemicalmid\cr\the\formulachemicalbot\cr}%
+ \else
+ \halign{&\hss##\hss\cr\the\formulachemicaltop\cr\the\formulachemicalmid\cr}%
+ \fi
+ \else
+ \ifconditional\formulachemicalhasbot
+ \halign{&\hss##\hss\cr\the\formulachemicalmid\cr\the\formulachemicalbot\cr}%
+ \else
+ \halign{&\hss##\hss\cr\the\formulachemicalmid\cr}%
+ \fi
+ \fi
+ \egroup}
+
+\unexpanded\def\formulachemical
+ {\relax\dotriplegroupempty\doformulachemical}
+
+\def\doformulachemical#1#2#3%
+ {\ifthirdargument
+ \doifelsenothing{#2}\noformulachemicaltop{\doformulachemicaltop{#2}}%
+ \doifelsenothing{#3}\noformulachemicalbot{\doformulachemicalbot{#3}}%
+ \else\ifsecondargument
+ \noformulachemicaltop
+ \doifelsenothing{#2}\noformulachemicalbot{\doformulachemicalbot{#2}}%
+ \else
+ \noformulachemicaltop
+ \noformulachemicalbot
+ \fi\fi
+ \formulachemicalmid\expandafter{\the\formulachemicalmid\dodochemicalformulamid{#1}&}}
+
+\def\noformulachemicaltop {\formulachemicaltop\expandafter{\the\formulachemicaltop&}}
+\def\noformulachemicalbot {\formulachemicalbot\expandafter{\the\formulachemicalbot&}}
+\def\doformulachemicaltop#1{\formulachemicaltop\expandafter{\the\formulachemicaltop\dodochemicalformulatop{#1}&}\settrue\formulachemicalhastop}
+\def\doformulachemicalbot#1{\formulachemicalbot\expandafter{\the\formulachemicalbot\dodochemicalformulabot{#1}&}\settrue\formulachemicalhasbot}
+
+\def\dodochemicalformulamid#1%
+ {\ifcsname\??cm::\detokenize{#1}\endcsname\csname\??cm::\detokenize{#1}\expandafter\endcsname\else\molecule{#1}\fi{}{}}
+
+\def\dodochemicalformulatop#1{\strut#1}
+\def\dodochemicalformulabot#1{\strut#1}
+
+% gone: state option resolution offset (now frame offset) alternative
+
+\setupchemicalframed
+ [\c!align=\v!normal,
+ \c!strut=\v!no,
+ \c!offset=\v!overlay,
+ \c!frame=off]
+
+\setupchemical
+ [\c!frame=,
+ \c!width=0,
+ \c!height=0,
+ \c!left=0,
+ \c!right=0,
+ \c!top=0,
+ \c!bottom=0,
+ \c!bodyfont=\the\bodyfontsize,
+ \c!scale=\v!medium,
+ \c!size=\v!medium,
+ \c!textsize=\v!big,
+ \c!axis=\v!off,
+ \c!style=\rm,
+ \c!location=,
+ \c!color=,
+ \c!rulethickness=\linewidth,
+ \c!rulecolor=,
+ \c!factor=1]
+
+\protect \endinput
diff --git a/tex/context/base/colo-ema.tex b/tex/context/base/colo-ema.tex
new file mode 100644
index 000000000..e5e90b235
--- /dev/null
+++ b/tex/context/base/colo-ema.tex
@@ -0,0 +1,590 @@
+%D \module
+%D [ file=colo-ema,
+%D version=2003.03.20,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Emacs Colors,
+%D author=Peter Rolf,
+%D date=\currentdate,
+%D copyright=PRAGMA ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% author : Peter Rolf
+% last change : 17 march 2003
+% origin : /emacs/etc/rgb.txt
+%
+% USAGE:
+%
+% - select emacs menu: Edit -> Text Properties -> Display
+% Colors, if you don't know what I'm talking about
+% - copy this file to your /texmf/tex/context/user directory
+% and add "\input colo-emacs" to your tex-file
+%
+% IMPORTANT NOTES:
+%
+% - all color names are written as ONE word in lowercase
+% letters (no redundancy as in rgb.txt) so if you want to
+% use the color "Light Sky Blue"/"light sky blue" it's new
+% name is lightskyblue
+% - the grayX values [X=0..100] can only be used with \color
+% [grayX]
+% - use it at your own risk :)
+%
+% HINT:
+%
+% I only include this file (\showcolor [ema]) until I've
+% found the colors I want. Copy and paste the color
+% definitions to a seperate file, to decrease compilation
+% time (540 color definitions).
+
+\definecolor [snow] [r=1,g=.980392,b=.980392]
+\definecolor [ghostwhite] [r=.972549,g=.972549,b=1]
+\definecolor [whitesmoke] [s=.960784]
+\definecolor [gainsboro] [s=.862745]
+\definecolor [floralwhite] [r=1,g=.980392,b=.941176]
+\definecolor [oldlace] [r=.992157,g=.960784,b=.901961]
+\definecolor [linen] [r=.980392,g=.941176,b=.901961]
+\definecolor [antiquewhite] [r=.980392,g=.921569,b=.843137]
+\definecolor [papayawhip] [r=1,g=.937255,b=.835294]
+\definecolor [blanchedalmond] [r=1,g=.921569,b=.803922]
+\definecolor [bisque] [r=1,g=.894118,b=.768627]
+\definecolor [peachpuff] [r=1,g=.854902,b=.72549]
+\definecolor [navajowhite] [r=1,g=.870588,b=.678431]
+\definecolor [moccasin] [r=1,g=.894118,b=.709804]
+\definecolor [cornsilk] [r=1,g=.972549,b=.862745]
+\definecolor [ivory] [r=1,g=1,b=.941176]
+\definecolor [lemonchiffon] [r=1,g=.980392,b=.803922]
+\definecolor [seashell] [r=1,g=.960784,b=.933333]
+\definecolor [honeydew] [r=.941176,g=1,b=.941176]
+\definecolor [mintcream] [r=.960784,g=1,b=.980392]
+\definecolor [azure] [r=.941176,g=1,b=1]
+\definecolor [aliceblue] [r=.941176,g=.972549,b=1]
+\definecolor [lavender] [r=.901961,g=.901961,b=.980392]
+\definecolor [lavenderblush] [r=1,g=.941176,b=.960784]
+\definecolor [mistyrose] [r=1,g=.894118,b=.882353]
+%definecolor[white] [s=1]
+%definecolor[black] [s=0]
+\definecolor [darkslategray] [r=.184314,g=.309804,b=.309804]
+\definecolor [dimgray] [s=.411765]
+\definecolor [slategray] [r=.439216,g=.501961,b=.564706]
+\definecolor [lightslategray] [r=.466667,g=.533333,b=.6]
+\definecolor [gray] [s=.745098]
+\definecolor [lightgray] [s=.827451]
+\definecolor [midnightblue] [r=.098039,g=.098039,b=.439216]
+\definecolor [navy] [b=.501961]
+\definecolor [navyblue] [navy]
+\definecolor [cornflowerblue] [r=.392157,g=.584314,b=.929412]
+\definecolor [darkslateblue] [r=.282353,g=.239216,b=.545098]
+\definecolor [slateblue] [r=.415686,g=.352941,b=.803922]
+\definecolor [mediumslateblue] [r=.482353,g=.407843,b=.933333]
+\definecolor [lightslateblue] [r=.517647,g=.439216,b=1]
+\definecolor [mediumblue] [b=.803922]
+\definecolor [royalblue] [r=.254902,g=.411765,b=.882353]
+%definecolor[blue] [b=1]
+\definecolor [dodgerblue] [r=.117647,g=.564706,b=1]
+\definecolor [deepskyblue] [g=.74902,b=1]
+\definecolor [skyblue] [r=.529412,g=.807843,b=.921569]
+\definecolor [lightskyblue] [r=.529412,g=.807843,b=.980392]
+\definecolor [steelblue] [r=.27451,g=.509804,b=.705882]
+\definecolor [lightsteelblue] [r=.690196,g=.768627,b=.870588]
+\definecolor [lightblue] [r=.678431,g=.847059,b=.901961]
+\definecolor [powderblue] [r=.690196,g=.878431,b=.901961]
+\definecolor [paleturquoise] [r=.686275,g=.933333,b=.933333]
+\definecolor [darkturquoise] [g=.807843,b=.819608]
+\definecolor [mediumturquoise] [r=.282353,g=.819608,b=.8]
+\definecolor [turquoise] [r=.25098,g=.878431,b=.815686]
+%definecolor[cyan] [g=1,b=1]
+\definecolor [lightcyan] [r=.878431,g=1,b=1]
+\definecolor [cadetblue] [r=.372549,g=.619608,b=.627451]
+\definecolor [mediumaquamarine] [r=.4,g=.803922,b=.666667]
+\definecolor [aquamarine] [r=.498039,g=1,b=.831373]
+\definecolor [darkgreen] [g=.392157]
+\definecolor [darkolivegreen] [r=.333333,g=.419608,b=.184314]
+\definecolor [darkseagreen] [r=.560784,g=.737255,b=.560784]
+\definecolor [seagreen] [r=.180392,g=.545098,b=.341176]
+\definecolor [mediumseagreen] [r=.235294,g=.701961,b=.443137]
+\definecolor [lightseagreen] [r=.12549,g=.698039,b=.666667]
+\definecolor [palegreen] [r=.596078,g=.984314,b=.596078]
+\definecolor [springgreen] [g=1,b=.498039]
+\definecolor [lawngreen] [r=.486275,g=.988235]
+%definecolor[green] [g=1]
+\definecolor [chartreuse] [r=.498039,g=1]
+\definecolor [mediumspringgreen] [g=.980392,b=.603922]
+\definecolor [greenyellow] [r=.678431,g=1,b=.184314]
+\definecolor [limegreen] [r=.196078,g=.803922,b=.196078]
+\definecolor [yellowgreen] [r=.603922,g=.803922,b=.196078]
+\definecolor [forestgreen] [r=.133333,g=.545098,b=.133333]
+\definecolor [olivedrab] [r=.419608,g=.556863,b=.137255]
+\definecolor [darkkhaki] [r=.741176,g=.717647,b=.419608]
+\definecolor [khaki] [r=.941176,g=.901961,b=.54902]
+\definecolor [palegoldenrod] [r=.933333,g=.909804,b=.666667]
+\definecolor [lightgoldenrodyellow] [r=.980392,g=.980392,b=.823529]
+\definecolor [lightyellow] [r=1,g=1,b=.878431]
+%definecolor[yellow] [r=1,g=1]
+\definecolor [gold] [r=1,g=.843137]
+\definecolor [lightgoldenrod] [r=.933333,g=.866667,b=.509804]
+\definecolor [goldenrod] [r=.854902,g=.647059,b=.12549]
+\definecolor [darkgoldenrod] [r=.721569,g=.52549,b=.043137]
+\definecolor [rosybrown] [r=.737255,g=.560784,b=.560784]
+\definecolor [indianred] [r=.803922,g=.360784,b=.360784]
+\definecolor [saddlebrown] [r=.545098,g=.270588,b=.07451]
+\definecolor [sienna] [r=.627451,g=.321569,b=.176471]
+\definecolor [peru] [r=.803922,g=.521569,b=.247059]
+\definecolor [burlywood] [r=.870588,g=.721569,b=.529412]
+\definecolor [beige] [r=.960784,g=.960784,b=.862745]
+\definecolor [wheat] [r=.960784,g=.870588,b=.701961]
+\definecolor [sandybrown] [r=.956863,g=.643137,b=.376471]
+\definecolor [tan] [r=.823529,g=.705882,b=.54902]
+\definecolor [chocolate] [r=.823529,g=.411765,b=.117647]
+\definecolor [firebrick] [r=.698039,g=.133333,b=.133333]
+\definecolor [brown] [r=.647059,g=.164706,b=.164706]
+\definecolor [darksalmon] [r=.913725,g=.588235,b=.478431]
+\definecolor [salmon] [r=.980392,g=.501961,b=.447059]
+\definecolor [lightsalmon] [r=1,g=.627451,b=.478431]
+\definecolor [orange] [r=1,g=.647059]
+\definecolor [darkorange] [r=1,g=.54902]
+\definecolor [coral] [r=1,g=.498039,b=.313725]
+\definecolor [lightcoral] [r=.941176,g=.501961,b=.501961]
+\definecolor [tomato] [r=1,g=.388235,b=.278431]
+\definecolor [orangered] [r=1,g=.270588]
+%definecolor[red] [r=1]
+\definecolor [hotpink] [r=1,g=.411765,b=.705882]
+\definecolor [deeppink] [r=1,g=.078431,b=.576471]
+\definecolor [pink] [r=1,g=.752941,b=.796078]
+\definecolor [lightpink] [r=1,g=.713725,b=.756863]
+\definecolor [palevioletred] [r=.858824,g=.439216,b=.576471]
+\definecolor [maroon] [r=.690196,g=.188235,b=.376471]
+\definecolor [mediumvioletred] [r=.780392,g=.082353,b=.521569]
+\definecolor [violetred] [r=.815686,g=.12549,b=.564706]
+%definecolor[magenta] [r=1,b=1]
+\definecolor [violet] [r=.933333,g=.509804,b=.933333]
+\definecolor [plum] [r=.866667,g=.627451,b=.866667]
+\definecolor [orchid] [r=.854902,g=.439216,b=.839216]
+\definecolor [mediumorchid] [r=.729412,g=.333333,b=.827451]
+\definecolor [darkorchid] [r=.6,g=.196078,b=.8]
+\definecolor [darkviolet] [r=.580392,b=.827451]
+\definecolor [blueviolet] [r=.541176,g=.168627,b=.886275]
+\definecolor [purple] [r=.627451,g=.12549,b=.941176]
+\definecolor [mediumpurple] [r=.576471,g=.439216,b=.858824]
+\definecolor [thistle] [r=.847059,g=.74902,b=.847059]
+\definecolor [snow1] [r=1,g=.980392,b=.980392]
+\definecolor [snow2] [r=.933333,g=.913725,b=.913725]
+\definecolor [snow3] [r=.803922,g=.788235,b=.788235]
+\definecolor [snow4] [r=.545098,g=.537255,b=.537255]
+\definecolor [seashell1] [r=1,g=.960784,b=.933333]
+\definecolor [seashell2] [r=.933333,g=.898039,b=.870588]
+\definecolor [seashell3] [r=.803922,g=.772549,b=.74902]
+\definecolor [seashell4] [r=.545098,g=.52549,b=.509804]
+\definecolor [antiquewhite1] [r=1,g=.937255,b=.858824]
+\definecolor [antiquewhite2] [r=.933333,g=.87451,b=.8]
+\definecolor [antiquewhite3] [r=.803922,g=.752941,b=.690196]
+\definecolor [antiquewhite4] [r=.545098,g=.513725,b=.470588]
+\definecolor [bisque1] [r=1,g=.894118,b=.768627]
+\definecolor [bisque2] [r=.933333,g=.835294,b=.717647]
+\definecolor [bisque3] [r=.803922,g=.717647,b=.619608]
+\definecolor [bisque4] [r=.545098,g=.490196,b=.419608]
+\definecolor [peachpuff1] [r=1,g=.854902,b=.72549]
+\definecolor [peachpuff2] [r=.933333,g=.796078,b=.678431]
+\definecolor [peachpuff3] [r=.803922,g=.686275,b=.584314]
+\definecolor [peachpuff4] [r=.545098,g=.466667,b=.396078]
+\definecolor [navajowhite1] [r=1,g=.870588,b=.678431]
+\definecolor [navajowhite2] [r=.933333,g=.811765,b=.631373]
+\definecolor [navajowhite3] [r=.803922,g=.701961,b=.545098]
+\definecolor [navajowhite4] [r=.545098,g=.47451,b=.368627]
+\definecolor [lemonchiffon1] [r=1,g=.980392,b=.803922]
+\definecolor [lemonchiffon2] [r=.933333,g=.913725,b=.74902]
+\definecolor [lemonchiffon3] [r=.803922,g=.788235,b=.647059]
+\definecolor [lemonchiffon4] [r=.545098,g=.537255,b=.439216]
+\definecolor [cornsilk1] [r=1,g=.972549,b=.862745]
+\definecolor [cornsilk2] [r=.933333,g=.909804,b=.803922]
+\definecolor [cornsilk3] [r=.803922,g=.784314,b=.694118]
+\definecolor [cornsilk4] [r=.545098,g=.533333,b=.470588]
+\definecolor [ivory1] [r=1,g=1,b=.941176]
+\definecolor [ivory2] [r=.933333,g=.933333,b=.878431]
+\definecolor [ivory3] [r=.803922,g=.803922,b=.756863]
+\definecolor [ivory4] [r=.545098,g=.545098,b=.513725]
+\definecolor [honeydew1] [r=.941176,g=1,b=.941176]
+\definecolor [honeydew2] [r=.878431,g=.933333,b=.878431]
+\definecolor [honeydew3] [r=.756863,g=.803922,b=.756863]
+\definecolor [honeydew4] [r=.513725,g=.545098,b=.513725]
+\definecolor [lavenderblush1] [r=1,g=.941176,b=.960784]
+\definecolor [lavenderblush2] [r=.933333,g=.878431,b=.898039]
+\definecolor [lavenderblush3] [r=.803922,g=.756863,b=.772549]
+\definecolor [lavenderblush4] [r=.545098,g=.513725,b=.52549]
+\definecolor [mistyrose1] [r=1,g=.894118,b=.882353]
+\definecolor [mistyrose2] [r=.933333,g=.835294,b=.823529]
+\definecolor [mistyrose3] [r=.803922,g=.717647,b=.709804]
+\definecolor [mistyrose4] [r=.545098,g=.490196,b=.482353]
+\definecolor [azure1] [r=.941176,g=1,b=1]
+\definecolor [azure2] [r=.878431,g=.933333,b=.933333]
+\definecolor [azure3] [r=.756863,g=.803922,b=.803922]
+\definecolor [azure4] [r=.513725,g=.545098,b=.545098]
+\definecolor [slateblue1] [r=.513725,g=.435294,b=1]
+\definecolor [slateblue2] [r=.478431,g=.403922,b=.933333]
+\definecolor [slateblue3] [r=.411765,g=.34902,b=.803922]
+\definecolor [slateblue4] [r=.278431,g=.235294,b=.545098]
+\definecolor [royalblue1] [r=.282353,g=.462745,b=1]
+\definecolor [royalblue2] [r=.262745,g=.431373,b=.933333]
+\definecolor [royalblue3] [r=.227451,g=.372549,b=.803922]
+\definecolor [royalblue4] [r=.152941,g=.25098,b=.545098]
+\definecolor [blue1] [blue]
+\definecolor [blue2] [b=.933333]
+\definecolor [blue3] [b=.803922]
+\definecolor [blue4] [b=.545098]
+\definecolor [dodgerblue1] [r=.117647,g=.564706,b=1]
+\definecolor [dodgerblue2] [r=.109804,g=.52549,b=.933333]
+\definecolor [dodgerblue3] [r=.094118,g=.454902,b=.803922]
+\definecolor [dodgerblue4] [r=.062745,g=.305882,b=.545098]
+\definecolor [steelblue1] [r=.388235,g=.721569,b=1]
+\definecolor [steelblue2] [r=.360784,g=.67451,b=.933333]
+\definecolor [steelblue3] [r=.309804,g=.580392,b=.803922]
+\definecolor [steelblue4] [r=.211765,g=.392157,b=.545098]
+\definecolor [deepskyblue1] [g=.74902,b=1]
+\definecolor [deepskyblue2] [g=.698039,b=.933333]
+\definecolor [deepskyblue3] [g=.603922,b=.803922]
+\definecolor [deepskyblue4] [g=.407843,b=.545098]
+\definecolor [skyblue1] [r=.529412,g=.807843,b=1]
+\definecolor [skyblue2] [r=.494118,g=.752941,b=.933333]
+\definecolor [skyblue3] [r=.423529,g=.65098,b=.803922]
+\definecolor [skyblue4] [r=.290196,g=.439216,b=.545098]
+\definecolor [lightskyblue1] [r=.690196,g=.886275,b=1]
+\definecolor [lightskyblue2] [r=.643137,g=.827451,b=.933333]
+\definecolor [lightskyblue3] [r=.552941,g=.713725,b=.803922]
+\definecolor [lightskyblue4] [r=.376471,g=.482353,b=.545098]
+\definecolor [slategray1] [r=.776471,g=.886275,b=1]
+\definecolor [slategray2] [r=.72549,g=.827451,b=.933333]
+\definecolor [slategray3] [r=.623529,g=.713725,b=.803922]
+\definecolor [slategray4] [r=.423529,g=.482353,b=.545098]
+\definecolor [lightsteelblue1] [r=.792157,g=.882353,b=1]
+\definecolor [lightsteelblue2] [r=.737255,g=.823529,b=.933333]
+\definecolor [lightsteelblue3] [r=.635294,g=.709804,b=.803922]
+\definecolor [lightsteelblue4] [r=.431373,g=.482353,b=.545098]
+\definecolor [lightblue1] [r=.74902,g=.937255,b=1]
+\definecolor [lightblue2] [r=.698039,g=.87451,b=.933333]
+\definecolor [lightblue3] [r=.603922,g=.752941,b=.803922]
+\definecolor [lightblue4] [r=.407843,g=.513725,b=.545098]
+\definecolor [lightcyan1] [r=.878431,g=1,b=1]
+\definecolor [lightcyan2] [r=.819608,g=.933333,b=.933333]
+\definecolor [lightcyan3] [r=.705882,g=.803922,b=.803922]
+\definecolor [lightcyan4] [r=.478431,g=.545098,b=.545098]
+\definecolor [paleturquoise1] [r=.733333,g=1,b=1]
+\definecolor [paleturquoise2] [r=.682353,g=.933333,b=.933333]
+\definecolor [paleturquoise3] [r=.588235,g=.803922,b=.803922]
+\definecolor [paleturquoise4] [r=.4,g=.545098,b=.545098]
+\definecolor [cadetblue1] [r=.596078,g=.960784,b=1]
+\definecolor [cadetblue2] [r=.556863,g=.898039,b=.933333]
+\definecolor [cadetblue3] [r=.478431,g=.772549,b=.803922]
+\definecolor [cadetblue4] [r=.32549,g=.52549,b=.545098]
+\definecolor [turquoise1] [g=.960784,b=1]
+\definecolor [turquoise2] [g=.898039,b=.933333]
+\definecolor [turquoise3] [g=.772549,b=.803922]
+\definecolor [turquoise4] [g=.52549,b=.545098]
+\definecolor [cyan1] [cyan]
+\definecolor [cyan2] [g=.933333,b=.933333]
+\definecolor [cyan3] [g=.803922,b=.803922]
+\definecolor [cyan4] [g=.545098,b=.545098]
+\definecolor [darkslategray1] [r=.592157,g=1,b=1]
+\definecolor [darkslategray2] [r=.552941,g=.933333,b=.933333]
+\definecolor [darkslategray3] [r=.47451,g=.803922,b=.803922]
+\definecolor [darkslategray4] [r=.321569,g=.545098,b=.545098]
+\definecolor [aquamarine1] [r=.498039,g=1,b=.831373]
+\definecolor [aquamarine2] [r=.462745,g=.933333,b=.776471]
+\definecolor [aquamarine3] [r=.4,g=.803922,b=.666667]
+\definecolor [aquamarine4] [r=.270588,g=.545098,b=.454902]
+\definecolor [darkseagreen1] [r=.756863,g=1,b=.756863]
+\definecolor [darkseagreen2] [r=.705882,g=.933333,b=.705882]
+\definecolor [darkseagreen3] [r=.607843,g=.803922,b=.607843]
+\definecolor [darkseagreen4] [r=.411765,g=.545098,b=.411765]
+\definecolor [seagreen1] [r=.329412,g=1,b=.623529]
+\definecolor [seagreen2] [r=.305882,g=.933333,b=.580392]
+\definecolor [seagreen3] [r=.262745,g=.803922,b=.501961]
+\definecolor [seagreen4] [r=.180392,g=.545098,b=.341176]
+\definecolor [palegreen1] [r=.603922,g=1,b=.603922]
+\definecolor [palegreen2] [r=.564706,g=.933333,b=.564706]
+\definecolor [palegreen3] [r=.486275,g=.803922,b=.486275]
+\definecolor [palegreen4] [r=.329412,g=.545098,b=.329412]
+\definecolor [springgreen1] [g=1,b=.498039]
+\definecolor [springgreen2] [g=.933333,b=.462745]
+\definecolor [springgreen3] [g=.803922,b=.4]
+\definecolor [springgreen4] [g=.545098,b=.270588]
+\definecolor [green1] [green]
+\definecolor [green2] [g=.933333]
+\definecolor [green3] [g=.803922]
+\definecolor [green4] [g=.545098]
+\definecolor [chartreuse1] [r=.498039,g=1]
+\definecolor [chartreuse2] [r=.462745,g=.933333]
+\definecolor [chartreuse3] [r=.4,g=.803922]
+\definecolor [chartreuse4] [r=.270588,g=.545098]
+\definecolor [olivedrab1] [r=.752941,g=1,b=.243137]
+\definecolor [olivedrab2] [r=.701961,g=.933333,b=.227451]
+\definecolor [olivedrab3] [r=.603922,g=.803922,b=.196078]
+\definecolor [olivedrab4] [r=.411765,g=.545098,b=.133333]
+\definecolor [darkolivegreen1] [r=.792157,g=1,b=.439216]
+\definecolor [darkolivegreen2] [r=.737255,g=.933333,b=.407843]
+\definecolor [darkolivegreen3] [r=.635294,g=.803922,b=.352941]
+\definecolor [darkolivegreen4] [r=.431373,g=.545098,b=.239216]
+\definecolor [khaki1] [r=1,g=.964706,b=.560784]
+\definecolor [khaki2] [r=.933333,g=.901961,b=.521569]
+\definecolor [khaki3] [r=.803922,g=.776471,b=.45098]
+\definecolor [khaki4] [r=.545098,g=.52549,b=.305882]
+\definecolor [lightgoldenrod1] [r=1,g=.92549,b=.545098]
+\definecolor [lightgoldenrod2] [r=.933333,g=.862745,b=.509804]
+\definecolor [lightgoldenrod3] [r=.803922,g=.745098,b=.439216]
+\definecolor [lightgoldenrod4] [r=.545098,g=.505882,b=.298039]
+\definecolor [lightyellow1] [r=1,g=1,b=.878431]
+\definecolor [lightyellow2] [r=.933333,g=.933333,b=.819608]
+\definecolor [lightyellow3] [r=.803922,g=.803922,b=.705882]
+\definecolor [lightyellow4] [r=.545098,g=.545098,b=.478431]
+\definecolor [yellow1] [yellow]
+\definecolor [yellow2] [r=.933333,g=.933333]
+\definecolor [yellow3] [r=.803922,g=.803922]
+\definecolor [yellow4] [r=.545098,g=.545098]
+\definecolor [gold1] [r=1,g=.843137]
+\definecolor [gold2] [r=.933333,g=.788235]
+\definecolor [gold3] [r=.803922,g=.678431]
+\definecolor [gold4] [r=.545098,g=.458824]
+\definecolor [goldenrod1] [r=1,g=.756863,b=.145098]
+\definecolor [goldenrod2] [r=.933333,g=.705882,b=.133333]
+\definecolor [goldenrod3] [r=.803922,g=.607843,b=.113725]
+\definecolor [goldenrod4] [r=.545098,g=.411765,b=.078431]
+\definecolor [darkgoldenrod1] [r=1,g=.72549,b=.058824]
+\definecolor [darkgoldenrod2] [r=.933333,g=.678431,b=.054902]
+\definecolor [darkgoldenrod3] [r=.803922,g=.584314,b=.047059]
+\definecolor [darkgoldenrod4] [r=.545098,g=.396078,b=.031373]
+\definecolor [rosybrown1] [r=1,g=.756863,b=.756863]
+\definecolor [rosybrown2] [r=.933333,g=.705882,b=.705882]
+\definecolor [rosybrown3] [r=.803922,g=.607843,b=.607843]
+\definecolor [rosybrown4] [r=.545098,g=.411765,b=.411765]
+\definecolor [indianred1] [r=1,g=.415686,b=.415686]
+\definecolor [indianred2] [r=.933333,g=.388235,b=.388235]
+\definecolor [indianred3] [r=.803922,g=.333333,b=.333333]
+\definecolor [indianred4] [r=.545098,g=.227451,b=.227451]
+\definecolor [sienna1] [r=1,g=.509804,b=.278431]
+\definecolor [sienna2] [r=.933333,g=.47451,b=.258824]
+\definecolor [sienna3] [r=.803922,g=.407843,b=.223529]
+\definecolor [sienna4] [r=.545098,g=.278431,b=.14902]
+\definecolor [burlywood1] [r=1,g=.827451,b=.607843]
+\definecolor [burlywood2] [r=.933333,g=.772549,b=.568627]
+\definecolor [burlywood3] [r=.803922,g=.666667,b=.490196]
+\definecolor [burlywood4] [r=.545098,g=.45098,b=.333333]
+\definecolor [wheat1] [r=1,g=.905882,b=.729412]
+\definecolor [wheat2] [r=.933333,g=.847059,b=.682353]
+\definecolor [wheat3] [r=.803922,g=.729412,b=.588235]
+\definecolor [wheat4] [r=.545098,g=.494118,b=.4]
+\definecolor [tan1] [r=1,g=.647059,b=.309804]
+\definecolor [tan2] [r=.933333,g=.603922,b=.286275]
+\definecolor [tan3] [r=.803922,g=.521569,b=.247059]
+\definecolor [tan4] [r=.545098,g=.352941,b=.168627]
+\definecolor [chocolate1] [r=1,g=.498039,b=.141176]
+\definecolor [chocolate2] [r=.933333,g=.462745,b=.129412]
+\definecolor [chocolate3] [r=.803922,g=.4,b=.113725]
+\definecolor [chocolate4] [r=.545098,g=.270588,b=.07451]
+\definecolor [firebrick1] [r=1,g=.188235,b=.188235]
+\definecolor [firebrick2] [r=.933333,g=.172549,b=.172549]
+\definecolor [firebrick3] [r=.803922,g=.14902,b=.14902]
+\definecolor [firebrick4] [r=.545098,g=.101961,b=.101961]
+\definecolor [brown1] [r=1,g=.25098,b=.25098]
+\definecolor [brown2] [r=.933333,g=.231373,b=.231373]
+\definecolor [brown3] [r=.803922,g=.2,b=.2]
+\definecolor [brown4] [r=.545098,g=.137255,b=.137255]
+\definecolor [salmon1] [r=1,g=.54902,b=.411765]
+\definecolor [salmon2] [r=.933333,g=.509804,b=.384314]
+\definecolor [salmon3] [r=.803922,g=.439216,b=.329412]
+\definecolor [salmon4] [r=.545098,g=.298039,b=.223529]
+\definecolor [lightsalmon1] [r=1,g=.627451,b=.478431]
+\definecolor [lightsalmon2] [r=.933333,g=.584314,b=.447059]
+\definecolor [lightsalmon3] [r=.803922,g=.505882,b=.384314]
+\definecolor [lightsalmon4] [r=.545098,g=.341176,b=.258824]
+\definecolor [orange1] [r=1,g=.647059]
+\definecolor [orange2] [r=.933333,g=.603922]
+\definecolor [orange3] [r=.803922,g=.521569]
+\definecolor [orange4] [r=.545098,g=.352941]
+\definecolor [darkorange1] [r=1,g=.498039]
+\definecolor [darkorange2] [r=.933333,g=.462745]
+\definecolor [darkorange3] [r=.803922,g=.4]
+\definecolor [darkorange4] [r=.545098,g=.270588]
+\definecolor [coral1] [r=1,g=.447059,b=.337255]
+\definecolor [coral2] [r=.933333,g=.415686,b=.313725]
+\definecolor [coral3] [r=.803922,g=.356863,b=.270588]
+\definecolor [coral4] [r=.545098,g=.243137,b=.184314]
+\definecolor [tomato1] [r=1,g=.388235,b=.278431]
+\definecolor [tomato2] [r=.933333,g=.360784,b=.258824]
+\definecolor [tomato3] [r=.803922,g=.309804,b=.223529]
+\definecolor [tomato4] [r=.545098,g=.211765,b=.14902]
+\definecolor [orangered1] [r=1,g=.270588]
+\definecolor [orangered2] [r=.933333,g=.25098]
+\definecolor [orangered3] [r=.803922,g=.215686]
+\definecolor [orangered4] [r=.545098,g=.145098]
+\definecolor [red1] [red]
+\definecolor [red2] [r=.933333]
+\definecolor [red3] [r=.803922]
+\definecolor [red4] [r=.545098]
+\definecolor [deeppink1] [r=1,g=.078431,b=.576471]
+\definecolor [deeppink2] [r=.933333,g=.070588,b=.537255]
+\definecolor [deeppink3] [r=.803922,g=.062745,b=.462745]
+\definecolor [deeppink4] [r=.545098,g=.039216,b=.313725]
+\definecolor [hotpink1] [r=1,g=.431373,b=.705882]
+\definecolor [hotpink2] [r=.933333,g=.415686,b=.654902]
+\definecolor [hotpink3] [r=.803922,g=.376471,b=.564706]
+\definecolor [hotpink4] [r=.545098,g=.227451,b=.384314]
+\definecolor [pink1] [r=1,g=.709804,b=.772549]
+\definecolor [pink2] [r=.933333,g=.662745,b=.721569]
+\definecolor [pink3] [r=.803922,g=.568627,b=.619608]
+\definecolor [pink4] [r=.545098,g=.388235,b=.423529]
+\definecolor [lightpink1] [r=1,g=.682353,b=.72549]
+\definecolor [lightpink2] [r=.933333,g=.635294,b=.678431]
+\definecolor [lightpink3] [r=.803922,g=.54902,b=.584314]
+\definecolor [lightpink4] [r=.545098,g=.372549,b=.396078]
+\definecolor [palevioletred1] [r=1,g=.509804,b=.670588]
+\definecolor [palevioletred2] [r=.933333,g=.47451,b=.623529]
+\definecolor [palevioletred3] [r=.803922,g=.407843,b=.537255]
+\definecolor [palevioletred4] [r=.545098,g=.278431,b=.364706]
+\definecolor [maroon1] [r=1,g=.203922,b=.701961]
+\definecolor [maroon2] [r=.933333,g=.188235,b=.654902]
+\definecolor [maroon3] [r=.803922,g=.160784,b=.564706]
+\definecolor [maroon4] [r=.545098,g=.109804,b=.384314]
+\definecolor [violetred1] [r=1,g=.243137,b=.588235]
+\definecolor [violetred2] [r=.933333,g=.227451,b=.54902]
+\definecolor [violetred3] [r=.803922,g=.196078,b=.470588]
+\definecolor [violetred4] [r=.545098,g=.133333,b=.321569]
+\definecolor [magenta1] [magenta]
+\definecolor [magenta2] [r=.933333,b=.933333]
+\definecolor [magenta3] [r=.803922,b=.803922]
+\definecolor [magenta4] [r=.545098,b=.545098]
+\definecolor [orchid1] [r=1,g=.513725,b=.980392]
+\definecolor [orchid2] [r=.933333,g=.478431,b=.913725]
+\definecolor [orchid3] [r=.803922,g=.411765,b=.788235]
+\definecolor [orchid4] [r=.545098,g=.278431,b=.537255]
+\definecolor [plum1] [r=1,g=.733333,b=1]
+\definecolor [plum2] [r=.933333,g=.682353,b=.933333]
+\definecolor [plum3] [r=.803922,g=.588235,b=.803922]
+\definecolor [plum4] [r=.545098,g=.4,b=.545098]
+\definecolor [mediumorchid1] [r=.878431,g=.4,b=1]
+\definecolor [mediumorchid2] [r=.819608,g=.372549,b=.933333]
+\definecolor [mediumorchid3] [r=.705882,g=.321569,b=.803922]
+\definecolor [mediumorchid4] [r=.478431,g=.215686,b=.545098]
+\definecolor [darkorchid1] [r=.74902,g=.243137,b=1]
+\definecolor [darkorchid2] [r=.698039,g=.227451,b=.933333]
+\definecolor [darkorchid3] [r=.603922,g=.196078,b=.803922]
+\definecolor [darkorchid4] [r=.407843,g=.133333,b=.545098]
+\definecolor [purple1] [r=.607843,g=.188235,b=1]
+\definecolor [purple2] [r=.568627,g=.172549,b=.933333]
+\definecolor [purple3] [r=.490196,g=.14902,b=.803922]
+\definecolor [purple4] [r=.333333,g=.101961,b=.545098]
+\definecolor [mediumpurple1] [r=.670588,g=.509804,b=1]
+\definecolor [mediumpurple2] [r=.623529,g=.47451,b=.933333]
+\definecolor [mediumpurple3] [r=.537255,g=.407843,b=.803922]
+\definecolor [mediumpurple4] [r=.364706,g=.278431,b=.545098]
+\definecolor [thistle1] [r=1,g=.882353,b=1]
+\definecolor [thistle2] [r=.933333,g=.823529,b=.933333]
+\definecolor [thistle3] [r=.803922,g=.709804,b=.803922]
+\definecolor [thistle4] [r=.545098,g=.482353,b=.545098]
+\definecolor [gray0] [black]
+\definecolor [gray1] [s=.01]
+\definecolor [gray2] [s=.02]
+\definecolor [gray3] [s=.03]
+\definecolor [gray4] [s=.04]
+\definecolor [gray5] [s=.05]
+\definecolor [gray6] [s=.06]
+\definecolor [gray7] [s=.07]
+\definecolor [gray8] [s=.08]
+\definecolor [gray9] [s=.09]
+\definecolor [gray10] [s=.1]
+\definecolor [gray11] [s=.11]
+\definecolor [gray12] [s=.12]
+\definecolor [gray13] [s=.13]
+\definecolor [gray14] [s=.14]
+\definecolor [gray15] [s=.15]
+\definecolor [gray16] [s=.16]
+\definecolor [gray17] [s=.17]
+\definecolor [gray18] [s=.18]
+\definecolor [gray19] [s=.19]
+\definecolor [gray20] [s=.2]
+\definecolor [gray21] [s=.21]
+\definecolor [gray22] [s=.22]
+\definecolor [gray23] [s=.23]
+\definecolor [gray24] [s=.24]
+\definecolor [gray25] [s=.25]
+\definecolor [gray26] [s=.26]
+\definecolor [gray27] [s=.27]
+\definecolor [gray28] [s=.28]
+\definecolor [gray29] [s=.29]
+\definecolor [gray30] [s=.3]
+\definecolor [gray31] [s=.31]
+\definecolor [gray32] [s=.32]
+\definecolor [gray33] [s=.33]
+\definecolor [gray34] [s=.34]
+\definecolor [gray35] [s=.35]
+\definecolor [gray36] [s=.36]
+\definecolor [gray37] [s=.37]
+\definecolor [gray38] [s=.38]
+\definecolor [gray39] [s=.39]
+\definecolor [gray40] [s=.4]
+\definecolor [gray41] [s=.41]
+\definecolor [gray42] [s=.42]
+\definecolor [gray43] [s=.43]
+\definecolor [gray44] [s=.44]
+\definecolor [gray45] [s=.45]
+\definecolor [gray46] [s=.46]
+\definecolor [gray47] [s=.47]
+\definecolor [gray48] [s=.48]
+\definecolor [gray49] [s=.49]
+\definecolor [gray50] [s=.5]
+\definecolor [gray51] [s=.51]
+\definecolor [gray52] [s=.52]
+\definecolor [gray53] [s=.53]
+\definecolor [gray54] [s=.54]
+\definecolor [gray55] [s=.55]
+\definecolor [gray56] [s=.56]
+\definecolor [gray57] [s=.57]
+\definecolor [gray58] [s=.58]
+\definecolor [gray59] [s=.59]
+\definecolor [gray60] [s=.6]
+\definecolor [gray61] [s=.61]
+\definecolor [gray62] [s=.62]
+\definecolor [gray63] [s=.63]
+\definecolor [gray64] [s=.64]
+\definecolor [gray65] [s=.65]
+\definecolor [gray66] [s=.66]
+\definecolor [gray67] [s=.67]
+\definecolor [gray68] [s=.68]
+\definecolor [gray69] [s=.69]
+\definecolor [gray70] [s=.7]
+\definecolor [gray71] [s=.71]
+\definecolor [gray72] [s=.72]
+\definecolor [gray73] [s=.73]
+\definecolor [gray74] [s=.74]
+\definecolor [gray75] [s=.75]
+\definecolor [gray76] [s=.76]
+\definecolor [gray77] [s=.77]
+\definecolor [gray78] [s=.78]
+\definecolor [gray79] [s=.79]
+\definecolor [gray80] [s=.8]
+\definecolor [gray81] [s=.81]
+\definecolor [gray82] [s=.82]
+\definecolor [gray83] [s=.83]
+\definecolor [gray84] [s=.84]
+\definecolor [gray85] [s=.85]
+\definecolor [gray86] [s=.86]
+\definecolor [gray87] [s=.87]
+\definecolor [gray88] [s=.88]
+\definecolor [gray89] [s=.89]
+\definecolor [gray90] [s=.9]
+\definecolor [gray91] [s=.91]
+\definecolor [gray92] [s=.92]
+\definecolor [gray93] [s=.93]
+\definecolor [gray94] [s=.94]
+\definecolor [gray95] [s=.95]
+\definecolor [gray96] [s=.96]
+\definecolor [gray97] [s=.97]
+\definecolor [gray98] [s=.98]
+\definecolor [gray99] [s=.99]
+\definecolor [gray100] [white]
+\definecolor [darkgray] [s=.662745]
+\definecolor [darkblue] [b=.545098]
+\definecolor [darkcyan] [g=.545098,b=.545098]
+\definecolor [darkmagenta] [r=.545098,b=.545098]
+\definecolor [darkred] [r=.545098]
+\definecolor [lightgreen] [r=.564706,g=.933333,b=.564706]
diff --git a/tex/context/base/colo-ext.mkii b/tex/context/base/colo-ext.mkii
new file mode 100644
index 000000000..473c010e0
--- /dev/null
+++ b/tex/context/base/colo-ext.mkii
@@ -0,0 +1,59 @@
+%D \module
+%D [ file=colo-ext, % mostof thsi code used to be in colo-ini.tex
+%D version=1997.04.01,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Extras,
+%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 Color Macros / Extras}
+
+\unprotect
+
+%D \macros
+%D {negatecolorcomponent, negativecolorbox}
+%D
+%D Sometimes, especially when we deal with typesetting
+%D devices, we want to reverse the color scheme. Instead of
+%D recalculating all those colors, we use a quick and dirty
+%D approach:
+%D
+%D \starttyping
+%D \negativecolorbox0
+%D \stoptyping
+%D
+%D will negate the colors in box zero.
+
+\def\negatecolorbox#1%
+ {\setbox#1\hbox
+ {\dostartnegative
+ \localstartcolor[white]\vrule\!!height\ht#1\!!depth\dp#1\!!width\wd#1\localstopcolor
+ \hskip-\wd#1%
+ \box#1%
+ \dostopnegative}}
+
+%D There are in principle two ways to handle overprint: bound to colors
+%D or independent. For the moment we only support independent overprint
+%D handling. Here we deal with a per-document setting.
+
+\setupcolors
+ [\c!intent=\v!none]
+
+\def\starttextoverprint
+ {\doifelse\@@clintent\v!overprint
+ {\glet\stoptextoverprint \dostopoverprint
+ \glet\starttextoverprint\dostartoverprint
+ \dostartoverprint}
+ {\glet\stoptextoverprint\donothing}}
+
+\let\stoptextoverprint\donothing
+
+\appendtoks \starttextoverprint \to \everystarttextproperties
+\appendtoks \stoptextoverprint \to \everystoptextproperties
+
+\protect \endinput
diff --git a/tex/context/base/colo-ext.mkiv b/tex/context/base/colo-ext.mkiv
new file mode 100644
index 000000000..b17608f59
--- /dev/null
+++ b/tex/context/base/colo-ext.mkiv
@@ -0,0 +1,103 @@
+%D \module
+%D [ file=colo-ext, % mostof thsi code used to be in colo-ini.tex
+%D version=1997.04.01,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Extras,
+%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 Color Macros / Extras}
+
+\unprotect
+
+%D \macros
+%D {negatecolorcomponent, negativecolorbox}
+%D
+%D Sometimes, especially when we deal with typesetting
+%D devices, we want to reverse the color scheme. Instead of
+%D recalculating all those colors, we use a quick and dirty
+%D approach:
+%D
+%D \starttyping
+%D \negativecolorbox0
+%D \stoptyping
+%D
+%D will negate the colors in box zero.
+
+\def\negatecolorbox#1%
+ {\setbox#1\hbox
+ {\startnegativeproperty % might change
+ \startcolor[white]\vrule\!!height\ht#1\!!depth\dp#1\!!width\wd#1\stopcolor
+ \hskip-\wd#1%
+ \box#1%
+ \stopnegativeproperty}}
+
+%D There are in principle two ways to handle overprint: bound to colors
+%D or independent. For the moment we only support independent overprint
+%D handling. Here we deal with a per-document setting.
+
+\unexpanded\def\startcolorintent[#1]%
+ {\pushattribute\colorintentattribute
+ \dotriggercolorintent{#1}}
+
+\unexpanded\def\stopcolorintent
+ {\popattribute\colorintentattribute}
+
+\unexpanded\def\startoverprint{\startcolorintent[\v!overprint]}
+\unexpanded\def\stopoverprint {\stopcolorintent}
+
+\unexpanded\def\startknockout {\startcolorintent[\v!knockout ]}
+\unexpanded\def\stopknockout {\stopcolorintent}
+
+\let\starttextcolorintent\relax
+\let\stoptextcolorintent \relax
+
+\setupcolors
+ [\c!overprint=\v!no]
+
+\appendtoks
+ \dosettextcolorintent
+\to \everysetupcolors
+
+\def\dosettextcolorintent
+ {\doifnot\@@clintent\v!none
+ {\xdef\starttextcolorintent{\noexpand\dotriggercolorintent{\@@clintent}}%
+ \glet\dosettextcolorintent\relax
+ \dotriggercolorintent\@@clintent}}
+
+\appendtoks \starttextcolorintent \to \everystarttextproperties
+\appendtoks \stoptextcolorintent \to \everystoptextproperties
+
+\setupcolors[\c!intent=\v!none]
+
+% A goodie that replaces the startMPcolor hackery
+%
+% \definecolor[red-t] [r=1,t=0.5,a=1]
+% \definecolor[green-t][g=1,t=0.5,a=1]
+% \defineintermediatecolor[mycolora][0.5,red,green]
+% \defineintermediatecolor[mycolorb][0.5,red-t,green-t]
+% \starttext
+% test {\mycolora OEPS} test
+% test {\mycolorb OEPS} test
+% \stoptext
+
+\unexpanded\def\defineintermediatecolor
+ {\dotripleempty\dodefineintermediatecolor}
+
+\def\dodefineintermediatecolor[#1][#2][#3]% \dotripleempty adds {} inside []
+ {\dododefineintermediatecolor[#1][#2][#3]}
+
+\def\dododefineintermediatecolor[#1][#2,#3,#4][#5]%
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
+ \ctxlua{colors.defineintermediatecolor("#1","#2",
+ \thecolorattribute{#3},\thecolorattribute{#4},
+ \thetransparencyattribute{#3},\thetransparencyattribute{#4},
+ "#5",false,\iffreezecolors true\else false\fi)}% not global
+ \dodefinecolorcommand\setvalue{#1}}
+
+\protect \endinput
diff --git a/tex/context/base/colo-hex.mkii b/tex/context/base/colo-hex.mkii
new file mode 100644
index 000000000..db67f1841
--- /dev/null
+++ b/tex/context/base/colo-hex.mkii
@@ -0,0 +1,125 @@
+%D \module
+%D [ file=colo-hex,
+%D version=2004.06.23,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Hex Colors,
+%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.
+
+\ifdefined \hexcolorprefix
+ \expandafter \endinput
+\fi
+
+\writestatus{loading}{ConTeXt Color Macros / Hexadecimal}
+
+% \edef\testcolor{\string#FFC0C0}
+% \edef\testcolor{\string#55}
+%
+% \setupcolors[state=start]
+%
+% \expanded{\definecolor[thehexcolor][\hexcolorspec\testcolor]}
+%
+% \checkhexcolor[\testcolor]
+%
+% \definecolor[thehexcolor][\testcolor]
+%
+% \starttext
+%
+% test \color[thehexcolor]{rood}
+% test \color[red]{rood}
+% test \color[\testcolor]{rood}
+%
+% \stoptext
+
+\unprotect
+
+% \definecolor[rgbtestcolor] [r=0.87843,g=0.87451,b=0.89020] % RGB(224,223,227)
+% \definecolor[hextestcolor] [h=E0DFE3]
+%
+% \startMPpage
+% path p ; % example by Peter Rolf
+% p := unitsquare xyscaled(5cm,5cm) ;
+% fill (point 0 of p -- point 1 of p -- point 2 of p --cycle) withcolor \MPcolor{rgbtestcolor} ; % bottom right part of the square
+% fill (point 0 of p -- point 3 of p -- point 2 of p --cycle) withcolor \MPcolor{hextestcolor} ; % top left part
+% \stopMPpage
+
+\newdimen\hexcolorfraction \hexcolorfraction=\dimexpr1pt/255\relax
+
+\chardef\hexcolorprefix=`#
+
+\def\hexcolorspec #1{\expandafter\dohexcolorspec #1\empty\empty\empty\empty\relax}
+\def\hexcolorpattern#1{\expandafter\dohexcolorpattern#1\empty\empty\empty\empty\relax}
+
+\ifx\dohexstringtonumber\undefined \def\dohexstringtonumber{"} \fi
+
+\def\hexcolorcomponent#1#2%
+ {\ifnum\dohexstringtonumber#1#2=\zerocount0\else\ifnum\dohexstringtonumber#1#2=\plusone1\else
+ \expandafter\withoutpt\the\dimexpr\dohexstringtonumber#1#2\hexcolorfraction\relax
+ \fi\fi}
+
+\def\dohexcolorspec#1#2#3#4#5#6#7#8\relax
+ {\ifx#4\empty
+ s=\hexcolorcomponent#2#3%
+ \else
+ r=\hexcolorcomponent#2#3,g=\hexcolorcomponent#4#5,b=\hexcolorcomponent#6#7%
+ \fi}
+
+\def\dohexcolorpattern#1#2#3#4#5#6#7#8\relax
+ {0\ifx#4\empty
+ S:\hexcolorcomponent#2#3%
+ \else
+ R:\hexcolorcomponent#2#3:\hexcolorcomponent#4#5:\hexcolorcomponent#6#7%
+ \fi:0:0}
+
+\def\doifhexcolorelse#1%
+ {\expandafter\dodoifhexcolorelse#10\od} % 0 is a dirty trick to catch an empty #1
+
+\def\dodoifhexcolorelse#1#2\od
+ {\ifnum`#1=\hexcolorprefix
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\docheckhexcolor#1%
+ {\doifhexcolorelse{#1}{\doifundefined{#1}{\setxvalue{\??cr#1}{\hexcolorpattern{#1}}}}\donothing}
+
+\def\checkhexcolor[#1]%
+ {\expanded{\docheckhexcolor{#1}}}
+
+\def\colorHpattern{\@EA\hexcolorpattern\@EA{\@EA*\@@cl@@h}} % * == dummy placeholder
+
+\let\dodododefinecolor\dododefinecolor % we will overload this one
+
+\def\dododefinecolor#1#2#3#4[#5][#6]%
+ {\doifhexcolorelse{#6}
+ {\setxvalue{\??cr#5}{\hexcolorpattern{#6}}}
+ {\dodododefinecolor#1#2#3#4[#5][#6]}}
+
+%D For Adam Lindsay and his XeTeX special driver:
+
+% because we intercept the zero condition, the .23pt in 1.23pt will disappear in the
+% ifcase zero part branch
+
+\def\colorhexcomponent#1%
+ {\ifdim#1\points<.005\points
+ 00\else\lchexnumbers{\the\dimexpr255\dimexpr#1\points\relax+.5\points\relax}%
+ \fi}
+
+% the faster one
+
+\newdimen\hex@color@a \hex@color@a=.005pt
+\newdimen\hex@color@b \hex@color@b=.5pt
+\chardef \hex@color@c =255
+
+\def\colorhexcomponent#1%
+ {\ifdim#1\points<\hex@color@a
+ 00\else\lchexnumbers{\the\dimexpr#1\points*\hex@color@c+\hex@color@b\relax}%
+ \fi}
+
+\protect \endinput
diff --git a/tex/context/base/colo-hex.mkiv b/tex/context/base/colo-hex.mkiv
new file mode 100644
index 000000000..f661b2445
--- /dev/null
+++ b/tex/context/base/colo-hex.mkiv
@@ -0,0 +1,28 @@
+%D \module
+%D [ file=colo-hex,
+%D version=2004.06.23,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Hex Colors,
+%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.
+
+%D This is built in.
+
+% \definecolor[rgbtestcolor] [r=0.87843,g=0.87451,b=0.89020] % RGB(224,223,227)
+% \definecolor[hextestcolor] [\letterhash E0DFE3] % or [h=E0DFE3]
+%
+% \startMPpage
+% path p ; % example by Peter Rolf
+% p := unitsquare xyscaled(5cm,5cm) ;
+% fill (point 0 of p -- point 1 of p -- point 2 of p --cycle) withcolor \MPcolor{rgbtestcolor} ; % bottom right part of the square
+% fill (point 0 of p -- point 3 of p -- point 2 of p --cycle) withcolor \MPcolor{hextestcolor} ; % top left part
+% \stopMPpage
+
+\def\checkhexcolor[#1]{\doifcolorelse{#1}\donothing{\definecolor[#1][x=#1]}} % is this ok?
+
+\endinput
diff --git a/tex/context/base/colo-hex.tex b/tex/context/base/colo-hex.tex
new file mode 100644
index 000000000..7d223c131
--- /dev/null
+++ b/tex/context/base/colo-hex.tex
@@ -0,0 +1,3 @@
+% this is just a stub
+
+\loadmarkfile{colo-hex}
diff --git a/tex/context/base/colo-ini.lua b/tex/context/base/colo-ini.lua
new file mode 100644
index 000000000..342d6110d
--- /dev/null
+++ b/tex/context/base/colo-ini.lua
@@ -0,0 +1,480 @@
+if not modules then modules = { } end modules ['colo-ini'] = {
+ version = 1.000,
+ comment = "companion to colo-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type = type
+local concat = table.concat
+local format, gmatch, gsub, lower, match, find = string.format, string.gmatch, string.gsub, string.lower, string.match, string.find
+local texsprint = tex.sprint
+local ctxcatcodes = tex.ctxcatcodes
+
+local trace_define = false trackers.register("colors.define",function(v) trace_define = v end)
+
+local settings_to_hash_strict = aux.settings_to_hash_strict
+
+colors = colors or { }
+transparencies = transparencies or { }
+
+local registrations = backends.registrations
+
+local a_color = attributes.private('color')
+local a_transparency = attributes.private('transparency')
+local a_colorspace = attributes.private('colormodel')
+local a_background = attributes.private('background')
+
+local register_color = colors.register
+local attributes_list = attributes.list
+
+local function definecolor(name, ca, global)
+ if ca and ca > 0 then
+ if global then
+ if trace_define then
+ commands.writestatus("color","define global color '%s' with attribute: %s",name,ca)
+ end
+ context.colordefagc(name,ca)
+ else
+ if trace_define then
+ commands.writestatus("color","define local color '%s' with attribute: %s",name,ca)
+ end
+ context.colordefalc(name,ca)
+ end
+ else
+ if global then
+ context.colordefrgc(name)
+ else
+ context.colordefrlc(name)
+ end
+ end
+end
+
+local function inheritcolor(name, ca, global)
+ if ca and ca ~= "" then
+ if global then
+ if trace_define then
+ commands.writestatus("color","inherit global color '%s' with attribute: %s",name,ca)
+ end
+ context.colordeffgc(name,ca)
+ else
+ if trace_define then
+ commands.writestatus("color","inherit local color '%s' with attribute: %s",name,ca)
+ end
+ context.colordefflc(name,ca)
+ end
+ else
+ if global then
+ context.colordefrgc(name)
+ else
+ context.colordefrlc(name)
+ end
+ end
+end
+
+local function definetransparent(name, ta, global)
+ if ta and ta > 0 then
+ if global then
+ if trace_define then
+ commands.writestatus("color","define global transparency '%s' with attribute: %s",name,ta)
+ end
+ context.colordefagt(name,ta)
+ else
+ if trace_define then
+ commands.writestatus("color","define local transparency '%s' with attribute: %s",name,ta)
+ end
+ context.colordefalt(name,ta)
+ end
+ else
+ if global then
+ context.colordefrgt(name)
+ else
+ context.colordefrlt(name)
+ end
+ end
+end
+
+local function inherittransparent(name, ta, global)
+ if ta and ta ~= "" then
+ if global then
+ if trace_define then
+ commands.writestatus("color","inherit global transparency '%s' with attribute: %s",name,ta)
+ end
+ context.colordeffgt(name,ta)
+ else
+ if trace_define then
+ commands.writestatus("color","inherit local transparency '%s' with attribute: %s",name,ta)
+ end
+ context.colordefflt(name,ta)
+ end
+ else
+ if global then
+ context.colordefrgt(name)
+ else
+ context.colordefrlt(name)
+ end
+ end
+end
+
+local transparent = {
+ none = 0,
+ normal = 1,
+ multiply = 2,
+ screen = 3,
+ overlay = 4,
+ softlight = 5,
+ hardlight = 6,
+ colordodge = 7,
+ colorburn = 8,
+ darken = 9,
+ lighten = 10,
+ difference = 11,
+ exclusion = 12,
+}
+
+-- By coupling we are downward compatible. When we decouple we need to do more tricky
+-- housekeeping (e.g. persist color independent transparencies when color bound ones
+-- are nil.)
+
+colors.couple = true
+
+function colors.definetransparency(name,n)
+ transparent[name] = n
+end
+
+local registered = { }
+
+local function do_registerspotcolor(parent,name,parentnumber,e,f,d,p)
+ if not registered[parentnumber] then
+ local v = colors.values[parentnumber]
+ if v then
+ local kind = colors.default -- else problems with shading etc
+ if kind == 1 then kind = v[1] end
+ if e and e ~= "" then
+ registrations.spotcolorname(parent,e) -- before registration of the color
+ end
+ if kind == 2 then -- name noffractions names p's r g b
+ registrations.grayspotcolor(parent,f,d,p,v[2])
+ elseif kind == 3 then
+ registrations.rgbspotcolor (parent,f,d,p,v[3],v[4],v[5])
+ elseif kind == 4 then
+ registrations.cmykspotcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
+ end
+ end
+ registered[parentnumber] = true
+ end
+end
+
+local function do_registermultitonecolor(parent,name,parentnumber,e,f,d,p) -- same as spot but different template
+ if not registered[parentnumber] then
+ local v = colors.values[parentnumber]
+ if v then
+ local kind = colors.default -- else problems with shading etc
+ if kind == 1 then kind = v[1] end
+ if kind == 2 then
+ registrations.grayindexcolor(parent,f,d,p,v[2])
+ elseif kind == 3 then
+ registrations.rgbindexcolor (parent,f,d,p,v[3],v[4],v[5])
+ elseif kind == 4 then
+ registrations.cmykindexcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
+ end
+ end
+ registered[parentnumber] = true
+ end
+end
+
+function colors.definesimplegray(name,s)
+ return register_color(name,'gray',s) -- we still need to get rid of 'color'
+end
+
+function colors.defineprocesscolor(name,str,global,freeze) -- still inconsistent color vs transparent
+ local x = match(str,"^#(.+)$") -- for old times sake (if we need to feed from xml or so)
+ if x then
+ local r, g, b = match(x .. "000000","(..)(..)(..)") -- watch the 255
+ definecolor(name, register_color(name,'rgb',(tonumber(r,16) or 0)/255,(tonumber(g,16) or 0)/255,(tonumber(b,16) or 0)/255), global)
+ else
+ local settings = settings_to_hash_strict(str)
+ if settings then
+ local r, g, b = settings.r, settings.g, settings.b
+ if r or g or b then
+ definecolor(name, register_color(name,'rgb', tonumber(r) or 0, tonumber(g) or 0, tonumber(b) or 0), global)
+ else
+ local c, m, y, k = settings.c, settings.m, settings.y, settings.k
+ if c or m or y or b then
+ definecolor(name, register_color(name,'cmyk',tonumber(c) or 0, tonumber(m) or 0, tonumber(y) or 0, tonumber(k) or 0), global)
+ else
+ local h, s, v = settings.h, settings.s, settings.v
+ if v then
+ r, g, b = colors.hsvtorgb(tonumber(h) or 0, tonumber(s) or 1, tonumber(v) or 1) -- maybe later native
+ definecolor(name, register_color(name,'rgb',r,g,b), global)
+ else
+ local x = settings.x or h
+ if x then
+ r, g, b = match(x .. "000000","(..)(..)(..)") -- watch the 255
+ definecolor(name, register_color(name,'rgb',(tonumber(r,16) or 0)/255,(tonumber(g,16) or 0)/255,(tonumber(b,16) or 0)/255), global)
+ else
+ definecolor(name, register_color(name,'gray',tonumber(s) or 0), global)
+ end
+ end
+ end
+ end
+ local a, t = settings.a, settings.t
+ if a and t then
+ definetransparent(name, transparencies.register(name,transparent[a] or tonumber(a) or 1,tonumber(t) or 1), global)
+ elseif colors.couple then
+ -- definetransparent(name, transparencies.register(nil, 1, 1), global) -- can be sped up
+ definetransparent(name, 0, global) -- can be sped up
+ end
+ elseif freeze then
+ local ca = attributes_list[a_color] [str]
+ local ta = attributes_list[a_transparency][str]
+ if ca then
+ definecolor(name, ca, global)
+ end
+ if ta then
+ definetransparent(name, ta, global)
+ end
+ else
+ inheritcolor(name, str, global)
+ inherittransparent(name, str, global)
+ -- if global and str ~= "" then -- For Peter Rolf who wants access to the numbers in Lua. (Currently only global is supported.)
+ -- attributes_list[a_color] [name] = attributes_list[a_color] [str] or attributes.unsetvalue -- reset
+ -- attributes_list[a_transparency][name] = attributes_list[a_transparency][str] or attributes.unsetvalue
+ -- end
+ end
+ end
+end
+
+function colors.isblack(ca) -- maybe commands
+ local cv = ca > 0 and colors.value(ca)
+ return (cv and cv[2] == 0) or false
+end
+
+function colors.definespotcolor(name,parent,str,global)
+ if parent == "" or find(parent,"=") then
+ colors.registerspotcolor(name, parent)
+ elseif name ~= parent then
+ local cp = attributes_list[a_color][parent]
+ if cp then
+ local t = settings_to_hash_strict(str)
+ if t then
+ local tp = tonumber(t.p) or 1
+ do_registerspotcolor(parent, name, cp, t.e, 1, "", tp) -- p not really needed, only diagnostics
+ if name and name ~= "" then
+ definecolor(name, register_color(name,'spot', parent, 1, "", tp), true)
+ local ta, tt = t.a, t.t
+ if ta and tt then
+ definetransparent(name, transparencies.register(name,transparent[ta] or tonumber(ta) or 1,tonumber(tt) or 1), global)
+ elseif colors.couple then
+ --~ definetransparent(name, transparencies.register(nil, 1, 1), global) -- can be sped up
+ definetransparent(name, 0, global) -- can be sped up
+ end
+ end
+ end
+ end
+ end
+end
+
+function colors.registerspotcolor(parent, str)
+ local cp = attributes_list[a_color][parent]
+ if cp then
+ local e = ""
+ if str then
+ local t = settings_to_hash_strict(str)
+ e = (t and t.e) or ""
+ end
+ do_registerspotcolor(parent, "dummy", cp, e, 1, "", 1) -- p not really needed, only diagnostics
+ end
+end
+
+function colors.definemultitonecolor(name,multispec,colorspec,selfspec)
+ local dd, pp, nn = { }, { }, { }
+ for k,v in gmatch(multispec,"(%a+)=([^%,]*)") do
+ dd[#dd+1] = k
+ pp[#pp+1] = v
+ nn[#nn+1] = k
+ nn[#nn+1] = format("%1.3g",tonumber(v) or 0) -- 0 can't happen
+ end
+--~ v = tonumber(v) * p
+ local nof = #dd
+ if nof > 0 then
+ dd, pp, nn = concat(dd,','), concat(pp,','), concat(nn,'_')
+ local parent = gsub(lower(nn),"[^%d%a%.]+","_")
+ colors.defineprocesscolor(parent,colorspec..","..selfspec,true,true)
+ local cp = attributes_list[a_color][parent]
+ if cp then
+ do_registerspotcolor(parent, name, cp, "", nof, dd, pp)
+ do_registermultitonecolor(parent, name, cp, "", nof, dd, pp)
+ definecolor(name, register_color(name, 'spot', parent, nof, dd, pp), true)
+ local t = settings_to_hash_strict(selfspec)
+ if t and t.a and t.t then
+ definetransparent(name, transparencies.register(name,transparent[t.a] or tonumber(t.a) or 1,tonumber(t.t) or 1), global)
+ elseif colors.couple then
+ -- definetransparent(name, transparencies.register(nil, 1, 1), global) -- can be sped up
+ definetransparent(name, 0, global) -- can be sped up
+ end
+ end
+ end
+end
+
+function colors.mp(model,ca,ta,default)
+ local cv = colors.value(ca) -- faster when direct colors.values[ca]
+ if cv then
+ local tv = transparencies.value(ta)
+ if model == 1 then
+ model = cv[1]
+ end
+ if tv then
+ if model == 2 then
+ return format("transparent(%s,%s,(%s,%s,%s))",tv[1],tv[2],cv[3],cv[4],cv[5])
+ elseif model == 3 then
+ return format("transparent(%s,%s,(%s,%s,%s))",tv[1],tv[2],cv[3],cv[4],cv[5])
+ elseif model == 4 then
+ return format("transparent(%s,%s,cmyk(%s,%s,%s,%s))",tv[1],tv[2],cv[6],cv[7],cv[8],cv[9])
+ else
+ return format("transparent(%s,%s,multitonecolor(\"%s\",%s,\"%s\",\"%s\"))",tv[1],tv[2],cv[10],cv[11],cv[12],cv[13])
+ end
+ else
+ if model == 2 then
+ return format("(%s,%s,%s)",cv[3],cv[4],cv[5])
+ elseif model == 3 then
+ return format("(%s,%s,%s)",cv[3],cv[4],cv[5])
+ elseif model == 4 then
+ return format("cmyk(%s,%s,%s,%s)",cv[6],cv[7],cv[8],cv[9])
+ else
+ return format("multitonecolor(\"%s\",%s,\"%s\",\"%s\")",cv[10],cv[11],cv[12],cv[13])
+ end
+ end
+ else
+ default = default or 0 -- rgb !
+ return format("(%s,%s,%s)",default,default,default)
+ end
+end
+
+function colors.formatcolor(ca,separator)
+ local cv = colors.value(ca)
+ if cv then
+ local c, f, t, model = { }, 13, 13, cv[1]
+ if model == 2 then
+ f, t = 2, 2
+ elseif model == 3 then
+ f, t = 3, 5
+ elseif model == 4 then
+ f, t = 6, 9
+ end
+ for i=f,t do
+ c[#c+1] = format("%0.3f",cv[i])
+ end
+ return concat(c,separator)
+ else
+ return format("%0.3f",0)
+ end
+end
+
+function colors.formatgray(ca,separator)
+ local cv = colors.value(ca)
+ return format("%0.3f",(cv and cv[2]) or 0)
+end
+
+function colors.colorcomponents(ca) -- return list
+ local cv = colors.value(ca)
+ if cv then
+ local model = cv[1]
+ if model == 2 then
+ return format("s=%1.3f",cv[2])
+ elseif model == 3 then
+ return format("r=%1.3f g=%1.3f b=%1.3f",cv[3],cv[4],cv[5])
+ elseif model == 4 then
+ return format("c=%1.3f m=%1.3f y=%1.3f k=%1.3f",cv[6],cv[7],cv[8],cv[9])
+ elseif type(cv[13]) == "string" then
+ return format("p=%s",cv[13])
+ else
+ return format("p=%1.3f",cv[13])
+ end
+ else
+ return ""
+ end
+end
+
+function colors.transparencycomponents(ta)
+ local tv = transparencies.value(ta)
+ if tv then
+ return format("a=%1.3f t=%1.3f",tv[1],tv[2])
+ else
+ return ""
+ end
+end
+
+function colors.spotcolorname(ca,default)
+ local cv, v = colors.value(ca), "unknown"
+ if cv and cv[1] == 5 then
+ v = cv[10]
+ end
+ return tostring(v)
+end
+
+function colors.spotcolorparent(ca,default)
+ local cv, v = colors.value(ca), "unknown"
+ if cv and cv[1] == 5 then
+ v = cv[12]
+ if v == "" then
+ v = cv[10]
+ end
+ end
+ return tostring(v)
+end
+
+function colors.spotcolorvalue(ca,default)
+ local cv, v = colors.value(ca), 0
+ if cv and cv[1] == 5 then
+ v = cv[13]
+ end
+ return tostring(v)
+end
+
+-- experiment (a bit of a hack, as we need to get the attribute number)
+
+local min = math.min
+
+-- a[b,c] -> b+a*(c-b)
+
+local function f(one,two,i,fraction)
+ local o, t = one[i], two[i]
+ local otf = o + fraction * (t - o)
+ if otf > 1 then
+ otf = 1
+ end
+ return otf
+end
+
+function colors.defineintermediatecolor(name,fraction,c_one,c_two,a_one,a_two,specs,global,freeze)
+ fraction = tonumber(fraction) or 1
+ local one, two = colors.value(c_one), colors.value(c_two)
+ if one and two then
+ local csone, cstwo = one[1], two[1]
+ if csone == cstwo then
+ -- actually we can set all 8 values at once here but this is cleaner as we avoid
+ -- problems with weighted gray conversions and work with original values
+ local ca
+ if csone == 2 then
+ ca = register_color(name,'gray',f(one,two,2,fraction))
+ elseif csone == 3 then
+ ca = register_color(name,'rgb',f(one,two,3,fraction),f(one,two,4,fraction),f(one,two,5,fraction))
+ elseif csone == 4 then
+ ca = register_color(name,'cmyk',f(one,two,6,fraction),f(one,two,7,fraction),f(one,two,8,fraction),f(one,two,9,fraction))
+ else
+ ca = register_color(name,'gray',f(one,two,2,fraction))
+ end
+ definecolor(name,ca,global,freeze)
+ end
+ end
+ local one, two = transparencies.value(a_one), transparencies.value(a_two)
+ local t = settings_to_hash_strict(specs)
+ local ta = tonumber((t and t.a) or (one and one[1]) or (two and two[1]))
+ local tt = tonumber((t and t.t) or (one and two and f(one,two,2,fraction)))
+ if ta and tt then
+--~ print(ta,tt)
+ definetransparent(name,transparencies.register(name,ta,tt),global)
+ end
+end
diff --git a/tex/context/base/colo-ini.mkii b/tex/context/base/colo-ini.mkii
new file mode 100644
index 000000000..2d2a7bdaa
--- /dev/null
+++ b/tex/context/base/colo-ini.mkii
@@ -0,0 +1,2776 @@
+%D \module
+%D [ file=colo-ini,
+%D version=2007.08.08,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Initialization,
+%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.
+
+%D We need to clean this up further but first we hav eto make sure that mkiv
+%D code works ok.
+
+\writestatus{loading}{ConTeXt Color Macros / Initialization}
+
+%D This module implements color. Since \MKII\ and \MKIV\ use a completely
+%D different approach, this module only implements a few generic mechanisms.
+
+\unprotect
+
+\chardef\colorversion=1 % temp, needed for tracing purposes, mkiv transition
+
+%D We use a couple of local registers. That way we don't have
+%D to group when converting colors. By the way, this is not
+%D really faster. We can sqeeze half a second runtime for 50K
+%D switches on a 1G machine, but the macros will become rather
+%D ugly then. To mention one such improvement: no colon
+%D after the key character (.25 sec).
+
+\newdimen\colordimen
+\newcount\colorcount
+
+%D When typesetting for paper, we prefer using the \cap{CMYK}
+%D color space, but for on||screen viewing we prefer \cap{RGB}
+%D (the previous implementation supported only this scheme).
+%D Independant of such specifications, we support some automatic
+%D conversions:
+%D
+%D \startitemize[packed]
+%D \item convert all colors to \cap{RGB}
+%D \item convert all colors to \cap{CMYK}
+%D \item convert all colors to gray scales
+%D \stopitemize
+%D
+%D We also support optimization of colors to gray scales.
+%D
+%D \startitemize[continue]
+%D \item reduce gray colors to gray scales
+%D \item reduce \cap{CMY} components to \cap{K}
+%D \stopitemize
+%D
+%D These options are communicated by means of:
+
+\newif\ifRGBsupported
+\newif\ifCMYKsupported
+\newif\ifSPOTsupported
+\newif\ifpreferGRAY
+\newif\ifGRAYprefered
+\newif\ifreduceCMYK
+\newif\ifconverttoGRAY
+\newif\ifweightGRAY \weightGRAYtrue
+
+\newif\ifconvertMPcolors
+\newif\ifreduceMPcolors
+\newif\ifforcegrayMPcolors
+
+%D The last boolean controls reduction of \cap{CMYK} to
+%D \cap{CMY} colors. When set to true, the black component
+%D is added to the other ones.
+%D
+%D Prefering gray is not the same as converting to gray.
+%D Conversion treats each color components in a different way,
+%D while prefering is just a reduction and thus a
+%D space||saving option.
+
+\newif\iffreezecolors \freezecolorsfalse
+\newif\ifincolor % true if colors enabled
+\newif\iflocalcolor
+
+\let\colorlist \empty
+\let\currentspotcolor \empty
+\let\allspotcolors \empty
+\let\usedspotcolors \empty
+\let\usedcolorchannels\empty
+\let\currentpalet \empty
+
+%D \macros
+%D {definecolor,defineglobalcolor,definenamedcolor,definespotcolor,definemultitonecolor}
+%D
+%D \startbuffer
+%D \definecolor [blue] [c=1,m=.38,y=0,k=.64] % pantone pms 2965 uncoated m
+%D \definecolor [yellow] [c=0,m=.28,y=1,k=.06] % pantone pms 124 uncoated m
+%D
+%D \definespotcolor [blue-100] [blue] [p=1]
+%D \definespotcolor [yellow-100] [yellow] [p=1]
+%D
+%D \definemultitonecolor [pdftoolscolor] [blue=.12,yellow=.28] [c=.1,m=.1,y=.3,k=.1]
+%D
+%D \useexternalfigure[demofig][mill.png][object=no]
+%D
+%D \startcombination[4*1]
+%D {\externalfigure[demofig]} {no color}
+%D {\externalfigure[demofig][color=pdftoolscolor]} {indexed duotone}
+%D {\externalfigure[demofig][color=blue-100]} {spot color}
+%D {\externalfigure[demofig][color=yellow-100]} {spot color}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \getbuffer \typebuffer
+
+\def\definecolor {\dodoubleargument\dodefinecolor}
+\def\defineglobalcolor {\dodoubleargument\dodefineglobalcolor}
+\def\definenamedcolor {\dodoubleargument\dodefinenamedcolor}
+\def\definespotcolor {\dotripleargument\dodefinespotcolor}
+\def\definemultitonecolor{\doquadrupleempty\dodefinemultitonecolor}
+
+% check: registerusedspotcolors
+% check: registerusedcolorchannels
+
+%D \macros
+%D {doifcolorelse, doifcolor}
+%D
+%D Switching to a color is done by means of the following
+%D command. Later on we will explain the use of palets. We
+%D define ourselves a color conditional first.
+
+\ifx\doifcolorelse\undefined
+ \let\doifcolorelse\secondoftwoarguments
+ \let\doifcolor \gobbleoneargument
+\fi
+
+%D \macros
+%D {localstartcolor,localstopcolor}
+%D
+%D Simple color support, that is without nesting, is provided
+%D by:
+
+\ifx\localstartcolor\undefined
+ \let\localstartcolor\undefined
+ \let\localstopcolor \undefined
+\fi
+
+%D \macros
+%D {faststartcolor,faststopcolor}
+%D
+%D No checking for arguments and such:
+
+\ifx\faststartcolor\undefined
+ \def\faststartcolor[#1]{}
+ \def\faststopcolor {}
+\fi
+
+%D These local ones may go away in future versions.
+
+%D \macros
+%D {startcolor,stopcolor}
+%D
+%D The more save method, the one that saves the current color
+%D state and returns to this state afterward, is activated by:
+%D
+%D \showsetup{startcolor}
+
+\ifx\startcolor\undefined
+ \let\startcolor\undefined
+ \let\stopcolor \undefined
+\fi
+
+%D \macros
+%D {startcurrentcolor,stopcurrentcolor}
+
+\def\startcurrentcolor{\startcolor[\outercolorname]}
+\def\stopcurrentcolor {\stopcolor}
+
+%D \macros
+%D {color,graycolor}
+%D
+%D This leaves the simple color command:
+%D
+%D \showsetup{color}
+%D \showsetup{graycolor}
+
+\ifx\color\undefined
+ \def\color [#1]{}
+ \def\graycolor[#1]{}
+ \def\gray {\graycolor}
+\fi
+
+%D \macros
+%D {localstartraster,localstopraster,
+%D startraster,stopraster,raster}
+%D
+%D The previous conversions are not linear and treat each color
+%D component according to human perception curves. Pure gray
+%D (we call them rasters) has equal color components. In
+%D \CONTEXT\ rasters are only used as backgrounds and these
+%D don't cross page boundaries in the way color does. Therefore
+%D we don't need stacks and marks. Just to be compatible with
+%D color support we offer both 'global' and 'local' commands.
+
+\ifx\startraster\undefined
+ \def\startraster [#1]{}
+ \def\stopraster {}
+ \def\raster [#1]{}
+ \def\localstartraster[#1]{}
+ \def\localstopraster {}
+\fi
+
+%D \macros
+%D {colorvalue, grayvalue}
+%D
+%D We can typeset the color components using \type{\colorvalue} and
+%D \type{\grayvalue}. The commands:
+%D
+%D \startbuffer
+%D color value of SomeKindOfRed: \colorvalue{SomeKindOfRed} \crlf
+%D gray value of SomeKindOfRed: \grayvalue{SomeKindOfRed}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D show us:
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+
+\def\colorformatseparator{ }
+
+\ifx\colorvalue\undefined
+ \let\colorvalue\gobbleoneargument
+ \let\grayvalue \gobbleoneargument
+\fi
+
+% check: \currentcolorname
+% check: \outercolorname
+
+%D \macros
+%D {setupcolor}
+%D
+%D Color definitions can be grouped in files with the name:
+%D
+%D \starttyping
+%D \f!colorprefix-identifier.tex
+%D \stoptyping
+%D
+%D where \type{\f!colorprefix} is \unprotect {\tttf \f!colorprefix}.
+%D Loading such a file is done by \protect
+%D
+%D \showsetup{setupcolor}
+%D
+%D Some default colors are specified in \type{colo-rgb.tex},
+%D which is loaded into the format by:
+%D
+%D \starttyping
+%D \setupcolor[rgb]
+%D \stoptyping
+
+\let\colorstyle\empty
+
+\def\setupcolor
+ {\dosingleargument\dosetupcolor}
+
+\def\dosetupcolor[#1]%
+ {\doifnot{#1}\colorstyle
+ {\def\colorstyle{#1}%
+ \processcommalist[#1]\dodosetupcolor}}
+
+\def\dodosetupcolor#1%
+ {\makeshortfilename[\truefilename{\f!colorprefix#1}]%
+ \startreadingfile
+ \readsysfile\shortfilename
+ {\showmessage\m!colors4\colorstyle}
+ {\showmessage\m!colors5\colorstyle}%
+ \stopreadingfile}
+
+\let\usecolors\setupcolor
+
+% check: \chardef\currentcolorchannel=0
+% check: \startcolormode
+% check: \newif\iffilterspotcolor \filterspotcolorfalse
+% check: \newif\ifdoingspotcolor \doingspotcolorfalse
+% check: \registercolorchannel
+
+%D \macros
+%D {definetransparency}
+%D
+%D This command numbers to names:
+
+\def\definetransparency
+ {\dodoubleargument\dodefinetransparency}
+
+\def\setupcolors
+ {\dosingleargument\dosetupcolors}
+
+\def\resetcolorsplitting
+ {\chardef\currentcolorchannel\zerocount
+ \let\currentspotcolor\empty
+ \filterspotcolorfalse}
+
+\def\colorsplitsuffix{\ifcase\currentcolorchannel\else-\@@clsplit\fi}
+\def\colorsplitprefix{\ifcase\currentcolorchannel\else\@@clsplit-\fi}
+
+\def\setcolorsplitting
+ {\resetsystemmode{\v!color\colorsplitsuffix}%
+ \resetcolorsplitting
+ \processaction
+ [\@@clsplit]
+ [ c=>\chardef\currentcolorchannel1,%
+ m=>\chardef\currentcolorchannel2,%
+ y=>\chardef\currentcolorchannel3,%
+ k=>\chardef\currentcolorchannel4,%
+ r=>\chardef\currentcolorchannel5,%
+ g=>\chardef\currentcolorchannel6,%
+ b=>\chardef\currentcolorchannel7,%
+ s=>\chardef\currentcolorchannel8,%
+ \v!no=>,% \currentcolorchannel0,% all colors
+ \s!default=>,% \currentcolorchannel0,% all colors
+ \s!unknown=>\filterspotcolortrue
+ \edef\currentspotcolor{\commalistelement}]%
+ \setsystemmode{\v!color\colorsplitsuffix}%
+ \iffilterspotcolor \let\@@clrgb\v!no \fi}
+
+\ifx\dosetupcolormodel\undefined
+ \let\dosetupcolormodel\relax
+\fi
+
+\def\dosetupcolors[#1]% some no longer make sense in MkIV
+ {\getparameters[\??cl][#1]%
+ \doifelse\@@clspot\v!yes
+ \SPOTsupportedtrue
+ \SPOTsupportedfalse
+ \doifelsenothing\@@clsplit
+ \resetcolorsplitting
+ \setcolorsplitting
+ \doifelse\@@clreduction\v!yes
+ \reduceCMYKtrue
+ \reduceCMYKfalse
+ \doifelse\@@clexpansion\v!yes
+ \freezecolorstrue
+ \freezecolorsfalse
+ \doifelse\@@clcriterium\v!all
+ \hidesplitcolortrue
+ \hidesplitcolorfalse
+ \doifelse\@@clrgb\v!no
+ {\ifRGBsupported \ifproductionrun\showmessage\m!colors {9}\v!rgb \fi\RGBsupportedfalse \fi}
+ {\ifRGBsupported \else\ifproductionrun\showmessage\m!colors{10}\v!rgb \fi\RGBsupportedtrue \fi}%
+ \doifelse\@@clcmyk\v!no
+ {\ifCMYKsupported \ifproductionrun\showmessage\m!colors {9}\v!cmyk \fi\CMYKsupportedfalse\fi}
+ {\ifCMYKsupported\else\ifproductionrun\showmessage\m!colors{10}\v!cmyk \fi\CMYKsupportedtrue \fi}%
+ \doifelse\@@clmpcmyk\v!no
+ {\ifMPcmykcolors \ifproductionrun\showmessage\m!colors {9}{\v!mp\v!cmyk}\fi\MPcmykcolorsfalse \fi}
+ {\ifMPcmykcolors \else\ifproductionrun\showmessage\m!colors{10}{\v!mp\v!cmyk}\fi\MPcmykcolorstrue \fi}%
+ \doifelse\@@clmpspot\v!no
+ {\ifMPspotcolors \ifproductionrun\showmessage\m!colors {9}{\v!mp\v!spot}\fi\MPspotcolorsfalse \fi}
+ {\ifMPspotcolors \else\ifproductionrun\showmessage\m!colors{10}{\v!mp\v!spot}\fi\MPspotcolorstrue \fi}%
+ \preferGRAYfalse
+ \processaction
+ [\@@clconversion]
+ [ \v!yes=>\preferGRAYtrue,
+ \v!always=>\preferGRAYtrue\RGBsupportedfalse\CMYKsupportedfalse]%
+ \ifRGBsupported
+ \converttoGRAYfalse
+ \forcegrayMPcolorsfalse
+ \else\ifCMYKsupported
+ \converttoGRAYfalse
+ \forcegrayMPcolorsfalse
+ \convertMPcolorstrue
+ \ifreduceCMYK
+ \reduceMPcolorstrue
+ \fi
+ \else
+ \ifconverttoGRAY\else\showmessage\m!colors{11}\empty\fi
+ \converttoGRAYtrue
+ \forcegrayMPcolorstrue
+ \convertMPcolorsfalse
+ \reduceMPcolorsfalse
+ \fi\fi
+ \processaction
+ [\@@clstate]
+ [ \v!global=>\ifincolor\else\showmessage\m!colors1\colorstyle\fi
+ \incolortrue\localcolorfalse,
+ \v!local=>\ifincolor\else\showmessage\m!colors2\colorstyle\fi
+ \incolortrue\localcolortrue,
+ \v!start=>\ifincolor\else\showmessage\m!colors1\colorstyle\fi
+ \incolortrue\localcolorfalse
+ \let\@@clstate\v!global,
+ \v!stop=>\incolorfalse\localcolorfalse
+ \forcegrayMPcolorstrue]%
+ \dosetupcolormodel
+ \initializemaintextcolor}
+
+%D \macros
+%D {startregistercolor,stopregistercolor,permitcolormode}
+%D
+%D If you only want to register a color, the switch \type
+%D {\ifpermitcolormode} can be used. That way the nested
+%D colors know where to go back to.
+
+\ifx\startregistercolor\undefined
+ \def\startregistercolor[#1]{}
+ \def\stopregistercolor {}
+\fi
+
+%D We use these macros for implementing text colors
+%D (actually, the first application was in foreground
+%D colors).
+%D
+%D \starttyping
+%D \starttextcolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stoptextcolor
+%D \stoptyping
+%D
+%D This is more efficient than the alternative:
+%D
+%D \starttyping
+%D \setupbackgrounds[text][foregroundcolor=red]
+%D \startregistercolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stopregistercolor
+%D \stoptyping
+
+\def\maintextcolor {}
+\def\defaulttextcolor {black}
+\def\@@themaintextcolor{themaintextcolor}
+
+\ifx\initializemaintextcolor\undefined
+ \def\starttextcolor [#1]{}
+ \def\stoptextcolor {}
+ \def\initializemaintextcolor {}
+\fi
+
+\ifx\restoretextcolor\undefined % to be redone
+ \let\restoretextcolor \firstofoneargument
+ \let\localstarttextcolor\relax
+ \let\localstoptextcolor \relax
+\fi
+
+%D In this documentation we will not go into too much details
+%D on palets. Curious users can find more information on this
+%D topic in \from[use of color].
+%D
+%D At the moment we implemented color in \CONTEXT\ color
+%D printing was not yet on the desktop. In spite of this lack our
+%D graphics designer made colorfull illustrations. When printed
+%D on a black and white printer, distinctive colors can come
+%D out equally gray. We therefore decided to use only colors
+%D that were distinctive in colors as well as in black and
+%D white print.
+%D
+%D Although none of the graphic packages we used supported
+%D logical colors and global color redefition, we build this
+%D support into \CONTEXT. This enabled us to experiment and
+%D also prepared us for the future.
+
+%D \macros
+%D {definepalet}
+%D
+%D Colors are grouped in palets. The colors in such a palet can
+%D have colorful names, but best is to use names that specify
+%D their use, like {\em important} or {\em danger}. As a sort
+%D of example \CONTEXT\ has some palets predefined,
+%D like:\footnote{At the time I wrote the palet support, I was
+%D reading 'A hort history of time' of S.~Hawkins, so that's
+%D why we stuck to quarks.}
+%D
+%D \starttyping
+%D \definepalet
+%D [alfa]
+%D [ top=rood:7,
+%D bottom=groen:6,
+%D up=blauw:5,
+%D down=cyaan:4,
+%D strange=magenta:3,
+%D charm=geel:2]
+%D \stoptyping
+%D
+%D It's formal definition is:
+%D
+%D \showsetup{definepalet}
+%D
+%D Visualized, such a palet looks like:
+%D
+%D \startbuffer[palet]
+%D \showpalet [alfa] [horizontal,name,number,value]
+%D \stopbuffer
+%D
+%D \startlinecorrection
+%D \getbuffer[palet]
+%D \stoplinecorrection
+%D
+%D This bar shows both the color and gray alternatives of the
+%D palet components (not visible in black and white print).
+%D
+%D When needed, one can copy a palet by saying:
+%D
+%D \starttyping
+%D \definepalet [TEXcolorpretty] [colorpretty]
+%D \stoptyping
+%D
+%D This saves us some typing in for instance the modules that
+%D deal with pretty verbatim typesetting.
+
+\def\definepalet
+ {\dodoubleargument\dodefinepalet}
+
+\def\dodefinepalet[#1][#2]%
+ {\doifassignmentelse{#2}
+ {%\showmessage\m!colors6{#1}%
+ \letvalue{\??pa#1}\empty
+ \setevalue{\??pa\??pa#1}{#2}%
+ \def\dodododefinepalet[##1=##2]%
+ {\doifvaluesomething{\??pa#1}
+ {\setevalue{\??pa#1}{\csname\??pa#1\endcsname,}}%
+ \setevalue{\??pa#1}{\csname\??pa#1\endcsname##1}%
+ \dodefinepaletcolor{#1}{##1}{##2}}%
+ \def\dododefinepalet##1%
+ {\dodododefinepalet[##1]}%
+ \processcommalist[#2]\dododefinepalet}
+ {\doifdefined{\??pa#2}
+ {\expanded{\dodefinepalet[#1][\csname\??pa\??pa#2\endcsname]}}}}
+
+\ifx\dodefinepaletcolor\undefined
+ \let\dodefinepaletcolor\gobblethreearguments
+\fi
+
+\let\paletsize\!!zerocount
+
+\def\getpaletsize[#1]%
+ {\getcommacommandsize[\csname\??pa\??pa#1\endcsname]%
+ \edef\paletsize{\number\commalistsize}}
+
+%D Instead of refering to colors, one can also directly specify
+%D a color:
+%D
+%D \starttyping
+%D \definepalet[test][xx=green]
+%D \definepalet[test][xx={y=.4}]
+%D \stoptyping
+
+%D \macros
+%D {setuppalet}
+%D
+%D Colors are taken from the current palet, if defined.
+%D Setting the current palet is done by:
+%D
+%D \showsetup{setuppalet}
+
+\let\currentpalet\empty
+
+\def\setuppalet
+ {\dosingleempty\dosetuppalet}
+
+\def\dosetuppalet[#1]%
+ {\edef\currentpalet{#1}%
+ \ifx\currentpalet\empty
+ % seems to be a reset
+ \else\ifcsname\??pa\currentpalet\endcsname
+ \edef\currentpalet{#1:}%
+ \else
+ \showmessage\m!colors7\currentpalet
+ \let\currentpalet\empty
+ \fi\fi}
+
+%D \macros
+%D {showpalet}
+%D
+%D The previous visualization was typeset with:
+%D
+%D \typebuffer[palet]
+%D
+%D This commands is defined as:
+%D
+%D \showsetup{showpalet}
+
+\fetchruntimecommand \showpalet {\f!colorprefix\s!run}
+
+%D \macros
+%D {showcolorcomponents}
+%D
+%D \starttyping
+%D \showcolorcomponents[color-1,color-2]
+%D \stoptyping
+
+\fetchruntimecommand \showcolorcomponents {\f!colorprefix\s!run}
+
+%D \macros
+%D {definecolorgroup}
+%D
+%D The naming of the colors in this palet suggests some
+%D ordening, which in turn is suported by color grouping.
+%D
+%D \starttyping
+%D \definecolorgroup
+%D [red]
+%D [1.00:0.90:0.90,
+%D 1.00:0.80:0.80,
+%D 1.00:0.70:0.70,
+%D 1.00:0.55:0.55,
+%D 1.00:0.40:0.40,
+%D 1.00:0.25:0.25,
+%D 1.00:0.15:0.15,
+%D 0.90:0.00:0.00]
+%D \stoptyping
+%D
+%D In such a color group colors are numbered from~$1$ to~$n$.
+%D
+%D \showsetup{definecolorgroup}
+%D
+%D This kind of specification is not only more compact than
+%D defining each color separate, it also loads faster and takes
+%D less bytes.
+
+\def\definecolorgroup
+ {\dotripleempty\dodefinecolorgroup}
+
+\def\dododefinecolorgroupgray [#1][#2:#3]{\definecolor [#1:\the\colorcount][s=#2]}
+\def\dododefinecolorgrouprgb [#1][#2:#3:#4:#5]{\definecolor [#1:\the\colorcount][r=#2,g=#3,b=#4]}
+\def\dododefinecolorgroupcmyk[#1][#2:#3:#4:#5:#6]{\definecolor [#1:\the\colorcount][c=#2,m=#3=,y=#4,k=#5]}
+\def\dododefinecolorgroupspot [#1][#2:#3:#4]{\definespotcolor[#1:\the\colorcount][#2][p=#3]}
+
+\def\dododefinecolorgroup#1#2%
+ {\advance\colorcount\plusone
+ \getvalue{dododefinecolorgroup\currentcolorspace}[#1][#2:0:0:0:0]}
+
+\def\dodefinecolorgroup[#1][#2][#3]% obsolete, just use palets
+ {\ifthirdargument
+ \doifelsenothing{#2}{\let\currentcolorspace\v!rgb}{\def\currentcolorspace{#2}}%
+ \colorcount\zerocount
+ \processcommalist[#3]{\dododefinecolorgroup{#1}}%
+ \else
+ \doifinstringelse{:}{#2}
+ {\definecolorgroup[#1][\v!rgb][#2]}
+ {\doloop
+ {\doifdefinedelse{\??cr#2:\recurselevel}
+ {\setevalue{\??cr#1:\recurselevel}{\csname\??cr#2:\recurselevel\endcsname}}
+ {\exitloop}}}%
+ \fi}
+
+%D \macros
+%D {showcolorgroup}
+%D
+%D We can show the group by:
+%D
+%D \startbuffer
+%D \showcolorgroup [blue] [horizontal,name,number,value]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or in color:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D which uses:
+%D
+%D \showsetup{showcolorgroup}
+
+\fetchruntimecommand \showcolorgroup {\f!colorprefix\s!run}
+
+%D There are ten predefined color groups, like
+%D \color[green]{\em groen}, \color[red]{\em rood},
+%D \color[blue]{\em blauw}, \color[cyan]{\em cyaan},
+%D \color[magenta]{\em magenta} and \color[yellow]{\em geel}.
+%D
+%D \startlinecorrection
+%D \hbox to \hsize
+%D {\hss
+%D \showcolorgroup [red] [vertical,name,number]\hss
+%D \showcolorgroup [green] [vertical,name]\hss
+%D \showcolorgroup [blue] [vertical,name]\hss
+%D \showcolorgroup [cyan] [vertical,name]\hss
+%D \showcolorgroup [magenta][vertical,name]\hss
+%D \showcolorgroup [yellow] [vertical,name]\hss}
+%D \stoplinecorrection
+%D
+%D These groups are used to define palets {\em alfa} upto {\em
+%D zeta}. As long as we don't use colors from the same row, we
+%D get ourselves distinctive palets. By activating such a palet
+%D one gains access to its members {\em top} to {\em charm} (of
+%D course one should use more suitable names than these).
+%D
+%D \startlinecorrection
+%D \hbox to \hsize
+%D {\showpalet [alfa] [vertical,name,number]\hss
+%D \showpalet [beta] [vertical,name]\hss
+%D \showpalet [gamma] [vertical,name]\hss
+%D \showpalet [delta] [vertical,name]\hss
+%D \showpalet [epsilon] [vertical,name]\hss
+%D \showpalet [zeta] [vertical,name]}
+%D \stoplinecorrection
+%D
+%D By using the keyword \type {value} the individual color
+%D components are shown too. When printed in color, these
+%D showcases show both the colors and the gray value.
+
+%D \macros
+%D {comparepalet}
+%D
+%D There are some more testing macros available:
+%D
+%D \startbuffer
+%D \comparepalet [alfa]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows the palet colors against a background:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D The formal definition is:
+%D
+%D \showsetup{comparepalet}
+
+\fetchruntimecommand \comparepalet {\f!colorprefix\s!run}
+
+%D \macros
+%D {comparecolorgroup}
+%D
+%D The similar command:
+%D
+%D \startbuffer
+%D \comparecolorgroup [blue]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows color groups:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D this commands are defined as:
+%D
+%D \showsetup{comparecolorgroup}
+
+\fetchruntimecommand \comparecolorgroup {\f!colorprefix\s!run}
+
+%D \macros
+%D {showcolor}
+%D
+%D But let's not forget that we also have the more traditional
+%D non||related colors. These show up after:
+%D
+%D \starttyping
+%D \showcolor [name]
+%D \stoptyping
+%D
+%D Where \type{name} for instance can be \type{rgb}.
+%D
+%D \showsetup{showcolor}
+
+\fetchruntimecommand \showcolor {\f!colorprefix\s!run}
+
+%D It would make sense to put the following code in \type
+%D {colo-mps}, but it it rather low level.
+
+%D \macros
+%D {negatecolorcomponent,negatedcolorcomponent}
+%D
+%D These speak for themselves. See \type {colo-ext} for usage.
+
+\def\negatecolorcomponent#1% #1 = \macro
+ {\scratchdimen\onepoint\advance\scratchdimen-#1\onepoint
+ \ifdim\scratchdimen<\zeropoint\scratchdimen\zeropoint\fi
+ \edef#1{\withoutpt\the\scratchdimen}}
+
+\let\negatedcolorcomponent\firstofoneargument
+
+\def\negatedcolorcomponent#1%
+ {\ifdim\dimexpr\onepoint-#1\onepoint\relax<\zeropoint
+ \!!zerocount
+ \else
+ \expandafter\withoutpt\the\dimexpr\onepoint-#1\onepoint\relax
+ \fi}
+
+\def\negatecolorcomponent#1% #1 = \macro
+ {\edef#1{\negatedcolorcomponent{#1}}}
+
+%D \macros
+%D {ifMPgraphics, ifMPcmykcolors, MPcolor}
+%D
+%D A very special macro is \type{\MPcolor}. This one can be
+%D used to pass a \CONTEXT\ color to \METAPOST.
+%D
+%D \starttyping
+%D \MPcolor{my own red}
+%D \stoptyping
+%D
+%D This macro returns a \METAPOST\ triplet \type{(R,G,B)}.
+%D Unless \CMYK\ color support is turned on with \type
+%D {MPcmyk}, only \cap{RGB} colors and gray scales are
+%D supported.
+
+\newif\ifMPcmykcolors % \MPcmykcolorsfalse
+\newif\ifMPspotcolors % \MPspotcolorsfalse
+
+\ifx\MPcolor\undefined
+ \def\MPcolor#1{(0,0,0)}
+\fi
+
+%D \macros
+%D {PDFcolor,FDFcolor}
+%D
+%D Similar alternatives are avaliable for \PDF:
+
+%D For the moment we keep the next downward compatibility
+%D switch, i.e.\ expanded colors. However, predefined colors
+%D and palets are no longer expanded (which is what I wanted
+%D in the first place).
+%D
+%D Well, in case we want to do color separation and use CMYK
+%D colors only, this is dangerous since unwanted remapping may
+%D take place. Especially when we redefine already defined
+%D colors in another color space (e.g. darkgreen is
+%D predefined in RGB color space, so a redefinition in CMYK
+%D coordinates before RGB mode is disabled, would give
+%D unexpected results due to the already frozen color spec.)
+%D
+%D So, from now on, colors are not frozen any more!
+
+\chardef\currentcolorchannel=0
+
+\newif\iffilterspotcolor \filterspotcolorfalse
+\newif\ifdoingspotcolor \doingspotcolorfalse
+
+\def\registercolorchannel#1%
+ {\ifdoingspotcolor \else
+ \global\expandafter\chardef\csname\??cs#1\endcsname\zerocount
+ \fi}
+
+\newif\ifhidesplitcolor \hidesplitcolortrue
+
+%D The next macro is for instance used in figure splitting:
+
+\def\doifseparatingcolorselse
+ {\iffilterspotcolor
+ \@EA\firstoftwoarguments
+ \else\ifcase\currentcolorchannel
+ \@EAEAEA\secondoftwoarguments
+ \else
+ \@EAEAEA\firstoftwoarguments
+ \fi\fi}
+
+\def\doifcolorchannelelse#1%
+ {\doifseparatingcolorselse
+ {\doifelsenothing{#1}
+ \secondoftwoarguments
+ {\doifelse{#1}\@@clsplit
+ \firstoftwoarguments
+ \secondoftwoarguments}}
+ \secondoftwoarguments}
+
+\def\resetcolorseparation
+ {\filterspotcolorfalse
+ \chardef\currentcolorchannel\zerocount}
+
+%D These can be used in selecting specific files (like
+%D figuredatabases).
+
+% we already have:
+%
+% \def\colorsplitsuffix{\ifcase\currentcolorchannel\else-\@@clsplitsen\fi}
+% \def\colorsplitprefix{\ifcase\currentcolorchannel\else\@@clsplitsen-\fi}
+
+\def\colorchannelprefix{\doifseparatingcolorselse\@@clsplit\empty-}
+\def\colorchannelsuffix{-\doifseparatingcolorselse\@@clsplit\empty}
+
+%D We now define the low level macros:
+
+\chardef\colorversion=1
+
+%D Color support is not present in \TEX. Colorful output can
+%D however be accomplished by using specials. This also means
+%D that this support depends on the \DVI\ driver used. At the
+%D moment this module was written, still no decent standard on
+%D color specials has been agreed upon. We therefore decided to
+%D implement a mechanism that is as independant as possible of
+%D drivers.
+%D
+%D Color support shares with fonts that is must be implemented
+%D in a way that permits processing of individual \DVI\ pages.
+%D Furthermore it should honour grouping. The first condition
+%D forces us to use a scheme that keeps track of colors at
+%D page boundaries. This can be done by means of \TEX's
+%D marking mechanism (\type{\mark}).
+%D
+%D When building pages, \TEX\ periodically looks at the
+%D accumulated typeset contents and breaks the page when
+%D suitable. At that moment, control is transfered to the
+%D output routine. This routine takes care of building the
+%D pagebody and for instance adds headers and footers. The page
+%D can be broken in the middle of some colored text, but
+%D headers and footers are often in black upon white or
+%D background. If colors are applied there, they definitely
+%D are used local, which means that they don't cross page
+%D borders.
+%D
+%D Boxes are handled as a whole, which means that when we
+%D apply colors inside a box, those colors don't cross page
+%D boundaries, unless of course boxes are split or unboxed.
+%D Especially in interactive texts, colors are often used in
+%D such a local way: in boxes (buttons and navigational tools)
+%D or in the pagebody (backgrounds).
+%D
+%D So we can distinguish local colors, that don't cross
+%D pages from global colors, of which we can end many pages
+%D later. The color macros will treat both types in a different
+%D way, thus gaining some speed.
+%D
+%D This module also deals with gray scales. Because similar
+%D colors can end up in the same gray scale when printed in
+%D black and white, we also implement a palet system that deals
+%D with these matters. Because of fundamental differences
+%D between color and gray scale printing, in \CONTEXT\ we also
+%D differ between these. For historic reasons |<|we first
+%D implemented gray scales using patterns of tiny periods|>|
+%D and therefore called them {\em rasters}. So don't be
+%D surprised if this term shows up.
+
+%D \macros
+%D {definecolor}
+%D
+%D We will enable users to specify colors in \cap{RGB} and
+%D \cap{CMYK} color spaces or gray scales using
+%D
+%D \showsetup{definecolor}
+%D
+%D For example:
+%D
+%D \starttyping
+%D \definecolor [SomeKindOfRed] [r=.8,g=.05,b=.05]
+%D \stoptyping
+%D
+%D Such color specifications are saved in a macro in the
+%D following way:
+%D
+%D \starttyping
+%D \setvalue{\??cr name}{R:r:g:b}
+%D \setvalue{\??cr name}{C:c:m:y:k}
+%D \setvalue{\??cr name}{S:s}
+%D \stoptyping
+%D
+%D Gray scales are specified with the \type{s} parameter,
+%D where the \type {s} is derived from {\em screen}.
+%D
+%D Starting with \PDF\ 1.4 (2001) \CONTEXT\ supports
+%D transparent colors. The transparency factor is represented
+%D by a \type {t} and the transparency method by an \type {a}
+%D (alternative). Later we will implement more control
+%D (probably by symbolic methods. So, currently the data is
+%D stored as follows:
+%D
+%D \starttyping
+%D \setvalue{\??cr name}{R:r:g:b:a:t}
+%D \setvalue{\??cr name}{C:c:m:y:k:a:t}
+%D \setvalue{\??cr name}{S:s:a:t}
+%D \stoptyping
+
+% r g b : rbg
+% c m y k : cmyk
+% s : gray
+% p n d f : spot
+% h : hexadecimal
+% t a : transparency
+% e : equivalent (spotcolors)
+
+\def\@@cl@@z{0}
+\def\@@cl@@o{1}
+
+\def\@@resetcolorparameters
+ {\let\@@cl@@r\@@cl@@z \let\@@cl@@g\@@cl@@z \let\@@cl@@b\@@cl@@z
+ \let\@@cl@@c\@@cl@@z \let\@@cl@@m\@@cl@@z \let\@@cl@@y\@@cl@@z \let\@@cl@@k\@@cl@@z
+ \let\@@cl@@s\@@cl@@z
+ \let\@@cl@@p\@@cl@@o \let\@@cl@@n\empty \let\@@cl@@d\empty \let\@@cl@@f\@@cl@@o
+ \let\@@cl@@h\empty
+ \let\@@cl@@e\empty
+ \let\@@cl@@t\@@cl@@z \let\@@cl@@a\@@cl@@z}
+
+\@@resetcolorparameters
+
+\def\@@cl@@A{\@@cl@@a} % a hook for symbolic conversion, see below
+
+%D Handling a few nested \type{\cs}'s is no problem (\type
+%D {\@EA\@EAEAEA\@EA}) but we need a full expansion, so I
+%D tried one of the fully expandable primitives using a sort
+%D of delimited thing. I tried \type {\number} first, but this
+%D does not work, but \type {\romannumeral} does. Actually,
+%D \type{\romannumeral0} returns nothing, so it's a perfect
+%D candidate for this kind of hackery. This reminds me that I
+%D have to look into David Kastrup's Euro\TeX\ 2002 article
+%D because he is using \type {\romannumeral} for loops
+%D (repetitive \quote {m} stuff).
+
+% \def\x{\y}\def\y{\z}\def\z{0:1:1:1}
+%
+% \def\bla #1:#2:#3\end{}
+%
+% \@EA\bla\romannumeral\x\end
+
+\def\colorXpattern{0S:\@@cl@@z:\@@cl@@z:\@@cl@@z}
+\def\colorZpattern{0S:\@@cl@@z:\@@cl@@A:\@@cl@@t}
+\def\colorSpattern{0S:\@@cl@@s:\@@cl@@A:\@@cl@@t}
+\def\colorCpattern{0C:\@@cl@@c:\@@cl@@m:\@@cl@@y:\@@cl@@k:\@@cl@@A:\@@cl@@t}
+\def\colorRpattern{0R:\@@cl@@r:\@@cl@@g:\@@cl@@b:\@@cl@@A:\@@cl@@t}
+
+%def\colorPpattern{0P:\@@cl@@n:\@@cl@@p:\@@cl@@A:\@@cl@@t}
+
+\def\colorPpattern{0P:\@@cl@@n:\@@cl@@f:\@@cl@@d:\@@cl@@p:\@@cl@@A:\@@cl@@t}
+
+%D The extra 0 catches empty colors specs (needed for the
+%D \type {\MPcolor} and \type {\PDFcolor} conversion (\type
+%D {\@@cr} equals \type {\relax}!).
+
+\def\handlecolorwith#1{\@EA#1\romannumeral0}
+
+%D Next comes the main definition macro.
+
+\def\dodefinecolor {\dododefinecolor\relax \setvalue \setevalue1}
+\def\dodefineglobalcolor{\dododefinecolor\doglobal\setgvalue\setxvalue1}
+\def\dodefinenamedcolor {\dododefinecolor\doglobal\setvalue \setevalue0}
+
+\let\colorlist\empty % not really used, only for colo-run
+\setfalse\collectcolorsinlist
+\def\collectcolorinlist#1{\doglobal\addtocommalist{#1}\colorlist}
+
+\def\dododefinecolor#1#2#3#4[#5][#6]% #2==set(g)value #3==set[e|x]value
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#5}\fi
+ \doifassignmentelse{#6}
+ {\@@resetcolorparameters
+ \getparameters[\??cl @@][#6]%
+ \ifx\@@cl@@h\empty
+ \doifelse{\@@cl@@r\@@cl@@g\@@cl@@b}{\@@cl@@z\@@cl@@z\@@cl@@z}
+ {\doifelse{\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k}{\@@cl@@z\@@cl@@z\@@cl@@z\@@cl@@z}
+ {\doifelse\@@cl@@s\@@cl@@z
+ {\showmessage\m!colors8{{[#6]},#5}%
+ #3{\??cr#5}{\colorZpattern}}
+ {#3{\??cr#5}{\colorSpattern}}}
+ {#3{\??cr#5}{\colorCpattern}}}
+ {#3{\??cr#5}{\colorRpattern}}%
+ \else
+ \setxvalue{\??cr#5}{\colorHpattern}%
+ \fi
+ % new: e=external spot color name
+ \ifx\@@cl@@e\empty \else
+ \doregisterspotcolorname{#5}\@@cl@@e
+ \fi}
+ {\doifelsenothing\currentpalet
+ \donefalse
+ {\doifdefinedelse{\??cr\currentpalet#6}\donetrue\donefalse}%
+ \ifdone
+ \doifnot{#5}{#6}
+ {#2{\??cr#5}{\paletcolorspec{#6}}}%
+ \else
+ \doifdefinedelse{\??cr#6}
+ {\doifelse{#5}{#6}
+ {% this way we can freeze \definecolor[somecolor][somecolor]
+ % and still prevent cyclic definitions
+ \iffreezecolors#3{\??cr#5}{\csname\??cr#6\endcsname}\fi}
+ {\iffreezecolors\@EA#3\else\@EA#2\fi{\??cr#5}{\csname\??cr#6\endcsname}}}
+ {\showmessage\m!colors3{#5 (def)}}%
+ \fi}%
+ \ifcase#4\or
+ \unexpanded#2{#5}{\switchtocolor[#5]}% \unexpanded toegevoegd
+ \fi}
+
+\def\paletcolorspec#1%
+ {\csname\??cr\currentpalet#1\endcsname}
+
+%D Hex color support is not enabled by default. You need to say \type
+%D {\setupcolor [hex]} to get this working.
+
+\ifx\colorHpattern\undefined \let\colorHpattern\colorZpattern \fi
+
+%D New and experimental.
+
+\def\dodefinespotcolor[#1][#2][#3]% todo: always global
+ {\doifnot{#1}{#2}
+ {\@@resetcolorparameters
+ \ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
+ \edef\@@cl@@n{#2}%
+ \getparameters[\??cl @@][#3]%
+ \doifnothing\@@cl@@p{\let\@@cl@@p\!!plusone}%
+ \ifx\@@cl@@e\empty \else
+ \doregisterspotcolorname{#2}\@@cl@@e
+ \fi
+ \doglobal\addtocommalist{#2}\allspotcolors
+ \setxvalue{\??cr#1}{\colorPpattern}% was \setevalue
+ \setgvalue{#1}{\switchtocolor[#1]}}} % was \setvalue
+
+\def\registerusedspotcolors
+ {\ifx\allspotcolors\empty \else
+ \bgroup
+ \let\usedspotcolors\empty
+ \def\docommand##1%
+ {\doifdefined{\??cs##1}{\addtocommalist{##1}\usedspotcolors}}%
+ \processcommacommand[\allspotcolors]\docommand
+ \savecurrentvalue\usedspotcolors\usedspotcolors
+ \egroup
+ \fi}
+
+\def\registerusedcolorchannels
+ {\bgroup
+ \doifdefinedelse{\??cs c}
+ {\def\usedcolorchannels{c,m,y,k}}%
+ {\let\usedcolorchannels\empty}%
+ \doifdefined{\??cs r}
+ {\addtocommalist{r,g,b}\usedcolorchannels}%
+ \doifdefined{\??cs s}
+ {\ExpandBothAfter\doifnotinset{k}\usedcolorchannels
+ {\addtocommalist{s}\usedcolorchannels}}%
+ \savecurrentvalue\usedcolorchannels\usedcolorchannels
+ \egroup}
+
+\prependtoks
+ \registerusedspotcolors
+ \registerusedcolorchannels
+\to \everylastshipout
+
+\def\registerusedspotcolor#1%
+ {\global\@EA\chardef\csname\??cs#1\endcsname\zerocount}
+
+%D On top of spotcolors, we define multitone colors. You'd better know
+%D what you're doing because invalid definitions will lead to invalid
+%D documents (i.e.\ resources).
+
+% \definecolor [darkblue] [c=.5,m=.5]
+% \definecolor [darkyellow] [y=.5]
+%
+% \definemultitonecolor [whatever] [darkblue=.5,darkyellow=.5] [c=.25,m=.25,y=.25] [a=1,t=.5]
+% \definemultitonecolor [another] [darkblue=.5,darkyellow=.5] [c=.25,m=.25,y=.25]
+
+\def\dodefinemultitonecolor[#1][#2][#3][#4]%
+ {\let\@@cl@@cl@@D\empty % n's
+ \let\@@cl@@cl@@P\empty % p's
+ \let\@@cl@@cl@@N\empty % name
+ \scratchcounter\zerocount
+ \processcommacommand[#2]\dododefinemultitonecolor
+ \bgroup
+ \lccode`\.=`\_%
+ \lccode`\,=`\_%
+ \lccode`\:=`\_%
+ \lccode`\;=`\_%
+ \lccode`\+=`\_%
+ \lccode`\-=`\_%
+ \lccode`\*=`\_%
+ \lccode`\/=`\_%
+% \lccode`\_=`\_%
+ % not needed, other attribute in driver:
+ %
+ % \@@resetcolorparameters
+ % \getparameters[#4]%
+ % \ifx\@@cl@@t\@@cl@@z\else
+ % \edef\@@cl@@cl@@N{\@@cl@@cl@@N_\@@cl@@t_\@@cl@@a}%
+ % \fi
+ \lowercase\@EA{\@EA\xdef\@EA\@@cleancolor\@EA{\@@cl@@cl@@N}}%
+ \egroup
+ \setxvalue{\??cl\@@cleancolor\s!check}{\noexpand\docheckmultitonecolor{\@@cl@@cl@@D}}%
+ \expanded{\defineglobalcolor[\@@cleancolor][#3,#4]}%
+ \expanded{\definespotcolor[#1][\@@cleancolor][#4,f=\the\scratchcounter,p={\@@cl@@cl@@P},d={\@@cl@@cl@@D}]}}
+
+\def\docheckmultitonecolor#1%
+ {\flushatshipout
+ {\let\checkmultitonecolor\gobbleoneargument
+ \def\docommand##1{\hbox{\definecolor[\s!dummy-100][##1][p=1]\color[\s!dummy-100]}}%
+ \processcommalist[#1]\docommand}}
+
+\def\checkmultitonecolor#1%
+ {\csname\??cl#1\s!check\endcsname\letgvalue{\??cl#1\s!check}\relax}
+
+\def\dodefinespotcolor[#1][#2][#3]% todo: always global (REDEFINED)
+ {\doifnot{#1}{#2}
+ {\@@resetcolorparameters
+ \ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
+ \edef\@@cl@@n{#2}%
+ \getparameters[\??cl @@][#3]%
+ \doifnothing \@@cl@@p{\let\@@cl@@p\!!plusone}%
+ \doifsomething\@@cl@@e{\doregisterspotcolorname{#2}\@@cl@@e}%
+ \doglobal\addtocommalist{#2}\allspotcolors
+ \setxvalue{\??cr#1}{\colorPpattern}% was \setevalue
+ \setgvalue{#1}{\switchtocolor[#1]}}}% was \setvalue
+
+\def\dododefinemultitonecolor#1%
+ {\advance\scratchcounter\plusone
+ \splitstring#1\at=\to\!!stringa\and\!!stringb
+ \ifx\@@cl@@cl@@D\empty
+ \let\@@cl@@cl@@D\!!stringa
+ \let\@@cl@@cl@@P\!!stringb
+ \normalizecolor\!!stringb
+ \edef\@@cl@@cl@@N{\!!stringa_\!!stringb}%
+ \else
+ \edef\@@cl@@cl@@D{\@@cl@@cl@@D,\!!stringa}%
+ \edef\@@cl@@cl@@P{\@@cl@@cl@@P,\!!stringb}%
+ \normalizecolor\!!stringb
+ \edef\@@cl@@cl@@N{\@@cl@@cl@@N_\!!stringa_\!!stringb}%
+ \fi}
+
+% \def\dododefinemultitonecolor#1% a/b safe
+% {\advance\scratchcounter\plusone
+% \splitstring#1\at=\to\@@cl@@one\and\@@cl@@two
+% \ifx\@@cl@@cl@@D\empty
+% \let\@@cl@@cl@@D\@@cl@@one
+% \let\@@cl@@cl@@P\@@cl@@two
+% \normalizecolor\@@cl@@two
+% \edef\@@cl@@cl@@N{\@@cl@@one_\@@cl@@two}%
+% \else
+% \edef\@@cl@@cl@@D{\@@cl@@cl@@D,\@@cl@@one}%
+% \edef\@@cl@@cl@@P{\@@cl@@cl@@P,\@@cl@@two}%
+% \normalizecolor\@@cl@@two
+% \edef\@@cl@@cl@@N{\@@cl@@cl@@N_\@@cl@@one_\@@cl@@two}%
+% \fi}
+
+%D The names of colors are stored in a comma separated list
+%D only for the purpose of showing them with \type {\showcolor}.
+%D
+%D \startbuffer
+%D \definecolor [SomeKindOfRed] [r=.8,g=.05,b=.05]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \getbuffer
+%D
+%D This color shows up as \color [SomeKindOfRed] {some kind
+%D of red}.
+%D
+%D \starttyping
+%D \setupcolors[state=start]
+%D
+%D \definecolor[mygreen][green]
+%D \definecolor[green][g=.5]
+%D
+%D \startcolor[mygreen]test\stopcolor
+%D
+%D \setupcolors[expansion=no]
+%D
+%D \definecolor[mygreen][green]
+%D \definecolor[green][g=.5]
+%D
+%D \startcolor[mygreen]test\stopcolor
+%D \stoptyping
+
+%D \macros
+%D {startcolormode,stopcolormode,permitcolormode}
+%D
+%D We use \type{\stopcolormode} to reset the color in
+%D whatever color space and do so by calling the corresponding
+%D special. Both commands can be used for fast color
+%D switching, like in colored verbatim,
+
+\newif\ifpermitcolormode \permitcolormodetrue
+
+\def\dowithcolor#1#2% #1=\action #2=color
+ {\ifincolor\ifpermitcolormode
+ \ifcsname\??cr\currentpalet#2\endcsname
+ \handlecolorwith#1\csname\??cr\currentpalet#2\endcsname\od
+ \else\ifcsname\??cr#2\endcsname
+ \handlecolorwith#1\csname\??cr#2\endcsname\od
+ \fi\fi
+ \fi\fi}
+
+\def\startcolormode % includes \ifincolor\ifpermitcolormode
+ {%\dostoptransparency % needed for: {test \trans test \notrans test}
+ \conditionalstoptransparency
+ \dowithcolor\execcolorRCSP}
+
+\def\stopcolormode
+ {\ifincolor\ifpermitcolormode
+ \supportedstoptransparency
+ \dostopcolormode
+ \fi\fi}
+
+\def\restorecolormode
+ {\ifincolor\ifpermitcolormode
+ \supportedstoptransparency
+ \dostopcolormode
+ \ifx\maintextcolor\empty \else
+ \startcolormode\maintextcolor
+ \fi
+ \fi\fi}
+
+%D Color modes are entered using the next set of commands.
+%D The \type{\stop} alternatives are implemented in a way
+%D that permits non||grouped use.
+%D
+%D The, for this module redundant, check if we are in color
+%D mode is needed when we use these macros in other modules.
+
+\def\execcolorRCSP#1:%
+ {\csname execcolor#1\endcsname}
+
+\def\execcolorR
+ {\iffilterspotcolor
+ \@EA\noexeccolorR
+ \else
+ \@EA\doexeccolorR
+ \fi}
+
+\def\execcolorC
+ {\iffilterspotcolor
+ \@EA\noexeccolorC
+ \else
+ \@EA\doexeccolorC
+ \fi}
+
+\def\execcolorS
+ {\iffilterspotcolor
+ \@EA\noexeccolorS
+ \else
+ \@EA\doexeccolorS
+ \fi}
+
+\def\execcolorP
+ {\iffilterspotcolor
+ \@EA\doexeccolorPP
+ \else\ifcase\currentcolorchannel
+ \@EAEAEA\doexeccolorP
+ \else
+ \@EAEAEA\noexeccolorP
+ \fi\fi}
+
+\def\doexeccolorR#1:#2:#3:%
+ {\edef\@@cl@@r{#1}\edef\@@cl@@g{#2}\edef\@@cl@@b{#3}%
+ \ifpreferGRAY\ifx\@@cl@@r\@@cr@@g\ifx\@@cl@@r\@@cl@@b
+ \GRAYpreferedtrue
+ \fi\fi\fi
+ \ifincolor\else\RGBsupportedfalse\CMYKsupportedfalse\fi
+ \ifGRAYprefered
+ \registercolorchannel\c!s
+ \let\@@cl@@s\@@cl@@r
+ \normalizeGRAY
+ \doexeccolorgray
+ \else\ifRGBsupported
+ \registercolorchannel\c!r
+ \normalizeRGB
+ \doexeccolorrgb
+ \else\ifCMYKsupported
+ \registercolorchannel\c!c
+ \convertRGBtoCMYK\@@cl@@r\@@cl@@g\@@cl@@b
+ \normalizeCMYK
+ \doexeccolorcmyk
+ \else
+ \registercolorchannel\c!s
+ \convertRGBtoGRAY\@@cl@@r\@@cl@@g\@@cl@@b
+ \normalizeGRAY
+ \doexeccolorgray
+ \fi\fi\fi
+ \exectransparency}
+
+\def\doexeccolorC#1:#2:#3:#4:%
+ {\edef\@@cl@@c{#1}\edef\@@cl@@m{#2}\edef\@@cl@@y{#3}\edef\@@cl@@k{#4}%
+ \ifpreferGRAY\ifx\@@cl@@k\@@cl@@z\ifx\@@cl@@c\@@cr@@m\ifx\@@cl@@c\@@cl@@y
+ \GRAYpreferedtrue
+ \fi\fi\fi\fi
+ \ifincolor\else\RGBsupportedfalse\CMYKsupportedfalse\fi
+ \ifGRAYprefered
+ \registercolorchannel\c!s
+ \let\@@cl@@s\@@cl@@c
+ \normalizeGRAY
+ \doexeccolorgray
+ \else\ifCMYKsupported
+ \registercolorchannel\c!c
+ \ifreduceCMYK
+ \convertCMYKtoCMY\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
+ \fi
+ \normalizeCMYK
+ \doexeccolorcmyk
+ \else\ifRGBsupported
+ \registercolorchannel\c!r
+ \convertCMYKtoRGB\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
+ \normalizeRGB
+ \doexeccolorrgb
+ \else
+ \registercolorchannel\c!s
+ \convertCMYKtoGRAY\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
+ \normalizeGRAY
+ \doexeccolorgray
+ \fi\fi\fi
+ \exectransparency}
+
+\def\doexeccolorS#1:%
+ {\edef\@@cl@@s{#1}%
+ \registercolorchannel\c!s
+ \normalizeGRAY
+ \doexeccolorgray
+ \exectransparency}
+
+% \def\doexeccolorP#1:#2:%
+% {\edef\@@cl@@n{#1}%
+% \edef\@@cl@@p{#2}%
+% \registerusedspotcolor\@@cl@@n
+% \ifSPOTsupported
+% \dowithcolor\registerspotcolor\@@cl@@n
+% \dostartspotcolormode\@@cl@@n\@@cl@@p
+% \else
+% \doingspotcolortrue
+% \let\spotcolorfactor\@@cl@@p
+% \factorizecolortrue % using counter and array
+% \dowithcolor\execcolorRCSP\@@cl@@n
+% \factorizecolorfalse
+% \let\spotcolorfactor\@@cl@@o
+% \doingspotcolorfalse
+% \fi
+% \exectransparency}
+
+\def\doexeccolorP#1:#2:#3:#4:%
+ {\edef\@@cl@@n{#1}% name
+ \edef\@@cl@@f{#2}% fractions
+ \edef\@@cl@@d{#3}% definitions
+ \edef\@@cl@@p{#4}%
+ \ifx\@@cl@@d\empty
+ \let\@@cl@@d\@@cl@@n
+ \fi
+ \registerusedspotcolor\@@cl@@n
+ \ifSPOTsupported
+ \checkmultitonecolor\@@cl@@n
+ \dowithcolor\registerspotcolor\@@cl@@n
+ \dostartspotcolormode\@@cl@@n\@@cl@@p
+ \else
+ \doingspotcolortrue
+ \normalizespotcolor\@@cl@@p
+ \let\spotcolorfactor\@@cl@@p
+ \factorizecolortrue % using counter and array
+ \dowithcolor\execcolorRCSP\@@cl@@n
+ \factorizecolorfalse
+ \let\spotcolorfactor\@@cl@@o
+ \doingspotcolorfalse
+ \fi
+ \exectransparency}
+
+\def\doexeccolorPindex#1:#2:#3:#4:%
+ {\edef\@@cl@@n{#1}%
+ \edef\@@cl@@f{#2}%
+ \edef\@@cl@@d{#3}%
+ \edef\@@cl@@p{#4}%
+ \ifx\@@cl@@d\empty
+ \let\@@cl@@d\@@cl@@n
+ \fi
+ \ifSPOTsupported
+ \checkmultitonecolor\@@cl@@n
+ \dowithcolor\registerindexcolor\@@cl@@n
+ \fi
+ \noexectransparency}
+
+\def\doexeccolorPP#1:#2:%
+ {\edef\@@cl@@n{#1}%
+ \edef\@@cl@@p{#2}%
+ \registerusedspotcolor\@@cl@@n
+ \ifx\@@cl@@n\currentspotcolor
+ \normalizeSPOT
+ \dostartgraycolormode\@@cl@@p % was spotcolormode
+ \else
+ \dovidecolor\@@cl@@p\@@cl@@o
+ \fi
+ \exectransparency}
+
+\def\doexeccolorrgb
+ {\ifcase\currentcolorchannel
+ \dostartrgbcolormode\@@cl@@r\@@cl@@g\@@cl@@b
+ \or \or \or \or
+ \or \dostartgraycolormode\@@cl@@r
+ \or \dostartgraycolormode\@@cl@@g
+ \or \dostartgraycolormode\@@cl@@b
+ \fi}
+
+\def\doexeccolorcmyk
+ {\ifcase\currentcolorchannel
+ \dostartcmykcolormode\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
+ \or \negatecolorcomponent\@@cl@@c\dostartgraycolormode\@@cl@@c
+ \or \negatecolorcomponent\@@cl@@m\dostartgraycolormode\@@cl@@m
+ \or \negatecolorcomponent\@@cl@@y\dostartgraycolormode\@@cl@@y
+ \or \negatecolorcomponent\@@cl@@k\dostartgraycolormode\@@cl@@k
+ \fi}
+
+\def\doexeccolorgray
+ {\ifcase\currentcolorchannel
+ \dostartgraycolormode\@@cl@@s
+ \or \or \or
+ \or \dostartgraycolormode\@@cl@@s
+ \or \or \or
+ \or \dostartgraycolormode\@@cl@@s
+ \fi}
+
+%D When filtering colors, we need to either erase
+%D the background, or ignore the foreground.
+
+% \newif\ifhidesplitcolor \hidesplitcolortrue
+%
+% \def\noexeccolor#1\od
+% {\dostartgraycolormode\@@cl@@o}
+%
+% \let\noexeccolorS\noexeccolor
+% \let\noexeccolorP\noexeccolor
+
+%D Well, here comes some real trickery. When we have the 100\%
+%D spot color or black color, we don't want to erase the
+%D background. So, instead we hide the content by giving it
+%D zero transparency.
+
+% todo : #1#2#3 met #2 > of < and #3 een threshold
+
+\def\dohidecolor#1#2%
+ {\ifhidesplitcolor
+ \ifx#1#2%
+ \dostartgraycolormode\@@cl@@o
+ \else
+ \doregisternonecolor
+ \dostartnonecolormode
+ \fi
+ \else
+ \dostartgraycolormode\@@cl@@o
+ \fi}
+
+\def\dovidecolor#1#2%
+ {\ifhidesplitcolor
+ \ifx#1#2%
+ \doregisternonecolor
+ \dostartnonecolormode
+ \else
+ \dostartgraycolormode\@@cl@@o
+ \fi
+ \else
+ \dostartgraycolormode\@@cl@@o
+ \fi}
+
+% \def\fullytransparentcolor % fails on floats
+% {\dostartgraycolormode\@@cl@@o % better than z
+% %\global\@EA\chardef\csname\@@currenttransparent\endcsname\plusone
+% %\global\intransparenttrue
+% \dostarttransparency10}
+
+\def\noexeccolorR#1:#2:#3:#4\od
+ {\edef\@@cl@@r{#1}\edef\@@cl@@g{#2}\edef\@@cl@@b{#3}%
+ \dohidecolor\@@cl@@s\@@cl@@o}
+
+\def\noexeccolorC#1:#2:#3:#4:#5\od
+ {\edef\@@cl@@c{#1}\edef\@@cl@@m{#2}\edef\@@cl@@y{#3}\edef\@@cl@@k{#4}%
+ \dohidecolor\@@cl@@s\@@cl@@o}
+
+\def\noexeccolorS#1:#2\od
+ {\edef\@@cl@@s{#1}%
+ \dohidecolor\@@cl@@s\@@cl@@o}
+
+\def\noexeccolorP#1:#2:#3:#4:#5\od
+ {\edef\@@cl@@p{#4}%
+ \dohidecolor\@@cl@@p\@@cl@@z}
+
+%D For the sake of postprocessing (i.e.\ color separation)
+%D we can normalize colors, which comes down to giving equal
+%D values an equal accuracy and format. This feature is
+%D turned off by default due to a speed penalty. This macro
+%D also handles spot color percentages.
+
+\newif\iffactorizecolor
+\newif\ifnormalizecolor
+
+\def\spotcolorfactor{1}
+
+% \def\normalizecolor#1%
+% {\colordimen#1\thousandpoint
+% \colordimen\spotcolorfactor\colordimen
+% \colorcount\colordimen
+% \advance\colorcount \medcard
+% \divide\colorcount \maxcard
+% \edef#1{\realcolorvalue\colorcount}}
+
+\def\normalizecolor#1%
+ {\colorcount\numexpr(\dimexpr\spotcolorfactor\dimexpr#1\thousandpoint\relax\relax+\medcard)/\maxcard\relax
+ \edef#1{\realcolorvalue\colorcount}}
+
+% \def\normalizespotcolor#1%
+% {\colordimen-#1\thousandpoint
+% \advance\colordimen\thousandpoint
+% \colorcount\colordimen
+% \advance\colorcount \medcard
+% \divide\colorcount \maxcard
+% \edef#1{\realcolorvalue\colorcount}}
+
+\def\normalizespotcolor#1%
+ {\colorcount\numexpr(\dimexpr\thousandpoint-#1\thousandpoint\relax+\medcard)/\maxcard\relax
+ \edef#1{\realcolorvalue\colorcount}}
+
+\def\donormalizeRGB
+ {\normalizecolor\@@cl@@r
+ \normalizecolor\@@cl@@g
+ \normalizecolor\@@cl@@b}
+
+\def\normalizeRGB
+ {\ifnormalizecolor
+ \donormalizeRGB
+ \else\iffactorizecolor
+ \donormalizeRGB
+ \fi\fi}
+
+\def\donormalizeCMYK
+ {\normalizecolor\@@cl@@c
+ \normalizecolor\@@cl@@m
+ \normalizecolor\@@cl@@y
+ \normalizecolor\@@cl@@k}
+
+\def\normalizeCMYK
+ {\ifnormalizecolor
+ \donormalizeCMYK
+ \else\iffactorizecolor
+ \donormalizeCMYK
+ \fi\fi}
+
+\def\donormalizeGRAY
+ {\normalizecolor\@@cl@@s}
+
+\def\normalizeGRAY
+ {\ifnormalizecolor
+ \donormalizeGRAY
+ \else\iffactorizecolor
+ \donormalizeGRAY
+ \fi\fi}
+
+\def\normalizeSPOT
+ {\normalizespotcolor\@@cl@@p}
+
+%D We need to register spot colors (i.e.\ resources need to
+%D be created.
+
+\def\registerspotcolor#1:%
+ {\ifcsname\??cl:\c!p:\@@cl@@n\endcsname
+ \@EA\dontregisterspotcolor
+ \else
+ \letgvalue{\??cl:\c!p:\@@cl@@n}\empty
+ %\@EA\@EA\csname registerspotcolor#1\endcsname
+ \csname registerspotcolor#1\@EA\endcsname
+ \fi}
+
+% todo: convert to rgb if needed, will will do this in mkiv
+
+\def\dontregisterspotcolor #1\od{}
+\def\registerspotcolorR #1:#2:#3:#4\od{\doregisterrgbspotcolor \@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#1}{#2}{#3}}
+\def\registerspotcolorC#1:#2:#3:#4:#5\od{\doregistercmykspotcolor\@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#1}{#2}{#3}{#4}}
+\def\registerspotcolorS #1:#2\od{\doregistergrayspotcolor\@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#1}}
+\def\registerspotcolorP #1:#2:#3\od{\doregistergrayspotcolor\@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#2}}
+
+%D Experimental feature:
+
+% \definecolor [darkblue] [c=1,m=.38,y=0,k=.64] % pantone pms 2965 uncoated m
+% \definecolor [darkyellow] [c=0,m=.28,y=1,k=.06] % pantone pms 124 uncoated m
+%
+% \definecolor [darkblue-50] [darkblue] [p=.5]
+% \definecolor [darkyellow-50] [darkyellow] [p=.5]
+% \definecolor [darkblue-80] [darkblue] [p=.8]
+% \definecolor [darkyellow-80] [darkyellow] [p=.8]
+%
+% \definecolor [darkblue,darkyellow] [r=.8]
+% \definecolor [darkdull-5030] [darkblue,darkyellow] [p={.5,.3}]
+%
+% \setupcolors[state=start]
+%
+% \blackrule[width=4cm,height=3cm,color=darkblue-50]
+% \blackrule[width=4cm,height=3cm,color=darkblue-80]
+% \blackrule[width=4cm,height=3cm,color=darkyellow-50]
+% \blackrule[width=4cm,height=3cm,color=darkyellow-80]
+% \blackrule[width=4cm,height=3cm,color=darkdull-5030]
+
+%D Experimental too (special purpose code).
+
+\def\registerindexcolor#1:%
+ {\ifcsname\??cl:i:\@@cl@@n\endcsname
+ \@EA\dontregisterindexcolor
+ \else
+ \letgvalue{\??cl:i:\@@cl@@n}\empty % signal
+ \showmessage\m!colors{12}\@@cl@@n
+ \@EA\@EA\csname registerindexcolor#1\endcsname
+ \fi}
+
+\let\dontregisterindexcolor\dontregisterspotcolor
+
+\def\registerindexcolorR #1:#2:#3:#4\od{\doregisterrgbindexcolor \@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#1}{#2}{#3}}
+\def\registerindexcolorC#1:#2:#3:#4:#5\od{\doregistercmykindexcolor\@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#1}{#2}{#3}{#4}}
+\def\registerindexcolorS #1:#2\od{\doregistergrayindexcolor\@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#1}}
+\def\registerindexcolorP #1:#2:#3\od{\doregistergrayindexcolor\@@cl@@n\@@cl@@f\@@cl@@d\@@cl@@p{#2}}
+
+\def\predefinecolor[#1]%
+ {\bgroup
+ \flushatshipout{\hbox{\localcolortrue\color[#1]{}}}% real ones
+ \egroup}
+
+\def\predefineindexcolor[#1]%
+ {\bgroup
+ \flushatshipout{\hbox{\localcolortrue\color[#1]{}}}% real ones
+ \let\doexeccolorP\doexeccolorPindex
+ \flushatshipout{\hbox{\localcolortrue\color[#1]{}}}% index one
+ \egroup}
+
+% \def\checkpredefinedcolor[#1]%
+% {\ifcase\internalspotcolorsize{#1}\relax
+% \@EA\predefinecolor\or\@EA\predefinecolor\else\@EA\predefineindexcolor
+% \fi[#1]}
+
+\let\checkpredefinedcolor\predefineindexcolor % we need an index in order to negate bitmaps
+
+%D Transparency is handled similar for all three color modes. We
+%D can turn transparency off with the following switch:
+
+\newif\iftransparencysupported \transparencysupportedtrue % only mkii
+
+\def\exectransparency
+ {\iftransparencysupported
+ \expandafter\doexectransparency
+ \else
+ \expandafter\noexectransparency
+ \fi}
+
+\def\doexectransparency#1:#2\od
+ {\ifcase#1\space
+ \global\intransparentfalse
+ \else
+ \global\intransparentfalse
+ %\dostarttransparency{#1}{#2}%
+ \supportedstarttransparency{#1}{#2}%
+ \global\intransparenttrue
+ \fi}
+
+\def\noexectransparency#1\od
+ {}
+
+%D Experimental: minimize transparency resets.
+
+\newif\ifintransparent
+\newif\ifoptimizetransparency \optimizetransparencytrue % under test
+
+\let\supportedstoptransparency\relax
+
+\def\conditionalstoptransparency
+ {\ifoptimizetransparency
+ \ifintransparent
+ \global\intransparentfalse
+ \supportedstoptransparency
+ \fi
+ \else
+ \supportedstoptransparency
+ \fi}
+
+\def\supportedstarttransparency
+ {\iftransparencysupported
+ \globallet\supportedstoptransparency\dostoptransparency
+ \expandafter\dostarttransparency
+ \else
+ \expandafter\gobbletwoarguments
+ \fi}
+
+%D We now use the \type {\@@cl@@A} hook to implement
+%D symbolic names. These are converted into numbers
+%D at definition time (which saves runtime).
+
+\def\dodefinetransparency[#1][#2]%
+ {\@EA\chardef\csname\??cl-#1\endcsname#2\relax}
+
+\def\transparencynumber#1%
+ {\number\executeifdefined{\??cl-#1}{#1}}
+
+%D Now we hook 'm into the patterns:
+
+\def\@@cl@@A{\transparencynumber\@@cl@@a}
+
+%D The next macro can be used to return to the (normal)
+%D page color. This macro is used in the same way as
+%D \type {\color}.
+
+\def\startregistercolor[#1]%
+ {\permitcolormodefalse\startcolor[#1]\permitcolormodetrue}
+
+\def\stopregistercolor
+ {\permitcolormodefalse\stopcolor\permitcolormodetrue}
+
+\def\starttextcolor[#1]%
+ {\doifsomething{#1}
+ {\bgroup
+ \def\stoptextcolor % also goes ok with \page after
+ {\let\maintextcolor\empty % this one because the top of
+ \stopregistercolor % page sets the color right (side
+ \egroup}% % effect)
+ \def\starttextcolor[##1]%
+ {\bgroup
+ % \@@themaintextcolor==##1 is catched in \definecolor
+ \definecolor[\@@themaintextcolor][##1]%
+ \let\stoptextcolor\egroup}%
+ \startregistercolor[\@@themaintextcolor]%
+ \definecolor[\@@themaintextcolor][#1]%
+ \let\maintextcolor\@@themaintextcolor}}
+
+\let\stoptextcolor\relax
+
+%D The following hook permits proper support at the text
+%D level. This definition actually belongs in another
+%D module. (May need a different \MKIV\ implementation.)
+
+% \ifx\initializemaintextcolor\undefined
+
+ \let\@@clprevcolor\empty
+
+ \def\initializemaintextcolor
+ {% saveguard for setting text color to empty after
+ % it has been set
+ \doifnothing\@@cltextcolor
+ {\ifx\@@clprevcolor\empty\else
+ \let\@@cltextcolor\defaulttextcolor
+ \fi}%
+ \doifelsenothing\@@cltextcolor
+ {\let\maintextcolor\empty}
+ {\edef\@@clprevcolor{\@@cltextcolor}%
+ \let\maintextcolor\@@themaintextcolor
+ \doifelsenothing\@@cltextcolor % another saveguard
+ {\definecolor[\@@themaintextcolor][\defaulttextcolor]}%
+ {\definecolor[\@@themaintextcolor][\@@cltextcolor]}%
+ \doinitializemaintextcolor}}
+
+ \def\doinitializemaintextcolor
+ {\appendtoks\starttextcolor[\@@themaintextcolor]\to\everystarttext
+ \appendtoks\stoptextcolor \to\everystoptext
+ \let\doinitializemaintextcolor\relax}
+
+% \fi
+
+\def\localstarttextcolor
+ {\ifx\maintextcolor\empty
+ \startcolormode\defaulttextcolor
+ \else
+ \startcolormode\maintextcolor
+ \fi}
+
+% \def\localstoptextcolor
+% {\stopcolormode}
+%
+% better:
+
+\def\localstoptextcolor
+ {\restorecolormode}
+
+\def\restoretextcolor
+ {\ifx\maintextcolor\empty
+ \expandafter\dorestoretextcolor
+ \else
+ % obey main text color
+ \fi}
+
+\def\dorestoretextcolor
+ {\color[\defaulttextcolor]}
+
+%D We use some reserved names for local color components.
+%D Consistent use of these scratch variables saves us
+%D unneccessary hash entries.
+%D
+%D \starttyping
+%D \@@cl@@r \@@cl@@g \@@cl@@b
+%D \@@cl@@c \@@cl@@m \@@cl@@y \@@cl@@k
+%D \@@cl@@s
+%D \stoptyping
+%D
+%D We implement several conversion routines.
+%D
+%D \starttyping
+%D \convertRGBtoCMYK {r} {g} {b}
+%D \convertRGBtoGRAY {r} {g} {b}
+%D \convertCMYKtoRGB {c} {m} {y} {k}
+%D \convertCMYKtoGRAY {c} {m} {y} {k}
+%D \convertCMYKtoCMY {c} {m} {y} {k}
+%D \stoptyping
+%D
+%D The relation between \cap{Gray}, \cap{RGB} and \cap{CMYK}
+%D is:
+%D
+%D \placeformula[-]
+%D \startformula
+%D G = .30r + .59g + .11b
+%D = 1.0 - \min(1.0,\ .30c + .59m + .11y + k)
+%D \stopformula
+%D
+%D When converting from \cap{CMYK} to \cap{RGB} we use the
+%D formula:
+%D
+%D \placeformula[-]
+%D \startformula
+%D \eqalign
+%D {r &= 1.0 - \min(1.0,\ c+k) \cr
+%D g &= 1.0 - \min(1.0,\ m+k) \cr
+%D b &= 1.0 - \min(1.0,\ y+k)}
+%D \stopformula
+%D
+%D In the conversion routine the color components are calculated
+%D in three digits precision.
+
+\def\realcolorvalue#1%
+ {\ifnum#1>\zerocount % important, first encountered in --modu supp-mpe
+ \ifnum#1<\plusten 0.00\the#1\else
+ \ifnum#1<\plushundred 0.0\the#1\else
+ \ifnum#1<\plusthousand 0.\the#1\else
+ 1\fi\fi\fi
+ \else 0\fi}
+
+% \def\doconvertCMYKtoRGB#1\k#2\to#3%
+% {\ifdim#2\points>#1\points% >= problem, repaired 2/12/2002
+% \let#3\@@cl@@z % k >= color
+% \else
+% \colordimen\onepoint
+% \advance\colordimen -#1\points
+% \advance\colordimen -#2\points
+% \multiply\colordimen \plusthousand
+% \colorcount\colordimen
+% \advance\colorcount \medcard
+% \divide\colorcount \maxcard
+% \edef#3{\realcolorvalue\colorcount}%
+% \fi}
+
+\def\doconvertCMYKtoRGB#1\k#2\to#3%
+ {\colorcount\numexpr(\dimexpr\plusthousand\dimexpr\onepoint-#1\points-#2\points\relax\relax+\medcard)/\maxcard\relax
+ \ifnum\colorcount>\zeropoint
+ \edef#3{\realcolorvalue\colorcount}%
+ \else
+ \let#3\@@cl@@z
+ \fi}
+
+\def\convertCMYKtoRGB#1#2#3#4%
+ {\doconvertCMYKtoRGB#1\k#4\to\@@cl@@r
+ \doconvertCMYKtoRGB#2\k#4\to\@@cl@@g
+ \doconvertCMYKtoRGB#3\k#4\to\@@cl@@b}
+
+% \def\doconvertRGBtoCMYK#1\to#2%
+% {\colordimen#1\points
+% \multiply\colordimen \plusthousand
+% \colorcount\colordimen
+% \advance\colorcount \medcard
+% \divide\colorcount \maxcard
+% \colorcount-\colorcount
+% \advance\colorcount \plusthousand
+% \edef#2{\realcolorvalue\colorcount}}
+
+\def\doconvertRGBtoCMYK#1\to#2%
+ {\colorcount\numexpr\plusthousand-(\dimexpr\plusthousand\dimexpr#1\points\relax\relax+\medcard)/\maxcard\relax
+ \edef#2{\realcolorvalue\colorcount}}
+
+\def\convertRGBtoCMYK#1#2#3%
+ {\doconvertRGBtoCMYK#1\to\@@cl@@c
+ \doconvertRGBtoCMYK#2\to\@@cl@@m
+ \doconvertRGBtoCMYK#3\to\@@cl@@y
+ \let\@@cl@@k\@@cl@@z}
+
+%D The following switch is mainly meant for (hidden)
+%D documentation purposes.
+
+\def\nGRAYfactor{333.333}
+\def\rGRAYfactor{\ifweightGRAY300\else\nGRAYfactor\fi}
+\def\gGRAYfactor{\ifweightGRAY590\else\nGRAYfactor\fi}
+\def\bGRAYfactor{\ifweightGRAY110\else\nGRAYfactor\fi}
+
+% \def\convertRGBtoGRAY#1#2#3%
+% {\colordimen#1\points
+% \colordimen\rGRAYfactor\colordimen
+% \colorcount\colordimen
+% \colordimen#2\points
+% \colordimen\gGRAYfactor\colordimen
+% \advance\colorcount \colordimen
+% \colordimen#3\points
+% \colordimen\bGRAYfactor\colordimen
+% \advance\colorcount \colordimen
+% \advance\colorcount \medcard
+% \divide\colorcount \maxcard
+% \edef\@@cl@@s{\realcolorvalue\colorcount}}
+
+\def\convertRGBtoGRAY#1#2#3%
+ {\colorcount\numexpr
+ (\dimexpr\rGRAYfactor\dimexpr#1\points\relax\relax+
+ \dimexpr\gGRAYfactor\dimexpr#2\points\relax\relax+
+ \dimexpr\bGRAYfactor\dimexpr#3\points\relax\relax+
+ \medcard)/\maxcard
+ \relax
+ \edef\@@cl@@s{\realcolorvalue\colorcount}}
+
+\def\convertCMYKtoGRAY#1#2#3#4%
+ {\convertCMYKtoRGB{#1}{#2}{#3}{#4}%
+ \convertRGBtoGRAY\@@cl@@r\@@cl@@g\@@cl@@b}
+
+% \def\doconvertCMYKtoCMY#1\k#2\to#3%
+% {\colordimen#1\points
+% \advance\colordimen #2\points\relax
+% \ifdim\colordimen>\onepoint
+% \colordimen\onepoint
+% %\else
+% % \colordimen\colordimen
+% \fi
+% \multiply\colordimen \plusthousand
+% \colorcount\colordimen
+% \advance\colorcount \medcard
+% \divide\colorcount \maxcard
+% \edef#3{\realcolorvalue\colorcount}}
+
+\def\doconvertCMYKtoCMY#1\k#2\to#3%
+ {\colorcount\numexpr(\dimexpr\plusthousand\dimexpr#1\points+#2\points\relax\relax+\medcard)/\maxcard\relax
+ \ifnum\colorcount>\plusthousand
+ \let#3\@@cl@@o
+ \else
+ \edef#3{\realcolorvalue\colorcount}%
+ \fi}
+
+\def\convertCMYKtoCMY#1#2#3#4%
+ {\doconvertCMYKtoCMY#1\k#4\to\@@cl@@c
+ \doconvertCMYKtoCMY#2\k#4\to\@@cl@@m
+ \doconvertCMYKtoCMY#3\k#4\to\@@cl@@y
+ \let\@@cl@@k\@@cl@@z}
+
+%D Before we present the color macros, we first define the
+%D setup command. This command takes care of setting up the
+%D booleans that control local and global behavior (more on
+%D that later) and conversion to other color spaces.
+
+\let\currentspotcolor \empty
+\let\previousspotcolor\empty
+
+%D The tests depend on the use of constants. If we use the \MKIV\
+%D method we can share more.
+
+\def\doifcolorelse#1%
+ {\ifcsname\??cr\ifcsname\??cr\currentpalet#1\endcsname\currentpalet\fi#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifcolor#1%
+ {\ifcsname\??cr\ifcsname\??cr\currentpalet#1\endcsname\currentpalet\fi#1\endcsname
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+%D There are a couple of different color switching macros,
+%D the local ones can be used to speed up things (only in \MKII).
+
+\def\localstartcolor
+ {\ifincolor
+ \localcolortrue
+ \expandafter\doglobalstartcolor
+ \else
+ \expandafter\noglobalstartcolor
+ \fi}
+
+\def\localstopcolor
+ {\ifincolor
+ \doglobalstopcolor
+ \else
+ \noglobalstopcolor
+ \fi}
+
+\unexpanded\def\startcolor
+ {\ifincolor
+ \expandafter\doglobalstartcolor
+ \else
+ \expandafter\noglobalstartcolor
+ \fi}
+
+\unexpanded\def\stopcolor
+ {\ifincolor
+ \doglobalstopcolor
+ \else
+ \noglobalstopcolor
+ \fi}
+
+%D This macros call the global color switching ones. Starting
+%D a global, i.e. a possible page boundary crossing, color
+%D mode also sets a \type{\mark} in \TEX's internal list.
+
+\newcount\colorlevel
+
+\letvalue{\??cl0C}\empty % saved color
+\letvalue{\??cl0S}\empty % stop command
+
+%D We keep a positive color stack for foreground colors, and
+%D a negative one for backgrounds. Not that brilliant a
+%D solution, but it suits. The signs are swapped when the
+%D page ornaments are typeset.
+
+\let\@@colorplus \plusone
+\let\@@colorminus\minusone
+
+\def\@@currentcolorname {\??cl\the\colorlevel C}
+\def\@@currentcolorstop {\??cl\the\colorlevel S}
+%def\@@currenttransparent{\??cl\the\colorlevel T}
+
+\letvalue{\??cl*\s!black}\s!black
+
+\def\currentcolorname
+ {\csname
+ \ifcsname\@@currentcolorname\endcsname
+ \expandafter\ifx\csname\@@currentcolorname\endcsname\empty
+ \??cl*\s!black
+ \else
+ \@@currentcolorname
+ \fi
+ \else
+ \??cl*\s!black
+ \fi
+ \endcsname}
+
+\def\outercolorname
+ {\ifcsname\@@currentcolorname\endcsname
+ \expandafter\ifx\csname\@@currentcolorname\endcsname\empty
+ \s!black
+ \else
+ currentcolor%
+ \fi
+ \else
+ \s!black
+ \fi}
+
+% not the following, because we need a different tag in order to trick the stack
+%
+% \def\outercolorname{\executeifdefined\@@currentcolorname\s!black}
+%
+% \def\startcurrentcolor{\expanded{\startcolor[\s!black]\noexpand\startcolor[\outercolorname]}}
+% \def\stopcurrentcolor {\stopcolor\stopcolor}
+%
+% test case:
+%
+% \setupcolors[state=start,textcolor=red]
+% \starttext
+% red
+% \color[green]{green
+% \startMPcode
+% label(\sometxt{green\color[blue]{blue}green}, origin) withcolor red;
+% draw fullcircle scaled 1cm xscaled 2;
+% \stopMPcode
+% green}
+% red
+% \stoptext
+
+\def\dodoglobalstartcolor
+ {\global\@EA\let\@EA\@@currentcolor\csname\@@currentcolorname\endcsname
+ \global\advance\colorlevel \@@colorplus
+ \global\@EA\let\csname\@@currentcolorname\endcsname\@@askedcolor
+ %\debuggerinfo\m!colors
+ % {start \@@askedcolor\space at level \the\colorlevel}%
+ \ifx\@@askedcolor\empty
+ \global\@EA\let\csname\@@currentcolorname\endcsname\@@currentcolor
+ \global\@EA\let\csname\@@currentcolorstop\endcsname\donoglobalstopcolor
+ \else\ifx\@@askedcolor\@@currentcolor
+ \global\@EA\let\csname\@@currentcolorstop\endcsname\donoglobalstopcolor
+ \else
+ \doifcolorelse\@@askedcolor
+ {%\docolormark\@@askedcolor
+ \ifpermitcolormode\docolormark\@@askedcolor\fi
+ \global\@EA\let\csname\@@currentcolorstop\endcsname\dodoglobalstopcolor
+ \startcolormode\@@askedcolor}
+ {\global\@EA\let\csname\@@currentcolorstop\endcsname\donoglobalstopcolor
+ \showmessage\m!colors3\@@askedcolor\empty}%
+ \fi\fi}
+
+\def\doglobalstartcolor[#1]%
+ {\edef\@@askedcolor{#1}%
+ \ifcase\colorlevel\relax
+ \ifx\@@askedcolor\empty
+ \global\@EA\let\csname\@@currentcolorstop\endcsname\empty
+ \else
+ \dodoglobalstartcolor
+ \fi
+ \else
+ \dodoglobalstartcolor
+ \fi
+ \ignorespaces}
+
+\def\noglobalstartcolor[#1]%
+ {}
+
+\def\dodoglobalstopcolor
+ {\ifcase\colorlevel \else
+ \donoglobalstopcolor
+ \global\@EA\let\@EA\@@previouscolor\csname\@@currentcolorname\endcsname
+ \ifcase\colorlevel\relax
+ \ifpermitcolormode
+ \docolormark\empty
+ \conditionalstoptransparency
+ \dostopcolormode
+ \fi
+ \else % let's do a bit redundant testing here
+ \docolormark\@@previouscolor
+ \ifx\@@previouscolor\empty
+ \ifpermitcolormode
+ \conditionalstoptransparency
+ \dostopcolormode
+ \fi
+ \else
+ \doifcolorelse\@@previouscolor
+ {\ifx\@@currentcolor\@@previouscolor\else
+ % alternatively we could let \startcolormode handle this
+ \ifpermitcolormode
+ \conditionalstoptransparency % really needed
+ % more safe but less efficient: \dostopcolormode
+ \fi
+ \startcolormode\@@previouscolor
+ \fi}
+ {\ifpermitcolormode
+ \conditionalstoptransparency
+ \dostopcolormode
+ \fi}%
+ \fi
+ \fi
+ \fi}
+
+\def\donoglobalstopcolor
+ {\ifcase\colorlevel \else
+ \global\@EA\let\@EA\@@currentcolor\csname\@@currentcolorname\endcsname
+ %\debuggerinfo{\m!colors}
+ % {stop \@@currentcolor\normalspace at level \the\colorlevel}%
+ \global\advance\colorlevel \@@colorminus
+ \fi}
+
+\def\doglobalstopcolor
+ {\csname\@@currentcolorstop\endcsname}
+
+\let\noglobalstopcolor\relax
+
+\let\faststartcolor\doglobalstartcolor
+\let\faststopcolor \doglobalstopcolor
+
+%D We don't use grouping and save each stop alternative. This
+%D permits be especially useful in for instance local color
+%D support in verbatim. Using \type{\bgroup}||\type{\egroup}
+%D pairs could interfere with calling commands
+
+%D This color mechanism takes care of nested colors, like in:
+%D
+%D \startbuffer
+%D \color[green]{groen \color[green]{groen \color[red]{rood}} groen}
+%D \color[green]{groen \color[]{groen \color[red]{rood}} groen}
+%D \color[green]{groen \color[red]{rood \color[red]{rood}} groen}
+%D \color[green]{groen \color[green]{groen \color[]{groen}} groen}
+%D \color[green]{groen \color[red]{rood} groen}
+%D \color[green]{groen \color[]{groen} groen}
+%D \color[]{zwart \color[red]{rood} zwart}
+%D \color[]{zwart}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D Crossing page boundaries is of course also handled.
+%D Undefined or empty color specifications are treated as
+%D efficient as possible.
+%D
+%D \startbuffer
+%D \startcolor[green]
+%D [green] \input tufte [green] \par
+%D \startcolor[]
+%D [green] \input knuth [green] \par
+%D \startcolor[red]
+%D [red] \input tufte [red] \par
+%D \startcolor[yellow]
+%D [yellow] \input knuth [yellow] \par
+%D \stopcolor
+%D [red] \input tufte [red] \par
+%D \stopcolor
+%D [green] \input knuth [green] \par
+%D \stopcolor
+%D [green] \input tufte [green] \par
+%D \stopcolor
+%D \stopbuffer
+%D
+%D \startpacked
+%D \getbuffer
+%D \stoppacked
+%D
+%D These quotes are typeset by saying:
+%D
+%D \typebuffer
+
+%D We already mentioned that colors interfere with building
+%D the pagebody. This means that when the page is composed,
+%D the colors temporary have to be reset. After the page is
+%D shipped out, we have to revive the current color.
+%D
+%D We use \type{\mark}s to keep track of colors across page
+%D boundaries. Unfortunately standard \TEX\ supports only one mark,
+%D and using this one for color support only would be a waste.
+%D We therefore use an adapted version of J.~Fox's multiple mark
+%D mechanism as (re|)|implemented in \module{supp-mrk}.
+
+\doifdefinedelse{rawnewmark}
+ {\rawnewmark\colormark}
+ {\let\colormark\gobbleoneargument}
+
+%D Using this mark mechanism with lots of colors has one
+%D major drawback: \TEX's memory tends to overflow when
+%D very colorful text is stored in a global box. Even worse is that
+%D the processing time grows considerably. We therefore support
+%D local as well as global color switching.
+%D
+%D Of the next macros, \type {\popcolor} is to be used after
+%D the actual \type {\shipout} and \type {\startcolorpage} and
+%D \type {\stopcolorpage} are called when entering and leaving
+%D the \type {\pagebody} builder. In case of emergencies
+%D \type {\pushcolor} can be used to undo the current color,
+%D for instance when insertions are appended to the page.
+%D
+%D Out of efficiency we only use marks when needed. The next
+%D macro tries to find out if indeed a mark should be set.
+%D This macro uses the boolean \type {\ifinpagebody}, which can
+%D be defined and set in the module that handles the pagebody.
+
+\def\docolormark#1%
+ {\iflocalcolor \else \ifinpagebody \else \ifinframed \else
+ \dodocolormark{#1}%
+ \fi \fi \fi}
+
+\let\lastcolormark=\empty
+
+\def\dodocolormark#1%
+ {\edef\newcolormark{#1}%
+ \ifx\newcolormark\lastcolormark\else
+ \global\let\lastcolormark\newcolormark
+ \@EA\rawsetmark\@EA\colormark\@EA{\lastcolormark}%
+ \fi}
+
+%D \macros
+%D {pushcolor, popcolor}
+%D
+%D Pushing the current state in the output routine simply comes
+%D to resetting the color to black, while popping restores the
+%D color state to that of before the break.
+
+\def\topofpagecolor{\rawgetbotmark\colormark} % see postponing
+
+\def\pushcolor
+ {\stopcolormode}
+
+\def\popcolor
+ {\doifsomething{\rawgetbotmark\colormark}
+ {%\debuggerinfo\m!colors{popping \getbotmark\colormark}%
+ \startcolormode{\rawgetbotmark\colormark}}}
+
+\def\popsplitcolor
+ {\getsplitmarks\colormark % hier wel
+ \doifsomething{\rawgetsplitbotmark\colormark}
+ {%\debuggerinfo\m!colors{split popping \getsplitbotmark\colormark}%
+ \startcolormode{\rawgetsplitbotmark\colormark}}}
+
+\appendtoks\pushcolor \to\everypushproperties
+\appendtoks\popcolor \to\everypopproperties
+\appendtoks\popsplitcolor\to\everypopsplitproperties
+
+% Private macro: only needed in test cases (like multiple
+% seperations in one file); no user command!
+
+\def\resynccolor
+ {\ifcase\pagetotal % \ifdim\pagetotal=\zeropoint
+ \popcolor
+ \else\ifx\@@currentcolor\empty
+ \ifx\maintextcolor\empty\else
+ \startcolormode\maintextcolor
+ \fi
+ \else
+ \startcolormode\@@currentcolor
+ \fi\fi}
+
+% weird stuff
+
+\def\pushpostponedpagecolor
+ {\edef\savedtopofpagecolor{\topofpagecolor}%
+ \doifsomething\savedtopofpagecolor\restorecolormode} % \stopcolormode
+
+\def\poppostponedpagecolor
+ {\doifsomething\savedtopofpagecolor\startcolormode\savedtopofpagecolor}
+
+%D \macros
+%D {startcolorpage, stopcolorpage}
+%D
+%D Local use can be forced with the next two macros. Nesting
+%D is still supported but colors are no longer marked.
+%D
+%D The next implementation makes (simple) color separation more
+%D easy. It also supports nested colors in page backgrounds
+%D and texts.
+
+\def\startcolorpage
+ {\bgroup
+ \let\@@colorplus \minusone
+ \let\@@colorminus\plusone
+ \let\docolormark\gobbleoneargument
+ \edef\savedcolorlevel{\the\colorlevel}%
+ \global\colorlevel\zerocount % before \localstartcolor of
+ \ifx\maintextcolor\empty % course, ugly bug removed
+ \localstartcolor[\defaulttextcolor]%
+ \else
+ \localstartcolor[\maintextcolor]%
+ \fi}
+
+\def\stopcolorpage
+ {\localstopcolor
+ \global\colorlevel\savedcolorlevel
+ \egroup}
+
+\appendtoks \startcolorpage\to\everystarttextproperties
+\prependtoks\stopcolorpage \to\everystoptextproperties
+
+%D We want color support to be similar to font support and
+%D therefore implement \type{\color} using grouping.
+%D
+%D When \type {\somecolor} is issued, we can savely assume
+%D grouping. Using \type {\groupedcommand} here (i.e.\ the
+%D definition of \type {\color}) is unsafe because in
+%D interferes with for instance switching attributes.
+
+\unexpanded\def\color[#1]%
+ {\groupedcommand{\startcolor[#1]}\stopcolor}
+
+%D This implementation enables use of defined colors like:
+%D
+%D \starttyping
+%D Look at the {\brightgreen bright} side of life and get
+%D yourself no \red{red} head!
+%D \stoptyping
+
+%D Also wrong, test in combinations: \type{...{}{\red test}}
+%D
+%D \def\switchtocolor[#1]%
+%D {\startcolor[#1]\aftergroup\stopcolor}
+
+\def\switchtocolor[#1]% grouping is realy needed, else migration
+ {\bgroup\startcolor[#1]\aftergroup\stopcolor\aftergroup\egroup}
+
+\unexpanded\def\color[#1]%
+ {\groupedcommand{\startcolor[#1]}\stopcolor}
+
+\unexpanded\def\graycolor[#1]% not \gray because this is a color
+ {\groupedcommand{\RGBsupportedfalse\CMYKsupportedfalse\SPOTsupportedfalse\startcolor[#1]}\stopcolor}
+
+\unexpanded\def\colored[#1]%
+ {\groupedcommand{\definecolor[@colored@][#1]\startcolor[@colored@]}\stopcolor}
+
+%D We can speed the following macros a bit up, but this
+%D hardly pays off; they are only used in the manual.
+
+\def\realcolorformat#1%
+ {\ifnum#1<\plusten 0.00\the#1\else
+ \ifnum#1<\plushundred 0.0\the#1\else
+ \ifnum#1<\plusthousand 0.\the#1\else
+ 1.000\fi\fi\fi}
+
+\def\dodoformatcolor#1%
+ {\colordimen#1\points\relax
+ \ifdim\colordimen>\onepoint
+ \colordimen\onepoint
+ \fi
+ \multiply\colordimen \plusthousand
+ \colorcount\colordimen
+ \advance\colorcount \medcard
+ \divide\colorcount \maxcard \relax
+ \realcolorformat\colorcount}
+
+\def\doformatcolorR#1:#2:#3:#4:#5\od
+ {\dodoformatcolor{#1}\colorformatseparator
+ \dodoformatcolor{#2}\colorformatseparator
+ \dodoformatcolor{#3}}
+
+\def\doformatcolorC#1:#2:#3:#4:#5:#6\od
+ {\dodoformatcolor{#1}\colorformatseparator
+ \dodoformatcolor{#2}\colorformatseparator
+ \dodoformatcolor{#3}\colorformatseparator
+ \dodoformatcolor{#4}}
+
+\def\doformatcolorS#1:#2:#3\od
+ {\dodoformatcolor{#1}}
+
+\def\doformatcolorP#1:#2:#3:#4:#5:#6\od
+ {#1\colorformatseparator
+ \dodoformatcolor{#2}\colorformatseparator
+ \dodoformatcolor{#3}\colorformatseparator
+ \dodoformatcolor{#4}\colorformatseparator}
+
+\def\doformatcolor#1:%
+ {\csname doformatcolor#1\endcsname}
+
+\def\colorvalue
+ {\dowithcolor\doformatcolor}
+
+\def\doformatgrayR#1:#2:#3:#4:#5\od
+ {\convertRGBtoGRAY{#1}{#2}{#3}%
+ \dodoformatcolor\@@cl@@s}
+
+\def\doformatgrayC#1:#2:#3:#4:#5:#6\od
+ {\convertCMYKtoGRAY{#1}{#2}{#3}{#4}%
+ \dodoformatcolor\@@cl@@s}
+
+\def\doformatgrayS#1:#2:#3\od
+ {\dodoformatcolor{#1}}
+
+% \def\doformatgrayP#1:#2:#3:#4:#5:#6\od
+% {\convertSPOTtoGRAY{#1}{#2}{#3}{#4}%
+% \dodoformatcolor\@@cl@@s}
+
+\def\doformatgrayP#1:#2:#3:#4:#5:#6\od
+ {todo}
+
+\def\doformatgray#1:%
+ {\csname doformatgray#1\endcsname}
+
+\def\grayvalue
+ {\dowithcolor\doformatgray}
+
+%D \macros
+%D {localstartraster,localstopraster,
+%D startraster,stopraster}
+%D
+%D The previous conversions are not linear and treat each color
+%D component according to human perception curves. Pure gray
+%D (we call them rasters) has equal color components. In
+%D \CONTEXT\ rasters are only used as backgrounds and these
+%D don't cross page boundaries in the way color does. Therefore
+%D we don't need stacks and marks. Just to be compatible with
+%D color support we offer both 'global' and 'local' commands.
+%D
+%D \starttyping
+%D \def\localstartraster[#1]%
+%D {\doifelsenothing{#1}
+%D {\dostartgraymode\@@rsscreen}
+%D {\dostartgraymode{#1}}}
+%D
+%D \def\localstopraster
+%D {\dostopgraymode}
+%D
+%D \let\startraster\localstartraster
+%D \let\stopraster \localstopraster
+%D \stoptyping
+%D
+%D The next alternative is slower, since it works on top of the
+%D color (stack) mechanism, but it does provide nesting.
+
+\def\dosetrastercolor#1%
+ {\edef\@@cl@@s{#1}%
+ \ifx\@@cl@@s\empty
+ \let\@@cl@@s\@@rsscreen
+ \fi
+ \let\@@cl@@t\@@cl@@z % else we get rogue
+ \let\@@cl@@a\@@cl@@z % transpancies
+ \setevalue{\??cr\??rs}{\colorSpattern}}
+
+% beware, don't add extra grouping, else color in tables
+% fails
+
+\def\localstartraster[#1]%
+ {\ifincolor\dosetrastercolor{#1}\localstartcolor[\??rs]\fi}
+
+\def\startraster[#1]%
+ {\ifincolor\dosetrastercolor{#1}\startcolor[\??rs]\fi}
+
+\def\localstopraster{\ifincolor\localstopcolor\fi}
+\def\stopraster {\ifincolor\stopcolor\fi}
+
+\def\raster[#1]{\groupedcommand{\startraster[#1]}{\stopraster}}
+
+%D Palets use an auxiliary macro:
+
+\def\dodefinepaletcolor#1#2#3%
+ {\doifassignmentelse{#3}
+ {% == \definepalet[test][xx={y=.4}]
+ \definecolor[\??pa#1:#2][#3]%
+ \iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{\??cr#1:#2}{\csname\??cr\??pa#1:#2\endcsname}}
+ {% == \definepalet[test][xx=green]
+ \doifdefinedelse{\??cr#3}
+ {\iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{\??cr#1:#2}{\csname\??cr#3\endcsname}}
+ {\letvalue{\??cr#1:#2}\colorXpattern}}}
+
+%D \MP\ related conversions:
+
+\def\scaledMPcolor#1#2%
+ {\ifMPgraphics
+ \handlecolorwith\doMPcolor
+ \csname\??cr
+ \ifcsname\??cr\currentpalet#2\endcsname\currentpalet\fi
+ #2\endcsname
+ :::::::\end#1\end
+ \else
+ #2%
+ \fi}
+
+\def\MPcolor{\scaledMPcolor1}
+
+%D Before we had transparency available, the following
+%D conversion macro was available:
+%D
+%D \starttyping
+%D \def\doMPcolor#1:#2:#3:#4:#5:#6:#7:#8\end
+%D {\if #1R(#2,#3,#4)%
+%D \else\if#1C\ifMPcmykcolors cmyk(#2,#3,#4,#5)\else(1-#2-#5,1-#3-#5,1-#4-#5)\fi
+%D \else\if#1S(#2,#2,#2)%
+%D \else (0,0,0)%
+%D \fi\fi\fi}
+%D \stoptyping
+%D
+%D In order to be useful, this macro is to be fully
+%D expandabele.
+
+\def\doMPcolor#1:% #1 can be \relax ! ! ! i.e. an empty color
+ {\csname MPc\@EA\ifx\csname MPc\string#1\endcsname\relax B\else#1\fi\endcsname}
+
+\def\MPcR{\doMPrgb}
+\def\MPcC{\ifMPcmykcolors\@EA\doMPcmykY\else\@EA\doMPcmykN\fi}
+\def\MPcS{\doMPgray}
+\def\MPcP{\ifMPspotcolors\@EA\doMPspotY\else\@EA\doMPspotN\fi}
+\def\MPcB{\doMPblack}
+
+\def\transparentMP {transparent}
+\def\cmykMP {scaledcmyk}
+\def\cmykASrgbMP {scaledcmykasrgb} % not really needed any more
+\def\rgbMP {scaledrgb}
+\def\grayMP {scaledgray}
+\def\spotMP {spotcolor}
+
+\def\doMPtransparent#1#2:#3:#4\end
+ {\ifcase#2\space(#1)\else\transparentMP(#2,#3,(#1))\fi}
+
+\def\doMPgray#1:#2\end#3\end
+ {\doMPtransparent{\grayMP(#1,#3)}#2\end}
+
+\def\doMPrgb#1:#2:#3:#4\end#5\end
+ {\doMPtransparent{\rgbMP(#1,#2,#3,#5)}#4\end}
+
+\def\doMPcmykY#1:#2:#3:#4:#5\end#6\end
+ {\doMPtransparent{\cmykMP(#1,#2,#3,#4,#6)}#5\end}
+
+\def\doMPcmykN#1:#2:#3:#4:#5\end#6\end
+ {\doMPtransparent{\cmykASrgbMP(#1,#2,#3,#4,#6)}#5\end}
+
+\def\doMPspotY#1:#2:#3:#4:#5\end#6\end % best make #3 same as #1 when empty
+ {\doMPtransparent{multitonecolor("#1",#2,"#3","#4")}#5\end}
+
+\def\doMPspotN#1:#2:#3:#4:#5\end#6\end
+ {\scaledMPcolor{#4}{#1}}
+
+\def\doMPblack#1\end#2\end
+ {\unknownMPcolor}
+
+\def\unknownMPcolor
+ {(0,0,0)}
+
+\let\processMP\spotMP % for some time, will become obsolete, brrr
+
+%D \PDF\ related conversions:
+
+\def\PDFcolor #1{\handlecolorwith\doPDFcolor \csname\??cr#1\endcsname:::::::\end}
+\def\PDFcolorvalue#1{\handlecolorwith\doPDFcolorvalue\csname\??cr#1\endcsname:::::::\end}
+\def\FDFcolor #1{\handlecolorwith\doFDFcolor \csname\??cr#1\endcsname:::::::\end}
+
+\def\doPDFcolor#1:#2:#3:#4:#5:#6:#7:#8\end
+ {\if #1R#2 #3 #4 rg%
+ \else\if#1C#2 #3 #4 #5 k%
+ \else\if#1S#2 g%
+ \else\if#1P#5 g%
+ \else 0 g%
+ \fi\fi\fi\fi}
+
+\def\doPDFcolorvalue#1:#2:#3:#4:#5:#6:#7:#8\end
+ {\if #1R#2 #3 #4%
+ \else\if#1C#2 #3 #4 #5%
+ \else\if#1S#2%
+ \else\if#1P#5%
+ \else 0%
+ \fi\fi\fi\fi}
+
+\def\doFDFcolor#1:#2:#3:#4:#5:#6:#7:#8\end
+ {[\if #1R#2 #3 #4%
+ \else\if#1C#2 #3 #4 #5%
+ \else\if#1S#2%
+ \else\if#1P#5%
+ \else 0%
+ \fi\fi\fi\fi]}
+
+\def\internalspotcolorname#1{\handlecolorwith\dointernalspotcolorname\csname\??cr#1\endcsname:::::::\end}
+\def\internalspotcolorsize#1{\handlecolorwith\dointernalspotcolorsize\csname\??cr#1\endcsname:::::::\end}
+
+\def\dointernalspotcolorname#1:#2:#3:#4:#5:#6:#7:#8\end{\if#1P\ifcase0#3 #1\else#2\fi\else#1\fi}
+\def\dointernalspotcolorsize#1:#2:#3:#4:#5:#6:#7:#8\end{\if#1P\ifcase0#3 0\else#3\fi\else 0\fi}
+
+%D Slow but ok \unknown
+
+\def\colorcomponents#1% might be broken
+ {\startnointerference
+ \localcolortrue
+ \globallet\thecolorcomponents\empty
+ \def\doexeccolorR ##1:##2:##3:##4:##5\od{\gdef\thecolorcomponents{r=\twodigitrounding{##1} g=\twodigitrounding{##2} b=\twodigitrounding{##3}}}%
+ \def\doexeccolorC##1:##2:##3:##4:##5:##6\od{\gdef\thecolorcomponents{c=\twodigitrounding{##1} m=\twodigitrounding{##2} y=\twodigitrounding{##3} k=\twodigitrounding{##4}}}%
+ \def\doexeccolorS ##1:##2:##3\od{\gdef\thecolorcomponents{s=\twodigitrounding{##1}}}%
+ \def\doexeccolorP##1:##2:##3:##4:##5:##6\od{\gdef\thecolorcomponents{p=\twodigitrounding{##4} n=##1}}%
+ \let\doexeccolorPindex\doexeccolorP
+ \backgroundline[#1]{}%
+ \stopnointerference
+ \thecolorcomponents}
+
+\def\transparencycomponents#1%
+ {\startnointerference
+ \localcolortrue
+ \globallet\thetransparencycomponents\empty
+ \def\doexeccolorR ##1:##2:##3:##4:##5\od{\gdef\thetransparencycomponents{a=\twodigitrounding{##4} t=\twodigitrounding{##5}}}%
+ \def\doexeccolorC##1:##2:##3:##4:##5:##6\od{\gdef\thetransparencycomponents{a=\twodigitrounding{##5} t=\twodigitrounding{##6}}}%
+ \def\doexeccolorS ##1:##2:##3\od{\gdef\thetransparencycomponents{a=\twodigitrounding{##2} t=\twodigitrounding{##3}}}%
+ \def\doexeccolorP##1:##2:##3:##4:##5:##6\od{\gdef\thetransparencycomponents{a=\twodigitrounding{##5} t=\twodigitrounding{##6}}}%
+ \let\doexeccolorPindex\doexeccolorP
+ \backgroundline[#1]{}%
+ \stopnointerference
+ \thetransparencycomponents}
+
+%D \macros
+%D {everyshapebox}
+%D
+%D A terrible hack, needed because we cannot have marks in
+%D shape boxes.
+
+\appendtoks \localcolortrue \to \everyshapebox
+
+%D \macros
+%D {forcecolorhack}
+%D
+%D Awful \unknown
+
+\let\forcecolorhack\relax
+
+%D We default to the colors defined in \module{colo-rgb} and
+%D support both \cap{RGB} and \cap{CMYK} output. As you can
+%D see, color support is turned off by default. Reduction of
+%D gray colors to gray scales is turned on.
+
+\definecolor[black][s=0]
+\definecolor[white][s=1]
+
+\definetransparency [none] [0]
+\definetransparency [normal] [1]
+\definetransparency [multiply] [2]
+\definetransparency [screen] [3]
+\definetransparency [overlay] [4]
+\definetransparency [softlight] [5]
+\definetransparency [hardlight] [6]
+\definetransparency [colordodge] [7]
+\definetransparency [colorburn] [8]
+\definetransparency [darken] [9]
+\definetransparency [lighten] [10]
+\definetransparency [difference] [11]
+\definetransparency [exclusion] [12]
+
+\setupcolors
+ [\c!state=\v!stop,
+ \c!conversion=\v!yes,
+ \c!reduction=\v!no,
+ \c!rgb=\v!yes,
+ \c!cmyk=\v!yes,
+ \c!spot=\v!yes,
+ \c!mp\c!cmyk=\@@clcmyk,
+ \c!mp\c!spot=\@@clspot,
+ \c!expansion=\v!no,
+ \c!textcolor=,
+ \c!split=\v!no,
+ \c!criterium=\v!all]
+
+\setupcolor
+ [\v!rgb]
+
+\protect \endinput
diff --git a/tex/context/base/colo-ini.mkiv b/tex/context/base/colo-ini.mkiv
new file mode 100644
index 000000000..1bceb5aa7
--- /dev/null
+++ b/tex/context/base/colo-ini.mkiv
@@ -0,0 +1,1091 @@
+%D \module
+%D [ file=colo-ini,
+%D version=2007.08.08,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Initialization,
+%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.
+
+%D We need to clean this up further but first we hav eto make sure that mkiv
+%D code works ok.
+
+\writestatus{loading}{ConTeXt Color Macros / Initialization}
+
+%D This module implements color. Since \MKII\ and \MKIV\ use a completely
+%D different approach, this module only implements a few generic mechanisms.
+
+\registerctxluafile{colo-ini}{1.000}
+\registerctxluafile{lpdf-col}{1.000}
+
+\unprotect
+
+%D We use a couple of local registers. That way we don't have
+%D to group when converting colors. By the way, this is not
+%D really faster. We can sqeeze half a second runtime for 50K
+%D switches on a 1G machine, but the macros will become rather
+%D ugly then. To mention one such improvement: no colon
+%D after the key character (.25 sec).
+
+\newcount\colorcount
+
+%D When typesetting for paper, we prefer using the \cap{CMYK}
+%D color space, but for on||screen viewing we prefer \cap{RGB}
+%D (the previous implementation supported only this scheme).
+%D Independant of such specifications, we support some automatic
+%D conversions:
+%D
+%D \startitemize[packed]
+%D \item convert all colors to \cap{RGB}
+%D \item convert all colors to \cap{CMYK}
+%D \item convert all colors to gray scales
+%D \stopitemize
+%D
+%D We also support optimization of colors to gray scales.
+%D
+%D \startitemize[continue]
+%D \item reduce gray colors to gray scales
+%D \item reduce \cap{CMY} components to \cap{K}
+%D \stopitemize
+%D
+%D These options are communicated by means of:
+
+\newif\ifRGBsupported
+\newif\ifCMYKsupported
+\newif\ifSPOTsupported
+\newif\ifpreferGRAY
+\newif\ifGRAYprefered
+\newif\ifconvertGRAY \convertGRAYtrue
+\newif\ifreduceCMYK
+\newif\ifconverttoGRAY
+\newif\ifweightGRAY \weightGRAYtrue
+
+\newif\ifconvertMPcolors
+\newif\ifreduceMPcolors
+\newif\ifforcegrayMPcolors
+
+%D The last boolean controls reduction of \cap{CMYK} to
+%D \cap{CMY} colors. When set to true, the black component
+%D is added to the other ones.
+%D
+%D Prefering gray is not the same as converting to gray.
+%D Conversion treats each color components in a different way,
+%D while prefering is just a reduction and thus a
+%D space||saving option.
+
+\newif\iffreezecolors \freezecolorsfalse
+\newif\ifincolor % true if colors enabled
+
+\let\colorlist \empty
+\let\currentspotcolor \empty
+\let\allspotcolors \empty
+\let\usedspotcolors \empty
+\let\currentpalet \empty
+
+%D \macros
+%D {definecolor,defineglobalcolor,definenamedcolor,definespotcolor,definemultitonecolor}
+%D
+%D \startbuffer
+%D \definecolor [blue] [c=1,m=.38,y=0,k=.64] % pantone pms 2965 uncoated m
+%D \definecolor [yellow] [c=0,m=.28,y=1,k=.06] % pantone pms 124 uncoated m
+%D
+%D \definespotcolor [blue-100] [blue] [p=1]
+%D \definespotcolor [yellow-100] [yellow] [p=1]
+%D
+%D \definemultitonecolor [pdftoolscolor] [blue=.12,yellow=.28] [c=.1,m=.1,y=.3,k=.1]
+%D
+%D \useexternalfigure[demofig][mill.png][object=no]
+%D
+%D \startcombination[4*1]
+%D {\externalfigure[demofig]} {no color}
+%D {\externalfigure[demofig][color=pdftoolscolor]} {indexed duotone}
+%D {\externalfigure[demofig][color=blue-100]} {spot color}
+%D {\externalfigure[demofig][color=yellow-100]} {spot color}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \getbuffer \typebuffer
+
+\unexpanded\def\definecolor {\dodoubleargument\dodefinecolor}
+\unexpanded\def\defineglobalcolor {\dodoubleargument\dodefineglobalcolor}
+\unexpanded\def\definenamedcolor {\dodoubleargument\dodefinenamedcolor}
+\unexpanded\def\definespotcolor {\dotripleargument\dodefinespotcolor}
+\unexpanded\def\definemultitonecolor{\doquadrupleempty\dodefinemultitonecolor}
+
+%D \macros
+%D {startcolor,stopcolor,
+%D faststartcolor,faststopcolor,
+%D startraster,stopraster,raster,
+%D color,graycolor}
+%D
+%D The local and global and raster commands are here just
+%D for compatibility with \MKII.
+%D
+%D \showsetup{startcolor}
+%D
+%D \macros
+%D {color,graycolor}
+%D
+%D This leaves the simple color command:
+%D
+%D \showsetup{color}
+%D \showsetup{graycolor}
+%D
+%D This leaves the simple color command:
+%D
+%D \showsetup{color}
+%D \showsetup{graycolor}
+
+ \def\switchtocolor [#1]{\getvalue{#1}}
+\unexpanded\def\color [#1]{\groupedcommand{\doactivatecolor{#1}}{}}
+\unexpanded\def\startcolor [#1]{\begingroup\doactivatecolor{#1}}
+\unexpanded\def\stopcolor {\endgroup}
+\unexpanded\def\graycolor [#1]{\groupedcommand{\dosetcolormodel{gray}\getvalue{#1}}{}}
+\unexpanded\def\colored [#1]{\groupedcommand{\definecolor[@colored@][#1]\doactivatecolor{@colored@}}{}}
+\unexpanded\def\fastcolored [#1]#2{\begingroup\dodefinefastcolor[@colored@][#1]\doactivatecolor{@colored@}#2\endgroup}
+ \def\predefinecolor [#1]{\flushatshipout{\hbox{\color[#1]{}}}}
+ \def\predefineindexcolor[#1]{\flushatshipout{\hbox{\color[#1]{}}}}
+ \unexpanded\def\startcolorpage {\startcolor[\ifx\maintextcolor\empty\defaulttextcolor\else\maintextcolor\fi]}
+ \unexpanded\def\stopcolorpage {\stopcolor}
+ \unexpanded\def\startraster [#1]{\dosetrastercolor{#1}}
+ \unexpanded\def\stopraster {}
+ \def\raster [#1]{\groupedcommand{\dosetrastercolor{#1}}{}}
+ \def\faststartcolor [#1]{\doactivatecolor{#1}}
+ \def\faststopcolor {}
+\unexpanded\def\dosetcolorattribute#1#2{\ifcsname#1#2\endcsname\doactivatecolor{\csname#1#2\endcsname}\fi}
+
+\let\grey\graycolor
+
+%D Stacking:
+
+% \colormodelattribute \colorattribute \transparencyattribute
+
+\newcount\currentcolornesting
+
+\unexpanded\def\pushcolor[#1]%
+ {\global\advance\currentcolornesting\plusone
+ \expandafter\edef\csname\??cl:s:\number\currentcolornesting\endcsname
+ {\attribute\colormodelattribute \the\attribute\colormodelattribute
+ \attribute\colorattribute \the\attribute\colorattribute
+ \attribute\transparencyattribute\the\attribute\transparencyattribute
+ \space}% stack
+ \doactivatecolor{#1}}
+
+\unexpanded\def\popcolor
+ {\csname\??cl:s:\number\currentcolornesting\endcsname
+ \global\advance\currentcolornesting\minusone}
+
+%D \macros
+%D {startcurrentcolor,stopcurrentcolor}
+
+\unexpanded\def\startcurrentcolor{\startcolor[\outercolorname]}
+\unexpanded\def\stopcurrentcolor {\stopcolor}
+
+%D \macros
+%D {setupcolor}
+%D
+%D Color definitions can be grouped in files with the name:
+%D
+%D \starttyping
+%D \f!colorprefix-identifier.tex
+%D \stoptyping
+%D
+%D where \type{\f!colorprefix} is \unprotect {\tttf \f!colorprefix}.
+%D Loading such a file is done by \protect
+%D
+%D \showsetup{setupcolor}
+%D
+%D Some default colors are specified in \type{colo-rgb.tex},
+%D which is loaded into the format by:
+%D
+%D \starttyping
+%D \setupcolor[rgb]
+%D \stoptyping
+
+\let\colorstyle\empty
+
+\unexpanded\def\setupcolor
+ {\dosingleargument\dosetupcolor}
+
+\def\dosetupcolor[#1]%
+ {\doifnot{#1}\colorstyle
+ {\def\colorstyle{#1}%
+ \processcommalist[#1]\dodosetupcolor}}
+
+\def\dodosetupcolor#1%
+ {\makeshortfilename[\truefilename{\f!colorprefix#1}]%
+ \startreadingfile
+ \readsysfile\shortfilename
+ {\showcolormessage\m!colors4\colorstyle}
+ {\showcolormessage\m!colors5\colorstyle}%
+ \stopreadingfile}
+
+\let\usecolors\setupcolor
+
+% check: \startcolormode
+
+%D \macros
+%D {definetransparency}
+%D
+%D This command numbers to names:
+
+\unexpanded\def\definetransparency
+ {\dodoubleargument\dodefinetransparency}
+
+\unexpanded\def\setupcolors
+ {\dosingleargument\dosetupcolors}
+
+\let\showcolormessage\gobblethreearguments
+
+\newtoks\everysetupcolors
+
+\def\dosetupcolors[#1]% some no longer make sense in MkIV
+ {\getparameters[\??cl][#1]%
+ \doifelse\@@clspot\v!yes
+ \SPOTsupportedtrue
+ \SPOTsupportedfalse
+ \doifelse\@@clreduction\v!yes
+ \reduceCMYKtrue
+ \reduceCMYKfalse
+ \doifelse\@@clexpansion\v!yes
+ \freezecolorstrue
+ \freezecolorsfalse
+ \doifelse\@@clfactor\v!no
+ \weightGRAYfalse
+ \weightGRAYtrue
+ \doifelse\@@clrgb\v!no
+ {\ifRGBsupported \showcolormessage\m!colors {9}\v!rgb \RGBsupportedfalse \fi}
+ {\ifRGBsupported \else\showcolormessage\m!colors{10}\v!rgb \RGBsupportedtrue \fi}%
+ \doifelse\@@clcmyk\v!no
+ {\ifCMYKsupported \showcolormessage\m!colors {9}\v!cmyk \CMYKsupportedfalse\fi}
+ {\ifCMYKsupported\else\showcolormessage\m!colors{10}\v!cmyk \CMYKsupportedtrue \fi}%
+ \doifelse\@@clmpcmyk\v!no
+ {\ifMPcmykcolors \showcolormessage\m!colors {9}{\v!mp\v!cmyk}\MPcmykcolorsfalse \fi}
+ {\ifMPcmykcolors \else\showcolormessage\m!colors{10}{\v!mp\v!cmyk}\MPcmykcolorstrue \fi}%
+ \doifelse\@@clmpspot\v!no
+ {\ifMPspotcolors \showcolormessage\m!colors {9}{\v!mp\v!spot}\MPspotcolorsfalse \fi}
+ {\ifMPspotcolors \else\showcolormessage\m!colors{10}{\v!mp\v!spot}\MPspotcolorstrue \fi}%
+ \preferGRAYfalse
+ \convertGRAYtrue
+ \processaction
+ [\@@clconversion]
+ [ \v!yes=>\preferGRAYtrue,
+ \v!no=>\convertGRAYfalse,
+ \v!never=>\convertGRAYfalse,
+ \v!always=>\preferGRAYtrue\RGBsupportedfalse\CMYKsupportedfalse]%
+ \ifRGBsupported
+ \converttoGRAYfalse
+ \forcegrayMPcolorsfalse
+ \else\ifCMYKsupported
+ \converttoGRAYfalse
+ \forcegrayMPcolorsfalse
+ \convertMPcolorstrue
+ \ifreduceCMYK
+ \reduceMPcolorstrue
+ \fi
+ \else
+ \ifconverttoGRAY\else\showcolormessage\m!colors{11}\empty\fi
+ \converttoGRAYtrue
+ \forcegrayMPcolorstrue
+ \convertMPcolorsfalse
+ \reduceMPcolorsfalse
+ \fi\fi
+ \doifelse\@@clstate\v!stop
+ {\incolorfalse\forcegrayMPcolorstrue}%
+ {\ifincolor\else\showcolormessage\m!colors1\colorstyle\fi\incolortrue\let\@@clstate\v!start}%
+ \dosetupcolormodel
+ \the\everysetupcolors}
+
+%D In this documentation we will not go into too much details
+%D on palets. Curious users can find more information on this
+%D topic in \from[use of color].
+%D
+%D At the moment we implemented color in \CONTEXT\ color
+%D printing was not yet on the desktop. In spite of this lack our
+%D graphics designer made colorfull illustrations. When printed
+%D on a black and white printer, distinctive colors can come
+%D out equally gray. We therefore decided to use only colors
+%D that were distinctive in colors as well as in black and
+%D white print.
+%D
+%D Although none of the graphic packages we used supported
+%D logical colors and global color redefition, we build this
+%D support into \CONTEXT. This enabled us to experiment and
+%D also prepared us for the future.
+
+%D \macros
+%D {definepalet}
+%D
+%D Colors are grouped in palets. The colors in such a palet can
+%D have colorful names, but best is to use names that specify
+%D their use, like {\em important} or {\em danger}. As a sort
+%D of example \CONTEXT\ has some palets predefined,
+%D like:\footnote{At the time I wrote the palet support, I was
+%D reading 'A hort history of time' of S.~Hawkins, so that's
+%D why we stuck to quarks.}
+%D
+%D \starttyping
+%D \definepalet
+%D [alfa]
+%D [ top=rood:7,
+%D bottom=groen:6,
+%D up=blauw:5,
+%D down=cyaan:4,
+%D strange=magenta:3,
+%D charm=geel:2]
+%D \stoptyping
+%D
+%D It's formal definition is:
+%D
+%D \showsetup{definepalet}
+%D
+%D Visualized, such a palet looks like:
+%D
+%D \startbuffer[palet]
+%D \showpalet [alfa] [horizontal,name,number,value]
+%D \stopbuffer
+%D
+%D \startlinecorrection
+%D \getbuffer[palet]
+%D \stoplinecorrection
+%D
+%D This bar shows both the color and gray alternatives of the
+%D palet components (not visible in black and white print).
+%D
+%D When needed, one can copy a palet by saying:
+%D
+%D \starttyping
+%D \definepalet [TEXcolorpretty] [colorpretty]
+%D \stoptyping
+%D
+%D This saves us some typing in for instance the modules that
+%D deal with pretty verbatim typesetting.
+
+\unexpanded\def\definepalet
+ {\dodoubleargument\dodefinepalet}
+
+\def\dodefinepalet[#1][#2]%
+ {\doifassignmentelse{#2}
+ {%\showcolormessage\m!colors6{#1}%
+ \letvalue{\??pa#1}\empty
+ \setevalue{\??pa\??pa#1}{#2}%
+ \def\dodododefinepalet[##1=##2]%
+ {\doifvaluesomething{\??pa#1}
+ {\setevalue{\??pa#1}{\csname\??pa#1\endcsname,}}%
+ \setevalue{\??pa#1}{\csname\??pa#1\endcsname##1}%
+ \dodefinepaletcolor{#1}{##1}{##2}}%
+ \def\dododefinepalet##1%
+ {\dodododefinepalet[##1]}%
+ \processcommalist[#2]\dododefinepalet}
+ {\doifdefined{\??pa#2}
+ {\expanded{\dodefinepalet[#1][\csname\??pa\??pa#2\endcsname]}}}}
+
+\let\paletsize\!!zerocount
+
+\def\getpaletsize[#1]%
+ {\getcommacommandsize[\csname\??pa\??pa#1\endcsname]%
+ \edef\paletsize{\number\commalistsize}}
+
+%D Instead of refering to colors, one can also directly specify
+%D a color:
+%D
+%D \starttyping
+%D \definepalet[test][xx=green]
+%D \definepalet[test][xx={y=.4}]
+%D \stoptyping
+
+%D \macros
+%D {setuppalet}
+%D
+%D Colors are taken from the current palet, if defined.
+%D Setting the current palet is done by:
+%D
+%D \showsetup{setuppalet}
+
+\let\currentpalet\empty
+
+\unexpanded\def\setuppalet
+ {\dosingleempty\dosetuppalet}
+
+\def\dosetuppalet[#1]%
+ {\edef\currentpalet{#1}%
+ \ifx\currentpalet\empty
+ % seems to be a reset
+ \else\ifcsname\??pa\currentpalet\endcsname
+ \edef\currentpalet{#1:}%
+ \else
+ \showcolormessage\m!colors7\currentpalet
+ \let\currentpalet\empty
+ \fi\fi
+ \initializemaintextcolor}
+
+%D \macros
+%D {showpalet}
+%D
+%D The previous visualization was typeset with:
+%D
+%D \typebuffer[palet]
+%D
+%D This commands is defined as:
+%D
+%D \showsetup{showpalet}
+
+\fetchruntimecommand \showpalet {\f!colorprefix\s!run}
+
+%D \macros
+%D {showcolorcomponents}
+%D
+%D \starttyping
+%D \showcolorcomponents[color-1,color-2]
+%D \stoptyping
+
+\fetchruntimecommand \showcolorcomponents {\f!colorprefix\s!run}
+
+%D \macros
+%D {definecolorgroup}
+%D
+%D The naming of the colors in this palet suggests some
+%D ordening, which in turn is suported by color grouping.
+%D
+%D \starttyping
+%D \definecolorgroup
+%D [red]
+%D [1.00:0.90:0.90,
+%D 1.00:0.80:0.80,
+%D 1.00:0.70:0.70,
+%D 1.00:0.55:0.55,
+%D 1.00:0.40:0.40,
+%D 1.00:0.25:0.25,
+%D 1.00:0.15:0.15,
+%D 0.90:0.00:0.00]
+%D \stoptyping
+%D
+%D In such a color group colors are numbered from~$1$ to~$n$.
+%D
+%D \showsetup{definecolorgroup}
+%D
+%D This kind of specification is not only more compact than
+%D defining each color separate, it also loads faster and takes
+%D less bytes.
+
+\unexpanded\def\definecolorgroup
+ {\dotripleempty\dodefinecolorgroup}
+
+\def\dododefinecolorgroupgray [#1][#2:#3]{\definecolor [#1:\the\colorcount][s=#2]}
+\def\dododefinecolorgrouprgb [#1][#2:#3:#4:#5]{\definecolor [#1:\the\colorcount][r=#2,g=#3,b=#4]}
+\def\dododefinecolorgroupcmyk[#1][#2:#3:#4:#5:#6]{\definecolor [#1:\the\colorcount][c=#2,m=#3=,y=#4,k=#5]}
+\def\dododefinecolorgroupspot [#1][#2:#3:#4]{\definespotcolor[#1:\the\colorcount][#2][p=#3]}
+
+\def\dododefinecolorgroup#1#2%
+ {\advance\colorcount\plusone
+ \getvalue{dododefinecolorgroup\currentcolorspace}[#1][#2:0:0:0:0]}
+
+\def\dodefinecolorgroup[#1][#2][#3]% obsolete, just use palets
+ {\ifthirdargument
+ \doifelsenothing{#2}{\let\currentcolorspace\v!rgb}{\def\currentcolorspace{#2}}%
+ \colorcount\zerocount
+ \processcommalist[#3]{\dododefinecolorgroup{#1}}%
+ \else
+ \doifinstringelse{:}{#2}
+ {\definecolorgroup[#1][\v!rgb][#2]}
+ {\doloop
+ {\ifcsname\??cr#2:\recurselevel\endcsname
+ \setevalue{\??cr#1:\recurselevel}{\csname\??cr#2:\recurselevel\endcsname}%
+ \else
+ \exitloop
+ \fi}}%
+ \fi}
+
+%D \macros
+%D {showcolorgroup}
+%D
+%D We can show the group by:
+%D
+%D \startbuffer
+%D \showcolorgroup [blue] [horizontal,name,number,value]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or in color:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D which uses:
+%D
+%D \showsetup{showcolorgroup}
+
+\fetchruntimecommand \showcolorgroup {\f!colorprefix\s!run}
+
+%D There are ten predefined color groups, like
+%D \color[green]{\em groen}, \color[red]{\em rood},
+%D \color[blue]{\em blauw}, \color[cyan]{\em cyaan},
+%D \color[magenta]{\em magenta} and \color[yellow]{\em geel}.
+%D
+%D \startlinecorrection
+%D \hbox to \hsize
+%D {\hss
+%D \showcolorgroup [red] [vertical,name,number]\hss
+%D \showcolorgroup [green] [vertical,name]\hss
+%D \showcolorgroup [blue] [vertical,name]\hss
+%D \showcolorgroup [cyan] [vertical,name]\hss
+%D \showcolorgroup [magenta][vertical,name]\hss
+%D \showcolorgroup [yellow] [vertical,name]\hss}
+%D \stoplinecorrection
+%D
+%D These groups are used to define palets {\em alfa} upto {\em
+%D zeta}. As long as we don't use colors from the same row, we
+%D get ourselves distinctive palets. By activating such a palet
+%D one gains access to its members {\em top} to {\em charm} (of
+%D course one should use more suitable names than these).
+%D
+%D \startlinecorrection
+%D \hbox to \hsize
+%D {\showpalet [alfa] [vertical,name,number]\hss
+%D \showpalet [beta] [vertical,name]\hss
+%D \showpalet [gamma] [vertical,name]\hss
+%D \showpalet [delta] [vertical,name]\hss
+%D \showpalet [epsilon] [vertical,name]\hss
+%D \showpalet [zeta] [vertical,name]}
+%D \stoplinecorrection
+%D
+%D By using the keyword \type {value} the individual color
+%D components are shown too. When printed in color, these
+%D showcases show both the colors and the gray value.
+
+%D \macros
+%D {comparepalet}
+%D
+%D There are some more testing macros available:
+%D
+%D \startbuffer
+%D \comparepalet [alfa]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows the palet colors against a background:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D The formal definition is:
+%D
+%D \showsetup{comparepalet}
+
+\fetchruntimecommand \comparepalet {\f!colorprefix\s!run}
+
+%D \macros
+%D {comparecolorgroup}
+%D
+%D The similar command:
+%D
+%D \startbuffer
+%D \comparecolorgroup [blue]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows color groups:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D this commands are defined as:
+%D
+%D \showsetup{comparecolorgroup}
+
+\fetchruntimecommand \comparecolorgroup {\f!colorprefix\s!run}
+
+%D \macros
+%D {showcolor}
+%D
+%D But let's not forget that we also have the more traditional
+%D non||related colors. These show up after:
+%D
+%D \starttyping
+%D \showcolor [name]
+%D \stoptyping
+%D
+%D Where \type{name} for instance can be \type{rgb}.
+%D
+%D \showsetup{showcolor}
+
+\fetchruntimecommand \showcolor {\f!colorprefix\s!run}
+
+%D It would make sense to put the following code in \type
+%D {colo-mps}, but it it rather low level.
+
+%D \macros
+%D {negatecolorcomponent,negatedcolorcomponent}
+%D
+%D These speak for themselves. See \type {colo-ext} for usage.
+
+\def\negatecolorcomponent#1% #1 = \macro
+ {\scratchdimen\onepoint\advance\scratchdimen-#1\onepoint
+ \ifdim\scratchdimen<\zeropoint\scratchdimen\zeropoint\fi
+ \edef#1{\withoutpt\the\scratchdimen}}
+
+\let\negatedcolorcomponent\firstofoneargument
+
+\def\negatedcolorcomponent#1%
+ {\ifdim\dimexpr\onepoint-#1\onepoint\relax<\zeropoint
+ \!!zerocount
+ \else
+ \expandafter\withoutpt\the\dimexpr\onepoint-#1\onepoint\relax
+ \fi}
+
+\def\negatecolorcomponent#1% #1 = \macro
+ {\edef#1{\negatedcolorcomponent{#1}}}
+
+%D \macros
+%D {ifMPgraphics, ifMPcmykcolors, MPcolor}
+%D
+%D A very special macro is \type{\MPcolor}. This one can be
+%D used to pass a \CONTEXT\ color to \METAPOST.
+%D
+%D \starttyping
+%D \MPcolor{my own red}
+%D \stoptyping
+%D
+%D This macro returns a \METAPOST\ triplet \type{(R,G,B)}.
+%D Unless \CMYK\ color support is turned on with \type
+%D {MPcmyk}, only \cap{RGB} colors and gray scales are
+%D supported.
+
+\newif\ifMPcmykcolors % \MPcmykcolorsfalse
+\newif\ifMPspotcolors % \MPspotcolorsfalse
+
+\ifx\MPcolor\undefined
+ \def\MPcolor#1{(0,0,0)}
+\fi
+
+%D For the moment we keep the next downward compatibility
+%D switch, i.e.\ expanded colors. However, predefined colors
+%D and palets are no longer expanded (which is what I wanted
+%D in the first place).
+%D
+%D Well, in case we want to do color separation and use CMYK
+%D colors only, this is dangerous since unwanted remapping may
+%D take place. Especially when we redefine already defined
+%D colors in another color space (e.g. darkgreen is
+%D predefined in RGB color space, so a redefinition in CMYK
+%D coordinates before RGB mode is disabled, would give
+%D unexpected results due to the already frozen color spec.)
+
+%D In \MKIV\ we don't support color separation as we might now assume
+%D that printing houses have the right programs to do it themselves.
+%D The \MKII\ color separator was implemented as part of a project
+%D that needed. If it's ever needed in \MKIV\ i'll do it in the
+%D backend.
+
+\let\doifseparatingcolorselse\secondoftwoarguments
+\let\doifcolorchannelelse \secondofthreearguments
+\let\resetcolorseparation \relax
+\let\colorchannelprefix \empty
+\let\colorchannelsuffix \empty
+
+%D We now define the low level macros:
+
+% todo: palets in definecolor
+% todo: {\red xx} vs \red{xx}
+
+% check: registerusedspotcolors
+% check: \currentcolorname
+% check: \outercolorname
+% check: \startcolormode
+
+% \def\mptexcolor#1{"\dogetattributeid\s!color \somecolorattribute{#1} A"}
+%
+% \startMPpage
+% fill fullcircle scaled 10cm ;
+% fill fullcircle scaled 5cm withprescript \mptexcolor{red} withpostscript \mptexcolor{black} ;
+% fill fullcircle scaled 3cm ;
+% draw btex test etex withprescript \mptexcolor{blue} ;
+% \stopMPpage
+
+\ifx\currentcolormodel\undefined \newcount\currentcolormodel \fi
+
+% \def\setcolormodel#1%
+% {\showcolormessage\m!colors1{#1}%
+% \dosetcolormodel{#1}}
+
+\def\dosetcolormodel#1% no message
+ {\currentcolormodel\ctxlua{tex.print(colors.setmodel('#1',\ifweightGRAY true\else false\fi))}%
+ \attribute\colormodelattribute\currentcolormodel}
+
+\dosetcolormodel{all}
+
+
+\def\dosetupcolormodel
+ {\ifincolor
+ \ifRGBsupported
+ \ifCMYKsupported
+ \dosetcolormodel{all}%
+ \else
+ \dosetcolormodel{rgb}%
+ \fi
+ \else
+ \ifCMYKsupported
+ \dosetcolormodel{cmyk}%
+ \else
+ \ifconvertGRAY
+ \dosetcolormodel{gray}%
+ \else
+ \dosetcolormodel{none}%
+ \fi
+ \fi
+ \fi
+ \else
+ \ifconvertGRAY
+ \dosetcolormodel{gray}%
+ \else
+ \dosetcolormodel{none}%
+ \fi
+ \fi}
+
+\appendtoks
+ \dosetupcolormodel
+\to \everyjob
+
+% Currently in mkiv transparency is implemented independent of color. This costs
+% a bit more processing time but gives the possibility to apply transparency
+% independently in the future. Is this useful? If not we may as well combine them
+% again in the future. By coupling we are downward compatible. When we decouple we
+% need to do more tricky housekeeping (e.g. persist color independent transparencies
+% when color bound ones are nil.
+
+% Since we couple definitions, we could stick to one test. Todo. Same for mpcolor.
+
+\letvalue{(cs:-}\empty
+\letvalue{(ts:-}\empty
+
+\def\doactivatecolor#1% : in currentpalet, maybe not, ugly
+ {\def\currentcolorname{#1}%
+ \ifcsname(cs:\currentpalet#1)\endcsname
+ \csname(cs:\currentpalet#1)\endcsname
+ \csname(ts:\currentpalet#1)\endcsname
+ \else\ifcsname(cs:#1)\endcsname
+ \csname(cs:#1)\endcsname
+ \csname(ts:#1)\endcsname
+ \fi\fi}
+
+\let\normaldoactivatecolor\doactivatecolor
+
+% if it becomes a bottleneck we can set up a more complex system with one shared
+% attribute for colorspace, color and transparency
+
+\def\doactivatecolor
+ {\ifproductionrun
+ \ctxlua{colors.enable() transparencies.enable()}% not that efficient but at least robust
+ \let\doactivatecolor\normaldoactivatecolor
+ \expandafter\doactivatecolor
+ \else
+ \expandafter\normaldoactivatecolor
+ \fi}
+
+\def\deactivatecolor
+ {\let\currentcolorname\s!black
+ \attribute\colorattribute\attributeunsetvalue
+ \attribute\transparencyattribute\attributeunsetvalue}
+
+\def\dodefinecolorcommand#1#2%
+ {\unexpanded#1{#2}{\doactivatecolor{#2}}}
+
+\let\colorlist\empty % not really used, only for colo-run
+\setfalse\collectcolorsinlist
+\def\collectcolorinlist#1{\doglobal\addtocommalist{#1}\colorlist}
+
+\def\doregistercolor#1#2{\ctxlua{colors.defineprocesscolor("#1","#2",false,\iffreezecolors true\else false\fi)}}
+
+\def\dodefinecolor[#1][#2]%
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
+ \ctxlua{colors.defineprocesscolor("#1","#2",false,\iffreezecolors true\else false\fi)}%
+ \dodefinecolorcommand\setvalue{#1}}
+
+\def\dodefineglobalcolor[#1][#2]%
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
+ \ctxlua{colors.defineprocesscolor("#1","#2",true,\iffreezecolors true\else false\fi)}%
+ \dodefinecolorcommand\setgvalue{#1}}
+
+\def\dodefinenamedcolor[#1][#2]%
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
+ \ctxlua{colors.defineprocesscolor("#1","#2",false,\iffreezecolors true\else false\fi)}%
+ \dodefinecolorcommand\setvalue{#1}}
+
+\def\dodefinespotcolor[#1][#2][#3]%
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
+ \ctxlua{colors.definespotcolor("#1","#2","#3",true)}%
+ \dodefinecolorcommand\setxvalue{#1}}
+
+\def\dodefinemultitonecolor[#1][#2][#3][#4]%
+ {\ctxlua{colors.definemultitonecolor("#1","#2","#3","#4",true)}%
+ \dodefinecolorcommand\setxvalue{#1}}
+
+\def\dodefinetransparency[#1][#2]%
+ {\ctxlua{colors.definetransparency("#1",#2)}}
+
+\def\dosetrastercolor#1% slow, we need a fast one
+ {\edef\@@rastervalue{#1}%
+ \ifx\@@rastervalue\empty
+ \let\@@rastervalue\@@rsscreen
+ \fi
+ \attribute\colorattribute\ctxlua{tex.sprint(colors.definesimplegray("_raster_",\@@rastervalue))}\relax}
+
+\def\dodefinefastcolor[#1][#2]% still not fast but ok
+ {\ctxlua{colors.defineprocesscolor("#1","#2",false,\iffreezecolors true\else false\fi)}%
+ \dodefinecolorcommand\setvalue{#1}}
+
+%D \macros
+%D {doifcolorelse, doifcolor}
+%D
+%D Switching to a color is done by means of the following
+%D command. Later on we will explain the use of palets. We
+%D define ourselves a color conditional first.
+
+\def\doifcolorelse#1%
+ {\ifcsname(ca:\currentpalet#1)\endcsname
+ \@EA\firstoftwoarguments
+ \else\ifcsname(ca:#1)\endcsname
+ \@EAEAEA\firstoftwoarguments
+ \else
+ \@EAEAEA\secondoftwoarguments
+ \fi\fi}
+
+\def\doifcolor#1%
+ {\ifcsname(ca:\currentpalet#1)\endcsname
+ \@EA\firstofoneargument
+ \else\ifcsname(ca:#1)\endcsname
+ \@EAEAEA\firstofoneargument
+ \else
+ \@EAEAEA\gobbleoneargument
+ \fi\fi}
+
+%D \macros
+%D {colored}
+%D
+%D A bit like \type {\definedfont}:
+
+\unexpanded\def\colored[#1]%
+ {\ctxlua{colors.defineprocesscolor("@colored@","#1",false,false)}%
+ \groupedcommand{\doactivatecolor{@colored@}}{}}
+
+%D \macros
+%D {startregistercolor,stopregistercolor,permitcolormode}
+%D
+%D If you only want to register a color, the switch \type
+%D {\ifpermitcolormode} can be used. That way the nested
+%D colors know where to go back to.
+%D
+%D We use these macros for implementing text colors
+%D (actually, the first application was in foreground
+%D colors).
+%D
+%D \starttyping
+%D \starttextcolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stoptextcolor
+%D \stoptyping
+%D
+%D This is more efficient than the alternative:
+%D
+%D \starttyping
+%D \setupbackgrounds[text][foregroundcolor=red]
+%D \startregistercolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stopregistercolor
+%D \stoptyping
+
+% can be cleaned up
+
+\let\maintextcolor \empty
+\def\defaulttextcolor {black}
+\def\@@themaintextcolor{themaintextcolor}
+
+\appendtoks
+ \deactivatecolor
+ \ifx\maintextcolor\empty\else\doactivatecolor\maintextcolor\fi
+\to \everybeforeoutput
+
+\def\registermaintextcolor{\ctxlua{colors.main = \thecolorattribute\maintextcolor}}
+
+\unexpanded\def\starttextcolor[#1]%
+ {\doifsomething{#1}
+ {\definecolor[\@@themaintextcolor][#1]%
+ \let\maintextcolor\@@themaintextcolor
+ \doactivatecolor\maintextcolor
+ \registermaintextcolor}}
+
+\let\stoptextcolor\relax
+
+\def\initializemaintextcolor
+ {\doifelsenothing\@@cltextcolor
+ {\definecolor[\@@themaintextcolor][\defaulttextcolor]}
+ {\definecolor[\@@themaintextcolor][\@@cltextcolor]}%
+ \let\maintextcolor\@@themaintextcolor
+ \doactivatecolor\maintextcolor
+ \registermaintextcolor}
+
+\appendtoks \initializemaintextcolor \to \everyjob
+\appendtoks \initializemaintextcolor \to \everysetupcolors
+
+\def\dodefinepaletcolor#1#2#3%
+ {\doifassignmentelse{#3}% \definepalet[test][xx={y=.4}]
+ {\definecolor[\??pa#1:#2][#3]%
+ \iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(cs:#1:#2)}{\csname(cs:\??pa#1:#2)\endcsname}%
+ \iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(ca:#1:#2)}{\csname(ca:\??pa#1:#2)\endcsname}}
+ {\ifcsname(cs:#3)\endcsname % \definepalet[test][xx=green]
+ \iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(cs:#1:#2)}{\csname(cs:#3)\endcsname}%
+ \iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(ca:#1:#2)}{\csname(ca:#3)\endcsname}%
+ \else
+ % not entered when making format
+ \localundefine{(cs:#1:#2)}% \letvalue{(cs:#1:#2)}\undefined
+ \localundefine{(ca:#1:#2)}% \letvalue{(ca:#1:#2)}\undefined
+ \fi}}
+
+\setvalue{(cs:)}{} \setvalue{(ca:)}{0}
+\setvalue{(ts:)}{} \setvalue{(ta:)}{0}
+
+\def\doinheritca#1{\csname(ca:\ifcsname(ca:\currentpalet#1)\endcsname\currentpalet#1\else\ifcsname(ca:#1)\endcsname#1\fi\fi)\endcsname}
+\def\doinheritcs#1{\csname(cs:\ifcsname(cs:\currentpalet#1)\endcsname\currentpalet#1\else\ifcsname(cs:#1)\endcsname#1\fi\fi)\endcsname}
+\def\doinheritta#1{\csname(ta:\ifcsname(ta:\currentpalet#1)\endcsname\currentpalet#1\else\ifcsname(ta:#1)\endcsname#1\fi\fi)\endcsname}
+\def\doinheritts#1{\csname(ts:\ifcsname(ts:\currentpalet#1)\endcsname\currentpalet#1\else\ifcsname(ts:#1)\endcsname#1\fi\fi)\endcsname}
+
+%D Low level defs:
+
+\def\colordefalc#1#2{\setevalue{(ca:#1)}{#2}\setvalue {(cs:#1)}{\attribute\colorattribute #2 }}
+\def\colordefagc#1#2{\setxvalue{(ca:#1)}{#2}\setvalue {(cs:#1)}{\attribute\colorattribute #2 }}
+\def\colordefalt#1#2{\setevalue{(ta:#1)}{#2}\setvalue {(ts:#1)}{\attribute\transparencyattribute#2 }}
+\def\colordefagt#1#2{\setxvalue{(ta:#1)}{#2}\setgvalue{(ts:#1)}{\attribute\transparencyattribute#2 }}
+
+\def\colordefflc#1#2{\setvalue {(ca:#1)}{\doinheritca{#2}}\setvalue {(cs:#1)}{\doinheritcs{#2}}}
+\def\colordeffgc#1#2{\setgvalue{(ca:#1)}{\doinheritca{#2}}\setvalue {(cs:#1)}{\doinheritcs{#2}}}
+\def\colordefflt#1#2{\setvalue {(ta:#1)}{\doinheritta{#2}}\setvalue {(ts:#1)}{\doinheritts{#2}}}
+\def\colordeffgt#1#2{\setgvalue{(ta:#1)}{\doinheritta{#2}}\setgvalue{(ts:#1)}{\doinheritts{#2}}}
+
+\def\colordefrlc #1{\localundefine {(ca:#1)}\localundefine {(cs:#1)}}
+\def\colordefrgc #1{\globalundefine{(ca:#1)}\globalundefine{(cs:#1)}}
+\def\colordefrlt #1{\localundefine {(ta:#1)}\localundefine {(ts:#1)}}
+\def\colordefrgt #1{\globalundefine{(ta:#1)}\globalundefine{(ts:#1)}}
+
+%D \macros
+%D {colorvalue, grayvalue}
+%D
+%D We can typeset the color components using \type{\colorvalue} and
+%D \type{\grayvalue}. The commands:
+%D
+%D \startbuffer
+%D color value of SomeKindOfRed: \colorvalue{SomeKindOfRed} \crlf
+%D gray value of SomeKindOfRed: \grayvalue{SomeKindOfRed}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D show us:
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+
+\def\colorformatseparator{ }
+
+\def\MPcolor#1{\ctxlua{tex.sprint(colors.mp(\number\currentcolormodel,\number\doinheritca{#1},\number\doinheritta{#1}))}}
+
+\let\currentcolorname\s!black % todo
+\let\outercolorname \s!black % todo
+
+\def\thecolorattribute #1{\number\csname(ca:\ifcsname(ca:\currentpalet#1)\endcsname\currentpalet#1\else\ifcsname(ca:#1)\endcsname#1\fi\fi)\endcsname}
+\def\thetransparencyattribute#1{\number\csname(ta:\ifcsname(ta:\currentpalet#1)\endcsname\currentpalet#1\else\ifcsname(ta:#1)\endcsname#1\fi\fi)\endcsname}
+
+\def\internalspotcolorname #1{\ctxlua{tex.sprint(colors.spotcolorname (\thecolorattribute{#1}))}}
+\def\internalspotcolorparent#1{\ctxlua{tex.sprint(colors.spotcolorparent(\thecolorattribute{#1}))}}
+\def\internalspotcolorsize #1{\ctxlua{tex.sprint(colors.spotcolorvalue (\thecolorattribute{#1}))}}
+
+\def\colorcomponents #1{\ctxlua{tex.sprint(colors.colorcomponents (\thecolorattribute {#1}))}}
+\def\transparencycomponents#1{\ctxlua{tex.sprint(colors.transparencycomponents(\thetransparencyattribute{#1}))}}
+
+\def\colorvalue#1{\ctxlua{tex.sprint(colors.formatcolor(\thecolorattribute{#1},"\colorformatseparator"))}}
+\def\grayvalue #1{\ctxlua{tex.sprint(colors.formatgray (\thecolorattribute{#1},"\colorformatseparator"))}}
+
+\def\doifblackelse #1{\ctxlua{commands.doifelse(colors.isblack(\thecolorattribute{#1}))}}
+\def\doifdrawingblackelse {\ctxlua{commands.doifelse(colors.isblack(tex.attribute[attributes.numbers['color']]))}}
+
+%D \macros
+%D {forcecolorhack}
+%D
+%D We can out this in front of (for instance) a special and so force color
+%D to be applied (only glyphs, rules and leaders are handled).
+%D
+%D \startbuffer
+%D \framed
+%D [background=color,backgroundcolor=yellow,framecolor=red,corner=round]
+%D {test}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+% ignores in attribute handler
+%
+% \def\forcecolorhack{\vrule\!!width\zeropoint\!!height\zeropoint\!!depth\zeropoint}
+
+% \normal added else fails in metafun manual (leaders do a hard scan)
+
+\unexpanded\def\forcecolorhack{\leaders\hrule\normalhskip\zeropoint}
+
+%D We default to the colors defined in \module{colo-rgb} and
+%D support both \cap{RGB} and \cap{CMYK} output. As you can
+%D see, color support is turned off by default. Reduction of
+%D gray colors to gray scales is turned on.
+
+\definecolor[black][s=0]
+\definecolor[white][s=1]
+
+\definetransparency [none] [0]
+\definetransparency [normal] [1]
+\definetransparency [multiply] [2]
+\definetransparency [screen] [3]
+\definetransparency [overlay] [4]
+\definetransparency [softlight] [5]
+\definetransparency [hardlight] [6]
+\definetransparency [colordodge] [7]
+\definetransparency [colorburn] [8]
+\definetransparency [darken] [9]
+\definetransparency [lighten] [10]
+\definetransparency [difference] [11]
+\definetransparency [exclusion] [12]
+
+\setupcolors
+ [\c!state=\v!stop, % will be enabled later on
+ \c!conversion=\v!yes,
+ \c!reduction=\v!no,
+ \c!rgb=\v!yes,
+ \c!cmyk=\v!yes,
+ \c!spot=\v!yes,
+ \c!mp\c!cmyk=\@@clcmyk,
+ \c!mp\c!spot=\@@clspot,
+ \c!expansion=\v!no,
+ \c!textcolor=,
+ \c!split=\v!no, % obsolete
+ \c!factor=\v!yes,
+ \c!criterium=\v!all] % obsolete
+
+\appendtoks
+ \setupcolors[\c!state=\v!start]% later direct
+\to \everyjob
+
+\appendtoks
+ \let\showcolormessage\showmessage
+\to \everyjob
+
+\setupcolor
+ [\v!rgb]
+
+\protect \endinput
diff --git a/tex/context/base/colo-rgb.tex b/tex/context/base/colo-rgb.tex
new file mode 100644
index 000000000..038e0ab0b
--- /dev/null
+++ b/tex/context/base/colo-rgb.tex
@@ -0,0 +1,530 @@
+%D \module
+%D [ file=colo-rgb,
+%D version=1995.01.01,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=RGB,
+%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.
+
+%D Just to give users a start we define some colors. While
+%D switching fonts is as international as can be, thanks to the
+%D mnemonics, naming colors is very interface dependant. To
+%D support international setups, we define both english and
+%D interface dependant colors. We use the color inheritance
+%D mechanisms to implement the interface dependant ones.
+
+%D First we define some simple primary \cap{RGB} and \cap{CMYK}
+%D colors. All colors are defined in \cap{RGB} color space.
+
+\definecolor [red] [r=1, g=0, b=0]
+\definecolor [green] [r=0, g=1, b=0]
+\definecolor [blue] [r=0, g=0, b=1]
+
+\definecolor [cyan] [r=0, g=1, b=1]
+\definecolor [magenta] [r=1, g=0, b=1]
+\definecolor [yellow] [r=1, g=1, b=0]
+
+\definecolor [white] [s=1] % [r=1, g=1, b=1]
+\definecolor [black] [s=0]
+\definecolor [gray] [s=.9]
+
+\definecolor [darkred] [r=.8, g=0, b=0]
+\definecolor [middlered] [r=.9, g=0, b=0]
+\definecolor [lightred] [r=1, g=0, b=0]
+
+\definecolor [darkgreen] [r=0, g=.6, b=0]
+\definecolor [middlegreen] [r=0, g=.8, b=0]
+\definecolor [lightgreen] [r=0, g=1, b=0]
+
+\definecolor [darkblue] [r=0, g=0, b=.8]
+\definecolor [middleblue] [r=0, g=0, b=.9]
+\definecolor [lightblue] [r=0, g=0, b=1]
+
+\definecolor [darkcyan] [r=.6, g=.8, b=.8]
+\definecolor [middlecyan] [r=0, g=.8, b=.8]
+
+\definecolor [darkmagenta] [r=.8, g=.6, b=.8]
+\definecolor [middlemagenta] [r=1, g=0, b=.6]
+
+\definecolor [darkyellow] [r=.8, g=.8, b=.6]
+\definecolor [middleyellow] [r=1, g=1, b=.2]
+
+\definecolor [darkgray] [s=.5]
+\definecolor [middlegray] [s=.7]
+\definecolor [lightgray] [s=.9]
+
+%D These colors are mapped to interface dependant colornames.
+
+\startinterface dutch
+
+ \definecolor [rood] [red]
+ \definecolor [groen] [green]
+ \definecolor [blauw] [blue]
+
+ \definecolor [cyaan] [cyan]
+ \definecolor [magenta] [magenta]
+ \definecolor [geel] [yellow]
+
+ \definecolor [wit] [white]
+ \definecolor [grijs] [gray]
+ \definecolor [zwart] [black]
+
+ \definecolor [donkerrood] [darkred]
+ \definecolor [middelrood] [middlered]
+ \definecolor [lichtrood] [lightred]
+
+ \definecolor [donkergroen] [darkgreen]
+ \definecolor [middelgroen] [middlegreen]
+ \definecolor [lichtgroen] [lightgreen]
+
+ \definecolor [donkerblauw] [darkblue]
+ \definecolor [middelblauw] [middleblue]
+ \definecolor [lichtblauw] [lightblue]
+
+ \definecolor [donkercyaan] [darkcyan]
+ \definecolor [middelcyaan] [middlecyan]
+
+ \definecolor [donkermagenta] [darkmagenta]
+ \definecolor [middelmagenta] [middlemagenta]
+
+ \definecolor [donkergeel] [darkyellow]
+ \definecolor [middelgeel] [middleyellow]
+
+ \definecolor [donkergrijs] [darkgray]
+ \definecolor [middengrijs] [middlegray]
+ \definecolor [lichtgrijs] [lightgray]
+
+\stopinterface
+
+\startinterface german
+
+ \definecolor [rot] [red]
+ \definecolor [gruen] [green]
+ \definecolor [blau] [blue]
+
+ \definecolor [cyan] [cyan]
+ \definecolor [magenta] [magenta]
+ \definecolor [gelb] [yellow]
+
+ \definecolor [weiss] [white]
+ \definecolor [grau] [gray]
+ \definecolor [schwarz] [black]
+
+ \definecolor [dunkelrot] [darkred]
+ \definecolor [mittelrot] [middlered]
+ \definecolor [hellrot] [lightred]
+
+ \definecolor [dunkelgruen] [darkgreen]
+ \definecolor [mittelgruen] [middlegreen]
+ \definecolor [hellgruen] [lightgreen]
+
+ \definecolor [dunkelblau] [darkblue]
+ \definecolor [mittelblau] [middleblue]
+ \definecolor [hellblau] [lightblue]
+
+ \definecolor [dunkelcyan] [darkcyan]
+ \definecolor [mittelcyan] [middlecyan]
+
+ \definecolor [dunkelmagenta] [darkmagenta]
+ \definecolor [mittelmagenta] [middlemagenta]
+
+ \definecolor [dunkelgelb] [darkyellow]
+ \definecolor [mittelgelb] [middleyellow]
+
+ \definecolor [dunkelgrau] [darkgray]
+ \definecolor [mittelgrau] [middlegray]
+ \definecolor [hellgrau] [lightgray]
+
+\stopinterface
+
+\startinterface czech
+
+ \definecolor [cervena] [red]
+ \definecolor [zelena] [green]
+ \definecolor [modra] [blue]
+
+ \definecolor [azurova] [cyan]
+ \definecolor [fialova] [magenta]
+ \definecolor [zluta] [yellow]
+
+ \definecolor [bila] [white]
+ \definecolor [cerna] [black]
+
+ \definecolor [tmavecervena] [darkred]
+ \definecolor [strednecervena] [middlered]
+ \definecolor [svetlecervena] [lightred]
+
+ \definecolor [tmavezelena] [darkgreen]
+ \definecolor [strednezelena] [middlegreen]
+ \definecolor [svetlezelena] [lightgreen]
+
+ \definecolor [tmavemodra] [darkblue]
+ \definecolor [strednemodra] [middleblue]
+ \definecolor [svetlemodra] [lightblue]
+
+ \definecolor [tmaveazurova] [darkcyan]
+ \definecolor [stredneazurova] [middlecyan]
+
+ \definecolor [tmavefialova] [darkmagenta]
+ \definecolor [strednefialova] [middlemagenta]
+
+ \definecolor [tmavezluta] [darkyellow]
+ \definecolor [strednezluta] [middleyellow]
+
+ \definecolor [tmaveseda] [darkgray]
+ \definecolor [stredneseda] [middlegray]
+ \definecolor [svetleseda] [lightgray]
+
+\stopinterface
+
+\startinterface italian
+
+ \definecolor [rosso] [red]
+ \definecolor [verde] [green]
+ \definecolor [blu] [blue]
+
+ \definecolor [azzurro] [cyan]
+ \definecolor [turchino] [cyan]
+ \definecolor [ciano] [cyan]
+ \definecolor [cremisi] [magenta]
+ \definecolor [giallo] [yellow]
+
+ \definecolor [bianco] [white]
+ \definecolor [grigio] [gray]
+ \definecolor [nero] [black]
+
+ \definecolor [rossoscuro] [darkred]
+ \definecolor [rossomedio] [middlered]
+ \definecolor [rossochiaro] [lightred]
+
+ \definecolor [verdescuro] [darkgreen]
+ \definecolor [verdemedio] [middlegreen]
+ \definecolor [verdechiaro] [lightgreen]
+
+ \definecolor [bluscuro] [darkblue]
+ \definecolor [blumedio] [middleblue]
+ \definecolor [bluchiaro] [lightblue]
+
+ \definecolor [azzurroscuro] [darkcyan]
+ \definecolor [azzurrochiaro] [middlecyan]
+
+ \definecolor [cremisiscuro] [darkmagenta]
+ \definecolor [cremisichiaro] [middlemagenta]
+
+
+ \definecolor [gialloscuro] [darkyellow]
+ \definecolor [giallomedio] [middleyellow]
+
+ \definecolor [grigioscuro] [darkgray]
+ \definecolor [grigiomedio] [middlegray]
+ \definecolor [grigiochiaro] [lightgray]
+
+\stopinterface
+
+\startinterface romanian
+
+ \definecolor [rosu] [red]
+ \definecolor [verde] [green]
+ \definecolor [albastru] [blue]
+
+ \definecolor [cian] [cyan]
+ \definecolor [magenta] [magenta]
+ \definecolor [galben] [yellow]
+
+ \definecolor [alb] [white]
+ \definecolor [gri] [gray]
+ \definecolor [negru] [black]
+
+ \definecolor [rosuinchis] [darkred]
+ \definecolor [rosumediu] [middlered]
+ \definecolor [rosudeschis] [lightred]
+
+ \definecolor [verdeinchis] [darkgreen]
+ \definecolor [verdemediu] [middlegreen]
+ \definecolor [verdedeschis] [lightgreen]
+
+ \definecolor [albastruinchis] [darkblue]
+ \definecolor [albastrumediu] [middleblue]
+ \definecolor [albastrudeschis] [lightblue]
+
+ \definecolor [cianinchis] [darkcyan]
+ \definecolor [cianmediu] [middlecyan]
+
+ \definecolor [magentainchis] [darkmagenta]
+ \definecolor [magentamediu] [middlemagenta]
+
+ \definecolor [galbeninchis] [darkyellow]
+ \definecolor [galbenmediu] [middleyellow]
+
+ \definecolor [griinchis] [darkgray]
+ \definecolor [grimediu] [middlegray]
+ \definecolor [grideschis] [lightgray]
+
+\stopinterface
+
+%D Like colors, we first define the english colorgroups. These
+%D colorgroups are tuned for distinctive gray scale printing.
+
+% todo : more efficient and real gray
+
+\definecolorgroup
+ [gray]
+ [0.95:0.95:0.95,
+ 0.90:0.90:0.90,
+ 0.80:0.80:0.80,
+ 0.70:0.70:0.70,
+ 0.60:0.60:0.60,
+ 0.50:0.50:0.50,
+ 0.40:0.40:0.40,
+ 0.30:0.30:0.30,
+ 0.20:0.20:0.20,
+ 0.10:0.10:0.10,
+ 0.00:0.00:0.00]
+
+\definecolorgroup
+ [red]
+ [1.00:0.90:0.90,
+ 1.00:0.80:0.80,
+ 1.00:0.70:0.70,
+ 1.00:0.55:0.55,
+ 1.00:0.40:0.40,
+ 1.00:0.25:0.25,
+ 1.00:0.15:0.15,
+ 0.90:0.00:0.00]
+
+\definecolorgroup
+ [green]
+ [0.90:1.00:0.90,
+ 0.70:1.00:0.70,
+ 0.50:1.00:0.50,
+ 0.30:1.00:0.30,
+ 0.15:0.90:0.15,
+ 0.00:0.80:0.00,
+ 0.00:0.65:0.00,
+ 0.00:0.50:0.00]
+
+\definecolorgroup
+ [blue]
+ [0.90:0.95:1.00,
+ 0.80:0.90:1.00,
+ 0.55:0.85:1.00,
+ 0.30:0.80:1.00,
+ 0.15:0.75:1.00,
+ 0.00:0.70:1.00,
+ 0.00:0.55:1.00,
+ 0.00:0.40:1.00]
+
+\definecolorgroup
+ [cyan]
+ [0.80:1.00:1.00,
+ 0.60:1.00:1.00,
+ 0.30:1.00:1.00,
+ 0.00:0.95:0.95,
+ 0.00:0.85:0.85,
+ 0.00:0.75:0.75,
+ 0.00:0.60:0.60,
+ 0.00:0.50:0.50]
+
+\definecolorgroup
+ [magenta]
+ [1.00:0.90:1.00,
+ 1.00:0.80:1.00,
+ 1.00:0.65:1.00,
+ 1.00:0.50:1.00,
+ 1.00:0.35:1.00,
+ 1.00:0.15:1.00,
+ 0.90:0.05:0.90,
+ 0.80:0.00:0.80]
+
+\definecolorgroup
+ [yellow]
+ [1.00:1.00:0.70,
+ 1.00:1.00:0.00,
+ 1.00:0.85:0.05,
+ 1.00:0.70:0.00,
+ 1.00:0.55:0.00,
+ 0.95:0.40:0.00,
+ 0.80:0.30:0.00,
+ 0.60:0.30:0.00]
+
+\definecolorgroup
+ [red*]
+ [1.00:0.95:0.95,
+ 1.00:0.90:0.90,
+ 1.00:0.80:0.80,
+ 1.00:0.70:0.70,
+ 1.00:0.60:0.60,
+ 1.00:0.50:0.50,
+ 1.00:0.40:0.40,
+ 1.00:0.30:0.30]
+
+\definecolorgroup
+ [green*]
+ [0.95:1.00:0.95,
+ 0.90:1.00:0.90,
+ 0.80:1.00:0.80,
+ 0.70:1.00:0.70,
+ 0.60:1.00:0.60,
+ 0.50:1.00:0.50,
+ 0.40:1.00:0.40,
+ 0.30:1.00:0.30]
+
+\definecolorgroup
+ [blue*]
+ [0.95:0.95:1.00,
+ 0.90:0.90:1.00,
+ 0.80:0.80:1.00,
+ 0.70:0.70:1.00,
+ 0.60:0.60:1.00,
+ 0.50:0.50:1.00,
+ 0.40:0.40:1.00,
+ 0.30:0.30:1.00]
+
+\definecolorgroup
+ [yellow*]
+ [1.00:1.00:0.10,
+ 1.00:1.00:0.00,
+ 0.90:0.90:0.00,
+ 0.80:0.80:0.00,
+ 0.70:0.70:0.00,
+ 0.60:0.60:0.00,
+ 0.50:0.50:0.00,
+ 0.40:0.40:0.00]
+
+%D For the sake of implementing interface dependant color
+%D groups we support colorgroup duplication.
+
+\startinterface dutch
+ \definecolorgroup [grijs] [gray]
+ \definecolorgroup [rood] [red]
+ \definecolorgroup [groen] [green]
+ \definecolorgroup [blauw] [blue]
+ \definecolorgroup [cyaan] [cyan]
+ \definecolorgroup [magenta] [magenta]
+ \definecolorgroup [geel] [yellow]
+ \definecolorgroup [rood*] [red*]
+ \definecolorgroup [groen*] [green*]
+ \definecolorgroup [blauw*] [blue*]
+ \definecolorgroup [geel*] [yellow*]
+\stopinterface
+
+\startinterface german
+ \definecolorgroup [grau] [gray]
+ \definecolorgroup [rot] [red]
+ \definecolorgroup [gruen] [green]
+ \definecolorgroup [blau] [blue]
+ \definecolorgroup [cyan] [cyan]
+ \definecolorgroup [magenta] [magenta]
+ \definecolorgroup [gelb] [yellow]
+ \definecolorgroup [rot*] [red*]
+ \definecolorgroup [gruen*] [green*]
+ \definecolorgroup [blau*] [blue*]
+ \definecolorgroup [gelb*] [yellow*]
+\stopinterface
+
+\startinterface czech
+ \definecolorgroup [seda] [gray]
+ \definecolorgroup [cervena] [red]
+ \definecolorgroup [zelena] [green]
+ \definecolorgroup [modra] [blue]
+ \definecolorgroup [azurova] [cyan]
+ \definecolorgroup [fialova] [magenta]
+ \definecolorgroup [zluta] [yellow]
+ \definecolorgroup [cervena*] [red*]
+ \definecolorgroup [zelena*] [green*]
+ \definecolorgroup [modra*] [blue*]
+ \definecolorgroup [zluta*] [yellow*]
+\stopinterface
+
+\startinterface italian
+ \definecolorgroup [grigio] [gray]
+ \definecolorgroup [rosso] [red]
+ \definecolorgroup [verde] [green]
+ \definecolorgroup [blu] [blue]
+ \definecolorgroup [ciano] [cyan]
+ \definecolorgroup [azzurro] [cyan]
+ \definecolorgroup [turchino][cyan]
+ \definecolorgroup [magenta] [magenta]
+ \definecolorgroup [cremisi] [magenta]
+ \definecolorgroup [giallo] [yellow]
+ \definecolorgroup [rosso*] [red*]
+ \definecolorgroup [verde*] [green*]
+ \definecolorgroup [blu*] [blue*]
+ \definecolorgroup [giallo*] [yellow*]
+\stopinterface
+
+%D The next set of color palets is quite language independant.
+%D These palets are meant as examples.
+
+\definepalet
+ [alfa]
+ [ top=red:7,
+ bottom=green:6,
+ up=blue:5,
+ down=cyan:4,
+ strange=magenta:3,
+ charm=yellow:2]
+
+\definepalet
+ [beta]
+ [ top=red:7,
+ bottom=green:5,
+ up=blue:3,
+ down=cyan:6,
+ strange=magenta:2,
+ charm=yellow:1]
+
+\definepalet
+ [gamma]
+ [ top=red:2,
+ bottom=green:5,
+ up=blue:3,
+ down=cyan:6,
+ strange=magenta:7,
+ charm=yellow:4]
+
+\definepalet
+ [delta]
+ [ top=yellow*:5,
+ bottom=yellow*:3,
+ up=yellow*:2,
+ down=magenta:6,
+ strange=blue:4,
+ charm=blue:1]
+
+\definepalet
+ [epsilon]
+ [ top=cyan:7,
+ bottom=cyan:5,
+ up=blue:3,
+ down=yellow:6,
+ strange=yellow:4,
+ charm=yellow:2]
+
+\definepalet
+ [zeta]
+ [ top=red:6,
+ bottom=green:5,
+ up=blue:7,
+ down=cyan:4,
+ strange=magenta:3,
+ charm=yellow:2]
+
+%D The next four colors are used for typesetting verbatim \TEX\
+%D in color.
+
+\definecolor [texcolorone] [middlered]
+\definecolor [texcolortwo] [middlegreen]
+\definecolor [texcolorthree] [middleblue]
+\definecolor [texcolorfour] [darkyellow]
+
+%D Bonus (needed for FO test):
+
+\definecolor [orange] [r=1,g=.5]
+
+\endinput
diff --git a/tex/context/base/colo-run.tex b/tex/context/base/colo-run.tex
new file mode 100644
index 000000000..d94ea9801
--- /dev/null
+++ b/tex/context/base/colo-run.tex
@@ -0,0 +1,257 @@
+%D \module
+%D [ file=colo-run,
+%D version=1997.04.01,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Runtime loaded commands,
+%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.
+
+\unprotect
+
+% temp hack (not do be documented)
+
+% \gdef\doformatcolorP#1:#2:#3:#4:#5:#6\od % was undefined in colo-ini
+% {#1\colorformatseparator
+% \dodoformatcolor{#2}\colorformatseparator
+% \dodoformatcolor{#3}\colorformatseparator
+% \dodoformatcolor{#4}\colorformatseparator}
+
+% \gdef\doformatgrayP#1:#2:#3:#4:#5:#6\od
+% {todo}
+
+% so far
+
+\gdef\showpalet
+ {\dodoubleargument\doshowpalet}
+
+\gdef\doshowpalet[#1][#2]%
+ {\doifdefined{\??pa#1}
+ {\doifinsetelse\v!vertical{#2}
+ {\showverticalpalet[#1][#2]}
+ {\showhorizontalpalet[#1][#2]}}}
+
+\gdef\showverticalpalet[#1][#2]%
+ {\localvbox
+ {\offinterlineskip
+ \setuppalet[#1]
+ \def\rule
+ {\vrule\!!width3em\!!height\strutht\!!depth\strutdp}
+ \tabskip\zeropoint
+ \def\doshowpalet##1%
+ {\doifinsetelse\v!number{#2}{##1\hskip.5em}{}&
+ \color[##1]{\rule}\graycolor[##1]{\rule}&
+ \doifinset\v!value{#2}{\hskip.5em\colorvalue{##1}}\crcr}
+ \halign
+ {\hss##&\hss##\hss#\cr
+ &\doifinset{\v!name}{#2}{\strut#1}&\cr%
+ \processpalet[#1]\doshowpalet\crcr}}}
+
+\gdef\showhorizontalpalet[#1][#2]%
+ {\localvbox
+ {\offinterlineskip
+ \setuppalet[#1]
+ \tabskip\zeropoint
+ \!!widtha\zeropoint
+ \doifinset\v!number{#2}
+ {\def\doshowpalet##1%
+ {\setbox0\hbox{##1}%
+ \ifdim\!!widtha<\wd0\!!widtha\wd0\fi}%
+ \processpalet[#1]\doshowpalet}%
+ \advance\!!widtha 1em
+ \ifdim\!!widtha<5em
+ \!!widtha5em
+ \fi
+ \halign
+ {##&&\hbox to \!!widtha{\hss##\hss}\cr
+ \doifinset\v!number{#2}
+ {\def\doshowpalet##1{&\strut##1}%
+ \processpalet[#1]\doshowpalet}\cr
+ \doifinset\v!name{#2}{#1\hskip.5em}%
+ \def\doshowpalet##1%
+ {&\strut\color[##1]{\vrule\!!width\!!widtha\!!height\strutht\!!depth\zeropoint}}%
+ \processpalet[#1]\doshowpalet\crcr
+ \noalign{\vskip-\strutdepth}%
+ \def\doshowpalet##1%
+ {&\graycolor[##1]{\vrule\!!width\!!widtha\!!height\zeropoint\!!depth\strutdp}}%
+ \processpalet[#1]\doshowpalet\crcr
+ \doifinset\v!value{#2}
+ {\def\doshowpalet##1%
+ {&\vbox
+ {\hsize\!!widtha
+ \vskip.25ex
+ \everypar{\strut}
+ \veryraggedcenter
+ \let\colorformatseparator=\endgraf
+ \colorvalue{##1}}}%
+ \processpalet[#1]\doshowpalet}%
+ \crcr}}}
+
+\gdef\processpalet[#1]%
+ {\expanded{\globalprocesscommalist[\getvalue{\??pa#1}]}}
+
+\gdef\showcolorgroup
+ {\dodoubleargument\doshowcolorgroup}
+
+\gdef\doshowcolorgroup[#1][#2]%
+ {\doifcolor{#1:1}
+ {\doifinsetelse\v!vertical{#2}
+ {\showverticalcolorgroup[#1][#2]}
+ {\showhorizontalcolorgroup[#1][#2]}}}
+
+\gdef\showhorizontalcolorgroup[#1][#2]%
+ {\localvbox
+ {\offinterlineskip
+ \setuppalet
+ \tabskip\zeropoint
+ \def\rule
+ {\vrule\!!width4em\!!height\strutht\!!depth\strutdp}
+ \def\colorformatseparator{\strut\cr}
+ \def\dodoshowgroup##1%
+ {\halign
+ {\hss####\hss\cr
+ \doifinset\v!number{#2}{\strut##1}\cr
+ \color[#1:##1]{\vrule\!!width4em\!!height\strutht\!!depth\zeropoint}\cr
+ \graycolor[#1:##1]{\vrule\!!width4em\!!height\zeropoint\!!depth\strutdp}\cr
+ \doifinset\v!value{#2}{\colorvalue{#1:##1}\strut}\crcr}}
+ \def\doshowgroup##1%
+ {\doifcolor{#1:##1}
+ {\vbox{\dodoshowgroup{##1}}}}%
+ \hbox
+ {\doifinset\v!name{#2}
+ {\strut
+ \doifinsetelse\v!value{#2}
+ {\raise3\lineheight\hbox{#1\hskip.5em}}
+ {#1}%
+ \hskip.5em}%
+ \doshowgroup1\doshowgroup2\doshowgroup3\doshowgroup4%
+ \doshowgroup5\doshowgroup6\doshowgroup7\doshowgroup8}}}
+
+\gdef\showverticalcolorgroup[#1][#2]%
+ {\localvbox
+ {\offinterlineskip
+ \setuppalet
+ \tabskip\zeropoint
+ \def\rule
+ {\vrule\!!width2.5em\!!height\strutht\!!depth\strutdp}%
+ \def\doshowgroup##1%
+ {\doifcolor{#1:##1}
+ {\doifinset\v!number{#2}{##1\hskip.5em}&
+ \color[#1:##1]{\rule}\graycolor[#1:##1]{\rule}&
+ \doifinset\v!value{#2}{\hskip.5em\colorvalue{#1:##1}}\crcr}}%
+ \halign
+ {\hss##&\hss##\hss#\hss\cr
+ &\doifinset\v!name{#2}{\strut#1}&\crcr
+ \doshowgroup1\doshowgroup2\doshowgroup3\doshowgroup4%
+ \doshowgroup5\doshowgroup6\doshowgroup7\doshowgroup8}}}
+
+\gdef\showcolor
+ {\dosingleempty\doshowcolor}
+
+\gdef\doshowcolor[#1]%
+ {\bgroup
+ \iffirstargument
+ \let\colorlist\empty % not really used, only for colo-run
+ \let\colorstyle\empty
+ \settrue\collectcolorsinlist
+ \setupcolor[#1]%
+ \fi
+ \def\rule
+ {\vrule\!!width4em\!!height\strutht\!!depth\strutdp}%
+ \def\docommand##1%
+ {\NC\graycolor[##1]{\rule}\NC\color[##1]{\rule}\NC\grayvalue{##1}\NC\colorvalue{##1}\NC##1\NC\NR}%
+ \starttabulate[|l|l|l|l|l|l|l|]
+ \expanded{\globalprocesscommalist[\colorlist]}\docommand
+ \stoptabulate
+ \egroup}
+
+\gdef\comparepalet
+ {\dosingleargument\docomparepalet}
+
+\gdef\docomparepalet[#1]%
+ {\doifdefined{\??pa#1}
+ {\hbox
+ {\dodocomparepalet\color[#1]%
+ \quad
+ \dodocomparepalet\graycolor[#1]}}}
+
+\gdef\dodocomparepalet#1[#2]%
+ {\localvbox
+ {\offinterlineskip
+ \setuppalet[#2]
+ \getcommacommandsize[\getvalue{\??pa#2}]
+ \!!widtha2em\relax
+ \hsize\commalistsize\!!widtha
+ \def\rule%
+ {\vrule\!!width.5\!!widtha\!!height2.25ex\!!depth-.75ex}
+ \def\dododocomparepalet##1%
+ {\hbox
+ {\setbox0\hbox
+ {#1[##1]{\vrule\!!width\hsize\!!height3ex}}%
+ \wd0\zeropoint
+ \box0
+ \hbox to \hsize
+ {\def\dododocomparepalet####1%
+ {\hbox to \!!widtha
+ {\hss#1[####1]{\rule}\hss}}%
+ \processcommacommand[\getvalue{\??pa#2}]\dododocomparepalet}}
+ \endgraf}
+ \processcommacommand[\getvalue{\??pa#2}]\dododocomparepalet}}
+
+\gdef\comparecolorgroup
+ {\dosingleargument\docomparecolorgroup}
+
+\gdef\docomparecolorgroup[#1]%
+ {\doifcolor{#1:1}
+ {\hbox
+ {\dodocomparecolorgroup\color[#1]%
+ \quad
+ \dodocomparecolorgroup\graycolor[#1]}}}
+
+\gdef\dodocomparecolorgroup#1[#2]%
+ {\localvbox
+ {\!!counta\zerocount
+ \dorecurse{15}
+ {\doifcolor{#2:\recurselevel}{\advance\!!counta\plusone}}
+ \!!widtha2em\relax
+ \hsize\!!counta\!!widtha
+ \def\rule
+ {\vrule\!!width.5\!!widtha\!!height2.25ex\!!depth-.75ex}
+ \def\dododocomparecolorgroup##1%
+ {\hbox to \hsize
+ {\setbox0\hbox
+ {#1[#2:##1]{\vrule\!!width\hsize\!!height3ex}}%
+ \wd0\zeropoint
+ \box0
+ \hbox to \hsize
+ {\hss\dorecurse\!!counta{#1[#2:\recurselevel]{\rule}\hss}}}
+ \endgraf}
+ \dorecurse\!!counta{\dododocomparecolorgroup\recurselevel}}}
+
+\gdef\dogetcolorcomponents#1%
+ {\doifelsenothing{#1}
+ {\appendtoks
+ \TB
+ \to \scratchtoks}
+ {\appendtoks
+ \NC\showcolorbar[#1]\NC#1\NC\transparencycomponents{#1}\NC\colorcomponents{#1}\NC \NR
+ \to \scratchtoks}}
+
+\gdef\showcolorbar[#1]%
+ {\backgroundline[#1]{\strut\enspace\color[white]{white}\enspace\color[black]{black}\enspace}}
+
+\gdef\showcolorcomponents[#1]%
+ {\begingroup
+ \scratchtoks{\TB}%
+ \processcommacommand[#1]\dogetcolorcomponents
+ \starttabulate[|lT|lT|lT|lT|]
+ \NC color \NC name \NC transparency \NC specification \NC\NR
+ \the\scratchtoks
+ \stoptabulate
+ \endgroup}
+
+\protect \endinput
diff --git a/tex/context/base/colo-x11.tex b/tex/context/base/colo-x11.tex
new file mode 100644
index 000000000..45d3aac62
--- /dev/null
+++ b/tex/context/base/colo-x11.tex
@@ -0,0 +1,677 @@
+%D \module
+%D [ file=colo-x11,
+%D version=2009.11.13,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=X11,
+%D author=Alan Braslau]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Standard X11 rgb colors (from \type {/usr/share/X11/rgb.txt}):
+
+\doifnotmode{mkiv} {
+ \input colo-hex.mkii
+}
+
+\definecolor [snow] [h=fffafa]
+\definecolor [ghostwhite] [h=f8f8ff]
+\definecolor [whitesmoke] [s=0.96]
+\definecolor [gainsboro] [s=0.86]
+\definecolor [floralwhite] [h=fffaf0]
+\definecolor [oldlace] [h=fdf5e6]
+\definecolor [linen] [h=faf0e6]
+\definecolor [antiquewhite] [h=faebd7]
+\definecolor [papayawhip] [h=ffefd5]
+\definecolor [blanchedalmond] [h=ffebcd]
+\definecolor [bisque] [h=ffe4c4]
+\definecolor [peachpuff] [h=ffdab9]
+\definecolor [navajowhite] [h=ffdead]
+\definecolor [moccasin] [h=ffe4b5]
+\definecolor [cornsilk] [h=fff8dc]
+\definecolor [ivory] [h=fffff0]
+\definecolor [lemonchiffon] [h=fffacd]
+\definecolor [seashell] [h=fff5ee]
+\definecolor [honeydew] [h=f0fff0]
+\definecolor [mintcream] [h=f5fffa]
+\definecolor [azure] [h=f0ffff]
+\definecolor [aliceblue] [h=f0f8ff]
+\definecolor [lavender] [h=e6e6fa]
+\definecolor [lavenderblush] [h=fff0f5]
+\definecolor [mistyrose] [h=ffe4e1]
+\definecolor [white] [s=1]
+\definecolor [black] [s=0]
+\definecolor [darkslategray] [h=2f4f4f]
+\definecolor [darkslategrey] [darkslategray]
+\definecolor [dimgray] [s=0.41]
+\definecolor [dimgrey] [dimgray]
+\definecolor [slategray] [h=708090]
+\definecolor [slategrey] [slategray]
+\definecolor [lightslategray] [h=778899]
+\definecolor [lightslategrey] [lightslategray]
+\definecolor [gray] [s=0.75]
+\definecolor [grey] [gray]
+\definecolor [lightgrey] [s=0.83]
+\definecolor [lightgray] [lightgrey]
+\definecolor [midnightblue] [h=191970]
+\definecolor [navy] [h=000080]
+\definecolor [navyblue] [navy]
+\definecolor [cornflowerblue] [h=6495ed]
+\definecolor [darkslateblue] [h=483d8b]
+\definecolor [slateblue] [h=6a5acd]
+\definecolor [mediumslateblue] [h=7b68ee]
+\definecolor [lightslateblue] [h=8470ff]
+\definecolor [mediumblue] [h=0000cd]
+\definecolor [royalblue] [h=4169e1]
+\definecolor [blue] [h=0000ff]
+\definecolor [dodgerblue] [h=1e90ff]
+\definecolor [deepskyblue] [h=00bfff]
+\definecolor [skyblue] [h=87ceeb]
+\definecolor [lightskyblue] [h=87cefa]
+\definecolor [steelblue] [h=4682b4]
+\definecolor [lightsteelblue] [h=b0c4de]
+\definecolor [lightblue] [h=add8e6]
+\definecolor [powderblue] [h=b0e0e6]
+\definecolor [paleturquoise] [h=afeeee]
+\definecolor [darkturquoise] [h=00ced1]
+\definecolor [mediumturquoise] [h=48d1cc]
+\definecolor [turquoise] [h=40e0d0]
+\definecolor [cyan] [h=00ffff]
+\definecolor [lightcyan] [h=e0ffff]
+\definecolor [cadetblue] [h=5f9ea0]
+\definecolor [mediumaquamarine] [h=66cdaa]
+\definecolor [aquamarine] [h=7fffd4]
+\definecolor [darkgreen] [h=006400]
+\definecolor [darkolivegreen] [h=556b2f]
+\definecolor [darkseagreen] [h=8fbc8f]
+\definecolor [seagreen] [h=2e8b57]
+\definecolor [mediumseagreen] [h=3cb371]
+\definecolor [lightseagreen] [h=20b2aa]
+\definecolor [palegreen] [h=98fb98]
+\definecolor [springgreen] [h=00ff7f]
+\definecolor [lawngreen] [h=7cfc00]
+\definecolor [green] [h=00ff00]
+\definecolor [chartreuse] [h=7fff00]
+\definecolor [mediumspringgreen] [h=00fa9a]
+\definecolor [greenyellow] [h=adff2f]
+\definecolor [limegreen] [h=32cd32]
+\definecolor [yellowgreen] [h=9acd32]
+\definecolor [forestgreen] [h=228b22]
+\definecolor [olivedrab] [h=6b8e23]
+\definecolor [darkkhaki] [h=bdb76b]
+\definecolor [khaki] [h=f0e68c]
+\definecolor [palegoldenrod] [h=eee8aa]
+\definecolor [lightgoldenrodyellow] [h=fafad2]
+\definecolor [lightyellow] [h=ffffe0]
+\definecolor [yellow] [h=ffff00]
+\definecolor [gold] [h=ffd700]
+\definecolor [lightgoldenrod] [h=eedd82]
+\definecolor [goldenrod] [h=daa520]
+\definecolor [darkgoldenrod] [h=b8860b]
+\definecolor [rosybrown] [h=bc8f8f]
+\definecolor [indianred] [h=cd5c5c]
+\definecolor [saddlebrown] [h=8b4513]
+\definecolor [sienna] [h=a0522d]
+\definecolor [peru] [h=cd853f]
+\definecolor [burlywood] [h=deb887]
+\definecolor [beige] [h=f5f5dc]
+\definecolor [wheat] [h=f5deb3]
+\definecolor [sandybrown] [h=f4a460]
+\definecolor [tan] [h=d2b48c]
+\definecolor [chocolate] [h=d2691e]
+\definecolor [firebrick] [h=b22222]
+\definecolor [brown] [h=a52a2a]
+\definecolor [darksalmon] [h=e9967a]
+\definecolor [salmon] [h=fa8072]
+\definecolor [lightsalmon] [h=ffa07a]
+\definecolor [orange] [h=ffa500]
+\definecolor [darkorange] [h=ff8c00]
+\definecolor [coral] [h=ff7f50]
+\definecolor [lightcoral] [h=f08080]
+\definecolor [tomato] [h=ff6347]
+\definecolor [orangered] [h=ff4500]
+\definecolor [red] [h=ff0000]
+\definecolor [hotpink] [h=ff69b4]
+\definecolor [deeppink] [h=ff1493]
+\definecolor [pink] [h=ffc0cb]
+\definecolor [lightpink] [h=ffb6c1]
+\definecolor [palevioletred] [h=db7093]
+\definecolor [maroon] [h=b03060]
+\definecolor [mediumvioletred] [h=c71585]
+\definecolor [violetred] [h=d02090]
+\definecolor [magenta] [h=ff00ff]
+\definecolor [violet] [h=ee82ee]
+\definecolor [plum] [h=dda0dd]
+\definecolor [orchid] [h=da70d6]
+\definecolor [mediumorchid] [h=ba55d3]
+\definecolor [darkorchid] [h=9932cc]
+\definecolor [darkviolet] [h=9400d3]
+\definecolor [blueviolet] [h=8a2be2]
+\definecolor [purple] [h=a020f0]
+\definecolor [mediumpurple] [h=9370db]
+\definecolor [thistle] [h=d8bfd8]
+\definecolor [snow1] [h=fffafa]
+\definecolor [snow2] [h=eee9e9]
+\definecolor [snow3] [h=cdc9c9]
+\definecolor [snow4] [h=8b8989]
+\definecolor [seashell1] [h=fff5ee]
+\definecolor [seashell2] [h=eee5de]
+\definecolor [seashell3] [h=cdc5bf]
+\definecolor [seashell4] [h=8b8682]
+\definecolor [antiquewhite1] [h=ffefdb]
+\definecolor [antiquewhite2] [h=eedfcc]
+\definecolor [antiquewhite3] [h=cdc0b0]
+\definecolor [antiquewhite4] [h=8b8378]
+\definecolor [bisque1] [h=ffe4c4]
+\definecolor [bisque2] [h=eed5b7]
+\definecolor [bisque3] [h=cdb79e]
+\definecolor [bisque4] [h=8b7d6b]
+\definecolor [peachpuff1] [h=ffdab9]
+\definecolor [peachpuff2] [h=eecbad]
+\definecolor [peachpuff3] [h=cdaf95]
+\definecolor [peachpuff4] [h=8b7765]
+\definecolor [navajowhite1] [h=ffdead]
+\definecolor [navajowhite2] [h=eecfa1]
+\definecolor [navajowhite3] [h=cdb38b]
+\definecolor [navajowhite4] [h=8b795e]
+\definecolor [lemonchiffon1] [h=fffacd]
+\definecolor [lemonchiffon2] [h=eee9bf]
+\definecolor [lemonchiffon3] [h=cdc9a5]
+\definecolor [lemonchiffon4] [h=8b8970]
+\definecolor [cornsilk1] [h=fff8dc]
+\definecolor [cornsilk2] [h=eee8cd]
+\definecolor [cornsilk3] [h=cdc8b1]
+\definecolor [cornsilk4] [h=8b8878]
+\definecolor [ivory1] [h=fffff0]
+\definecolor [ivory2] [h=eeeee0]
+\definecolor [ivory3] [h=cdcdc1]
+\definecolor [ivory4] [h=8b8b83]
+\definecolor [honeydew1] [h=f0fff0]
+\definecolor [honeydew2] [h=e0eee0]
+\definecolor [honeydew3] [h=c1cdc1]
+\definecolor [honeydew4] [h=838b83]
+\definecolor [lavenderblush1] [h=fff0f5]
+\definecolor [lavenderblush2] [h=eee0e5]
+\definecolor [lavenderblush3] [h=cdc1c5]
+\definecolor [lavenderblush4] [h=8b8386]
+\definecolor [mistyrose1] [h=ffe4e1]
+\definecolor [mistyrose2] [h=eed5d2]
+\definecolor [mistyrose3] [h=cdb7b5]
+\definecolor [mistyrose4] [h=8b7d7b]
+\definecolor [azure1] [h=f0ffff]
+\definecolor [azure2] [h=e0eeee]
+\definecolor [azure3] [h=c1cdcd]
+\definecolor [azure4] [h=838b8b]
+\definecolor [slateblue1] [h=836fff]
+\definecolor [slateblue2] [h=7a67ee]
+\definecolor [slateblue3] [h=6959cd]
+\definecolor [slateblue4] [h=473c8b]
+\definecolor [royalblue1] [h=4876ff]
+\definecolor [royalblue2] [h=436eee]
+\definecolor [royalblue3] [h=3a5fcd]
+\definecolor [royalblue4] [h=27408b]
+\definecolor [blue1] [h=0000ff]
+\definecolor [blue2] [h=0000ee]
+\definecolor [blue3] [h=0000cd]
+\definecolor [blue4] [h=00008b]
+\definecolor [dodgerblue1] [h=1e90ff]
+\definecolor [dodgerblue2] [h=1c86ee]
+\definecolor [dodgerblue3] [h=1874cd]
+\definecolor [dodgerblue4] [h=104e8b]
+\definecolor [steelblue1] [h=63b8ff]
+\definecolor [steelblue2] [h=5cacee]
+\definecolor [steelblue3] [h=4f94cd]
+\definecolor [steelblue4] [h=36648b]
+\definecolor [deepskyblue1] [h=00bfff]
+\definecolor [deepskyblue2] [h=00b2ee]
+\definecolor [deepskyblue3] [h=009acd]
+\definecolor [deepskyblue4] [h=00688b]
+\definecolor [skyblue1] [h=87ceff]
+\definecolor [skyblue2] [h=7ec0ee]
+\definecolor [skyblue3] [h=6ca6cd]
+\definecolor [skyblue4] [h=4a708b]
+\definecolor [lightskyblue1] [h=b0e2ff]
+\definecolor [lightskyblue2] [h=a4d3ee]
+\definecolor [lightskyblue3] [h=8db6cd]
+\definecolor [lightskyblue4] [h=607b8b]
+\definecolor [slategray1] [h=c6e2ff]
+\definecolor [slategray2] [h=b9d3ee]
+\definecolor [slategray3] [h=9fb6cd]
+\definecolor [slategray4] [h=6c7b8b]
+\definecolor [lightsteelblue1] [h=cae1ff]
+\definecolor [lightsteelblue2] [h=bcd2ee]
+\definecolor [lightsteelblue3] [h=a2b5cd]
+\definecolor [lightsteelblue4] [h=6e7b8b]
+\definecolor [lightblue1] [h=bfefff]
+\definecolor [lightblue2] [h=b2dfee]
+\definecolor [lightblue3] [h=9ac0cd]
+\definecolor [lightblue4] [h=68838b]
+\definecolor [lightcyan1] [h=e0ffff]
+\definecolor [lightcyan2] [h=d1eeee]
+\definecolor [lightcyan3] [h=b4cdcd]
+\definecolor [lightcyan4] [h=7a8b8b]
+\definecolor [paleturquoise1] [h=bbffff]
+\definecolor [paleturquoise2] [h=aeeeee]
+\definecolor [paleturquoise3] [h=96cdcd]
+\definecolor [paleturquoise4] [h=668b8b]
+\definecolor [cadetblue1] [h=98f5ff]
+\definecolor [cadetblue2] [h=8ee5ee]
+\definecolor [cadetblue3] [h=7ac5cd]
+\definecolor [cadetblue4] [h=53868b]
+\definecolor [turquoise1] [h=00f5ff]
+\definecolor [turquoise2] [h=00e5ee]
+\definecolor [turquoise3] [h=00c5cd]
+\definecolor [turquoise4] [h=00868b]
+\definecolor [cyan1] [h=00ffff]
+\definecolor [cyan2] [h=00eeee]
+\definecolor [cyan3] [h=00cdcd]
+\definecolor [cyan4] [h=008b8b]
+\definecolor [darkslategray1] [h=97ffff]
+\definecolor [darkslategray2] [h=8deeee]
+\definecolor [darkslategray3] [h=79cdcd]
+\definecolor [darkslategray4] [h=528b8b]
+\definecolor [aquamarine1] [h=7fffd4]
+\definecolor [aquamarine2] [h=76eec6]
+\definecolor [aquamarine3] [h=66cdaa]
+\definecolor [aquamarine4] [h=458b74]
+\definecolor [darkseagreen1] [h=c1ffc1]
+\definecolor [darkseagreen2] [h=b4eeb4]
+\definecolor [darkseagreen3] [h=9bcd9b]
+\definecolor [darkseagreen4] [h=698b69]
+\definecolor [seagreen1] [h=54ff9f]
+\definecolor [seagreen2] [h=4eee94]
+\definecolor [seagreen3] [h=43cd80]
+\definecolor [seagreen4] [h=2e8b57]
+\definecolor [palegreen1] [h=9aff9a]
+\definecolor [palegreen2] [h=90ee90]
+\definecolor [palegreen3] [h=7ccd7c]
+\definecolor [palegreen4] [h=548b54]
+\definecolor [springgreen1] [h=00ff7f]
+\definecolor [springgreen2] [h=00ee76]
+\definecolor [springgreen3] [h=00cd66]
+\definecolor [springgreen4] [h=008b45]
+\definecolor [green1] [h=00ff00]
+\definecolor [green2] [h=00ee00]
+\definecolor [green3] [h=00cd00]
+\definecolor [green4] [h=008b00]
+\definecolor [chartreuse1] [h=7fff00]
+\definecolor [chartreuse2] [h=76ee00]
+\definecolor [chartreuse3] [h=66cd00]
+\definecolor [chartreuse4] [h=458b00]
+\definecolor [olivedrab1] [h=c0ff3e]
+\definecolor [olivedrab2] [h=b3ee3a]
+\definecolor [olivedrab3] [h=9acd32]
+\definecolor [olivedrab4] [h=698b22]
+\definecolor [darkolivegreen1] [h=caff70]
+\definecolor [darkolivegreen2] [h=bcee68]
+\definecolor [darkolivegreen3] [h=a2cd5a]
+\definecolor [darkolivegreen4] [h=6e8b3d]
+\definecolor [khaki1] [h=fff68f]
+\definecolor [khaki2] [h=eee685]
+\definecolor [khaki3] [h=cdc673]
+\definecolor [khaki4] [h=8b864e]
+\definecolor [lightgoldenrod1] [h=ffec8b]
+\definecolor [lightgoldenrod2] [h=eedc82]
+\definecolor [lightgoldenrod3] [h=cdbe70]
+\definecolor [lightgoldenrod4] [h=8b814c]
+\definecolor [lightyellow1] [h=ffffe0]
+\definecolor [lightyellow2] [h=eeeed1]
+\definecolor [lightyellow3] [h=cdcdb4]
+\definecolor [lightyellow4] [h=8b8b7a]
+\definecolor [yellow1] [h=ffff00]
+\definecolor [yellow2] [h=eeee00]
+\definecolor [yellow3] [h=cdcd00]
+\definecolor [yellow4] [h=8b8b00]
+\definecolor [gold1] [h=ffd700]
+\definecolor [gold2] [h=eec900]
+\definecolor [gold3] [h=cdad00]
+\definecolor [gold4] [h=8b7500]
+\definecolor [goldenrod1] [h=ffc125]
+\definecolor [goldenrod2] [h=eeb422]
+\definecolor [goldenrod3] [h=cd9b1d]
+\definecolor [goldenrod4] [h=8b6914]
+\definecolor [darkgoldenrod1] [h=ffb90f]
+\definecolor [darkgoldenrod2] [h=eead0e]
+\definecolor [darkgoldenrod3] [h=cd950c]
+\definecolor [darkgoldenrod4] [h=8b6508]
+\definecolor [rosybrown1] [h=ffc1c1]
+\definecolor [rosybrown2] [h=eeb4b4]
+\definecolor [rosybrown3] [h=cd9b9b]
+\definecolor [rosybrown4] [h=8b6969]
+\definecolor [indianred1] [h=ff6a6a]
+\definecolor [indianred2] [h=ee6363]
+\definecolor [indianred3] [h=cd5555]
+\definecolor [indianred4] [h=8b3a3a]
+\definecolor [sienna1] [h=ff8247]
+\definecolor [sienna2] [h=ee7942]
+\definecolor [sienna3] [h=cd6839]
+\definecolor [sienna4] [h=8b4726]
+\definecolor [burlywood1] [h=ffd39b]
+\definecolor [burlywood2] [h=eec591]
+\definecolor [burlywood3] [h=cdaa7d]
+\definecolor [burlywood4] [h=8b7355]
+\definecolor [wheat1] [h=ffe7ba]
+\definecolor [wheat2] [h=eed8ae]
+\definecolor [wheat3] [h=cdba96]
+\definecolor [wheat4] [h=8b7e66]
+\definecolor [tan1] [h=ffa54f]
+\definecolor [tan2] [h=ee9a49]
+\definecolor [tan3] [h=cd853f]
+\definecolor [tan4] [h=8b5a2b]
+\definecolor [chocolate1] [h=ff7f24]
+\definecolor [chocolate2] [h=ee7621]
+\definecolor [chocolate3] [h=cd661d]
+\definecolor [chocolate4] [h=8b4513]
+\definecolor [firebrick1] [h=ff3030]
+\definecolor [firebrick2] [h=ee2c2c]
+\definecolor [firebrick3] [h=cd2626]
+\definecolor [firebrick4] [h=8b1a1a]
+\definecolor [brown1] [h=ff4040]
+\definecolor [brown2] [h=ee3b3b]
+\definecolor [brown3] [h=cd3333]
+\definecolor [brown4] [h=8b2323]
+\definecolor [salmon1] [h=ff8c69]
+\definecolor [salmon2] [h=ee8262]
+\definecolor [salmon3] [h=cd7054]
+\definecolor [salmon4] [h=8b4c39]
+\definecolor [lightsalmon1] [h=ffa07a]
+\definecolor [lightsalmon2] [h=ee9572]
+\definecolor [lightsalmon3] [h=cd8162]
+\definecolor [lightsalmon4] [h=8b5742]
+\definecolor [orange1] [h=ffa500]
+\definecolor [orange2] [h=ee9a00]
+\definecolor [orange3] [h=cd8500]
+\definecolor [orange4] [h=8b5a00]
+\definecolor [darkorange1] [h=ff7f00]
+\definecolor [darkorange2] [h=ee7600]
+\definecolor [darkorange3] [h=cd6600]
+\definecolor [darkorange4] [h=8b4500]
+\definecolor [coral1] [h=ff7256]
+\definecolor [coral2] [h=ee6a50]
+\definecolor [coral3] [h=cd5b45]
+\definecolor [coral4] [h=8b3e2f]
+\definecolor [tomato1] [h=ff6347]
+\definecolor [tomato2] [h=ee5c42]
+\definecolor [tomato3] [h=cd4f39]
+\definecolor [tomato4] [h=8b3626]
+\definecolor [orangered1] [h=ff4500]
+\definecolor [orangered2] [h=ee4000]
+\definecolor [orangered3] [h=cd3700]
+\definecolor [orangered4] [h=8b2500]
+\definecolor [red1] [h=ff0000]
+\definecolor [red2] [h=ee0000]
+\definecolor [red3] [h=cd0000]
+\definecolor [red4] [h=8b0000]
+\definecolor [debianred] [h=d70751]
+\definecolor [deeppink1] [h=ff1493]
+\definecolor [deeppink2] [h=ee1289]
+\definecolor [deeppink3] [h=cd1076]
+\definecolor [deeppink4] [h=8b0a50]
+\definecolor [hotpink1] [h=ff6eb4]
+\definecolor [hotpink2] [h=ee6aa7]
+\definecolor [hotpink3] [h=cd6090]
+\definecolor [hotpink4] [h=8b3a62]
+\definecolor [pink1] [h=ffb5c5]
+\definecolor [pink2] [h=eea9b8]
+\definecolor [pink3] [h=cd919e]
+\definecolor [pink4] [h=8b636c]
+\definecolor [lightpink1] [h=ffaeb9]
+\definecolor [lightpink2] [h=eea2ad]
+\definecolor [lightpink3] [h=cd8c95]
+\definecolor [lightpink4] [h=8b5f65]
+\definecolor [palevioletred1] [h=ff82ab]
+\definecolor [palevioletred2] [h=ee799f]
+\definecolor [palevioletred3] [h=cd6889]
+\definecolor [palevioletred4] [h=8b475d]
+\definecolor [maroon1] [h=ff34b3]
+\definecolor [maroon2] [h=ee30a7]
+\definecolor [maroon3] [h=cd2990]
+\definecolor [maroon4] [h=8b1c62]
+\definecolor [violetred1] [h=ff3e96]
+\definecolor [violetred2] [h=ee3a8c]
+\definecolor [violetred3] [h=cd3278]
+\definecolor [violetred4] [h=8b2252]
+\definecolor [magenta1] [h=ff00ff]
+\definecolor [magenta2] [h=ee00ee]
+\definecolor [magenta3] [h=cd00cd]
+\definecolor [magenta4] [h=8b008b]
+\definecolor [orchid1] [h=ff83fa]
+\definecolor [orchid2] [h=ee7ae9]
+\definecolor [orchid3] [h=cd69c9]
+\definecolor [orchid4] [h=8b4789]
+\definecolor [plum1] [h=ffbbff]
+\definecolor [plum2] [h=eeaeee]
+\definecolor [plum3] [h=cd96cd]
+\definecolor [plum4] [h=8b668b]
+\definecolor [mediumorchid1] [h=e066ff]
+\definecolor [mediumorchid2] [h=d15fee]
+\definecolor [mediumorchid3] [h=b452cd]
+\definecolor [mediumorchid4] [h=7a378b]
+\definecolor [darkorchid1] [h=bf3eff]
+\definecolor [darkorchid2] [h=b23aee]
+\definecolor [darkorchid3] [h=9a32cd]
+\definecolor [darkorchid4] [h=68228b]
+\definecolor [purple1] [h=9b30ff]
+\definecolor [purple2] [h=912cee]
+\definecolor [purple3] [h=7d26cd]
+\definecolor [purple4] [h=551a8b]
+\definecolor [mediumpurple1] [h=ab82ff]
+\definecolor [mediumpurple2] [h=9f79ee]
+\definecolor [mediumpurple3] [h=8968cd]
+\definecolor [mediumpurple4] [h=5d478b]
+\definecolor [thistle1] [h=ffe1ff]
+\definecolor [thistle2] [h=eed2ee]
+\definecolor [thistle3] [h=cdb5cd]
+\definecolor [thistle4] [h=8b7b8b]
+\definecolor [gray0] [s=0.00]
+\definecolor [grey0] [gray0]
+\definecolor [gray1] [s=0.01]
+\definecolor [grey1] [gray1]
+\definecolor [gray2] [s=0.02]
+\definecolor [grey2] [gray2]
+\definecolor [gray3] [s=0.03]
+\definecolor [grey3] [gray3]
+\definecolor [gray4] [s=0.04]
+\definecolor [grey4] [gray4]
+\definecolor [gray5] [s=0.05]
+\definecolor [grey5] [gray5]
+\definecolor [gray6] [s=0.06]
+\definecolor [grey6] [gray6]
+\definecolor [gray7] [s=0.07]
+\definecolor [grey7] [gray7]
+\definecolor [gray8] [s=0.08]
+\definecolor [grey8] [gray8]
+\definecolor [gray9] [s=0.09]
+\definecolor [grey9] [gray9]
+\definecolor [gray10] [s=0.10]
+\definecolor [grey10] [gray10]
+\definecolor [gray11] [s=0.11]
+\definecolor [grey11] [gray11]
+\definecolor [gray12] [s=0.12]
+\definecolor [grey12] [gray12]
+\definecolor [gray13] [s=0.13]
+\definecolor [grey13] [gray13]
+\definecolor [gray14] [s=0.14]
+\definecolor [grey14] [gray14]
+\definecolor [gray15] [s=0.15]
+\definecolor [grey15] [gray15]
+\definecolor [gray16] [s=0.16]
+\definecolor [grey16] [gray16]
+\definecolor [gray17] [s=0.17]
+\definecolor [grey17] [gray17]
+\definecolor [gray18] [s=0.18]
+\definecolor [grey18] [gray18]
+\definecolor [gray19] [s=0.19]
+\definecolor [grey19] [gray19]
+\definecolor [gray20] [s=0.20]
+\definecolor [grey20] [gray20]
+\definecolor [gray21] [s=0.21]
+\definecolor [grey21] [gray21]
+\definecolor [gray22] [s=0.22]
+\definecolor [grey22] [gray22]
+\definecolor [gray23] [s=0.23]
+\definecolor [grey23] [gray23]
+\definecolor [gray24] [s=0.24]
+\definecolor [grey24] [gray24]
+\definecolor [gray25] [s=0.25]
+\definecolor [grey25] [gray25]
+\definecolor [gray26] [s=0.26]
+\definecolor [grey26] [gray26]
+\definecolor [gray27] [s=0.27]
+\definecolor [grey27] [gray27]
+\definecolor [gray28] [s=0.28]
+\definecolor [grey28] [gray28]
+\definecolor [gray29] [s=0.29]
+\definecolor [grey29] [gray29]
+\definecolor [gray30] [s=0.30]
+\definecolor [grey30] [gray30]
+\definecolor [gray31] [s=0.31]
+\definecolor [grey31] [gray31]
+\definecolor [gray32] [s=0.32]
+\definecolor [grey32] [gray32]
+\definecolor [gray33] [s=0.33]
+\definecolor [grey33] [gray33]
+\definecolor [gray34] [s=0.34]
+\definecolor [grey34] [gray34]
+\definecolor [gray35] [s=0.35]
+\definecolor [grey35] [gray35]
+\definecolor [gray36] [s=0.36]
+\definecolor [grey36] [gray36]
+\definecolor [gray37] [s=0.37]
+\definecolor [grey37] [gray37]
+\definecolor [gray38] [s=0.38]
+\definecolor [grey38] [gray38]
+\definecolor [gray39] [s=0.39]
+\definecolor [grey39] [gray39]
+\definecolor [gray40] [s=0.40]
+\definecolor [grey40] [gray40]
+\definecolor [gray41] [s=0.41]
+\definecolor [grey41] [gray41]
+\definecolor [gray42] [s=0.42]
+\definecolor [grey42] [gray42]
+\definecolor [gray43] [s=0.43]
+\definecolor [grey43] [gray43]
+\definecolor [gray44] [s=0.44]
+\definecolor [grey44] [gray44]
+\definecolor [gray45] [s=0.45]
+\definecolor [grey45] [gray45]
+\definecolor [gray46] [s=0.46]
+\definecolor [grey46] [gray46]
+\definecolor [gray47] [s=0.47]
+\definecolor [grey47] [gray47]
+\definecolor [gray48] [s=0.48]
+\definecolor [grey48] [gray48]
+\definecolor [gray49] [s=0.49]
+\definecolor [grey49] [gray49]
+\definecolor [gray50] [s=0.50]
+\definecolor [grey50] [gray50]
+\definecolor [gray51] [s=0.51]
+\definecolor [grey51] [gray51]
+\definecolor [gray52] [s=0.52]
+\definecolor [grey52] [gray52]
+\definecolor [gray53] [s=0.53]
+\definecolor [grey53] [gray53]
+\definecolor [gray54] [s=0.54]
+\definecolor [grey54] [gray54]
+\definecolor [gray55] [s=0.55]
+\definecolor [grey55] [gray55]
+\definecolor [gray56] [s=0.56]
+\definecolor [grey56] [gray56]
+\definecolor [gray57] [s=0.57]
+\definecolor [grey57] [gray57]
+\definecolor [gray58] [s=0.58]
+\definecolor [grey58] [gray58]
+\definecolor [gray59] [s=0.59]
+\definecolor [grey59] [gray59]
+\definecolor [gray60] [s=0.60]
+\definecolor [grey60] [gray60]
+\definecolor [gray61] [s=0.61]
+\definecolor [grey61] [gray61]
+\definecolor [gray62] [s=0.62]
+\definecolor [grey62] [gray62]
+\definecolor [gray63] [s=0.63]
+\definecolor [grey63] [gray63]
+\definecolor [gray64] [s=0.64]
+\definecolor [grey64] [gray64]
+\definecolor [gray65] [s=0.65]
+\definecolor [grey65] [gray65]
+\definecolor [gray66] [s=0.66]
+\definecolor [grey66] [gray66]
+\definecolor [gray67] [s=0.67]
+\definecolor [grey67] [gray67]
+\definecolor [gray68] [s=0.68]
+\definecolor [grey68] [gray68]
+\definecolor [gray69] [s=0.69]
+\definecolor [grey69] [gray69]
+\definecolor [gray70] [s=0.70]
+\definecolor [grey70] [gray70]
+\definecolor [gray71] [s=0.71]
+\definecolor [grey71] [gray71]
+\definecolor [gray72] [s=0.72]
+\definecolor [grey72] [gray72]
+\definecolor [gray73] [s=0.73]
+\definecolor [grey73] [gray73]
+\definecolor [gray74] [s=0.74]
+\definecolor [grey74] [gray74]
+\definecolor [gray75] [s=0.75]
+\definecolor [grey75] [gray75]
+\definecolor [gray76] [s=0.76]
+\definecolor [grey76] [gray76]
+\definecolor [gray77] [s=0.77]
+\definecolor [grey77] [gray77]
+\definecolor [gray78] [s=0.78]
+\definecolor [grey78] [gray78]
+\definecolor [gray79] [s=0.79]
+\definecolor [grey79] [gray79]
+\definecolor [gray80] [s=0.80]
+\definecolor [grey80] [gray80]
+\definecolor [gray81] [s=0.81]
+\definecolor [grey81] [gray81]
+\definecolor [gray82] [s=0.82]
+\definecolor [grey82] [gray82]
+\definecolor [gray83] [s=0.83]
+\definecolor [grey83] [gray83]
+\definecolor [gray84] [s=0.84]
+\definecolor [grey84] [gray84]
+\definecolor [gray85] [s=0.85]
+\definecolor [grey85] [gray85]
+\definecolor [gray86] [s=0.86]
+\definecolor [grey86] [gray86]
+\definecolor [gray87] [s=0.87]
+\definecolor [grey87] [gray87]
+\definecolor [gray88] [s=0.88]
+\definecolor [grey88] [gray88]
+\definecolor [gray89] [s=0.89]
+\definecolor [grey89] [gray89]
+\definecolor [gray90] [s=0.90]
+\definecolor [grey90] [gray90]
+\definecolor [gray91] [s=0.91]
+\definecolor [grey91] [gray91]
+\definecolor [gray92] [s=0.92]
+\definecolor [grey92] [gray92]
+\definecolor [gray93] [s=0.93]
+\definecolor [grey93] [gray93]
+\definecolor [gray94] [s=0.94]
+\definecolor [grey94] [gray94]
+\definecolor [gray95] [s=0.95]
+\definecolor [grey95] [gray95]
+\definecolor [gray96] [s=0.96]
+\definecolor [grey96] [gray96]
+\definecolor [gray97] [s=0.97]
+\definecolor [grey97] [gray97]
+\definecolor [gray98] [s=0.98]
+\definecolor [grey98] [gray98]
+\definecolor [gray99] [s=0.99]
+\definecolor [grey99] [gray99]
+\definecolor [gray100] [s=1.00]
+\definecolor [grey100] [gray100]
+\definecolor [darkgrey] [s=0.66]
+\definecolor [darkgray] [darkgrey]
+\definecolor [darkblue] [h=00008b]
+\definecolor [darkcyan] [h=008b8b]
+\definecolor [darkmagenta] [h=8b008b]
+\definecolor [darkred] [h=8b0000]
+\definecolor [lightgreen] [h=90ee90]
+
+\endinput
diff --git a/tex/context/base/colo-xwi.tex b/tex/context/base/colo-xwi.tex
new file mode 100644
index 000000000..81e09d871
--- /dev/null
+++ b/tex/context/base/colo-xwi.tex
@@ -0,0 +1,142 @@
+%D \module
+%D [ file=colo-xwi,
+%D version=1995.01.01,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=X Windows,
+%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.
+
+%D I've forgotten where I got these definitions from, but maybe
+%D they can be of use.
+
+\definecolor [aliceblue] [r=0.94,g=0.97,b=1.00]
+\definecolor [antiquewhite] [r=0.98,g=0.92,b=0.84]
+\definecolor [aquamarine] [r=0.50,g=1.00,b=0.83]
+\definecolor [azure] [r=0.94,g=1.00,b=1.00]
+\definecolor [beige] [r=0.96,g=0.96,b=0.86]
+\definecolor [bisque] [r=1.00,g=0.89,b=0.77]
+\definecolor [black] [s=0] % [r=0.00,g=0.00,b=0.00]
+\definecolor [blanchedalmond] [r=1.00,g=0.92,b=0.80]
+\definecolor [blue] [r=0.00,g=0.00,b=1.00]
+\definecolor [blueviolet] [r=0.54,g=0.17,b=0.89]
+\definecolor [brown] [r=0.65,g=0.16,b=0.16]
+\definecolor [burlywood] [r=0.87,g=0.72,b=0.53]
+\definecolor [cadetblue] [r=0.37,g=0.62,b=0.63]
+\definecolor [chartreuse] [r=0.50,g=1.00,b=0.00]
+\definecolor [chocolate] [r=0.82,g=0.41,b=0.12]
+\definecolor [coral] [r=1.00,g=0.50,b=0.31]
+\definecolor [cornflowerblue] [r=0.39,g=0.58,b=0.93]
+\definecolor [cornsilk] [r=1.00,g=0.97,b=0.86]
+\definecolor [cyan] [r=0.00,g=1.00,b=1.00]
+\definecolor [darkgoldenrod] [r=0.72,g=0.53,b=0.04]
+\definecolor [darkgreen] [r=0.00,g=0.39,b=0.00]
+\definecolor [darkkhaki] [r=0.74,g=0.72,b=0.42]
+\definecolor [darkolivegreen] [r=0.33,g=0.42,b=0.18]
+\definecolor [darkorange] [r=1.00,g=0.55,b=0.00]
+\definecolor [darkorchid] [r=0.60,g=0.20,b=0.80]
+\definecolor [darksalmon] [r=0.91,g=0.59,b=0.48]
+\definecolor [darkseagreen] [r=0.56,g=0.74,b=0.56]
+\definecolor [darkslateblue] [r=0.28,g=0.24,b=0.55]
+\definecolor [darkturquoise] [r=0.00,g=0.81,b=0.82]
+\definecolor [darkviolet] [r=0.58,g=0.00,b=0.83]
+\definecolor [deeppink] [r=1.00,g=0.08,b=0.58]
+\definecolor [deepskyblue] [r=0.00,g=0.75,b=1.00]
+\definecolor [dodgerblue] [r=0.12,g=0.56,b=1.00]
+\definecolor [firebrick] [r=0.70,g=0.13,b=0.13]
+\definecolor [floralwhite] [r=1.00,g=0.98,b=0.94]
+\definecolor [forestgreen] [r=0.13,g=0.55,b=0.13]
+\definecolor [gainsboro] [r=0.86,g=0.86,b=0.86]
+\definecolor [ghostwhite] [r=0.97,g=0.97,b=1.00]
+\definecolor [gold] [r=1.00,g=0.84,b=0.00]
+\definecolor [goldenrod] [r=0.85,g=0.65,b=0.13]
+\definecolor [green] [r=0.00,g=1.00,b=0.00]
+\definecolor [greenyellow] [r=0.68,g=1.00,b=0.18]
+\definecolor [honeydew] [r=0.94,g=1.00,b=0.94]
+\definecolor [hotpink] [r=1.00,g=0.41,b=0.71]
+\definecolor [indianred] [r=0.80,g=0.36,b=0.36]
+\definecolor [ivory] [r=1.00,g=1.00,b=0.94]
+\definecolor [khaki] [r=0.94,g=0.90,b=0.55]
+\definecolor [lavender] [r=0.90,g=0.90,b=0.98]
+\definecolor [lavenderblush] [r=1.00,g=0.94,b=0.96]
+\definecolor [lawngreen] [r=0.49,g=0.99,b=0.00]
+\definecolor [lemonchiffon] [r=1.00,g=0.98,b=0.80]
+\definecolor [lightblue] [r=0.68,g=0.85,b=0.90]
+\definecolor [lightcoral] [r=0.94,g=0.50,b=0.50]
+\definecolor [lightcyan] [r=0.88,g=1.00,b=1.00]
+\definecolor [lightgoldenrod] [r=0.93,g=0.87,b=0.51]
+\definecolor [lightgoldenrodyellow] [r=0.98,g=0.98,b=0.82]
+\definecolor [lightpink] [r=1.00,g=0.71,b=0.76]
+\definecolor [lightsalmon] [r=1.00,g=0.63,b=0.48]
+\definecolor [lightseagreen] [r=0.13,g=0.70,b=0.67]
+\definecolor [lightskyblue] [r=0.53,g=0.81,b=0.98]
+\definecolor [lightslateblue] [r=0.52,g=0.44,b=1.00]
+\definecolor [lightsteelblue] [r=0.69,g=0.77,b=0.87]
+\definecolor [lightyellow] [r=1.00,g=1.00,b=0.88]
+\definecolor [limegreen] [r=0.20,g=0.80,b=0.20]
+\definecolor [linen] [r=0.98,g=0.94,b=0.90]
+\definecolor [magenta] [r=1.00,g=0.00,b=1.00]
+\definecolor [maroon] [r=0.69,g=0.19,b=0.38]
+\definecolor [mediumaquamarine] [r=0.40,g=0.80,b=0.67]
+\definecolor [mediumblue] [r=0.00,g=0.00,b=0.80]
+\definecolor [mediumorchid] [r=0.73,g=0.33,b=0.83]
+\definecolor [mediumpurple] [r=0.58,g=0.44,b=0.86]
+\definecolor [mediumseagreen] [r=0.24,g=0.70,b=0.44]
+\definecolor [mediumslateblue] [r=0.48,g=0.41,b=0.93]
+\definecolor [mediumspringgreen] [r=0.00,g=0.98,b=0.60]
+\definecolor [mediumturquoise] [r=0.28,g=0.82,b=0.80]
+\definecolor [mediumvioletred] [r=0.78,g=0.08,b=0.52]
+\definecolor [midnightblue] [r=0.10,g=0.10,b=0.44]
+\definecolor [mintcream] [r=0.96,g=1.00,b=0.98]
+\definecolor [mistyrose] [r=1.00,g=0.89,b=0.88]
+\definecolor [moccasin] [r=1.00,g=0.89,b=0.71]
+\definecolor [navajowhite] [r=1.00,g=0.87,b=0.68]
+\definecolor [navy] [r=0.00,g=0.00,b=0.50]
+\definecolor [navyblue] [r=0.00,g=0.00,b=0.50]
+\definecolor [oldlace] [r=0.99,g=0.96,b=0.90]
+\definecolor [olivedrab] [r=0.42,g=0.56,b=0.14]
+\definecolor [orange] [r=1.00,g=0.65,b=0.00]
+\definecolor [orangered] [r=1.00,g=0.27,b=0.00]
+\definecolor [orchid] [r=0.85,g=0.44,b=0.84]
+\definecolor [palegoldenrod] [r=0.93,g=0.91,b=0.67]
+\definecolor [palegreen] [r=0.60,g=0.98,b=0.60]
+\definecolor [paleturquoise] [r=0.69,g=0.93,b=0.93]
+\definecolor [palevioletred] [r=0.86,g=0.44,b=0.58]
+\definecolor [papayawhip] [r=1.00,g=0.94,b=0.84]
+\definecolor [peachpuff] [r=1.00,g=0.85,b=0.73]
+\definecolor [peru] [r=0.80,g=0.52,b=0.25]
+\definecolor [pink] [r=1.00,g=0.75,b=0.80]
+\definecolor [plum] [r=0.87,g=0.63,b=0.87]
+\definecolor [powderblue] [r=0.69,g=0.88,b=0.90]
+\definecolor [purple] [r=0.63,g=0.13,b=0.94]
+\definecolor [red ] [r=1.00,g=0.00,b=0.00]
+\definecolor [rosybrown] [r=0.74,g=0.56,b=0.56]
+\definecolor [royalblue] [r=0.25,g=0.41,b=0.88]
+\definecolor [saddlebrown] [r=0.55,g=0.27,b=0.07]
+\definecolor [salmon] [r=0.98,g=0.50,b=0.45]
+\definecolor [sandybrown] [r=0.96,g=0.64,b=0.38]
+\definecolor [seagreen] [r=0.18,g=0.55,b=0.34]
+\definecolor [seashell] [r=1.00,g=0.96,b=0.93]
+\definecolor [sienna] [r=0.63,g=0.32,b=0.18]
+\definecolor [skyblue] [r=0.53,g=0.81,b=0.92]
+\definecolor [slateblue] [r=0.42,g=0.35,b=0.80]
+\definecolor [snow] [r=1.00,g=0.98,b=0.98]
+\definecolor [springgreen] [r=0.00,g=1.00,b=0.50]
+\definecolor [steelblue] [r=0.27,g=0.51,b=0.71]
+\definecolor [tan ] [r=0.82,g=0.71,b=0.55]
+\definecolor [thistle] [r=0.85,g=0.75,b=0.85]
+\definecolor [tomato] [r=1.00,g=0.39,b=0.28]
+\definecolor [turquoise] [r=0.25,g=0.88,b=0.82]
+\definecolor [violet] [r=0.93,g=0.51,b=0.93]
+\definecolor [violetred] [r=0.82,g=0.13,b=0.56]
+\definecolor [wheat] [r=0.96,g=0.87,b=0.70]
+\definecolor [white] [r=1.00,g=1.00,b=1.00]
+\definecolor [whitesmoke] [s=0.96] % [r=0.96,g=0.96,b=0.96]
+\definecolor [yellow] [r=1.00,g=1.00,b=0.00]
+\definecolor [yellowgreen] [r=0.60,g=0.80,b=0.20]
+
+\endinput
diff --git a/tex/context/base/cont-cs.tex b/tex/context/base/cont-cs.tex
new file mode 100644
index 000000000..f878920aa
--- /dev/null
+++ b/tex/context/base/cont-cs.tex
@@ -0,0 +1,39 @@
+%D \module
+%D [ file=cont-cs,
+%D version=1998.12.02,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Czech Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \def\defaultinterface{czech}
+
+\input context.tex
+
+\unprotect
+
+\setupcurrentlanguage[\s!cs]
+
+\loaduserspecifications
+
+\installlanguage [\s!en] [\c!state=\v!start]
+\installlanguage [\s!de] [\c!state=\v!start]
+\installlanguage [\s!sk] [\c!state=\v!start]
+\installlanguage [\s!cs] [\c!state=\v!start]
+
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-de.tex b/tex/context/base/cont-de.tex
new file mode 100644
index 000000000..460ca7eca
--- /dev/null
+++ b/tex/context/base/cont-de.tex
@@ -0,0 +1,44 @@
+%D \module
+%D [ file=cont-de,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ German Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \def\defaultinterface{german}
+
+\input context.tex
+
+\unprotect
+
+\setupcurrentlanguage[\s!de]
+
+\loaduserspecifications
+
+\installlanguage [\s!us] [\c!state=\v!start]
+\installlanguage [\s!gb] [\c!state=\v!start]
+\installlanguage [\s!de] [\c!state=\v!start]
+\installlanguage [\s!fr] [\c!state=\v!start]
+\installlanguage [\s!es] [\c!state=\v!start]
+\installlanguage [\s!nl] [\c!state=\v!start]
+\installlanguage [\s!it] [\c!state=\v!start]
+
+\installlanguage [deo] [\c!state=\v!start]
+
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-en.tex b/tex/context/base/cont-en.tex
new file mode 100644
index 000000000..e2b09ecbe
--- /dev/null
+++ b/tex/context/base/cont-en.tex
@@ -0,0 +1,46 @@
+%D \module
+%D [ file=cont-en,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ English Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \def\defaultinterface{english}
+
+\input context.tex
+
+\unprotect
+
+\setupcurrentlanguage[\s!en]
+
+\loaduserspecifications
+
+% Do we need more defaults? or maybe all languages?
+
+\installlanguage [\s!us] [\c!state=\v!start]
+\installlanguage [\s!gb] [\c!state=\v!start]
+\installlanguage [\s!de] [\c!state=\v!start]
+\installlanguage [\s!fr] [\c!state=\v!start]
+\installlanguage [\s!es] [\c!state=\v!start]
+\installlanguage [\s!pt] [\c!state=\v!start]
+\installlanguage [\s!it] [\c!state=\v!start]
+\installlanguage [\s!nl] [\c!state=\v!start]
+\installlanguage [\s!cs] [\c!state=\v!start]
+\installlanguage [\s!sk] [\c!state=\v!start]
+\installlanguage [\s!pl] [\c!state=\v!start]
+
+\ifnum\texengine=\luatexengine
+% \prependtoks
+% \the \everysetupdocument
+% \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-err.tex b/tex/context/base/cont-err.tex
new file mode 100644
index 000000000..f01ce87aa
--- /dev/null
+++ b/tex/context/base/cont-err.tex
@@ -0,0 +1,18 @@
+%D \module
+%D [ file=cont-err,
+%D version=2003.08.12,
+%D title=\CONTEXT\ System Files,
+%D subtitle=Just A warning,
+%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.
+
+\unprotect
+
+\writestatus\m!systems{no file 'cont-sys.tex', using 'cont-sys.rme' instead}
+
+\protect \endinput
diff --git a/tex/context/base/cont-fil.tex b/tex/context/base/cont-fil.tex
new file mode 100644
index 000000000..b295872ca
--- /dev/null
+++ b/tex/context/base/cont-fil.tex
@@ -0,0 +1,124 @@
+%D \module
+%D [ file=cont-fil,
+%D version=1997.11.15,
+%D title=\CONTEXT\ Miscellaneous Macros,
+%D subtitle=File Synonyms,
+%D author=J. 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 File Synonyms}
+
+\definefilesynonym [chemie] [chemic]
+\definefilesynonym [chemics] [chemic]
+
+\definefilesynonym [unit] [units]
+\definefilesynonym [eenheid] [units]
+\definefilesynonym [einheit] [units]
+
+\definefilesynonym [pstric] [pstricks]
+\definefilesynonym [pstrick] [pstricks]
+
+\definefilesynonym [finance] [financ]
+
+\definefilesynonym [con-01] [contml] % will go away
+
+%definefilesynonym [sch-base] [sch-00]
+%definefilesynonym [sch-make] [sch-01]
+
+\definefilesynonym [dir-make] [dir-01]
+\definefilesynonym [dir-identify] [dir-05]
+
+\definefilesynonym [xml-format] [xml-01]
+\definefilesynonym [xml-pretty] [xml-02]
+\definefilesynonym [xml-analyze] [xml-11]
+
+\definefilesynonym [int-load] [set-11]
+\definefilesynonym [int-make] [set-12]
+
+\definefilesynonym [fig-base] [fig-00]
+\definefilesynonym [fig-make] [fig-01]
+\definefilesynonym [fig-fake] [fig-02]
+\definefilesynonym [fig-missing] [fig-06]
+
+\definefilesynonym [exi-interface] [exi-21]
+
+\definefilesynonym [res-make] [res-01]
+\definefilesynonym [res-base] [res-04]
+\definefilesynonym [res-crop] [res-07]
+\definefilesynonym [res-trace] [res-08]
+\definefilesynonym [res-log] [res-09]
+\definefilesynonym [res-identify] [res-12]
+
+\definefilesynonym [med-show] [res-50]
+
+\definefilesynonym [pre-general] [pre-00]
+
+\definefilesynonym [pre-original] [pre-01]
+\definefilesynonym [pre-green] [pre-02]
+\definefilesynonym [pre-funny] [pre-03]
+\definefilesynonym [pre-colorful] [pre-04]
+\definefilesynonym [pre-fuzzy] [pre-05]
+\definefilesynonym [pre-polish] [pre-06]
+\definefilesynonym [pre-spider] [pre-07]
+\definefilesynonym [pre-wonder] [pre-08]
+\definefilesynonym [pre-windows] [pre-09]
+\definefilesynonym [pre-grow] [pre-10]
+\definefilesynonym [pre-stack] [pre-11]
+\definefilesynonym [pre-arrows] [pre-12]
+\definefilesynonym [pre-writing] [pre-13]
+\definefilesynonym [pre-split] [pre-14]
+\definefilesynonym [pre-balls] [pre-15]
+\definefilesynonym [pre-knot] [pre-16]
+\definefilesynonym [pre-weird] [pre-17]
+\definefilesynonym [pre-shade] [pre-18]
+\definefilesynonym [pre-organic] [pre-19]
+\definefilesynonym [pre-speckle] [pre-20]
+\definefilesynonym [pre-zoom] [pre-21]
+\definefilesynonym [pre-cycle] [pre-22]
+\definefilesynonym [pre-super] [pre-23]
+
+%definefilesynonym [pre-more] [pre-24]
+%definefilesynonym [pre-more] [pre-25]
+
+\definefilesynonym [pre-more] [pre-26]
+
+%definefilesynonym [pre-more] [pre-27]
+%definefilesynonym [pre-more] [pre-28]
+%definefilesynonym [pre-more] [pre-29]
+%definefilesynonym [pre-more] [pre-30]
+
+\definefilesynonym [pre-stepwise] [pre-60]
+\definefilesynonym [pre-stepper] [pre-61]
+
+\definefilesynonym [pre-punk] [pre-70]
+\definefilesynonym [pre-random] [pre-71]
+
+\definefilesynonym [abr-pseudocaps] [abr-01]
+\definefilesynonym [abr-smallcaps] [abr-02]
+
+\definefilesynonym [chinese] [chi-00]
+\definefilesynonym [japanese] [jap-00]
+
+%definefilesynonym [chi-simplified] [chi-01]
+%definefilesynonym [chi-traditional] [chi-02]
+
+\definefilesynonym [greek] [grk-00]
+
+\definefilesynonym [unic-chi] [unic-cjk]
+\definefilesynonym [unic-jap] [unic-cjk]
+
+%definefilesynonym [practexjournal] [ptj-01]
+\definefilesynonym [pracjourn] [ptj-01]
+
+\definefilesynonym [maps] [map-10]
+\definefilesynonym [map-se] [map-10] % for some time
+
+\definefilesynonym [mml] [mathml]
+\definefilesynonym [cml] [chemml]
+
+\endinput
diff --git a/tex/context/base/cont-fr.tex b/tex/context/base/cont-fr.tex
new file mode 100644
index 000000000..d812b28f9
--- /dev/null
+++ b/tex/context/base/cont-fr.tex
@@ -0,0 +1,42 @@
+%D \module
+%D [ file=cont-de,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ French Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \def\defaultinterface{french}
+
+\input context.tex
+
+\unprotect
+
+\setupcurrentlanguage[\s!fr]
+
+\loaduserspecifications
+
+\installlanguage [\s!us] [\c!state=\v!start]
+\installlanguage [\s!gb] [\c!state=\v!start]
+\installlanguage [\s!de] [\c!state=\v!start]
+\installlanguage [\s!fr] [\c!state=\v!start]
+\installlanguage [\s!es] [\c!state=\v!start]
+\installlanguage [\s!nl] [\c!state=\v!start]
+\installlanguage [\s!it] [\c!state=\v!start]
+
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-gb.tex b/tex/context/base/cont-gb.tex
new file mode 100644
index 000000000..99d297425
--- /dev/null
+++ b/tex/context/base/cont-gb.tex
@@ -0,0 +1,42 @@
+%D \module
+%D [ file=cont-uk,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ English Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \def\defaultinterface{english}
+
+\input context.tex
+
+\unprotect
+
+\setupcurrentlanguage[\s!gb]
+
+\loaduserspecifications
+
+\installlanguage [\s!us] [\c!state=\v!start]
+\installlanguage [\s!gb] [\c!state=\v!start]
+\installlanguage [\s!de] [\c!state=\v!start]
+\installlanguage [\s!fr] [\c!state=\v!start]
+\installlanguage [\s!es] [\c!state=\v!start]
+\installlanguage [\s!nl] [\c!state=\v!start]
+\installlanguage [\s!it] [\c!state=\v!start]
+
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-it.tex b/tex/context/base/cont-it.tex
new file mode 100644
index 000000000..2141e3bc9
--- /dev/null
+++ b/tex/context/base/cont-it.tex
@@ -0,0 +1,41 @@
+%D \module
+%D [ file=cont-it,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Italian Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \def\defaultinterface{italian}
+
+\input context.tex
+
+\unprotect
+
+\setupcurrentlanguage[\s!it]
+
+\loaduserspecifications
+
+\installlanguage [\s!us] [\c!state=\v!start]
+\installlanguage [\s!gb] [\c!state=\v!start]
+\installlanguage [\s!de] [\c!state=\v!start]
+\installlanguage [\s!fr] [\c!state=\v!start]
+\installlanguage [\s!es] [\c!state=\v!start]
+\installlanguage [\s!it] [\c!state=\v!start]
+
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-log.tex b/tex/context/base/cont-log.tex
new file mode 100644
index 000000000..9bfec2999
--- /dev/null
+++ b/tex/context/base/cont-log.tex
@@ -0,0 +1,359 @@
+%D \module
+%D [ file=cont-log,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Miscellaneous Macros,
+%D subtitle=\TEX\ Logos,
+%D author=J. 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 TeX Logos}
+
+%D The system that is used to typeset this text is called \TEX,
+%D typeset with an lowered~E. From te beginning of \TEX,
+%D authors of macro packages adapted this raising and lowering
+%D style. In this module we define some of those logos.
+%D Watch the \type{cmr} detection hack.
+
+\unprotect
+
+\defconvertedargument\someCMRfont{cmr} % hm, we now have lm
+
+% \def\doifCMRfontelse#1#2%
+% {\doifinstringelse{\someCMRfont}{\fontname\font}
+% {\def\next{#1}}
+% {\def\next{#2}}%
+% \next}
+
+\def\doifCMRfontelse
+ {\doifinstringelse\someCMRfont{\fontname\font}}
+
+\unexpanded\def\CMRkern
+ {\doifCMRfontelse\kern{\scratchdimen=}}
+
+% \def\TeX
+% {T%
+% \kern-.1667em\lower.5ex\hbox{E}%
+% \kern-.125emX}
+
+\def\Mkern#1%
+ {{\setbox\scratchbox\hbox{M}\kern#1\wd\scratchbox}}
+
+\unexpanded\def\TeX
+ {T%
+ \Mkern{-.1667}\lower.5ex\hbox{E}%
+ \Mkern{-.125}X}
+
+\unexpanded\def\ConTeXt
+ {C%
+ \CMRkern-.0333emo%
+ \CMRkern-.0333emn%
+% \CMRkern-.1667em\TeX%
+ \CMRkern-.0667em\TeX%
+ \CMRkern-.0333emt}
+
+\unexpanded\def\PPCHTeX
+ {ppch\TeX}
+
+\unexpanded\def\PRAGMA
+ {Pragma ADE}
+
+%\def\LaTeX
+% {L%
+% \kern-.30em\raise.3ex\hbox{\txx A}%
+% \kern-.18em\TeX}
+
+\unexpanded\def\LaTeX % requested by erik frambach
+ {{\setbox\scratchbox\hbox{L}%
+ \scratchdimen\ht\scratchbox
+ \setbox\scratchbox\hbox{\txx A}%
+ L\kern-.55\wd\scratchbox
+ \raise\scratchdimen\hbox{\lower\ht\scratchbox\copy\scratchbox}%
+ \kern-.2\wd\scratchbox\TeX}}
+
+\unexpanded\def\TaBlE
+ {T%
+ \kern-.27em\lower.5ex\hbox{A}%
+ \kern-.18emB%
+ \kern-.1em\lower.5ex\hbox{L}%
+ \kern-.075emE}
+
+\unexpanded\def\PiCTeX
+ {P%
+ \kern-.12em\lower.5ex\hbox{I}%
+ \kern-.075em C%
+ \kern-.11em\TeX}
+
+\def\AMSswitch#1%
+ {$\cal\ifdim\bodyfontsize>1.1em\scriptstyle\fi#1$}
+
+\unexpanded\def\AmSTeX
+ {\AMSswitch A%
+ \kern-.1667em\lower.5ex\hbox{\AMSswitch M}%
+ \kern-.125em\AMSswitch S%
+ -\TeX}
+
+\unexpanded\def\LamSTeX
+ {L%
+ \kern-.4em\raise.3ex\hbox{\AMSswitch A}%
+ \kern-.25em\lower.4ex\hbox{\AMSswitch M}%
+ \kern-.1em{\AMSswitch S}%
+ -\TeX}
+
+\unexpanded\def\AmSLaTeX
+ {\AMSswitch A%
+ \kern-.1667em\lower.5ex\hbox{\AMSswitch M}%
+ \kern-.125em\AMSswitch S%
+ -\LaTeX}
+
+%D Alternative \CONTEXT\ logo, first Idris S.~Hamid's version:
+%D
+%D \def\Context
+%D {{\sc C\kern -.0667emo\kern -.0667emn\kern -.0549emt\kern
+%D -.1667em\lower.5ex\hbox {e}\kern -.125emx\kern -.0549emt}}
+%D
+%D I changed this into one that adapts itself:
+
+\unexpanded\def\Context
+ {{C\kern -.0667em\getscaledglyph{.8}\empty{O\kern -.0667emN\kern
+ -.0549emT\doifitalicelse{\kern-.1em}{\kern-.1667em}\lower.5ex\hbox
+ {E}\doifitalicelse\empty{\kern-.11em}X\kern-.055emT}}}
+
+%D The \METAFONT\ and \METAPOST\ logos adapt themselves to the
+%D current fontsize, an ugly but usefull hack.
+
+% rather hard coded
+%
+% \loadmapfile[original-base.map] % \loadmapfile[original-vogel-symbol]
+%
+% \unexpanded\def\setMFPfont
+% {\font\logofont=logo%
+% \ifnum\fam=\bffam\c!bf\else
+% \ifnum\fam=\slfam\c!sl\else
+% \ifnum\fam=\itfam\c!sl\else
+% \ifnum\fam=\bsfam\c!bf\else
+% \ifnum\fam=\bifam\c!bf\else
+% \fi\fi\fi\fi\fi
+% 10 at \currentfontscale\bodyfontsize
+% \logofont}
+%
+% or:
+%
+% \definefontsynonym [MetaLogo] [logo10]
+% \definefontsynonym [MetaLogoBold] [logobf10]
+% \definefontsynonym [MetaLogoSlanted] [logosl10]
+% \definefontsynonym [MetaLogoItalic] [logosl10]
+% \definefontsynonym [MetaLogoBoldSlanted] [logobf10]
+% \definefontsynonym [MetaLogoBoldtalic] [logobf10]
+%
+% \loadmapfile[original-base.map] % \loadmapfile[original-vogel-symbol]
+%
+% \def\setMFPfont{\symbolicfont{MetaLogo}}
+
+\let\logofont\nullfont
+
+\loadmapfile[original-base.map]
+
+\unexpanded\def\setMFPfont% more sensitive for low level changes
+ {\font\logofont=logo%
+ \ifx\fontalternative\c!bf\else
+ \ifx\fontalternative\c!it\else
+ \ifx\fontalternative\c!sl\else
+ \ifx\fontalternative\c!bi\else
+ \ifx\fontalternative\c!bs\else
+ \fi\fi\fi\fi\fi
+ 10 at \currentfontscale\bodyfontsize
+ \logofont}
+
+%\unexpanded\def\MetaFont%
+% {\hbox{\setMFPfont METAFONT}}
+%
+%\unexpanded\def\MetaPost%
+% {\hbox{\setMFPfont METAPOST}}
+
+\def\MetaHyphen% there is no hyphenchar in this font
+ {\discretionary{\vrule\!!height.33em\!!depth-.27em\!!width.33em}{}{}}
+
+\unexpanded\def\MetaFont
+ {{\setMFPfont META\MetaHyphen FONT}}
+
+\unexpanded\def\MetaPost
+ {{\setMFPfont META\MetaHyphen POST}}
+
+\unexpanded\def\MetaFun
+ {MetaFun}
+
+%D \macros
+%D {TEX, METAFONT, METAPOST, METAFUN,
+%D PICTEX, TABLE,
+%D CONTEXT, PPCHTEX,
+%D AMSTEX, LATEX, LAMSTEX}
+%D
+%D We define the funny written ones as well as th eless
+%D error prone upper case names (in \CONTEXT\ we tend to
+%D write all user defined commands, like abbreviations, in
+%D uppercase.)
+
+\unexpanded\def\METAFONT {\MetaFont}
+\unexpanded\def\METAPOST {\MetaPost}
+\unexpanded\def\PPCHTEX {\PPCHTeX}
+\unexpanded\def\CONTEXT {\ConTeXt}
+\unexpanded\def\METAFUN {\MetaFun}
+
+\unexpanded\def\TEX {\TeX}
+\unexpanded\def\LATEX {\LaTeX}
+\unexpanded\def\PICTEX {\PiCTeX}
+\unexpanded\def\TABLE {\TaBlE}
+\unexpanded\def\AMSTEX {\AmSTeX}
+\unexpanded\def\LAMSTEX {\LamSTeX}
+\unexpanded\def\INRSTEX {inrs\TeX}
+
+%D And this is how they show up: \TeX, \MetaFont, \MetaPost,
+%D \PiCTeX, \TaBlE, \ConTeXt, \PPCHTeX, \AmSTeX, \LaTeX,
+%D \LamSTeX.
+
+% \def\TEXEDIT {\TeX edit}
+% \def\TEXFORM {\TeX form}
+% \def\TEXADRES {\TeX adres}
+% \def\TEXSPELL {\TeX spell}
+% \def\TEXUTIL {\TeX util}
+% \def\TEXEXEC {\TeX exec}
+
+%D Some placeholders:
+
+\unexpanded\def\eTeX {\mathematics{\varepsilon}-\TeX}
+\unexpanded\def\pdfTeX {pdf\TeX}
+\unexpanded\def\pdfeTeX{pdfe-\TeX}
+\unexpanded\def\luaTeX {lua\TeX}
+\unexpanded\def\metaTeX{meta\TeX}
+\unexpanded\def\XeTeX {X\lower.5ex\hbox{\kern-.15em\mirror{E}}\kern-.1667em\TeX}
+
+% Better, since lm has a mirrored E (don't ask me why)
+
+% \unexpanded\def\XeTeX
+% {X\lower.5ex
+% \hbox
+% {\kern-.15em
+% \ifx\XeTeXcharglyph\undefined
+% \mirror{E}%
+% \else\ifcase\XeTeXcharglyph"018E\relax
+% \mirror{E}%
+% \else
+% \char"018E%
+% \fi}%
+% \kern-.1667em \TeX}
+
+% Adapted from a patch by Mojca:
+
+\def\@XeTeX@
+ {\setbox\scratchbox\hbox{E}%
+ \raise\dimexpr\ht\scratchbox+\dp\scratchbox\relax\hbox{\rotate[\c!rotation=180]{\box\scratchbox}}}
+
+\ifnum\texengine=\pdftexengine
+
+ \unexpanded\def\XeTeX
+ {X\lower.5ex
+ \hbox
+ {\kern-.15em
+ \ifx\fontalternative\c!bf\mirror{E}\else
+ \ifx\fontalternative\c!it \@XeTeX@\else
+ \ifx\fontalternative\c!sl \@XeTeX@\else
+ \ifx\fontalternative\c!bi \@XeTeX@\else
+ \ifx\fontalternative\c!bs \@XeTeX@\else
+ \mirror{E}\fi\fi\fi\fi\fi}%
+ \kern-.1667em \TeX}
+
+\else
+
+ \unexpanded\def\XeTeX
+ {X\lower.5ex
+ \hbox
+ {\kern-.15em
+ \iffontchar\font"018E\relax
+ \char"018E%
+ \else
+ \ifx\fontalternative\c!bf\mirror{E}\else
+ \ifx\fontalternative\c!it \@XeTeX@\else
+ \ifx\fontalternative\c!sl \@XeTeX@\else
+ \ifx\fontalternative\c!bi \@XeTeX@\else
+ \ifx\fontalternative\c!bs \@XeTeX@\else
+ \mirror{E}\fi\fi\fi\fi\fi
+ \fi}%
+ \kern-.1667em \TeX}
+
+\fi
+
+\let\ETEX \eTeX
+\let\PDFTEX \pdfTeX
+\let\PDFETEX\pdfeTeX
+\let\LUATEX \luaTeX
+\let\LuaTeX \luaTeX
+\let\XETEX \XeTeX
+
+\unexpanded\def\MkApproved
+ {\dontleavehmode\rotate
+ [\c!rotation={\ifnum\texengine=\luatexengine\ctxlua{tex.write(45-45*\the\luatexversion/100)}\else0\fi},
+ \c!align=\v!middle,
+ \c!foregroundstyle=\v!type,
+ \c!foregroundcolor=darkred,
+ \c!frame=\v!on,
+ \c!offset=1ex,
+ \c!background=\v!color,
+ \c!backgroundcolor=lightgray,
+ \c!framecolor=darkred,
+ \c!rulethickness=2pt]
+ {Mk\ifnum\texengine=\luatexengine IV\else II\fi\\approved}}
+
+
+% \unexpanded\def\luaTeX
+% {\dontleavehmode\begingroup
+% Lua%
+% \setbox0\hbox{oT}%
+% \setbox2\hbox{o\kern0ptT}%
+% \ifdim\wd0=\wd2
+% \setbox0\hbox dir TRT{To}%
+% \setbox2\hbox{T\kern0pto}%
+% \hskip\dimexpr\wd0-\wd2\relax
+% \fi
+% \TeX
+% \endgroup}
+%
+% a further iteration from the list, patched again
+
+% \ifx\fontalternative\c!it -\else
+% \ifx\fontalternative\c!sl -\else
+% \ifx\fontalternative\c!bi -\else
+% \ifx\fontalternative\c!bs -\fi\fi\fi\fi
+
+\def\LuaTeX
+ {\dontleavehmode
+ \begingroup
+ Lua%
+ % hope for kerning, try aT
+ \setbox0\hbox{aT}%
+ \setbox2\hbox{a\kern\zeropoint T}%
+ \ifdim\wd0=\wd2 % kerns can go two ways
+ % no aT kerning, try oT as a is not symmetrical
+ \setbox0\hbox{oT}%
+ \setbox2\hbox{o\kern\zeropoint T}%
+ \ifdim\wd0=\wd2 % kerns can go two ways
+ % no aT and oT kerning, try To
+ \setbox0\hbox{To}%
+ \setbox2\hbox{T\kern\zeropoint o}%
+ % maybe we need to compensate for the angle (sl/it/bs/bi)
+ \fi
+ \ifdim\wd0=\wd2\else
+ \kern\dimexpr\wd0-\wd2\relax
+ \fi
+ \fi
+ \TeX
+ \endgroup}
+
+\let\luaTeX \LuaTeX
+\let\LUATEX \LuaTeX
+
+\protect \endinput
diff --git a/tex/context/base/cont-mtx.tex b/tex/context/base/cont-mtx.tex
new file mode 100644
index 000000000..833785a7f
--- /dev/null
+++ b/tex/context/base/cont-mtx.tex
@@ -0,0 +1,25 @@
+%D \module
+%D [ file=cont-mtx,
+%D version=2006.01.01, % no date -)
+%D title=\CONTEXT\ Miscellaneous Macros,
+%D subtitle=Experimental MetaTeX Macros,
+%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.
+
+% format generation : texexec --make --all --luatex
+%
+% pdftex compatible run : texexec --luatex filename
+% aleph compatible run : texexec --luatex --output=dvipdfmx filename
+%
+% or, at top of tex file : % engine=luatex
+
+% \loadcorefile{meta-xxx.tex}
+
+%D Here we load files that are not yet part of the core.
+
+\endinput
diff --git a/tex/context/base/cont-new.mkii b/tex/context/base/cont-new.mkii
new file mode 100644
index 000000000..2defba6d7
--- /dev/null
+++ b/tex/context/base/cont-new.mkii
@@ -0,0 +1,22 @@
+%D \module
+%D [ file=cont-new,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Miscellaneous Macros,
+%D subtitle=New Macros,
+%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.
+
+\enablemode[mkii]
+
+\long\def\startluacode#1\stopluacode{}
+\long\def\ctxlua #1{}
+
+\def\enabletrackers [#1]{}
+\def\disabletrackers[#1]{}
+
+\endinput
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv
new file mode 100644
index 000000000..6269e5a61
--- /dev/null
+++ b/tex/context/base/cont-new.mkiv
@@ -0,0 +1,40 @@
+%D \module
+%D [ file=cont-new,
+%D version=2006.10.04,
+%D title=\CONTEXT\ Miscellaneous Macros,
+%D subtitle=New Macros,
+%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.
+
+% potential new defaults:
+%
+% \setbreakpoints[compound]
+
+\unprotect
+
+\ctxlua{logs.report = commands.report} % this will become default
+
+\def\immediatemessage#1{\ctxlua{commands.writestatus("message","#1")}}
+
+% we need to figure this out (to be discussed)
+
+\unexpanded\def\textminus
+ {\char \iffontchar\font"2012 "2012 % figuredash
+ \else\iffontchar\font"2013 "2013 % endash
+ \else\iffontchar\font"2212 "2212 % math minus
+ "002D % hyphen
+ \fi\fi\fi}
+
+\unexpanded\def\textplus
+ {\char"002B } % plus
+
+% till we fixed all styles
+
+\let\\=\crlf
+
+\protect \endinput
diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex
new file mode 100644
index 000000000..9c4fdba18
--- /dev/null
+++ b/tex/context/base/cont-new.tex
@@ -0,0 +1,992 @@
+%D \module
+%D [ file=cont-new,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Miscellaneous Macros,
+%D subtitle=New Macros,
+%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.
+
+\newcontextversion{2010.05.24 13:05}
+
+%D This file is loaded at runtime, thereby providing an
+%D excellent place for hacks, patches, extensions and new
+%D features.
+
+\unprotect
+
+% it's about time to clean up this file ...
+
+\writestatus\m!systems{beware: some patches loaded from cont-new.tex}
+
+% \ifx\pdfmapfile \undefined \else \pdfmapfile{ } \fi
+
+% \font\f=dummyfont \rpcode\f0=500 \hbox{..}\char0
+% todo: mp-new
+% caption: grid=top|bottom in xml defs
+
+\def\fastscale#1%
+ {\begingroup
+ \ifnum#1=1000\relax
+ \setfalse\scaleboxdone
+ \else
+ \settrue\scaleboxdone
+ \edef\finalscaleboxxscale{\withoutpt\the\dimexpr#1pt/1000\relax}%
+ \let\finalscaleboxyscale\finalscaleboxxscale
+ \fi
+ \dowithnextbox{\doscaleboxindeed\flushnextbox\endgroup}\hbox}
+
+% \setupcaption [figure] [align=flushleft]
+% \setupcaption [figure-1] [align=flushleft,leftmargin=10mm]
+% \setupcaption [figure-2] [align=flushleft,leftmargin=10mm,rightmargin=-10mm,width=\textwidth]
+%
+% \startsetups somefigure
+% \ifdim\floatsetupwidth>\textwidth
+% \placesetupfloat[figure-2]
+% \else
+% \placesetupfloat[figure-1]
+% \fi
+% \stopsetups
+%
+% \placefloatwithsetups[somefigure]{}{\externalfigure[dummy][width=5cm,height=2cm]}
+
+\def\placefloatwithsetups
+ {\dotripleempty\doplacefloatwithsetups}
+
+\long\def\doplacefloatwithsetups[#1][#2][#3]#4%
+ {\def\floatsetupcaption {#4}%
+ \def\floatsetupcontent {\copy\nextbox}%
+ \def\floatsetupwidth {\wd\nextbox}%
+ \def\floatsetupheight {\ht\nextbox}%
+ \def\placesetupfloat[##1]{\placefloat[##1][#2][#3]{#4}{\floatsetupcontent}}% #4 and not \floatsetupcaption (unexpanded)
+ \dowithnextbox{\setups[#1]}\vbox}
+
+\def\dividedsize#1#2#3% size gap n
+ {\dimexpr
+ \ifnum\dimexpr#1\relax>\plusone
+ (\dimexpr#1\relax-\numexpr#3-1\relax\dimexpr#2\relax)/#3\else#1%
+ \fi
+ \relax}
+
+% \setuplabeltext[\s!itemcount1={{I(},{)}}]
+% \def\labeledcountervalue#1{\labeltexts{#1}{\countervalue{#1}}}
+
+\def\singlewidened #1{\hbox spread 1em{\hss#1\hss}}
+\def\complexwidened[#1]#2{\hbox spread #1{\hss#2\hss}}
+
+\definecomplexorsimple\widened
+
+% todo
+%
+% \def\definelocation{\dodoubleargument\dodefinelocation}
+% \def\dodefinelocation[#1][#2]{\setvalue{loc:#1}{#2}}
+%
+% \definelocation[lt] [\v!left\v!top]
+% \definelocation[tl] [\v!left\v!top]
+% \definelocation[\v!top\v!left][\v!left\v!top]
+%
+% \def\getlocation#1{\executeifdefined{loc:#1}{#1}}
+
+% just in case we load something from a file (pdfr-ec for instance)
+
+\prependtoks \restoreendofline \to \everybeforeshipout
+
+\let\cs\getvalue
+
+% experimental so this may change
+
+\def\startdescriptions
+ {\dosingleempty\dostartdescriptions}
+
+\def\dostartdescriptions[#1]%
+ {\begingroup
+ \def\item{\getvalue{#1}}%
+ \let\dostoppairdescription \donothing
+ \let\@@description \dostartpairdescription
+ \let\@@startsomedescription\dostartsomedescription}
+
+\def\stopdescriptions
+ {\dostoppairdescription
+ \endgroup}
+
+\def\dostartpairdescription[#1][#2]%
+ {\dostoppairdescription
+ \def\dostoppairdescription{\@@stopdescription{#1}}%
+ \bgroup
+ \def\currentdescription{#1}%
+ \doifelse{\descriptionparameter{\s!do\c!state}}\v!start
+ {\@@makedescription{#1}[#2]{}}
+ {\@@makedescription{#1}[#2]}}
+
+\def\dostartsomedescription% #1[#2]#3%
+ {\bgroup
+ \@@makedescription} % {#1}[#2]{#3}}
+
+% \starttext
+%
+% \definedescription[test]
+%
+% \startdescriptions
+% \test{Foo} Bar bar bar
+% \test{Foo} Bar bar bar
+% \test{Foo} Bar bar bar
+% \stopdescriptions
+%
+% \startdescriptions[test]
+% \item{Foo} Bar bar bar
+% \item{Foo} Bar bar bar
+% \item{Foo} Bar bar bar
+% \stopdescriptions
+%
+% \startdescriptions
+% \starttest{Foo} Bar bar bar \stoptest
+% \starttest{Foo} Bar bar bar \stoptest
+% \starttest{Foo} Bar bar bar \stoptest
+% \stopdescriptions
+%
+% \startdescriptions[test]
+% \item{Foo} Bar bar bar
+% \item{Foo} Bar bar bar
+% \item{Foo} Bar bar bar
+% \stopdescriptions
+%
+% \stoptext
+
+% to do:
+%
+% \def\defineshapesynonym
+% {\dodoubleargument\dodefineshapesynonym}
+%
+% \def\dodefineshapesynonym[#1][#2]%
+% {\setvalue{shsy:#1}{#2}}
+%
+% \def\shapesynonym#1%
+% {\ifcsname shsy:#1\endcsname
+% \expandafter\shapesynonym\csname shsy:#1\endcsname\else#1%
+% \fi}
+%
+%\defineshapesynonym[eacute] [e]
+%\defineshapesynonym[egrave] [e]
+%\defineshapesynonym[eumlaut [e]
+%\defineshapesynonym[eogonek][e]
+%
+% more reduction
+%
+%\defineshapesynonym[e][o]
+%\defineshapesynonym[w][v]
+%\defineshapesynonym[m][n]
+%
+% \shapesynonym{eacute}
+
+% this will be activated when
+
+% \newinsert\thispageinsert % <- installinsertion
+
+% \def\flushatthispage
+% {\bgroup
+% \dowithnextbox{\insert\thispageinsert{\box\nextbox}\egroup}%
+% \hbox}
+
+% \appendtoks
+% \ifvoid\thispageinsert\else\hbox{\smashedbox\thispageinsert}\fi
+% \to \everyshipout
+
+% \definemarkedpage[nobackgrounds]
+% \markpage[nobackgrounds]
+% \doifmarkedpageelse{nobackgrounds}
+
+\newcounter\nofmarkedpages
+
+\def\definemarkedpage[#1]%
+ {\definetwopasslist{\v!page:#1}}
+
+\def\markpage[#1]% looks very much like domarginreference
+ {\iftrialtypesetting\else
+ \doglobal\increment\nofmarkedpages\relax
+ \lazysavetwopassdata{\v!page:#1}{\nofmarkedpages}{\noexpand\realfolio}%
+ \fi}
+
+\def\doifmarkedpageelse#1%
+ {\gettwopassdatalist{\v!page:#1}%
+ \expanded{\doifinsetelse{\realfolio}{\twopassdatalist}}}
+
+% Just a simple and fast hanger, for usage in macros.
+
+\def\setuphanging
+ {\dodoubleempty\getparameters[\??ha]}
+
+\setuphanging
+ [\c!distance=.5em]
+
+\def\starthanging
+ {\noindent\bgroup
+ \dowithnextbox
+ {\setbox\nextbox\hbox{\flushnextbox\hskip\@@hadistance}%
+ \hangindent\nextboxwd
+ \hangafter\plusone
+ \flushnextbox\ignorespaces}
+ \hbox}
+
+\def\stophanging
+ {\endgraf
+ \egroup}
+
+% experimental
+
+\def\stophangaround
+ {\endgraf
+ \egroup}
+
+\def\starthangaround
+ {\noindent\bgroup
+ \dowithnextbox
+ {\ifdim\nextboxht>\strutht\setbox\nextbox\tbox{\flushnextbox}\fi
+ \setbox\nextbox\hbox{\flushnextbox\hskip\@@hadistance}%
+ \getboxheight\scratchdimen\of\box\nextbox
+ \getnoflines\scratchdimen
+ \nextboxht\strutht
+ \nextboxdp\strutdp
+ \hangindent\nextboxwd
+ \hangafter-\noflines
+ \llap{\flushnextbox}\ignorespaces}
+ \hbox}
+
+\def\modevalue#1#2#3%
+ {\@EA\ifx\csname\@mode@\systemmodeprefix#1\endcsname\endcsname\enabledmode#2\else#2\fi}
+
+\def\systemmodevalue#1%
+ {\modevalue{\systemmodeprefix#1}}
+
+% \getmulticolumnlines -> now in cont-loc, to be tested and really needed
+
+% \tracefonthandlingtrue
+
+% new, still to be improved
+%
+% \dorecurse{10}
+% {\input thuan
+% \placefigure{}{\framed[height=1.5cm]{test}}
+% \placefloatplaceholder}
+
+\def\placefloatplaceholder
+ {\ifroomforfloat \else
+ \scratchdimen\pagegoal
+ \advance\scratchdimen-\pagetotal
+ \advance\scratchdimen-3\lineheight
+ \ifdim\scratchdimen>\zeropoint
+ \startlinecorrection[blank]
+ \mhbox{\inframed{\labeltexts{placeholder}{\lastcaptiontag}}}%
+ \stoplinecorrection
+ \else
+ \allowbreak
+ \fi
+ \fi}
+
+\setuplabeltext
+ [placeholder={, moved}]
+
+% etex only, of course we could just parse (scan for \% in string)
+
+\newif\ifpercentdimendone
+
+\bgroup % usage: \setpercentdimen\somedimen{% or dimen} todo: pct
+\catcode124=\@@comment
+\catcode 37=\@@active
+\gdef\setpercentdimen#1#2|
+ {\xdef\@@expanded{#2}|
+ \ifx\@@expanded\empty\else
+ \bgroup
+ \global\percentdimendonefalse
+ \def\%{\dimexpr#1/100\relax\global\percentdimendonetrue\ignorespaces}| scantokens add's a space
+ \catcode`%=\@@active
+ \catcode`\\=\@@escape
+ \let%\%|
+ \scratchdimen#1|
+ \xdef\@@expanded{\@@expanded\scratchdimen\!!zeropoint}| trick: when 1.2 => .2\scratchdimen and 0pt typeset
+ \startnointerference
+ \global\globalscratchdimen\scantokens\@EA{\@@expanded}| i'm lazy and use etex
+ \stopnointerference
+ \egroup
+ #1\globalscratchdimen
+ \fi}
+\egroup
+
+% TEX alternative, in principle accurate enough and also a bit faster
+
+% \bgroup
+%
+% \catcode`\%=\@@other
+% \catcode`\|=\@@comment
+%
+% \gdef\setpercentdimen#1#2|
+% {\beforesplitstring#2\at%\to\ascii
+% \doifelse\ascii{#2}
+% {#1=#2}
+% {\divide#1by100\relax#1=\ascii#1\relax}} | or: {#1=\ascii#1\divide#1by100\relax}}
+%
+% \egroup
+%
+% \dimen0=1000pt \setpercentdimen{\dimen0}{10%} \the\dimen0
+% \dimen0= 100pt \setpercentdimen{\dimen0}{10%} \the\dimen0
+% \dimen0= 95pt \setpercentdimen{\dimen0}{10%} \the\dimen0
+% \dimen0= 10pt \setpercentdimen{\dimen0}{10%} \the\dimen0
+% \dimen0= 1pt \setpercentdimen{\dimen0}{10%} \the\dimen0
+
+\bgroup
+
+\obeylines % don't remove %'s !
+
+\gdef\collapsedspace#1%
+ {\ifx#1^^M%
+ \expandafter\collapsedspace
+ \else
+ \space
+ \expandafter#1%
+ \fi}
+
+\gdef\collapsespaces
+ {\prependtoksonce\relax\to\everyeof%
+ \ignorelines%
+ \ignoretabs%
+ \let\obeyedspace\collapsedspace%
+ \obeyspaces}
+
+\egroup
+
+\def\inlinedbox
+ {\bgroup
+ \dowithnextbox
+ {\scratchdimen\nextboxht
+ \advance\scratchdimen\nextboxdp
+ \advance\scratchdimen-\lineheight
+ \divide\scratchdimen\plustwo
+ \advance\scratchdimen\strutdepth
+ \setbox\nextbox\hbox{\lower\scratchdimen\flushnextbox}%
+ \nextboxht\strutht
+ \nextboxdp\strutdp
+ \flushnextbox
+ \egroup}%
+ \hbox}
+
+% \readfile{cont-exp}\donothing\donothing % speed up (5-20%)
+
+\def\dimenratio#1#2% etex only
+ {\withoutpt\the\dimexpr2\dimexpr(#1)/\dimexpr(#2)/32768\relax\relax}
+
+\def\doxprecurse#1#2%
+ {\ifnum#1=\zerocount % no \ifcase
+ \expandafter\gobblethreearguments
+ \else
+ #2\expandafter\expandafter\expandafter\doxprecurse\expandafter
+ \fi\expandafter{\the\numexpr#1-1\relax}{#2}}
+
+\def\buttonframed{\dodoubleempty\localframed[\??bt]} % goodie
+
+\unexpanded\def\asciistr#1{\dontleavehmode{\defconvertedargument\ascii{#1}\verbatimfont\ascii}}
+
+\def\shapefill{\vskip\zeropoint\!!plus\lineheight\!!minus\lineheight\relax}
+
+\let\normaltype\type
+
+\ifx\scantextokens\undefined
+ \ifx\scantokens\undefined
+ \unexpanded\def\retype#1{\dontleavehmode{\defconvertedargument\ascii{#1}\@EA\normaltype\@EA{\ascii}}}
+ \else
+ \unexpanded\def\retype#1{\dontleavehmode\scantokens{\normaltype{#1}\ignorespaces}\relax}
+ \fi
+\else
+ \unexpanded\def\retype#1{\dontleavehmode\scantextokens{\normaltype{#1}}}
+\fi
+
+\def\simplifytype{\let\type\retype}
+
+% \ruledhbox
+% {\startignorespaces
+% \def\oeps{a}
+% \startignorespaces
+% \def\oeps{a}
+% \stopignorespaces
+% \def\oeps{a}
+% \stopignorespaces
+% \oeps}
+
+\newsignal\boissignal
+\newcount \boislevel
+
+\long\def\startignorespaces
+ {\advance\boislevel\plusone
+ \ifcase\boislevel\or \ifhmode
+ \hskip\boissignal
+ \fi \fi
+ \ignorespaces}
+
+\long\def\stopignorespaces
+ {\ifcase\boislevel\or \ifhmode
+ \doloop
+ {\ifdim\lastskip=\zeropoint
+ \exitloop
+ \else\ifdim\lastskip=\boissignal
+ \unskip
+ \exitloop
+ \else
+ \unskip
+ \fi\fi}%
+ \fi \fi
+ \advance\boislevel\minusone}
+
+\def\minimalhbox#1#%
+ {\dowithnextbox
+ {\bgroup
+ \setbox\scratchbox\hbox#1{\hss}%
+ \ifdim\nextboxwd<\wd\scratchbox\nextboxwd\wd\scratchbox\fi
+ \flushnextbox
+ \egroup}
+ \hbox}
+
+% \def\dodimchoice#1#2#3%
+% {\ifx#3\relax
+% #1\@EA\gobbleuntilrelax
+% \else\ifdim#1#2%
+% #3\@EAEAEA\gobbleuntilrelax
+% \else
+% \@EAEAEA\dodimchoice
+% \fi\fi{#1}}
+
+% \def\donumchoice#1#2#3%
+% {\ifx#3\relax
+% #1\@EA\gobbleuntilrelax
+% \else\ifnum#1#2%
+% #3\@EAEAEA\gobbleuntilrelax
+% \else
+% \@EAEAEA\dodimchoice
+% \fi\fi{#1}}
+
+% \def\dimchoice#1#2{\dodimchoice{#1}#2\empty\relax}
+% \def\numchoice#1#2{\donumchoice{#1}#2\empty\relax}
+
+\def\gobbleuntilempty#1\empty{}
+
+\def\dodimchoice#1#2#3%
+ {\ifdim#1#2%
+ #3\@EA\gobbleuntilempty
+ \else
+ \@EA\dodimchoice
+ \fi{#1}}
+
+\def\donumchoice#1#2#3%
+ {\ifnum#1#2%
+ #3\@EA\gobbleuntilempty
+ \else
+ \@EA\dodimchoice
+ \fi{#1}}
+
+\def\dimchoice#1#2{\dodimchoice{#1}#2{=#1}{#1}\empty}
+\def\numchoice#1#2{\donumchoice{#1}#2{=#1}{#1}\empty}
+
+% \the\dimexpr(\dimchoice {7pt}{{<10pt}{8pt}{<12pt}{9pt}{<15pt}{10pt}{=11pt}{12pt}})
+% \the\dimexpr(\dimchoice{11pt}{{<10pt}{8pt}{<12pt}{9pt}{<15pt}{10pt}{=11pt}{12pt}})
+% \the\dimexpr(\dimchoice{14pt}{{<10pt}{8pt}{<12pt}{9pt}{<15pt}{10pt}{=11pt}{12pt}})
+
+\def\showsetupsdefinition[#1]{\showvalue{\??su:#1}} % temp hack for debugging
+
+% documentation : \setupregister[alternative=a|b|A|B]
+\unprotected \def\traceposstring#1#2#3%
+ {\iftracepositions
+ \smashedhbox%
+ {#1{\infofont#2#3}%
+ \scratchdimen.5\points
+ \kern-2\scratchdimen
+ \vrule\!!width4\scratchdimen\!!height\scratchdimen\!!depth\scratchdimen}%
+ \fi}
+
+% will be a MyWay
+%
+% \setuplayout[grid=yes] \setupcaption[figure][inbetween=] \useMPlibrary[dum] \setupcolors[state=start]
+%
+% \starttext \showgrid \showstruts
+%
+% \input ward \placefigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=yes]}
+% \input ward \placefigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=fit]}
+% \input ward \placefigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=height]}
+% \input ward
+% \page
+% \input ward \placefigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=yes]}
+% \input ward \placefigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=fit]}
+% \input ward \placefigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=height]}
+% \input ward
+% \page
+% \input ward \placefigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=yes]}
+% \input ward \placefigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=fit]}
+% \input ward \placefigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=height]}
+% \input ward
+% \page
+% \input ward \placefigure[none]{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=yes]}
+% \input ward \placefigure[none]{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=fit]}
+% \input ward \placefigure[none]{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=height]}
+% \input ward
+% \page
+% \input ward \placefigure[none]{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=yes]}
+% \input ward \placefigure[none]{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=fit]}
+% \input ward \placefigure[none]{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=height]}
+% \input ward
+% \page
+% \input ward \placefigure[none]{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=yes]}
+% \input ward \placefigure[none]{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=fit]}
+% \input ward \placefigure[none]{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=height]}
+% \input ward
+%
+% \stoptext
+
+% funny, as field action with e.g. dissolve ... only the field dissolves, bug?
+
+\setglobalsystemreference\rt!exec{Transition}{transition}
+
+%def\PDFexecutetransition {/Trans /Trans <>}
+\def\PDFexecutetransition {/Trans /Trans <<\executeifdefined{PDFpage\argumentA}\PDFpagereplace>>}
+
+% new, continuous blocks, \som \par \startdoorlopendblok ...
+
+% \startitemize
+% \item bagger
+% \item bagger
+% \item \startdoorlopendblok bagger \stopdoorlopendblok
+% \item \endgraf \startdoorlopendblok bagger \stopdoorlopendblok
+% \item \endgraf \startdoorlopendblok \strut bagger \stopdoorlopendblok
+% \item \startdoorlopendblok
+% \starttabulate
+% \NC test \NC test \NC \NR
+% \NC test \NC test \NC \NR
+% \NC test \NC test \NC \NR
+% \stoptabulate
+% \stopdoorlopendblok
+% \item test
+% \stopitemize
+
+\def\startdoorlopendblok % for special cases, don't change it too much and don't rely on it
+ {\ifhmode\endgraf\nobreak\fi % don't remove the \nobreak
+ \dowithnextboxcontent
+ {\setlocalhsize \hsize\localhsize \forgetall}
+ {\bgroup
+ \forgeteverypar
+ \forgetparskip
+ \scratchdimen\nextboxht
+ \advance\scratchdimen\nextboxdp
+ \getnoflines\scratchdimen
+ \advance\scratchdimen-\strutheight
+ \setbox\nextbox\hbox{\lower\scratchdimen\box\nextbox}%
+ \ht\nextbox\strutheight
+ \dp\nextbox\strutdepth
+ \setbox\nextbox\vbox
+ {\indent\box\nextbox
+ \endgraf
+ \nobreak
+ \advance\noflines\minusone
+ \dorecurse\noflines{\crlf\nobreak}}%
+ \verticalstrut
+ \endgraf
+ \nobreak
+ \offinterlineskip
+ \kern-2\lineheight % 2\lineheight when no vertical struts in main \vbox
+ \nobreak
+ \unvbox\nextbox
+ \prevdepth\strutdepth
+ % evt (eerst testen) een signal zodat een direct volgend blok goed gaat)
+ \egroup}
+ \vbox\bgroup
+ \vskip-\lineheight \verticalstrut\endgraf
+ \insidefloattrue
+ \doinhibitblank} % beware, no \inhibitblank ! ! ! ! ! !
+
+\def\stopdoorlopendblok
+ {\endgraf\verticalstrut\endgraf\kern-2\lineheight
+ \egroup}
+
+\def\tabulaterule % to be redone, not correct
+ {\dotabulaterule
+ {\hrule\!!height.5\scratchdimen\!!depth.5\scratchdimen\relax
+ \doifvalue{\??tt\currenttabulate\c!distance}\v!grid
+ {\kern-\scratchdimen}}} % experimental tm-prikkels
+
+% experimental: \synchronizegrid bla bla bla
+
+\newcounter\currentgridsync
+
+\def\gridsynctag{grs:\currentgridsync}
+
+\def\synchronizegrid
+ {\doglobal\increment\currentgridsync
+ \par\prevdepth\zeropoint
+ \nointerlineskip
+ \hpos\gridsynctag{\strut}\par
+ \vskip-\lineheight
+ \nointerlineskip
+ % top of text
+ \scratchdimen\MPy{\v!text:\MPp\gridsynctag}%
+ \advance\scratchdimen\MPh{\v!text:\MPp\gridsynctag}%
+ % move to first baseline
+ \advance\scratchdimen-\topskip
+ % subtract wrong baseline
+ \advance\scratchdimen-\MPy\gridsynctag
+ % get minimal number of lines
+ \advance\scratchdimen\lineheight
+ \getnoflines\scratchdimen
+ % calculate difference
+ \advance\scratchdimen-\noflines\lineheight\relax
+ \scratchdimen-\scratchdimen\relax
+ \ifdim\scratchdimen>\zeropoint
+ \nointerlineskip
+ \advance\scratchdimen-\lineheight
+ \vskip\scratchdimen \dontleavehmode \quad \strut
+ \par
+ %\else
+ % \message{no grid correction: \the\scratchdimen}\wait
+ \fi}
+
+% needed for extreme (will go away)
+
+\definesystemvariable{ie}
+
+\def\definetest
+ {\dodoubleempty\dodefinetest}
+
+\def\dodefinetest[#1][#2]#3%
+ {\setgvalue{\??ie#1}{#3}%
+ \ifsecondargument
+ \processaction
+ [#2]
+ [% first test true, rest depends
+ \v!next=>\setgvalue{\??ie#1}{\setgvalue{\??ie#1}{#3}\firstoftwoarguments},
+ % rest true if first true
+ % \v!first=>\setgvalue{\??ie#1}{#3{\letgvalue{\??ie#1}%
+ % \firstoftwoarguments\firstoftwoarguments}%
+ % \secondoftwoarguments},
+ % always true
+ \v!yes=>\letgvalue{\??ie#1}\firstoftwoarguments,
+ % always false
+ \v!no=>\letgvalue{\??ie#1}\secondoftwoarguments]%
+ \fi}
+
+\def\doperformtest#1%
+ {\executeifdefined{\??ie#1}\secondoftwoarguments}
+
+\def\definecolumnsethsize#1#2#3#4% will be improved/speed up
+ {\bgroup
+ \def\OTRSETidentifier{#1}%
+ \ifcase\columnsetlevel\relax
+ \mofcolumns\plusone
+ \OTRSETinitializecolumns
+ \OTRSETassignwidths
+ \OTRSETsethsize
+ \fi
+ \!!counta#2\!!countb#3\docalculatecolumnsetspan
+ \expandafter\egroup\expandafter\edef\expandafter
+ #4\expandafter{\the\!!widtha}}
+
+% so far
+
+% between alignment lines certain rules apply, and even a
+% simple test can mess up a table, which is why we have a
+% special test facility
+%
+% \ruledvbox
+% {\starttabulate[|l|p|]
+% \NC 1test \NC test \NC \NR
+% \tableifelse{\doifelse{a}{a}}{\NC Xtest \NC test \NC \NR}{}%
+% \stoptabulate}
+
+\long\def\tableifelse#1%
+ {\TABLEnoalign{#1%
+ {\aftergroup \firstoftwoarguments}%
+ {\aftergroup\secondoftwoarguments}}}
+
+\long \def\tableiftextelse#1{\tableifelse{\doiftextelse{#1}}}
+
+% experiment, not yet to be used
+
+\def\displaybreak
+ {\ifhmode
+ \removeunwantedspaces
+ \ifcase\raggedstatus\hfill\fi
+ \strut\penalty-9999 % \break fails on case (3)
+ \fi}
+
+\def\startdisplay{\displaybreak\ignorespaces\startpacked}
+\def\stopdisplay {\stoppacked\displaybreak\ignorespaces}
+
+\def\tightvbox{\dowithnextbox{\nextboxdp\zeropoint\flushnextbox}\vbox}
+\def\tightvtop{\dowithnextbox{\nextboxht\zeropoint\flushnextbox}\vtop}
+
+% what is this stupid macro meant for:
+
+\def\hyphenationpoint
+ {\hskip\zeropoint}
+
+\def\hyphenated#1%
+ {\bgroup
+ \!!counta\zerocount
+ \def\hyphenated##1{\advance\!!counta\plusone}%
+ \handletokens#1\with\hyphenated
+ \!!countb\plusone
+ \def\hyphenated##1%
+ {##1%
+ \advance\!!countb\plusone\relax
+ \ifnum\!!countb>2 \ifnum\!!countb<\!!counta
+ \hyphenationpoint
+ \fi\fi}%
+ \handletokens#1\with\hyphenated
+ \egroup}
+
+\def\obeysupersubletters
+ {\let\super\normalsuper
+ \let\suber\normalsuber
+ \let\normalsuper\letterhat
+ \let\normalsuber\letterunderscore
+ \enablesupersub}
+
+\def\obeysupersubmath
+ {\let\normalsuper\letterhat
+ \let\normalsuber\letterunderscore
+ \enablesupersub}
+
+%\let\normaltype\type
+%
+%\def\type#1%
+% {\expanded{\normaltype{\detokenize{#1}}}}
+
+% {x123 \os x123} {\tfa x123 \os x123} {x123 \tx x123 \os x123}
+% \definefontsynonym[OldStyle][Serif]
+% {x123 \os x123} {\tfa x123 \os x123} {x123 \tx x123 \os x123}
+
+% testen :
+%
+% \appendtoks
+% \let\registerparoptions\relax
+% \to \everyforgetall
+
+\def\startgridcorrection
+ {\dosingleempty\dostartgridcorrection}
+
+\def\dostartgridcorrection[#1]%
+ {\ifgridsnapping
+ \iffirstargument\doifsomething{#1}{\moveongrid[#1]}\fi
+ \snaptogrid\vbox\bgroup
+ \else
+ \startbaselinecorrection
+ \fi}
+
+\def\stopgridcorrection
+ {\ifgridsnapping
+ \egroup
+ \else
+ \stopbaselinecorrection
+ \fi}
+
+\def\checkgridsnapping
+ {\lineskip\ifgridsnapping\zeropoint\else\normallineskip\fi}
+
+\def\startplaatsen
+ {\dosingleempty\dostartplaatsen}
+
+\def\dostartplaatsen[#1]% tzt n*links etc
+ {\endgraf
+ \noindent\bgroup
+ \setlocalhsize
+ \hbox to \localhsize\bgroup
+ \doifnot{#1}\v!left\hss
+ \def\stopplaatsen
+ {\unskip\unskip\unskip
+ \doifnot{#1}\v!right\hss
+ \egroup
+ \egroup
+ \endgraf}%
+ \gobblespacetokens}
+
+% \startplaatsen[links] bla \stopplaatsen
+
+% we don't register the paragraph characteristics, only the
+% width
+
+\appendtoks
+ \setinnerparpositions % see "techniek" for application
+\to \everytabulate
+
+\def\fontclassname#1#2%
+ {\ifcsname\??ff#1#2\endcsname
+ \fontclassname{#1}{\csname\??ff#1#2\endcsname}%
+ \else\ifcsname\??ff#2\endcsname
+ \fontclassname{#1}{\csname\??ff#2\endcsname}%
+ \else
+ #2%
+ \fi\fi}
+
+\def\defineclassfontsynonym
+ {\dotripleargument\dodefineclassfontsynonym}
+
+\def\dodefineclassfontsynonym[#1][#2][#3]%
+ {\definefontsynonym[#1][\fontclassname{#2}{#3}]}
+
+%\definefontsynonym [KopFont] [\fontclassname{officina}{SerifBold}]
+%
+%\defineclassfontsynonym [KopFont] [officina] [SerifBold]
+
+\def\startcolumnmakeup % don't change
+ {\bgroup
+ \getrawnoflines\textheight % teksthoogte kan topskip hebben, dus raw
+ \scratchdimen\noflines\lineheight
+ \advance\scratchdimen-\lineheight
+ \advance\scratchdimen\topskip
+ \setbox\scratchbox
+ \ifcase\showgridstate\vbox\else\ruledvbox\fi to \scratchdimen\bgroup
+ \forgetall} % ! don't change
+
+\def\stopcolumnmakeup
+ {\egroup
+ \dp\scratchbox\zeropoint
+ \wd\scratchbox\textwidth
+ \box\scratchbox
+ \egroup
+ \synchronizehsize}
+
+\long\def\startexternalfigure
+ {\dotripleempty\dostartexternalfigure}
+
+\long\def\dostartexternalfigure[#1][#2][#3]#4\stopexternalfigure
+ {\gdef\figuredescription{#4}%
+ \externalfigure[#1][#2][#3]%
+ \globallet\figuredescription\empty}
+
+\let\figuredescription\empty
+
+%% where does this come from, old code probably
+%%
+%%
+%% \newif\ifpagechanged \let\lastchangedpage\empty
+%%
+%% \def\checkpagechange#1%
+%% {\gettwopassdata\s!paragraph
+%% \pagechangedfalse
+%% \iftwopassdatafound
+%% \ifnum\twopassdata>0\getvalue{\s!paragraph:p:#1}\relax
+%% \pagechangedtrue
+%% \fi
+%% \fi
+%% \ifpagechanged
+%% \letgvalue{\s!paragraph:p:#1}\twopassdata
+%% \globallet\lastchangedpage\twopassdata
+%% \else
+%% \globallet\lastchangedpage\realfolio
+%% \fi
+%% \doparagraphreference}
+%%
+%% \def\changedpage#1%
+%% {\getvalue{\s!paragraph:p:#1}}
+
+\newcount\nofprofiled
+
+\def\profilemacro#1%
+ {\nofprofiled\zerocount
+ \letvalue{\string#1\string#1}#1%
+ \appendtoks
+ \normalwritestatus\m!systems{profile \string#1: \number\nofprofiled}%
+ \to \everystoptext
+ \unexpanded\def#1%
+ {\global\advance\nofprofiled\plusone
+ \csname\string#1\string#1\endcsname}}
+
+% incomplete, will be a special case of float placement
+
+\def\startfixed{\dosingleempty\dostartfixed}
+
+\def\dostartfixed[#1]%
+ {\expanded{\dowithnextbox{\noexpand\dodofixed{\ifhmode0\else1\fi}{#1}}}%
+ \vbox\bgroup
+ \setlocalhsize}
+
+\def\stopfixed
+ {\egroup}
+
+\def\dodofixed#1#2%
+ {\ifcase#1\relax
+ \processaction
+ [#2]
+ [ \v!high=>\bbox {\flushnextbox},
+ \v!low=>\tbox {\flushnextbox},
+ \v!middle=>\vcenter{\flushnextbox},
+ \v!lohi=>\vcenter{\flushnextbox},
+ \s!unknown=>\tbox {\flushnextbox},
+ \s!default=>\tbox {\flushnextbox}]%
+ \else
+ \startbaselinecorrection
+ \noindent\flushnextbox
+ \stopbaselinecorrection
+ \fi}
+
+% \startitemize
+%
+% \item \externalfigure[koe][height=2cm]
+% \item \externalfigure[koe][height=2cm]
+% \item \externalfigure[koe][height=2cm]
+% \item \externalfigure[koe][height=2cm]
+%
+% \page
+%
+% \item \startfixed \externalfigure[koe][height=2cm]\stopfixed
+% \item \startfixed[high]\externalfigure[koe][height=2cm]\stopfixed
+% \item \startfixed[low] \externalfigure[koe][height=2cm]\stopfixed
+% \item \startfixed[lohi]\externalfigure[koe][height=2cm]\stopfixed
+%
+% \page
+%
+% \item test \startfixed \externalfigure[koe][height=2cm]\stopfixed
+% \item test \startfixed[high]\externalfigure[koe][height=2cm]\stopfixed
+% \item test \startfixed[low] \externalfigure[koe][height=2cm]\stopfixed
+% \item test \startfixed[lohi]\externalfigure[koe][height=2cm]\stopfixed
+%
+% \page
+%
+% \item test \par \startfixed \externalfigure[koe][height=2cm]\stopfixed
+% \item test \par \startfixed[high]\externalfigure[koe][height=2cm]\stopfixed
+% \item test \par \startfixed[low] \externalfigure[koe][height=2cm]\stopfixed
+% \item test \par \startfixed[lohi]\externalfigure[koe][height=2cm]\stopfixed
+%
+% \stopitemize
+
+\def\obeyfollowingtoken{{}} % end \cs scanning
+
+% \def\comparedimension#1#2%
+% {\chardef\compresult
+% \ifdim#1<#2%
+% \zerocount
+% \else\ifdim#1<#2%
+% \plusone
+% \else
+% \plustwo
+% \fi\fi}
+% \newdimen\roundingeps \roundingeps=10sp
+% \def\comparedimensioneps#1#2%
+% {\chardef\compresult
+% \ifdim\dimexpr(#1-#2)<\roudingeps
+% \zerocount
+% \else\ifdim\dimexpr(#2-#1)<\roudingeps
+% \zerocount
+% \else\ifdim#1<#2%
+% \plusone
+% \else
+% \plustwo
+% \fi\fi\fi}
+
+%D Next we load a few local optimizations and new features. They
+%D live on on my machine and are not distributed, but they may end
+%D up in the distributed files.
+
+\loadmarkfile{cont-new}
+
+\readsysfile {cont-loc} {} {} % local improvements, patches, new features
+\readsysfile {cont-exp} {} {} % experimental features (e.g. local speed-ups)
+%readsysfile {cont-mtx} {} {} % experimental metatex features
+
+\protect \endinput
diff --git a/tex/context/base/cont-nl.tex b/tex/context/base/cont-nl.tex
new file mode 100644
index 000000000..32b82b01a
--- /dev/null
+++ b/tex/context/base/cont-nl.tex
@@ -0,0 +1,42 @@
+%D \module
+%D [ file=cont-nl,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Dutch Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \def\defaultinterface{dutch}
+
+\input context.tex
+
+\unprotect
+
+\setupcurrentlanguage[\s!nl]
+
+\loaduserspecifications
+
+\installlanguage [\s!us] [\c!state=\v!start]
+\installlanguage [\s!gb] [\c!state=\v!start]
+\installlanguage [\s!de] [\c!state=\v!start]
+\installlanguage [\s!fr] [\c!state=\v!start]
+\installlanguage [\s!es] [\c!state=\v!start]
+\installlanguage [\s!nl] [\c!state=\v!start]
+\installlanguage [\s!it] [\c!state=\v!start]
+
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-old.tex b/tex/context/base/cont-old.tex
new file mode 100644
index 000000000..360b5f2e6
--- /dev/null
+++ b/tex/context/base/cont-old.tex
@@ -0,0 +1,48 @@
+%D \module
+%D [ file=cont-old,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Miscellaneous Macros,
+%D subtitle=Old Macros,
+%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 Old Macros}
+
+\unprotect
+
+\def\middleraggedness {6\bodyfontsize}
+
+\def\dosubstitutecommand#1#2%
+ {\writestatus\m!systems{\string#1\normalspace -> \string#2}%
+ \gdef#1{#2}%
+ #2}
+
+\def\substitutecommand#1#2%
+ {\gdef#1{\dosubstitutecommand{#1}{#2}}}
+
+\substitutecommand \volgendehoofdstuk {\setupheadnumber[hoofdstuk][+1]}
+\substitutecommand \volgendeparagraaf {\setupheadnumber[paragraaf][+1]}
+\substitutecommand \volgendesubparagraaf {\setupheadnumber[subparagraaf][+1]}
+\substitutecommand \volgendesubsubparagraaf {\setupheadnumber[subsubparagraaf][+1]}
+
+\substitutecommand \volledigeinhoudsopgave \volledigeinhoud
+\substitutecommand \plaatsinhoudsopgave \plaatsinhoud
+\substitutecommand \stelinhoudsopgavein \stelinhoudin
+
+\substitutecommand \streep \onderstreep
+\substitutecommand \strepen \onderstrepen
+
+\substitutecommand \pragmakenmerk \referral
+
+\substitutecommand \definieersynoniem \definesynonyms
+
+\substitutecommand \setupintermezzos \setupintermezzi
+
+\let \Everybodyfont \EveryBodyFont
+
+\protect \endinput
diff --git a/tex/context/base/cont-pe.tex b/tex/context/base/cont-pe.tex
new file mode 100644
index 000000000..fdf47d680
--- /dev/null
+++ b/tex/context/base/cont-pe.tex
@@ -0,0 +1,45 @@
+%D \module
+%D [ file=cont-en,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ English Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \def\defaultinterface{persian} \def\messageinterface{english}
+
+\input context.tex
+
+\unprotect
+
+\setupcurrentlanguage[\s!pe]
+
+\loaduserspecifications
+
+% Do we need more defaults? or maybe all languages?
+
+\installlanguage [\s!us] [\c!state=\v!start]
+\installlanguage [\s!gb] [\c!state=\v!start]
+\installlanguage [\s!de] [\c!state=\v!start]
+\installlanguage [\s!fr] [\c!state=\v!start]
+\installlanguage [\s!es] [\c!state=\v!start]
+\installlanguage [\s!it] [\c!state=\v!start]
+\installlanguage [\s!nl] [\c!state=\v!start]
+\installlanguage [\s!pe] [\c!state=\v!start]
+
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-ro.tex b/tex/context/base/cont-ro.tex
new file mode 100644
index 000000000..9be9b1162
--- /dev/null
+++ b/tex/context/base/cont-ro.tex
@@ -0,0 +1,38 @@
+%D \module
+%D [ file=cont-ro,
+%D version=2000.01.09,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Romanian Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \def\defaultinterface{romanian}
+
+\input context.tex
+
+\unprotect
+
+\setupcurrentlanguage[\s!ro]
+
+\loaduserspecifications
+
+\installlanguage [\s!en] [\c!state=\v!start]
+\installlanguage [\s!de] [\c!state=\v!start]
+\installlanguage [\s!ro] [\c!state=\v!start]
+
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-sys.ori b/tex/context/base/cont-sys.ori
new file mode 100644
index 000000000..11c0141e7
--- /dev/null
+++ b/tex/context/base/cont-sys.ori
@@ -0,0 +1,182 @@
+%D \module
+%D [ file=cont-sys,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Miscellaneous Macros,
+%D subtitle=System Specific Setups,
+%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.
+
+\unprotect
+
+% Speed up typescript loading, but at the cost of much memory:
+
+\preloadtypescripts
+
+% If you want another default font:
+%
+% \let\preloadfonts\relax
+% \usetypescript[palatino][\defaultencoding]
+% \setupbodyfont[palatino,rm,12pt]
+%
+% Please make sure that this defines rm, ss, tt and mm.
+
+% Occasionally we will support both A4 and letter in
+% styles. If you want letter size paper to be the default,
+% uncomment:
+%
+% \enablemode[\systemmodeprefix letter]
+%
+% If you always want to default to letter, you may uncomment
+% the following line, but beware: it makes your documents less
+% portable:
+%
+% \setuppapersize[letter][letter]
+
+% If you want some extras, just uncomment the following
+% line:
+%
+% \usemodule[plus] % experimental code
+%
+% Here you can take care of overloading some (style)
+% defaults. What goes here, depends on your local system.
+
+% The following commands sets the default font encoding:
+%
+% \setupencoding [\s!default=texnansi]
+%
+% or:
+
+\setupencoding [\s!default=ec]
+
+% If you want the default berry names:
+%
+% \usetypescript [berry] [\defaultencoding]
+%
+% or, if you also want other encodings:
+
+\usetypescript [berry] [ec,t5,8r] % texnansi is never present
+
+% If you run into missing font metrics kind of problems,
+% you may want to uncomment:
+%
+% \usetypescript[adobekb] [\defaultencoding]
+
+% You can let \CONTEXT\ load the map files for \PDFTEX.
+
+\autoloadmapfilestrue
+
+% (1) you can prevent loading with:
+%
+% \preloadmapfile[<...somename...>.map]
+%
+% (2) otherwise, use this if you have a fast machine
+%
+% \resetmapfiles \usetypescript [map] [base] [all]
+%
+% (3) or this if it's a slow one:
+
+\resetmapfiles
+
+% more recent versions of pdftex support map loading on each page
+
+\donefalse \ifx\pdftexversion\undefined \else \ifnum\number\pdftexversion>119
+ \donetrue
+\fi \fi \ifdone
+
+ \loadmapfile[original-base.map]
+ \loadmapfile[original-ams-base.map]
+ \loadmapfile[original-ams-euler.map]
+ \loadmapfile[original-public-lm.map]
+
+\else
+
+ \loadmapfile[original-base.map]
+ \loadmapfile[texnansi-base.map]
+ \loadmapfile[ec-base.map]
+ \loadmapfile[qx-base.map]
+ \loadmapfile[t5-base.map]
+ %loadmapfile[il2-base.map]
+ %loadmapfile[pl0-base.map]
+ \loadmapfile[8r-base.map]
+
+ \loadmapfile[original-ams-base.map]
+ \loadmapfile[original-ams-euler.map]
+
+ \loadmapfile[original-public-lm.map]
+
+ %loadmapfile[texnansi-public-lm.map]
+ %loadmapfile[ec-public-lm.map]
+ %loadmapfile[qx-public-lm.map]
+ %loadmapfile[t5-public-lm.map]
+ %loadmapfile[pl0-public-lm.map]
+ %loadmapfile[il2-public-lm.map]
+
+\fi
+
+% When you have your own fonts installed, you may want to predefine:
+%
+% \usetypescriptfile[type-buy]
+
+% Some styles default to Lucida Bright. You can overload
+% Lucida by Times cum suis. Watch out, the pos collection
+% is not scaled relatively.
+%
+% \definetypescriptsynonym [lbr] [pos]
+
+% Compensate for missing files:
+%
+% \definefontsynonym [gbhei] [gbsong]
+% \definefontsynonym [gbheisl] [gbsong]
+% \definefontsynonym [gbheisl] [gbsong]
+
+% Setting up a global figure path
+%
+% \setupexternalfigures [\c!directory={e:/fig/eps,t:/mine/figs}]
+%
+% Loading a specific special driver:
+%
+% \setupoutput [dviwindo]
+
+% Changing language defaults
+%
+% \setuplanguage
+% [nl]
+% [\c!leftquote=\upperleftsinglesixquote,
+% \c!leftquotation=\upperleftdoublesixquote]
+
+% Loading local preferences, for example
+%
+% \input prag-gen % company styles
+% \input prag-log % more company styles
+%
+% Enabling run time \METAPOST\ (also enable \write18 in
+% texmf.cnf):
+
+\runMPgraphicstrue
+\runMPTEXgraphicstrue
+
+% This saves some runtime, but needs a format, which you can
+% make with 'texexec --make --alone metafun'. Make sure that
+% the mem files are moved to the used web2c path (locate with
+% 'kpsewhich plain.mem').
+
+\useMETAFUNformattrue
+
+% This can be a way to get things working on system with
+% name clashes. (Some \TeX's tend do search system wide.)
+
+\protectbufferstrue
+
+% You can enable a more extensive figure searching, but
+% normally this is not really needed and even annoying.
+%
+% \runutilityfiletrue
+
+% So far.
+
+\protect \endinput
diff --git a/tex/context/base/cont-usr.ori b/tex/context/base/cont-usr.ori
new file mode 100644
index 000000000..5a3070362
--- /dev/null
+++ b/tex/context/base/cont-usr.ori
@@ -0,0 +1,109 @@
+%D \module
+%D [ file=cont-usr,
+%D version=1997.10.05,
+%D title=\CONTEXT\ User Format Specifications,
+%D subtitle=System Specific Setups,
+%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 User Settings}
+
+\unprotect
+
+%D Additional languages can be defined here. Beware of
+%D encoding incompatibilities. Please take a look at the
+%D \type {cont-en.tex}, \type {cont-nl.tex}, enz.\ files
+%D first. Normally you don't have to change a byte. If you
+%D want to play safe, use \typ {texexec --make --alone
+%D --all}.
+
+% \preloadallpatterns % will load them all
+
+% \installlanguage [\s!af] [\c!state=\v!start] % afrikaans
+% \installlanguage [\s!ca] [\c!state=\v!start] % catalan
+% \installlanguage [\s!cs] [\c!state=\v!start] % czech
+% \installlanguage [\s!da] [\c!state=\v!start] % danish
+% \installlanguage [\s!de] [\c!state=\v!start] % german
+% \installlanguage [\s!en] [\c!state=\v!start] % english us
+% \installlanguage [\s!es] [\c!state=\v!start] % spanish
+% \installlanguage [\s!fi] [\c!state=\v!start] % finnish
+% \installlanguage [\s!fr] [\c!state=\v!start] % french
+% \installlanguage [\s!hr] [\c!state=\v!start] % croatian
+% \installlanguage [\s!hu] [\c!state=\v!start] % hungarian
+% \installlanguage [\s!it] [\c!state=\v!start] % italian
+% \installlanguage [\s!la] [\c!state=\v!start] % latin
+% \installlanguage [\s!nl] [\c!state=\v!start] % dutch
+% \installlanguage [\s!nb] [\c!state=\v!start] % bokmal
+% \installlanguage [\s!nn] [\c!state=\v!start] % nynorsk
+% \installlanguage [\s!pl] [\c!state=\v!start] % polish
+% \installlanguage [\s!pt] [\c!state=\v!start] % portuguese
+% \installlanguage [\s!ro] [\c!state=\v!start] % romanian
+% \installlanguage [\s!ru] [\c!state=\v!start] % russian
+% \installlanguage [\s!sk] [\c!state=\v!start] % slovak
+% \installlanguage [\s!sl] [\c!state=\v!start] % slovenian
+% \installlanguage [\s!sv] [\c!state=\v!start] % swedish
+% \installlanguage [\s!tr] [\c!state=\v!start] % turkish
+% \installlanguage [\s!ua] [\c!state=\v!start] % ukrainian
+% \installlanguage [\s!gb] [\c!state=\v!start] % english uk
+% \installlanguage [\s!vn] [\c!state=\v!start] % vietnamese
+
+% \installlanguage [deo] [\c!state=\v!start] % old german
+
+%D The next lines can be used for setting the language to be
+%D used at startup time.
+
+% \setupcurrentlanguage[\s!af]
+% \setupcurrentlanguage[\s!ca]
+% \setupcurrentlanguage[\s!cs]
+% \setupcurrentlanguage[\s!da]
+% \setupcurrentlanguage[\s!de]
+% \setupcurrentlanguage[\s!en]
+% \setupcurrentlanguage[\s!es]
+% \setupcurrentlanguage[\s!fi]
+% \setupcurrentlanguage[\s!fr]
+% \setupcurrentlanguage[\s!hr]
+% \setupcurrentlanguage[\s!hu]
+% \setupcurrentlanguage[\s!it]
+% \setupcurrentlanguage[\s!la]
+% \setupcurrentlanguage[\s!nl]
+% \setupcurrentlanguage[\s!nb]
+% \setupcurrentlanguage[\s!nn]
+% \setupcurrentlanguage[\s!pl]
+% \setupcurrentlanguage[\s!pt]
+% \setupcurrentlanguage[\s!ro]
+% \setupcurrentlanguage[\s!ru]
+% \setupcurrentlanguage[\s!sk]
+% \setupcurrentlanguage[\s!sl]
+% \setupcurrentlanguage[\s!sv]
+% \setupcurrentlanguage[\s!tr]
+% \setupcurrentlanguage[\s!ua]
+
+%D Local font settings can go here. Normally suitable
+%D defaults are already preloaded, almost certainly the
+%D Computer Modern Roman typefaces or some derivate. So, the
+%D next line is only meant as sample, take a look at the
+%D format related files first.
+
+% This is obsolete due to latin modern:
+%
+% \definefilesynonym [font-cmr] [font-csr] % czech & slovak
+% \definefilesynonym [font-cmr] [font-plr] % polish
+
+%D In some languages, compound characters, like \type {"e}
+%D are used to get accented and non latin characters.
+
+% Per 21/9/2006 one needs to explicitly enable this.
+
+% \useencoding[fde] % german
+% \useencoding[ffr] % french
+% \useencoding[fro] % romanian
+% \useencoding[fpl] % polish
+
+%D Don't remove the next few lines.
+
+\protect \endinput
diff --git a/tex/context/base/context-base.lmx b/tex/context/base/context-base.lmx
new file mode 100644
index 000000000..fd27927bf
--- /dev/null
+++ b/tex/context/base/context-base.lmx
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+ 0) and v('refreshurl') then ?>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tex/context/base/context-characters.lmx b/tex/context/base/context-characters.lmx
new file mode 100644
index 000000000..f018e412b
--- /dev/null
+++ b/tex/context/base/context-characters.lmx
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tex/context/base/context.css b/tex/context/base/context.css
new file mode 100644
index 000000000..f332ae242
--- /dev/null
+++ b/tex/context/base/context.css
@@ -0,0 +1,241 @@
+body {
+ color: #FFFFFF ;
+ background-color: ;
+ font-family: optima, verdana, futura, "lucida sans", arial, geneva, helvetica, sans ;
+ font-size: 12px ;
+ line-height: 18px ;
+}
+a:link, a:active, a:visited {
+ color: #FFFFFF ;
+}
+a.dir-view:link, a.dir-view:active, a.dir-view:visited {
+ color: #FFFFFF ;
+ text-decoration: underline ;
+}
+.valid {
+ color: #00FF00 ;
+}
+.invalid {
+ color: #FF0000 ;
+}
+h1, .title {
+ font-style: normal ;
+ font-weight: normal ;
+ font-size: 18px ;
+ line-height: 18px ;
+ margin-bottom: 20px ;
+}
+h2, .subtitle {
+ font-style: normal ;
+ font-weight: normal ;
+ font-size: 12px ;
+ margin-top: 18px ;
+ margin-bottom: 18px ;
+}
+table {
+ line-height: 18px ;
+ font-size: 12px ;
+ margin: 0 ;
+}
+th {
+ font-weight: bold ;
+ text-align: left ;
+ padding-bottom: 6px ;
+}
+.tc {
+ font-weight: bold ;
+ text-align: left ;
+}
+p, li {
+ max-width: 60em ;
+}
+.empty-line {
+ margin-top: 4px ;
+}
+.more-room {
+ margin-right: 1.5em ;
+}
+.much-more-room {
+ margin-right: 3em ;
+}
+#main {
+ position: absolute;
+ left: 10% ;
+ top: 10% ;
+ right: 10% ;
+ bottom: 10% ;
+ z-index: 2 ;
+ width: 80% ;
+ height: 80% ;
+ padding: 0% ;
+ margin: 0% ;
+ overflow: auto ;
+ border-style: none ;
+ border-width: 0 ;
+ background-color: ;
+}
+#main-settings {
+ margin: 12px ;
+ x_max-width: 60em ;
+ line-height: 18px ;
+ font-size: 12px ;
+}
+#left {
+ position: absolute;
+ top : 10% ;
+ left: 0% ;
+ bottom: 0%;
+ right: 90% ;
+ z-index: 1 ;
+ width: 10% ;
+ height: 90% ;
+ padding: 0% ;
+ margin: 0% ;
+ font-size: 16px ;
+ border-style: none ;
+ border-width: 0 ;
+ background-color: ;
+}
+#right {
+ position: absolute;
+ top : 0% ;
+ left: 90% ;
+ bottom: 10% ;
+ right: 0% ;
+ z-index: 1 ;
+ width: 10% ;
+ height: 90% ;
+ padding: 0% ;
+ margin: 0% ;
+ font-size: 16px ;
+ border-style: none ;
+ border-width: 0 ;
+ background-color: ;
+ _margin-left: -15px ;
+}
+#bottom {
+ position: absolute ;
+ left: 10% ;
+ right: 0% ;
+ top: 90% ;
+ bottom: 0% ;
+ z-index: 1 ;
+ width: 90% ;
+ height: 10% ;
+ padding: 0% ;
+ margin: 0% ;
+ font-size: 16px ;
+ border-style: none ;
+ border-width: 0 ;
+ background-color: ;
+}
+#top {
+ position: absolute ;
+ left: 0% ;
+ right: 10% ;
+ top: 0% ;
+ bottom: 90% ;
+ z-index: 1 ;
+ width: 90% ;
+ height: 10% ;
+ padding: 0% ;
+ margin: 0% ;
+ font-size: 16px ;
+ border-style: none ;
+ border-width: 0 ;
+ background-color: ;
+}
+#top-one {
+ position: absolute ;
+ bottom: 50% ;
+ width: 100% ;
+ buggedheight: 100% ;
+}
+#top-two {
+ position: relative ;
+ margin-bottom: -9px ;
+ margin-left: 12px ;
+ margin-right: 12px ;
+ line-height: 18px ;
+ text-align: right ;
+ vertical-align: middle ;
+}
+#bottom-one {
+ position: absolute ;
+ bottom: 50% ;
+ width: 100% ;
+ buggedheight: 100% ;
+}
+#bottom-two {
+ position: relative ;
+ margin-bottom: -9px ;
+ margin-left: 12px ;
+ margin-right: 12px ;
+ line-height: 18px ;
+ text-align: left ;
+ vertical-align: middle ;
+}
+#left-one {
+ position: absolute ;
+ width: 100% ;
+ buggedheight: 100% ;
+}
+#left-two {
+ position: relative ;
+ margin-top: 12px ;
+ line-height: 18px ;
+ text-align: center ;
+ vertical-align: top ;
+}
+#right-one {
+ display: table ;
+ height: 100% ;
+ width: 100% ;
+}
+#right-two {
+ display: table-row ;
+ height: 100% ;
+ width: 100% ;
+}
+#right-three {
+ display: table-cell ;
+ width: 100% ;
+ vertical-align: bottom ;
+ _position: absolute ;
+ _top: 100% ;
+}
+#right-four {
+ text-align: center ;
+ margin-bottom: 2ex ;
+ _position: relative ;
+ _top: -100% ;
+}
+#more-top {
+ position: absolute;
+ top: 0% ;
+ left: 90% ;
+ bottom: 90%;
+ right: 0% ;
+ z-index: 3 ;
+ width: 10% ;
+ height: 10% ;
+ padding: 0% ;
+ margin: 0% ;
+ border-style: none ;
+ border-width: 0 ;
+}
+#more-top-settings {
+ text-align: center ;
+}
+#more-right-settings {
+ margin-right: 12px ;
+ margin-left: 12px ;
+ line-height: 18px ;
+ font-size: 10px ;
+ text-align: center ;
+}
+#right-safari {
+ display: table ;
+ width: 100% ;
+ height: 100% ;
+}
diff --git a/tex/context/base/context.mkii b/tex/context/base/context.mkii
new file mode 100644
index 000000000..4be60cbfc
--- /dev/null
+++ b/tex/context/base/context.mkii
@@ -0,0 +1,391 @@
+%D \module
+%D [ file=context,
+%D version=2008.28.10, % 1995.10.10,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Format Generation,
+%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.
+
+%D First we load the system modules. These implement a lot of
+%D manipulation macros. The first one loads \PLAIN\ \TEX, as
+%D minimal as possible.
+
+\loadcorefile{syst-ini}
+\loadcorefile{syst-pln}
+
+\loadcorefile{norm-tex}
+\loadcorefile{norm-etx}
+\loadcorefile{norm-ptx}
+\loadcorefile{norm-xtx}
+\loadcorefile{norm-ctx}
+
+\loadmarkfile{catc-ini}
+\loadcorefile{catc-act}
+\loadcorefile{catc-def}
+\loadcorefile{catc-ctx}
+\loadcorefile{catc-sym}
+
+\loadmarkfile{syst-gen}
+\loadmarkfile{syst-ext}
+\loadmarkfile{syst-new}
+\loadmarkfile{syst-con}
+\loadcorefile{syst-ltx}
+\loadmarkfile{thrd-trg} % based on: David Carlisle
+
+\loadmarkfile{syst-fnt}
+\loadmarkfile{syst-str}
+\loadmarkfile{syst-rtp}
+
+\ifnum\texengine=\xetexengine
+ \loadmarkfile{xetx-ini}
+ \loadmarkfile{xetx-utf}
+ \loadmarkfile{xetx-chr}
+ \loadmarkfile{xetx-cls}
+\fi
+
+%D To enable selective loading, we say:
+
+\newif\ifCONTEXT \CONTEXTtrue % will disappear
+
+%D In order to conveniently load files, we need a few
+%D support modules.
+
+\loadmarkfile{supp-fil}
+\loadmarkfile{supp-dir}
+
+%D After this we're ready for the multi||lingual interface
+%D modules.
+
+\loadmarkfile{mult-ini}
+\loadcorefile{mult-fst}
+\loadcorefile{mult-sys}
+\loadcorefile{mult-def}
+\loadmarkfile{mult-chk}
+
+%D Now we're ready for some general support modules. These
+%D modules implement some basic typesetting functionality.
+
+\loadmarkfile{core-var}
+\loadmarkfile{core-env}
+
+\loadcorefile{supp-box}
+\loadmarkfile{supp-mrk}
+\loadcorefile{supp-vis}
+\loadcorefile{supp-fun}
+%loadmarkfile{supp-eps}
+\loadmarkfile{supp-spe}
+\loadmarkfile{supp-ran}
+\loadmarkfile{supp-mps}
+\loadmarkfile{supp-tpi}
+\loadmarkfile{supp-mat}
+\loadcorefile{supp-ali}
+\loadcorefile{supp-num}
+
+%D Verbatim typesetting is implemented in a separate class of
+%D modules. The pretty typesetting modules are loaded at run
+%D time.
+
+\loadmarkfile{verb-ini}
+
+%D The following modules are not sequentially dependent,
+%D i.e. they have ugly dependencies, which will be cleaned
+%D up by adding more overloading.
+
+%D When loading the font, color and special modules, we need a
+%D bit more advanced file handling as well as some general
+%D variables, and features, so next we load:
+
+\loadmarkfile{page-ins}
+\loadmarkfile{core-fil}
+\loadmarkfile{core-con}
+
+%D We already need some synonyms (patterns). At runtime this
+%D file will be reloaded.
+
+\loadcorefile{cont-fil}
+
+%D \CONTEXT\ does not implement its own table handling. We
+%D just go for the best there is and load \TABLE. Just to be
+%D sure we do it here, before we redefine \type{|}.
+
+\loadcorefile{thrd-tab} % based on: Michael Wichura / will be reimplemented
+
+%D Here comes the last support modules. They take care of
+%D some language specific things.
+
+\loadmarkfile{supp-pat}
+
+%D The next few modules do what their names state. They
+%D load additional definition modules when needed.
+
+\loadmarkfile{regi-ini}
+\loadcorefile{regi-syn}
+\loadmarkfile{enco-ini}
+%loadmarkfile{filt-ini}
+\loadmarkfile{hand-ini}
+
+\loadmarkfile{lang-ini}
+\loadmarkfile{lang-spe}
+\loadmarkfile{lang-lab}
+
+\loadmarkfile{unic-ini}
+
+\loadmarkfile{core-gen}
+\loadmarkfile{core-uti}
+\loadmarkfile{core-two}
+\loadmarkfile{core-stg}
+
+\loadmarkfile{spec-ini}
+\loadmarkfile{spec-mis}
+\loadmarkfile{spec-def}
+\loadmarkfile{spec-var}
+
+\loadmarkfile{colo-ini}
+\loadmarkfile{colo-ext}
+
+%D For the moment we load a lot of languages. In the future
+%D we'll have to be more space conservative.
+
+\loadmarkfile{lang-mis}
+\loadmarkfile{lang-url}
+
+\loadcorefile{lang-ger}
+\loadcorefile{lang-ita}
+\loadcorefile{lang-sla}
+\loadcorefile{lang-alt}
+\loadcorefile{lang-ana}
+\loadcorefile{lang-art}
+\loadcorefile{lang-bal}
+\loadcorefile{lang-cel}
+\loadcorefile{lang-grk}
+\loadcorefile{lang-ind}
+\loadcorefile{lang-ura}
+\loadcorefile{lang-vn}
+\loadcorefile{lang-cyr}
+
+\loadmarkfile{typo-ini}
+
+%D All kind of symbols are handled in:
+
+\loadmarkfile{symb-ini}
+
+%D Sorting:
+
+\loadmarkfile{sort-ini}
+
+%D Next we load some core macro's. These implement the
+%D macros' that are seen by the users. The order of loading
+%D is important, due to dependancies.
+
+\loadmarkfile{spac-gen}
+\loadmarkfile{spac-grd}
+
+\loadmarkfile{strc-mar}
+\loadmarkfile{anch-pos}
+
+\loadmarkfile{buff-ver}
+\loadmarkfile{buff-ini}
+
+\loadmarkfile{pack-rul}
+\loadmarkfile{trac-vis}
+\loadmarkfile{strc-num}
+\loadmarkfile{tabl-com}
+\loadmarkfile{tabl-pln}
+\loadmarkfile{tabl-tab}
+\loadmarkfile{tabl-tsp}
+\loadmarkfile{scrn-nav}
+\loadmarkfile{strc-ref}
+\loadmarkfile{pack-obj}
+\loadmarkfile{strc-lst}
+\loadmarkfile{strc-itm}
+\loadmarkfile{strc-des}
+\loadmarkfile{strc-mat} % should come after math-pln etc
+\loadmarkfile{strc-syn}
+\loadmarkfile{core-sys}
+
+\loadmarkfile{page-ini}
+\loadmarkfile{page-bck}
+\loadmarkfile{page-not}
+\loadmarkfile{page-one}
+\loadmarkfile{page-lay}
+\loadmarkfile{page-log}
+\loadmarkfile{page-txt}
+\loadmarkfile{page-sid}
+\loadmarkfile{strc-flt}
+\loadmarkfile{page-mis}
+\loadmarkfile{page-mul}
+\loadmarkfile{page-set}
+\loadmarkfile{pack-lyr}
+\loadmarkfile{page-mak}
+\loadmarkfile{strc-pag}
+\loadmarkfile{page-lin}
+\loadmarkfile{page-par}
+\loadmarkfile{page-mar}
+
+\loadmarkfile{core-job} % why so late?
+
+% so far
+
+\loadmarkfile{strc-sec}
+\loadmarkfile{strc-swd}
+\loadmarkfile{strc-blk}
+
+\loadmarkfile{page-imp}
+\loadmarkfile{tabl-tbl}
+\loadmarkfile{scrn-int}
+\loadmarkfile{tabl-ntb}
+\loadmarkfile{tabl-nte}
+\loadmarkfile{tabl-ltb}
+
+%D A few more languages, that have specifics using core
+%D functionality:
+
+%loadmarkfile{lang-ara} % undefined
+\loadmarkfile{lang-chi}
+\loadmarkfile{lang-jap}
+
+%D How about fill||in fields and related stuff?
+
+\loadmarkfile{java-ini}
+\loadmarkfile{scrn-fld}
+\loadmarkfile{scrn-hlp}
+
+%D Registers can depend on fields, so we load that now.
+
+\loadmarkfile{strc-reg}
+
+%D Of course we do need fonts. There are no \TFM\ files
+%D loaded yet, so the format file is independant of their
+%D content. Here we also redefine \type{\it} as {\it italic}
+%D instead of italian.
+
+\loadmarkfile{font-ini}
+
+\ifnum\texengine=\xetexengine
+ \loadmarkfile{font-xtx}
+\fi
+
+\loadmarkfile{font-unk}
+\loadmarkfile{font-uni}
+\loadmarkfile{font-bfm}
+
+\loadmarkfile{enco-pfr}
+
+\loadmarkfile{type-ini}
+\loadmarkfile{type-set}
+
+%D Properties. Don't ask.
+
+\loadmarkfile{prop-ini}
+\loadmarkfile{prop-lay}
+\loadmarkfile{prop-mis}
+
+%D Like languages, fonts, encodings and symbols, \METAPOST\
+%D support is also organized in its own class of modules.
+
+\loadmarkfile{meta-ini}
+\loadmarkfile{meta-tex}
+\loadmarkfile{meta-pdf}
+
+\loadmarkfile{meta-pag}
+
+%D Special page handling (maybe even later)
+
+\loadmarkfile{page-flw}
+\loadmarkfile{page-spr}
+\loadmarkfile{page-plg}
+\loadmarkfile{page-str}
+
+%D Anchoring graphics:
+
+\loadmarkfile{anch-pgr}
+\loadmarkfile{anch-bar}
+\loadmarkfile{anch-snc}
+
+%D Math.
+
+\loadmarkfile{math-pln}
+\loadmarkfile{math-ini}
+\loadmarkfile{math-arr}
+\loadmarkfile{math-frc}
+
+%D Now we're ready for more core modules.
+
+\loadmarkfile{core-fnt}
+\loadmarkfile{strc-not}
+\loadmarkfile{strc-lnt}
+
+\loadmarkfile{core-mis}
+
+\loadmarkfile{grph-trf}
+\loadmarkfile{grph-inc}
+\loadmarkfile{grph-fig}
+
+\loadmarkfile{core-par}
+
+\loadmarkfile{pack-box}
+\loadmarkfile{page-app}
+\loadmarkfile{meta-fig}
+
+%D Language specific spacing.
+
+\loadcorefile{lang-spa}
+
+%D Bibliographies:
+
+\loadmarkfile{bibl-tra}
+
+%D Only the basic XML parser and remapper are part of the core.
+%D These macros are loaded last since they overload and|/|or
+%D extend previously defined ones.
+
+\loadcorefile{xtag-ini}
+\loadcorefile{xtag-ext}
+\loadcorefile{xtag-exp}
+\loadcorefile{xtag-pre}
+\loadcorefile{xtag-xsd}
+\loadcorefile{xtag-rng}
+
+%D How about this:
+
+\loadcorefile{meta-xml}
+
+%D \TEX\ related logo's are always typeset in a special way.
+%D Here they come:
+
+\loadcorefile{cont-log}
+
+%D This one overloads af few things:
+
+\loadmarkfile{core-ctx}
+
+%D Defaults go here (more will be moved to this module
+%D later):
+
+\loadmarkfile{core-ini}
+\loadmarkfile{core-def}
+
+%D Preloaded modules (some need xml support):
+
+%usemodule[x][res-04] % xml resource libraries
+%usemodule[x][res-08] % rlx runtime conversion
+\usemodule[x][res-12] % rli external indentification
+
+%D At run time, a few more files are loaded, like:
+%D
+%D \startitemize[packed]
+%D \item \type{cont-sys}: local (system dependant) defaults
+%D \item \type{cont-old}: substitutes for old (obsolete) macros
+%D \item \type{cont-new}: new macro implementations (for testing)
+%D \item \type{cont-fil}: filename and module synonyms
+%D \stopitemize
+
+% %D Except from english, no hyphenation patterns are loaded
+% %D yet. Users can specify their needs in the next module:
+%
+% \input cont-usr
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
new file mode 100644
index 000000000..33fa3a901
--- /dev/null
+++ b/tex/context/base/context.mkiv
@@ -0,0 +1,380 @@
+%D \module
+%D [ file=context,
+%D version=2008.28.10, % 1995.10.10,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Format Generation,
+%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.
+
+% syst-cat -> catc-ini + vectors
+% spec-* -> special backends for luatex
+
+%D First we load the system modules. These implement a lot of
+%D manipulation macros. The first one loads \PLAIN\ \TEX, as
+%D minimal as possible.
+
+\loadcorefile{syst-ini}
+
+\ifnum\luatexversion<60 % also change message
+ \writestatus{!!!!}{Your luatex binary is too old, you need at least version 0.60!}
+ \expandafter\end
+\fi
+
+\newtoks\contextversiontoks \contextversiontoks\expandafter{\contextversion} % at the lua end
+
+\loadcorefile{norm-ctx}
+\loadcorefile{syst-pln}
+
+\newif\ifCONTEXT \CONTEXTtrue % will disappear
+
+\loadmarkfile{luat-cod}
+\loadmarkfile{luat-bas}
+\loadmarkfile{luat-lib}
+
+\loadmarkfile{catc-ini}
+\loadcorefile{catc-act}
+\loadcorefile{catc-def}
+\loadcorefile{catc-ctx}
+\loadcorefile{catc-sym}
+
+% From here on we have \unexpanded being \normalprotected, as we
+% already had \unexpanded long before etex came around.
+
+\loadmarkfile{syst-aux}
+\loadmarkfile{syst-lua}
+\loadmarkfile{syst-con}
+\loadcorefile{syst-ltx}
+
+\loadmarkfile{syst-fnt}
+\loadmarkfile{syst-str}
+\loadmarkfile{syst-rtp}
+
+\loadmarkfile{supp-fil}
+\loadmarkfile{supp-dir}
+
+\loadmarkfile{char-ini}
+\loadmarkfile{char-utf}
+\loadmarkfile{char-act}
+
+\loadmarkfile{mult-ini}
+\loadcorefile{mult-fst}
+\loadcorefile{mult-sys}
+\loadcorefile{mult-def}
+\loadmarkfile{mult-chk}
+\loadmarkfile{mult-cld}
+
+\loadmarkfile{luat-ini}
+
+\loadmarkfile{toks-ini}
+
+\loadmarkfile{node-ini}
+\loadmarkfile{node-fin}
+\loadmarkfile{node-mig}
+\loadmarkfile{node-par}
+%loadmarkfile{node-pag}
+
+\loadmarkfile{core-var}
+
+\loadmarkfile{back-ini}
+\loadmarkfile{lpdf-ini} % some day back-ini will load this
+\loadmarkfile{lpdf-pdx} % might be merged into lpdf-ini
+\loadmarkfile{back-pdf} % some day back-ini will load this
+
+\loadmarkfile{attr-ini}
+
+\loadmarkfile{core-env}
+
+\loadmarkfile{trac-tex}
+\loadmarkfile{trac-lmx}
+\loadmarkfile{trac-deb}
+
+\loadmarkfile{blob-ini} % not to be used, we only use a helper
+
+\loadcorefile{supp-box}
+
+\loadcorefile{supp-vis}
+\loadcorefile{supp-fun}
+
+\loadmarkfile{supp-ran}
+\loadmarkfile{supp-mat}
+\loadcorefile{supp-ali}
+\loadcorefile{supp-num}
+
+\loadmarkfile{typo-ini}
+
+\loadmarkfile{page-ins}
+\loadmarkfile{core-fil}
+\loadmarkfile{core-con}
+
+\loadcorefile{cont-fil}
+
+\loadmarkfile{regi-ini}
+\loadcorefile{regi-syn}
+\loadmarkfile{enco-ini}
+\loadmarkfile{hand-ini}
+
+\loadmarkfile{lang-ini}
+\loadmarkfile{lang-lab}
+\loadmarkfile{lang-wrd}
+
+\loadmarkfile{unic-ini}
+
+\loadmarkfile{core-gen}
+\loadmarkfile{core-uti}
+\loadmarkfile{core-two}
+
+\loadmarkfile{colo-ini}
+\loadmarkfile{colo-ext}
+
+\loadmarkfile{trac-vis}
+
+\loadmarkfile{lang-mis}
+\loadmarkfile{lang-url}
+
+\loadcorefile{lang-ger}
+\loadcorefile{lang-ita}
+\loadcorefile{lang-sla}
+\loadcorefile{lang-alt}
+\loadcorefile{lang-ana}
+\loadcorefile{lang-art}
+\loadcorefile{lang-bal}
+\loadcorefile{lang-cel}
+\loadcorefile{lang-grk}
+\loadcorefile{lang-ind}
+\loadcorefile{lang-ura}
+\loadcorefile{lang-vn}
+\loadcorefile{lang-cyr}
+
+\loadmarkfile{lang-ara}
+\loadmarkfile{lang-cjk}
+
+\loadmarkfile{symb-ini}
+
+\loadmarkfile{sort-ini}
+
+\loadmarkfile{pack-rul}
+
+\loadmarkfile{lxml-ini}
+\loadmarkfile{lxml-sor}
+
+\loadmarkfile{strc-ini}
+\loadmarkfile{strc-doc}
+\loadmarkfile{strc-mar}
+\loadmarkfile{strc-prc}
+\loadmarkfile{strc-sbe}
+\loadmarkfile{strc-lst}
+\loadmarkfile{strc-sec}
+\loadmarkfile{strc-num}
+\loadmarkfile{strc-ren}
+\loadmarkfile{strc-xml}
+\loadmarkfile{strc-pag} % hm, depends on core-num
+\loadmarkfile{strc-def} % might happen later
+\loadmarkfile{strc-ref}
+\loadmarkfile{strc-reg}
+
+\loadmarkfile{spac-hor}
+\loadmarkfile{spac-ver}
+\loadmarkfile{spac-ali}
+\loadmarkfile{spac-pag}
+\loadmarkfile{spac-fnt}
+\loadmarkfile{spac-par}
+\loadmarkfile{spac-def}
+\loadmarkfile{spac-grd}
+
+\loadmarkfile{anch-pos}
+
+\loadmarkfile{scrn-nav}
+\loadmarkfile{pack-obj}
+
+\loadmarkfile{strc-itm}
+\loadmarkfile{strc-des}
+\loadmarkfile{strc-syn}
+
+\loadmarkfile{core-sys}
+
+\loadmarkfile{page-ini}
+\loadmarkfile{page-flt}
+\loadmarkfile{page-bck}
+\loadmarkfile{page-not}
+\loadmarkfile{page-one}
+\loadmarkfile{page-lay}
+\loadmarkfile{page-txt}
+\loadmarkfile{page-sid}
+
+\loadmarkfile{strc-flt}
+
+\loadmarkfile{page-mis}
+\loadmarkfile{page-mul}
+\loadmarkfile{page-set}
+\loadmarkfile{pack-lyr}
+\loadmarkfile{page-mak}
+
+\loadmarkfile{page-lin}
+\loadmarkfile{page-par}
+\loadmarkfile{page-mar}
+
+\loadmarkfile{core-job} % why so late?
+
+\loadmarkfile{buff-ini}
+\loadmarkfile{buff-ver}
+
+\loadmarkfile{strc-blk}
+
+\loadmarkfile{page-imp}
+
+\loadmarkfile{scrn-int}
+\loadmarkfile{scrn-men}
+\loadmarkfile{scrn-but}
+\loadmarkfile{scrn-bar}
+\loadmarkfile{strc-bkm} % bookmarks
+
+\loadmarkfile{tabl-com}
+\loadmarkfile{tabl-pln}
+\loadcorefile{thrd-tab}
+\loadmarkfile{tabl-tab}
+\loadmarkfile{tabl-tbl}
+\loadmarkfile{tabl-ntb}
+\loadmarkfile{tabl-nte}
+\loadmarkfile{tabl-ltb}
+\loadmarkfile{tabl-tsp}
+
+\loadmarkfile{java-ini}
+
+\loadmarkfile{scrn-fld}
+\loadmarkfile{scrn-hlp}
+
+\loadmarkfile{char-enc}
+\loadmarkfile{font-ini}
+\loadmarkfile{font-unk}
+\loadmarkfile{font-tra}
+\loadmarkfile{font-uni}
+\loadmarkfile{font-col}
+\loadmarkfile{font-gds}
+
+\loadmarkfile{typo-spa}
+\loadmarkfile{typo-krn}
+\loadmarkfile{typo-mir}
+\loadmarkfile{typo-brk}
+\loadmarkfile{typo-cap}
+\loadmarkfile{typo-dig}
+\loadmarkfile{typo-rep}
+
+\loadmarkfile{type-ini}
+\loadmarkfile{type-set}
+
+\loadmarkfile{scrp-ini}
+
+\loadmarkfile{prop-ini}
+\loadmarkfile{prop-lay}
+\loadmarkfile{prop-mis}
+
+\loadmarkfile{mlib-ctx}
+\loadmarkfile{mlib-pdf}
+\loadmarkfile{mlib-pps}
+
+\loadmarkfile{meta-ini}
+\loadmarkfile{meta-tex}
+\loadmarkfile{meta-pdf}
+\loadmarkfile{meta-fun}
+
+\loadmarkfile{meta-pag}
+
+\loadmarkfile{page-flw}
+\loadmarkfile{page-spr}
+\loadmarkfile{page-plg}
+\loadmarkfile{page-str}
+
+\loadmarkfile{anch-pgr} % overloads tabl-tbl
+\loadmarkfile{anch-bar}
+\loadmarkfile{anch-snc}
+
+\loadmarkfile{math-ini}
+\loadmarkfile{math-pln}
+\loadmarkfile{math-for}
+\loadmarkfile{math-def}
+\loadmarkfile{math-ali}
+\loadmarkfile{math-arr}
+\loadmarkfile{math-frc}
+\loadmarkfile{math-scr}
+\loadmarkfile{math-int}
+\loadmarkfile{math-del}
+\loadmarkfile{math-inl}
+\loadmarkfile{math-dis}
+\loadmarkfile{math-lan}
+
+\loadmarkfile{strc-mat}
+
+\loadmarkfile{chem-ini}
+\loadmarkfile{chem-str}
+
+\loadmarkfile{core-fnt}
+\loadmarkfile{node-rul}
+
+\loadmarkfile{strc-not}
+\loadmarkfile{strc-lnt}
+
+\loadmarkfile{core-mis}
+
+\loadmarkfile{grph-trf}
+\loadmarkfile{grph-inc}
+\loadmarkfile{grph-fig}
+
+\loadmarkfile{pack-box}
+\loadmarkfile{pack-bar}
+\loadmarkfile{page-app}
+\loadmarkfile{meta-fig}
+
+\loadmarkfile{node-bck} % overloads anch-pgr (experimental and undocumented)
+
+\loadcorefile{lang-spa}
+
+\loadmarkfile{bibl-bib}
+\loadmarkfile{bibl-tra}
+
+\loadmarkfile{x-xtag} % at some point this will not be preloaded
+
+\loadcorefile{meta-xml}
+
+\loadcorefile{cont-log}
+
+\loadmarkfile{task-ini}
+
+\loadmarkfile{core-ctx}
+
+\loadmarkfile{core-ini}
+\loadmarkfile{core-def}
+
+%usemodule[x][res-04] % xml resource libraries
+%usemodule[x][res-08] % rlx runtime conversion
+%usemodule[x][res-12] % rli external indentification
+
+\unprotect
+
+\setupcurrentlanguage[\s!en]
+
+\prependtoks
+ \ctxlua{statistics.starttiming(ctx)}%
+\to \everyjob
+
+\appendtoks
+ \ctxlua{statistics.stoptiming(ctx)}%
+\to \everyjob
+
+\appendtoks
+ \writestatus\m!lua{used config path - \ctxlua{tex.print(caches.configpath())}}%
+ \writestatus\m!lua{used cache path - \ctxlua{tex.print(caches.path)}}%
+\to \everydump
+
+\appendtoks
+ \ctxlua {
+ statistics.report_storage("log")
+ statistics.save_fmt_status("\jobname","\contextversion","context.tex")
+ }%
+\to \everydump
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/context.rme b/tex/context/base/context.rme
new file mode 100644
index 000000000..1b1e48902
--- /dev/null
+++ b/tex/context/base/context.rme
@@ -0,0 +1,85 @@
+Some Basic information
+----------------------
+
+There are currently three interfaces available:
+
+ cont-en the english version
+ cont-de the german version
+ cont-nl the dutch version
+ cont-cz the czech version
+ cont-ro the romanian version
+ cont-it the italian version
+
+One should compile one of these (or all) into a fmt file.
+When one uses the main file,
+
+ context the undefined version
+
+TeX ask for an interface language as well as a message
+language. Here one has to specify the full name (english,
+german, dutch, etc.) or use the default (enter). The \
+savest way to update the TeX and MetaPost format files
+is to use TeXExec:
+
+texexec --make --alone en nl metafun
+
+In the TeXExec manual you can read how to generate a format
+with specific fonts and patterns.
+
+By default only the english hyphenation patterns are loaded,
+unless more are enabled in:
+
+ cont-usr the typesetting language specifications
+
+Furthermore, users can preset commands etc in the file
+
+ cont-sys a system file loaded at runtime
+
+For questions and remarks on ConTeXt, one can subscribe to
+the list:
+
+ ntg-context@ntg.nl
+
+by sending the message
+
+ subscribe ntg-context
+
+to the list server:
+
+ majordomo@ntg.nl
+
+One can find more info at:
+
+ www.pragma-ade.com
+
+or at the mirror sites mentioned there.
+
+Don't hesitate to ask questions. ConTeXt can do a lot, and
+the manuals are always a bit behind and incomplete. Also take
+a look at the files
+
+ mreadme.pdf
+ minstall.pdf
+ mtexexec.pdf
+ mtexutil.pdf
+
+The teTeX, fpTeX, and 4TeX distributions demonstrate how
+ConTeXt can be integrated in a TeX directory structure.
+
+-------------------------
+
+functionality removed from mkiv:
+
+page-log : layers can do teh same and are more flexible
+core-dat : just use lua for database purposes
+core-swd : this was a temporary solution
+
+functionality changed in mkii and mkiv:
+
+xtag-map : no longer preloaded
+xtag-stk : no longer preloaded
+xtag-prs : no longer preloaded
+
+-------------------------
+
+Hans Hagen, pragma@wxs.nl
diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex
new file mode 100644
index 000000000..47489658e
--- /dev/null
+++ b/tex/context/base/context.tex
@@ -0,0 +1,225 @@
+%D \module
+%D [ file=context,
+%D version=1995.10.10,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Format Generation,
+%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.
+
+\catcode`\{=1 \catcode`\}=2 \catcode`\#=6
+
+%D From the next string (which is set by the script that assembles the
+%D distribution) later on we will calculate a number that can be used
+%D by use modules to identify the feature level. Starting with version
+%D 2004.8.30 the low level interface is english. Watch out and adapt
+%D your styles an modules.
+
+\edef\contextformat {\jobname}
+\edef\contextversion{2010.05.24 13:05}
+
+%D For those who want to use this:
+
+\let\fmtname \contextformat
+\let\fmtversion\contextversion
+
+\let\showcontextbanner\relax
+
+%D Here we will test for what branch of source files we will take. The
+%D file suffix depends on the maintream engine: either lua enhanced,
+%D or traditional:
+%D
+%D \starttyping
+%D mki : low level dutch
+%D mkii : low level english
+%D mkiv : lua enhanced
+%D \stoptyping
+%D
+%D There is no \type {mkiii} unless you want to tag the transition
+%D version that way (going completely etex, code cleanup and such).
+
+\ifx\normalinput\undefined \let\normalinput\input \fi
+
+%D We have two versions, one for \PDFTEX\ and \XETEX, and one for
+%D \LUATEX.
+
+\chardef\contextmarkmode = \ifx\directlua\undefined 2 \else 4 \fi
+
+\def\loadcorefile#1{\normalinput#1\relax}
+\def\loadmarkfile#1{\normalinput#1.\mksuffix\relax}
+
+\ifnum\contextmarkmode=4
+ \def\loadmarkiifile#1{} \let\loadmarkivfile\loadcorefile \edef\mksuffix {mkiv} \edef\contextmark{MKIV}
+\else
+ \def\loadmarkivfile#1{} \let\loadmarkiifile\loadcorefile \edef\mksuffix {mkii} \edef\contextmark{MKII}
+\fi
+
+\let\loadmkiifile\loadmarkiifile
+\let\loadmkivfile\loadmarkivfile
+\let\loadmkfile \loadmarkfile
+
+%D Welcome to the main module. When this module is ran through
+%D \type{initex} or \type {tex -i} or \type {whatevertex} using
+%D \type{whatever switch}, the \CONTEXT\ format file is
+%D generated. During this process the user is asked for an
+%D interface language. Supplying \type{dutch} will generate a
+%D dutch version of \CONTEXT, supplying \type {english} will of
+%D course end op in a english version.
+%D
+%D Another option is to use \TEXEXEC\ (for \MKII):
+%D
+%D \starttyping
+%D texexec --make [--alone] [--engine] [--all]
+%D texexec --make [--alone] [--engine] en nl ... metafun mptopdf
+%D \stoptyping
+%D
+%D More information can be found in the \TEXEXEC\ manual.
+%D
+%D For \MKIV\ you have to do:
+%D
+%D \starttyping
+%D luatools --generate
+%D context --make en nl ...
+%D \stoptyping
+
+%D When you write modules (or extensions) you should avoid
+%D conflicts with existing macro names and mechanisms. If you are
+%D coming from another macro package, don't assume that macros
+%D with the same name are doing the same! \CONTEXT\ was written
+%D from scratch and therefore similarities are often a coincidence
+%D (to some extent one always ends up with the same names for
+%D similar concepts). The underlying models for elementary subsystems
+%D that deal with encodings, languages and fonts probably differ.
+%D
+%D Time has learned that users coming from \LATEX\ should not fall
+%D into thinking that macros like \type {\protect} represent the
+%D same functionality in both systems; actually, due to the way
+%D \CONTEXT\ is set up, some of those macros do complete different
+%D things. Macro packages evolve independent of each other, which
+%D means that code written for one system will not work in another
+%D system, unless it's real generic code.
+%D
+%D An API will become available soon (keep an eye on the ConTeXt
+%D Wiki www.contextgarden.org) and or listen in to the context
+%D mailing list (ntg-context@ntg.nl). Much additional information
+%D can be found at the PRAGMA website (www.pragma-ade.com).
+
+%D We now go either the \MKII\ or \MKIV\ route:
+
+\loadmarkfile{context}
+
+%D Let's quit this file when doing a \type {cont-..} generation.
+
+\doifparentfileelse{context}{\donothing}{\endinput}
+
+%D Unless we're generating a \type {cont-..} format, we also
+%D do the following.
+
+%D Except from english, no hyphenation patterns are loaded
+%D yet. Users can specify their needs in the next module:
+
+\loaduserspecifications
+
+%D Next we default to the same language as the interface.
+
+\unprotect
+
+\installlanguage [\s!us] [\c!state=\v!start]
+
+\startinterface english
+ \installlanguage [\s!gb] [\c!state=\v!start]
+\stopinterface
+
+\appendtoks \language [\s!us] \to \everyjob
+\appendtoks \mainlanguage [\s!us] \to \everyjob
+
+\startinterface german
+
+ \installlanguage [\s!de] [\c!state=\v!start]
+
+ \appendtoks \language [\s!de] \to \everyjob
+ \appendtoks \mainlanguage [\s!de] \to \everyjob
+
+\stopinterface
+
+\startinterface dutch
+
+ \installlanguage [\s!nl] [\c!state=\v!start]
+
+ \appendtoks \language [\s!nl] \to \everyjob
+ \appendtoks \mainlanguage [\s!nl] \to \everyjob
+
+\stopinterface
+
+\startinterface czech
+
+ \installlanguage [\s!cs] [\c!state=\v!start]
+
+ \appendtoks \language [\s!cs] \to \everyjob
+ \appendtoks \mainlanguage [\s!cs] \to \everyjob
+
+\stopinterface
+
+\startinterface italian
+
+ \installlanguage [\s!it] [\c!state=\v!start]
+
+ \appendtoks \language [\s!it] \to \everyjob
+ \appendtoks \mainlanguage [\s!it] \to \everyjob
+
+\stopinterface
+
+\startinterface romanian
+
+ \installlanguage [\s!ro] [\c!state=\v!start]
+
+ \appendtoks \language [\s!ro] \to \everyjob
+ \appendtoks \mainlanguage [\s!ro] \to \everyjob
+
+\stopinterface
+
+\startinterface french
+
+ \installlanguage [\s!fr] [\c!state=\v!start]
+
+ \appendtoks \language [\s!fr] \to \everyjob
+ \appendtoks \mainlanguage [\s!fr] \to \everyjob
+
+\stopinterface
+
+\startinterface persian
+
+ \installlanguage [\s!pe] [\c!state=\v!start]
+
+ \appendtoks \language [\s!pe] \to \everyjob
+ \appendtoks \mainlanguage [\s!pe] \to \everyjob
+
+\stopinterface
+
+\protect
+
+%D Finally we (pre)load some fonts.
+
+\setupencoding[default=ec]
+
+\usetypescript[fallback][\defaultencoding]
+
+\setupbodyfont[rm,12pt]
+
+%D The next hook can be used to generate a local (extended)
+%D format. This file is only searched for at the current
+%D path.
+
+% \readlocfile{cont-def.tex}
+% {\writestatus{loading}{adding extensions from cont-def}}
+% {}
+
+%D Now dumping the format is all that's left to be done.
+
+\errorstopmode \dump
+
+\endinput
diff --git a/tex/context/base/core-con.lua b/tex/context/base/core-con.lua
new file mode 100644
index 000000000..dca1c7d10
--- /dev/null
+++ b/tex/context/base/core-con.lua
@@ -0,0 +1,605 @@
+if not modules then modules = { } end modules ['core-con'] = {
+ version = 1.001,
+ comment = "companion to core-con.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+
This module implements a bunch of conversions. Some are more
+efficient than their counterpart, some are even
+slower but look nicer this way.
+
+
Some code may move to a module in the language namespace.
+--ldx]]--
+
+local utf = unicode.utf8
+
+local floor, date, time, concat = math.floor, os.date, os.time, table.concat
+local lower, format, rep = string.lower, string.format, string.rep
+local texsprint, utfchar = tex.sprint, utf.char
+local tonumber, tostring = tonumber, tostring
+
+local ctxcatcodes = tex.ctxcatcodes
+
+converters = converters or { }
+languages = languages or { }
+
+--~ ['arabic-digits'] = {
+--~ 0x0660, 0x0661, 0x0662, 0x0663, 0x0664,
+--~ 0x0665, 0x0666, 0x0667, 0x0668, 0x0669
+--~ },
+--~ ['persian-digits'] = {
+--~ 0x06F0, 0x06F1, 0x06F2, 0x06F3, 0x06F4,
+--~ 0x06F5, 0x06F6, 0x06F7, 0x06F8, 0x06F9
+--~ },
+
+languages.counters = {
+ ['**'] = {
+ 0x0061, 0x0062, 0x0063, 0x0064, 0x0065,
+ 0x0066, 0x0067, 0x0068, 0x0069, 0x006A,
+ 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074,
+ 0x0075, 0x0076, 0x0077, 0x0078, 0x0079,
+ 0x007A
+ },
+ ['slovenian'] = {
+ 0x0061, 0x0062, 0x0063, 0x010D, 0x0064,
+ 0x0065, 0x0066, 0x0067, 0x0068, 0x0069,
+ 0x006A, 0x006B, 0x006C, 0x006D, 0x006E,
+ 0x006F, 0x0070, 0x0072, 0x0073, 0x0161,
+ 0x0074, 0x0075, 0x0076, 0x007A, 0x017E
+ },
+ ['greek'] = { -- this should be the lowercase table
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395,
+ 0x0396, 0x0397, 0x0398, 0x0399, 0x039A,
+ 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5,
+ 0x03A6, 0x03A7, 0x03A8, 0x03A9
+ },
+ ['arabic'] = {
+ 0x0627, 0x0628, 0x062C, 0x062F, 0x0647,
+ 0x0648, 0x0632, 0x062D, 0x0637, 0x0649,
+ 0x0643, 0x0644, 0x0645, 0x0646, 0x0633,
+ 0x0639, 0x0641, 0x0635, 0x0642, 0x0631,
+ 0x0634, 0x062A, 0x062B, 0x062E, 0x0630,
+ 0x0636, 0x0638, 0x063A,
+ },
+ ['persian'] = {
+ 0x0627, 0x0628, 0x062C, 0x062F, 0x0647,
+ 0x0648, 0x0632, 0x062D, 0x0637, 0x0649,
+ 0x06A9, 0x0644, 0x0645, 0x0646, 0x0633,
+ 0x0639, 0x0641, 0x0635, 0x0642, 0x0631,
+ 0x0634, 0x062A, 0x062B, 0x062E, 0x0630,
+ 0x0636, 0x0638, 0x063A,
+ },
+ ['thai'] = {
+ 0xE050, 0xE051, 0xE052, 0xE053, 0xE054,
+ 0xE055, 0xE056, 0xE057, 0xE058, 0xE059
+ },
+ ['devangari'] = {
+ 0x0966, 0x0967, 0x0968, 0x0969, 0x096A,
+ 0x096B, 0x096C, 0x096D, 0x096E, 0x096F
+ },
+ ['gurmurkhi'] = {
+ 0x0A66, 0x0A67, 0x0A68, 0x0A69, 0x0A6A,
+ 0x0A6B, 0x0A6C, 0x0A6D, 0x0A6E, 0x0A6F
+ },
+ ['gujarati'] = {
+ 0x0AE6, 0x0AE7, 0x0AE8, 0x0AE9, 0x0AEA,
+ 0x0AEB, 0x0AEC, 0x0AED, 0x0AEE, 0x0AEF
+ },
+ ['tibetan'] = {
+ 0x0F20, 0x0F21, 0x0F22, 0x0F23, 0x0F24,
+ 0x0F25, 0x0F26, 0x0F27, 0x0F28, 0x0F29
+ },
+ ['korean'] = {
+ 0x3131, 0x3134, 0x3137, 0x3139, 0x3141,
+ 0x3142, 0x3145, 0x3147, 0x3148, 0x314A,
+ 0x314B, 0x314C, 0x314D, 0x314E
+ },
+ ['korean-parent'] = { -- parenthesed
+ 0x3200, 0x3201, 0x3202, 0x3203, 0x3204,
+ 0x3205, 0x3206, 0x3207, 0x3208, 0x3209,
+ 0x320A, 0x320B, 0x320C, 0x320D
+ },
+ ['korean-circle'] = { -- circled
+ 0x3260, 0x3261, 0x3262, 0x3263, 0x3264,
+ 0x3265, 0x3266, 0x3267, 0x3268, 0x3269,
+ 0x326A, 0x326B, 0x326C, 0x326D
+ },
+}
+
+local counters = languages.counters
+
+counters['ar'] = counters['arabic']
+counters['gr'] = counters['greek']
+counters['g'] = counters['greek']
+counters['sl'] = counters['slovenian']
+counters['kr'] = counters['korean']
+counters['kr-p'] = counters['korean-parent']
+counters['kr-c'] = counters['korean-circle']
+
+local fallback = utf.byte('0')
+
+local function chr(n,m)
+ if n > 0 and n < 27 then
+ texsprint(utfchar(n+m))
+ end
+end
+local function chrs(n,m)
+ if n > 26 then
+ chrs(floor((n-1)/26),m)
+ n = (n-1)%26 + 1
+ end
+ texsprint(utfchar(n+m))
+end
+local function maxchrs(n,m,cmd)
+ if n > m then
+ maxchrs(floor((n-1)/m),m,cmd)
+ n = (n-1)%m + 1
+ end
+ texsprint(ctxcatcodes, format("%s{%s}",cmd,n))
+end
+
+converters.chr = chr
+converters.chrs = chrs
+converters.maxchrs = maxchrs
+
+--~ more efficient but needs testing
+--~
+--~ local escapes = utffilters.private.escapes
+--~
+--~ local function do_alphabetic(n,mapping,chr)
+--~ local max = #mapping
+--~ if n > max then
+--~ do_alphabetic(floor((n-1)/max),max,chr)
+--~ n = (n-1)%max+1
+--~ end
+--~ n = chr(n,mapping)
+--~ texsprint(ctxcatcodes,escapes[n] or utfchar(n))
+--~ end
+
+--~ local lccodes, uccodes = characters.lccode, characters.uccode
+
+--~ local function do_alphabetic(n,mapping,chr)
+--~ local max = #mapping
+--~ if n > max then
+--~ do_alphabetic(floor((n-1)/max),mapping,chr)
+--~ n = (n-1)%max+1
+--~ end
+--~ characters.flush(chr(n,mapping))
+--~ end
+--~
+--~ local function lowercased(n,mapping) return characters.lccode(mapping[n] or fallback) end
+--~ local function uppercased(n,mapping) return characters.uccode(mapping[n] or fallback) end
+--~
+--~ function converters.alphabetic(n,code)
+--~ do_alphabetic(n,counters[code] or counters['**'],lowercased) -- lccode catches wrong tables
+--~ end
+--~
+--~ function converters.Alphabetic(n,code)
+--~ do_alphabetic(n,counters[code] or counters['**'],uppercased)
+--~ end
+
+--
+
+local function do_alphabetic(n,mapping,mapper)
+ local chr = mapper(mapping[n] or fallback)
+ local max = #mapping
+ if n > max then
+ do_alphabetic(floor((n-1)/max),mapping,mapper)
+ n = (n-1)%max+1
+ end
+ characters.flush(chr)
+end
+
+function converters.alphabetic(n,code)
+ do_alphabetic(n,counters[code] or counters['**'],characters.lccode)
+end
+
+function converters.Alphabetic(n,code)
+ do_alphabetic(n,counters[code] or counters['**'],characters.uccode)
+end
+
+--
+
+function converters.character (n) chr (n,96) end
+function converters.Character (n) chr (n,64) end
+function converters.characters(n) chrs(n,96) end
+function converters.Characters(n) chrs(n,64) end
+
+function converters.weekday(day,month,year)
+ texsprint(date("%w",time{year=year,month=month,day=day})+1)
+end
+
+function converters.isleapyear(year)
+ return (year % 400 == 0) or ((year % 100 ~= 0) and (year % 4 == 0))
+end
+
+function converters.leapyear(year)
+ if converters.isleapyear(year) then texsprint(1) else texsprint(0) end
+end
+
+local days = {
+ [false] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ [true] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+}
+
+function converters.nofdays(year,month)
+ texsprint(days[converters.isleapyear(year)][month])
+end
+
+function converters.year () texsprint(date("%Y")) end
+function converters.month () texsprint(date("%m")) end
+function converters.hour () texsprint(date("%H")) end
+function converters.minute () texsprint(date("%M")) end
+function converters.second () texsprint(date("%S")) end
+function converters.textime() texsprint(tonumber(date("%H"))*60+tonumber(date("%M"))) end
+
+local roman = {
+ { [0] = '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' },
+ { [0] = '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC' },
+ { [0] = '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM' },
+}
+
+local function toroman(n)
+ if n >= 4000 then
+ return toroman(floor(n/1000)) .. " " .. toroman(n%1000)
+ else
+ return rep("M",floor(n/1000)) .. roman[3][floor((n%1000)/100)] ..
+ roman[2][floor((n%100)/10)] .. roman[1][floor((n% 10)/1)]
+ end
+end
+
+function converters.romannumerals(n) return texsprint(lower(toroman(n))) end
+function converters.Romannumerals(n) return texsprint( toroman(n) ) end
+
+converters.toroman = toroman
+
+--~ local small = {
+--~ 0x0627, 0x066E, 0x062D, 0x062F, 0x0647, 0x0648, 0x0631
+--~ }
+
+--~ local large = {
+--~ { 0x0627, 0x0628, 0x062C, 0x062F, 0x0647, 0x0648, 0x0632, 0x062D, 0x0637, },
+--~ { 0x064A, 0x0643, 0x0644, 0x0645, 0x0646, 0x0633, 0x0639, 0x0641, 0x0635, },
+--~ { 0x0642, 0x0631, 0x0634, 0x062A, 0x062B, 0x062E, 0x0630, 0x0636, 0x0638, },
+--~ { 0x063A },
+--~ }
+
+local small = {
+ "ا", "ٮ", "ح", "د", "ه", "و", "ر",
+}
+
+local medium = {
+ "ا", "ب", "ج", "د", "ه", "و","ز", "ح", "ط" ,
+ "ي", "ك", "ل", "م", "ن", "س", "ع", "ف", "ص" ,
+ "ق", "ر", "ش", "ت", "ث", "خ", "ذ", "ض", "ظ" ,
+ "غ" ,
+}
+
+local large = {
+ { "ا", "ب", "ج", "د", "ه", "و","ز", "ح", "ط" },
+ { "ي", "ك", "ل", "م", "ن", "س", "ع", "ف", "ص" },
+ { "ق", "ر", "ش", "ت", "ث", "خ", "ذ", "ض", "ظ" },
+ { "غ" },
+}
+
+function converters.toabjad(n,what)
+ if n <= 0 or n >= 2000 then
+ return tostring(n)
+ elseif what == 2 and n <= 7 then
+ return small[n]
+ elseif what == 3 and n <= 28 then
+ return medium[n]
+ else
+ local a, b, c, d
+ a, n = floor(n/1000), n % 1000 -- mod(n,1000)
+ b, n = floor(n/ 100), n % 100 -- mod(n, 100)
+ c, n = floor(n/ 10), n % 10 -- mod(n, 10)
+ d, n = floor(n/ 1), n % 1 -- mod(n, 1)
+ return (large[4][a] or "") .. (large[3][b] or "") .. (large[2][c] or "") .. (large[1][d] or "")
+ end
+end
+
+function converters.abjadnumerals (n) return texsprint(converters.toabjad(n,false)) end
+function converters.abjadnodotnumerals(n) return texsprint(converters.toabjad(n,true)) end
+
+local vector = {
+ normal = {
+ [0] = "〇",
+ [1] = "一",
+ [2] = "二",
+ [3] = "三",
+ [4] = "四",
+ [5] = "五",
+ [6] = "六",
+ [7] = "七",
+ [8] = "八",
+ [9] = "九",
+ [10] = "十",
+ [100] = "百",
+ [1000] = "千",
+ [10000] = "万",
+ [100000000] = "亿",
+ },
+ cap = {
+ [0] = "零",
+ [1] = "壹",
+ [2] = "贰",
+ [3] = "叁",
+ [4] = "肆",
+ [5] = "伍",
+ [6] = "陆",
+ [7] = "柒",
+ [8] = "捌",
+ [9] = "玖",
+ [10] = "拾",
+ [100] = "佰",
+ [1000] = "仟",
+ [10000] = "萬",
+ [100000000] = "亿",
+ },
+ all = {
+ [0] = "〇",
+ [1] = "一",
+ [2] = "二",
+ [3] = "三",
+ [4] = "四",
+ [5] = "五",
+ [6] = "六",
+ [7] = "七",
+ [8] = "八",
+ [9] = "九",
+ [10] = "十",
+ [20] = "廿",
+ [30] = "卅",
+ [100] = "百",
+ [1000] = "千",
+ [10000] = "万",
+ [100000000] = "亿",
+ }
+}
+
+--~ function tochinese(n,name) -- normal, caps, all
+--~ local result = { }
+--~ local vector = vector[name] or vector.normal
+--~ while true do
+--~ if n == 0 then
+--~ break
+--~ elseif n >= 100000000 then
+--~ local m = floor(n/100000000)
+--~ if m > 1 then result[#result+1] = tochinese(m) end
+--~ result[#result+1] = vector[100000000]
+--~ n = n % 100000000
+--~ elseif n >= 10000000 then
+--~ result[#result+1] = tochinese(floor(n/10000))
+--~ result[#result+1] = vector[10000]
+--~ n = n % 10000
+--~ elseif n >= 1000000 then
+--~ result[#result+1] = tochinese(floor(n/10000))
+--~ result[#result+1] = vector[10000]
+--~ n = n % 10000
+--~ elseif n >= 100000 then
+--~ result[#result+1] = tochinese(floor(n/10000))
+--~ result[#result+1] = vector[10000]
+--~ n = n % 10000
+--~ elseif n >= 10000 then
+--~ local m = floor(n/10000)
+--~ if m > 1 then result[#result+1] = vector[m] end
+--~ result[#result+1] = vector[10000]
+--~ n = n % 10000
+--~ elseif n >= 1000 then
+--~ local m = floor(n/1000)
+--~ if m > 1 then result[#result+1] = vector[m] end
+--~ result[#result+1] = vector[1000]
+--~ n = n % 1000
+--~ elseif n >= 100 then
+--~ local m = floor(n/100)
+--~ if m > 1 then result[#result+1] = vector[m] end
+--~ result[#result+1] = vector[100]
+--~ n = n % 100
+--~ elseif n >= 10 then
+--~ local m = floor(n/10)
+--~ if vector[m*10] then
+--~ result[#result+1] = vector[m*10]
+--~ else
+--~ result[#result+1] = vector[m]
+--~ result[#result+1] = vector[10]
+--~ end
+--~ n = n % 10
+--~ else
+--~ result[#result+1] = vector[n]
+--~ break
+--~ end
+--~ end
+--~ return concat(result)
+--~ end
+
+function tochinese(n,name) -- normal, caps, all
+ -- improved version by Li Yanrui
+ local result = { }
+ local vector = vector[name] or vector.normal
+ while true do
+ if n == 0 then
+ break
+ elseif n >= 100000000 then
+ local m = floor(n/100000000)
+ result[#result+1] = tochinese(m,name)
+ result[#result+1] = vector[100000000]
+ local z = n - m * 100000000
+ if z > 0 and z < 10000000 then result[#result+1] = vector[0] end
+ n = n % 100000000
+ elseif n >= 10000000 then
+ local m = floor(n/10000)
+ result[#result+1] = tochinese(m,name)
+ result[#result+1] = vector[10000]
+ local z = n - m * 10000
+ if z > 0 and z < 1000 then result[#result+1] = vector[0] end
+ n = n % 10000
+ elseif n >= 1000000 then
+ local m = floor(n/10000)
+ result[#result+1] = tochinese(m,name)
+ result[#result+1] = vector[10000]
+ local z = n - m * 10000
+ if z > 0 and z < 1000 then result[#result+1] = vector[0] end
+ n = n % 10000
+ elseif n >= 100000 then
+ local m = floor(n/10000)
+ result[#result+1] = tochinese(m,name)
+ result[#result+1] = vector[10000]
+ local z = n - m * 10000
+ if z > 0 and z < 1000 then result[#result+1] = vector[0] end
+ n = n % 10000
+ elseif n >= 10000 then
+ local m = floor(n/10000)
+ result[#result+1] = vector[m]
+ result[#result+1] = vector[10000]
+ local z = n - m * 10000
+ if z > 0 and z < 1000 then result[#result+1] = vector[0] end
+ n = n % 10000
+ elseif n >= 1000 then
+ local m = floor(n/1000)
+ result[#result+1] = vector[m]
+ result[#result+1] = vector[1000]
+ local z = n - m * 1000
+ if z > 0 and z < 100 then result[#result+1] = vector[0] end
+ n = n % 1000
+ elseif n >= 100 then
+ local m = floor(n/100)
+ result[#result+1] = vector[m]
+ result[#result+1] = vector[100]
+ local z = n - m * 100
+ if z > 0 and z < 10 then result[#result+1] = vector[0] end
+ n = n % 100
+ elseif n >= 10 then
+ local m = floor(n/10)
+ if m > 1 and vector[m*10] then
+ result[#result+1] = vector[m*10]
+ else
+ result[#result+1] = vector[m]
+ result[#result+1] = vector[10]
+ end
+ n = n % 10
+ else
+ result[#result+1] = vector[n]
+ break
+ end
+ end
+ if (result[1] == vector[1] and result[2] == vector[10]) then
+ result[1] = ""
+ end
+ return concat(result)
+end
+
+--~ local t = { 1,10,15,25,35,45,11,100,111,1111,10000,11111,100000,111111,1111111,11111111,111111111,100000000,1111111111,11111111111,111111111111,1111111111111 }
+--~ for k=1,#t do
+--~ local v = t[k]
+--~ print(v,tochinese(v),tochinese(v,"all"),tochinese(v,"cap"))
+--~ end
+
+function converters.chinesenumerals (n) return texsprint(tochinese(n,"normal")) end
+function converters.chinesecapnumerals(n) return texsprint(tochinese(n,"cap" )) end
+function converters.chineseallnumerals(n) return texsprint(tochinese(n,"all" )) end
+
+--~ Well, since the one asking for this didn't test it the following code is not
+--~ enabled.
+--~
+--~ -- This Lua version is based on a Javascript by Behdad Esfahbod which in turn
+--~ -- is based on GPL'd code by Roozbeh Pournader of the The FarsiWeb Project
+--~ -- Group: http://www.farsiweb.info/jalali/jalali.js.
+--~ --
+--~ -- We start tables at one, I kept it zero based in order to stay close to
+--~ -- the original.
+--~ --
+--~ -- Conversion by Hans Hagen
+--~
+--~ local g_days_in_month = { [0]=31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+--~ local j_days_in_month = { [0]=31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 }
+--~
+--~ local function div(a,b)
+--~ return math.floor(a/b)
+--~ end
+--~
+--~ local function remainder(a,b)
+--~ return a - div(a,b)*b
+--~ end
+--~
+--~ function gregorian_to_jalali(gy,gm,gd)
+--~ local jy, jm, jd, g_day_no, j_day_no, j_np, i
+--~ gy, gm, gd = gy - 1600, gm - 1, gd - 1
+--~ g_day_no = 365*gy + div((gy+3),4) - div((gy+99),100) + div((gy+399),400)
+--~ i = 0
+--~ while i < gm do
+--~ g_day_no = g_day_no + g_days_in_month[i]
+--~ i = i + 1
+--~ end
+--~ if (gm>1 and ((gy%4==0 and gy%100~=0) or (gy%400==0))) then
+--~ g_day_no = g_day_no + 1
+--~ end
+--~ g_day_no = g_day_no + gd
+--~ j_day_no = g_day_no - 79
+--~ j_np = div(j_day_no,12053)
+--~ j_day_no = remainder(j_day_no,12053)
+--~ jy = 979 + 33*j_np + 4*div(j_day_no,1461)
+--~ j_day_no = remainder(j_day_no,1461)
+--~ if j_day_no >= 366 then
+--~ jy = jy + div((j_day_no-1),365)
+--~ j_day_no = remainder((j_day_no-1),365)
+--~ end
+--~ i = 0
+--~ while i < 11 and j_day_no >= j_days_in_month[i] do
+--~ j_day_no = j_day_no - j_days_in_month[i]
+--~ i = i + 1
+--~ end
+--~ jm = i + 1
+--~ jd = j_day_no + 1
+--~ return jy, jm, jd
+--~ end
+--~
+--~ function jalali_to_gregorian(jy,jm,jd)
+--~ local gy, gm, gd, g_day_no, j_day_no, leap, i
+--~ jy, jm, jd = jy - 979, jm - 1, jd - 1
+--~ j_day_no = 365*jy + div(jy,33)*8 + div((remainder(jy,33)+3),4)
+--~ i = 0
+--~ while i < jm do
+--~ j_day_no = j_day_no + j_days_in_month[i]
+--~ i = i + 1
+--~ end
+--~ j_day_no = j_day_no + jd
+--~ g_day_no = j_day_no + 79
+--~ gy = 1600 + 400*div(g_day_no,146097)
+--~ g_day_no = remainder (g_day_no, 146097)
+--~ leap = 1
+--~ if g_day_no >= 36525 then
+--~ g_day_no = g_day_no - 1
+--~ gy = gy + 100*div(g_day_no,36524)
+--~ g_day_no = remainder (g_day_no, 36524)
+--~ if g_day_no >= 365 then
+--~ g_day_no = g_day_no + 1
+--~ else
+--~ leap = 0
+--~ end
+--~ end
+--~ gy = gy + 4*div(g_day_no,1461)
+--~ g_day_no = remainder (g_day_no, 1461)
+--~ if g_day_no >= 366 then
+--~ leap = 0
+--~ g_day_no = g_day_no - 1
+--~ gy = gy + div(g_day_no, 365)
+--~ g_day_no = remainder(g_day_no, 365)
+--~ end
+--~ i = 0
+--~ while g_day_no >= g_days_in_month[i] + ((i == 1 and leap) or 0) do
+--~ g_day_no = g_day_no - g_days_in_month[i] + ((i == 1 and leap) or 0)
+--~ i = i + 1
+--~ end
+--~ gm = i + 1
+--~ gd = g_day_no + 1
+--~ return gy, gm, gd
+--~ end
+--~
+--~ print(gregorian_to_jalali(2009,02,24))
+--~ print(jalali_to_gregorian(1387,12,06))
diff --git a/tex/context/base/core-con.mkii b/tex/context/base/core-con.mkii
new file mode 100644
index 000000000..c39bdd9d4
--- /dev/null
+++ b/tex/context/base/core-con.mkii
@@ -0,0 +1,969 @@
+%D \module
+%D [ file=core-con,
+%D version=1997.26.08,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Conversion,
+%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 Core Macros / Conversion}
+
+\unprotect
+
+\ifx\currentlanguage\undefined \let\currentlanguage\empty \fi
+\ifx\labeltext \undefined \let\labeltext\firstofoneargument \fi
+
+%D This module deals with all kind of conversions from numbers
+%D and dates. I considered splitting this module in a support
+%D one and a core one, but to keep things simple as well as
+%D preserve the overview, I decided against splitting.
+
+\let\spr\firstofoneargument % separator
+\let\stp\firstofoneargument % stopper
+
+% cleaner, some day:
+%
+% \def\isolateseparators % etex only, even works with list separator overloading
+% {\unexpanded\def\spr##1{{##1}}%
+% \unexpanded\def\stp##1{{##1}}}
+
+% needed for arab :
+
+\def\isolateseparators % even works with list separator overloading
+ {\def\spr##1{{##1}}%
+ \def\stp##1{{##1}}}
+
+%D \macros
+%D {numbers}
+%D
+%D First we deal with the dummy conversion of numbers using the
+%D \TEX\ primitive \type{\number}. The uppercase alternative is
+%D only there for compatibility with the other conversion
+%D macros. We could do without \type{#1} but this way we get
+%D rid of unwanted braces. For the savety we also define a
+%D non||sence uppercase alternative.
+%D
+%D \showsetup{numbers}
+%D
+%D \starttyping
+%D \def\numbers#1{\number#1}
+%D \def\Numbers#1{\number#1}
+%D \stoptyping
+%D
+%D Due to read ahead, as in \type{[\pagenumber\space]} the space will
+%D disappear, unless we use:
+
+\def\numbers#1{\purenumber{#1}}
+\def\Numbers#1{\purenumber{#1}}
+
+%D \macros
+%D {romannumerals,Romannumerals}
+%D
+%D \TEX\ the program uses a rather tricky conversion from
+%D numbers to their roman counterparts. This conversion could
+%D of course be programmed in \TEX\ itself, but I guess Knuth
+%D found the programming trick worth presenting.
+%D
+%D \showsetup{romannumerals}
+%D \showsetup{Romannumerals}
+
+%D When upcasing the result, we just follow the text book rules
+%D of expansion. Later on we'll see some more uppercase tricks.
+
+\def\romannumerals#1%
+ {\romannumeral#1}
+
+%D For some years we had \unknown
+%D
+%D \starttyping
+%D \def\Romannumerals#1%
+%D {\uppercase\expandafter{\romannumeral#1}}
+%D \stoptyping
+%D
+%D \unknown but we need to be fully expandable in order to get
+%D the utility output file right, so now we have the following
+%D solution. It was Patrick Gundlach who first noticed this
+%D ommision.
+
+\def\Romannumerals#1%
+ {\expandafter\doRomannumerals\number#1\relax}
+
+\def\doRomannumerals#1#2\relax % spaces after ifcase prevent \relax
+ {\ifnum#1#2<10
+ \ifcase0#1#2 \or I\or II\or III\or IV\or V\or VI\or VII\or VIII\or IX\fi
+ \else\ifnum#1#2<100
+ \ifcase0#1 \or X\or XX\or XXX\or XL\or L\or LX\or LXX\or LXXX\or XC\fi
+ \doRomannumerals#2\relax
+ \else\ifnum#1#2<1000
+ \ifcase0#1 \or C\or CC\or CCC\or CD\or D\or DC\or DCC\or DCCC\or CM\fi
+ \doRomannumerals#2\relax
+ \else\ifnum#1#2<4000
+ \ifcase0#1 \or M\or MM\or MMM\fi
+ \doRomannumerals#2\relax
+ \else
+ \uppercase\expandafter{\romannumeral#1#2}%
+ \fi\fi\fi\fi}
+
+%D \macros
+%D {character,Character}
+%D
+%D Converting a number into a character can of course only
+%D be done with numbers less or equal to~26. At the cost of
+%D much more macros a faster conversion is possible, using:
+%D
+%D \starttyping
+%D \setvalue{char1}{a} \def\character#1{\getvalue{char#1}}
+%D \stoptyping
+%D
+%D But we prefer a simpel \type{\case}.
+%D
+%D \showsetup{character}
+%D \showsetup{Character}
+
+\def\unknowncharacter{-} % else in lists \relax
+
+%D Big case statements but pretty fast:
+
+\def\character#1%
+ {\ifcase#1\unknowncharacter
+ \or a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or k\or l\or m%
+ \or n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or x\or y\or z%
+ \else
+ \unknowncharacter
+ \fi}
+
+\def\Character#1%
+ {\ifcase#1\unknowncharacter
+ \or A\or B\or C\or D\or E\or F\or G\or H\or I\or J\or K\or L\or M%
+ \or N\or O\or P\or Q\or R\or S\or T\or U\or V\or W\or X\or Y\or Z%
+ \else
+ \unknowncharacter
+ \fi}
+
+%D \macros
+%D {characters,Characters}
+%D
+%D Converting large numbers is supported by the next two
+%D macros. This time we just count on: $\cdots$~x, y, z, aa,
+%D ab, ac~$\cdots$.
+%D
+%D \showsetup{characters}
+%D \showsetup{Characters}
+
+%D The fully expandable alternative:
+
+\def\dodoconvertcharacters#1#2#3%
+ {\ifcase#3\else
+ \ifnum#3>#1
+ \expandafter\doconvertcharacters\expandafter#2\expandafter{\the\numexpr(#3+12)/#1-1\relax}%
+ \expandafter#2\expandafter{\the\numexpr#3-((#3+12)/#1-1)*#1\relax}%
+ \else
+ \expandafter#2\expandafter{\number#3}%
+ \fi
+ \fi}
+
+\def\doconvertcharacters{\dodoconvertcharacters{26}}
+
+\def\characters{\doconvertcharacters\character}
+\def\Characters{\doconvertcharacters\Character}
+
+%D \macros
+%D {greeknumerals,Greeknumerals}
+%D
+%D Why should we only honour the romans, and not the greek?
+
+\def\greeknumerals#1%
+ {% no longer needed: \mathematics
+ {\ifcase#1\unknowncharacter\or
+ \alpha \or \beta \or \gamma \or \delta \or
+ \varepsilon \or \zeta \or \eta \or \theta \or
+ \iota \or \kappa \or \lambda \or \mu \or
+ \nu \or \xi \or \omicron \or \pi \or
+ \varrho \or \sigma \or \tau \or \upsilon \or
+ \phi \or \chi \or \psi \or \omega
+ \else
+ \unknowncharacter
+ \fi}}
+
+\def\Greeknumerals#1%
+ {% no longer needed: \mathematics
+ {\ifcase#1\unknowncharacter \or
+ \Alpha \or \Beta \or \Gamma \or \Delta \or
+ \Epsilon \or \Zeta \or \Eta \or \Theta \or
+ \Iota \or \Kappa \or \Lambda \or \Mu \or
+ \Nu \or \Xi \or \Omicron \or \Pi \or
+ \Rho \or \Sigma \or \Tau \or \Upsilon \or
+ \Phi \or \Xi \or \Psi \or \Omega
+ \else
+ \unknowncharacter
+ \fi}}
+
+%D \macros
+%D {oldstylenumerals,oldstyleromannumerals}
+%D
+%D These conversions are dedicated to Frans Goddijn.
+
+\unexpanded\def\oldstylenumerals#1%
+ {{\os\number#1}}
+
+\unexpanded\def\oldstyleromannumerals#1%
+ {{\leftrulefalse\rightrulefalse\ss\txx\boxrulewidth.15ex
+ \ruledhbox spread .15em{\hss\uppercased{\romannumerals{#1}}\hss}}}
+
+%D \macros
+%D {protectconversion}
+%D
+%D The previous two commands are not robust enough to be
+%D passed to \type{\write} en \type{\message}. That's why we
+%D introduce:
+
+\def\protectconversion
+ {\def\doconvertcharacters##1{##1}} % was \relax
+ %{\def\doconvertcharacters##1{\ifcase0##1 0\else##1\fi}} more save
+
+%D \macros
+%D {normaltime,normalyear,normalmonth,normalday}
+%D
+%D The last part of this module is dedicated to converting
+%D dates. Because we want to use as meaningful commands as
+%D possible, and because \TEX\ already uses up some of those,
+%D we save the original meanings.
+
+\savenormalmeaning\time
+\savenormalmeaning\year
+\savenormalmeaning\month
+\savenormalmeaning\day
+
+%D \macros
+%D {month,MONTH}
+%D
+%D Converting the month number into a month name is done
+%D using a case statement, abstact values and the label
+%D mechanism. This way users can easily redefine a label from
+%D for instance german into austrian.
+%D
+%D \starttyping
+%D \setuplabeltext [de] [january=J\"anner]
+%D \stoptyping
+%D
+%D Anyhow, the conversion looks like:
+
+\def\domonthtag#1%
+ {\ifcase#1%
+ \or \v!january \or \v!february \or \v!march \or \v!april
+ \or \v!may \or \v!june \or \v!july \or \v!august
+ \or \v!september \or \v!october \or \v!november \or \v!december
+ \else
+ \v!unknown
+ \fi}
+
+\def\doconvertmonthlong #1{\labeltext{\domonthtag{#1}}}
+\def\doconvertmonthshort#1{\labeltext{\domonthtag{#1}:\s!mnem}}
+
+\let\doconvertmonth\doconvertmonthlong
+
+%D We redefine the \TEX\ primitive \type{\month} as:
+%D
+%D \showsetup{month}
+%D \showsetup{MONTH}
+
+\def\monthlong {\doconvertmonthlong}
+\def\monthshort{\doconvertmonthshort}
+\def\month {\doconvertmonth}
+
+\def\MONTH #1{{\let\labeltext\LABELTEXT\month {#1}}}
+\def\MONTHLONG #1{{\let\labeltext\LABELTEXT\monthlong {#1}}}
+\def\MONTHSHORT#1{{\let\labeltext\LABELTEXT\monthshort{#1}}}
+
+%D We never explicitly needed this, but Tobias Burnus pointed
+%D out that it would be handy to convert to the day of the
+%D week. In doing so, we have to calculate the total number of
+%D days, taking leapyears into account. For those who are
+%D curious:
+%D
+%D \startitemize[packed]
+%D \item years that can be divided by 4 are leapyears
+%D \item exept years that can be divided by 100
+%D \item unless years can be divided by 400
+%D \stopitemize
+%D
+%D This makes the year 1900 into a normal year and 1996 and
+%D 2000 into leap years, right? Well, converting to string
+%D looks familiar:
+
+\def\doconvertday#1%
+ {\labeltext
+ {\ifcase#1
+ \or \v!sunday \or \v!monday \or \v!tuesday \or \v!wednesday
+ \or \v!thursday \or \v!friday \or \v!saturday \fi}}
+
+%D \macros
+%D {getdayoftheweek, dayoftheweek}
+%D
+%D The conversion algoritm is an old one and a translation from
+%D a procedure written in MODULA~2 back in the 80's. I finaly
+%D found the 4--100-400 rules in some enclopedia. Look at this
+%D messy low level routine that takes the day, month and year
+%D as arguments:
+
+\newcount\normalweekday
+
+\def\getdayoftheweek#1#2#3%
+ {\bgroup
+ \!!counta#3\relax
+ \advance\!!counta \minusone
+ \!!countb\!!counta
+ \multiply\!!countb 365
+ \advance\!!countb \ifcase#2\relax
+ 0 \or 0 \or 31 \or 59 \or 90 \or120 \or151 \or
+ 181 \or212 \or243 \or273 \or304 \or334 \or365 \fi
+ \advance\!!countb #1\relax
+ \ifnum#2>2
+ \doifleapyearelse{#3}{\advance\!!countb 1}{}\relax
+ \fi
+ \!!countc\!!counta
+ \dosetdivision\!!countc4\!!countc
+ \advance\!!countb \!!countc
+ \!!countc\!!counta
+ \dosetdivision\!!countc{100}\!!countc
+ \advance\!!countb -\!!countc
+ \!!countc\!!counta
+ \dosetdivision\!!countc{400}\!!countc
+ \advance\!!countb \!!countc
+ \dosetmodulo\!!countb7\!!countb
+ \advance\!!countb \plusone
+ \@EA\egroup\@EA\normalweekday\the\!!countb\relax}
+
+\def\dayoftheweek#1#2#3%
+ {\getdayoftheweek{#1}{#2}{#3}\doconvertday{\normalweekday}}
+
+%D Using this macro in
+%D
+%D \startbuffer
+%D monday: \dayoftheweek {4} {5} {1992}
+%D friday: \dayoftheweek {16} {6} {1995}
+%D monday: \dayoftheweek {25} {8} {1997}
+%D saturday: \dayoftheweek {30} {8} {1997}
+%D tuesday: \dayoftheweek {2} {1} {1996}
+%D tuesday: \dayoftheweek {7} {1} {1997}
+%D tuesday: \dayoftheweek {13} {1} {1998}
+%D friday: \dayoftheweek {1} {1} {2000}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D The macro \type {\getdayoftheweek} can be used to calculate
+%D the number \type {\normalweekday}.
+
+%D \macros
+%D {weekday,WEEKDAY}
+%D
+%D The first one is sort of redundant. It takes the day
+%D number argument.
+%D
+%D \showsetup{weekday}
+%D \showsetup{WEEKDAY}
+
+\def\weekday
+ {\doconvertday}
+
+\def\WEEKDAY#1%
+ {{\let\labeltext\LABELTEXT\doconvertday{#1}}}
+
+%D \macros
+%D {weekoftheday}
+%D
+%D {\em not yet implemented:}
+%D
+%D \starttyping
+%D \def\weekoftheday#1#2#3%
+%D {}
+%D \stoptyping
+
+%D \macros
+%D {doifleapyearelse,
+%D getdayspermonth}
+%D
+%D Sometimes we need to know if we're dealing with a
+%D leapyear, so here is a testmacro:
+%D
+%D \starttyping
+%D \doifleapyearelse{year}{yes}{no}
+%D \stoptyping
+%D
+%D An example of its use can be seen in the macro
+%D
+%D \starttyping
+%D \getdayspermonth{year}{month}
+%D \stoptyping
+%D
+%D The number of days is available in the macro \type
+%D {\numberofdays}.
+
+\def\doifleapyearelse#1% #2#3%
+ {\bgroup
+ \!!doneafalse
+ \!!counta#1%
+ \dosetmodulo\!!counta4\!!countb
+ \ifcase\!!countb
+ \dosetmodulo\!!counta{100}\!!countb
+ \ifcase\!!countb \else \!!doneatrue \fi
+ \dosetmodulo\!!counta{400}\!!countb
+ \ifcase\!!countb \!!doneatrue \fi
+ \fi
+ \if!!donea
+ \egroup\@EA\firstoftwoarguments % \def\next{#2}%
+ \else
+ \egroup\@EA\secondoftwoarguments % \def\next{#3}%
+ \fi} % \next}
+
+% untested but cleaner:
+%
+% \def\doifleapyearelse#1% #2#3%
+% {\bgroup
+% \dosetmodulo{#1}{400}\scratchcounter
+% \ifcase\scratchcounter
+% \else
+% \dosetmodulo{#1}{100}\scratchcounter
+% \ifcase\scratchcounter
+% \scratchcounter\plusone
+% \else
+% \dosetmodulo{#1}4\scratchcounter
+% \fi
+% \fi
+% \ifcase\scratchcounter
+% \egroup\@EA\firstoftwoarguments
+% \else
+% \egroup\@EA\secondoftwoarguments
+% \fi}
+
+\def\getdayspermonth#1#2%
+ {\doifleapyearelse{#1}
+ {\def\numberofdays{29}}
+ {\def\numberofdays{28}}%
+ \edef\numberofdays
+ {\ifcase#2 \or31\or\numberofdays\or31\or30\or
+ 31\or30\or31\or31\or30\or31\or30\or31\fi}}
+
+%D \macros
+%D {currentdate, date}
+%D
+%D We use these conversion macros in the date formatting
+%D macro:
+%D
+%D \showsetup{currentdate}
+%D
+%D This macro takes care of proper spacing and delivers for
+%D instance:
+%D
+%D \startbuffer
+%D \currentdate[weekday,day,month,year] % still dutch example
+%D \currentdate[WEEKDAY,day,MONTH,year] % still dutch example
+%D \stopbuffer
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D depending of course on the keywords. Here we gave:
+%D
+%D \typebuffer
+%D
+%D If needed one can also add non||keywords, like in
+%D
+%D \startbuffer
+%D \currentdate[dd,--,mm,--,yy]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or typeset: \getbuffer.
+%D
+%D When no argument is passed, the current date is given as
+%D specified per language (using \type{\installlanguage}).
+%D
+%D \showsetup{currentdate}
+%D
+%D \startbuffer
+%D \date
+%D \date[d=12,m=12,y=1998][weekday]
+%D \date[d=12,m=12,y=1998]
+%D \stopbuffer
+%D
+%D We can also typeset arbitrary dates, using the previous
+%D command.
+%D
+%D \typebuffer
+%D
+%D The date is specified by one character keys. When no date
+%D is given, we get the current date.
+%D
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+\def\kenmerkdatumpatroon{j,mm,dd} % jj,mm,dd changed at januari 1-1-2000
+
+\newsignal\datesignal
+
+\def\dobetweendates
+ {\ifdim\lastskip=\datesignal\relax\else
+ \unskip\space
+ \hskip\datesignal\relax
+ \fi}
+
+\newtoks \everycurrentdate
+
+\def\complexcurrentdate[#1]%
+ {\bgroup
+ \the\everycurrentdate
+ \def\betweendates{\let\betweendates\dobetweendates}%
+ % was \processcommacommandp[#1]\docomplexcurrentdate
+ \safeedef\ascii{\empty#1}% keep encoded chars
+ \@EA\processcommalist\@EA[\ascii]\docomplexcurrentdate
+ \ifdim\lastskip=\datesignal\relax
+ \unskip
+ \fi
+ \egroup}
+
+\def\docomplexcurrentdate#1%
+ {\lowercase{\edef\!!stringa{#1}}% permits usage in \smallcapped
+ \expanded{\processaction[\!!stringa]}% [#1]
+ [ \v!day=>\betweendates\the\normalday,
+ %\v!day+=>\betweendates\ordinaldaynumber\normalday,
+ \v!day+=>\betweendates\convertnumber{\v!day+}\normalday,
+ \v!month=>\betweendates\month\normalmonth,
+ \v!year=>\betweendates\the\normalyear,
+ \v!space=>\unskip\ \hskip\datesignal,% optimization -)
+ \ =>\unskip\ \hskip\datesignal,% optimization -)
+ d=>\convertnumber\v!day\normalday,
+ %d+=>\ordinaldaynumber\normalday,
+ d+=>\convertnumber{\v!day+}\normalday,
+ m=>\convertnumber\v!month\normalmonth,
+ j=>\convertnumber\v!year\normalyear,
+ y=>\convertnumber\v!year\normalyear,
+ w=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
+ dd=>\ifnum\normalday >9 \else0\fi\the\normalday,
+ %dd+=>\ordinaldaynumber{\ifnum\normalday >9 \else0\fi\the\normalday},
+ dd+=>\convertnumber{\v!day+}{\ifnum\normalday >9 \else0\fi\the\normalday},
+ mm=>\ifnum\normalmonth>9 \else0\fi\the\normalmonth,
+ jj=>\expandafter\gobbletwoarguments\the\normalyear,
+ yy=>\expandafter\gobbletwoarguments\the\normalyear,
+ \v!weekday=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
+ \v!referral=>\expanded{\complexcurrentdate[\kenmerkdatumpatroon]},
+ \s!unknown=>\unskip
+ % #1 and not the lowercased \commalistelement, vietnamese has text
+ % {} because #1 can have comma, like: {\ ,}
+ {#1}%
+ \hskip\datesignal
+ \def\betweendates{\let\betweendates\dobetweendates}]}
+
+\def\simplecurrentdate
+ {\expanded{\complexcurrentdate[\currentdatespecification]}}
+
+\definecomplexorsimple\currentdate
+
+\def\dodate[#1][#2]%
+ {\bgroup
+ \iffirstargument
+ \getparameters[\??da][d=\normalday,m=\normalmonth,y=\normalyear,#1]%
+ \normalday \@@dad\relax
+ \normalmonth\@@dam\relax
+ \normalyear \@@day\relax
+ \ifsecondargument
+ \currentdate[#2]%
+ \else
+ \currentdate
+ \fi
+ \else
+ \currentdate
+ \fi
+ \egroup}
+
+\def\date
+ {\dodoubleempty\dodate}
+
+%D \macros
+%D {currenttime}
+%D
+%D The currenttime is actually the jobtime. You can specify
+%D a pattern similar to the previous date macro using the
+%D keys \type {h}, \type {m} and a separator.
+
+\def\calculatecurrenttime
+ {\dosetdivision\time{60}\scratchcounter
+ \edef\currenthour {\ifnum\scratchcounter<10 0\fi \the\scratchcounter}%
+ \dosetmodulo \time{60}\scratchcounter
+ \edef\currentminute{\ifnum\scratchcounter<10 0\fi \the\scratchcounter}}
+
+\let\currenthour \!!plusone
+\let\currentminute\!!plusone
+
+\def\currenttimespecification{h,:,m}
+
+\def\complexcurrenttime[#1]%
+ {\calculatecurrenttime
+ \processallactionsinset[#1]
+ [h=>\currenthour,m=>\currentminute,\s!unknown=>\commalistelement]}
+
+\def\simplecurrenttime
+ {\expanded{\complexcurrenttime[\currenttimespecification]}}
+
+\definecomplexorsimple\currenttime
+
+%D Because we're dealing with dates, we also introduce a few
+%D day loops:
+%D
+%D \starttyping
+%D \processmonth{year}{month}{command}
+%D \processyear{year}{command}{before}{after}
+%D \stoptyping
+%D
+%D The counters \type {\normalyear}, \type {\normalmonth} and
+%D \type{\normalday} can be used for for date manipulations.
+
+\long\def\processmonth#1#2#3% year month command
+ {\bgroup
+ \getdayspermonth{#1}{#2}%
+ \dostepwiserecurse1\numberofdays1%
+ {\normalyear #1\relax
+ \normalmonth#2\relax
+ \normalday \recurselevel\relax
+ #3}%
+ \egroup}
+
+\def\lastmonth{12} % can be set to e.g. 1 when testing
+
+\long\def\processyear#1#2#3#4% year command before after
+ {\bgroup
+ \dorecurse\lastmonth
+ {\normalyear #1\relax
+ \normalmonth\recurselevel\relax
+ #3\processmonth\normalyear\normalmonth{#2}#4}%
+ \egroup}
+
+%D \macros
+%D {defineconversion, convertnumber}
+%D
+%D Conversion involves the macros that we implemented earlier
+%D in this module.
+%D
+%D \showsetup{defineconversion}
+%D \showsetup{convertnumber}
+%D
+%D We can feed this command with conversion macros as well as
+%D a set of conversion symbols. Both need a bit different
+%D treatment.
+%D
+%D \starttyping
+%D \defineconversion [roman] [\romannumerals]
+%D \defineconversion [set 1] [$\star$,$\bullet$,$\ast$]
+%D \stoptyping
+%D
+%D You can define a language dependent conversion with:
+%D
+%D \starttyping
+%D \defineconversion [en] [whatever] [\something]
+%D \stoptyping
+
+% \def\dodefineconversion[#1][#2]%
+% {\ConvertConstantAfter\doifinstringelse{,}{#2}
+% {\scratchcounter=0
+% \def\docommand##1%
+% {\advance\scratchcounter 1
+% \setvalue{\??cv#1\the\scratchcounter}{##1}}%
+% \processcommalist[#2]\docommand
+% \setvalue{\??cv#1}##1{\csname\??cv#1##1\endcsname}}
+% {\setvalue{\??cv#1}{#2}}}
+%
+% \def\defineconversion%
+% {\dodoubleargument\dodefineconversion}
+
+\def\defineconversion
+ {\dotripleempty\dodefineconversion}
+
+\def\dodefineconversion[#1][#2][#3]%
+ {\ifthirdargument
+ \dododefineconversion[#1][#2][#3]%
+ \else
+ \dododefineconversion[][#1][#2]%
+ \fi}
+
+%D \starttyping
+%D \def\dododefineconversion[#1][#2][#3]%
+%D {\ConvertConstantAfter\doifinstringelse{,}{#3}
+%D {\scratchcounter\zerocount
+%D \def\docommand##1%
+%D {\advance\scratchcounter \plusone
+%D \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
+%D \processcommalist[#3]\docommand
+%D \setvalue{\??cv#1#2}##1{\executeifdefined{\??cv#1#2##1}\unknown}} % catch out-of-range numbers
+%D {\setvalue{\??cv#1#2}{#3}}}
+%D \stoptyping
+
+%D This approach has the disadvantage that when you run out of
+%D symbols you get unknown results. The following implementation
+%D permits overloading of the converter:
+
+\def\dododefineconversion[#1][#2][#3]%
+ {\ConvertConstantAfter\doifinstringelse{,}{#3}
+ {\scratchcounter\zerocount
+ \def\docommand##1%
+ {\advance\scratchcounter \plusone
+ \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
+ \processcommalist[#3]\docommand
+ \setevalue{\??cv#1#2}##1%
+ {\noexpand\docheckedconversion{#1#2}{\the\scratchcounter}{##1}}}
+ {\setvalue{\??cv#1#2}{#3}}}
+
+\def\docheckedconversion#1#2#3% class maxnumber number
+ {\executeifdefined{\??cv#1#3}\unknown}
+
+%D When Gerben reported problems with footnote numbering per page,
+%D Taco came with the following wrap around solution. So, let's
+%D overload the checked conversion macro:
+
+\def\docheckedconversion#1#2#3% class maxnumber number
+ {\executeifdefined{\??cv#1\modulatednumber{#2}{#3}}\unknown}
+
+%D Taco's modulo code is implemented in the system module
+%D \type {syst-con}.
+
+%D If a conversion is just a font switch then we need to make sure
+%D that the number is indeed end up as number in the input, so we
+%D need to handle the second argument.
+
+\def\convertnumber#1#2%
+ {\csname\??cv
+ \ifcsname\??cv\currentlanguage#1\endcsname
+ \currentlanguage#1%
+ \else\ifcsname\??cv#1\endcsname
+ #1%
+ \else
+ \s!default
+ \fi\fi
+ \endcsname{\number#2}}
+
+\def\doifconversiondefinedelse#1%
+ {\ifcsname\??cv\currentlanguage#1\endcsname
+ \@EA\firstoftwoarguments
+ \else\ifcsname\??cv#1\endcsname
+ \@EAEAEA\firstoftwoarguments
+ \else
+ \@EAEAEA\secondoftwoarguments
+ \fi\fi}
+
+\def\doifelseconversionnumber#1#2% slow but seldom used
+ {\doifdefinedelse{\??cv#1#2}}
+
+%D Handy.
+
+\setvalue{\??cv:\c!n:\v!one }{1}
+\setvalue{\??cv:\c!n:\v!two }{2}
+\setvalue{\??cv:\c!n:\v!three}{3}
+\setvalue{\??cv:\c!n:\v!four }{4}
+\setvalue{\??cv:\c!n:\v!five }{5}
+
+\def\wordtonumber#1#2{\ifcsname\??cv:\c!n:#1\endcsname\csname\??cv:\c!n:#1\endcsname\else#2\fi}
+
+% \defineconversion[ctx][c,o,n,t,e,x,t]
+%
+% \doloop{\doifelseconversionnumber{ctx}{\recurselevel}{[\recurselevel]}{\exitloop}}
+
+\defineconversion [\s!default] [\numbers]
+
+%D As longs as symbols are linked to levels or numbers, we can
+%D also use the conversion mechanism, but in for instance the
+%D itemization macros, we prefer symbols because they can more
+%D easier be (partially) redefined. Symbols are implemented
+%D in another module.
+
+\defineconversion [] [\numbers] % the default conversion
+
+\defineconversion [a] [\characters]
+\defineconversion [A] [\Characters]
+\defineconversion [AK] [\smallcapped\characters]
+\defineconversion [KA] [\smallcapped\characters]
+
+\defineconversion [n] [\numbers]
+\defineconversion [N] [\Numbers]
+\defineconversion [m] [\mediaeval]
+
+\defineconversion [i] [\romannumerals]
+\defineconversion [I] [\Romannumerals]
+\defineconversion [r] [\romannumerals]
+\defineconversion [R] [\Romannumerals]
+\defineconversion [KR] [\smallcapped\romannumerals]
+\defineconversion [RK] [\smallcapped\romannumerals]
+
+\defineconversion [g] [\greeknumerals]
+\defineconversion [G] [\Greeknumerals]
+
+\defineconversion [o] [\oldstylenumerals]
+\defineconversion [O] [\oldstylenumerals]
+\defineconversion [or] [\oldstyleromannumerals]
+
+\defineconversion [\v!character] [\character]
+\defineconversion [\v!Character] [\Character]
+
+\defineconversion [\v!characters] [\characters]
+\defineconversion [\v!Characters] [\Characters]
+
+\defineconversion [\v!numbers] [\numbers]
+\defineconversion [\v!Numbers] [\Numbers]
+\defineconversion [\v!mediaeval] [\mediaeval]
+
+\defineconversion [\v!romannumerals] [\romannumerals]
+\defineconversion [\v!Romannumerals] [\Romannumerals]
+
+\defineconversion [\v!greek] [\greeknumerals]
+\defineconversion [\v!Greek] [\Greeknumerals]
+
+\defineconversion [arabicnumerals] [\arabicnumerals]
+\defineconversion [persiannumerals] [\arabicnumerals]
+
+\defineconversion [month] [\doconvertmonthlong]
+\defineconversion [month:mnem] [\doconvertmonthshort]
+
+% Some bonus ones:
+
+\defineconversion [\v!empty] [\gobbleoneargument]
+\defineconversion [\v!none] [\numbers]
+
+\ifx\symbol\undefined \def\symbol[#1]{#1} \fi % todo
+
+\defineconversion
+ [set 0]
+ [{\symbol[bullet]},
+ {\symbol[dash]},
+ {\symbol[star]},
+ {\symbol[triangle]},
+ {\symbol[circle]},
+ {\symbol[medcircle]},
+ {\symbol[bigcircle]},
+ {\symbol[square]}]
+
+\defineconversion
+ [set 1]
+ [\mathematics{\star},
+ \mathematics{\star\star},
+ \mathematics{\star\star\star},
+ \mathematics{\ddagger},
+ \mathematics{\ddagger\ddagger},
+ \mathematics{\ddagger\ddagger\ddagger},
+ \mathematics{\ast},
+ \mathematics{\ast\ast},
+ \mathematics{\ast\ast\ast}]
+
+\defineconversion
+ [set 2]
+ [\mathematics{*},
+ \mathematics{\dag},
+ \mathematics{\ddag},
+ \mathematics{**},
+ \mathematics{\dag\dag},
+ \mathematics{\ddag\ddag},
+ \mathematics{***},
+ \mathematics{\dag\dag\dag},
+ \mathematics{\ddag\ddag\ddag},
+ \mathematics{****},
+ \mathematics{\dag\dag\dag\dag},
+ \mathematics{\ddag\ddag\ddag\ddag}]
+
+\defineconversion
+ [set 3]
+ [\mathematics{\star},
+ \mathematics{\star\star},
+ \mathematics{\star\star\star},
+ \mathematics{\ddagger},
+ \mathematics{\ddagger\ddagger},
+ \mathematics{\ddagger\ddagger\ddagger},
+ \mathematics{\P},
+ \mathematics{\P\P},
+ \mathematics{\P\P\P},
+ \mathematics{\S},
+ \mathematics{\S\S},
+ \mathematics{\S\S\S},
+ \mathematics{\ast},
+ \mathematics{\ast\ast},
+ \mathematics{\ast\ast\ast}]
+
+%D \macros
+%D {defineconversionvector,conversionnumber} % bad names so no danger for clash
+%D
+%D For Adam and friends \unknown
+%D
+%D \startitemize[persiannummerals]
+%D \item test \item test \item test \item test
+%D \stopitemize
+
+\def\defineconversionvector#1#2% name base
+ {\bgroup
+ % dirty trick
+ \uccode`\*=`\1
+ % plain:
+ % \uccode`\0=\numexpr#2+0\relax \uccode`\1=\numexpr#2+1\relax
+ % \uccode`\2=\numexpr#2+2\relax \uccode`\3=\numexpr#2+3\relax
+ % \uccode`\4=\numexpr#2+4\relax \uccode`\5=\numexpr#2+5\relax
+ % \uccode`\6=\numexpr#2+6\relax \uccode`\7=\numexpr#2+7\relax
+ % \uccode`\8=\numexpr#2+8\relax \uccode`\9=\numexpr#2+9\relax
+ % context:
+ \dostepwiserecurse091{\expandafter\uccode\expandafter`\recurselevel=\numexpr#2+\recurselevel}%
+ % prepared macro
+ \uppercase\expandafter{\expandafter\gdef\csname::cvn::#1::\endcsname##*%
+ {\ifcase##* 0\or1\or2\or3\or4\or5\or6\or7\or8\or9\fi}}%
+ \egroup}
+
+\def\conversionnumber#1#2%
+ {\ifcsname::cvn::#1::\endcsname
+ \expandafter\doconversionnumber\csname::cvn::#1::\expandafter\endcsname\number#2\relax
+ \else
+ \number#2%
+ \fi}
+
+\def\doconversionnumber#1#2%
+ {\ifx#2\relax
+ \expandafter\gobbleoneargument
+ \else
+ #1{#2}%
+ \expandafter\doconversionnumber
+ \fi#1}
+
+% actually mkiii code
+
+\ifnum\texengine=\xetexengine
+
+ \defineconversionvector{arabicnumerals} {"0660}
+ \defineconversionvector{persiannumerals} {"06F0}
+ \defineconversionvector{thainumerals} {"0E50}
+ \defineconversionvector{devanagarinumerals}{"0966}
+ \defineconversionvector{gurmurkhinumerals} {"0A66}
+ \defineconversionvector{gujaratinumerals} {"0AE6}
+ \defineconversionvector{tibetannumerals} {"0F20} % also "half numerals?"
+
+ \defineconversion[arabicnumerals] [\conversionnumber{arabicnumerals}]
+ \defineconversion[persiannumerals] [\conversionnumber{persiannumerals}]
+ \defineconversion[thainumerals] [\conversionnumber{thainumerals}]
+ \defineconversion[devanagarinumerals][\conversionnumber{devanagarinumerals}]
+ \defineconversion[gurmurkhinumerals] [\conversionnumber{gurmurkhinumerals}]
+ \defineconversion[gujaratinumerals] [\conversionnumber{gujaratinumerals}]
+ \defineconversion[tibetannumerals] [\conversionnumber{tibetannumerals}]
+
+\fi
+
+\protect \endinput
diff --git a/tex/context/base/core-con.mkiv b/tex/context/base/core-con.mkiv
new file mode 100644
index 000000000..2d2e5d5d7
--- /dev/null
+++ b/tex/context/base/core-con.mkiv
@@ -0,0 +1,860 @@
+%D \module
+%D [ file=core-con,
+%D version=1997.26.08,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Conversion,
+%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 Core Macros / Conversion}
+
+\registerctxluafile{core-con}{1.001}
+
+\unprotect
+
+\ifx\currentlanguage\undefined \let\currentlanguage\empty \fi
+\ifx\labeltext \undefined \let\labeltext\firstofoneargument \fi
+
+%D This module deals with all kind of conversions from numbers
+%D and dates. I considered splitting this module in a support
+%D one and a core one, but to keep things simple as well as
+%D preserve the overview, I decided against splitting.
+
+\let\spr\firstofoneargument % separator
+\let\stp\firstofoneargument % stopper
+
+% cleaner, some day:
+%
+% \def\isolateseparators % etex only, even works with list separator overloading
+% {\unexpanded\def\spr##1{{##1}}%
+% \unexpanded\def\stp##1{{##1}}}
+
+% needed for arab :
+
+\def\isolateseparators % even works with list separator overloading
+ {\def\spr##1{{##1}}%
+ \def\stp##1{{##1}}}
+
+%D \macros
+%D {numbers}
+%D
+%D First we deal with the dummy conversion of numbers using the
+%D \TEX\ primitive \type{\number}. The uppercase alternative is
+%D only there for compatibility with the other conversion
+%D macros. We could do without \type{#1} but this way we get
+%D rid of unwanted braces. For the savety we also define a
+%D non||sence uppercase alternative.
+%D
+%D \showsetup{numbers}
+%D
+%D \starttyping
+%D \def\numbers#1{\number#1}
+%D \def\Numbers#1{\number#1}
+%D \stoptyping
+%D
+%D Due to read ahead, as in \type{[\pagenumber\space]} the space will
+%D disappear, unless we use:
+
+\def\numbers#1{\purenumber{#1}}
+\def\Numbers#1{\purenumber{#1}}
+
+%D \macros
+%D {romannumerals,Romannumerals}
+%D
+%D \TEX\ the program uses a rather tricky conversion from
+%D numbers to their roman counterparts. This conversion could
+%D of course be programmed in \TEX\ itself, but I guess Knuth
+%D found the programming trick worth presenting.
+%D
+%D \showsetup{romannumerals}
+%D \showsetup{Romannumerals}
+
+\def\romannumerals#1{\ctxlua{converters.romannumerals(\number#1)}}
+\def\Romannumerals#1{\ctxlua{converters.Romannumerals(\number#1)}}
+
+%D Arabic etc:
+
+\def\abjadnumerals #1{\ctxlua{converters.abjadnumerals (\number#1)}}
+\def\abjadnodotnumerals#1{\ctxlua{converters.abjadnodotnumerals(\number#1)}}
+\def\abjadnaivenumerals#1{\ctxlua{converters.arabicnumerals (\number#1)}}
+
+\def\languagecharacters#1{\ctxlua{converters.alphabetic(\number#1,"\currentlanguage")}} % new
+\def\languageCharacters#1{\ctxlua{converters.Alphabetic(\number#1,"\currentlanguage")}} % new
+
+% we could use an auxiliary macro to save some bytes in the format
+%
+% \def\dolanguagecharacters#1#2{\ctxlua{converters.alphabetic(\number#2,"#1")}}
+
+\def\thainumerals #1{\ctxlua{converters.alphabetic(\number#1,"thai")}}
+\def\devanagarinumerals#1{\ctxlua{converters.alphabetic(\number#1,"devanagari")}}
+\def\gurmurkhinumerals #1{\ctxlua{converters.alphabetic(\number#1,"gurmurkhi")}}
+\def\gujaratinumerals #1{\ctxlua{converters.alphabetic(\number#1,"gujarati")}}
+\def\tibetannumerals #1{\ctxlua{converters.alphabetic(\number#1,"tibetan")}}
+\def\greeknumerals #1{\ctxlua{converters.alphabetic(\number#1,"greek")}}
+\def\Greeknumerals #1{\ctxlua{converters.Alphabetic(\number#1,"greek")}}
+\def\arabicnumerals #1{\ctxlua{converters.alphabetic(\number#1,"arabic")}}
+\def\persiannumerals #1{\ctxlua{converters.alphabetic(\number#1,"persian")}}
+
+\let\arabicexnumerals \persiannumerals
+
+\def\koreannumerals #1{\ctxlua{converters.alphabetic(\number#1,"korean")}}
+\def\koreannumeralsp#1{\ctxlua{converters.alphabetic(\number#1,"korean-parent")}}
+\def\koreannumeralsc#1{\ctxlua{converters.alphabetic(\number#1,"korean-circle")}}
+
+\def\chinesenumerals #1{\ctxlua{converters.chinesenumerals (\number#1)}}
+\def\chinesecapnumerals#1{\ctxlua{converters.chinesecapnumerals(\number#1,"cap")}}
+\def\chineseallnumerals#1{\ctxlua{converters.chineseallnumerals(\number#1,"all")}}
+
+%D \macros
+%D {character,Character}
+%D
+%D Converting a number into a character can of course only
+%D be done with numbers less or equal to~26. At the cost of
+%D much more macros a faster conversion is possible, using:
+%D
+%D \starttyping
+%D \setvalue{char1}{a} \def\character#1{\getvalue{char#1}}
+%D \stoptyping
+%D
+%D But we prefer a simpel \type{\case}.
+%D
+%D \showsetup{character}
+%D \showsetup{Character}
+
+\def\unknowncharacter{-} % else in lists \relax
+
+\def\character#1{\ctxlua{converters.character (\number#1)}}
+\def\Character#1{\ctxlua{converters.Character (\number#1)}}
+
+%D \macros
+%D {characters,Characters}
+%D
+%D Converting large numbers is supported by the next two
+%D macros. This time we just count on: $\cdots$~x, y, z, aa,
+%D ab, ac~$\cdots$.
+%D
+%D \showsetup{characters}
+%D \showsetup{Characters}
+
+\def\characters#1{\ctxlua{converters.characters(\number#1)}}
+\def\Characters#1{\ctxlua{converters.Characters(\number#1)}}
+
+%D \macros
+%D {greeknumerals,Greeknumerals}
+%D
+%D Why should we only honour the romans, and not the greek?
+
+\let\greeknumerals\gobbleoneargument
+\let\Greeknumerals\gobbleoneargument
+
+%D \macros
+%D {oldstylenumerals,oldstyleromannumerals}
+%D
+%D These conversions are dedicated to Frans Goddijn.
+
+\unexpanded\def\oldstylenumerals#1%
+ {{\os\number#1}}
+
+\unexpanded\def\oldstyleromannumerals#1%
+ {{\leftrulefalse\rightrulefalse\ss\txx\boxrulewidth.15ex
+ \ruledhbox spread .15em{\hss\uppercased{\romannumerals{#1}}\hss}}}
+
+%D \macros
+%D {protectconversion}
+%D
+%D The previous two commands are not robust enough to be
+%D passed to \type{\write} en \type{\message}. That's why we
+%D introduce:
+
+\def\protectconversion
+ {\def\doconvertcharacters##1{##1}} % was \relax
+ %{\def\doconvertcharacters##1{\ifcase0##1 0\else##1\fi}} more save
+
+%D \macros
+%D {normaltime,normalyear,normalmonth,normalday}
+%D
+%D The last part of this module is dedicated to converting
+%D dates. Because we want to use as meaningful commands as
+%D possible, and because \TEX\ already uses up some of those,
+%D we save the original meanings.
+
+\savenormalmeaning\time
+\savenormalmeaning\year
+\savenormalmeaning\month
+\savenormalmeaning\day
+
+%D \macros
+%D {month,MONTH}
+%D
+%D Converting the month number into a month name is done
+%D using a case statement, abstact values and the label
+%D mechanism. This way users can easily redefine a label from
+%D for instance german into austrian.
+%D
+%D \starttyping
+%D \setuplabeltext [de] [january=J\"anner]
+%D \stoptyping
+%D
+%D Anyhow, the conversion looks like:
+
+\def\domonthtag#1%
+ {\ifcase#1%
+ \or \v!january \or \v!february \or \v!march \or \v!april
+ \or \v!may \or \v!june \or \v!july \or \v!august
+ \or \v!september \or \v!october \or \v!november \or \v!december
+ \else
+ \v!unknown
+ \fi}
+
+\def\doconvertmonthlong #1{\labeltext{\domonthtag{#1}}}
+\def\doconvertmonthshort#1{\labeltext{\domonthtag{#1}:\s!mnem}}
+
+\let\doconvertmonth\doconvertmonthlong
+
+%D We redefine the \TEX\ primitive \type{\month} as:
+%D
+%D \showsetup{month}
+%D \showsetup{MONTH}
+
+\def\monthlong {\doconvertmonthlong}
+\def\monthshort{\doconvertmonthshort}
+\def\month {\doconvertmonth}
+
+\def\MONTH #1{{\let\labeltext\LABELTEXT\month {#1}}}
+\def\MONTHLONG #1{{\let\labeltext\LABELTEXT\monthlong {#1}}}
+\def\MONTHSHORT#1{{\let\labeltext\LABELTEXT\monthshort{#1}}}
+
+%D We never explicitly needed this, but Tobias Burnus pointed
+%D out that it would be handy to convert to the day of the
+%D week. In doing so, we have to calculate the total number of
+%D days, taking leapyears into account. For those who are
+%D curious:
+%D
+%D \startitemize[packed]
+%D \item years that can be divided by 4 are leapyears
+%D \item exept years that can be divided by 100
+%D \item unless years can be divided by 400
+%D \stopitemize
+%D
+%D This makes the year 1900 into a normal year and 1996 and
+%D 2000 into leap years, right? Well, converting to string
+%D looks familiar:
+
+\def\doconvertday#1%
+ {\labeltext
+ {\ifcase#1
+ \or \v!sunday \or \v!monday \or \v!tuesday \or \v!wednesday
+ \or \v!thursday \or \v!friday \or \v!saturday \fi}}
+
+%D \macros
+%D {getdayoftheweek, dayoftheweek}
+%D
+%D The conversion algoritm is an old one and a translation from
+%D a procedure written in MODULA~2 back in the 80's. I finaly
+%D found the 4--100-400 rules in some enclopedia. Look at this
+%D messy low level routine that takes the day, month and year
+%D as arguments:
+
+\newcount\normalweekday
+
+\def\getdayoftheweek#1#2#3{\normalweekday\ctxlua{converters.weekday(\number#1,\number#2,\number#3)}}
+\def\dayoftheweek #1#2#3{\doconvertday{\ctxlua{converters.weekday(\number#1,\number#2,\number#3)}}}
+
+%D Using this macro in
+%D
+%D \startbuffer
+%D monday: \dayoftheweek {4} {5} {1992}
+%D friday: \dayoftheweek {16} {6} {1995}
+%D monday: \dayoftheweek {25} {8} {1997}
+%D saturday: \dayoftheweek {30} {8} {1997}
+%D tuesday: \dayoftheweek {2} {1} {1996}
+%D tuesday: \dayoftheweek {7} {1} {1997}
+%D tuesday: \dayoftheweek {13} {1} {1998}
+%D friday: \dayoftheweek {1} {1} {2000}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D The macro \type {\getdayoftheweek} can be used to calculate
+%D the number \type {\normalweekday}.
+
+%D \macros
+%D {weekday,WEEKDAY}
+%D
+%D The first one is sort of redundant. It takes the day
+%D number argument.
+%D
+%D \showsetup{weekday}
+%D \showsetup{WEEKDAY}
+
+\def\weekday
+ {\doconvertday}
+
+\def\WEEKDAY#1%
+ {{\let\labeltext\LABELTEXT\doconvertday{#1}}}
+
+%D \macros
+%D {weekoftheday}
+%D
+%D {\em not yet implemented:}
+%D
+%D \starttyping
+%D \def\weekoftheday#1#2#3%
+%D {}
+%D \stoptyping
+
+%D \macros
+%D {doifleapyearelse,
+%D getdayspermonth}
+%D
+%D Sometimes we need to know if we're dealing with a
+%D leapyear, so here is a testmacro:
+%D
+%D \starttyping
+%D \doifleapyearelse{year}{yes}{no}
+%D \stoptyping
+%D
+%D An example of its use can be seen in the macro
+%D
+%D \starttyping
+%D \getdayspermonth{year}{month}
+%D \stoptyping
+%D
+%D The number of days is available in the macro \type
+%D {\numberofdays}.
+
+\def\doifleapyearelse#1%
+ {\ifcase\ctxlua{converters.leapyear(\number#1)}
+ \@EA\secondoftwoarguments
+ \else
+ \@EA\firstoftwoarguments
+ \fi}
+
+\def\getdayspermonth#1#2%
+ {\edef\numberofdays{\ctxlua{converters.nofdays(\number#1,\number#2)}}}
+
+\def\dayspermonth#1#2%
+ {\ctxlua{converters.nofdays(\number#1,\number#2)}}
+
+% problem is that we calculate with those numbers
+%
+% \def\time {\numexpr\ctxlua{converters.textime()}\relax}
+% \def\year {\numexpr\ctxlua{converters.year ()}\relax}
+% \def\month{\numexpr\ctxlua{converters.month ()}\relax}
+% \def\day {\numexpr\ctxlua{converters.day ()}\relax}
+
+% \dayoftheweek{2006}{9}{15}
+% \doifleapyearelse{2000}{OK}{NOT OK}
+% \doifleapyearelse{2100}{NOT OK}{OK}
+% \doifleapyearelse{2004}{OK}{NOT OK}
+% \doifleapyearelse{2003}{NOT OK}{OK}
+% \dayspermonth{2000}{2}
+% [\the\normaltime=\the\time]
+
+%D \macros
+%D {currentdate, date}
+%D
+%D We use these conversion macros in the date formatting
+%D macro:
+%D
+%D \showsetup{currentdate}
+%D
+%D This macro takes care of proper spacing and delivers for
+%D instance:
+%D
+%D \startbuffer
+%D \currentdate[weekday,day,month,year] % still dutch example
+%D \currentdate[WEEKDAY,day,MONTH,year] % still dutch example
+%D \stopbuffer
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D depending of course on the keywords. Here we gave:
+%D
+%D \typebuffer
+%D
+%D If needed one can also add non||keywords, like in
+%D
+%D \startbuffer
+%D \currentdate[dd,--,mm,--,yy]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or typeset: \getbuffer.
+%D
+%D When no argument is passed, the current date is given as
+%D specified per language (using \type{\installlanguage}).
+%D
+%D \showsetup{currentdate}
+%D
+%D \startbuffer
+%D \date
+%D \date[d=12,m=12,y=1998][weekday]
+%D \date[d=12,m=12,y=1998]
+%D \stopbuffer
+%D
+%D We can also typeset arbitrary dates, using the previous
+%D command.
+%D
+%D \typebuffer
+%D
+%D The date is specified by one character keys. When no date
+%D is given, we get the current date.
+%D
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+\def\kenmerkdatumpatroon{j,mm,dd} % jj,mm,dd changed at januari 1-1-2000
+
+\newsignal\datesignal
+
+\def\dobetweendates
+ {\ifdim\lastskip=\datesignal\relax\else
+ \unskip\space
+ \hskip\datesignal\relax
+ \fi}
+
+\newtoks \everycurrentdate
+
+\def\complexcurrentdate[#1]%
+ {\bgroup
+ \the\everycurrentdate
+ \def\betweendates{\let\betweendates\dobetweendates}%
+ % was \processcommacommandp[#1]\docomplexcurrentdate
+ \safeedef\ascii{\empty#1}% keep encoded chars
+ \@EA\processcommalist\@EA[\ascii]\docomplexcurrentdate
+ \ifdim\lastskip=\datesignal\relax
+ \unskip
+ \fi
+ \egroup}
+
+\def\docomplexcurrentdate#1%
+ {\lowercase{\edef\!!stringa{#1}}% permits usage in \smallcapped
+ \expanded{\processaction[\!!stringa]}% [#1]
+ [ \v!day=>\betweendates\the\normalday,
+ %\v!day+=>\betweendates\ordinaldaynumber\normalday,
+ \v!day+=>\betweendates\convertnumber{\v!day+}\normalday,
+ \v!month=>\betweendates\month\normalmonth,
+ \v!year=>\betweendates\the\normalyear,
+ \v!space=>\unskip\ \hskip\datesignal,% optimization -)
+ \ =>\unskip\ \hskip\datesignal,% optimization -)
+ d=>\convertnumber\v!day\normalday,
+ %d+=>\ordinaldaynumber\normalday,
+ d+=>\convertnumber{\v!day+}\normalday,
+ m=>\convertnumber\v!month\normalmonth,
+ j=>\convertnumber\v!year\normalyear,
+ y=>\convertnumber\v!year\normalyear,
+ w=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
+ dd=>\ifnum\normalday >9 \else0\fi\the\normalday,
+ %dd+=>\ordinaldaynumber{\ifnum\normalday >9 \else0\fi\the\normalday},
+ dd+=>\convertnumber{\v!day+}{\ifnum\normalday >9 \else0\fi\the\normalday},
+ mm=>\ifnum\normalmonth>9 \else0\fi\the\normalmonth,
+ jj=>\expandafter\gobbletwoarguments\the\normalyear,
+ yy=>\expandafter\gobbletwoarguments\the\normalyear,
+ \v!weekday=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
+ \v!referral=>\expanded{\complexcurrentdate[\kenmerkdatumpatroon]},
+ \s!unknown=>\unskip
+ % #1 and not the lowercased \commalistelement, vietnamese has text
+ % {} because #1 can have comma, like: {\ ,}
+ {#1}%
+ \hskip\datesignal
+ \def\betweendates{\let\betweendates\dobetweendates}]}
+
+\def\simplecurrentdate
+ {\expanded{\complexcurrentdate[\currentdatespecification]}}
+
+\definecomplexorsimple\currentdate
+
+\def\dodate[#1][#2]%
+ {\bgroup
+ \iffirstargument
+ \getparameters[\??da][d=\normalday,m=\normalmonth,y=\normalyear,#1]%
+ \normalday \@@dad\relax
+ \normalmonth\@@dam\relax
+ \normalyear \@@day\relax
+ \ifsecondargument
+ \currentdate[#2]%
+ \else
+ \currentdate
+ \fi
+ \else
+ \currentdate
+ \fi
+ \egroup}
+
+\def\date
+ {\dodoubleempty\dodate}
+
+%D \macros
+%D {currenttime}
+%D
+%D The currenttime is actually the jobtime. You can specify
+%D a pattern similar to the previous date macro using the
+%D keys \type {h}, \type {m} and a separator.
+
+\def\calculatecurrenttime
+ {\edef\currenthour {\ctxlua{converters.hour ()}}%
+ \edef\currentminute{\ctxlua{converters.minute()}}%
+ \edef\currentsecond{\ctxlua{converters.second()}}}
+
+\let\currenthour \!!plusone
+\let\currentminute\!!plusone
+
+\def\currenttimespecification{h,:,m}
+
+\def\complexcurrenttime[#1]%
+ {\calculatecurrenttime
+ \processallactionsinset[#1]
+ [h=>\currenthour,m=>\currentminute,\s!unknown=>\commalistelement]}
+
+\def\simplecurrenttime
+ {\expanded{\complexcurrenttime[\currenttimespecification]}}
+
+\definecomplexorsimple\currenttime
+
+%D Because we're dealing with dates, we also introduce a few
+%D day loops:
+%D
+%D \starttyping
+%D \processmonth{year}{month}{command}
+%D \processyear{year}{command}{before}{after}
+%D \stoptyping
+%D
+%D The counters \type {\normalyear}, \type {\normalmonth} and
+%D \type{\normalday} can be used for for date manipulations.
+
+\long\def\processmonth#1#2#3% year month command
+ {\bgroup
+ \getdayspermonth{#1}{#2}%
+ \dostepwiserecurse1\numberofdays1%
+ {\normalyear #1\relax
+ \normalmonth#2\relax
+ \normalday \recurselevel\relax
+ #3}%
+ \egroup}
+
+\def\lastmonth{12} % can be set to e.g. 1 when testing
+
+\long\def\processyear#1#2#3#4% year command before after
+ {\bgroup
+ \dorecurse\lastmonth
+ {\normalyear #1\relax
+ \normalmonth\recurselevel\relax
+ #3\processmonth\normalyear\normalmonth{#2}#4}%
+ \egroup}
+
+%D \macros
+%D {defineconversion, convertnumber}
+%D
+%D Conversion involves the macros that we implemented earlier
+%D in this module.
+%D
+%D \showsetup{defineconversion}
+%D \showsetup{convertnumber}
+%D
+%D We can feed this command with conversion macros as well as
+%D a set of conversion symbols. Both need a bit different
+%D treatment.
+%D
+%D \starttyping
+%D \defineconversion [roman] [\romannumerals]
+%D \defineconversion [set 1] [$\star$,$\bullet$,$\ast$]
+%D \stoptyping
+%D
+%D You can define a language dependent conversion with:
+%D
+%D \starttyping
+%D \defineconversion [en] [whatever] [\something]
+%D \stoptyping
+
+% \def\dodefineconversion[#1][#2]%
+% {\ConvertConstantAfter\doifinstringelse{,}{#2}
+% {\scratchcounter=0
+% \def\docommand##1%
+% {\advance\scratchcounter 1
+% \setvalue{\??cv#1\the\scratchcounter}{##1}}%
+% \processcommalist[#2]\docommand
+% \setvalue{\??cv#1}##1{\csname\??cv#1##1\endcsname}}
+% {\setvalue{\??cv#1}{#2}}}
+%
+% \unexpanded\def\defineconversion%
+% {\dodoubleargument\dodefineconversion}
+
+\unexpanded\def\defineconversion
+ {\dotripleempty\dodefineconversion}
+
+\def\dodefineconversion[#1][#2][#3]%
+ {\ifthirdargument
+ \dododefineconversion[#1][#2][#3]%
+ \else
+ \dododefineconversion[][#1][#2]%
+ \fi}
+
+%D \starttyping
+%D \def\dododefineconversion[#1][#2][#3]%
+%D {\ConvertConstantAfter\doifinstringelse{,}{#3}
+%D {\scratchcounter\zerocount
+%D \def\docommand##1%
+%D {\advance\scratchcounter \plusone
+%D \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
+%D \processcommalist[#3]\docommand
+%D \setvalue{\??cv#1#2}##1{\executeifdefined{\??cv#1#2##1}\unknown}} % catch out-of-range numbers
+%D {\setvalue{\??cv#1#2}{#3}}}
+%D \stoptyping
+
+%D This approach has the disadvantage that when you run out of
+%D symbols you get unknown results. The following implementation
+%D permits overloading of the converter:
+
+\def\dododefineconversion[#1][#2][#3]%
+ {\ConvertConstantAfter\doifinstringelse{,}{#3}
+ {\scratchcounter\zerocount
+ \def\docommand##1%
+ {\advance\scratchcounter \plusone
+ \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
+ \processcommalist[#3]\docommand
+ \setevalue{\??cv#1#2}##1%
+ {\noexpand\docheckedconversion{#1#2}{\the\scratchcounter}{##1}}}
+ {\setvalue{\??cv#1#2}{#3}}}
+
+\def\docheckedconversion#1#2#3% class maxnumber number
+ {\executeifdefined{\??cv#1#3}\unknown}
+
+%D When Gerben reported problems with footnote numbering per page,
+%D Taco came with the following wrap around solution. So, let's
+%D overload the checked conversion macro:
+
+\def\docheckedconversion#1#2#3% class maxnumber number
+ {\executeifdefined{\??cv#1\modulatednumber{#2}{#3}}\unknown}
+
+%D Taco's modulo code is implemented in the system module
+%D \type {syst-con}.
+
+%D If a conversion is just a font switch then we need to make sure
+%D that the number is indeed end up as number in the input, so we
+%D need to handle the second argument.
+
+\def\convertnumber#1#2%
+ {\csname\??cv
+ \ifcsname\??cv\currentlanguage#1\endcsname
+ \currentlanguage#1%
+ \else\ifcsname\??cv#1\endcsname
+ #1%
+ \else
+ \s!default
+ \fi\fi
+ \endcsname{\number#2}}
+
+\def\doifconversiondefinedelse#1%
+ {\ifcsname\??cv\currentlanguage#1\endcsname
+ \@EA\firstoftwoarguments
+ \else\ifcsname\??cv#1\endcsname
+ \@EAEAEA\firstoftwoarguments
+ \else
+ \@EAEAEA\secondoftwoarguments
+ \fi\fi}
+
+\def\doifelseconversionnumber#1#2% slow but seldom used
+ {\doifdefinedelse{\??cv#1#2}}
+
+%D Handy.
+
+\setvalue{\??cv:\c!n:\v!one }{1}
+\setvalue{\??cv:\c!n:\v!two }{2}
+\setvalue{\??cv:\c!n:\v!three}{3}
+\setvalue{\??cv:\c!n:\v!four }{4}
+\setvalue{\??cv:\c!n:\v!five }{5}
+
+\def\wordtonumber#1#2{\ifcsname\??cv:\c!n:#1\endcsname\csname\??cv:\c!n:#1\endcsname\else#2\fi}
+
+% \defineconversion[ctx][c,o,n,t,e,x,t]
+%
+% \doloop{\doifelseconversionnumber{ctx}{\recurselevel}{[\recurselevel]}{\exitloop}}
+
+%D \macros
+%D {ordinaldaynumber, highordinalstr, ordinalstr}
+%D
+%D Efficient general ordinal number converters are sometimes
+%D difficult to implement. Fortunately dates never exceed the
+%D number~31.
+
+\ifx\high \undefined \let\high \firstofoneargument \fi
+\ifx\notsmallcapped\undefined \let\notsmallcapped\firstofoneargument \fi
+
+\def\highordinalstr#1{\high{\notsmallcapped{#1}}}
+\def\ordinalstr #1{\notsmallcapped{#1}}
+
+\def\ordinaldaynumber#1% \strippedcsname\ordinaldaynumber
+ {\expanded{\executeifdefined{\currentlanguage ordinaldaynumber}\noexpand\firstofoneargument{\number#1}}}
+
+%D As longs as symbols are linked to levels or numbers, we can
+%D also use the conversion mechanism, but in for instance the
+%D itemization macros, we prefer symbols because they can more
+%D easier be (partially) redefined. Symbols are implemented
+%D in another module.
+
+\def\smallcappedromannumerals#1{\smallcapped{\romannumerals{#1}}}
+\def\smallcappedcharacters #1{\smallcapped{\characters {#1}}}
+
+\defineconversion [] [\numbers] % the default conversion
+\defineconversion [\v!empty] [\gobbleoneargument]
+\defineconversion [\v!none] [\numbers]
+\defineconversion [\s!default] [\numbers]
+
+\defineconversion [month] [\doconvertmonthlong]
+\defineconversion [month:mnem] [\doconvertmonthshort]
+
+\defineconversion [\v!character] [\character]
+\defineconversion [\v!Character] [\Character]
+
+\defineconversion [\v!characters] [\characters]
+\defineconversion [\v!Characters] [\Characters]
+
+\defineconversion [a] [\characters]
+\defineconversion [A] [\Characters]
+\defineconversion [AK] [\smallcappedcharacters]
+\defineconversion [KA] [\smallcappedcharacters]
+
+\defineconversion [\v!numbers] [\numbers]
+\defineconversion [\v!Numbers] [\Numbers]
+\defineconversion [\v!mediaeval] [\mediaeval]
+
+\defineconversion [n] [\numbers]
+\defineconversion [N] [\Numbers]
+\defineconversion [m] [\mediaeval]
+\defineconversion [o] [\oldstylenumerals]
+\defineconversion [O] [\oldstylenumerals]
+\defineconversion [or] [\oldstyleromannumerals]
+
+\defineconversion [\v!romannumerals] [\romannumerals]
+\defineconversion [\v!Romannumerals] [\Romannumerals]
+
+\defineconversion [i] [\romannumerals]
+\defineconversion [I] [\Romannumerals]
+\defineconversion [r] [\romannumerals]
+\defineconversion [R] [\Romannumerals]
+
+\defineconversion [KR] [\smallcappedromannumerals]
+\defineconversion [RK] [\smallcappedromannumerals]
+
+\defineconversion [\v!greek] [\greeknumerals]
+\defineconversion [\v!Greek] [\Greeknumerals]
+
+\defineconversion [g] [\greeknumerals]
+\defineconversion [G] [\Greeknumerals]
+
+\defineconversion [arabicnumerals] [\arabicnumerals]
+\defineconversion [persiannumerals] [\persiannumerals]
+
+\defineconversion [abjadnumerals] [\abjadnumerals]
+\defineconversion [abjadnodotnumerals] [\adjadnodotnumerals]
+\defineconversion [abjadnaivenumerals] [\adjadnaivenumerals]
+
+\defineconversion [thainumerals] [\thainumerals]
+\defineconversion [devanagarinumerals] [\devanagarinumerals]
+\defineconversion [gurmurkhinumerals] [\gurmurkhinumerals]
+\defineconversion [gujaratinumerals] [\gujaratinumerals]
+\defineconversion [tibetannumerals] [\tibetannumerals]
+\defineconversion [greeknumerals] [\greeknumerals]
+\defineconversion [Greeknumerals] [\Greeknumerals]
+\defineconversion [arabicnumerals] [\arabicnumerals]
+\defineconversion [persiannumerals] [\persiannumerals]
+\defineconversion [arabicexnumerals] [\arabicexnumerals]
+
+
+\defineconversion [koreannumerals] [\koreannumerals]
+\defineconversion [koreanparentnumerals] [\koreanparentnumerals]
+\defineconversion [koreancirclenumerals] [\koreancirclenumerals]
+
+\defineconversion [kr] [\koreannumerals]
+\defineconversion [kr-p] [\koreanparentnumerals]
+\defineconversion [kr-c] [\koreancirclenumerals]
+
+\defineconversion [chinesenumerals] [\chinesenumerals]
+\defineconversion [chinesecapnumeralscn] [\chinesecapnumerals]
+\defineconversion [chineseallnumeralscn] [\chineseallnumerals]
+
+\defineconversion [cn] [\chinesenumerals]
+\defineconversion [cn-c] [\chinesecapnumerals]
+\defineconversion [cn-a] [\chineseallnumerals]
+
+%D Symbol sets:
+
+\ifx\symbol\undefined \def\symbol[#1]{#1} \fi % todo
+
+\defineconversion
+ [set 0]
+ [{\symbol[bullet]},
+ {\symbol[dash]},
+ {\symbol[star]},
+ {\symbol[triangle]},
+ {\symbol[circle]},
+ {\symbol[medcircle]},
+ {\symbol[bigcircle]},
+ {\symbol[square]}]
+
+\defineconversion
+ [set 1]
+ [\mathematics{\star},
+ \mathematics{\star\star},
+ \mathematics{\star\star\star},
+ \mathematics{\ddagger},
+ \mathematics{\ddagger\ddagger},
+ \mathematics{\ddagger\ddagger\ddagger},
+ \mathematics{\ast},
+ \mathematics{\ast\ast},
+ \mathematics{\ast\ast\ast}]
+
+\defineconversion
+ [set 2]
+ [\mathematics{*},
+ \mathematics{\dag},
+ \mathematics{\ddag},
+ \mathematics{**},
+ \mathematics{\dag\dag},
+ \mathematics{\ddag\ddag},
+ \mathematics{***},
+ \mathematics{\dag\dag\dag},
+ \mathematics{\ddag\ddag\ddag},
+ \mathematics{****},
+ \mathematics{\dag\dag\dag\dag},
+ \mathematics{\ddag\ddag\ddag\ddag}]
+
+\defineconversion
+ [set 3]
+ [\mathematics{\star},
+ \mathematics{\star\star},
+ \mathematics{\star\star\star},
+ \mathematics{\ddagger},
+ \mathematics{\ddagger\ddagger},
+ \mathematics{\ddagger\ddagger\ddagger},
+ \mathematics{\P},
+ \mathematics{\P\P},
+ \mathematics{\P\P\P},
+ \mathematics{\S},
+ \mathematics{\S\S},
+ \mathematics{\S\S\S},
+ \mathematics{\ast},
+ \mathematics{\ast\ast},
+ \mathematics{\ast\ast\ast}]
+
+\protect \endinput
diff --git a/tex/context/base/core-ctx.lua b/tex/context/base/core-ctx.lua
new file mode 100644
index 000000000..1dad7c2d7
--- /dev/null
+++ b/tex/context/base/core-ctx.lua
@@ -0,0 +1,93 @@
+if not modules then modules = { } end modules ['core-ctx'] = {
+ version = 1.001,
+ comment = "companion to core-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local trace_prepfiles = false trackers.register("resolvers.prepfiles", function(v) trace_prepfiles = v end)
+
+commands = commands or { }
+
+local list, suffix, islocal, found = { }, "prep", false, false
+
+function commands.loadctxpreplist()
+ local ctlname = file.replacesuffix(tex.jobname,"ctl")
+ if lfs.isfile(ctlname) then
+ local x = xml.load(ctlname)
+ if x then
+ islocal = xml.found(x,"ctx:preplist[@local=='yes']")
+--~ if trace_prepfiles then
+ if islocal then
+ commands.writestatus("systems","loading ctx log file (local)") -- todo: m!systems
+ else
+ commands.writestatus("systems","loading ctx log file (specified)") -- todo: m!systems
+ end
+--~ end
+ for e in xml.collected(x,"ctx:prepfile") do
+ local name = xml.text(e)
+ if islocal then
+ name = file.basename(name)
+ end
+ local done = e.at['done'] or 'no'
+ if trace_prepfiles then
+ commands.writestatus("systems","registering %s -> %s",done)
+ end
+ found = true
+ list[name] = done -- 'yes' or 'no'
+ end
+ end
+ end
+end
+
+-- -- --
+
+local function found(name) -- used in resolve
+ local prepname = name .. "." .. suffix
+ if list[name] and lfs.isfile(prepname) then
+ if trace_prepfiles then
+ commands.writestatus("systems", "preprocessing: using %s",prepname)
+ end
+ return prepname
+ end
+ return false
+end
+
+local function resolve(name) -- used a few times later on
+ local filename = file.collapse_path(name)
+ local prepname = islocal and found(file.basename(name))
+ if prepname then
+ return prepname
+ end
+ prepname = found(filename)
+ if prepname then
+ return prepname
+ end
+ return false
+end
+
+--~ support.doiffileexistelse(name)
+
+local processfile = commands.processfile
+local doifinputfileelse = commands.doifinputfileelse
+
+function commands.processfile(name,maxreadlevel) -- overloaded
+ local prepname = resolve(name)
+ if prepname then
+ return processfile(prepname,0)
+ end
+ return processfile(name,maxreadlevel)
+end
+
+function commands.doifinputfileelse(name,depth)
+ local prepname = resolve(name)
+ if prepname then
+ return doifinputfileelse(prepname,0)
+ end
+ return doifinputfileelse(name,depth)
+end
+
+function commands.preparedfile(name)
+ return resolve(name) or name
+end
diff --git a/tex/context/base/core-ctx.mkii b/tex/context/base/core-ctx.mkii
new file mode 100644
index 000000000..93cf8b4be
--- /dev/null
+++ b/tex/context/base/core-ctx.mkii
@@ -0,0 +1,203 @@
+%D \module
+%D [ file=core-ctx,
+%D version=2006.08.16, % old stuff
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Job Control,
+%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 Core Macros / Job Control}
+
+\unprotect
+
+\chardef\preprocessmethod 2 % 0=no check 1=present_check 2=log_check
+\chardef\preprocessstate 0 % 1=found 2=not_present (skip)
+\chardef\preprocesslocal 0 % 0=no 1=yes
+\def \preprocesssuffix {.prep}
+
+\def\loadctxpreplist
+ {\begingroup
+ \chardef\XMLtokensreduction\plusone
+ \ifcase\preprocessmethod
+ % no checking
+ \or
+ % simple checking
+ \or
+ \doiffileexistselse{./\jobname.ctl}
+ {\bgroup
+ \defineXMLenvironment[ctx:preplist][local=no]
+ {\doifelse{\XMLop{local}}{yes}
+ {\global\chardef\preprocesslocal\plusone
+ \writestatus\m!systems{loading ctx log file (local)}}%
+ {\writestatus\m!systems{loading ctx log file (specified)}}}
+ \donothing
+ \defineXMLenvironmentsave[ctx:prepfile][done=no]
+ \donothing
+ {\edef\readfilename{\XMLflush{ctx:prepfile}}%
+ \ifcase\preprocesslocal\else
+ \splitfilename\readfilename
+ \let\readfilename\splitoffbase
+ \fi
+ \writestatus\m!systems{registering \readfilename\space -> \XMLop{done}}%
+ \setxvalue{fp..\readfilename}{\XMLop{done}}}%
+ \processXMLfile{./\jobname.ctl}%
+ \egroup}%
+ {\global\chardef\preprocessmode\plusone}%
+ \fi
+ \global\let\loadctxpreplist\relax
+ \endgroup}
+
+\appendtoks\loadctxpreplist\to\everystarttext % will become: \prependtoks\loadctxpreplist\to\everyjob
+
+\def\docheckprepfile
+ {\ifcase\preprocessmethod
+ \iftracefiles\writestatus\m!systems{preprocessing - not needed}\fi
+ % no preprocessing
+ \or
+ % only check for existence
+ \iftracefiles\writestatus\m!systems{preprocessing - check existence of \readfilename\preprocesssuffix}\fi
+ \doiffileexistselse{\readfilename\preprocesssuffix}
+ {\chardef\preprocessstate\plusone}
+ \donothing
+ \or
+ % check when in list, otherwise assume normal file
+ \bgroup
+ \splitfilename\readfilename
+ \ifx\splitofftype\empty
+ % saveguard and speed up
+ \iftracefiles\writestatus\m!systems{preprocessing - no suffix}\fi
+ \egroup
+ \else\ifcase\preprocesslocal
+ % also ./ strippen
+ \iftracefiles\writestatus\m!systems{preprocessing - check presence of \readfilename\preprocesssuffix}\fi
+ \doifdefinedelse{fp..\readfilename}
+ {\egroup
+ \doiffileexistselse{\readfilename\preprocesssuffix}
+ {\chardef\preprocessstate\plusone}
+ {\chardef\preprocessstate\plustwo}}%
+ {\doifdefinedelse{fp.../\readfilename}
+ {\egroup
+ \edef\readfilename{./\readfilename}%
+ \doiffileexistselse{\readfilename\preprocesssuffix}
+ {\chardef\preprocessstate\plusone}
+ {\chardef\preprocessstate\plustwo}}%
+ {\doifdefinedelse{fp..\splitoffbase}%
+ {\egroup
+ \doiffileexistselse{\readfilename\preprocesssuffix}
+ {\chardef\preprocessstate\plusone}
+ {\chardef\preprocessstate\plustwo}}%
+ {\egroup}}}%
+ \else
+ % maybe just filecheck, why ctl
+ \iftracefiles\writestatus\m!systems{preprocessing - check local presence of \readfilename\preprocesssuffix}\fi
+ \doifdefinedelse{fp..\readfilename}
+ {\egroup
+ \doiffileexistselse{\readfilename\preprocesssuffix}
+ {\chardef\preprocessstate\plusone}
+ {\chardef\preprocessstate\plustwo}}%
+ {\egroup}%
+ \fi
+ \fi\fi}
+
+% beware, \readfilename keeps the original one, but we load and store the
+% suffixed with .prep file (if present)
+
+\def\doreadfile#1#2#3#4% beware, this one already works at format generation time!
+ {\sanitizefilename#2\to\readfilename
+ \ifx\readfilename\empty
+ % silently ignore
+ \else
+ \let\trackedfilename\readfilename
+ \chardef\preprocessstate\zerocount
+ \ifconditional\trackfilenames
+ \doifundefinedelse{fn..\trackedfilename}\donetrue\donefalse
+ \else
+ \donetrue
+ \fi
+ \ifdone
+ \checkfilename\readfilename
+ \ifcase\kindoffile
+ % not a full path or url, check for existence
+ \doifelsenothing{#1}
+ {\iftracefiles\writestatus\m!systems{searching for \readfilename\space on tex path}\fi
+ \def\next{\redoreadfile\readfilename{#3}{#4}}}%
+ {\iftracefiles\writestatus\m!systems{searching for \readfilename\space on #1}\fi
+ \def\next{\redoreadfile{\pathplusfile{#1}{\readfilename}}{#3}{#4}}}%
+ \else
+ % a full path or url, no further checking done
+ \docheckprepfile
+ \ifcase\preprocessstate
+ \doiffileexistselse\readfilename
+ {\iftracefiles\writestatus\m!systems{located \readfilename}\fi
+ \def\next{#3\dodoreadfile}}%
+ {\iftracefiles\writestatus\m!systems{not found \readfilename}\fi
+ \def\next{#4}}%
+ \or
+ \iftracefiles\writestatus\m!systems{located \readfilename\preprocesssuffix}\fi
+ \def\next{#3\dodoreadfile}%
+ \or
+ \iftracefiles\writestatus\m!systems{not found \readfilename\preprocesssuffix}\fi
+ \def\next{#4}%
+ \fi
+ \fi
+ \else
+ \edef\readfilename{\getvalue{fn..\readfilename}}% ??? is done !
+ \iftracefiles\writestatus\m!systems{already located \readfilename}\fi
+ \def\next{#3\dodoreadfile}%
+ \fi
+ \expandafter\next
+ \fi}
+
+\def\redoreadfile#1#2#3%
+ {\docheckprepfile
+ \ifcase\preprocessstate
+ \doiffileexistselse{#1}%
+ {\edef\readfilename{#1}%
+ \iftracefiles\writestatus\m!systems{#1 located}\fi
+ \def\next{#2\dodoreadfile}}%
+ {\iftracefiles\writestatus\m!systems{cannot locate #1}\fi
+ \advance\readlevel\minusone
+ \ifnum\readlevel>\zerocount
+ \edef\readfilename{\pathplusfile{\f!parentpath}{\readfilename}}%
+ \def\next{\redoreadfile\readfilename{#2}{#3}}%
+ \else
+ \def\next{#3}%
+ \fi}%
+ \or
+ \ifcase\preprocesslocal
+ \edef\readfilename{#1}% nor found
+ \else
+ % no path prepending
+ \fi
+ \iftracefiles\writestatus\m!systems{#1\preprocesssuffix\space located}\fi
+ \def\next{#2\dodoreadfile}%
+ \or
+ \def\next{#3}%
+ \fi
+ \next}
+
+\def\dodoreadfile % we provide hooks, for instance for \enableXML
+ {\ifconditional\trackfilenames
+ \setxvalue{fn..\trackedfilename}{\readfilename\ifcase\preprocessstate\or\preprocesssuffix\fi}%
+ \fi
+ \the\everybeforereadfile
+ \ifcase\preprocessstate
+ % no checking or not found when using method 1
+ \def\dodoreadfileindeed{\inputgivenfile\readfilename}%
+ \or
+ % found when using method 1 or 2
+ \def\dodoreadfileindeed{\inputgivenfile{\readfilename\preprocesssuffix}}%
+ \or
+ % not found when using method 2
+ \let\dodoreadfileindeed\relax
+ \fi
+ \dodoreadfileindeed
+ \relax
+ \the\everyafterreadfile}
+
+\protect \endinput
diff --git a/tex/context/base/core-ctx.mkiv b/tex/context/base/core-ctx.mkiv
new file mode 100644
index 000000000..9bf456952
--- /dev/null
+++ b/tex/context/base/core-ctx.mkiv
@@ -0,0 +1,28 @@
+%D \module
+%D [ file=core-ctx,
+%D version=2006.08.16, % old stuff
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Job Control,
+%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 Core Macros / Job Control}
+
+\unprotect
+
+\chardef\preprocessmethod \plustwo % always check in mkiv
+
+\registerctxluafile{core-ctx}{1.000}
+
+\def\loadctxpreplist{\ctxlua{commands.loadctxpreplist()}\global\let\loadctxpreplist\relax}
+
+% \prependtoks\loadctxpreplist\to\everyjob
+
+\appendtoks\loadctxpreplist\to\everystarttext
+
+\protect \endinput
diff --git a/tex/context/base/core-def.mkii b/tex/context/base/core-def.mkii
new file mode 100644
index 000000000..840f853a7
--- /dev/null
+++ b/tex/context/base/core-def.mkii
@@ -0,0 +1,105 @@
+%D \module
+%D [ file=core-def,
+%D version=2002.05.07,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Defaults,
+%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 Core Macros / Defaults}
+
+%D Here we collect settings that cannot be done earlier due to
+%D depedencies. More code will moved to this module later.
+
+\unprotect
+
+\usesymbols[mis,mvs] % 'glm' no longer needed due to lm
+
+\usesymbols[nav] \setupsymbolset[navigation 1]
+
+\setupinteraction[\c!symbolset=navigation 1]
+
+% initialization order:
+
+%appendtoks \initializeluainstances \to \everyjob
+\appendtoks \showcontextbanner \to \everyjob
+\appendtoks \initializenewlinechar \to \everyjob
+\appendtoks \checksystemcommandmode \to \everyjob
+\appendtoks \calculatecurrenttime \to \everyjob
+\appendtoks \loadsystemfiles \to \everyjob
+
+\appendtoks \loadoptionfile \to \everyjob % can load files !
+
+\appendtoks \preloadfonts \to \everyjob
+\appendtoks \settopskip \to \everyjob
+\appendtoks \preloadlanguages \to \everyjob
+\appendtoks \preloadspecials \to \everyjob
+\appendtoks \openspecialfile \to \everyjob
+\appendtoks \openutilities \to \everyjob
+\appendtoks \splitjobfilename \to \everyjob
+\appendtoks \checknotes \to \everyjob % depends on bodyfont
+\appendtoks \initializeMPgraphics \to \everyjob % after loading system files
+\appendtoks \reportsystemcommandmode \to \everyjob
+\appendtoks \initializemainlanguage \to \everyjob
+\appendtoks \settrue\trackfilenames \to \everyjob
+\appendtoks \newbackgroundfalse \to \everyjob % global
+
+\ifdefined\initializepagecounters
+ \appendtoks \initializepagecounters \to \everyjob
+\fi
+
+\appendtoks \directsetup{*runtime:options} \to \everyjob % we could erase them afterwards % order can change
+\appendtoks \directsetup{*runtime:modules} \to \everyjob % we could erase them afterwards % order can change
+
+\appendtoks \checkpreprocessor \to \everyjob
+
+%appendtoks \page[\v!last] \page \to \everybye % moved to core-job, we need to do this cleaner
+\appendtoks \ifarrangingpages\poparrangedpages\fi \to \everybye
+\appendtoks \registerfileinfo[end]\jobname \to \everybye
+\appendtoks \savenofpages \to \everybye
+\appendtoks \savenofsubpages \to \everybye
+
+\appendtoks \closeutilities \to \everygoodbye
+\appendtoks \stopcopyingblocks \to \everygoodbye
+\appendtoks \closespecialfile \to \everygoodbye
+
+\prependtoks \resetutilities \to \everystarttext % moved 28-02-2002
+\prependtoks \loadtwopassdata \to \everystarttext % moved 28-02-2002
+\appendtoks \checkreferences \to \everystarttext % new 04-12-1999
+
+% \appendtoks\everyjob\expandafter{\the\everyjob\checkpreprocessor}\to\everydump
+
+% temporary here:
+
+% \in \at \about \from \over
+
+\unexpanded\def\arg{\mathortext\normalmatharg\normaltextarg}
+
+% brrr
+% normally one does not want this to happen nested, maybe there
+% is more; non public vars btw, will become conditionals
+
+\ifx\writetoregisterfalse\undefined \else \appendtoks \writetoregisterfalse \to \everybeforeutilityread \fi
+\ifx\writetolistfalse \undefined \else \appendtoks \writetolistfalse \to \everybeforeutilityread \fi
+\ifx\notesenabledfalse \undefined \else \appendtoks \notesenabledfalse \to \everybeforeutilityread \fi
+
+\def\synctexwarning
+ {\ifdefined\synctex \ifnum\synctex=\zerocount \else
+ \writeline
+ \writestatus\m!systems{BEWARE: syntex functionality is enabled!}%
+ \writeline
+ \globallet\synctexwarning\relax
+ \fi \fi}
+
+\prependtoks \synctexwarning \to \everyjob
+\prependtoks \synctexwarning \to \everystarttext
+\appendtoks \synctexwarning \to \everystoptext
+
+% last minute hacks
+
+\protect \endinput
diff --git a/tex/context/base/core-def.mkiv b/tex/context/base/core-def.mkiv
new file mode 100644
index 000000000..59451a914
--- /dev/null
+++ b/tex/context/base/core-def.mkiv
@@ -0,0 +1,94 @@
+%D \module
+%D [ file=core-def,
+%D version=2002.05.07,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Defaults,
+%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 Core Macros / Defaults}
+
+%D Here we collect settings that cannot be done earlier due to
+%D depedencies. More code will moved to this module later.
+
+\unprotect
+
+\usesymbols[mis,mvs,nav]
+
+\setupsymbolset[navigation 1]
+
+\setupinteraction[\c!symbolset=navigation 1]
+
+% initialization order:
+
+\appendtoks \showcontextbanner \to \everyjob
+\appendtoks \initializenewlinechar \to \everyjob
+\appendtoks \calculatecurrenttime \to \everyjob
+\appendtoks \loadsystemfiles \to \everyjob
+\appendtoks \loadoptionfile \to \everyjob % can load files !
+\appendtoks \preloadfonts \to \everyjob
+\appendtoks \settopskip \to \everyjob
+\appendtoks \preloadlanguages \to \everyjob
+\appendtoks \preloadspecials \to \everyjob
+\appendtoks \initializeMPgraphics \to \everyjob % after loading system files
+\appendtoks \initializemainlanguage \to \everyjob
+%appendtoks \MPLIBregister \to \everyjob
+\appendtoks \xmlinitialize \to \everyjob
+\appendtoks \newbackgroundfalse \to \everyjob % global
+\appendtoks \initializepagecounters \to \everyjob
+\appendtoks \directsetup{*runtime:options} \to \everyjob % we could erase them afterwards % order can change
+\appendtoks \directsetup{*runtime:modules} \to \everyjob % we could erase them afterwards % order can change
+\appendtoks \checkpreprocessor \to \everyjob
+
+%appendtoks \page[\v!last] \page \to \everybye % moved to core-job, we need to do this cleaner
+\appendtoks \ifarrangingpages\poparrangedpages\fi \to \everybye
+%appendtoks \registerfileinfo[end]\jobfilename \to \everybye
+
+%appendtoks \MPLIBallocate{1000} \to \everydump
+
+\prependtoks \resetallattributes \to \everybeforeoutput
+
+\appendtoks \the\everybackendshipout \to \everyshipout
+\prependtoks \the\everylastbackendshipout \to \everylastshipout
+
+\prependtoks \lefttoright \to \everybeforeoutput
+
+% temporary here:
+
+\ifdefined\in \let\normalmathin \in \unexpanded\def\in {\mathortext\normalmathin \dospecialin } \else \let\in \dospecialin \fi
+\ifdefined\at \let\normalmathat \at \unexpanded\def\at {\mathortext\normalmathat \dospecialat } \else \let\at \dospecialat \fi
+\ifdefined\about \let\normalmathabout\about \unexpanded\def\about{\mathortext\normalmathabout\dospecialabout} \else \let\about\dospecialabout \fi
+\ifdefined\from \let\normalmathfrom \from \unexpanded\def\from {\mathortext\normalmathfrom \dospecialfrom } \else \let\from \dospecialfrom \fi
+\ifdefined\over \let\normalmathover \over \unexpanded\def\over {\mathortext\normalmathover \dospecialabout} \else \let\over \dospecialabout \fi
+
+\unexpanded\def\arg{\mathortext\normalmatharg\normaltextarg}
+
+% brrr
+
+\appendtoks
+ \synchronizegloballinespecs
+ \synchronizelocallinespecs
+\to \everysetupbodyfont
+
+\appendtoks
+ \synchronizelocallinespecs
+\to \everyswitchtobodyfont
+
+\def\synctexwarning
+ {\ifdefined\synctex \ifnum\synctex=\zerocount \else
+ \writeline
+ \writestatus\m!systems{BEWARE: synctex functionality is enabled!}%
+ \writeline
+ \globallet\synctexwarning\relax
+ \fi \fi}
+
+\prependtoks \synctexwarning \to \everyjob
+\prependtoks \synctexwarning \to \everystarttext
+\appendtoks \synctexwarning \to \everystoptext
+
+\protect \endinput
diff --git a/tex/context/base/core-env.mkii b/tex/context/base/core-env.mkii
new file mode 100644
index 000000000..a22594b27
--- /dev/null
+++ b/tex/context/base/core-env.mkii
@@ -0,0 +1,543 @@
+%D \module
+%D [ file=core-env, % was core-new
+%D version=1995.01.01, % wrong
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=New ones,
+%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 Core Macros / Environments}
+
+\unprotect
+
+% Clean labels:
+
+\bgroup % some day this will go away / we could use detokenize as well
+
+% actually we should handle all discretionaries here
+
+\catcode`:=\@@active
+
+\gdef\cleanuplabel#1%
+ {\begingroup
+ \let:\lettercolon
+ \xdef\cleanlabel{#1}%
+ \endgroup}
+
+\gdef\cleanupprefixedlabel#1#2%
+ {\begingroup
+ \let:\lettercolon
+ \xdef\cleanprefix{#1}%
+ \xdef\cleanlabel {#2}%
+ \endgroup}
+
+\gdef\protectlabels
+ {\let:\lettercolon}
+
+\global\def\blabelgroup {\begingroup \let:\lettercolon}
+\global\let\elabelgroup \endgroup
+
+\gdef\labelcsname
+ {\begingroup\let:\lettercolon
+ \expandafter\endgroup\csname}
+
+\gdef\labelvalue#1%
+ {\labelcsname#1\endcsname}
+
+\egroup
+
+%D Modes:
+%D
+%D \starttyping
+%D \enablemode[screen,paper,bound]
+%D
+%D \doifmodeelse {paper} {this} {that}
+%D \doifmode {paper,screen} {this}
+%D \doifnotmode {paper,bound} {that}
+%D
+%D \startmode [list]
+%D \stopmode
+%D
+%D \startnotmode [list]
+%D \stopnotmode
+%D \stoptyping
+%D
+%D system modes have a * as prefix
+%D
+%D Sometimes, we want to prevent a mode for being set. Think
+%D of situations where a style enables a mode, but an outer
+%D level style does not want that. Preventing can be
+%D considered a permanent disabling on forehand.
+
+\def\@mode@{@md@}
+
+\def\systemmodeprefix{*}
+
+\def\disabledmode {0}
+\def\enabledmode {1}
+\def\preventedmode {2}
+
+% fast internal ones
+
+\def\setmode #1{\@EA\let\csname\@mode@#1\endcsname\enabledmode }
+\def\resetmode#1{\@EA\let\csname\@mode@#1\endcsname\disabledmode}
+
+\def\setsystemmode #1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\enabledmode }
+\def\resetsystemmode#1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\disabledmode}
+
+% user ones
+
+\def\preventmode{\unprotect\dopreventmode}
+\def\enablemode {\unprotect\doenablemode }
+\def\disablemode{\unprotect\dodisablemode}
+
+\def\dopreventmode[#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dodopreventmode}
+\def\doenablemode [#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dodoenablemode }
+\def\dodisablemode[#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dododisablemode}
+
+\def\dodopreventmode#1%
+ {\@EA\let\csname\@mode@#1\endcsname\preventedmode}
+
+\def\dodoenablemode#1% mode can be relax
+ {\ifcase0\csname\@mode@#1\endcsname\relax
+ \@EA\let\csname\@mode@#1\endcsname\enabledmode
+ \fi}
+
+\def\dododisablemode#1%
+ {\ifcase0\csname\@mode@#1\endcsname\or
+ \@EA\let\csname\@mode@#1\endcsname\disabledmode
+ \fi}
+
+% handy for mp
+
+\def\booleanmodevalue#1% can be \relax
+ {\expandafter\ifx\csname\@mode@#1\endcsname\relax
+ fals%
+ \else\ifnum0\csname\@mode@#1\endcsname=0
+ fals%
+ \else
+ tru%
+ \fi\fi e}
+
+% check macros
+
+\newif\ifcheckedmode
+
+\def\dodocheckformode#1%
+ {\ifcase0\csname\@mode@#1\endcsname\or\checkedmodetrue\fi}
+
+\def\docheckformode#1#2#3% will be sped up with a quit
+ {\cleanuplabel{#3}%
+ \protect\checkedmodefalse\rawprocesscommacommand[\cleanlabel]\dodocheckformode
+ \ifcheckedmode\@EA#1\else\@EA#2\fi}
+
+\def\dodocheckforallmodes#1%
+ {\ifcase0\csname\@mode@#1\endcsname\relax\checkedmodefalse\or\or\checkedmodefalse\fi}
+
+\def\docheckforallmodes#1#2#3% will be sped up with a quit
+ {\cleanuplabel{#3}%
+ \protect\checkedmodetrue\rawprocesscommacommand[\cleanlabel]\dodocheckforallmodes
+ \ifcheckedmode\@EA#1\else\@EA#2\fi}
+
+% simple ones
+
+\def\doifmodeelse{\unprotect\dodoifmodeelse}
+\def\doifmode {\unprotect\dodoifmode}
+\def\doifnotmode {\unprotect\dodoifnotmode}
+\def\startmode {\unprotect\dostartmode}
+\def\startnotmode{\unprotect\dostartnotmode}
+
+\def\dodoifmodeelse
+ {\docheckformode\firstoftwoarguments\secondoftwoarguments}
+
+\def\dodoifmode
+ {\docheckformode\firstofoneargument\gobbleoneargument}
+
+\def\dodoifnotmode
+ {\docheckformode\gobbleoneargument\firstofoneargument}
+
+\long\def\dostartmode[#1]%
+ {\docheckformode\donothing\dostopmode{#1}}
+
+\long\def\dostartnotmode[#1]%
+ {\docheckformode\dostopnotmode\donothing{#1}}
+
+\let\stopmode \donothing
+\let\stopnotmode\donothing
+
+\long\def\dostopmode #1\stopmode {}
+\long\def\dostopnotmode#1\stopnotmode{}
+
+\def\doifallmodeselse{\unprotect\dodoifallmodeselse}
+\def\doifallmodes {\unprotect\dodoifallmodes}
+\def\doifnotallmodes {\unprotect\dodoifnotallmodes}
+\def\startallmodes {\unprotect\dostartallmodes}
+\def\startnotallmodes{\unprotect\dostartnotallmodes}
+
+\def\dodoifallmodeselse
+ {\docheckforallmodes\firstoftwoarguments\secondoftwoarguments}
+
+\def\dodoifallmodes
+ {\docheckforallmodes\firstofoneargument\gobbleoneargument}
+
+\def\dodoifnotallmodes
+ {\docheckforallmodes\gobbleoneargument\firstofoneargument}
+
+\long\def\dostartallmodes[#1]%
+ {\docheckforallmodes\donothing\dostopallmodes{#1}}
+
+\long\def\dostartnotallmodes[#1]%
+ {\docheckforallmodes\dostopnotallmodes\donothing{#1}}
+
+\let\stopallmodes \donothing
+\let\stopnotallmodes\donothing
+
+\long\def\dostopallmodes #1\stopallmodes {}
+\long\def\dostopnotallmodes#1\stopnotallmodes{}
+
+% Setups
+
+\let\startsetups\relax % to please dep checker
+\let\stopsetups \relax % to please dep checker
+
+\expanded
+ {\long\def\@EA\noexpand\csname\e!start\v!setups\endcsname
+ {\begingroup\noexpand\doifnextoptionalelse
+ {\noexpand\startsetupsA\@EA\noexpand\csname\e!stop\v!setups\endcsname}
+ {\noexpand\startsetupsB\@EA\noexpand\csname\e!stop\v!setups\endcsname}}}
+
+\letvalue{\e!stop\v!setups}\relax
+
+\unexpanded \def\setups{\doifnextbgroupelse\dosetupsA\dosetupsB} % {..} or [..]
+\unexpanded \def\setup {\doifnextbgroupelse\dosetups \dosetupsC} % {..} or [..]
+
+\def\dosetupsA #1{\cleanuplabel{#1}\processcommacommand[\cleanlabel]\dosetups} % {..}
+\def\dosetupsB[#1]{\cleanuplabel{#1}\processcommacommand[\cleanlabel]\dosetups} % [..]
+\def\dosetupsC[#1]{\cleanuplabel{#1}\dosetups\cleanlabel} % [..]
+
+% \def\dosetups#1% the grid option will be extended to other main modes
+% {\executeifdefined{\??su\ifgridsnapping\v!grid\fi:#1}
+% {\executeifdefined{\??su :#1}\gobbleoneargument}\empty} % takes one argument
+%
+% \def\setupwithargument#1% the grid option will be extended to other main modes
+% {\executeifdefined{\??su:#1}\gobbleoneargument}
+
+% better:
+
+% \def\dosetups#1% the grid option will be extended to other main modes
+% {\executeifdefined{\??su\ifgridsnapping\v!grid\fi:#1}
+% {\executeifdefined{\??su :#1}\gobbleoneargument}\empty} % takes one argument
+%
+% \def\setupwithargument#1% the grid option will be extended to other main modes
+% {\executeifdefined{\??su:#1}\gobbleoneargument}
+
+% faster:
+
+\letvalue{\??su:\letterpercent}\gobbleoneargument
+
+\def\dosetups#1% the grid option will be extended to other main modes
+ {\csname\??su
+ \ifgridsnapping
+ \ifcsname\??su\v!grid:#1\endcsname\v!grid:#1\else\ifcsname\??su:#1\endcsname:#1\else:\letterpercent\fi\fi
+ \else
+ \ifcsname\??su:#1\endcsname:#1\else:\letterpercent\fi
+ \fi
+ \endcsname\empty} % takes one argument
+
+\def\setupwithargument#1% the grid option will be extended to other main modes
+ {\csname\??su:\ifcsname\??su:#1\endcsname#1\else\letterpercent\fi\endcsname}
+
+\let\directsetup\dosetups
+
+% somehow fails ...
+%
+% \letvalue{\??su:..}\gobbleoneargument
+%
+% \def\dosetups#1% the grid option will be extended to other main modes
+% {\csname \??su
+% \ifcsname\??su\ifgridsnapping\v!grid\fi:#1\endcsname\v!grid:#1\else
+% \ifcsname\??su :#1\endcsname :#1\else
+% :..\fi\fi
+% \endcsname\empty} % takes one argument
+%
+% \def\setupwithargument#1% the grid option will be extended to other main modes
+% {\csname\??su:\ifcsname\??su:#1\endcsname#1\else..\fi\endcsname}
+
+\let\directsetup\dosetups
+
+\def\doifsetupselse#1% to be done: grid
+ {\doifdefinedelse{\??su:#1}}
+
+\chardef\setupseolmode\plusone
+
+\def\startsetups {\xxstartsetups\plusone \stopsetups } \let\stopsetups \relax
+\def\startlocalsetups{\xxstartsetups\plusone \stoplocalsetups} \let\stoplocalsetups\relax
+\def\startrawsetups {\xxstartsetups\zerocount\stoprawsetups } \let\stoprawsetups \relax
+\def\startxmlsetups {\xxstartsetups\plustwo \stopxmlsetups } \let\stopxmlsetups \relax
+
+\def\xxstartsetups#1#2%
+ {\begingroup\chardef\setupseolmode#1\doifnextoptionalelse{\startsetupsA#2}{\startsetupsB#2}}
+
+\def\startsetupsA#1% [ ] delimited
+ {\ifcase\setupseolmode\or\catcode`\^^M\@@ignore\or\catcode`\^^M\@@ignore\catcode`\|\@@other\fi
+ \dotripleempty\dostartsetups[#1]}
+
+\def\startsetupsB#1#2 % space delimited
+ {\ifcase\setupseolmode\or\catcode`\^^M\@@ignore\or\catcode`\^^M\@@ignore\catcode`\|\@@other\fi
+ \dodostartsetups#1\empty{#2}}
+
+\def\startsetupsC[#1][#2][#3]{\dodostartsetups#1{#2}{#3}} % [..] [..]
+\def\startsetupsD[#1][#2][#3]{\dodostartsetups#1\empty{#2}} % [..]
+
+\def\dostartsetups
+ {\ifthirdargument\@EA\startsetupsC\else\@EA\startsetupsD\fi}
+
+% \long\def\dodostartsetups#1#2#3% watch out: not \grabuntil
+% {\dograbuntil#1{\endgroup\dodoglobal\long\setvalue{\??su#2:#3}}} % \doglobal
+%
+% better:
+
+% \long\def\dodostartsetups#1#2#3% watch out: not \grabuntil
+% {\cleanuplabel{\??su#2:#3}\dograbuntil#1{\endgroup\dodoglobal\long\setvalue\cleanlabel}} % \doglobal
+
+% \long\def\dodostartsetups#1#2#3%
+% {\cleanuplabel{\??su#2:#3}%
+% \long\def\dododostartsetups##1#1{\endgroup\dodoglobal\long\setvalue\cleanlabel####1{##1}}\dododostartsetups}
+
+\long\def\dodostartsetups#1#2#3%
+ {\cleanuplabel{\??su#2:#3}%
+ \long\def\dododostartsetups##1#1%
+ {\endgroup
+ \dodoglobal % bah
+ \long\expandafter\setvalue\expandafter\cleanlabel\expandafter####\expandafter1\expandafter{##1}}%
+ \dododostartsetups\empty} % the empty trick prevents the { } in {arg} from being eaten up
+
+\def\systemsetupsprefix{*}
+
+\def\systemsetups#1{\dosetups{\systemsetupsprefix#1}}
+
+\def\resetsetups[#1]% see x-fo for usage
+ {\ifundefined{\??su\ifgridsnapping\v!grid\fi:#1}%
+ \dodoglobal\letbeundefined{\??su:#1}%
+ \else
+ \dodoglobal\letbeundefined{\??su\ifgridsnapping\v!grid\fi:#1}%
+ \fi}
+
+% or
+%
+% \def\resetsetups[#1]%
+% {\letbeundefined
+% {\??su:%
+% \ifundefined{\??su\ifgridsnapping\v!grid\fi:#1}#1\else\ifgridsnapping\v!grid\fi%
+% #1}}
+
+%D new and beta and will become a module instead
+
+\def\defineshortcut
+ {\dotripleargument\dodefineshortcut}
+
+\def\dodefineshortcut[#1][#2][#3]%
+ {\ifthirdargument
+ \doifelsenothing{#1}
+ {\dododefineshortcut[<>][#2][#3]}
+ {\dododefineshortcut[#1][#2][#3]}%
+ \else\ifsecondargument
+ \dododefineshortcut[<>][#1][#2]%
+ \else
+ \dododefineshortcut[<>][][#1]%
+ \fi\fi}
+
+\def\dododefineshortcut[#1#2][#3][#4]% #1 is the trigger, #2 the delimiter/tag
+ {\doifundefined{\??te\??te\string#2}{\letvalue{\??te\??te\string#2}=#1}%
+ \defineactivecharacter #1 {\@EA\doshortcut\string#2} %
+ \getparameters
+ [\??te\string#2#3]
+ [\c!commands=,\c!command=,\c!style=,\c!color=,#4]}
+
+\def\doshortcut#1%
+ {\ifmmode
+ \getvalue{\??te\??te#1}%
+ \else
+ \bgroup
+ \catcode`#1=\@@other
+ \def\dodoshortcut##1#1%
+ {\def\shorttag{\??te#1}%
+ \def\shortcut{##1}%
+ \dododoshortcut##1:\end}%
+ \@EA\dodoshortcut
+ \fi}
+
+\def\dododoshortcut#1:#2\end
+ {\doifelsenothing{#2}
+ {\doifundefinedelse{\shorttag\c!commands}
+ {\shortcut}
+ {\@EA\dodododoshortcut\@EA\shorttag\@EA:\shortcut:\end}}
+ {\doifundefinedelse{\shorttag#1\c!commands}
+ {\shortcut}
+ {\dodododoshortcut\shorttag#1:#2\end}}%
+ \egroup}
+
+\def\dodododoshortcut#1:#2:\end
+ {\getvalue{#1\c!commands}%
+ \doattributes{#1}\c!style\c!color{\getvalue{#1\c!command}{#2}}}
+
+%D \defineshortcut [style=type]
+%D \defineshortcut [b] [style=bold]
+%D \defineshortcut [e] [style=\em]
+%D \defineshortcut [t] [style=type]
+%D \defineshortcut [c] [style=cap]
+%D \defineshortcut [k] [style=cap]
+%D \defineshortcut [u] [style=type,command=\hyphenatedurl]
+%D
+%D \startlines
+%D test test
+%D test test
+%D test test
+%D test test
+%D zus<>zo zus<:>zo zus<::>zo
+%D test test dat (ziezo)
+%D test test dat (:ziezo)
+%D test test dat (ziezo:)
+%D test test dat (zi:ezo:)
+%D well, looks fuzzy
+%D $10<20$
+%D \stoplines
+%D
+%D \defineshortcut [<>] [i] [style=\it]
+%D \defineshortcut [()] [b] [style=\bf]
+%D \defineshortcut [++] [s] [style=\sl]
+%D \defineshortcut [//] [u] [style=\underbars]
+%D \defineshortcut [--] [a] [style=\overstrike]
+%D
+%D \startlines
+%D it seems well
+%D it seems (b:to work) well
+%D it seems +s:to work+ well
+%D it seems /u:to work/ well
+%D it seems -a:to work- well
+%D \stoplines
+
+%D \macros
+%D {setvariables,getvariable,getvariabledefault}
+%D
+%D \starttyping
+%D \setvariables[xx][title=]
+%D \setvariables[xx][title=test test]
+%D \setvariables[xx][title=test $x=1$ test] % fatal error reported
+%D \setvariables[xx][title=test {$x=1$} test]
+%D \setvariables[xx][title] % fatal error reported
+%D \setvariables[xx][titletitel=e]
+%D \stoptyping
+
+\def\??vars{@@vars}
+
+\def\setvariables {\dotripleargument\dosetvariables[\getrawparameters ]}
+\def\setevariables{\dotripleargument\dosetvariables[\getraweparameters]}
+\def\setgvariables{\dotripleargument\dosetvariables[\getrawgparameters]}
+\def\setxvariables{\dotripleargument\dosetvariables[\getrawxparameters]}
+
+\def\globalsetvariables % obsolete
+ {\dotripleargument\dosetvariables[\globalgetrawparameters]}
+
+\long\def\dosetvariables[#1][#2][#3]% tricky, test on s-pre-60
+ {\errorisfataltrue
+ \doifelse{#2}\currentvariableclass
+ {#1[\??vars:#2:][#3]}%
+ {\pushmacro\currentvariableclass
+ \def\currentvariableclass{#2}%
+ \getvariable{#2}\s!reset
+ #1[\??vars:#2:][#3]%
+ \getvariable{#2}\s!set
+ \popmacro\currentvariableclass}%
+ \errorisfatalfalse}
+
+\long\def\setvariable #1#2#3{\long\setvalue {\??vars:#1:#2}{#3}}
+\long\def\setevariable#1#2#3{\long\setevalue{\??vars:#1:#2}{#3}}
+\long\def\setgvariable#1#2#3{\long\setgvalue{\??vars:#1:#2}{#3}}
+\long\def\setxvariable#1#2#3{\long\setxvalue{\??vars:#1:#2}{#3}}
+
+\def\getvariable#1#2% to be sped up
+ {\csname
+ \ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi
+ \endcsname}
+
+\def\showvariable#1#2%
+ {\showvalue{\ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi}}
+
+\let\currentvariableclass\empty
+
+%D \macros
+%D {doifelsevariable,doifvariable,doifnotvariable}
+%D
+%D A few trivial macros:
+
+\def\doifelsevariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifvariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\doifnotvariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\def\getvariabledefault#1#2% #3% can be command, so no ifcsname here
+ {\executeifdefined{\??vars:#1:#2}}% {#3}
+
+%D \macros
+%D {checkvariables}
+%D
+%D I'll probably forget that this on exists.
+
+\def\checkvariables
+ {\dodoubleargument\docheckvariables}
+
+\def\docheckvariables
+ {\dogetparameters\docheckrawvalue}
+
+\def\docheckrawvalue#1#2#3%
+ {\doifundefined {\??vars:#1:#2}{\setvalue{\??vars:#1:#2}{#3}}
+ {\doifvaluenothing{\??vars:#1:#2}{\setvalue{\??vars:#1:#2}{#3}}}}
+
+% \def\setupenv{\dodoubleargument\rawgetparameters[\??en]}
+%
+% \def\doifenvelse#1{\doifdefinedelse{\??en#1}} % speed up
+% \def\doifenv #1{\doifdefined {\??en#1}} % speed up
+% \def\doifnotenv #1{\doifundefined {\??en#1}} % speed up
+%
+% \def\env#1{\csname\??en#1\endcsname}
+%
+% \def\envvar#1#2%
+% {\ifcsname\??en#1\endcsname
+% \csname\??en#1\endcsname\else#2%
+% \fi}
+
+% low level change, now also accessible as \getvariable{environment}{...}; the
+% next macros will become obsolete some day in favor of normal variables
+
+\def\s!environment{environment}
+
+\def\setupenv {\dotripleargument\dosetvariables[\getrawparameters][\s!environment]}
+\def\doifenvelse{\doifelsevariable \s!environment}
+\def\doifenv {\doifvariable \s!environment}
+\def\doifnotenv {\doifnotvariable \s!environment}
+\def\env {\getvariable \s!environment}
+\def\envvar {\getvariabledefault\s!environment}
+
+\protect \endinput
diff --git a/tex/context/base/core-env.mkiv b/tex/context/base/core-env.mkiv
new file mode 100644
index 000000000..d927ff3ad
--- /dev/null
+++ b/tex/context/base/core-env.mkiv
@@ -0,0 +1,388 @@
+%D \module
+%D [ file=core-env, % was core-new
+%D version=1995.01.01, % wrong
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=New ones,
+%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 Core Macros / Environments}
+
+\unprotect
+
+%D Modes:
+%D
+%D \starttyping
+%D \enablemode[screen,paper,bound]
+%D
+%D \doifmodeelse {paper} {this} {that}
+%D \doifmode {paper,screen} {this}
+%D \doifnotmode {paper,bound} {that}
+%D
+%D \startmode [list]
+%D \stopmode
+%D
+%D \startnotmode [list]
+%D \stopnotmode
+%D \stoptyping
+%D
+%D system modes have a * as prefix
+%D
+%D Sometimes, we want to prevent a mode for being set. Think
+%D of situations where a style enables a mode, but an outer
+%D level style does not want that. Preventing can be
+%D considered a permanent disabling on forehand.
+
+\def\@mode@{@md@}
+
+\def\systemmodeprefix{*}
+
+\def\disabledmode {0} % no chardefs
+\def\enabledmode {1}
+\def\preventedmode{2}
+
+% fast internal ones
+
+\def\setmode #1{\@EA\let\csname\@mode@#1\endcsname\enabledmode }
+\def\resetmode#1{\@EA\let\csname\@mode@#1\endcsname\disabledmode}
+
+\def\setsystemmode #1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\enabledmode }
+\def\resetsystemmode#1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\disabledmode}
+
+% user ones
+
+\def\preventmode{\unprotect\dopreventmode}
+\def\enablemode {\unprotect\doenablemode }
+\def\disablemode{\unprotect\dodisablemode}
+
+\def\dopreventmode[#1]{\protect\rawprocesscommacommand[#1]\dodopreventmode}
+\def\doenablemode [#1]{\protect\rawprocesscommacommand[#1]\dodoenablemode }
+\def\dodisablemode[#1]{\protect\rawprocesscommacommand[#1]\dododisablemode}
+
+\def\dodopreventmode#1%
+ {\@EA\let\csname\@mode@#1\endcsname\preventedmode}
+
+\def\dodoenablemode#1% mode can be relax
+ {\ifcase0\csname\@mode@#1\endcsname\relax
+ \@EA\let\csname\@mode@#1\endcsname\enabledmode
+ \fi}
+
+\def\dododisablemode#1%
+ {\ifcase0\csname\@mode@#1\endcsname\or
+ \@EA\let\csname\@mode@#1\endcsname\disabledmode
+ \fi}
+
+% handy for mp
+
+\def\booleanmodevalue#1% can be \relax
+ {\expandafter\ifx\csname\@mode@#1\endcsname\relax
+ fals%
+ \else\ifnum0\csname\@mode@#1\endcsname=0
+ fals%
+ \else
+ tru%
+ \fi\fi e}
+
+% check macros
+
+\newif\ifcheckedmode
+
+\def\dodocheckformode#1%
+ {\ifcase0\csname\@mode@#1\endcsname\or\checkedmodetrue\fi}
+
+\def\docheckformode#1#2#3% will be sped up with a quit
+ {\protect\checkedmodefalse\rawprocesscommacommand[#3]\dodocheckformode
+ \ifcheckedmode\@EA#1\else\@EA#2\fi}
+
+\def\dodocheckforallmodes#1%
+ {\ifcase0\csname\@mode@#1\endcsname\relax\checkedmodefalse\or\or\checkedmodefalse\fi}
+
+\def\docheckforallmodes#1#2#3% will be sped up with a quit
+ {\protect\checkedmodetrue\rawprocesscommacommand[#3]\dodocheckforallmodes
+ \ifcheckedmode\@EA#1\else\@EA#2\fi}
+
+% simple ones
+
+\unexpanded\def\doifmodeelse{\unprotect\dodoifmodeelse}
+\unexpanded\def\doifmode {\unprotect\dodoifmode}
+\unexpanded\def\doifnotmode {\unprotect\dodoifnotmode}
+\unexpanded\def\startmode {\unprotect\dostartmode}
+\unexpanded\def\startnotmode{\unprotect\dostartnotmode}
+
+\def\dodoifmodeelse
+ {\docheckformode\firstoftwoarguments\secondoftwoarguments}
+
+\def\dodoifmode
+ {\docheckformode\firstofoneargument\gobbleoneargument}
+
+\def\dodoifnotmode
+ {\docheckformode\gobbleoneargument\firstofoneargument}
+
+\long\unexpanded\def\dostartmode[#1]%
+ {\docheckformode\donothing\dostopmode{#1}}
+
+\long\def\dostartnotmode[#1]%
+ {\docheckformode\dostopnotmode\donothing{#1}}
+
+\unexpanded\def\stopmode {} % no relax
+\unexpanded\def\stopnotmode{} % no relax
+
+\long\def\dostopmode #1\stopmode {}
+\long\def\dostopnotmode#1\stopnotmode{}
+
+\unexpanded\def\doifallmodeselse{\unprotect\dodoifallmodeselse}
+\unexpanded\def\doifallmodes {\unprotect\dodoifallmodes}
+\unexpanded\def\doifnotallmodes {\unprotect\dodoifnotallmodes}
+\unexpanded\def\startallmodes {\unprotect\dostartallmodes}
+\unexpanded\def\startnotallmodes{\unprotect\dostartnotallmodes}
+
+\def\dodoifallmodeselse
+ {\docheckforallmodes\firstoftwoarguments\secondoftwoarguments}
+
+\def\dodoifallmodes
+ {\docheckforallmodes\firstofoneargument\gobbleoneargument}
+
+\def\dodoifnotallmodes
+ {\docheckforallmodes\gobbleoneargument\firstofoneargument}
+
+\long\def\dostartallmodes[#1]%
+ {\docheckforallmodes\donothing\dostopallmodes{#1}}
+
+\long\def\dostartnotallmodes[#1]%
+ {\docheckforallmodes\dostopnotallmodes\donothing{#1}}
+
+\unexpanded\def\stopallmodes {} % no relax
+\unexpanded\def\stopnotallmodes{} % no relax
+
+\long\def\dostopallmodes #1\stopallmodes {}
+\long\def\dostopnotallmodes#1\stopnotallmodes{}
+
+%D Lets now set a mode:
+
+\enablemode[mkiv] \setsystemmode{mkiv}
+
+%D Setups:
+
+\unexpanded\def\startsetups{} % to please dep checker
+\unexpanded\def\stopsetups {} % to please dep checker
+
+\expanded
+ {\long\def\@EA\noexpand\csname\e!start\v!setups\endcsname
+ {\begingroup\noexpand\doifnextoptionalelse
+ {\noexpand\dostartsetupsA\@EA\noexpand\csname\e!stop\v!setups\endcsname}
+ {\noexpand\dostartsetupsB\@EA\noexpand\csname\e!stop\v!setups\endcsname}}}
+
+\letvalue{\e!stop\v!setups}\relax
+
+\unexpanded\def\setups{\doifnextbgroupelse\dosetupsA\dosetupsB} % {..} or [..]
+\unexpanded\def\setup {\doifnextbgroupelse\dosetups \dosetupsC} % {..} or [..]
+
+\def\dosetupsA #1{\processcommacommand[#1]\dosetups} % {..}
+\def\dosetupsB[#1]{\processcommacommand[#1]\dosetups} % [..]
+\def\dosetupsC[#1]{\dosetups{#1}} % [..]
+
+\letvalue{\??su:\letterpercent}\gobbleoneargument
+
+\def\dosetups#1% the grid option will be extended to other main modes
+ {\csname\??su
+ \ifgridsnapping
+ \ifcsname\??su\v!grid:#1\endcsname\v!grid:#1\else\ifcsname\??su:#1\endcsname:#1\else:\letterpercent\fi\fi
+ \else
+ \ifcsname\??su:#1\endcsname:#1\else:\letterpercent\fi
+ \fi
+ \endcsname\empty} % takes one argument
+
+% the next one is meant for \c!setups situations, hence the check for
+% a shortcut
+
+\def\doprocesslocalsetups#1%
+ {\edef\tobeprocessedsetups{#1}%
+ \ifx\tobeprocessedsetups\empty\else
+ \dodoprocesslocalsetups
+ \fi}
+
+\def\dodoprocesslocalsetups
+ {\@EA\processcommalist\@EA[\tobeprocessedsetups]\dosetups}
+
+\edef\setupwithargument#1% saves a few expansions
+ {\noexpand\csname\??su:\noexpand\ifcsname\??su:#1\endcsname#1\noexpand\else\letterpercent\noexpand\fi\endcsname}
+
+\let\directsetup\dosetups
+
+\def\doifsetupselse#1% to be done: grid
+ {\doifdefinedelse{\??su:#1}}
+
+\chardef\setupseolmode\plusone
+
+\unexpanded\def\startsetups {\xxstartsetups\plusone \stopsetups } \let\stopsetups \relax
+\unexpanded\def\startlocalsetups{\xxstartsetups\plusone \stoplocalsetups} \let\stoplocalsetups\relax
+\unexpanded\def\startrawsetups {\xxstartsetups\zerocount\stoprawsetups } \let\stoprawsetups \relax
+\unexpanded\def\startxmlsetups {\xxstartsetups\plustwo \stopxmlsetups } \let\stopxmlsetups \relax
+
+\def\xxstartsetups#1#2%
+ {\begingroup\let\setupseolmode#1\doifnextoptionalelse{\dostartsetupsA#2}{\dostartsetupsB#2}}
+
+\def\dostartsetupsA#1% [ ] delimited
+ {\ifcase\setupseolmode\or\catcode`\^^M\@@ignore\or\catcode`\^^M\@@ignore\catcode`\|\@@other\fi
+ \dotripleempty\dostartsetups[#1]}
+
+\def\dostartsetupsB#1#2 % space delimited
+ {\ifcase\setupseolmode\or\catcode`\^^M\@@ignore\or\catcode`\^^M\@@ignore\catcode`\|\@@other\fi
+ \dodostartsetups#1\empty{#2}}
+
+\def\dostartsetupsC[#1][#2][#3]{\dodostartsetups#1{#2}{#3}} % [..] [..]
+\def\dostartsetupsD[#1][#2][#3]{\dodostartsetups#1\empty{#2}} % [..]
+
+\def\dostartsetups
+ {\ifthirdargument\@EA\dostartsetupsC\else\@EA\dostartsetupsD\fi}
+
+\long\def\dodostartsetups#1#2#3%
+ {\long\def\dododostartsetups##1#1%
+ {\endgroup
+ \dodoglobal % bah
+ \long\expandafter\def\csname\??su#2:#3\expandafter\endcsname\expandafter####\expandafter1\expandafter{##1}}%
+ \dododostartsetups\empty} % the empty trick prevents the { } in {arg} from being eaten up
+
+\def\systemsetupsprefix{*}
+
+\def\systemsetups#1{\dosetups{\systemsetupsprefix#1}}
+
+\def\resetsetups[#1]% see x-fo for usage
+ {\ifcsname\??su\ifgridsnapping\v!grid\fi:#1\endcsname
+ \dodoglobal\letbeundefined{\??su\ifgridsnapping\v!grid\fi:#1}%
+ \else
+ \dodoglobal\letbeundefined{\??su:#1}%
+ \fi}
+
+%D \macros
+%D {setvariables,getvariable,getvariabledefault}
+%D
+%D \starttyping
+%D \setvariables[xx][title=]
+%D \setvariables[xx][title=test test]
+%D \setvariables[xx][title=test $x=1$ test] % fatal error reported
+%D \setvariables[xx][title=test {$x=1$} test]
+%D \setvariables[xx][title] % fatal error reported
+%D \setvariables[xx][titletitel=e]
+%D \stoptyping
+
+\def\??vars{@@vars}
+
+\def\setvariables {\dotripleargument\dosetvariables[\getrawparameters ]}
+\def\setevariables{\dotripleargument\dosetvariables[\getraweparameters]}
+\def\setgvariables{\dotripleargument\dosetvariables[\getrawgparameters]}
+\def\setxvariables{\dotripleargument\dosetvariables[\getrawxparameters]}
+
+\def\globalsetvariables % obsolete
+ {\dotripleargument\dosetvariables[\globalgetrawparameters]}
+
+\long\def\dosetvariables[#1][#2][#3]% tricky, test on s-pre-60
+ {\errorisfataltrue
+ \doifelse{#2}\currentvariableclass
+ {#1[\??vars:#2:][#3]}%
+ {\pushmacro\currentvariableclass
+ \def\currentvariableclass{#2}%
+ \getvariable{#2}\s!reset
+ #1[\??vars:#2:][#3]%
+ \getvariable{#2}\s!set
+ \popmacro\currentvariableclass}%
+ \errorisfatalfalse}
+
+\long\def\setvariable #1#2#3{\long\expandafter\def \csname\??vars:#1:#2\endcsname{#3}}
+\long\def\setevariable#1#2#3{\long\expandafter\edef\csname\??vars:#1:#2\endcsname{#3}}
+\long\def\setgvariable#1#2#3{\long\expandafter\gdef\csname\??vars:#1:#2\endcsname{#3}}
+\long\def\setxvariable#1#2#3{\long\expandafter\xdef\csname\??vars:#1:#2\endcsname{#3}}
+
+\def\getvariable#1#2%
+ {\csname
+ \ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi
+ \endcsname}
+
+\def\showvariable#1#2%
+ {\showvalue{\ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi}}
+
+\let\currentvariableclass\empty
+
+%D \macros
+%D {checkvariables}
+%D
+%D I'll probably forget that this on exists.
+
+\def\checkvariables
+ {\dodoubleargument\docheckvariables}
+
+\def\docheckvariables
+ {\dogetparameters\docheckrawvalue}
+
+\long\def\docheckrawvalue#1#2#3%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \edef\checkedrawvalue{\csname\??vars:#1:#2\endcsname}%
+ \ifx\checkedrawvalue\empty
+ \long\expandafter\def\csname\??vars:#1:#2\endcsname{#3}%
+ \fi
+ \else
+ \long\expandafter\def\csname\??vars:#1:#2\endcsname{#3}%
+ \fi}
+
+%D \macros
+%D {doifelsevariable,doifvariable,doifnotvariable}
+%D
+%D A few trivial macros:
+
+\def\doifelsevariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifvariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\doifnotvariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\def\getvariabledefault#1#2% #3% can be command, so no ifcsname here
+ {\executeifdefined{\??vars:#1:#2}}% {#3}
+
+% \unexpanded\def\setupenv{\dodoubleargument\rawgetparameters[\??en]}
+%
+% \def\doifenvelse#1{\doifdefinedelse{\??en#1}} % speed up
+% \def\doifenv #1{\doifdefined {\??en#1}} % speed up
+% \def\doifnotenv #1{\doifundefined {\??en#1}} % speed up
+%
+% \def\env#1{\csname\??en#1\endcsname}
+%
+% \def\envvar#1#2%
+% {\ifcsname\??en#1\endcsname
+% \csname\??en#1\endcsname\else#2%
+% \fi}
+%
+% low level change, now also accessible as \getvariable
+% {environment}{...}; the next macros will become obsolete
+% some day in favor of normal variables in the environment
+% namespace
+
+\def\s!environment{environment}
+
+\unexpanded\def\setupenv {\dotripleargument\dosetvariables[\getrawparameters][\s!environment]}
+\def\doifenvelse{\doifelsevariable \s!environment}
+\def\doifenv {\doifvariable \s!environment}
+\def\doifnotenv {\doifnotvariable \s!environment}
+\def\env {\getvariable \s!environment}
+\def\envvar {\getvariabledefault\s!environment}
+
+\protect \endinput
diff --git a/tex/context/base/core-fil.mkii b/tex/context/base/core-fil.mkii
new file mode 100644
index 000000000..fca253a7b
--- /dev/null
+++ b/tex/context/base/core-fil.mkii
@@ -0,0 +1,347 @@
+%D \module
+%D [ file=core-fil,
+%D version=1997.11.15,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=File 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 Core Macros / File Support}
+
+\unprotect
+
+%D Files registered as temporary files will be deleted after a
+%D run by texexec:
+
+% \starttext
+% \immediate\openout\scratchwrite=oeps.tmp
+% \immediate\write\scratchwrite{oeps}
+% \immediate\closeout\scratchwrite
+% \registertempfile{oeps.tmp}
+% \typefile{oeps.tmp}
+% \stoptext
+
+\let\usedtempfile\gobbleoneargument
+
+\def\registertempfile#1{\immediatewriteutility{f t {#1}}}
+
+%D \macros
+%D {definefilesynonym}
+%D
+%D One of the problems with loading files is that their names
+%D can depend on the interface language. We therefore need a
+%D method to define filesynonyms. The actual synonyms are
+%D defined elsewhere, but look like:
+%D
+%D \starttyping
+%D \definefilesynonym [chemic] [chemie]
+%D \definefilesynonym [einheit] [unit]
+%D \definefilesynonym [unit] [unit]
+%D \stoptyping
+%D
+%D So we can say in english:
+%D
+%D \starttyping
+%D \usemodules[pictex,chemic,unit]
+%D \stoptyping
+%D
+%D and in dutch:
+%D
+%D \starttyping
+%D \usemodules[pictex,chemie,unit]
+%D \stoptyping
+
+% will be redone in mkiv
+
+\def\definefilesynonym
+ {\dodoubleempty\dodefinefilesynonym}
+
+\def\dodefinefilesynonym[#1][#2]%
+ {\ifundefined{\??fs#1}\else
+ \doifnotvalue{\??fs#1}{#2}{\showmessage\m!files1{#1 (#2),\getvalue{\??fs#1}}}%
+ \fi
+ \doifelse{#1}{#2}{\letbeundefined{\??fs#1}{#2}}{\setevalue{\??fs#1}{#2}}}
+
+%D \macros
+%D {definefilefallback}
+
+\def\definefilefallback
+ {\dodoubleargument\dodefinefilefallback}
+
+\def\dodefinefilefallback[#1][#2]%
+ {\doifnotfile{#1}
+ {\def\docommand##1{\doiffile{##1}{\definefilesynonym[#1][##1]\quitcommalist}}%
+ \processcommalist[#2]\docommand}}
+
+%D \macros
+%D {truefilename}
+%D
+%D At the system level such a filename can be called upon by
+%D saying:
+%D
+%D \starttyping
+%D \truefilename{filename/filesynonym}
+%D \stoptyping
+%D
+%D The implementation shows that nesting is supported.
+
+\def\truefilename#1%
+ {\ifundefined{\??fs#1}#1\else\truefilename{\csname\??fs#1\endcsname}\fi}
+
+%D \macros
+%D {makeshortfilename}
+%D
+%D To prevent cross platform problems with filenames, we
+%D lowercase them as well as only use the first 8~characters.
+%D
+%D \starttyping
+%D \def\domakeshortfilename[#1#2#3#4#5#6#7#8#9]%
+%D {\lowercase{\edef\shortfilename{#1#2#3#4#5#6#7#8.}}%
+%D \expandafter\beforesplitstring\shortfilename\at.\to\shortfilename}
+%D
+%D \def\makeshortfilename[#1]%
+%D {\edef\fullfilename{#1.........}%
+%D \expanded{\domakeshortfilename[\fullfilename]}}
+%D \stoptyping
+%D
+%D In 2005 there is no need for the 8~character limit any more, so:
+
+\def\makeshortfilename[#1]% no need for further cleanup and shortening
+ {\lowercase{\edef\shortfilename{#1.}}%
+ \expandafter\beforesplitstring\shortfilename\at.\to\shortfilename}
+
+%D \macros
+%D {usemodule}
+%D
+%D Most of \CONTEXT is preloaded in the format file. Some very
+%D domain specific typesetting topics are however dealt with in
+%D separate modules, e.g. typesetting of chemical structure
+%D formulas. These modules are loaded by:
+%D
+%D \showsetup{usemodule}
+%D
+%D More information on the specific modules can be found in
+%D their dedicated manuals. We use \type {\next} so that we
+%D can \type {\end} in modules.
+
+\newconditional\moduleisloaded
+
+\def\dododousemodules#1#2% no \unprotect/\protect when loading,
+ {\relax % since we need to use ? ! unprotected
+ \ifconditional\moduleisloaded % sometimes (see xtag-map)
+ \let\next\relax % or: \expandafter\gobbleoneargument
+ \else
+ \makeshortfilename[#1\truefilename{#2}]% beware: *- is not part of syn
+ \doifelseflagged\shortfilename
+ {\showmessage\m!systems7{#2 (line \number\inputlineno)}%
+ \settrue\moduleisloaded
+ \let\next\relax}
+ {\doglobal\setflag\shortfilename
+ \def\next
+ {\startreadingfile
+ \readsysfile\shortfilename
+ {\showmessage\m!systems5{#2}\settrue\moduleisloaded}
+ {\readsysfile{\shortfilename.\mksuffix} % new
+ {\showmessage\m!systems5{#2 (\mksuffix)}\settrue\moduleisloaded}
+ \donothing}%
+ \stopreadingfile}}%
+ \fi
+ \next}
+
+\def\dodousemodules#1#2%
+ {\setfalse\moduleisloaded
+ \doifelsenothing{#1}
+ {\dododousemodules\f!moduleprefix {#2}%
+ \dododousemodules\f!privateprefix{#2}%
+ \dododousemodules\f!styleprefix {#2}%
+ \dododousemodules\f!xstyleprefix {#2}%
+ \dododousemodules\f!thirdprefix {#2}%
+ \dododousemodules\empty {#2}}% new, fall back on raw name
+ {\dododousemodules{#1-}{#2}}%
+ \ifconditional\moduleisloaded\else
+ \showmessage\m!systems6{#2}%
+ \appendtoks\showmessage\m!systems6{#2}\to\everynotabene
+ \fi}
+
+% \def\usemodules
+% {\dodoubleempty\dousemodules}
+%
+% \def\dousemodules[#1][#2]%
+% {\ifsecondargument
+% \doifelsenothing{#2}
+% {\let\next\relax}
+% {\def\next{\processcommalist[#2]{\dodousemodules{#1}}}}%
+% \else
+% \def\next{\usemodules[][#1]}%
+% \fi
+% \next}
+%
+% \let\usemodule\usemodules
+
+\def\usemodules
+ {\dotripleempty\dousemodules}
+
+\def\dousemodules[#1][#2][#3]%
+ {\pushmacro\currentmodule
+ \pushmacro\currentmoduleparameters
+ \let\currentmoduleparameters\empty
+ \ifthirdargument
+ \doifelsenothing{#2}
+ {\let\next\relax}
+ {\def\currentmoduleparameters{#3}%
+ \def\next{\processcommalist[#2]{\dodousemodules{#1}}}}%
+ \else\ifsecondargument
+ \doifelsenothing{#2}
+ {\let\next\relax}
+ {\doifassignmentelse{#2}
+ {\def\currentmoduleparameters{#2}%
+ \def\next{\processcommalist[#1]{\dodousemodules{}}}}
+ {\def\next{\processcommalist[#2]{\dodousemodules{#1}}}}}%
+ \else
+ \def\next{\processcommalist[#1]{\dodousemodules{}}}%
+ \fi\fi
+ \next
+ \popmacro\currentmoduleparameters
+ \popmacro\currentmodule}
+
+\let\currentmoduleparameters\empty
+\let\currentmodule \s!unknown
+
+\def\startmodule
+ {\doifnextoptionalelse\dostartmodule\nostartmodule}
+
+\def\nostartmodule #1 %
+ {\dostartmodule[#1]}
+
+\def\dostartmodule[#1]%
+ {\pushmacro\currentmodule
+ \pushmacro\currentmoduleparameters
+ \def\currentmodule{#1}}
+
+\def\stopmodule
+ {\popmacro\currentmoduleparameters
+ \popmacro\currentmodule}
+
+\def\setupmodule
+ {\dodoubleempty\dosetupmodule}
+
+\def\dosetupmodule[#1][#2]%
+ {\scratchtoks\expandafter{\currentmoduleparameters}%
+ \ifsecondargument
+ \getparameters[\??md:#1:][#2]%
+ \expanded{\getparameters[\??md:#1:][\the\scratchtoks]}%
+ \else
+ \getparameters[\??md:\currentmodule:][#1]%
+ \expanded{\getparameters[\??md:\currentmodule:][\the\scratchtoks]}%
+ \fi
+ \let\currentmoduleparameters\empty}
+
+\def\moduleparameter #1#2{\executeifdefined{\??md:#1:#2}\s!empty}
+\def\currentmoduleparameter#1{\executeifdefined{\??md:\currentmodule:#1}\s!empty}
+
+% \usemodule[newmml]
+% \usemodule[newmml][a=b]
+% \usemodule[x][newmml]
+% \usemodule[x][newmml][a=b]
+%
+% \startmodule [mathml]
+% \setupmodule[a=c] \relax [\currentmoduleparameter{a}] % user vars will be set afterwards
+% \setupmodule[a=c] \relax [\currentmoduleparameter{a}] % user vars are now forgotten
+% \stopmodule
+
+% one can introduce test sections with:
+%
+% \enablemode[newmml:test:\currentmoduleparameter{test}]
+% \startmode[newmml:test:yes} ... \stopmode
+%
+% these will be ignored unless test=yes
+%
+% however, a better way is:
+
+\let\stopmoduletestsection\donothing
+
+\def\startmoduletestsection
+ {\bgroup
+ \setupmodule % we need to make sure that the vars are set
+ \doifelse{\currentmoduleparameter\v!test}\v!yes
+ {\egroup
+ \writestatus{\currentmodule}{loading experimental code}}
+ {\egroup
+ \writestatus{\currentmodule}{skipping experimental code}%
+ \gobbleuntil\stopmoduletestsection}}
+
+%D We also support a singular call, which saves us for
+%D frustrations when we do a typo.
+
+\let\usemodule=\usemodules
+
+% %D The definition shows that the language specific settings
+% %D are activated after loading all the modules specified.
+
+%D \macros
+%D {ifprotectbuffers, bufferprefix,
+%D TEXbufferfile, MPgraphicfile}
+%D
+%D The next switch enables protection of temporary filenames,
+%D which is needed when we process more files on one path at
+%D the same time.
+
+\newif\ifprotectbuffers
+
+\def\bufferprefix{\ifprotectbuffers\jobname-\fi}
+
+% The following filenames are defined here:
+
+\def\TEXbufferfile #1{\bufferprefix#1.\f!temporaryextension}
+\def\MPgraphicfile {\bufferprefix mp\ifMPrun run\else graph\fi} % not needed in luatex
+\def\convertMPcolorfile{\bufferprefix metacmyk.tmp}
+
+%D To save memory, we implement some seldomly used commands
+%D in a lazy way. Nota bene: such runtime definitions are
+%D global.
+%D
+%D \starttyping
+%D \fetchruntimecommand\showaccents{\f!encodingprefix ...}
+%D \stoptyping
+
+\def\fetchruntimecommand#1#2%
+ {\def#1{\dofetchruntimecommand#1{#2}}}
+
+\def\dofetchruntimecommand#1#2%
+ {\doifnotflagged{#2}
+ {\let#1\undefined
+ \startreadingfile
+ \startnointerference % \bgroup
+ \cleanupfeatures % better \setnormalcatcodes / test first
+ \readfile{#2}\donothing\donothing
+ \stopnointerference % \egroup
+ \stopreadingfile
+ \doglobal\setflag{#2}}%
+ \ifx#1\undefined
+ \writestatus\m!systems{command \string#1 not found in file #2}%
+ \def#1{{\infofont[unknown command \string#1]}}%
+ \fi
+ #1}
+
+%D Experimental:
+
+\let\checkpreprocessor\relax
+
+%D To be documented and probably moved
+
+\def\documentresources{\@@erurl}
+
+\def\setupexternalresources
+ {\dodoubleargument\getparameters[\??er]}
+
+\setupexternalresources
+ [url=]
+
+%D This module will be perfected / changed / weeded.
+
+\protect \endinput
diff --git a/tex/context/base/core-fil.mkiv b/tex/context/base/core-fil.mkiv
new file mode 100644
index 000000000..daef176d2
--- /dev/null
+++ b/tex/context/base/core-fil.mkiv
@@ -0,0 +1,284 @@
+%D \module
+%D [ file=core-fil,
+%D version=1997.11.15,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=File 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 Core Macros / File Support}
+
+\unprotect
+
+%D \macros
+%D {definefilesynonym}
+%D
+%D One of the problems with loading files is that their names
+%D can depend on the interface language. We therefore need a
+%D method to define filesynonyms. The actual synonyms are
+%D defined elsewhere, but look like:
+%D
+%D \starttyping
+%D \definefilesynonym [chemic] [chemie]
+%D \definefilesynonym [einheit] [unit]
+%D \definefilesynonym [unit] [unit]
+%D \stoptyping
+%D
+%D So we can say in english:
+%D
+%D \starttyping
+%D \usemodules[pictex,chemic,unit]
+%D \stoptyping
+%D
+%D and in dutch:
+%D
+%D \starttyping
+%D \usemodules[pictex,chemie,unit]
+%D \stoptyping
+
+% will be redone in mkiv
+
+\unexpanded\def\definefilesynonym
+ {\dodoubleempty\dodefinefilesynonym}
+
+\def\dodefinefilesynonym[#1][#2]%
+ {\ifcsname\??fs#1\endcsname
+ \doifnotvalue{\??fs#1}{#2}{\showmessage\m!files1{#1 (#2),\getvalue{\??fs#1}}}%
+ \fi
+ \doifelse{#1}{#2}{\letbeundefined{\??fs#1}{#2}}{\setevalue{\??fs#1}{#2}}}
+
+%D \macros
+%D {definefilefallback}
+
+\unexpanded\def\definefilefallback
+ {\dodoubleargument\dodefinefilefallback}
+
+\def\dodefinefilefallback[#1][#2]%
+ {\doifnotfile{#1}
+ {\def\docommand##1{\doiffile{##1}{\definefilesynonym[#1][##1]\quitcommalist}}%
+ \processcommalist[#2]\docommand}}
+
+%D \macros
+%D {truefilename}
+%D
+%D At the system level such a filename can be called upon by
+%D saying:
+%D
+%D \starttyping
+%D \truefilename{filename/filesynonym}
+%D \stoptyping
+%D
+%D The implementation shows that nesting is supported.
+
+\def\truefilename#1%
+ {\ifcsname\??fs#1\endcsname\expandafter\truefilename\csname\??fs#1\endcsname\else#1\fi}
+
+%D \macros
+%D {makeshortfilename}
+%D
+%D To prevent cross platform problems with filenames, we
+%D lowercase them as well as only use the first 8~characters.
+%D
+%D \starttyping
+%D \def\domakeshortfilename[#1#2#3#4#5#6#7#8#9]%
+%D {\lowercase{\edef\shortfilename{#1#2#3#4#5#6#7#8.}}%
+%D \expandafter\beforesplitstring\shortfilename\at.\to\shortfilename}
+%D
+%D \def\makeshortfilename[#1]%
+%D {\edef\fullfilename{#1.........}%
+%D \expanded{\domakeshortfilename[\fullfilename]}}
+%D \stoptyping
+%D
+%D In 2005 there is no need for the 8~character limit any more, so:
+
+\def\makeshortfilename[#1]% no need for further cleanup and shortening
+ {\lowercase{\edef\shortfilename{#1.}}%
+ \expandafter\beforesplitstring\shortfilename\at.\to\shortfilename}
+
+%D \macros
+%D {usemodule}
+%D
+%D Most of \CONTEXT is preloaded in the format file. Some very
+%D domain specific typesetting topics are however dealt with in
+%D separate modules, e.g. typesetting of chemical structure
+%D formulas. These modules are loaded by:
+%D
+%D \showsetup{usemodule}
+%D
+%D More information on the specific modules can be found in
+%D their dedicated manuals. We use \type {\next} so that we
+%D can \type {\end} in modules.
+
+\def\dodousemodules#1#2%
+ {\ctxlua{support.usemodules("#1","#2","\truefilename{#2}")}}
+
+\def\usemodules
+ {\dotripleempty\dousemodules}
+
+\def\dousemodules[#1][#2][#3]%
+ {\pushmacro\currentmodule
+ \pushmacro\currentmoduleparameters
+ \let\currentmoduleparameters\empty
+ \ifthirdargument
+ \doifelsenothing{#2}
+ {\let\next\relax}
+ {\def\currentmoduleparameters{#3}%
+ \def\next{\processcommalist[#2]{\dodousemodules{#1}}}}%
+ \else\ifsecondargument
+ \doifelsenothing{#2}
+ {\let\next\relax}
+ {\doifassignmentelse{#2}
+ {\def\currentmoduleparameters{#2}%
+ \def\next{\processcommalist[#1]{\dodousemodules{}}}}
+ {\def\next{\processcommalist[#2]{\dodousemodules{#1}}}}}%
+ \else
+ \def\next{\processcommalist[#1]{\dodousemodules{}}}%
+ \fi\fi
+ \next
+ \popmacro\currentmoduleparameters
+ \popmacro\currentmodule}
+
+\let\currentmoduleparameters\empty
+\let\currentmodule \s!unknown
+
+\unexpanded\def\startmodule
+ {\doifnextoptionalelse\dostartmodule\nostartmodule}
+
+\def\nostartmodule #1 %
+ {\dostartmodule[#1]}
+
+\def\dostartmodule[#1]%
+ {\pushmacro\currentmodule
+ \pushmacro\currentmoduleparameters
+ \def\currentmodule{#1}}
+
+\unexpanded\def\stopmodule
+ {\popmacro\currentmoduleparameters
+ \popmacro\currentmodule}
+
+\unexpanded\def\setupmodule
+ {\dodoubleempty\dosetupmodule}
+
+\def\dosetupmodule[#1][#2]%
+ {\scratchtoks\expandafter{\currentmoduleparameters}%
+ \ifsecondargument
+ \getparameters[\??md:#1:][#2]%
+ \expanded{\getparameters[\??md:#1:][\the\scratchtoks]}%
+ \else
+ \getparameters[\??md:\currentmodule:][#1]%
+ \expanded{\getparameters[\??md:\currentmodule:][\the\scratchtoks]}%
+ \fi
+ \let\currentmoduleparameters\empty}
+
+\def\moduleparameter #1#2{\executeifdefined{\??md:#1:#2}\s!empty}
+\def\currentmoduleparameter#1{\executeifdefined{\??md:\currentmodule:#1}\s!empty}
+
+\def\useluamodule [#1]{\ctxlua{dofile(resolvers.findctxfile("#1"))}}
+\def\luaenvironment #1 {\ctxlua{dofile(resolvers.findctxfile("#1"))}}
+
+% \usemodule[newmml]
+% \usemodule[newmml][a=b]
+% \usemodule[x][newmml]
+% \usemodule[x][newmml][a=b]
+%
+% \startmodule [mathml]
+% \setupmodule[a=c] \relax [\currentmoduleparameter{a}] % user vars will be set afterwards
+% \setupmodule[a=c] \relax [\currentmoduleparameter{a}] % user vars are now forgotten
+% \stopmodule
+
+% one can introduce test sections with:
+%
+% \enablemode[newmml:test:\currentmoduleparameter{test}]
+% \startmode[newmml:test:yes} ... \stopmode
+%
+% these will be ignored unless test=yes
+%
+% however, a better way is:
+
+\let\stopmoduletestsection\donothing
+
+\unexpanded\def\startmoduletestsection
+ {\bgroup
+ \setupmodule % we need to make sure that the vars are set
+ \doifelse{\currentmoduleparameter\v!test}\v!yes
+ {\egroup
+ \writestatus{\currentmodule}{loading experimental code}}
+ {\egroup
+ \writestatus{\currentmodule}{skipping experimental code}%
+ \gobbleuntil\stopmoduletestsection}}
+
+%D We also support a singular call, which saves us for
+%D frustrations when we do a typo.
+
+\let\usemodule=\usemodules
+
+% %D The definition shows that the language specific settings
+% %D are activated after loading all the modules specified.
+
+%D \macros
+%D {ifprotectbuffers, bufferprefix,
+%D TEXbufferfile, MPgraphicfile}
+%D
+%D The next switch enables protection of temporary filenames,
+%D which is needed when we process more files on one path at
+%D the same time.
+
+\newif\ifprotectbuffers
+
+\def\bufferprefix{\ifprotectbuffers\jobname-\fi}
+
+% The following filenames are defined here:
+
+\def\TEXbufferfile #1{\bufferprefix#1.\f!temporaryextension}
+\def\MPgraphicfile {\bufferprefix mp\ifMPrun run\else graph\fi} % not needed in luatex
+\def\convertMPcolorfile{\bufferprefix metacmyk.tmp}
+
+%D To save memory, we implement some seldomly used commands
+%D in a lazy way. Nota bene: such runtime definitions are
+%D global.
+%D
+%D \starttyping
+%D \fetchruntimecommand\showaccents{\f!encodingprefix ...}
+%D \stoptyping
+
+\def\fetchruntimecommand#1#2%
+ {\def#1{\dofetchruntimecommand#1{#2}}}
+
+\def\dofetchruntimecommand#1#2%
+ {\doifnotflagged{#2}
+ {\let#1\undefined
+ \startreadingfile
+ \startnointerference % \bgroup
+ \cleanupfeatures % better \setnormalcatcodes / test first
+ \readfile{#2}\donothing\donothing
+ \stopnointerference % \egroup
+ \stopreadingfile
+ \doglobal\setflag{#2}}%
+ \ifx#1\undefined
+ \writestatus\m!systems{command \string#1 not found in file #2}%
+ \def#1{{\infofont[unknown command \string#1]}}%
+ \fi
+ #1}
+
+%D Experimental:
+
+\let\checkpreprocessor\relax
+
+%D To be documented and probably moved
+
+\def\documentresources{\@@erurl}
+
+\unexpanded\def\setupexternalresources
+ {\dodoubleargument\getparameters[\??er]}
+
+\setupexternalresources
+ [url=]
+
+%D This module will be perfected / changed / weeded.
+
+\protect \endinput
diff --git a/tex/context/base/core-fnt.mkii b/tex/context/base/core-fnt.mkii
new file mode 100644
index 000000000..9bc2a66f5
--- /dev/null
+++ b/tex/context/base/core-fnt.mkii
@@ -0,0 +1,726 @@
+%D \module
+%D [ file=core-fnt,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Fonts,
+%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 Core Macros / Fonts}
+
+\unprotect
+
+%D \macros
+%D {compound}
+%D
+%D We will overload the already active \type {|} so we have
+%D to save its meaning in order to be able to use this handy
+%D macro.
+%D
+%D \starttyping
+%D so test\compound{}test can be used instead of test||test
+%D \stoptyping
+
+\bgroup \catcode`\|=\@@active \gdef\compound#1{|#1|} \egroup
+
+%D Here we hook some code into the clean up mechanism needed
+%D for verbatim data.
+
+\appendtoks
+ \disablecompoundcharacters
+ \disablediscretionaries
+\to \everycleanupfeatures
+
+%D \macros
+%D {kap,KAP,Kap,Kaps,nokap,userealcaps,usepseudocaps}
+%D
+%D We already introduced \type{\cap} as way to capitalize
+%D words. This command comes in several versions:
+%D
+%D \startbuffer
+%D \cap {let's put on a \cap{cap}}
+%D \cap {let's put on a \nocap{cap}}
+%D \CAP {let's put on a \\{cap}}
+%D \Cap {let's put on a \\{cap}}
+%D \Caps{let's put on a cap}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Note the use of \type{\nocap}, \type{\\} and the nested
+%D \type{\cap}.
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D These macros show te main reason why we introduced the
+%D smaller \type{\tx} and \type{\txx}.
+%D
+%D \starttyping
+%D \cap\romannumerals{1995}
+%D \stoptyping
+%D
+%D This at first sight unusual capitilization is completely
+%D legal.
+%D
+%D \showsetup{smallcapped}
+%D \showsetup{notsmallcapped}
+%D \showsetup{CAPPED}
+%D \showsetup{SmallCapped}
+%D \showsetup{SmallCaps}
+%D
+%D The difference between pseudo and real caps is demonstrated
+%D below:
+%D
+%D \startbuffer
+%D \usepseudocaps \cap{Hans Hagen}
+%D \userealcaps \cap{Hans Hagen}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D The \type {\bgroup} trickery below is needed because of
+%D \type {\groupedcommand}.
+
+\def\usepseudocaps
+ {\def\cap@@uppercase{\the\everyuppercase\uppercased}%
+ \def\cap@@lowercase{\the\everylowercase\lowercased}%
+ \def\cap@@visualize{\tx}}
+
+\def\userealcaps
+ {\let\cap@@uppercase\relax
+ %\let\cap@@lowercase\relax % Definitely not!
+ \def\cap@@visualize{\sc}}
+
+\usepseudocaps
+
+\unexpanded\def\smallcapped % else conflict with math
+ {\futurelet\next\dosmallcapped}
+
+\def\disablepseudocaps
+ {\let\smallcapped\donothing}
+
+\def\dosmallcapped
+ {\ifx\next\bgroup
+ \expandafter\dodosmallcapped\expandafter\relax
+ \else
+ \expandafter\dodosmallcapped
+ \fi}
+
+\def\dodosmallcapped#1#2%
+ {\ifmmode\hbox\fi
+ \bgroup
+ \cap@@visualize
+ \cap@@uppercase{#1{#2}}%
+ \egroup}
+
+\unexpanded\def\notsmallcapped#1%
+ {\cap@@lowercase{#1}}
+
+\unexpanded\def\CAPPED#1%
+ {{\def\\##1{\smallcapped{##1}}#1}}
+
+\unexpanded\def\SmallCapped#1%
+ {\CAPPED{\\#1}}
+
+\unexpanded\def\SmallCaps
+ {\let\processword\SmallCapped
+ \processwords}
+
+%D Sure:
+
+\def\kap{\smallcapped} % for old times sake
+
+%D Some precautions for a \PLAIN\ \TEX\ definition.
+
+\unexpanded\def\normalcap{\dohandlemathtoken{cap}}
+\unexpanded\def\normalCap{\dohandlemathtoken{Cap}}
+
+\def\cap{\mathortext\normalcap\smallcapped}
+\def\Cap{\mathortext\normalCap\SmallCapped}
+
+\appendtoks
+ \let\cap\firstofoneargument
+ \let\Cap\firstofoneargument
+\to \simplifiedcommands
+
+%D \macros
+%D {setupcapitals}
+%D
+%D By default we use pseudo small caps in titles. This can be
+%D set up with:
+%D
+%D \showsetup{setupcapitals}
+
+\let\normalsmallcapped\smallcapped
+
+\def\setupcapitals
+ {\dosingleempty\dosetupcapitals}
+
+\def\dosetupcapitals[#1]%
+ {\getparameters[\??kk][#1]%
+ \doifelse\@@kktitle\v!yes
+ {\definealternativestyle[\v!capital][\normalsmallcapped][\normalsmallcapped]%
+ \definealternativestyle[\v!smallcaps][\sc][\sc]%
+ \unexpanded\def\smallcapped{\normalsmallcapped}}
+ {\definealternativestyle[\v!capital][\normalsmallcapped][\uppercased]%
+ \definealternativestyle[\v!smallcaps][\sc][\uppercased]%
+ \unexpanded\def\smallcapped{\doconvertfont\v!capital}}%
+ \doifelse\@@kksc\v!yes
+ \userealcaps
+ \usepseudocaps}
+
+\ifx\uppercased\undefined \let\uppercased\uppercase \fi
+\ifx\lowercased\undefined \let\lowercased\lowercase \fi
+
+% pretty tricky stuff:
+%
+% \usemodule[abr-01] \TEX \METAPOST \PPCHTEX \LATEX
+% \usemodule[abr-02] \TEX \METAPOST \PPCHTEX \LATEX
+
+%def\uppercased#1{{\forceunexpanded\xdef\@@globalcrap{\uppercase{#1}}}\@@globalcrap}
+%def\lowercased#1{{\forceunexpanded\xdef\@@globalcrap{\lowercase{#1}}}\@@globalcrap}
+
+\def\uppercased#1{{\forceunexpanded\xdef\@@expanded{\uppercase{#1}}}\@@expanded}
+\def\lowercased#1{{\forceunexpanded\xdef\@@expanded{\lowercase{#1}}}\@@expanded}
+
+\setupcapitals
+ [\c!title=\v!yes,
+ \c!sc=\v!no]
+
+%D \macros
+%D {Word, Words, WORD, WORDS, doprocesswords}
+%D
+%D This is probably not the right place to present the next set
+%D of macros.
+%D
+%D \starttyping
+%D \Word {far too many words}
+%D \Words{far too many words}
+%D \WORD {far too many words}
+%D \WORDS{far too many words}
+%D \stoptyping
+%D
+%D \typebuffer
+%D
+%D This calls result in:
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D \showsetup{Word}
+%D \showsetup{Words}
+%D \showsetup{WORD}
+%D \showsetup{WORDS}
+
+\def\doWord#1%
+ {\bgroup
+ \the\everyuppercase
+ \uppercase{#1}%
+ \egroup}
+
+\unexpanded\def\Word#1%
+ {\doWord#1}
+
+\def\doprocesswords#1 #2\od
+ {\ConvertToConstant\doifnot{#1}{}
+ {\processword{#1} %
+ \doprocesswords#2 \od}}
+
+\def\processwords#1%
+ {\doprocesswords#1 \od\unskip}
+
+\let\processword\relax
+
+\unexpanded\def\Words
+ {\let\processword\Word
+ \processwords}
+
+\unexpanded\def\WORD#1%
+ {\bgroup
+ \let\smallcapped\firstofoneargument
+ \let\WORD\firstofoneargument
+ \douppercase{#1}%
+ \egroup}
+
+\unexpanded\def\WORDS#1%
+ {\WORD{#1}}
+
+%D \macros
+%D {stretched}
+%D
+%D Stretching characters in a word is a sort of typographical
+%D murder. Nevertheless we support this manipulation for use in
+%D for instance titles.
+%D
+%D \starttyping
+%D \hbox to 5cm{\stretched{murder}}
+%D \stoptyping
+%D
+%D \typebuffer
+%D
+%D or
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D \showsetup{stretched}
+
+\def\stretched#1%
+ {\ifvmode\hbox to \hsize\else\ifinner\else\hbox\fi\fi
+ \bgroup\processtokens\relax\hss\relax{\hss\hss}{#1}\egroup}
+
+%D \startbuffer
+%D \stretched{Unknown Box}
+%D \hbox to .5\hsize{\stretched{A Horizontal Box}}
+%D \vbox to 2cm{\stretched{A Vertical Box}}
+%D \hbox to 3cm{\stretched{sp{\'e}c{\`\i}{\"a}l}}
+%D \stopbuffer
+%D
+%D \getbuffer
+%D
+%D The first line of this macros takes care of boxing. Normally
+%D one will use an \type{\hbox} specification. The last line
+%D shows how special characters should be passed.
+%D
+%D \typebuffer
+
+%D \macros
+%D {stretchednormalcase, stretcheduppercase, stretchedlowercase}
+%D
+%D A convenient alternative is:
+%D
+%D \starttyping
+%D \stretcheduppercase{Is this what you like?}
+%D \stoptyping
+%D
+%D \typebuffer
+%D
+%D this one uses fixed skips and kerns.
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D The default skip can be set with:
+
+% \def\stretchedspacefactor{4}
+% \def\stretchedspaceamount{.25em}
+%
+% \unexpanded\def\stretcheduppercase#1%
+% {\bgroup
+% \the\everyuppercase
+% \uppercase{\def\textstring{#1}}%
+% \ifdim\stretchedspaceamount>\zeropoint
+% \def\textkern%
+% {\kern\stretchedspaceamount}%
+% \def\textskip%
+% {\scratchdimen=\stretchedspaceamount
+% \hskip\stretchedspacefactor\scratchdimen}%
+% \@EA\processtokens\@EA\relax\@EA\textkern\@EA\relax\@EA
+% \textskip\@EA{\textstring}%
+% \else
+% \textstring
+% \fi
+% \egroup}
+
+%D Given the following settings, the space is 1em by default:
+
+\def\stretchedspacefactor{4}
+\def\stretchedspaceamount{.25em}
+\def\stretchedbreaktokens{.@/}
+
+\unexpanded\def\stretchednormalcase
+ {\stretchedsomecase\firstofoneargument}
+
+\unexpanded\def\stretcheduppercase
+ {\stretchedsomecase{\the\everyuppercase\uppercase}}
+
+\unexpanded\def\stretchedlowercase
+ {\stretchedsomecase{\the\everylowercase\lowercase}}
+
+\def\stretchedsomecase#1#2%
+ {\bgroup
+ #1{\def\textstring{#2}}%
+ \ifdim\stretchedspaceamount=\zeropoint
+ \textstring
+ \else
+ \def\textkern##1%
+ {% beware: ##1 may not be \box\somebox -)
+ \determinemidwordbreak{##1}{\stretchedbreaktokens}%
+ \kern\stretchedspaceamount##1\domidwordbreak}%
+ \def\textskip
+ {\scratchdimen\stretchedspaceamount
+ \hskip\stretchedspacefactor\scratchdimen}%
+ \@EA\processtokens\@EA\relax\@EA\textkern\@EA\relax\@EA
+ \textskip\@EA{\textstring}%
+ \fi
+ \egroup}
+
+%D An auxiliary macro, see for usage \type {\stretcheduppercase}.
+
+\let\domidwordbreak\relax
+
+\def\setmidwordbreaktoken#1%
+ {\sfcode`#1=5000\relax}
+
+\def\determinemidwordbreak#1#2%
+ {\edef\midwordbreaktokens{#2}%
+ \ifx\midwordbreaktokens\empty
+ \global\let\domidwordbreak\relax
+ \else
+ \setbox\scratchbox\hbox
+ {\expandafter\handletokens\midwordbreaktokens\with\setmidwordbreaktoken
+ a\space \!!dimena\lastskip
+ #1\space\!!dimenb\lastskip \relax % needed
+ \ifdim\!!dimena=\!!dimenb
+ \globallet\domidwordbreak\relax
+ \else
+ \globallet\domidwordbreak\allowbreak
+ \fi}%
+ \fi}
+
+%D \macros
+%D {underbar,underbars,
+%D overbar,overbars,
+%D overstrike,overstrikes,
+%D setupunderbar}
+%D
+%D In the rare case that we need undelined words, for instance
+%D because all font alternatives are already in use, one can
+%D use \type{\underbar} and \type{\overstrike} and their plural
+%D forms.
+%D
+%D \startbuffer
+%D \underbars{drawing \underbar{bars} under words is a typewriter leftover}
+%D \overstrikes{striking words makes them \overstrike{unreadable} but
+%D sometimes even \overbar{top lines} come into view.}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D The next macros are derived from the \PLAIN\ \TEX\ one, but
+%D also supports nesting. The \type{$} keeps us in horizontal
+%D mode and at the same time applies grouping.
+%D
+%D \showsetup{underbar}
+%D \showsetup{underbars}
+%D \showsetup{overbar}
+%D \showsetup{overbars}
+%D \showsetup{overstrike}
+%D \showsetup{overstrikes}
+%D
+%D Although underlining is ill advised, we permit some
+%D alternatives, that can be set up by:
+%D
+%D \showsetup{setupunderbar}
+%D
+%D The alternatives show up as
+%D {\setupunderbar [alternative=a]\underbar{alternative a}},
+%D {\setupunderbar [alternative=b]\underbar{alternative b}},
+%D {\setupunderbar [alternative=c]\underbar{alternative c}}
+%D and
+%D {\setupunderbar [rulethickness=1pt]\underbar{1pt width}},
+%D {\setupunderbar [rulethickness=2pt]\underbar{2pt width}},
+%D or whatever. Because \type{\overstrike} uses the same
+%D method, the settings also apply to that macro.
+
+\newcount\underbarlevel
+
+\def\underbarmethoda#1#2#3% RULE
+ {\hbox to #1{\vrule\!!width#1\!!height#2\!!depth#3}}
+
+\def\underbarmethodb#1#2#3% DASH
+ {\hbox to #1
+ {\hskip-.25em
+ \xleaders
+ \hbox{\hskip.25em\vrule\!!width.25em\!!height#2\!!depth#3}
+ \hfil}}
+
+\def\underbarmethodc#1#2#3% PERIOD
+ {\hbox to #1
+ {\dimen4=#3
+ \advance\dimen4 .2ex
+ \hskip-.25em
+ \xleaders
+ \hbox{\hskip.25em\lower\dimen4\hbox{.}}
+ \hfil}}
+
+\def\dododounderbar#1#2#3%
+ {\startmathmode
+ \setbox0\hbox{#3}%
+ \setbox2\hbox{\color[\@@onrulecolor]{\getvalue{underbarmethod\@@onalternative}{\wd0}{#1}{#2}}}%
+ \wd0\zeropoint
+ \ht2\ht0
+ \dp2\dp0
+ \box0\box2
+ \stopmathmode}
+
+\unexpanded\def\dodounderbar#1%
+ {\bgroup
+ \dimen0=\@@onbottomoffset
+ \dimen0=\underbarlevel\dimen0
+ \ifdone \else
+ \advance\dimen0 -\strutht
+ \fi
+ \dimen2\dimen0
+ \advance\dimen2 \@@onrulethickness
+ \dododounderbar{-\dimen0}{\dimen2}{#1}%
+ \egroup}
+
+\def\betweenunderbarwords
+ {\bgroup
+ \setbox0\hbox{\dodounderbar{\hskip\interwordspace}}%
+ \nobreak
+ \hskip\zeropoint\!!minus\interwordshrink
+ \discretionary{}{}{\box0}%
+ \egroup}
+
+\def\betweenunderbarspaces
+ {\hskip\currentspaceskip}
+
+% \unexpanded\def\dounderbar#1#2%
+% {\let\betweenisolatedwords#1%
+% \processisolatedwords{#2}\dodounderbar
+% \egroup}
+
+\unexpanded\def\underbar
+ {\bgroup
+ \advance\underbarlevel\plusone
+ \donetrue
+ \dounderbar\betweenunderbarwords}
+
+\unexpanded\def\dounderbar#1%
+ {\let\betweenisolatedwords#1%
+ \dosingleempty\redounderbar}
+
+\unexpanded\def\redounderbar[#1]#2%
+ {\iffirstargument\setupunderbar[#1]\fi
+ \processisolatedwords{#2}\dodounderbar
+ \egroup}
+
+\unexpanded\def\underbars
+ {\bgroup
+ \advance\underbarlevel\plusone
+ \donetrue
+ \dounderbar\betweenunderbarspaces}
+
+\unexpanded\def\overbar
+ {\bgroup
+ \advance\underbarlevel\minusone
+ \donefalse
+ \dounderbar\betweenunderbarwords}
+
+\unexpanded\def\overbars
+ {\bgroup
+ \advance\underbarlevel\minusone
+ \donefalse
+ \dounderbar\betweenunderbarspaces}
+
+\def\dooverstrike#1%
+ {\bgroup
+ \dimen0=\@@ontopoffset
+ \dimen2=\dimen0
+ \advance\dimen2 \@@onrulethickness
+ \dododounderbar{\dimen2}{-\dimen0}{#1}%
+ \egroup}
+
+\def\betweenoverstrikewords
+ {\bgroup
+ \setbox0\hbox{\dooverstrike{\hskip\interwordspace}}%
+ \nobreak
+ \hskip\zeropoint\!!minus\interwordshrink
+ \discretionary{}{}{\box0}%
+ \egroup}
+
+\unexpanded\def\overstrike#1%
+ {\bgroup
+ \let\betweenisolatedwords\betweenoverstrikewords
+ \processisolatedwords{#1}\dooverstrike
+ \egroup}
+
+\unexpanded\def\overstrikes#1%
+ {\bgroup
+ \processisolatedwords{#1}\dooverstrike
+ \egroup}
+
+\def\underbarparameter#1{\csname\??on#1\csname}
+
+\def\setupunderbar
+ {\dodoubleargument\getparameters[\??on]}
+
+%D \macros
+%D {shiftedword, shiftedwords}
+%D
+%D Used as \type {\shiftedwords {10pt} {some text}} this macro will
+%D move
+
+% \def\shiftedword#1% #2%
+% {\raise#1\hbox} % {#2}} % officially: {\ifdim#1>\zeropoint\raise\else\lower\fi#1\hbox{#2}}
+
+% \def\shiftedwords#1#2%
+% {\processisolatedwords{#2}{\shiftedword{#1}}}
+
+%D \macros
+%D {low, high, lohi}
+%D
+%D Although \TEX\ is pretty well aware of super- and
+%D subscripts, its mechanism is mainly tuned for math mode.
+%D The next few commands take care of script texts both modes.
+%D
+%D \startbuffer
+%D The higher\high{one goes} the lower\low{one drops}, or\lohi{yes}{no}?
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D Note the different placement of \type {\lohi}, where we
+%D need a bit more space. The implementation looks a bit
+%D fuzzy, since some \type {\fontdimen}'s are involved to
+%D determine the optimal placement.
+
+\def\dodohighlow
+ {\ifx\fontsize\empty
+ \ifmmode
+ \ifnum\fam<0 \tx \else \holamathfont \fi
+ \else
+ \tx
+ \fi
+ \else
+ \tx
+ \fi}
+
+\def\dohighlow#1#2#3#4#5% todo, named fontdimens
+ {\dontleavehmode
+ \bgroup
+ \scratchdimen\ifdim\fontexheight\textfont2=1ex #2\textfont2\else #3ex\fi
+ \advance\scratchdimen #4ex
+ \kern.1ex
+ \setbox\scratchbox\hbox{#1\scratchdimen\hbox{\dodohighlow#5}}%
+ \ht\scratchbox\strutheight
+ \dp\scratchbox\strutdepth
+ \box\scratchbox
+ \egroup}
+
+\unexpanded\def\high{\dohighlow\raise\mathsupnormal{.86}{0}}
+\unexpanded\def\low {\dohighlow\lower\mathsubnormal{.48}{0}}
+
+% \unexpanded\def\lohi#1#2%
+% {\dontleavehmode
+% \hbox
+% {\setbox4=\hbox{\dohighlow\lower\mathsubnormal{.48}{.1}{#1}}%
+% \setbox6=\hbox{\dohighlow\raise\mathsupnormal{.86}{.1}{#2}}%
+% \ifdim\wd4<\wd6
+% \wd4=\zeropoint\box4\box6
+% \else
+% \wd6=\zeropoint\box6\box4
+% \fi}}
+
+\unexpanded\def\lohi
+ {\dosingleempty\dolohi}
+
+\def\dolohi[#1]#2#3%
+ {\dontleavehmode
+ \hbox
+ {\setbox4\hbox{\dohighlow\lower\mathsubnormal{.48}{.1}{#2}}%
+ \setbox6\hbox{\dohighlow\raise\mathsupnormal{.86}{.1}{#3}}%
+ \doif{#1}{\v!left}
+ {\ifdim\wd4<\wd6
+ \setbox4\hbox to \wd6{\hss\box4}%
+ \else
+ \setbox6\hbox to \wd4{\hss\box6}%
+ \fi}%
+ \ifdim\wd4<\wd6
+ \wd4=\zeropoint\box4\box6
+ \else
+ \wd6=\zeropoint\box6\box4
+ \fi}}
+
+%D You can provide an optional keyword \type {left}, in which
+%D case the super and subscripts will be aligned in a way that
+%D permits placement at the left of a word (which means that
+%D it will be right aligned).
+%D
+%D \startbuffer
+%D \lohi{aha}{ah} test \lohi{aha}{ah} test
+%D \lohi[left]{aha}{ah} test \lohi[left]{aha}{ah} test
+%D \lohi{aha}{ah} test\lohi{aha}{ah} test
+%D \lohi[left]{aha}{ah}test \lohi[left]{aha}{ah}test
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+%D \macros
+%D {setupinitial,placeinitial,checkinitial}
+%D
+%D {\em To be documented.}
+%D
+%D \starttyping
+%D \setupinitial[state=start] \placeinitial \input tufte
+%D \stoptyping
+%D
+%D and
+%D
+%D \starttyping
+%D \def\bpar{\ifvmode\checkinitial\fi}
+%D \def\epar{\ifhmode\par\fi\checkinitial}
+%D \stoptyping
+
+% to do: more fine tuning
+
+\def\setupinitial
+ {\dodoubleempty\getparameters[\??dc]}
+
+\definefontsynonym[Initial][Regular] % prefered initial identifier
+\definefontsynonym[initial][Initial] % internal but accepted too
+
+\setupinitial
+ [\c!state=\v!stop,
+ \c!location=\v!text,
+ \c!n=3,
+ \c!distance=.125em,
+ \c!command=,
+ \s!font=initial]
+
+\def\AutoDroppedCapsCommand{\NiceDroppedCaps\@@dccommand\@@dcfont\@@dcdistance\@@dcn}%
+
+\def\placeinitial
+ {\doifelse\@@dclocation\v!margin{\chardef\DropMode\plusone}{\chardef\DropMode\zerocount}%
+ \doif \@@dcstate\v!start{\ifcase\@@dcn\else\AutoDroppedCaps\fi}}
+
+\let\checkinitial\CheckDroppedCaps
+
+%D This module has only a few setups:
+
+\setupunderbar
+ [\c!alternative=a,
+ \c!rulethickness=\linewidth,
+ \c!bottomoffset=1.5pt,
+ \c!topoffset=2.5pt,
+ \c!rulecolor=]
+
+\protect \endinput
diff --git a/tex/context/base/core-fnt.mkiv b/tex/context/base/core-fnt.mkiv
new file mode 100644
index 000000000..a7c84a5a0
--- /dev/null
+++ b/tex/context/base/core-fnt.mkiv
@@ -0,0 +1,293 @@
+%D \module
+%D [ file=core-fnt,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Fonts,
+%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 Core Macros / Fonts}
+
+\unprotect
+
+%D \macros
+%D {compound}
+%D
+%D We will overload the already active \type {|} so we have
+%D to save its meaning in order to be able to use this handy
+%D macro.
+%D
+%D \starttyping
+%D so test\compound{}test can be used instead of test||test
+%D \stoptyping
+
+\bgroup \catcode`\|=\@@active \gdef\compound#1{|#1|} \egroup
+
+%D Here we hook some code into the clean up mechanism needed
+%D for verbatim data.
+
+\appendtoks
+ \disablecompoundcharacters
+ \disablediscretionaries
+\to \everycleanupfeatures
+
+%D \macros
+%D {stretched}
+%D
+%D Stretching characters in a word is a sort of typographical
+%D murder. Nevertheless we support this manipulation for use in
+%D for instance titles.
+%D
+%D \starttyping
+%D \hbox to 5cm{\stretched{murder}}
+%D \stoptyping
+%D
+%D \typebuffer
+%D
+%D or
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D \showsetup{stretched}
+
+\def\stretched#1%
+ {\ifvmode\hbox to \hsize\else\ifinner\else\hbox\fi\fi
+ \bgroup\processtokens\relax\hss\relax{\hss\hss}{#1}\egroup}
+
+%D \startbuffer
+%D \stretched{Unknown Box}
+%D \hbox to .5\hsize{\stretched{A Horizontal Box}}
+%D \vbox to 2cm{\stretched{A Vertical Box}}
+%D \hbox to 3cm{\stretched{sp{\'e}c{\`\i}{\"a}l}}
+%D \stopbuffer
+%D
+%D \getbuffer
+%D
+%D The first line of this macros takes care of boxing. Normally
+%D one will use an \type{\hbox} specification. The last line
+%D shows how special characters should be passed.
+%D
+%D \typebuffer
+
+%D \macros
+%D {stretchednormalcase, stretcheduppercase, stretchedlowercase}
+%D
+%D A convenient alternative is:
+%D
+%D \starttyping
+%D \stretcheduppercase{Is this what you like?}
+%D \stoptyping
+%D
+%D \typebuffer
+%D
+%D this one uses fixed skips and kerns.
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D The default skip can be set with:
+
+%D Given the following settings, the space is 1em by default:
+
+\def\stretchedspacefactor{4}
+\def\stretchedspaceamount{.25em}
+\def\stretchedbreaktokens{.@/}
+
+\unexpanded\def\stretchednormalcase
+ {\stretchedsomecase\firstofoneargument}
+
+\unexpanded\def\stretcheduppercase
+ {\stretchedsomecase{\the\everyuppercase\uppercase}}
+
+\unexpanded\def\stretchedlowercase
+ {\stretchedsomecase{\the\everylowercase\lowercase}}
+
+\def\stretchedsomecase#1#2%
+ {\bgroup
+ #1{\def\textstring{#2}}%
+ \ifdim\stretchedspaceamount=\zeropoint
+ \textstring
+ \else
+ \def\textkern##1%
+ {% beware: ##1 may not be \box\somebox -)
+ \determinemidwordbreak{##1}{\stretchedbreaktokens}%
+ \kern\stretchedspaceamount##1\domidwordbreak}%
+ \def\textskip
+ {\scratchdimen\stretchedspaceamount
+ \hskip\stretchedspacefactor\scratchdimen}%
+ \@EA\processtokens\@EA\relax\@EA\textkern\@EA\relax\@EA\textskip\@EA{\textstring}%
+ \fi
+ \egroup}
+
+%D An auxiliary macro, see for usage \type {\stretcheduppercase}.
+
+\let\domidwordbreak\relax
+
+\def\setmidwordbreaktoken#1%
+ {\sfcode`#1=5000\relax}
+
+\def\determinemidwordbreak#1#2%
+ {\edef\midwordbreaktokens{#2}%
+ \ifx\midwordbreaktokens\empty
+ \global\let\domidwordbreak\relax
+ \else
+ \setbox\scratchbox\hbox
+ {\expandafter\handletokens\midwordbreaktokens\with\setmidwordbreaktoken
+ a\space \!!dimena\lastskip
+ #1\space\!!dimenb\lastskip \relax % needed
+ \ifdim\!!dimena=\!!dimenb
+ \globallet\domidwordbreak\relax
+ \else
+ \globallet\domidwordbreak\allowbreak
+ \fi}%
+ \fi}
+
+%D \macros
+%D {shiftedword, shiftedwords}
+%D
+%D Used as \type {\shiftedwords {10pt} {some text}} this macro will
+%D move
+
+% \def\shiftedword#1% #2%
+% {\raise#1\hbox} % {#2}} % officially: {\ifdim#1>\zeropoint\raise\else\lower\fi#1\hbox{#2}}
+
+% \def\shiftedwords#1#2%
+% {\processisolatedwords{#2}{\shiftedword{#1}}}
+
+%D \macros
+%D {low, high, lohi, hilo}
+%D
+%D Although \TEX\ is pretty well aware of super- and
+%D subscripts, its mechanism is mainly tuned for math mode.
+%D The next few commands take care of script texts both modes.
+%D
+%D \startbuffer
+%D The higher\high{one goes} the lower\low{one drops}, or\lohi{yes}{no}?
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D Note the different placement of \type {\lohi}, where we
+%D need a bit more space. The implementation looks a bit
+%D fuzzy, since some \type {\fontdimen}'s are involved to
+%D determine the optimal placement.
+
+\def\dodohighlow
+ {\ifx\fontsize\empty
+ \ifmmode
+ \ifnum\fam<0 \tx \else \holamathfont \fi
+ \else
+ \tx
+ \fi
+ \else
+ \tx
+ \fi}
+
+\def\dohighlow#1#2#3#4#5% todo, named fontdimens
+ {\dontleavehmode
+ \bgroup
+ \scratchdimen\ifdim\fontexheight\textfont2=1ex #2\textfont2\else #3ex\fi
+ \advance\scratchdimen #4ex
+ \kern.1ex
+ \setbox\scratchbox\hbox{#1\scratchdimen\hbox{\dodohighlow#5}}%
+ \ht\scratchbox\strutheight
+ \dp\scratchbox\strutdepth
+ \box\scratchbox
+ \egroup}
+
+\unexpanded\def\high{\dohighlow\raise\mathsupnormal{.86}{0}}
+\unexpanded\def\low {\dohighlow\lower\mathsubnormal{.48}{0}}
+
+\unexpanded\def\lohi
+ {\dosingleempty\dolohi}
+
+\unexpanded\def\hilo
+ {\dosingleempty\dohilo}
+
+\def\dolohi[#1]#2#3%
+ {\dontleavehmode
+ \hbox
+ {\setbox4\hbox{\dohighlow\lower\mathsubnormal{.48}{.1}{#2}}%
+ \setbox6\hbox{\dohighlow\raise\mathsupnormal{.86}{.1}{#3}}%
+ \doif{#1}{\v!left}
+ {\ifdim\wd4<\wd6
+ \setbox4\hbox to \wd6{\hss\box4}%
+ \else
+ \setbox6\hbox to \wd4{\hss\box6}%
+ \fi}%
+ \ifdim\wd4<\wd6
+ \wd4=\zeropoint\box4\box6
+ \else
+ \wd6=\zeropoint\box6\box4
+ \fi}}
+
+\def\dohilo[#1]#2#3%
+ {\dolohi[#1]{#3}{#2}}
+
+%D You can provide an optional keyword \type {left}, in which
+%D case the super and subscripts will be aligned in a way that
+%D permits placement at the left of a word (which means that
+%D it will be right aligned).
+%D
+%D \startbuffer
+%D \lohi{aha}{ah} test \lohi{aha}{ah} test
+%D \lohi[left]{aha}{ah} test \lohi[left]{aha}{ah} test
+%D \lohi{aha}{ah} test\lohi{aha}{ah} test
+%D \lohi[left]{aha}{ah}test \lohi[left]{aha}{ah}test
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+%D \macros
+%D {setupinitial,placeinitial,checkinitial}
+%D
+%D {\em To be documented.}
+%D
+%D \starttyping
+%D \setupinitial[state=start] \placeinitial \input tufte
+%D \stoptyping
+%D
+%D and
+%D
+%D \starttyping
+%D \def\bpar{\ifvmode\checkinitial\fi}
+%D \def\epar{\ifhmode\par\fi\checkinitial}
+%D \stoptyping
+
+% to do: more fine tuning
+
+\unexpanded\def\setupinitial
+ {\dodoubleempty\getparameters[\??dc]}
+
+\definefontsynonym[Initial][Regular] % prefered initial identifier
+\definefontsynonym[initial][Initial] % internal but accepted too
+
+\setupinitial
+ [\c!state=\v!stop,
+ \c!location=\v!text,
+ \c!n=3,
+ \c!distance=.125em,
+ \c!command=,
+ \s!font=initial]
+
+\def\AutoDroppedCapsCommand{\NiceDroppedCaps\@@dccommand\@@dcfont\@@dcdistance\@@dcn}%
+
+\unexpanded\def\placeinitial
+ {\doifelse\@@dclocation\v!margin{\chardef\DropMode\plusone}{\chardef\DropMode\zerocount}%
+ \doif \@@dcstate\v!start{\ifcase\@@dcn\else\AutoDroppedCaps\fi}}
+
+\let\checkinitial\CheckDroppedCaps
+
+\protect \endinput
diff --git a/tex/context/base/core-gen.mkii b/tex/context/base/core-gen.mkii
new file mode 100644
index 000000000..b6ab2a208
--- /dev/null
+++ b/tex/context/base/core-gen.mkii
@@ -0,0 +1,166 @@
+%D \module
+%D [ file=core-gen,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=General,
+%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 Core Macros / General}
+
+\unprotect
+
+%D \macros
+%D {assigndimension,assignalfadimension}
+%D
+%D Hieronder worden enkele commando's gedefinieerd rond
+%D toekenningen. Allereerst een commando om waarden aan
+%D een \DIMENSION\ toe te kennen:
+%D
+%D \starttyping
+%D \assigndimension
+%D {|klein|middel|groot|-klein|-middel|-groot|geen}
+%D {\dimension}
+%D {waarde klein}
+%D {waarde middel}
+%D {waarde groot}
+%D \stoptyping
+%D
+%D Hierbij krijgt de \DIMENSION\ \type{\dimension} een waarde
+%D afhankelijk van het meegegeven trefwoord.
+%D
+%D \startnarrower
+%D \startlines
+%D \type{(-)klein }\qquad (--) waarde klein
+%D \type{(-)middel}\qquad (--) waarde middel
+%D \type{(-)groot }\qquad (--) waarde groot
+%D \type{geen }\qquad 0pt
+%D \type{waarde }\qquad waarde
+%D \stoplines
+%D \stopnarrower
+%D
+%D Een trefwoord mag worden voorafgegaan door een \type{-}.
+%D Deze macro toont een voorbeeld van het gebruik van
+%D \type{\processaction} en constanten.
+%D
+%D Analoog aan het bovenstaande commando kennen we een
+%D commando om waarden toe te kennen aan een macro:
+%D
+%D \starttyping
+%D \assignalfadimension
+%D {|klein|middel|groot|geen}
+%D {\macro}
+%D {waarde klein}
+%D {waarde middel}
+%D {waarde groot}
+%D \stoptyping
+
+% The third (optimized) version:
+
+\def\@ad@{@ad@}
+
+\setvalue{\@ad@ \v!none }{\zeropoint\gobblethreearguments}
+\setvalue{\@ad@ \v!big }{\thirdofthreearguments}
+\setvalue{\@ad@ \v!medium}{\secondofthreearguments}
+\setvalue{\@ad@ \v!small }{\firstofthreearguments}
+\setvalue{\@ad@-\v!big }{-\thirdofthreearguments}
+\setvalue{\@ad@-\v!medium}{-\secondofthreearguments}
+\setvalue{\@ad@-\v!small }{-\firstofthreearguments}
+
+\def\assigndimension#1#2% #3 #4 #5
+ {#2=\ifcsname\@ad@#1\endcsname
+ \csname\@ad@#1\expandafter\endcsname
+ \else
+ #1\expandafter\gobblethreearguments
+ \fi}
+
+\def\@aa@{@aa@}
+
+\setvalue{\@aa@\v!none }{0\gobblethreearguments}
+\setvalue{\@aa@\v!big }{\thirdofthreearguments}
+\setvalue{\@aa@\v!medium}{\secondofthreearguments}
+\setvalue{\@aa@\v!small }{\firstofthreearguments}
+
+\def\assignalfadimension#1#2#3#4#5% #3#4#5 are single digits
+ {\edef#2{\ifcsname\@aa@#1\endcsname
+ \csname\@aa@#1\expandafter\endcsname
+ \else
+ #1\expandafter\gobblethreearguments
+ \fi#3#4#5}}
+
+%D \macros
+%D {assignvalue}
+%D
+%D Een variant hierop is het commando:
+%D
+%D \starttyping
+%D \assignvalue
+%D {|klein|middel|groot}
+%D {\macro}
+%D {waarde klein }
+%D {waarde middel}
+%D {waarde groot}
+%D \stoptyping
+%D
+%D Hierbij krijgt \type{\macro} een waarde afhankelijk van
+%D het meegegeven trefwoord:
+%D
+%D \startnarrower
+%D \startlines
+%D \type{klein }\qquad waarde klein
+%D \type{middel}\qquad waarde middel
+%D \type{groot }\qquad waarde groot
+%D \type{waarde}\qquad waarde
+%D \stoplines
+%D \stopnarrower
+%D
+%D Hier doet \type{geen} dus niet mee.
+
+\def\@av@{@av@}
+
+\letvalue{\@av@\v!big }\thirdofthreearguments
+\letvalue{\@av@\v!medium}\secondofthreearguments
+\letvalue{\@av@\v!small }\firstofthreearguments
+
+\def\assignvalue#1#2#3#4#5%
+ {\edef#2{\ifcsname\@av@#1\endcsname
+ \csname\@av@#1\expandafter\endcsname
+ \else
+ #1\expandafter\gobblethreearguments
+ \fi{#3}{#4}{#5}}}
+
+%D \macros
+%D {assignwidth}
+%D
+%D Een breedte van een opgegeven tekst kan worden berekend en
+%D toegekend aan een \DIMENSION\ met:
+%D
+%D \starttyping
+%D \assignwidth
+%D {\dimension}
+%D {|passend|ruim}
+%D {tekst}
+%D \stoptyping
+%D
+%D Dit commando sluit, evenals de bovenstaande
+%D \type{\assign}||commando's, aan op de wijze waarop
+%D in de andere \CONTEXT||modules toekenningen
+%D plaatsvinden. Bij \type{ruim} wordt de gemeten breedte
+%D met 1~em vermeerderd.
+
+\def\assignwidth#1#2#3#4%
+ {\doifelsenothing{#2}
+ {\setbox\scratchbox\hbox{#3}%
+ #1\wd\scratchbox}
+ {\doifinsetelse{#2}{\v!fit,\v!broad}
+ {\setbox\scratchbox\hbox{#3}%
+ #1\wd\scratchbox
+ \doif{#2}\v!broad{\advance#1 #4}}%
+ {#1=#2}}}%
+
+\protect \endinput
diff --git a/tex/context/base/core-gen.mkiv b/tex/context/base/core-gen.mkiv
new file mode 100644
index 000000000..b6ab2a208
--- /dev/null
+++ b/tex/context/base/core-gen.mkiv
@@ -0,0 +1,166 @@
+%D \module
+%D [ file=core-gen,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=General,
+%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 Core Macros / General}
+
+\unprotect
+
+%D \macros
+%D {assigndimension,assignalfadimension}
+%D
+%D Hieronder worden enkele commando's gedefinieerd rond
+%D toekenningen. Allereerst een commando om waarden aan
+%D een \DIMENSION\ toe te kennen:
+%D
+%D \starttyping
+%D \assigndimension
+%D {|klein|middel|groot|-klein|-middel|-groot|geen}
+%D {\dimension}
+%D {waarde klein}
+%D {waarde middel}
+%D {waarde groot}
+%D \stoptyping
+%D
+%D Hierbij krijgt de \DIMENSION\ \type{\dimension} een waarde
+%D afhankelijk van het meegegeven trefwoord.
+%D
+%D \startnarrower
+%D \startlines
+%D \type{(-)klein }\qquad (--) waarde klein
+%D \type{(-)middel}\qquad (--) waarde middel
+%D \type{(-)groot }\qquad (--) waarde groot
+%D \type{geen }\qquad 0pt
+%D \type{waarde }\qquad waarde
+%D \stoplines
+%D \stopnarrower
+%D
+%D Een trefwoord mag worden voorafgegaan door een \type{-}.
+%D Deze macro toont een voorbeeld van het gebruik van
+%D \type{\processaction} en constanten.
+%D
+%D Analoog aan het bovenstaande commando kennen we een
+%D commando om waarden toe te kennen aan een macro:
+%D
+%D \starttyping
+%D \assignalfadimension
+%D {|klein|middel|groot|geen}
+%D {\macro}
+%D {waarde klein}
+%D {waarde middel}
+%D {waarde groot}
+%D \stoptyping
+
+% The third (optimized) version:
+
+\def\@ad@{@ad@}
+
+\setvalue{\@ad@ \v!none }{\zeropoint\gobblethreearguments}
+\setvalue{\@ad@ \v!big }{\thirdofthreearguments}
+\setvalue{\@ad@ \v!medium}{\secondofthreearguments}
+\setvalue{\@ad@ \v!small }{\firstofthreearguments}
+\setvalue{\@ad@-\v!big }{-\thirdofthreearguments}
+\setvalue{\@ad@-\v!medium}{-\secondofthreearguments}
+\setvalue{\@ad@-\v!small }{-\firstofthreearguments}
+
+\def\assigndimension#1#2% #3 #4 #5
+ {#2=\ifcsname\@ad@#1\endcsname
+ \csname\@ad@#1\expandafter\endcsname
+ \else
+ #1\expandafter\gobblethreearguments
+ \fi}
+
+\def\@aa@{@aa@}
+
+\setvalue{\@aa@\v!none }{0\gobblethreearguments}
+\setvalue{\@aa@\v!big }{\thirdofthreearguments}
+\setvalue{\@aa@\v!medium}{\secondofthreearguments}
+\setvalue{\@aa@\v!small }{\firstofthreearguments}
+
+\def\assignalfadimension#1#2#3#4#5% #3#4#5 are single digits
+ {\edef#2{\ifcsname\@aa@#1\endcsname
+ \csname\@aa@#1\expandafter\endcsname
+ \else
+ #1\expandafter\gobblethreearguments
+ \fi#3#4#5}}
+
+%D \macros
+%D {assignvalue}
+%D
+%D Een variant hierop is het commando:
+%D
+%D \starttyping
+%D \assignvalue
+%D {|klein|middel|groot}
+%D {\macro}
+%D {waarde klein }
+%D {waarde middel}
+%D {waarde groot}
+%D \stoptyping
+%D
+%D Hierbij krijgt \type{\macro} een waarde afhankelijk van
+%D het meegegeven trefwoord:
+%D
+%D \startnarrower
+%D \startlines
+%D \type{klein }\qquad waarde klein
+%D \type{middel}\qquad waarde middel
+%D \type{groot }\qquad waarde groot
+%D \type{waarde}\qquad waarde
+%D \stoplines
+%D \stopnarrower
+%D
+%D Hier doet \type{geen} dus niet mee.
+
+\def\@av@{@av@}
+
+\letvalue{\@av@\v!big }\thirdofthreearguments
+\letvalue{\@av@\v!medium}\secondofthreearguments
+\letvalue{\@av@\v!small }\firstofthreearguments
+
+\def\assignvalue#1#2#3#4#5%
+ {\edef#2{\ifcsname\@av@#1\endcsname
+ \csname\@av@#1\expandafter\endcsname
+ \else
+ #1\expandafter\gobblethreearguments
+ \fi{#3}{#4}{#5}}}
+
+%D \macros
+%D {assignwidth}
+%D
+%D Een breedte van een opgegeven tekst kan worden berekend en
+%D toegekend aan een \DIMENSION\ met:
+%D
+%D \starttyping
+%D \assignwidth
+%D {\dimension}
+%D {|passend|ruim}
+%D {tekst}
+%D \stoptyping
+%D
+%D Dit commando sluit, evenals de bovenstaande
+%D \type{\assign}||commando's, aan op de wijze waarop
+%D in de andere \CONTEXT||modules toekenningen
+%D plaatsvinden. Bij \type{ruim} wordt de gemeten breedte
+%D met 1~em vermeerderd.
+
+\def\assignwidth#1#2#3#4%
+ {\doifelsenothing{#2}
+ {\setbox\scratchbox\hbox{#3}%
+ #1\wd\scratchbox}
+ {\doifinsetelse{#2}{\v!fit,\v!broad}
+ {\setbox\scratchbox\hbox{#3}%
+ #1\wd\scratchbox
+ \doif{#2}\v!broad{\advance#1 #4}}%
+ {#1=#2}}}%
+
+\protect \endinput
diff --git a/tex/context/base/core-ini.mkii b/tex/context/base/core-ini.mkii
new file mode 100644
index 000000000..69edf9735
--- /dev/null
+++ b/tex/context/base/core-ini.mkii
@@ -0,0 +1,67 @@
+%D \module
+%D [ file=core-ini,
+%D version=2003.12.01,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Additional Initialization,
+%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 Core Macros / Additional Initialization}
+
+%D We will move more code to here, so that we become less dependent of the
+%D orde in which modules are loaded.
+
+\unprotect
+
+\everypar \emptytoks
+\neverypar \emptytoks
+
+\appendtoks \flushnotes \to \everypar
+\appendtoks \synchronizesidefloats \to \everypar
+
+\appendtoks \checkinlinedirection \to \everypar
+
+\appendtoks \checkindentation \to \everypar
+\appendtoks \showparagraphnumber \to \everypar
+\appendtoks \flushmargincontents \to \everypar
+\appendtoks \flushcommentanchors \to \everypar
+\appendtoks \synchronizenotes \to \everypar
+\appendtoks \OTRSETshowstatus \to \everypar
+\appendtoks \flushpostponedbookmark \to \everypar
+\appendtoks \registerparoptions \to \everypar
+\appendtoks \flushsyncpositions \to \everypar
+\appendtoks \flushpostponednodedata \to \everypar
+\appendtoks \dohandlerepeatdelimitedtext \to \everypar
+\appendtoks \insertparagraphintro \to \everypar
+
+\appendtoks \flushpostponedbookmark \to \neverypar
+\appendtoks \flushpostponedbookmark \to \everylistentry
+
+\appendtoks \flushnotes \to \everydisplay
+\appendtoks \adjustsidefloatdisplaylines \to \everydisplay
+
+\appendtoks \flushsyncpositions \to \everyheadstart
+
+\appendtoks \flushsyncresets \to \everyendoftextbody
+
+\appendtoks \ignorespaces \to \everybeginofpar
+
+\appendtoks \removeunwantedspaces \to \everyendofpar
+%appendtoks \strut \to \everyendofpar % option ?
+\appendtoks \flushsyncresets \to \everyendofpar
+\appendtoks \setlastlinewidth \to \everyendofpar % must happen before endgraf
+\appendtoks \endgraf \to \everyendofpar
+
+% Todo: verbatim, xml, tex, move code to here
+
+\ifx\normalcompound\undefined \let\normalcompound=| \fi
+
+\appendtoks \catcode`|=\@@active \let|\normalcompound \to \everyTEXinputmode
+\appendtoks \catcode`|=\@@letter \to \everyXMLinputmode
+
+\protect \endinput
diff --git a/tex/context/base/core-ini.mkiv b/tex/context/base/core-ini.mkiv
new file mode 100644
index 000000000..d6a72bb26
--- /dev/null
+++ b/tex/context/base/core-ini.mkiv
@@ -0,0 +1,66 @@
+%D \module
+%D [ file=core-ini,
+%D version=2003.12.01,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Additional Initialization,
+%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 Core Macros / Additional Initialization}
+
+%D We will move more code to here, so that we become less dependent of the
+%D orde in which modules are loaded.
+
+\unprotect
+
+\everypar \emptytoks
+\neverypar \emptytoks
+
+\appendtoks \flushnotes \to \everypar
+\appendtoks \synchronizesidefloats \to \everypar
+
+\appendtoks \checkindentation \to \everypar
+\appendtoks \showparagraphnumber \to \everypar
+\appendtoks \restoreinterlinepenalty \to \everypar
+\appendtoks \flushmargincontents \to \everypar
+\appendtoks \flushcommentanchors \to \everypar
+\appendtoks \synchronizenotes \to \everypar
+\appendtoks \OTRSETshowstatus \to \everypar
+\appendtoks \flushpostponedbookmark \to \everypar
+\appendtoks \registerparoptions \to \everypar
+\appendtoks \flushsyncpositions \to \everypar
+\appendtoks \flushpostponednodedata \to \everypar
+\appendtoks \dohandlerepeatdelimitedtext \to \everypar
+\appendtoks \insertparagraphintro \to \everypar
+
+\appendtoks \flushpostponedbookmark \to \neverypar
+\appendtoks \flushpostponedbookmark \to \everylistentry
+
+\appendtoks \flushnotes \to \everydisplay
+\appendtoks \adjustsidefloatdisplaylines \to \everydisplay
+
+\appendtoks \flushsyncpositions \to \everyheadstart
+
+\appendtoks \flushsyncresets \to \everyendoftextbody
+
+\appendtoks \ignorespaces \to \everybeginofpar
+
+\appendtoks \removeunwantedspaces \to \everyendofpar
+%appendtoks \strut \to \everyendofpar % option ?
+\appendtoks \flushsyncresets \to \everyendofpar
+%appendtoks \setlastlinewidth \to \everyendofpar % gone, will be done in lua
+\appendtoks \endgraf \to \everyendofpar
+
+% Todo: verbatim, xml, tex, move code to here
+
+\ifx\normalcompound\undefined \let\normalcompound=| \fi
+
+\appendtoks \catcode`|=\@@active \let|\normalcompound \to \everyTEXinputmode
+\appendtoks \catcode`|=\@@letter \to \everyXMLinputmode
+
+\protect \endinput
diff --git a/tex/context/base/core-job.lua b/tex/context/base/core-job.lua
new file mode 100644
index 000000000..d557818bb
--- /dev/null
+++ b/tex/context/base/core-job.lua
@@ -0,0 +1,202 @@
+if not modules then modules = { } end modules ['core-job'] = {
+ version = 1.001,
+ comment = "companion to core-job.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local texsprint, texprint, texwrite = tex.sprint, tex.print, tex.write
+local ctxcatcodes, texcatcodes = tex.ctxcatcodes, tex.texcatcodes
+local lower, format, find, gmatch, gsub, match = string.lower, string.format, string.find, string.gmatch, string.gsub, string.match
+local concat = table.concat
+
+-- main code
+
+resolvers.maxreadlevel = 3
+
+directives.register("resolvers.maxreadlevel", function(v) resolvers.maxreadlevel = tonumber(v) or resolvers.maxreadlevel end)
+
+local function exists(n)
+ if io.exists(n) then
+ return n
+ else
+ n = file.addsuffix(n,'tex')
+ if io.exists(n) then
+ return n
+ end
+ end
+ return nil
+end
+
+function resolvers.findctxfile(name,maxreadlevel)
+ if file.is_qualified_path(name) then
+ return name
+ else
+ -- not that efficient, too many ./ lookups
+ local n = "./" .. name
+ local found = exists(n)
+ if found then
+ return found
+ else
+ for i=1,maxreadlevel or resolvers.maxreadlevel or 0 do
+ n = "../" .. n
+ found = exists(n)
+ if found then
+ return found
+ end
+ end
+ end
+ return resolvers.find_file(name) or ""
+ end
+end
+
+function commands.maxreadlevel()
+ texwrite(resolvers.maxreadlevel)
+end
+
+function commands.processfile(name,maxreadlevel)
+ name = resolvers.findctxfile(name,maxreadlevel)
+ if name ~= "" then
+ texsprint(ctxcatcodes,format("\\input %s\\relax",name)) -- we need \input {name}
+ end
+end
+
+function commands.doifinputfileelse(name,maxreadlevel)
+ commands.doifelse(resolvers.findctxfile(name,maxreadlevel) ~= "")
+end
+
+function commands.locatefilepath(name,maxreadlevel)
+ texsprint(texcatcodes,file.dirname(resolvers.findctxfile(name,maxreadlevel)))
+end
+
+function commands.usepath(paths,maxreadlevel)
+ resolvers.register_extra_path(paths)
+ texsprint(texcatcodes,concat(resolvers.instance.extra_paths or {}, ""))
+end
+
+function commands.usesubpath(subpaths,maxreadlevel)
+ resolvers.register_extra_path(nil,subpaths)
+ texsprint(texcatcodes,concat(resolvers.instance.extra_paths or {}, ""))
+end
+
+function commands.usezipfile(name,tree)
+ if tree and tree ~= "" then
+ resolvers.usezipfile(format("zip:///%s?tree=%s",name,tree))
+ else
+ resolvers.usezipfile(format("zip:///%s",name))
+ end
+end
+
+-- for the moment here, maybe a module
+
+--~
+--~
+--~ nee
+--~ standaard
+--~
+
+local function convertexamodes(str)
+ local x = xml.convert(str)
+ for e in xml.collected(x,"exa:variable") do
+ local label = e.at and e.at.label
+ if label and label ~= "" then
+ local data = xml.text(e)
+ local mode = match(label,"^mode:(.+)$")
+ if mode then
+ texsprint(ctxcatcodes,format("\\enablemode[%s:%s]",mode,data))
+ end
+ texsprint(ctxcatcodes,format("\\setvariable{exa:variables}{%s}{%s}",label,gsub(data,"([{}])","\\%1")))
+ end
+ end
+end
+
+-- we need a system file option: ,. .. etc + paths but no tex lookup so resolvers.find_file is wrong here
+
+function commands.loadexamodes(filename)
+ if not filename or filename == "" then
+ filename = file.removesuffix(tex.jobname)
+ end
+ filename = resolvers.find_file(file.addsuffix(filename,'ctm')) or ""
+ if filename ~= "" then
+ commands.writestatus("examodes","loading %s",filename) -- todo: message system
+ convertexamodes(io.loaddata(filename))
+ else
+ commands.writestatus("examodes","no mode file %s",filename) -- todo: message system
+ end
+end
+
+function commands.logoptionfile(name)
+ -- todo: xml if xml logmode
+ local f = io.open(name)
+ if f then
+ texio.write_nl("log","%\n%\tbegin of optionfile\n%\n")
+ for line in f:lines() do
+ texio.write("log",format("%%\t%s\n",line))
+ end
+ texio.write("log","%\n%\tend of optionfile\n%\n")
+ f:close()
+ end
+end
+
+--~ set functions not ok and not faster on mk runs either
+--~
+--~ local function doifcommonelse(a,b)
+--~ local ba = find(a,",")
+--~ local bb = find(b,",")
+--~ if ba and bb then
+--~ for sa in gmatch(a,"[^ ,]+") do
+--~ for sb in gmatch(b,"[^ ,]+") do
+--~ if sa == sb then
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",sa,"}")
+--~ return true
+--~ end
+--~ end
+--~ end
+--~ elseif ba then
+--~ for sa in gmatch(a,"[^ ,]+") do
+--~ if sa == b then
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",b,"}")
+--~ return true
+--~ end
+--~ end
+--~ elseif bb then
+--~ for sb in gmatch(b,"[^ ,]+") do
+--~ if a == sb then
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",a,"}")
+--~ return true
+--~ end
+--~ end
+--~ else
+--~ if a == b then
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",a,"}")
+--~ return true
+--~ end
+--~ end
+--~ texsprint(ctxcatcodes,"\\let\\commalistelement\\empty")
+--~ return false
+--~ end
+--~ local function doifinsetelse(a,b)
+--~ local bb = find(b,",")
+--~ if bb then
+--~ for sb in gmatch(b,"[^ ,]+") do
+--~ if a == sb then
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",a,"}")
+--~ return true
+--~ end
+--~ end
+--~ else
+--~ if a == b then
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",a,"}")
+--~ return true
+--~ end
+--~ end
+--~ texsprint(ctxcatcodes,"\\let\\commalistelement\\empty")
+--~ return false
+--~ end
+--~ function commands.doifcommon (a,b) commands.doif (doifcommonelse(a,b)) end
+--~ function commands.doifnotcommon (a,b) commands.doifnot (doifcommonelse(a,b)) end
+--~ function commands.doifcommonelse(a,b) commands.doifelse(doifcommonelse(a,b)) end
+--~ function commands.doifinset (a,b) commands.doif (doifinsetelse(a,b)) end
+--~ function commands.doifnotinset (a,b) commands.doifnot (doifinsetelse(a,b)) end
+--~ function commands.doifinsetelse (a,b) commands.doifelse(doifinsetelse(a,b)) end
diff --git a/tex/context/base/core-job.mkii b/tex/context/base/core-job.mkii
new file mode 100644
index 000000000..5c280c15b
--- /dev/null
+++ b/tex/context/base/core-job.mkii
@@ -0,0 +1,415 @@
+%D \module
+%D [ file=core-job, % copied from main-001,
+%D version=1997.03.31,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Job Handling,
+%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.
+
+%D This module is still to be split and documented.
+
+\writestatus{loading}{ConTeXt Core Macros / Job Handling}
+
+\unprotect
+
+\let \currentproject \empty
+\let \currentproduct \empty
+\let \currentenvironment \empty
+\let \currentcomponent \empty
+
+\let \loadedfiles \empty
+\let \processedfiles \empty
+
+\let \nomorefiles \relax
+
+\let \allinputpaths \empty
+\let \locatedfilepath \empty
+
+\newcount\textlevel
+\newcount\fileprocesslevel
+
+\setvalue{\c!file::0}{\jobname}
+
+\def\processedfile % is used in styles, don't change !
+ {\getvalue{\c!file::\number\fileprocesslevel}}
+
+\def\dostarttextfile#1%
+ {\global\advance\fileprocesslevel\plusone
+ \setxvalue{\c!file::\number\fileprocesslevel}{#1}%
+ \@EA\doglobal\@EA\addtocommalist\@EA{#1}\processedfiles}
+
+\def\dostoptextfile
+ {\global\advance\fileprocesslevel\minusone}
+
+\def\processlocalfile#1#2%
+ {#1{#2}\donothing{\readfile{#2}\donothing\donothing}}
+
+\def\processfile#1%
+ {\ifx\allinputpaths\empty
+ \def\next{\processlocalfile\readlocfile}%
+ \else
+ \let\filepath\empty
+ \def\docommand##1%
+ {\doiffileelse{\pathplusfile{##1}{#1}}{\donetrue\def\filepath{##1}}\donefalse
+ \ifdone\expandafter\quitcommalist\fi}%
+ \doifparentfileelse{#1} % new
+ {\processcommacommand [\allinputpaths]\docommand}
+ {\processcommacommand[.,\allinputpaths]\docommand}%
+ \ifx\filepath\empty
+ \def\next{\processlocalfile\readlocfile}% fall back ../../..
+ \else
+ \def\next{\processlocalfile{\readsetfile\filepath}}% file found
+ \fi
+ \fi
+ \next{#1}}
+
+\def\doifinputfileelse#1% rarely used
+ {\ifx\allinputpaths\empty
+ \@EA\secondoftwoarguments
+ \else
+ \let\filepath\empty
+ \def\docommand##1%
+ {\doiffileelse{\pathplusfile{##1}{#1}}{\donetrue\def\filepath{##1}}\donefalse
+ \ifdone\expandafter\quitcommalist\fi}%
+ \processcommacommand[.,\allinputpaths]\docommand
+ \ifx\filepath\empty
+ \@EAEAEA\secondoftwoarguments
+ \else
+ \@EAEAEA\firstoftwoarguments
+ \fi
+ \fi}
+
+\let\locatedfilepath\empty
+
+\def\locatefilepath#1%
+ {\let\locatedfilepath\empty
+ \ifx\allinputpaths\empty \else
+ \def\docommand##1%
+ {\doiffileelse{\pathplusfile{##1}{#1}}{\donetrue\def\locatedfilepath{##1}}\donefalse
+ \ifdone\expandafter\quitcommalist\fi}%
+ \doifparentfileelse{#1} % new
+ {\processcommacommand [\allinputpaths]\docommand}
+ {\processcommacommand[.,\allinputpaths]\docommand}%
+ \fi}
+
+\def\usepath[#1]%
+ {\def\docommand##1%
+ {\doifelse{##1}\v!reset
+ {\let\allinputpaths\empty}
+ {\sanitizefilename#1\to\ascii
+ \defconvertedcommand\ascii\ascii
+ \addtocommalist\ascii\allinputpaths}}%
+ \processcommalist[#1]\docommand}
+
+\def\usesubpath[#1]% test for a real long time, permits ../{name} i.e. braces
+ {\ifx\allinputpaths\empty
+ \sanitizefilename#1\to\allinputpaths
+ \else
+ \def\docommand##1%
+ {\def\dodocommand####1%
+ {\sanitizefilename####1\to\ascii
+ \defconvertedcommand\ascii\ascii
+ \addtocommalist{##1/\ascii}\allinputpaths}%
+ \processcommalist[#1]\dodocommand}%
+ \processcommacommand[\allinputpaths]\docommand
+ \fi}
+
+\def\registerfileinfo[#1#2]#3% geen \showmessage ?
+ {\writestatus\m!systems{#1#2 file #3 at line \the\inputlineno}%
+ \immediatewriteutility{f #1 {#3}}}
+
+\ifx\preloadfonts \undefined \let\preloadfonts \relax \fi
+\ifx\preloadspecials\undefined \let\preloadspecials\relax \fi
+
+\def\loadallsystemfiles#1#2%
+ {\ifx\@@svdirectory\empty
+ \readsysfile{#1}{\showmessage\m!systems2{#1}}{#2}%
+ \else% yet undocumented
+ \def\doloadsystemfile##1%
+ {\readsetfile{##1}{#1}{\showmessage\m!systems2{#1}}{#2}}%
+ \processcommacommand[\@@svdirectory]\doloadsystemfile
+ \fi}
+
+\ifx\disableXML\undefined \let\disableXML\relax \fi
+
+\def\loadsystemfiles
+ {\reportprotectionstate
+ \readsysfile\f!newfilename{\showmessage\m!systems2\f!newfilename}\donothing
+ %\readsysfile\f!oldfilename{\showmessage\m!systems2\f!oldfilename}\donothing
+ \loadallsystemfiles\f!filfilename
+ \donothing
+ \loadallsystemfiles\f!sysfilename
+ {\loadallsystemfiles{\f!sysfilename.rme}\donothing % new, fall back
+ \doglobal\appendtoks % brrr better \setcatcodetable\ctxcatcodes % % test
+ \bgroup\disableXML\loadallsystemfiles\f!errfilename\donothing\egroup
+ \to\everygoodbye}}
+
+%D Loading of \type {cont-usr.tex} (edited by the user)
+%D and \type {cont-fmt.tex} (generated by texexec).
+
+\def\loaduserspecifications
+ {% this used to be the file where users can tune their system, especially patterns
+ \readsysfile\f!usrfilename{\showmessage\m!systems2\f!usrfilename}\donothing
+ % this one took care of user preferences (fonts, messages) but lm made this obsolete
+ \readjobfile\f!fmtfilename{\showmessage\m!systems2\f!fmtfilename}\donothing
+ % from now on we preload all patterns (only in mkii)
+ \preloadallpatterns}
+
+\let\loaduserspecifications\relax
+
+%D We don't want multiple jobfiles to interfere.
+
+\def\loadoptionfile
+ {\readjobfile{\jobname.\f!optionextension}
+ {\showmessage\m!systems2{\jobname.\f!optionextension}}%
+ {\writestatus\m!systems {no \jobname.\f!optionextension}}}
+
+% Most natural ...
+%
+% \def\doateverystarttext
+% {\the\everystarttext
+% \global\let\doateverystarttext\relax}
+%
+% ... most practical, since we can load env's in a
+% something.run file (nested \starttext's; see for
+% instance x-res-08, where we definitely want to
+% open the file!).
+
+\def\doateverystarttext
+ {\the\everystarttext
+ \global\everystarttext\emptytoks}
+
+\def\starttext
+ {\doateverystarttext
+ \ifcase\textlevel
+ \registerfileinfo[begin]\jobname
+ \expandafter\startcopyingblocks
+ \fi
+ \global\advance\textlevel\plusone}
+
+\def\stoptext
+ {\global\advance\textlevel\minusone
+ \ifnum\textlevel>\zerocount \else
+ \page[\v!last]\page % new, moved from everybye to here; flushes headers, colors etc etc etc
+ \the\everystoptext
+ %\the\everybye %
+ %\the\everygoodbye % == \end (new)
+ %\expandafter\normalend %
+ \expandafter\finalend
+ \fi}
+
+\def\forcequitjob#1%
+ {\writestatus\m!systems{forcing quit: #1}%
+ \batchmode
+ \dorecurse\textlevel\stoptext
+ \normalend}
+
+\let\autostoptext\relax
+
+\def\autostarttext
+ {\ifcase\textlevel
+ \starttext
+ \writestatus\m!systems{auto \string\starttext..\string\stoptext}%
+ \let\autostoptext\stoptext
+ \fi}
+
+\def\finalend
+ {\ifnum\textlevel>\zerocount \else
+ \the\everybye
+ \the\everygoodbye
+ \doifsometokselse\everynotabene{\writeline\the\everynotabene\writeline}\donothing
+ \global\everybye \emptytoks % rather unneeded
+ \global\everygoodbye\emptytoks % but for sure
+ \expandafter\normalend
+ \fi}
+
+\let\end\finalend
+
+\def\emergencyend
+ {\writestatus\m!systems{invalid \@EA\string\csname\e!start\v!text\endcsname...\@EA\string\csname\e!stop\v!text\endcsname\space structure}%
+ \stoptext}
+
+\def\currentfile{\inputfilename}
+
+\def\doexecutefileonce#1%
+ {\beforesplitstring#1\at.\to\currentfile
+ \fullexpandtwoargsafter\doifnotinset\currentfile\loadedfiles
+ {\fullexpandoneargafter\addtocommalist\currentfile\loadedfiles
+ \doexecutefile{#1}}}
+
+\def\doexecutefile#1%
+ {\registerfileinfo[begin]{#1}%
+ \dostarttextfile{#1}%
+ \processfile{#1}%
+ \dostoptextfile
+ \registerfileinfo[end]{#1}}
+
+\def\donotexecutefile#1%
+ {}
+
+\def\verwerkfile#1 %
+ {\doexecutefile{#1}}
+
+\def\useenvironment[#1]% maybe commalist
+ {\environment #1 \relax}
+
+\def\environment #1 % at outermost level only (load only once)
+ {\pushmacro\startenvironment
+ \pushmacro\stopenvironment
+ \def\startenvironment ##1 {}%
+ \let\stopenvironment\relax
+ \startreadingfile
+ \doexecutefileonce{#1}
+ \stopreadingfile
+ \popmacro\stopenvironment
+ \popmacro\startenvironment}
+
+\def\component #1 % at outermost level only
+ {\dostarttextfile{#1}%
+ \processfile{#1}%
+ \dostoptextfile}
+
+\newcount\filelevel
+
+\let\currentcomponent \v!text
+\let\currentcomponentpath\f!currentpath
+
+\def\donextlevel#1#2#3#4#5#6#7\\%
+ {\pushmacro\currentcomponent
+ \pushmacro\currentcomponentpath
+ \let\currentcomponent#1%
+ \setsystemmode\currentcomponent
+ \splitfilename{#1}%
+ \ifx\splitoffpath\empty
+ \let\currentcomponentpath\f!currentpath
+ \else
+ \let\currentcomponentpath\splitoffpath
+ \fi
+ \beforesplitstring#7\at.\to#2\relax % can become path + base
+ \ifcase\filelevel\relax
+ \starttext
+ \def\project ##1 {#3{##1}}%
+ \def\environment ##1 {#4{##1}}%
+ \def\product ##1 {#5{##1}}%
+ \def\component ##1 {#6{##1}}%
+ \fi
+ \advance\filelevel\plusone
+ \fullexpandoneargafter\addtocommalist{#1}\loadedfiles}
+
+\def\doprevlevel
+ {\popmacro\currentcomponentpath
+ \popmacro\currentcomponent
+ \setsystemmode\currentcomponent
+ \ifnum\filelevel=\plusone
+ \expandafter\stoptext
+ \else
+ \advance\filelevel\minusone
+ \expandafter\endinput
+ \fi}
+
+\def\startproject #1 %
+ {\donextlevel\v!project\currentproject
+ \donotexecutefile\doexecutefileonce
+ \doexecutefileonce\doexecutefile#1\\}
+
+\def\startproduct #1 %
+ {\doateverystarttext
+ \donextlevel\v!product\currentproduct
+ \doexecutefileonce\doexecutefileonce
+ \donotexecutefile\doexecutefile#1\\}
+
+\def\startcomponent #1 %
+ {\doateverystarttext
+ \donextlevel\v!component\currentcomponent
+ \doexecutefileonce\doexecutefileonce
+ \donotexecutefile\doexecutefile#1\\}
+
+\def\startenvironment #1 %
+ {\donextlevel\v!environment\currentenvironment
+ \donotexecutefile\doexecutefileonce
+ \donotexecutefile\donotexecutefile#1\\}
+
+% \startproject test
+% 1: \startmode[*project] project \stopmode \endgraf
+% 2: \startmode[*product] product \stopmode \endgraf
+% \stopproject
+
+\def\stopproject {\doprevlevel}
+\def\stopproduct {\doprevlevel}
+\def\stopcomponent {\doprevlevel}
+\def\stopenvironment{\doprevlevel}
+
+% more or less replaced by modes
+
+\setvalue{\e!start\v!localenvironment}[#1]%
+ {\let\loadedlocalenvironments\empty
+ \def\docommand##1%
+ {\beforesplitstring##1\at.\to\someevironment
+ \fullexpandoneargafter\addtocommalist\someevironment\loadedlocalenvironments}%
+ \processcommalist[#1]\docommand
+ \fullexpandtwoargsafter\doifcommonelse % no longer next needed
+ {\currentproject,\currentproduct,%
+ \currentcomponent,\currentenvironment}
+ {\loadedlocalenvironments}
+ {\letvalue{\e!stop\v!localenvironment}\relax}
+ {\grabuntil{\e!stop\v!localenvironment}\gobbleoneargument}} % TH: fixed, was \relax
+
+\setvalue{\v!localenvironment}#1 {\doexecutefileonce{#1}}
+
+% NOT TOEVOEGEN: \the\everytrace
+
+\neverypar=\emptytoks
+
+% \appendtoks \flushnotes \to \everypar
+% \appendtoks \synchronizesidefloats \to \everypar
+% \appendtoks \checkindentation \to \everypar
+% \appendtoks \showparagraphnumber \to \everypar
+% \appendtoks \flushmargincontents \to \everypar
+% \appendtoks \flushcommentanchors \to \everypar
+% \appendtoks \synchronizenotes \to \everypar
+
+% \appendtoks \flushnotes \to \everydisplay
+% \appendtoks \adjustsidefloatdisplaylines \to \everydisplay
+
+% soon, when pdftex 1.22 is out in the field:
+
+\chardef\systemcommandmode\zerocount % 0=unknown 1=disabled 2=enabled
+
+\def\checksystemcommandmode
+ {\ifx\pdfshellescape\undefined \else
+ \chardef\systemcommandmode \ifcase\pdfshellescape \plusone \else \plustwo \fi
+ \fi
+ \global\let\checksystemcommandmode\relax}
+
+\def\reportsystemcommandmode
+ {\ifcase\systemcommandmode
+ \or
+ \writestatus\m!systems{system commands are disabled}%
+ \or
+ \writestatus\m!systems{system commands are enabled}%
+ \fi}
+
+% \ifx\etexversion\undefined \else \ifnum\etexversion<202
+% \prependtoks
+% \writestatus\m!systems{eTeX version \number\etexversion\space -> too old (bugs)}%
+% \writeline
+% \to \everyjob
+% \fi \fi
+
+% \ifx\pdftexversion\undefined \else \ifnum\number\pdftexversion<120
+% \prependtoks
+% \writestatus\m!systems{pdfTeX version \number\pdftexversion\space -> please update}%
+% \writeline
+% \to \everyjob
+% \fi \fi
+
+% Default-instellingen (verborgen)
+
+\resetutilities
+
+\protect \endinput
diff --git a/tex/context/base/core-job.mkiv b/tex/context/base/core-job.mkiv
new file mode 100644
index 000000000..de328c92b
--- /dev/null
+++ b/tex/context/base/core-job.mkiv
@@ -0,0 +1,309 @@
+%D \module
+%D [ file=core-job, % copied from main-001,
+%D version=1997.03.31,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Job Handling,
+%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.
+
+%D This module is still to be split and documented.
+
+\writestatus{loading}{ConTeXt Core Macros / Job Handling}
+
+\unprotect
+
+\registerctxluafile{core-job}{1.001}
+
+\let \currentproject \empty
+\let \currentproduct \empty
+\let \currentenvironment \empty
+\let \currentcomponent \empty
+
+\let \loadedfiles \empty
+\let \processedfiles \empty
+
+\let \nomorefiles \relax
+
+\let \allinputpaths \empty
+\let \locatedfilepath \empty
+
+\newcount\textlevel
+\newcount\fileprocesslevel
+
+\setvalue{\c!file::0}{\jobname}
+
+\def\processedfile % is used in styles, don't change !
+ {\getvalue{\c!file::\number\fileprocesslevel}}
+
+\def\dostarttextfile#1%
+ {\global\advance\fileprocesslevel\plusone
+ \setxvalue{\c!file::\number\fileprocesslevel}{#1}%
+ \@EA\doglobal\@EA\addtocommalist\@EA{#1}\processedfiles}
+
+\def\dostoptextfile
+ {\global\advance\fileprocesslevel\minusone}
+
+\def\processlocalfile#1#2%
+ {#1{#2}\donothing{\readfile{#2}\donothing\donothing}}
+
+\def\processfile #1{\ctxlua{commands.processfile("#1")}}
+\def\doifinputfileelse #1{\ctxlua{commands.doifinputfileelse("#1")}}
+\def\locatefilepath #1{\edef\locatedfilepath{\ctxlua{commands.locatefilepath("#1")}}}
+\def\usepath [#1]{\edef\allinputpaths{\ctxlua{commands.usepath("#1")}}}
+\def\usesubpath [#1]{\edef\allinputpaths{\ctxlua{commands.usesubpath("#1")}}}
+\def\usezipfile {\dodoubleempty\dousezipfile}
+\def\dousezipfile[#1][#2]{\ctxlua{commands.usezipfile("#1","#2")}} % [filename] [optional subtree]
+
+\def\loadexamodes {\dosingleempty\doloadexamodes}
+\def\doloadexamodes [#1]{\ctxlua{commands.loadexamodes("#1")}}
+
+\def\registerfileinfo[#1#2]#3% geen \showmessage ?
+ {\writestatus\m!systems{#1#2 file #3 at line \the\inputlineno}}
+
+\ifx\preloadfonts \undefined \let\preloadfonts \relax \fi
+\ifx\preloadspecials\undefined \let\preloadspecials\relax \fi
+
+\def\loadallsystemfiles#1#2%
+ {\ifx\@@svdirectory\empty
+ \readsysfile{#1}{\showmessage\m!systems2{#1}}{#2}%
+ \else% yet undocumented
+ \def\doloadsystemfile##1%
+ {\readsetfile{##1}{#1}{\showmessage\m!systems2{#1}}{#2}}%
+ \processcommacommand[\@@svdirectory]\doloadsystemfile
+ \fi}
+
+\ifx\disableXML\undefined \let\disableXML\relax \fi
+
+\def\loadsystemfiles
+ {\reportprotectionstate
+ \readsysfile\f!newfilename{\showmessage\m!systems2\f!newfilename}\donothing
+ %\readsysfile\f!oldfilename{\showmessage\m!systems2\f!oldfilename}\donothing
+ \loadallsystemfiles\f!filfilename
+ \donothing
+ \loadallsystemfiles\f!sysfilename
+ {\loadallsystemfiles{\f!sysfilename.rme}\donothing % new, fall back
+ \doglobal\appendtoks % brrr better \setcatcodetable\ctxcatcodes % % test
+ \bgroup\disableXML\loadallsystemfiles\f!errfilename\donothing\egroup
+ \to\everygoodbye}}
+
+%D We don't want multiple jobfiles to interfere.
+
+\def\loadoptionfile
+ {\readjobfile{\jobname.\f!optionextension}
+ {\showmessage\m!systems2{\jobname.\f!optionextension}%
+ \ctxlua{commands.logoptionfile("\jobname.\f!optionextension")}}%
+ {\writestatus\m!systems {no \jobname.\f!optionextension}}}
+
+% Most natural ...
+%
+% \def\doateverystarttext
+% {\the\everystarttext
+% \global\let\doateverystarttext\relax}
+%
+% ... most practical, since we can load env's in a
+% something.run file (nested \starttext's; see for
+% instance x-res-08, where we definitely want to
+% open the file!).
+
+\def\doateverystarttext
+ {\the\everystarttext
+ \global\everystarttext\emptytoks}
+
+\unexpanded\def\starttext
+ {\doateverystarttext
+ \ifcase\textlevel
+ \registerfileinfo[begin]\jobfilename
+ \fi
+ \global\advance\textlevel\plusone}
+
+\unexpanded\def\stoptext
+ {\global\advance\textlevel\minusone
+ \ifnum\textlevel>\zerocount \else
+ \flushfinallayoutpage % optional
+ \page % anyway
+ \the\everystoptext
+ %\the\everybye %
+ %\the\everygoodbye % == \end (new)
+ %\expandafter\normalend %
+\ifcase\textlevel
+ \registerfileinfo[end]\jobfilename
+\fi
+ \expandafter\finalend
+ \fi}
+
+\def\forcequitjob#1%
+ {\writestatus\m!systems{forcing quit: #1}%
+ \batchmode
+ \dorecurse\textlevel{\stoptext}
+ \normalend}
+
+\let\autostoptext\relax
+
+\def\autostarttext
+ {\ifcase\textlevel
+ \starttext
+ \writestatus\m!systems{auto \string\starttext..\string\stoptext}%
+ \let\autostoptext\stoptext
+ \fi}
+
+\def\finalend
+ {\ifnum\textlevel>\zerocount \else
+ \the\everybye
+ \the\everygoodbye
+ \doifsometokselse\everynotabene{\writeline\the\everynotabene\writeline}\donothing
+ \global\everybye \emptytoks % rather unneeded
+ \global\everygoodbye\emptytoks % but for sure
+ \expandafter\normalend
+ \fi}
+
+\let\end\finalend
+
+\def\emergencyend
+ {\writestatus\m!systems{invalid \@EA\string\csname\e!start\v!text\endcsname...\@EA\string\csname\e!stop\v!text\endcsname\space structure}%
+ \stoptext}
+
+\def\currentfile{\inputfilename}
+
+\def\doexecutefileonce#1%
+ {\beforesplitstring#1\at.\to\currentfile
+ \fullexpandtwoargsafter\doifnotinset\currentfile\loadedfiles
+ {\fullexpandoneargafter\addtocommalist\currentfile\loadedfiles
+ \doexecutefile{#1}}}
+
+\def\doexecutefile#1%
+ {\registerfileinfo[begin]{#1}%
+ \dostarttextfile{#1}%
+ \processfile{#1}%
+ \dostoptextfile
+ \registerfileinfo[end]{#1}}
+
+\def\donotexecutefile#1%
+ {}
+
+\def\useenvironment[#1]% maybe commalist
+ {\environment #1 \relax}
+
+\def\environment #1 % at outermost level only (load only once)
+ {\pushmacro\startenvironment
+ \pushmacro\stopenvironment
+ \unexpanded\def\startenvironment ##1 {}%
+ \let\stopenvironment\relax
+ \startreadingfile
+ \doexecutefileonce{#1}
+ \stopreadingfile
+ \popmacro\stopenvironment
+ \popmacro\startenvironment}
+
+\def\component #1 % at outermost level only
+ {\dostarttextfile{#1}%
+ \processfile{#1}%
+ \dostoptextfile}
+
+\newcount\filelevel
+
+\let\currentcomponent \v!text
+\let\currentcomponentpath\f!currentpath
+
+\def\donextlevel#1#2#3#4#5#6#7\\%
+ {\pushmacro\currentcomponent
+ \pushmacro\currentcomponentpath
+ \let\currentcomponent#1%
+ \setsystemmode\currentcomponent
+ \splitfilename{#1}%
+ \ifx\splitoffpath\empty
+ \let\currentcomponentpath\f!currentpath
+ \else
+ \let\currentcomponentpath\splitoffpath
+ \fi
+ \beforesplitstring#7\at.\to#2\relax % can become path + base
+ \ifcase\filelevel\relax
+ \starttext
+ \def\project ##1 {#3{##1}}%
+ \def\environment ##1 {#4{##1}}%
+ \def\product ##1 {#5{##1}}%
+ \def\component ##1 {#6{##1}}%
+ \fi
+ \advance\filelevel\plusone
+ \fullexpandoneargafter\addtocommalist{#1}\loadedfiles}
+
+\def\doprevlevel
+ {\popmacro\currentcomponentpath
+ \popmacro\currentcomponent
+ \setsystemmode\currentcomponent
+ \ifnum\filelevel=\plusone
+ \expandafter\stoptext
+ \else
+ \advance\filelevel\minusone
+ \expandafter\endinput
+ \fi}
+
+\unexpanded\def\startproject #1 %
+ {\donextlevel\v!project\currentproject
+ \donotexecutefile\doexecutefileonce
+ \doexecutefileonce\doexecutefile#1\\}
+
+\unexpanded\def\startproduct #1 %
+ {\doateverystarttext
+ \donextlevel\v!product\currentproduct
+ \doexecutefileonce\doexecutefileonce
+ \donotexecutefile\doexecutefile#1\\}
+
+\unexpanded\def\startcomponent #1 %
+ {\doateverystarttext
+ \donextlevel\v!component\currentcomponent
+ \doexecutefileonce\doexecutefileonce
+ \donotexecutefile\doexecutefile#1\\}
+
+\unexpanded\def\startenvironment #1 %
+ {\donextlevel\v!environment\currentenvironment
+ \donotexecutefile\doexecutefileonce
+ \donotexecutefile\donotexecutefile#1\\}
+
+% \startproject test
+% 1: \startmode[*project] project \stopmode \endgraf
+% 2: \startmode[*product] product \stopmode \endgraf
+% \stopproject
+
+\unexpanded\def\stopproject {\doprevlevel}
+\unexpanded\def\stopproduct {\doprevlevel}
+\unexpanded\def\stopcomponent {\doprevlevel}
+\unexpanded\def\stopenvironment{\doprevlevel}
+
+% more or less replaced by modes
+
+\setvalue{\e!start\v!localenvironment}[#1]%
+ {\let\loadedlocalenvironments\empty
+ \def\docommand##1%
+ {\beforesplitstring##1\at.\to\someevironment
+ \fullexpandoneargafter\addtocommalist\someevironment\loadedlocalenvironments}%
+ \processcommalist[#1]\docommand
+ \fullexpandtwoargsafter\doifcommonelse % no longer next needed
+ {\currentproject,\currentproduct,%
+ \currentcomponent,\currentenvironment}
+ {\loadedlocalenvironments}
+ {\letvalue{\e!stop\v!localenvironment}\relax}
+ {\grabuntil{\e!stop\v!localenvironment}\gobbleoneargument}} % TH: fixed, was \relax
+
+\setvalue{\v!localenvironment}#1 {\doexecutefileonce{#1}}
+
+% NOT TOEVOEGEN: \the\everytrace
+
+\neverypar\emptytoks
+
+% \appendtoks \flushnotes \to \everypar
+% \appendtoks \synchronizesidefloats \to \everypar
+% \appendtoks \checkindentation \to \everypar
+% \appendtoks \showparagraphnumber \to \everypar
+% \appendtoks \flushmargincontents \to \everypar
+% \appendtoks \flushcommentanchors \to \everypar
+% \appendtoks \synchronizenotes \to \everypar
+
+% \appendtoks \flushnotes \to \everydisplay
+% \appendtoks \adjustsidefloatdisplaylines \to \everydisplay
+
+\protect \endinput
diff --git a/tex/context/base/core-mis.mkii b/tex/context/base/core-mis.mkii
new file mode 100644
index 000000000..98079830d
--- /dev/null
+++ b/tex/context/base/core-mis.mkii
@@ -0,0 +1,2742 @@
+%D \module
+%D [ file=core-mis,
+%D version=1998.01.29,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Miscelaneous,
+%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 Core Macros / Misc Commands}
+
+% todo: kleur in legenda + letter
+
+% %D You would not expect the next macro in \CONTEXT,
+% %D wouldn't you? It's there to warn \LATEX\ users that
+% %D something is wrong.
+% %D
+% %D Obsolete now:
+% %
+% % \def\documentstyle{\showmessage\m!systems3\empty\stoptekst}
+% %
+% % \let\documentclass=\documentstyle
+% %D \macros
+% %D {simplifiedcommands, simplifycommands}
+% %D
+% %D I first needed this simplification in bookmarks. Users can
+% %D add their own if needed.
+
+\unprotect
+
+%D Sometimes (for instance in bookmarks) we need to simplify macro
+%D behaviour, so here is the hook.
+
+\ifx\simplifiedcommands\undefined \newtoks\simplifiedcommands \fi
+
+\def\simplifycommands{\the\simplifiedcommands}
+
+%D A possibly growing list:
+
+%appendtoks \def\executesynonym#1#2#3#4{#3}\to\simplifiedcommands
+%appendtoks \def\executesort#1#2#3{#3}\to\simplifiedcommands
+
+\appendtoks \def\ { }\to\simplifiedcommands
+\appendtoks \def\type#1{\letterbackslash\strippedcsname#1}\to\simplifiedcommands
+\appendtoks \def\tex#1{\letterbackslash#1}\to\simplifiedcommands
+\appendtoks \def\TeX{TeX}\to\simplifiedcommands
+\appendtoks \def\ConTeXt{ConTeXt}\to\simplifiedcommands
+\appendtoks \def\MetaPost{MetaPost}\to\simplifiedcommands
+\appendtoks \def\MetaFont{MetaFont}\to\simplifiedcommands
+\appendtoks \def\MetaFun{MetaFun}\to\simplifiedcommands
+%appendtoks \def||{-}\to\simplifiedcommands
+\appendtoks \def|#1|{\ifx#1\empty\empty-\else#1\fi}\to\simplifiedcommands
+
+\appendtoks\let\buildtextaccent\secondoftwoarguments\to\simplifiedcommands
+
+% THIS WAS MAIN-002.TEX
+
+%\def\checkinterlineskip
+% {\ifvmode
+% \ifdim\lastskip>\zeropoint
+% \nointerlineskip
+% \else\ifdim\lastkern>\zeropoint
+% \nointerlineskip
+% \fi\fi
+% \fi}
+
+\def\horitems#1#2% #1=breedte #2=commandos
+ {\scratchdimen#1%
+ \divide\scratchdimen \nofitems
+ \!!counta\zerocount
+ \def\docommand##1%
+ {\advance\!!counta \plusone
+ \processaction
+ [\@@isalign]
+ [ \v!left=>\hbox to \scratchdimen{\strut##1\hss},
+ \v!right=>\hbox to \scratchdimen{\hss\strut##1},
+ \v!middle=>\hbox to \scratchdimen{\hss\strut##1\hss},
+ \v!margin=>\ifnum\!!counta=\plusone\hss\else\hfill\fi
+ \strut##1%
+ \ifnum\!!counta=\nofitems\hss\else\hfill\fi,
+ \s!default=>\hbox to \scratchdimen{\hss\strut##1\hss}, % midden
+ \s!unknown=>\hbox to \scratchdimen{\strut##1\hss}]}% % links
+ \hbox to #1{\hss#2\hss}}
+
+\def\veritems#1#2% #1=breedte #2=commandos
+ {\scratchdimen#1%
+ \def\docommand##1%
+ {\ifdim\scratchdimen<\zeropoint % the - was a signal
+ \hbox to -\scratchdimen{\hss\strut##1}%
+ \else\ifdim\scratchdimen>\zeropoint
+ \hbox to \scratchdimen{\strut##1\hss}%
+ \else
+ \hbox{\strut##1}%
+ \fi\fi}%
+ \vbox{#2}}
+
+\def\dosetupitems[#1]%
+ {\getparameters[\??is][#1]%
+ \doif\@@iswidth\v!unknown
+ {\def\@@iswidth{\hsize}}%
+ \doifconversiondefinedelse\@@issymbol
+ {\def\doitembullet##1{\convertnumber{\@@issymbol}{##1}}}
+ {\doifsymboldefinedelse\@@issymbol
+ {\def\doitembullet##1{\symbol[\@@issymbol]}}{}}}
+
+\def\makeitemsandbullets#1%
+ {\doifelse\@@isn\v!unknown
+ {\getcommalistsize[#1]%
+ \edef\nofitems{\commalistsize}}
+ {\edef\nofitems{\@@isn}}%
+ \setbox0\hbox
+ {\doitems \@@iswidth
+ {\processcommalist[#1]\docommand}}%
+ \setbox2\hbox
+ {\doitems \@@isbulletbreedte
+ {\dorecurse\nofitems
+ {\docommand{\strut\doitembullet\recurselevel}}}}}
+
+\def\dostartitems#1#2#3%
+ {\let\doitems#2%
+ \def\@@isbulletbreedte{#3}%
+ \makeitemsandbullets{#1}%
+ \@@isbefore}
+
+\def\dostopitems
+ {\@@isafter
+ \egroup}
+
+\setvalue{doitems\v!top}#1%
+ {\dostartitems{#1}\horitems\@@iswidth
+ \noindent\vbox
+ {\forgetall
+ \doifsomething\@@issymbol
+ {\doifnot\@@issymbol\v!none
+ {\box2
+ \@@isinbetween
+ \nointerlineskip}}%
+ \box0}%
+ \dostopitems}
+
+\setvalue{doitems\v!bottom}#1%
+ {\dostartitems{#1}\horitems\@@iswidth
+ \noindent\vbox
+ {\forgetall
+ \box0
+ \doifsomething\@@issymbol
+ {\@@isinbetween
+ \nointerlineskip
+ \box2}}%
+ \dostopitems}
+
+\setvalue{doitems\v!inmargin}#1%
+ {\dostartitems{#1}\veritems{-1.5em}% - is a signal
+ \noindent\hbox{\llap{\box2\hskip\leftmargindistance}\box0}%
+ \dostopitems}
+
+\setvalue{doitems\v!left}#1%
+ {\advance\hsize -1.5em%
+ \dostartitems{#1}\veritems{1.5em}%
+ \noindent\hbox{\box2\box0}%
+ \dostopitems}
+
+\setvalue{doitems\v!right}#1%
+ {\dostartitems{#1}\veritems{0em}%
+ \noindent\hbox{\box0\hskip-\wd2\box2}%
+ \dostopitems}
+
+\def\setupitems
+ {\dosingleargument\dosetupitems}
+
+\def\complexitems[#1]%
+ {\bgroup
+ \setupitems[#1]%
+ \parindent\zeropoint
+ \setlocalhsize
+ \hsize\localhsize
+ \dontcomplain
+ %\doifundefined{doitems\@@islocation}%
+ % {\let\@@islocation\v!left}%
+ %\getvalue{doitems\@@islocation}}
+ \executeifdefined{doitems\@@islocation}{\let\@@islocation\v!left}}
+
+\definecomplexorsimpleempty\items
+
+\setupitems
+ [\c!location=\v!left,
+ \c!symbol=5,
+ \c!width=\hsize,
+ \c!align=\v!middle,
+ \c!n=\v!unknown,
+ \c!before=\blank,
+ \c!inbetween={\blank[\v!medium]},
+ \c!after=\blank]
+
+% \definieerplaats[naam][instellingen]
+% \stelplaatsin[naam][instellingen]
+% \plaats[[instellingen]]
+%
+% - still undocumented and also not in setupb yet
+% - kan ook intern/direct (scheelt duplicatie), zie \framedtext
+
+\def\dodefineplacement[#1][#2]%
+ {\getparameters
+ [\??pl#1]
+ [\c!left=\hss,
+ \c!right=\hss,
+ \c!linecorrection=\v!off,
+ \c!depthcorrection=\v!off,
+ \c!margin=\v!standard,
+ \c!grid=\v!middle,
+ %\c!before=,
+ %\c!after=,
+ #2]%
+ \setvalue{\e!place#1}{\doplacement[\??pl#1]}}
+
+\def\defineplacement
+ {\dodoubleempty\dodefineplacement}
+
+\def\setupplacement
+ {\dodoubleempty\dosetupplacement}
+
+\def\dosetupplacement[#1]%
+ {\dodoubleempty\getparameters[\??pl#1]}
+
+\def\doplacement
+ {\dodoubleempty\dodoplacement}
+
+\def\dodoplacement[#1][#2]% correctie moet mooier
+ {\bgroup
+ \dowithnextboxcontent
+ {\forgetall}
+ {\setlocalhsize
+ \getparameters[#1][#2]%
+ \getvalue{#1\c!before}%
+ \begingroup
+ \disableparpositions
+ \setbox\nextbox\hbox to \localhsize
+ {\getvalue{#1\c!left}%
+ \flushnextbox
+ \getvalue{#1\c!right}}%
+ \ifinsidefloat \else
+ \addlocalbackgroundtobox\nextbox
+ \fi
+ \ifgridsnapping
+ \doifundefined{#1\c!grid}{\letvalue{#1\c!grid}\v!middle}%
+ % unchecked
+ \doifinset{\getvalue{#1\c!margin}}{\v!standard,\v!yes}\noindent
+ \snaptogrid[\getvalue{#1\c!grid}]\hbox{\flushnextbox}%
+ \else
+ \doifvalue{#1\c!linecorrection}\v!on \startbaselinecorrection
+ \doifinset{\getvalue{#1\c!margin}}{\v!standard,\v!yes}\noindent
+ \flushnextbox
+ \doifvalue{#1\c!depthcorrection}\v!on\baselinecorrection
+ \doifvalue{#1\c!linecorrection }\v!on\stopbaselinecorrection
+ \fi
+ \endgroup
+ \getvalue{#1\c!after}%
+ \egroup}
+ \vbox}
+
+% Te zijner tijd [plaats=boven,onder,midden] implementeren,
+% in dat geval moet eerst de maximale hoogte worden bepaald.
+%
+% Overigens kan een en ander mooier met \halign.
+
+% there is quite some historic balast in this mechanism, the next variant
+% is a first cleanup
+
+\let\currentparagraph\empty
+
+\newcount\alcounter \newcount\alnsize \newdimen\alhsize
+
+\def\paragraphparameter#1% \checkedparameter\??al\currentparagraph#1
+ {\executeifdefined{\??al\currentparagraph#1}{\executeifdefined{\??al#1}\empty}}
+
+\def\paragraphcellmeter#1#2% \checkedparameter\??al\currentparagraph#1
+ {\executeifdefined{\??al\currentparagraph\number#1#2}{\paragraphparameter{#2}}}
+
+\def\dodefineparagraphs[#1][#2]%
+ {\edef\currentparagraph{#1}%
+ \setvalue{\s!do\s!next\currentparagraph}%
+ {\def\\{\getvalue\currentparagraph}}%
+ \setvalue\currentparagraph
+ {\getvalue{\s!do\s!next#1}%
+ \dostartparagraphs{#1}}%
+ \setvalue{\e!next\currentparagraph}%
+ {\getvalue{#1}}%
+ \setvalue{\e!start\currentparagraph}%
+ {\bgroup
+ \edef\currentparagraph{#1}%
+ \letvalue{\s!do\s!next\currentparagraph}\empty
+ \setvalue{\e!stop\currentparagraph}{\getvalue\currentparagraph\egroup}%
+ \getvalue\currentparagraph}%
+ \getparameters[\??al\currentparagraph]%
+ [%\c!n=3,
+ %\c!before=\blank,
+ %\c!after=\blank,
+ %\c!distance=1em,
+ %\c!height=\v!fit,
+ %\c!rule=\v!off,
+ %\c!command=,
+ %\c!align=,
+ %\c!tolerance=\v!tolerant,
+ %\c!rulethickness=\linewidth,
+ %\c!rulecolor=,
+ %\c!style=,
+ %\c!color=,
+ %\c!top=,
+ %\c!top=\vss,
+ %\c!bottom=\vfill,
+ #2]%
+ \setvalue{\e!setup#1\e!endsetup}%
+ {\setupparagraphs[#1]}%
+ \dorecurse
+ {\paragraphparameter\c!n}
+ {\setupparagraphs
+ [\currentparagraph]
+ [\recurselevel]
+ [\c!width=,
+ %\c!bottom=\paragraphparameter\c!bottom,
+ %\c!top=\paragraphparameter\c!top,
+ %\c!height=\paragraphparameter\c!height,
+ %\c!rule=\paragraphparameter\c!rule,
+ %\c!rulethickness=\paragraphparameter\c!rulethickness,
+ %\c!rulecolor=\paragraphparameter\c!rulecolor,
+ %\c!align=\paragraphparameter\c!align,
+ %\c!tolerance=\paragraphparameter\c!tolerance, % obsolete
+ %\c!distance=\paragraphparameter\c!distance,
+ \c!style=\paragraphparameter\c!style,
+ \c!color=\paragraphparameter\c!color]}%
+ \setupparagraphs[\currentparagraph][1][\c!distance=\zeropoint]}
+
+\def\defineparagraphs
+ {\dodoubleargument\dodefineparagraphs}
+
+\def\dosetupparagraphs[#1][#2][#3]%
+ {\edef\currentparagraph{#1}%
+ \ifsecondargument
+ \doifelse{#2}\v!each
+ {\dorecurse
+ {\paragraphparameter\c!n}
+ {\getparameters[\??al\currentparagraph\recurselevel][#3]}}
+ {\doifelsenothing{#3}
+ {\getparameters[\??al\currentparagraph][#2]}
+ {\def\docommand##1{\getparameters[\??al\currentparagraph##1][#3]}%
+ \processcommalist[#2]\docommand}}%
+ \else
+ \getparameters[\??al][#1]%
+ \fi}
+
+\def\setupparagraphs
+ {\dotripleempty\dosetupparagraphs}
+
+\setupparagraphs
+ [\c!n=3,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!distance=1em,
+ \c!height=\v!fit,
+ \c!rule=\v!off,
+ \c!command=,
+ \c!align=,
+ \c!tolerance=\v!tolerant, % obsolete
+ \c!rulethickness=\linewidth,
+ \c!rulecolor=,
+ \c!style=,
+ \c!color=,
+ \c!top=,
+ \c!top=\vss,
+ \c!bottom=\vfill]
+
+\def\doparagraphrule
+ {\doifelse{\paragraphcellmeter\alcounter\c!rule}\v!on
+ {\linewidth\paragraphcellmeter\alcounter\c!rulethickness
+ \scratchdimen\paragraphcellmeter\alcounter\c!distance
+ \advance\scratchdimen-\linewidth
+ \divide\scratchdimen \plustwo
+ \hskip\scratchdimen
+ \color[\paragraphcellmeter\alcounter\c!rulecolor]{\vrule\!!width\linewidth}%
+ \hskip\scratchdimen}
+ {\hskip\paragraphcellmeter\alcounter\c!distance}}
+
+\def\dostartparagraph
+ {\doifelsenothing{\paragraphcellmeter\alcounter\c!width}
+ {\!!widtha\alhsize
+ \divide\!!widtha \alnsize}
+ {\!!widtha\paragraphcellmeter\alcounter\c!width}%
+ \dostartattributes{\??al\currentparagraph\number\alcounter}\c!style\c!color\empty
+ \doifelse{\paragraphcellmeter\alcounter\c!height}\v!fit
+ {\setbox\scratchbox\vtop}
+ {\setbox\scratchbox\vtop to \paragraphcellmeter\alcounter\c!height}%
+ \bgroup
+ \blank[\v!disable]%
+ \forgetall
+ \paragraphcellmeter\alcounter\c!top
+ \paragraphparameter\c!inner
+ \hsize\!!widtha % setting \wd afterwards removed
+ \paragraphcellmeter\alcounter\c!inner % twice
+ \expanded{\setupalign [\paragraphcellmeter\alcounter\c!align ]}% {normal,verytolerant,stretch}
+ \expanded{\setuptolerance[\paragraphcellmeter\alcounter\c!tolerance]}% obsolete
+ \ignorespaces
+ \endgraf
+ \ignorespaces
+ %
+ % Nadeel van de onderstaande constructie is dat \everypar
+ % binnen een groep kan staan en zo steeds \begstruts
+ % worden geplaatst. Mooi is anders dus moet het anders!
+ %
+ % Hier is \Everypar niet nodig.
+ %
+ \everypar{\begstrut\everypar\emptytoks}%
+ %
+ \nospace % remove + ignore
+ \paragraphcellmeter\alcounter\c!command}
+
+\def\dostopparagraph
+ {\ifvmode
+ \removelastskip
+ \else
+ \unskip\endstrut\endgraf
+ \fi
+ \paragraphcellmeter\alcounter\c!bottom
+ \egroup
+ \ifdim\wd\scratchbox=\zeropoint % no data
+ \wd\scratchbox\!!widtha
+ \fi
+ \box\scratchbox
+ \dostopattributes
+ \ifnum\alcounter<\paragraphparameter\c!n\relax
+ \@EA\doparagraphcell
+ \else
+ \@EA\dostopparagraphs
+ \fi}
+
+\def\doparagraphcell
+ {\global\advance\alcounter \plusone
+ \doifelsenothing{\paragraphcellmeter\alcounter\c!distance}
+ {\ifnum\alcounter=\plusone\else
+ \hskip\paragraphparameter\c!distance
+ \fi}
+ {\ifnum\alcounter=\plusone
+ \hskip\paragraphcellmeter\alcounter\c!distance
+ \else
+ \doparagraphrule
+ \fi}%
+ \letvalue\currentparagraph\dostopparagraph
+ \dostartparagraph}
+
+\def\dostartparagraphs#1%
+ {\bgroup
+ \edef\currentparagraph{#1}%
+ \global\alcounter\zerocount
+ \parindent\zeropoint
+ \setlocalhsize
+ \alhsize\localhsize
+ \alnsize\paragraphparameter\c!n\relax
+ \dorecurse \alnsize
+ {\doifelsenothing{\paragraphcellmeter\recurselevel\c!distance}
+ {\ifnum\recurselevel=\plusone\else
+ \global\advance\alhsize -\paragraphparameter\c!distance
+ \fi}
+ {\global\advance\alhsize -\paragraphcellmeter\recurselevel\c!distance}%
+ \doifsomething{\paragraphcellmeter\recurselevel\c!width}
+ {\global\advance\alnsize \minusone
+ \global\advance\alhsize -\paragraphcellmeter\recurselevel\c!width}}%
+ %whitespace % gaat fout bij \framed
+ \paragraphparameter\c!before
+ \leavevmode % gaat wel goed bij \framed, brrr
+ \setbox\scratchbox\vbox\bgroup\hbox\bgroup\doparagraphcell}
+
+\def\dostopparagraphs
+ {\egroup
+ \egroup
+ \iftrue
+ \hbox{\raise\strutheight\box\scratchbox}% new
+ \else
+ \box\scratchbox % old
+ \fi
+ \par
+ \paragraphparameter\c!after
+ \egroup}
+
+\def\dosetuptab[#1]%
+ {\getparameters[\??ta]
+ [\c!headstyle=\v!normal,
+ \c!headcolor=,
+ \c!style=\v!normal,
+ \c!color=,
+ \c!width=\v!broad,
+ \c!sample={\hskip4em},
+ \c!before=,
+ \c!after=,
+ #1]%
+ \definedescription
+ [tab]
+ [\c!headstyle=\@@taheadstyle,
+ \c!headcolor=\@@tacolor,
+ \c!sample=\@@tasample,
+ \c!width=\@@tawidth,
+ \c!before=\@@tabefore,
+ \c!after=\@@taafter]}
+
+\def\setuptab
+ {\dosingleargument\dosetuptab}
+
+\setuptab
+ [\c!location=\v!left]
+
+% The following macro's are derived from PPCHTEX and
+% therefore take some LaTeX font-switching into account.
+
+\newif\ifloweredsubscripts
+
+% Due to some upward incompatibality of LaTeX to LaTeX2.09
+% and/or LaTeX2e we had to force \@@chemieletter. Otherwise
+% some weird \nullfont error comes up.
+
+\doifundefined{@@chemieletter}{\def\@@chemieletter{\rm}}
+
+\def\beginlatexmathmodehack
+ {\ifmmode
+ \let\endlatexmathmodehack\relax
+ \else
+ \def\endlatexmathmodehack{$}$\@@chemieletter
+ \fi}
+
+\def\setsubscripts
+ {\beginlatexmathmodehack
+ \def\dosetsubscript##1##2##3%
+ {\dimen0=##3\fontexheight##2%
+ \setxvalue{@@\string##1\string##2}{\the##1##2\relax}%
+ ##1##2=\dimen0\relax}%
+ \def\dodosetsubscript##1##2%
+ {\dosetsubscript{##1}{\textfont2}{##2}%
+ \dosetsubscript{##1}{\scriptfont2}{##2}%
+ \dosetsubscript{##1}{\scriptscriptfont2}{##2}}%
+ %dodosetsubscript\mathsupnormal {?}%
+ \dodosetsubscript\mathsubnormal {.7}%
+ \dodosetsubscript\mathsubcombined{.7}%
+ \global\loweredsubscriptstrue
+ \endlatexmathmodehack}
+
+\def\resetsubscripts
+ {\ifloweredsubscripts
+ \beginlatexmathmodehack
+ \def\doresetsubscript##1##2%
+ {\dimen0=\getvalue{@@\string##1\string##2}\relax
+ ##1##2=\dimen0}%
+ \def\dodoresetsubscript##1%
+ {\doresetsubscript{##1}{\textfont2}%
+ \doresetsubscript{##1}{\scriptfont2}%
+ \doresetsubscript{##1}{\scriptscriptfont2}}%
+ %dodoresetsubscript\mathsupnormal
+ \dodoresetsubscript\mathsubnormal
+ \dodoresetsubscript\mathsubcombined
+ \global\loweredsubscriptsfalse
+ \endlatexmathmodehack
+ \fi}
+
+\let\beginlatexmathmodehack = \relax
+\let\endlatexmathmodehack = \relax
+
+\def\chem#1#2#3%
+ {\bgroup
+ \setsubscripts
+ \mathematics{\hbox{#1}_{#2}^{#3}}%
+ \resetsubscripts
+ \egroup}
+
+\unexpanded\def\celsius #1{#1\mathematics{^\circ}C}
+\unexpanded\def\inch {\mathematics{\prime\prime}} % was: \hbox{\rm\char125\relax}
+\unexpanded\def\fraction#1#2{\mathematics{#1\over#2}}
+
+% very dutch
+
+\unexpanded\def\graden {\mathematics{^\circ}}
+
+\def\bedragprefix {\euro\normalfixedspace}
+\def\bedragsuffix {}
+\def\bedragempty {\euro}
+
+\unexpanded\def\bedrag#1%
+ {\strut\hbox\bgroup
+ \let\normalfixedspace\nonbreakablespace
+ \doifelsenothing{#1}
+ {\bedragempty}
+ {\bedragprefix\digits{#1}\bedragsuffix}%
+ \egroup}
+
+% \definieeralineas[test][n=3]
+%
+% \stelalineasin[test][3][breedte=4cm,uitlijnen=links]
+%
+% \startopelkaar
+% \test hans \\ ton \\ \bedrag{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{~.~~1,--} \\
+% \test hans \\ ton \\ \bedrag{~.~~1,~~} \\
+% \test hans \\ ton \\ \bedrag{~.100,--} \\
+% \test hans \\ ton \\ \subtot{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{1.000,--} \\
+% \test hans \\ ton \\ \totaal{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{nihil,--} \\
+% \test hans \\ ton \\ \totaal{nihil,--} \\
+% \test hans \\ ton \\ \subtot{nihil,--} \\
+% \stopopelkaar
+
+\def\periodswidth {.5em}
+\def\periodsdefault{3} % was 5, but now it's like \unknown
+
+\unexpanded\def\periods
+ {\dosingleempty\doperiods}
+
+\def\doperiods[#1]%
+ {\dontleavehmode
+ \begingroup
+ \scratchdimen\periodswidth
+ \hbox to \iffirstargument#1\else\periodsdefault\fi \scratchdimen
+ {\leaders\hbox to \scratchdimen{\hss.\hss}\hss}%
+ \endgroup}
+
+\unexpanded\def\unknown
+ {\periods\relax} % relax prevents lookahead for []
+
+% compatibility macros
+
+\def\doorsnede
+ {\hbox{\rlap/$\circ$} }
+
+\unexpanded\def\ongeveer
+ {\mathematics\pm}
+
+\chardef\boundarycharactermode\plusone
+
+\def\midboundarycharacter#1#2%
+ {\ifcase\boundarycharactermode
+ \or
+ %\nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \languageparameter#1%
+ %\nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \or
+ \languageparameter#1%
+ \fi
+ \chardef\boundarycharactermode\plusone}
+
+\def\leftboundarycharacter#1#2%
+ {\ifcase\boundarycharactermode
+ \or
+ \languageparameter#1%
+ \nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \or
+ \languageparameter#1%
+ \fi
+ \chardef\boundarycharactermode\plusone}
+
+\def\rightboundarycharacter#1#2%
+ {\ifcase\boundarycharactermode
+ \or
+ \prewordbreak %\nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \languageparameter#1%
+ \or
+ \languageparameter#1%
+ \fi
+ \chardef\boundarycharactermode\plusone}
+
+% actually this is pretty old, but temporary moved here
+%
+% obsolete:
+
+\def\setuphyphenmark
+ {\dodoubleargument\getparameters[\??kp]}
+
+\def\setuphyphenmark[#1]% sign=normal|wide
+ {\dodoubleargument\getparameters[\??kp][#1]%
+ \doifinsetelse\@@kpsign {\v!normal}
+ {\let\textmodehyphen\normalhyphen \let\textmodehyphendiscretionary\normalhyphendiscretionary}
+ {\let\textmodehyphen\composedhyphen\let\textmodehyphendiscretionary\composedhyphendiscretionary}}
+
+\setuphyphenmark[\c!sign=\v!wide]
+% % \setuphyphenmark[\c!sign=\v!normal]
+
+\definesymbol[\c!lefthyphen] [\languageparameter\c!lefthyphen]
+\definesymbol[\c!righthyphen] [\languageparameter\c!righthyphen]
+\definesymbol[\c!hyphen] [\languageparameter\c!hyphen]
+
+\def\normalhyphen
+ {\hbox{\directsymbol\empty\c!hyphen}}
+
+\def\composedhyphen
+ {\hbox{\directsymbol\empty\c!compoundhyphen}}
+
+\def\normalhyphendiscretionary
+ {\discretionary
+ {\hbox{\directsymbol\empty\c!lefthyphen}}
+ {\hbox{\directsymbol\empty\c!righthyphen}}
+ {\hbox{\directsymbol\empty\c!hyphen}}}
+
+\def\composedhyphendiscretionary
+ {\discretionary
+ {\hbox{\directsymbol\empty\c!leftcompoundhyphen}}
+ {\hbox{\directsymbol\empty\c!rightcompoundhyphen}}
+ {\hbox{\directsymbol\empty\c!compoundhyphen}}}
+
+\let\textmodehyphen \composedhyphen
+\let\textmodehyphendiscretionary\composedhyphendiscretionary
+
+\definesymbol[\c!leftcompoundhyphen] [\languageparameter\c!leftcompoundhyphen]
+\definesymbol[\c!rightcompoundhyphen] [\languageparameter\c!rightcompoundhyphen]
+\definesymbol[\c!compoundhyphen] [\languageparameter\c!compoundhyphen]
+
+\definehspace [sentence] [\zeropoint]
+\definehspace [intersentence] [.250em]
+
+\definesymbol
+ [\c!midsentence]
+ [\midboundarycharacter\c!midsentence{sentence}]
+
+\definesymbol
+ [\c!leftsentence]
+ [\leftboundarycharacter\c!leftsentence{sentence}]
+
+\definesymbol
+ [\c!rightsentence]
+ [\rightboundarycharacter\c!rightsentence{sentence}]
+
+\definesymbol
+ [\c!leftsubsentence]
+ [\leftboundarycharacter\c!leftsubsentence{sentence}]
+
+\definesymbol
+ [\c!rightsubsentence]
+ [\rightboundarycharacter\c!rightsubsentence{sentence}]
+
+\newsignal \subsentencesignal
+\newcounter\subsentencelevel
+
+\let\beforesubsentence\donothing
+\let\aftersubsentence \donothing
+
+% todo: make this language option
+%
+% \def\beforesubsentence{\removeunwantedspaces}
+% \def\aftersubsentence {\ignorespaces}
+
+\def\midsentence
+ {\symbol[\c!midsentence]}
+
+\def\beginofsubsentence
+ {\beforesubsentence
+ \ifdim\lastkern=\subsentencesignal
+ \unskip
+ \kern\hspaceamount\currentlanguage{intersentence}%
+ \fi
+ \doglobal\increment\subsentencelevel
+ \ifnum\subsentencelevel=\plusone
+ \dontleavehmode % was \leaveoutervmode
+ \fi
+ \symbol[\ifodd\subsentencelevel\c!leftsentence\else\c!leftsubsentence\fi]%
+ }% \ignorespaces}
+
+\def\endofsubsentence % relax prevents space gobbling
+ {\symbol[\ifodd\subsentencelevel\c!rightsentence\else\c!rightsubsentence\fi]%
+ \doglobal\decrement\subsentencelevel
+ \unskip
+ \kern\subsentencesignal\relax
+ \aftersubsentence}
+
+\def\beginofsubsentencespacing % relax prevents space gobbling
+ {\kern\subsentencesignal\relax}% \ignorespaces}
+
+\def\endofsubsentencespacing
+ {\ifdim\lastkern=\subsentencesignal
+ \unskip
+ \hskip\hspaceamount\currentlanguage{intersentence}%
+ % no good, actually language dependent:
+% \ignorespaces
+ \else
+ \unskip
+ \fi}
+
+%D \startbuffer
+%D test |<|test |<|test|>| test|>| test \par
+%D test|<|test|<|test|>|test|>|test \par
+%D test |<||<|test|>||>| test \par
+%D test \directdiscretionary{<}test\directdiscretionary{>} test \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \getbuffer
+
+\def\startsubsentence{\beginofsubsentence \prewordbreak\beginofsubsentencespacing}
+\def\stopsubsentence {\endofsubsentencespacing\prewordbreak\endofsubsentence}
+
+%D \defineXMLenvironment [subsentence]
+%D {|<|}
+%D {|>|}
+%D \defineXMLenvironment [subsentence]
+%D {\directdiscretionary{<}}
+%D {\directdiscretionary{>}}
+%D \defineXMLenvironment [subsentence]
+%D {\startsubsentence}
+%D {\stopsubsentence}
+%D
+%D \startbuffer
+%D test test test
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \processXMLbuffer
+
+\enableactivediscretionaries
+
+\definehspace [quotation] [\zeropoint]
+\definehspace [interquotation] [.125em]
+
+%definehspace [quote] [\zeropoint]
+%definehspace [speech] [\zeropoint]
+
+\definehspace [quote] [\hspaceamount\currentlanguage{quotation}]
+\definehspace [speech] [\hspaceamount\currentlanguage{quotation}]
+
+\definesymbol
+ [\c!leftquotation]
+ [\leftboundarycharacter\c!leftquotation{quotation}]
+
+\definesymbol
+ [\c!rightquotation]
+ [\rightboundarycharacter\c!rightquotation{quotation}]
+
+\definesymbol
+ [\c!leftquote]
+ [\leftboundarycharacter\c!leftquote{quote}]
+
+\definesymbol
+ [\c!rightquote]
+ [\rightboundarycharacter\c!rightquote{quote}]
+
+\definesymbol
+ [\c!leftspeech]
+ [\leftboundarycharacter\c!leftspeech{speech}]
+
+\definesymbol
+ [\c!rightspeech]
+ [\rightboundarycharacter\c!rightspeech{speech}]
+
+\definesymbol
+ [\c!middlespeech]
+ [\leftboundarycharacter\c!middlespeech{speech}]
+
+\appendtoks\def\quotation#1{"#1"}\to\simplifiedcommands
+\appendtoks\def\quote #1{'#1'}\to\simplifiedcommands
+
+%D The next features was so desperately needed by Giuseppe
+%D Bilotta that he made a module for it. Since this is a
+%D typical example of core functionality, I decided to extend
+%D the low level quotation macros in such a way that a speech
+%D feature could be build on top of it. The speech opening and
+%D closing symbols are defined per language. Italian is an
+%D example of a language that has them set.
+
+% this will replace the quotation and speed definitions
+
+\newsignal\delimitedtextsignal
+
+\let\currentdelimitedtext\s!unknown
+
+\def\delimitedtextparameter#1% will be sped up
+ {\executeifdefined{\??ci\currentdelimitedtext:\csname\??ci\currentdelimitedtext\c!level\endcsname#1}%
+ {\executeifdefined{\??ci\currentdelimitedtext#1}%
+ {\executeifdefined{\??ci#1}\empty}}}
+
+\def\definedelimitedtext
+ {\dodoubleempty\dodefinedelimitedtext}
+
+\def\dodefinedelimitedtext[#1][#2]%
+ {\doifassignmentelse{#2}
+ {\getparameters
+ [\??ci#1]
+ [\c!location=\v!margin, % \v!text \v!paragraph
+ \c!spacebefore=,
+ \c!spaceafter=\delimitedtextparameter\c!spacebefore,
+ \c!style=\v!normal,
+ \c!color=,
+ \c!leftmargin=\zeropoint,
+ \c!rightmargin=\delimitedtextparameter\c!leftmargin,
+ \c!indentnext=\v!yes,
+ \c!before=,
+ \c!after=,
+ \c!left=,
+ \c!right=,
+ \c!level=0,
+ \c!repeat=\v!no,
+ \c!method=,
+ #2]}%
+ {\doifdefined{#2}
+ {\copyparameters[\??ci#1][\??ci#2]
+ [\c!location,\c!spacebefore,\c!spaceafter,\c!style,\c!color,
+ \c!leftmargin,\c!rightmargin,\c!indentnext,
+ \c!before,\c!after,\c!left,\c!right]}}%
+ \doifsomething{#1}
+ {\unexpanded\setvalue{#1}{\delimitedtext[#1]}%
+ \setvalue{\e!start#1}{\startdelimitedtext[#1]}%
+ \setvalue{\e!stop #1}{\stopdelimitedtext}}}
+
+\def\setupdelimitedtext
+ {\dotripleargument\dosetupdelimitedtext}
+
+\def\dosetupdelimitedtext[#1][#2][#3]% #2 = optional level
+ {\ifthirdargument
+ \getparameters[\??ci#1:#2][#3]%
+ \else\ifsecondargument
+ \getparameters[\??ci#1][#2]%
+ \else
+ \getparameters[\??ci][#1]%
+ \fi\fi}
+
+\def\dorepeatdelimitedtext
+ {\relax\ifcase\delimitedtextparameter\c!level\else
+ \dohandledelimitedtext\c!middle % maybe better \dohandleleftdelimitedtext
+ \fi}
+
+\let\dohandlerepeatdelimitedtext\relax
+
+\def\startdelimitedtext[#1]%
+ {\bgroup
+ \pushdelimitedtext{#1}%
+ \doifelse{\delimitedtextparameter\c!method}\s!font
+ {\def\dostopdelimitedtext
+ {\removeunwantedspaces\ignoredelimitedtext\c!right}%
+ \ignoredelimitedtext\c!left\ignorespaces}
+ {\doifelse{\delimitedtextparameter\c!repeat}\v!yes
+ {\let\dohandlerepeatdelimitedtext\dorepeatdelimitedtext}%
+ {\let\dohandlerepeatdelimitedtext\relax}%
+ \doifinsetelse{\delimitedtextparameter\c!location}{\v!paragraph,\v!margin}%
+ {\dosingleempty\dostartdelimitedtextpar}\dostartdelimitedtexttxt}}
+
+\def\dostartdelimitedtextpar[#1]%
+ {\let\dostopdelimitedtext\dostopdelimitedtextpar
+ \doifsomething{\delimitedtextparameter\c!spacebefore}
+ {\blank[\delimitedtextparameter\c!spacebefore]}%
+ \delimitedtextparameter\c!before
+ % nicer:
+ % \doadaptleftskip {\delimitedtextparameter\c!leftmargin}%
+ % \doadaptrightskip{\delimitedtextparameter\c!rightmargin}%
+ % backward compatible:
+ \doifelsenothing{#1}
+ {\endgraf
+ \doadaptleftskip {\delimitedtextparameter\c!leftmargin}%
+ \doadaptrightskip{\delimitedtextparameter\c!rightmargin}%
+ \let\dodostopdelimitedtextpar\endgraf}
+ {\startnarrower[#1]\let\dodostopdelimitedtextpar\stopnarrower}%
+ % so far
+ % \dochecknextindentation{\??ci\currentdelimitedtext}% AM: not here
+ \dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color\empty
+ \leftdelimitedtextmark
+ \ignorespaces}
+
+\def\dostopdelimitedtextpar
+ {\removeunwantedspaces
+ \removelastskip
+ \rightdelimitedtextmark
+ \dostopattributes
+ \dodostopdelimitedtextpar
+ \delimitedtextparameter\c!after
+ \doifsomething{\delimitedtextparameter\c!spaceafter}
+ {\blank[\delimitedtextparameter\c!spaceafter]}%
+ \dochecknextindentation{\??ci\currentdelimitedtext}% AM: here
+ \dorechecknextindentation}% AM: This was missing!
+
+\def\dostartdelimitedtexttxt
+ {\let\dostopdelimitedtext\dostopdelimitedtexttxt
+ \dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color\empty
+ \dohandleleftdelimitedtext\c!left
+ \ignorespaces}
+
+\def\dostopdelimitedtexttxt
+ {\removeunwantedspaces
+ \dohandlerightdelimitedtext\c!right
+ \dostopattributes}
+
+\def\stopdelimitedtext
+ {\dostopdelimitedtext
+ \popdelimitedtext
+ \egroup}
+
+\def\pushdelimitedtext#1%
+ {\globalpushmacro\currentdelimitedtext
+ \def\currentdelimitedtext{#1}%
+ \doglobal\incrementvalue{\??ci\currentdelimitedtext\c!level}}
+
+\def\popdelimitedtext
+ {\doglobal\decrementvalue{\??ci\currentdelimitedtext\c!level}%
+ \globalpopmacro\currentdelimitedtext}
+
+\def\delimitedtext[#1]%
+ {\pushdelimitedtext{#1}%
+ \doifelse{\delimitedtextparameter\c!method}\s!font
+ {\dofontdrivendelimited}
+ {\doifinsetelse{\delimitedtextparameter\c!location}{\v!paragraph,\v!margin}%
+ \dodelimitedtextpar\dodelimitedtexttxt}}
+
+% shortcuts
+
+\def\startdelimited{\startdelimitedtext}
+\def\stopdelimited {\stopdelimitedtext} % no let, dynamically assigned
+\def\delimited {\delimitedtext}
+
+\def\leftdelimitedtextmark
+ {\doifsomething{\delimitedtextparameter\c!left}
+ {\setbox\scratchbox\hbox{\delimitedtextparameter\c!left}%
+ \dontleavehmode
+ \doif{\delimitedtextparameter\c!location}\v!margin{\hskip-\wd\scratchbox}%
+ \box\scratchbox}}
+
+\def\rightdelimitedtextmark
+ {\doifsomething{\delimitedtextparameter\c!right}
+ {\hsmash{\delimitedtextparameter\c!right}}}
+
+% \starttext
+% \hyphenatedword{groepsvrijstellingsverordeningen}\par
+% \hyphenatedword{\quote{groepsvrijstellingsverordeningen}}\par
+% \dorecurse{100}{\hskip300pt\hskip\recurselevel pt test \quote{xxx xxxx}.\par}
+% \page \setuppapersize[A5][A4]
+% \quotation {overly beautiful pusillanimous sesquipedalian
+% longwinded} test test test test test test test test test test test
+% test test test test test test test test test test test test test
+% test test test test test test test test test test test test test
+% test test test test test test test test test test test test test
+% test test test
+% \stoptext
+
+\def\dohandledelimitedtext#1#2%
+ {\begingroup
+ \setbox\scratchbox\hbox{\delimitedtextparameter#1}%
+ \ifdim\wd\scratchbox>\zeropoint
+% \ifdim\lastskip=\delimitedtextsignal
+% \unskip
+ \ifdim\lastkern=\delimitedtextsignal
+ \unkern
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else
+ #2%
+ \fi
+ \ifhmode % else funny pagebeaks
+ \penalty\!!tenthousand
+ \hskip\zeropoint % == \prewordbreak
+ \fi
+ \strut % new, needed below
+ \delimitedtextparameter#1% unhbox\scratchbox
+% \penalty\!!tenthousand % else overfull boxes, but that's better than dangling periods
+ \kern\delimitedtextsignal % +- \prewordbreak
+ \fi
+ \endgroup}
+
+\def\dohandleleftdelimitedtext#1#2%
+ {\begingroup
+ \setbox\scratchbox\hbox{\delimitedtextparameter#1}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \ifdim\lastkern=\delimitedtextsignal
+ \unkern
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else\ifdim\lastskip=\delimitedtextsignal
+ \unskip
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else
+ #2%
+ \fi\fi
+ \strut % new, needed below
+ \ifhmode % else funny pagebeaks
+ \penalty\!!tenthousand
+ \hskip\zeropoint % == \prewordbreak
+ \fi
+ \strut % new, needed below
+ \delimitedtextparameter#1% unhbox\scratchbox
+ \hskip\delimitedtextsignal % +- \prewordbreak
+ \fi
+ \endgroup}
+
+\def\dohandlerightdelimitedtext#1#2%
+ {\begingroup
+ \setbox\scratchbox\hbox{\delimitedtextparameter#1}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \ifdim\lastkern=\delimitedtextsignal
+ \unkern
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else\ifdim\lastskip=\delimitedtextsignal
+ \unskip
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else
+ #2%
+ \fi\fi
+ \ifhmode % else funny pagebeaks
+ \penalty\!!tenthousand
+ \hskip\zeropoint % == \prewordbreak
+ \fi
+ \strut % new, needed below
+ \delimitedtextparameter#1% unhbox\scratchbox
+ \kern\delimitedtextsignal % +- \prewordbreak
+ \fi
+ \endgroup}
+
+\def\ignoredelimitedtext#1%
+ {\delimitedtextparameter#1}
+
+\def\handledelimitedtext#1%
+ {\dohandledelimitedtext{#1}\relax}
+
+\def\handleleftdelimitedtext#1%
+ {\dohandleleftdelimitedtext{#1}\relax}
+
+\def\handlerightdelimitedtext#1%
+ {\dohandlerightdelimitedtext{#1}\relax}
+
+\unexpanded\def\dodelimitedtextpar
+ {\dohandleleftdelimitedtext\c!left\relax
+ \groupedcommand
+ \donothing
+ {\dohandlerightdelimitedtext\c!right\removelastskip
+ \popdelimitedtext}}
+
+\unexpanded\def\dodelimitedtexttxt
+ {\doifelse{\delimitedtextparameter\c!style}\v!normal
+ \doquoteddelimited\doattributeddelimited}
+
+\def\doquoteddelimited
+ {\dohandleleftdelimitedtext\c!left\relax
+ \groupedcommand
+ \donothing
+ {\dohandlerightdelimitedtext\c!right
+ \removelastskip
+ \popdelimitedtext}}
+
+\def\doattributeddelimited
+ {\groupedcommand
+ {\dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color}
+ {\dostopattributes
+ \popdelimitedtext}}
+
+\def\dofontdrivendelimited
+ {\simplegroupedcommand
+ {\languageparameter{\c!left\currentdelimitedtext}}
+ {\languageparameter{\c!right\currentdelimitedtext}%
+ \popdelimitedtext}}
+
+% testcase for nesting:
+%
+% \quotation{... \quotation{...} ...}
+% \startquotation ... \startquotation... \quotation{...} \stopquotation\space ...\stopquotation
+% \setupdelimitedtext[quotation][1][left=(,right=)]
+% \setupdelimitedtext[quotation][2][left={[},right={]}]
+% \setupdelimitedtext[quotation][3][left=\{,right=\}]
+% \quotation{... \quotation{...} ...}
+% \startquotation ... \startquotation... \quotation{...} \stopquotation\space ...\stopquotation
+
+\definedelimitedtext
+ [\v!quotation]
+ [\c!left={\symbol[\c!leftquotation]},
+ \c!right={\symbol[\c!rightquotation]},
+ \c!leftmargin=\v!standard]
+
+\definedelimitedtext
+ [\v!quote][\v!quotation]
+
+\setupdelimitedtext
+ [\v!quote]
+ [\c!location=\v!text,
+ \c!left={\symbol[\c!leftquote]},
+ \c!right={\symbol[\c!rightquote]}]
+
+\definedelimitedtext
+ [\v!blockquote][\v!quotation]
+
+\setupdelimitedtext
+ [\v!blockquote]
+ [\c!left=,
+ \c!right=]
+
+\definedelimitedtext
+ [\v!speech][\v!quotation]
+
+\setupdelimitedtext
+ [\v!speech]
+ [\c!repeat=\v!yes,
+ \c!left={\symbol[\c!leftspeech]},
+ \c!middle={\symbol[\c!middlespeech]},
+ \c!right={\symbol[\c!rightspeech]}]
+
+% how do we call an tight quote
+%
+% \definedelimitedtext
+% [\v!quotation][\v!quotation]
+%
+% \setupdelimitedtext
+% [\v!quotation]
+% [\c!indentnext=\v!no,
+% \c!spacebefore=\v!nowhite]
+
+\def\setupquotation{\setupdelimitedtext[\v!quotation]}
+\def\setupquote {\setupdelimitedtext[\v!quote]}
+
+% seldom used, move from kernel to run time module
+
+\ifx\tfx\undefined \let\tfx\relax \fi
+
+\def\basegrid
+ {\dosingleempty\dobasegrid}
+
+\def\dobasegrid[#1]%
+ {\begingroup
+ \getparameters[\??rt]
+ [\c!x=0,\c!y=0,
+ \c!nx=10,\c!ny=10,
+ \c!dx=.5,\c!dy=.5,
+ \c!xstep=0,\c!ystep=0,
+ \c!unit=\s!cm,
+ \c!scale=1,
+ \c!factor=1,
+ \c!offset=\v!yes,
+ \c!location=\v!left,
+ #1]%
+ \startpositioning
+ \dimen0=\@@rtdx\@@rtunit\relax
+ \dimen0=\@@rtscale\dimen0\relax
+ \dimen0=\@@rtfactor\dimen0\relax
+ \multiply\dimen0 \@@rtnx\relax
+ \dimen2=\@@rtdy\@@rtunit\relax
+ \dimen2=\@@rtscale\dimen2\relax
+ \dimen2=\@@rtfactor\dimen2\relax
+ \multiply\dimen2 \@@rtny\relax
+ \def\horline
+ {\vbox
+ {\hrule
+ \!!width \dimen0
+ \!!height \linewidth
+ \!!depth \!!zeropoint}}%
+ \def\verline%
+ {\vrule
+ \!!width \linewidth
+ \!!height \dimen2
+ \!!depth \!!zeropoint}%
+ \doglobal\newcounter\@@gridc
+ \doglobal\newcounter\@@gridd
+ \doglobal\newcounter\@@gride
+ \def\setlegend##1##2##3%
+ {\gdef\@@gridc{0}%
+ \dimen0=2em\relax
+ \dimen2=##2\@@rtunit\relax
+ \dimen2=\@@rtscale\dimen2\relax
+ \dimen2=\@@rtfactor\dimen2\relax
+ \divide\dimen0 \dimen2\relax
+ \xdef\@@gride{\number\dimen0}%
+ \ifnum\@@gride>50
+ \gdef\@@gride{100}%
+ \else\ifnum\@@gride>10
+ \gdef\@@gride{50}%
+ \else\ifnum\@@gride>5
+ \gdef\@@gride{10}%
+ \else\ifnum\@@gride>1
+ \gdef\@@gride{5}%
+ \else
+ \gdef\@@gride{1}%
+ \fi\fi\fi\fi
+ \gdef\@@gridd{0}%
+ \def\legend
+ {\ifnum\@@gridd=\zerocount
+ \vbox
+ {\increment(\@@gridc,##1)%
+ \hbox to 2em{\hss\@@gridc\hss}}%
+ \global\let\@@gridd=\@@gride
+ \fi
+ \doglobal\decrement\@@gridd
+ \doglobal\increment(\@@gridc,##1)}}%
+ \def\draw##1##2##3##4##5##6##7##8##9%
+ {\setuppositioning
+ [\c!state=##8,
+ \c!xstep=\v!absolute,
+ \c!ystep=\v!absolute,
+ \c!unit=\@@rtunit,
+ \c!scale=\@@rtscale,
+ \c!factor=\@@rtfactor,
+ \c!offset=\@@rtoffset,
+ \c!xoffset=##6,
+ \c!yoffset=##7]%
+ \doifelse{##9}\v!middle
+ {\scratchdimen##3pt\scratchdimen.5\scratchdimen
+ \edef\@@psxx{\withoutpt\the\scratchdimen}%
+ \scratchdimen##4pt\scratchdimen.5\scratchdimen
+ \edef\@@psyy{\withoutpt\the\scratchdimen}%
+ \scratchcounter##2\advance\scratchcounter -1
+ \edef\@@pszz{\the\scratchcounter}}
+ {\edef\@@psxx{0}\edef\@@psyy{0}\edef\@@pszz{##2}}%
+ \position(\@@psxx,\@@psyy){##1}%
+ \setuppositioning
+ [\c!state=##8,
+ \c!xstep=\v!relative,
+ \c!ystep=\v!relative,
+ \c!scale=\@@rtscale,
+ \c!factor=\@@rtfactor,
+ \c!offset=\@@rtoffset,
+ \c!unit=\@@rtunit]%
+ \dorecurse\@@pszz{\position(##3,##4){##5}}}%
+ \draw
+ \verline\@@rtnx\@@rtdx0\verline\!!zeropoint\!!zeropoint\v!start\empty
+ \draw
+ \horline\@@rtny0\@@rtdy\horline\!!zeropoint\!!zeropoint\v!start\empty
+ \tfx
+ \doifnot\@@rtxstep{0}
+ {\setlegend\@@rtxstep\@@rtdx\@@rtx
+ \draw\legend\@@rtnx\@@rtdx0\legend{-1em}{-1.5em}\v!overlay\@@rtlocation}%
+ \doifnot\@@rtystep{0}
+ {\setlegend\@@rtystep\@@rtdy\@@rty
+ \draw\legend\@@rtny0\@@rtdy\legend{-2em}{-.75ex}\v!overlay\@@rtlocation}%
+ \stoppositioning
+ \endgroup}
+
+\let\grid\basegrid
+
+% Dit wordt:
+%
+% \doorverwijzen[naam][instellingen] enz.
+%
+% waarbij bijvoorbeeld publicatie is. Dit levert:
+%
+% \start
+% \stop
+%
+% \beginvan
+% \eindvan
+%
+% \publicatie
+%
+% \volledigelijstmetpublicaties
+%
+% eigenlijk kan ook door... zo worden uitgebreid!
+
+% old, will become obsolete or module, replace by bib module
+
+% \defineenumeration
+% [@publicatie]
+% [\c!location=\v!left,
+% \c!width=\@@pbwidth,\c!hang=,\c!sample=,
+% \c!before=\@@pbbefore,\c!after=\@@pbafter,\c!inbetween=,
+% \c!headstyle=\@@pbheadstyle,\c!style=,
+% \c!headcolor=\@@pbheadcolor,\c!color=,
+% \c!way=\@@pbway,\c!blockway=\@@pbblockway,
+% \c!text=,\c!left=\@@pbleft,\c!right=\@@pbright]
+
+% \def\dosetuppublications[#1]%
+% {\getparameters[\??pb][#1]}
+%
+% \def\setuppublications%
+% {\dosingleargument\dosetuppublications}
+%
+% \def\apa@publicatie
+% {\doifsomething\@@pb@naam {\@@pb@naam,\space}%
+% \doifsomething\@@pb@titel {{\sl\@@pb@titel}.\space}%
+% \doifsomething\@@pb@jaar {(\@@pb@jaar).\space}%
+% \doifsomething\@@pb@plaats {\@@pb@plaats\doifelsenothing\@@pb@uitgever{.}{:\space}}%
+% \doifsomething\@@pb@uitgever{\@@pb@uitgever.}}
+%
+% \def\normaal@publicatie
+% {\@@pb@naam, \@@pb@titel, \@@pb@jaar, \@@pb@pagina, \@@pb@plaats, \@@pb@uitgever.}
+%
+% \def\complexstartpublicatie[#1]#2\stoppublicatie
+% {\bgroup
+% \def\dosetpublicatie
+% {\processcommalist
+% [naam,titel,jaar,plaats,pagina,uitgever]
+% \setpublicatie
+% \ignorespaces}%
+% \def\setpublicatie##1%
+% {\letvalue{\??pb @##1}\empty
+% \setvalue{##1}####1{\setvalue{\??pb @##1}{####1}\ignorespaces}}%
+% \def\getpublicatie%
+% {\doifsomething\@@pbalternative{\getvalue{\@@pbalternative @publicatie}}}%
+% \doifelse\@@pbnumbering\v!yes
+% {\@publicatie[#1]\dosetpublicatie#2\getpublicatie\par}%
+% {\@@pbbefore
+% \dosetpublicatie\ignorespaces#2\getpublicatie
+% \@@pbafter}%
+% \egroup}
+%
+% \definecomplexorsimpleempty\startpublicatie
+%
+% \def\publication#1[#2]%
+% {\@@pbleft\in{#1}[#2]\@@pbright}
+%
+% \setuppublications
+% [\c!numbering=\v!yes,
+% \c!alternative=\c!apa,
+% \c!width=2em,
+% \c!hang=,
+% \c!sample=,
+% \c!before=,
+% \c!after=,
+% \c!inbetween=,
+% \c!headstyle=,
+% \c!headcolor=,
+% \c!style=,
+% \c!color=,
+% \c!blockway=\v!by\v!text,
+% \c!way=\v!by\v!text,
+% \c!text=,
+% \c!left={[},
+% \c!right={]}]
+
+% only used at pragma, move from kernel to run time module
+
+\def\referraldate
+ {\currentdate[\v!referral]}
+
+\def\doreferral[#1]%
+ {\noheaderandfooterlines
+ \bgroup
+ \getparameters
+ [\??km]
+ [\c!bet=\unknown,\c!dat=\unknown,\c!ken=\unknown,
+ \c!from=,\c!to=,\c!ref=,#1]%
+ % moet anders, hoort niet in 01b
+ \assigntranslation[\s!nl=referentie,\s!en=reference,\s!de=Referenz,\s!sp=referencia]\to\@@@kmref
+ \assigntranslation[\s!nl=van,\s!en=from,\s!de=Von,\s!sp=de]\to\@@@kmvan
+ \assigntranslation[\s!nl=aan,\s!en=to,\s!de=An,\s!sp=a]\to\@@@kmaan
+ \assigntranslation[\s!nl=betreft,\s!en=concerns,\s!de=Betreff,\s!sp=]\to\@@@kmbet
+ \assigntranslation[\s!nl=datum,\s!en=date,\s!de=Datum,\s!sp=fecha]\to\@@@kmdat
+ \assigntranslation[\s!nl=kenmerk,\s!en=mark,\s!de=Kennzeichen,\s!sp=]\to\@@@kmken
+ %
+ \definetabulate[\s!dummy][|l|p|]
+ \startdummy
+ \NC\@@@kmbet\EQ\@@kmbet\NC\NR
+ \NC\@@@kmdat\EQ\@@kmdat\NC\NR
+ \NC\@@@kmken\EQ\expanded{\smallcapped{\@@kmken}}\NC\NR
+ \doifsomething{\@@kmfrom\@@kmto}{\NC\NC\NC\NR}%
+ \doifsomething \@@kmfrom {\NC\@@@kmvan\EQ\@@kmfrom\NC\NR}%
+ \doifsomething \@@kmto {\NC\@@@kmaan\EQ\@@kmto\NC\NR}%
+ \doifsomething \@@kmref {\NC\NC\NC\NR\NC\@@@kmref\EQ\@@kmref\NC\NR}%
+ \stopdummy
+ \egroup}
+
+\def\referral
+ {\dosingleargument\doreferral}
+
+% FUZZY OLD STUFF: will be removed when not used in some manual;
+% rows instead of columns, i'd forgotten that this code exist
+%
+% \definesystemvariable{ri}
+%
+% \def\setuprows
+% {\dodoubleargument\getparameters[\??ri]}
+%
+% \definecomplexorsimpleempty\startrows
+%
+% \def\complexstartrows[#1]%
+% {\bgroup
+% \setuprows[#1]%
+% \let\do@@ribottom\relax
+% \def\row
+% {\do@@ribottom
+% \egroup
+% \dimen0\vsize
+% \divide\dimen0 \@@rin
+% \advance\dimen0 -\lineskip
+% \vbox to \dimen0
+% \bgroup
+% \@@ritop
+% \let\do@@ribottom\@@ribottom
+% \ignorespaces}%
+% \bgroup
+% \row}
+%
+% \def\stoprows
+% {\do@@ribottom
+% \egroup
+% \egroup}
+%
+% \setuprows
+% [\c!n=2,
+% \c!top=,
+% \c!bottom=\vfill]
+
+% THIS WAS MAIN-003.TEX
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+\definetabulate
+ [\v!legend]
+ [|emj1|i1|mR|]
+
+\setuptabulate
+ [\v!legend]
+ [\c!unit=.75em,\c!inner=\setquicktabulate\leg,EQ={=}]
+
+\definetabulate
+ [\v!legend][\v!two]
+ [|emj1|emk1|i1|mR|]
+
+\definetabulate
+ [\v!fact]
+ [|R|ecmj1|i1mR|]
+
+\setuptabulate
+ [\v!fact]
+ [\c!unit=.75em,\c!inner=\setquicktabulate\fact,EQ={=}]
+
+\unexpanded\def\xbox
+ {\bgroup\aftergroup\egroup\hbox\bgroup\tx\let\next=}
+
+\unexpanded\def\xxbox
+ {\bgroup\aftergroup\egroup\hbox\bgroup\txx\let\next=}
+
+% \def\mrm#1%
+% {$\rm#1$}
+
+%D \macros
+%D {definepairedbox, setuppairedbox, placepairedbox}
+%D
+%D Paired boxes, formally called legends, but from now on a
+%D legend is just an instance, are primarily meant for
+%D typesetting some text alongside an illustration. Although
+%D there is quite some variation possible, the functionality is
+%D kept simple, if only because in most cases such pairs are
+%D typeset sober.
+%D
+%D The location specification accepts a pair, where the first
+%D keyword specifies the arrangement, and the second one the
+%D alignment. The first key of the location pair is one of
+%D \type {left}, \type {right}, \type {top} or \type {bottom},
+%D while the second key can also be \type {middle}.
+%D
+%D The first box is just collected in an horizontal box, but
+%D the second one is a vertical box that gets passed the
+%D bodyfont and alignment settings.
+
+%D Today we would implement this using layers .... but for the
+%D moment we keep it this way.
+
+% \startbuffer[test]
+% \test left \test left,top \test left,bottom \test left,middle
+% \test right \test right,top \test right,bottom \test right,middle
+% \test top \test top,left \test top,right \test top,middle
+% \test bottom \test bottom,left \test bottom,right \test bottom,middle
+% \stopbuffer
+%
+% \def\showtest#1%
+% {\pagina
+% \typebuffer[demo]
+% \def\test##1
+% {\startlinecorrection[blank]
+% \getbuffer[demo]%
+% \ruledhbox\placelegend
+% [bodyfont=6pt,location={##1}]
+% {\framed[width=.25\textwidth]{\tttf##1}}
+% {#1}
+% \stoplinecorrection}
+% \getbuffer[test]}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=\hsize,maxwidth=\makeupwidth,
+% height=\vsize,maxheight=\makeupheight]
+% \stopbuffer
+%
+% \showtest{These examples demonstrate the default settings.}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=\textwidth,
+% maxwidth=\textwidth]
+% \stopbuffer
+%
+% \showtest{\input tufte }
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=.65\textwidth]
+% \stopbuffer
+%
+% \showtest{\input knuth }
+%
+% \startbuffer[demo]
+% \setuplegend
+% [height=2cm]
+% \stopbuffer
+%
+% \showtest{These examples demonstrate some other settings.}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=.65\textwidth,
+% height=2cm]
+% \stopbuffer
+%
+% \showtest{These examples demonstrate some other settings.}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [n=2,align=right,width=.5\textwidth]
+% \stopbuffer
+%
+% \showtest{\input zapf }
+
+%D \macros
+%D {setuplegend, placelegend}
+%D
+%D It makes sense to typeset a legend to a figure in \TEX\
+%D and not in a drawing package. The macro \type {\placelegend}
+%D combines a figure (or something else) and its legend. This
+%D command is just a paired box.
+%D
+%D The legend is placed according to \type {location}, being
+%D \type {bottom} or \type {right}. The macro macro is used as
+%D follows.
+%D
+%D \starttyping
+%D \placefigure
+%D {whow}
+%D {\placelegend
+%D {\externalfigure[cow]}
+%D {\starttabulation
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulation}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend
+%D {\externalfigure[cow]}
+%D {\starttabulation[|l|l|l|l|]
+%D \NC 1 \NC head \NC 3 \NC tail \NC \NR
+%D \NC 2 \NC legs \NC \NC \NC \NR
+%D \stoptabulation}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {\starttabulation
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulation}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {head \par legs \par tail}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {\startitemize[packed]
+%D \item head \item legs \item tail \item belly \item horns
+%D \stopitemize}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2,width=.8\hsize]
+%D {\externalfigure[cow]}
+%D {\startitemize[packed]
+%D \item head \item legs \item tail \item belly \item horns
+%D \stopitemize}}
+%D \stoptyping
+
+\newbox\firstpairedbox
+\newbox\secondpairedbox
+
+\def\definepairedbox
+ {\dodoubleempty\dodefinepairedbox}
+
+\def\dodefinepairedbox[#1][#2]%
+ {\getparameters
+ [\??ld#1]
+ [\c!n=1,
+ \c!distance=\bodyfontsize,
+ \c!before=,
+ \c!after=,
+ \c!color=,
+ \c!style=,
+ \c!inbetween={\blank[\v!medium]},
+ \c!width=\hsize,
+ \c!height=\vsize,
+ \c!maxwidth=\textwidth, % \makeupwidth,
+ \c!maxheight=\textheight, % \makeupheight,
+ \c!bodyfont=,
+ \c!align=,
+ \c!location=\v!bottom,
+ #2]%
+ \setvalue{\e!setup#1\e!endsetup}{\setuppairedbox[#1]}%
+ \setvalue{\e!place#1}{\placepairedbox[#1]}}
+
+\def\setuppairedbox
+ {\dodoubleempty\dosetuppairedbox}
+
+\def\dosetuppairedbox[#1]%
+ {\getparameters[\??ld#1]}
+
+\def\placepairedbox
+ {\bgroup\dodoubleempty\doplacepairedbox}
+
+\def\doplacepairedbox[#1][#2]% watch the hsize/vsize tricks
+ {\setuppairedbox[#1][#2]% % and don't change them
+ \copyparameters % brrr
+ [\??ld][\??ld#1]
+ [\c!n,\c!distance,\c!inbetween,\c!before,\c!after,
+ \c!width,\c!height,\c!maxwidth,\c!maxheight,
+ \c!color,\c!style,\c!bodyfont,\c!align,\c!location]%
+ \@@ldbefore\bgroup
+ \global\setsystemmode{pairedbox}%
+ \beforefirstpairedbox
+ \dowithnextbox
+ {\betweenbothpairedboxes
+ \dowithnextbox
+ {\afterbothpairedboxes
+ \egroup\@@ldafter
+ \egroup}
+ \vbox\bgroup
+ \insidesecondpairedbox
+ \let\next=}
+ \hbox}
+
+\def\beforefirstpairedbox
+ {\chardef\pairedlocationa1 % left
+ \chardef\pairedlocationb4 % middle
+ \getfromcommacommand[\@@ldlocation][1]%
+ \processaction
+ [\commalistelement]
+ [ \v!left=>\chardef\pairedlocationa0,
+ \v!right=>\chardef\pairedlocationa1,
+ \v!top=>\chardef\pairedlocationa2,
+ \v!bottom=>\chardef\pairedlocationa3]%
+ \getfromcommacommand[\@@ldlocation][2]%
+ \processaction
+ [\commalistelement]
+ [ \v!left=>\chardef\pairedlocationb0,
+ \v!right=>\chardef\pairedlocationb1,
+ \v!high=>\chardef\pairedlocationb2,
+ \v!top=>\chardef\pairedlocationb2,
+ \v!low=>\chardef\pairedlocationb3,
+ \v!bottom=>\chardef\pairedlocationb3,
+ \v!middle=>\chardef\pairedlocationb4]}
+
+\def\betweenbothpairedboxes
+ {\switchtobodyfont[\@@ldbodyfont]% split under same regime
+ \setbox\firstpairedbox\flushnextbox
+ \ifnum\pairedlocationa<2
+ \hsize\wd\firstpairedbox % trick
+ \hsize\@@ldwidth
+ \scratchdimen\wd\firstpairedbox
+ \advance\scratchdimen \@@lddistance
+ \bgroup\advance\scratchdimen \hsize
+ \ifdim\scratchdimen>\@@ldmaxwidth\relax
+ \egroup
+ \hsize\@@ldmaxwidth
+ \advance\hsize -\scratchdimen
+ \else
+ \egroup
+ \fi
+ \else
+ \hsize\wd\firstpairedbox
+ \hsize\@@ldwidth % can be \hsize
+ \ifdim\hsize>\@@ldmaxwidth\relax \hsize\@@ldmaxwidth \fi % can be \hsize
+ \fi
+ \ifnum\@@ldn>\plusone
+ \setrigidcolumnhsize\hsize\@@lddistance\@@ldn
+ \fi}
+
+\def\afterbothpairedboxes
+ {\setbox\secondpairedbox\vbox
+ {% \localstartcolor[\@@ldcolor]% does not work yet
+ \ifnum\@@ldn>1
+ \rigidcolumnbalance\nextbox
+ \else
+ \flushnextbox
+ \fi
+ }% \localstopcolor}%
+ \ifnum\pairedlocationa<2\hbox\else\vbox\fi\bgroup % hide vsize
+ \forgetall
+ \ifnum\pairedlocationa<2
+ \scratchdimen\maxoftwoboxdimens\ht\firstpairedbox\secondpairedbox
+ \vsize\scratchdimen
+ \ifdim\scratchdimen<\@@ldheight\relax % can be \vsize
+ \scratchdimen\@@ldheight
+ \fi
+ \ifdim\scratchdimen>\@@ldmaxheight\relax
+ \scratchdimen\@@ldmaxheight
+ \fi
+ \valignpairedbox\firstpairedbox \scratchdimen
+ \valignpairedbox\secondpairedbox\scratchdimen
+ \else
+ \scratchdimen\maxoftwoboxdimens\wd\firstpairedbox\secondpairedbox
+ \halignpairedbox\firstpairedbox \scratchdimen
+ \halignpairedbox\secondpairedbox\scratchdimen
+ \scratchdimen\ht\secondpairedbox
+ \vsize\scratchdimen
+ \ifdim\ht\secondpairedbox<\@@ldheight\relax % can be \vsize
+ \scratchdimen\@@ldheight\relax % \relax needed
+ \fi
+ \ifdim\scratchdimen>\@@ldmaxheight\relax % todo: totale hoogte
+ \scratchdimen\@@ldmaxheight\relax % \relax needed
+ \fi
+ \ifdim\scratchdimen>\ht\secondpairedbox
+ \setbox\secondpairedbox\vbox to \scratchdimen
+ {\ifnum\pairedlocationa=3 \vss\fi %
+ \box\secondpairedbox
+ \ifnum\pairedlocationa=2 \vss\fi}% \kern\zeropoint
+ \fi
+ \fi
+ \ifcase\pairedlocationa
+ \box\secondpairedbox\hskip\@@lddistance\box\firstpairedbox \or
+ \box\firstpairedbox \hskip\@@lddistance\box\secondpairedbox\or
+ \box\secondpairedbox\endgraf \nointerlineskip \@@ldinbetween \box\firstpairedbox \or
+ \box\firstpairedbox \endgraf \nointerlineskip \@@ldinbetween \box\secondpairedbox\else
+ \fi
+ \egroup}
+
+\def\insidesecondpairedbox
+ {\forgetall
+ \setupalign[\@@ldalign]%
+ \tolerantTABLEbreaktrue % hm.
+ \blank[\v!disable]%
+ \everypar{\begstrut}}
+
+\def\maxoftwoboxdimens#1#2#3%
+ {#1\ifdim#1#2>#1#3 #2\else#3\fi}
+
+\def\valignpairedbox#1#2%
+ {\setbox#1\vbox to #2
+ {\ifcase\pairedlocationb\or\or\or\vss\or\vss\fi
+ \box#1\relax
+ \ifcase\pairedlocationb\or\or\vss\or\or\vss\fi}}
+
+\def\halignpairedbox#1#2%
+ {\setbox#1\hbox to #2
+ {\ifcase\pairedlocationb\or\hss\or\or\or\hss\fi
+ \box#1\relax
+ \ifcase\pairedlocationb\hss\or\or\or\or\hss\fi}}
+
+\definepairedbox[\v!legend]
+
+%D Goody:
+
+\appendtoks
+ \global\resetsystemmode{combination}%
+ \global\resetsystemmode{pairedbox}%
+\to \everyinsidefloat
+
+% todo: \startcombination \startcomb \stopcomb ...
+
+\newcount\horcombination % counter
+\newcount\totcombination
+
+\def\definecombination
+ {\dodoubleempty\dodefinecombination}
+
+\def\dodefinecombination[#1][#2]%
+ {\copyparameters
+ [\??co#1][\??co]
+ [\c!width,\c!height,\c!distance,\c!location,%
+ \c!before,\c!inbetween,\c!after,\c!align,%
+ \c!style,\c!color]%
+ \getparameters
+ [\??co#1][#2]}
+
+\def\setupcombinations
+ {\dodoubleempty\dosetupcombinations}
+
+\def\dosetupcombinations[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??co#1][#2]%
+ \else
+ \getparameters[\??co][#1]%
+ \fi}
+
+\def\combinationparameter#1%
+ {\csname\??co\currentcombination#1\endcsname}%
+
+\def\startcombination
+ {\bgroup % so we can grab a group
+ \dodoubleempty\dostartcombination}
+
+% \startcombination {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[2*1] {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[1*2] {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[2] {alpha} {a} {beta} {b} \stopcombination
+
+\def\dostartcombination[#1][#2]%
+ {\global\setsystemmode{combination}%
+ \doifnothing{#1}\firstargumentfalse % to be sure (when called in macros)
+ \doifnothing{#2}\secondargumentfalse % to be sure (when called in macros)
+ \ifsecondargument
+ \def\currentcombination{#1}%
+ \edef\currentcombinationspec{#2*1*}%
+ \else % better : \doifcombinationelse ... \??co#1\c!location
+ \doifinstringelse{*}{#1}
+ {\let\currentcombination\empty
+ \edef\currentcombinationspec{#1*1*}}
+ {\doifnumberelse{#1}
+ {\let\currentcombination\empty
+ \edef\currentcombinationspec{#1*1*}}
+ {\def\currentcombination{#1}%
+ \edef\currentcombinationspec{2*1*}}}%
+ \fi
+ \forgetall
+ \doifelse{\combinationparameter\c!height}\v!fit
+ \vbox {\vbox to \combinationparameter\c!height}%
+ \bgroup
+ \expanded{\dodostartcombination[\currentcombinationspec]}}
+
+\long\def\dodostartcombination[#1*#2*#3]%
+ {\setuphorizontaldivision
+ [\c!n=\v!fit,\c!distance=\combinationparameter\c!distance]%
+ \global\horcombination#1%
+ \global\totcombination#2%
+ \global\setbox\combinationstack\emptybox
+ \xdef\maxhorcombination{\the\horcombination}%
+ \multiply\totcombination\horcombination
+ \tabskip\zeropoint
+ \doifelse{\combinationparameter\c!width}\v!fit
+ {\halign}{\halign to \combinationparameter\c!width}%
+ \bgroup&%
+ %\hfil##\hfil% now : location={left,top}
+ \expanded{\doifnotinset{\v!left}{\combinationparameter\c!location}}\hfil
+ ##%
+ \expanded{\doifnotinset{\v!right}{\combinationparameter\c!location}}\hfil
+ &\tabskip\zeropoint \!!plus 1fill##\cr
+ \docombination}
+
+\def\docombination % we want to add struts but still ignore an empty box
+ {\dowithnextbox
+ {\setbox0\flushnextbox
+ \dowithnextbox
+ {\setbox2\flushnextbox
+ \dodocombination}%
+ \vtop\bgroup
+ \def\next
+ {\futurelet\nexttoken\nextnext}%
+ \def\nextnext
+ {\ifx\nexttoken\egroup \else % the next box is empty
+ \hsize\wd0
+ \setupalign[\combinationparameter\c!align]%
+ \dostartattributes{\??co\currentcombination}\c!style\c!color\empty
+ \bgroup
+ \aftergroup\endstrut
+ \aftergroup\dostopattributes
+ \aftergroup\egroup
+ \begstrut
+ \fi}%
+ \afterassignment\next\let\nexttoken=}
+ \hbox}
+
+% stupid version, does not align top stuff when captions,
+% keep as example
+%
+% \def\dodocombination
+% {\vbox
+% {\forgetall % \setupwhitespace[\v!none]%
+% \let\next\vbox
+% \ExpandFirstAfter\processallactionsinset
+% [\combinationparameter\c!location]
+% [ \v!top=>\let\next\tbox,
+% \v!middle=>\let\next\halfwaybox]%
+% \next{\copy0}%
+% \ifdim\ht2>\zeropoint % beter dan \wd2, nu \strut mogelijk
+% \combinationparameter\c!inbetween
+% %\vtop % wrong code
+% % {\nointerlineskip % recently added
+% % \hsize\wd0
+% % \setupalign[\combinationparameter\c!align]% % \raggedcenter
+% % \begstrut\unhbox2\endstrut}%
+% \box2
+% \fi}%
+% \ifnum\totcombination>\plusone
+% \global\advance\totcombination\minusone
+% \global\advance\horcombination\minusone
+% \ifnum\horcombination=\zerocount
+% \def\next
+% {\cr\noalign
+% {\forgetall % \setupwhitespace[\v!geen]% no
+% \nointerlineskip
+% \combinationparameter\c!before
+% \combinationparameter\c!after
+% \vss
+% \nointerlineskip}%
+% \global\horcombination\maxhorcombination\relax
+% \docombination}%
+% \else
+% \def\next
+% {&&&\hskip\combinationparameter\c!distance&\docombination}%
+% \fi
+% \else
+% \def\next
+% {\cr\egroup}%
+% \fi
+% \next}
+
+% \def\dodocombination
+% {\vbox
+% {\forgetall % \setupwhitespace[\v!none]%
+% \let\next\vbox
+% \ExpandFirstAfter\processallactionsinset
+% [\combinationparameter\c!plaats]
+% [ \v!top=>\let\next\tbox,
+% \v!middle=>\let\next\halfwaybox]%
+% \next{\copy0}%
+% % we need to save the caption for a next alignment line
+% \saveoncombinationstack2}%
+% \ifnum\totcombination>\plusone
+% \global\advance\totcombination\minusone
+% \global\advance\horcombination\minusone
+% \ifnum\horcombination=\zerocount
+% \def\next
+% {\cr
+% \flushcombinationstack
+% \noalign
+% {\forgetall % \setupwhitespace[\v!none]% no
+% \global\setbox\combinationstack\emptybox
+% \nointerlineskip
+% \combinationparameter\c!after
+% \combinationparameter\c!before
+% \vss
+% \nointerlineskip}%
+% \global\horcombination\maxhorcombination\relax
+% \docombination}%
+% \else
+% \def\next
+% {&&&\hskip\combinationparameter\c!distance&\docombination}%
+% \fi
+% \else
+% \def\next
+% {\cr
+% \flushcombinationstack
+% \egroup}%
+% \fi
+% \next}
+
+\def\depthonlybox
+ {\dowithnextbox{\vtop{\hsize\wd\nextbox\kern\zeropoint\box\nextbox}}\vbox}
+
+% \def\boxwithstrutheight
+% {\dowithnextbox
+% {\scratchdimen\strutheight
+% \advance\scratchdimen-\nextboxht
+% \hbox{\raise\scratchdimen\box\nextbox}}%
+% \vbox}
+
+\def\dodocombination
+ {\vbox
+ {\forgetall % \setupwhitespace[\v!none]%
+ \let\next\vbox
+ \expanded{\processallactionsinset[\combinationparameter\c!location]}
+ [ \v!top=>\let\next\depthonlybox, % \tbox,
+ \v!middle=>\let\next\halfwaybox]%
+ \next{\copy0}%
+ % we need to save the caption for a next alignment line
+ \saveoncombinationstack2}%
+ \ifnum\totcombination>\plusone
+ \global\advance\totcombination\minusone
+ \global\advance\horcombination\minusone
+ \ifnum\horcombination=\zerocount
+ \def\next
+ {\cr
+ \flushcombinationstack
+ \noalign
+ {\forgetall % \setupwhitespace[\v!none]% no
+ \global\setbox\combinationstack\emptybox
+ \nointerlineskip
+ \combinationparameter\c!after
+ \combinationparameter\c!before
+ \vss
+ \nointerlineskip}%
+ \global\horcombination\maxhorcombination\relax
+ \docombination}%
+ \else
+ \def\next
+ {&&&\hskip\combinationparameter\c!distance&\docombination}%
+ \fi
+ \else
+ \def\next
+ {\cr
+ \flushcombinationstack
+ \egroup}%
+ \fi
+ \next}
+
+% formally ok:
+%
+% \def\stopcombination
+% {\egroup
+% \egroup}
+%
+% more robust:
+%
+% \def\stopcombination
+% {{}{}{}{}{}{}{}{}% catches (at most 4) missing entries
+% \egroup
+% \egroup}
+%
+% even better:
+
+\def\stopcombination
+ {{\scratchtoks{{}{}{}}\dorecurse\totcombination{\appendtoks{}{}{}{}\to\scratchtoks}\expandafter}\the\scratchtoks
+ \egroup
+ \egroup}
+
+\newbox\combinationstack
+
+\def\saveoncombinationstack#1%
+ {\global\setbox\combinationstack\hbox
+ {\hbox{\box#1}\unhbox\combinationstack}}
+
+\def\flushcombinationstack
+ {\noalign
+ {\ifdim\ht\combinationstack>\zeropoint
+\nointerlineskip % nieuw
+ \combinationparameter\c!inbetween
+ \global\horcombination\maxhorcombination
+ \globallet\doflushcombinationstack\dodoflushcombinationstack
+ \else
+ \global\setbox\combinationstack\emptybox
+ \globallet\doflushcombinationstack\donothing
+ \fi}%
+ \doflushcombinationstack\crcr}
+
+\gdef\dodoflushcombinationstack
+ {\global\setbox\combinationstack\hbox
+ {\unhbox\combinationstack
+ \global\setbox1\lastbox}%
+ \box1% \ruledhbox{\box1}%
+ \global\advance\horcombination\minusone\relax
+ \ifnum\horcombination>\zerocount
+ \def\next{&&&&\doflushcombinationstack}%
+ \else
+ \global\setbox\combinationstack\emptybox
+ %\let\next\relax
+ \@EA\gobbleoneargument
+ \fi
+ \next}
+
+\setupcombinations
+ [\c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!distance=1em,
+ \c!location=\v!bottom, % can be something {top,left}
+ \c!before=\blank,
+ \c!inbetween={\blank[\v!medium]},
+ \c!style=,
+ \c!color=,
+ \c!after=,
+ \c!align=\v!middle]
+
+%D \macros
+%D {startfloatcombination}
+%D
+%D \setupexternalfigures[directory={../sample}]
+%D \startbuffer
+%D \placefigure
+%D [left,none]
+%D {}
+%D {\startfloatcombination[2*2]
+%D \placefigure{alpha}{\externalfigure[cow.pdf][width=1cm]}
+%D \placefigure{beta} {\externalfigure[cow.pdf][width=2cm]}
+%D \placefigure{gamma}{\externalfigure[cow.pdf][width=3cm]}
+%D \placefigure{delta}{\externalfigure[cow.pdf][width=4cm]}
+%D \stopfloatcombination}
+%D
+%D \input tufte
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\startfloatcombination
+ {\dodoubleempty\dostartfloatcombination}
+
+\def\dostartfloatcombination[#1][#2]%
+ {\vbox\bgroup
+ %\insidecolumnstrue % trick, forces no centering, todo: proper switch/feature
+ \chardef\postcenterfloatmethod\zerocount
+ \forcelocalfloats
+ \def\stopfloatcombination
+ {\scratchtoks\emptytoks
+ \dorecurse\noflocalfloats
+ {\appendetoks{\noexpand\getlocalfloat{\recurselevel}}{}\to\scratchtoks}%
+ \expanded{\startcombination[#1]\the\scratchtoks}\stopcombination
+ \resetlocalfloats
+ \egroup}}
+
+\def\placerelativetoeachother#1#2%
+ {\bgroup
+ \dowithnextbox
+ {\bgroup
+ \setbox0\box\nextbox
+ \dowithnextbox
+ {\setbox2\box\nextbox
+ #1{#2#########2\cr\box0\cr\box2\cr}
+ \egroup
+ \egroup}
+ \hbox}
+ \hbox}
+
+\def\placeontopofeachother{\placerelativetoeachother\halign\hss}
+\def\placesidebyside {\placerelativetoeachother\valign\vss}
+
+% this will be replaced or go away, never used
+
+\def\douseexternalfiles[#1][#2]%
+ {\getparameters
+ [\??fi#1]
+ [\c!file=,
+ \c!bodyfont=,
+ \c!option=,
+ #2]}
+
+\def\useexternalfiles
+ {\dodoubleargument\douseexternalfiles}
+
+\def\dostelexternefilesin[#1][#2]%
+ {\doifundefinedelse{\??fi#1\c!file}
+ {\useexternalfiles[#1][#2]}
+ {\getparameters[\??fi#1][#2]}}
+
+\def\stelexternefilesin
+ {\dodoubleargument\dostelexternefilesin}
+
+\def\verwerkexternefile#1#2#3%
+ {\bgroup
+ \getparameters[\??fi#1][\c!file=,#3]%
+ \doinputonce{\getvalue{\??fi#1\c!file}}%
+ \ExpandFirstAfter\switchtobodyfont[\getvalue{\??fi#1\c!bodyfont}]%
+ \readsysfile{#2} % beter: loc of fix gebied
+ \donothing
+ {\showmessage\m!systems{41}{#2,#1}}%
+ \egroup}
+
+\def\douseexternalfile[#1][#2][#3][#4]%
+ {\stelexternefilesin[#1][]%
+ \doinputonce{\getvalue{\??fi#1\c!file}}%
+ \doifelsenothing{#2}
+ {\setvalue{#3}{\verwerkexternefile{#1}{#3}{#4}}}
+ {\setvalue{#2}{\verwerkexternefile{#1}{#3}{#4}}}}
+
+\def\useexternalfile
+ {\doquadrupleargument\douseexternalfile}
+
+\useexternalfiles
+ [pictex]
+ [\c!bodyfont=\v!small,
+ \c!file=pictex]
+
+\useexternalfiles
+ [table]
+ [\c!file=table]
+
+%D A couple of examples, demonstrating how the depth is
+%D taken care of:
+%D
+%D \startbuffer
+%D test\rotate[frame=on, rotation=0] {gans}%
+%D test\rotate[frame=on, rotation=90] {gans}%
+%D test\rotate[frame=on, rotation=180]{gans}%
+%D test\rotate[frame=on, rotation=270]{gans}%
+%D test
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+% When we rotate over arbitrary angles, we need to relocate the
+% resulting box because rotation brings that box onto the negative
+% axis. The calculations (mostly sin and cosine) need to be tuned for
+% the way a box is packages (i.e. the refence point). A typical example
+% of drawing, scribbling, and going back to the days of school math.
+%
+% We do a bit more calculations than needed, simply because that way
+% it's easier to debug the code.
+
+\def\dododorotatenextbox
+ {\setbox\nextbox\vbox to \@@layerysiz
+ {\vfill
+ \hbox to \@@layerxsiz
+ {\dostartrotation\@@rorotation
+ \nextboxwd\zeropoint
+ \nextboxht\zeropoint
+ \flushnextbox
+ \dostoprotation
+ \hfill}%
+ \kern\@@layerypos}%
+ \setbox\nextbox\hbox
+ {\kern\@@layerxpos
+ \kern\@@layerxoff
+ \lower\@@layeryoff\flushnextbox}}
+
+\def\dodorotatenextbox#1#2% quite some trial and error -)
+ {\dontshowcomposition
+ \dontcomplain
+ \ifnum#2=\plusfour
+ % new, location=middle
+ \!!widthb \nextboxwd
+ \!!heightb\nextboxht
+ \!!depthb \nextboxdp
+ \setbox\nextbox\vbox{\vskip.5\nextboxht\hskip-.5\nextboxwd\flushnextbox}%
+ \smashbox\nextbox
+ \fi
+ \!!widtha \nextboxwd
+ \!!heighta\nextboxht
+ \!!deptha \nextboxdp
+ \!!doneafalse
+ \!!donebfalse
+ \ifcase#2\or
+ % 1: fit
+ \or
+ % 2: depth, not fit
+ \!!doneatrue
+ \!!donebtrue
+ \or
+ % 3: depth, fit
+ \!!donebtrue
+ \fi
+ \setbox\nextbox\vbox{\hbox{\raise\nextboxdp\flushnextbox}}%
+ \!!dimena \nextboxht
+ \setcalculatedcos\cos\@@rorotation
+ \setcalculatedsin\sin\@@rorotation
+ \@@layerxpos\zeropoint
+ \@@layerypos\zeropoint
+ \@@layerxoff\zeropoint
+ \@@layeryoff\zeropoint
+ \ifdim\sin\points>\zeropoint
+ \ifdim\cos\points>\zeropoint
+ \@@layerxsiz \cos\!!widtha
+ \@@layerysiz \sin\!!widtha
+ \advance\@@layerxsiz \sin\!!dimena
+ \advance\@@layerysiz \cos\!!dimena
+ \@@layerypos \cos\!!dimena
+ \if!!donea
+ \@@layerxoff \negated\sin\!!dimena
+ \advance\@@layerxoff \sin\!!deptha
+ \fi
+ \if!!doneb
+ \@@layeryoff \cos\!!deptha
+ \fi
+ \dododorotatenextbox
+ \else
+ \@@layerxsiz \negated\cos\!!widtha
+ \@@layerysiz \sin\!!widtha
+ \advance\@@layerxsiz \sin\!!dimena
+ \advance\@@layerysiz \negated\cos\!!dimena
+ \@@layerxpos \negated\cos\!!widtha
+ \if!!donea
+ \@@layerxoff -\@@layerxsiz
+ \advance\@@layerxoff \sin\!!deptha
+ \fi
+ \if!!doneb
+ \@@layeryoff \negated\cos\!!heighta
+ \fi
+ \dododorotatenextbox
+ \wd\nextbox\if!!donea\sin\!!deptha\else\@@layerxsiz\fi
+ \fi
+ \else
+ \ifdim\cos\points<\zeropoint
+ \@@layerxsiz \negated\cos\!!widtha
+ \@@layerysiz \negated\sin\!!widtha
+ \advance\@@layerxsiz \negated\sin\!!dimena
+ \advance\@@layerysiz \negated\cos\!!dimena
+ \@@layerxpos \@@layerxsiz
+ \@@layerypos \negated\sin\!!widtha
+ \if!!donea
+ \@@layerxoff -\@@layerxsiz
+ \advance\@@layerxoff \negated\sin\!!heighta
+ \fi
+ \if!!doneb
+ \@@layeryoff \@@layerysiz
+ \advance\@@layeryoff \cos\!!deptha
+ \fi
+ \dododorotatenextbox
+ \wd\nextbox\if!!donea\negated\sin\!!heighta\else\@@layerxsiz\fi
+ \else
+ \@@layerxsiz \cos\!!widtha
+ \@@layerysiz \negated\sin\!!widtha
+ \advance\@@layerxsiz \negated\sin\!!dimena
+ \advance\@@layerysiz \cos\!!dimena
+ \ifdim\sin\points=\zeropoint
+ \@@layerxpos \zeropoint
+ \@@layerxoff \zeropoint
+ \@@layerypos \@@layerysiz
+ \if!!doneb
+ \@@layeryoff \!!deptha
+ \fi
+ \else
+ \@@layerypos \@@layerysiz
+ \@@layerxpos \negated\sin\!!dimena
+ \if!!donea
+ \@@layerxoff -\@@layerxsiz
+ \advance\@@layerxoff \negated\sin\!!heighta
+ \fi
+ \if!!doneb
+ \@@layeryoff \negated\sin\!!deptha
+ \fi
+ \fi
+ \dododorotatenextbox
+ \ifdim\sin\points=\zeropoint
+ \else
+ \wd\nextbox\if!!donea\negated\sin\!!heighta\else\@@layerxsiz\fi
+ \fi
+ \fi
+ \fi
+ % new, location=middle
+ \ifnum#2=\plusfour
+ \setbox\nextbox\vbox{\vskip-.5\!!heightb\hskip.5\!!heightb\flushnextbox}%
+ \nextboxwd\!!widthb
+ \nextboxht\!!heightb
+ \nextboxdp\!!depthb
+ \fi}
+
+\def\dorotatenextbox#1#2%
+ {\doifsomething{#1}
+ {\edef\@@rorotation{\realnumber{#1}}% get rid of leading zeros and spaces
+ \setbox\nextbox\vbox{\flushnextbox}% not really needed
+ \dodorotatenextbox\@@rorotation#2}%
+ \hbox{\boxcursor\flushnextbox}}
+
+\def\dodorotatebox#1% {angle} \hbox/\vbox/\vtop
+ {\bgroup\hbox\bgroup % compatibility hack
+ \dowithnextbox
+ {\dorotatenextbox{#1}\plusone
+ \egroup\egroup}}
+
+\def\dorotatebox#1% {angle} \hbox/\vbox/\vtop
+ {\ifcase#1\relax
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\dodorotatebox
+ \fi{#1}}
+
+\unexpanded\def\rotate % \bgroup: \rotate kan argument zijn
+ {\bgroup\complexorsimpleempty\rotate}
+
+% \def\complexrotate[#1]% framed met diepte !
+% {\getparameters[\??ro][#1]%
+% \processaction
+% [\@@rolocation]
+% [ \v!depth=>\!!counta\plusthree\donefalse,% depth fit - raw box
+% \v!fit=>\!!counta\plustwo \donefalse,% depth tight - raw box
+% \v!broad=>\!!counta\plusone \donefalse,% nodepth fit - raw box
+% \v!high=>\!!counta\plusone \donetrue ,% nodepth fit - framed
+% \v!middle=>\!!counta\plusfour \donefalse,% centered, keep dimensions
+% \s!default=>\!!counta\plusthree\donetrue ,% depth fit - framed
+% \s!unknown=>\!!counta\plusthree\donetrue ]% depth fit - framed
+% \ifdone
+% \def\docommand{\localframed[\??ro][#1,\c!location=]}%
+% \else
+% \let\docommand\relax
+% \fi
+% \dowithnextbox{\dorotatenextbox\@@rorotation\!!counta\egroup}\vbox\docommand}
+
+\setvalue{\??ro::\c!location::\v!depth }{\!!counta\plusthree\donefalse} % depth fit - raw box
+\setvalue{\??ro::\c!location::\v!fit }{\!!counta\plustwo \donefalse} % depth tight - raw box
+\setvalue{\??ro::\c!location::\v!broad }{\!!counta\plusone \donefalse} % nodepth fit - raw box
+\setvalue{\??ro::\c!location::\v!high }{\!!counta\plusone \donetrue } % nodepth fit - framed
+\setvalue{\??ro::\c!location::\v!middle }{\!!counta\plusfour \donefalse} % centered, keep dimensions
+\setvalue{\??ro::\c!location::\v!default}{\!!counta\plusthree\donetrue } % depth fit - framed
+
+\def\complexrotate[#1]% framed met diepte !
+ {\getparameters[\??ro][#1]%
+ \executeifdefined{\??ro::\c!location::\@@rolocation}{\!!counta\plusthree\donetrue}%
+ \ifdone
+ \def\docommand{\localframed[\??ro][#1,\c!location=]}%
+ \else
+ \let\docommand\relax
+ \fi
+ \dowithnextbox{\dorotatenextbox\@@rorotation\!!counta\egroup}\vbox\docommand}
+
+\presetlocalframed[\??ro]
+
+\def\setuprotate
+ {\dodoubleargument\getparameters[\??ro]}
+
+\setuprotate
+ [\c!rotation=90,
+ \c!location=\v!normal,
+ \c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!offset=\v!overlay,
+ \c!frame=\v!off]
+
+% \dostepwiserecurse{0}{360}{10}
+% {\startlinecorrection[blank]
+% \hbox
+% {\expanded{\setuprotate[rotation=\recurselevel]}%
+% \traceboxplacementtrue
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=depth] {\ruledhbox{\bfb (depth)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=fit] {\ruledhbox{\bfb (fit)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=broad] {\ruledhbox{\bfb (broad)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=normal]{\ruledhbox{\bfb (normal)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=high] {\ruledhbox{\bfb (high)}}}}}
+% \stoplinecorrection}
+
+% to be used in some other places! todo!
+%
+% divides \hsize in fractions, will be made a bit more
+% clever and advanced when needed
+%
+% \horizontaldivision[n/m,elements,distance]
+%
+% \horizontaldivision[2/5,3,1em]
+% \horizontaldivision[2/5,3,1em]
+% \horizontaldivision[1/5,3,1em]
+%
+% \setuphorizontaldivision[afstand=,aantal=] (passend,passend)
+
+\def\??fr{@@fr}
+
+\def\setuphorizontaldivision
+ {\dodoubleargument\getparameters[\??fr]}
+
+\def\horizontaldivision
+ {\dosingleargument\dohorizontaldivision}
+
+\def\dohorizontaldivision[#1]%
+ {\dodohorizontaldivision[#1,,,,,,]}
+
+\def\dodohorizontaldivision[#1/#2,#3,#4,#5]%
+ {\doifelsenothing{#3}
+ {\doifelse\@@frn\v!fit
+ {\!!counta#2\relax}
+ {\!!counta\@@frn\relax}}
+ {\!!counta#3\relax}%
+ \doifelsenothing{#4}
+ {\doifelse\@@frdistance\v!fit
+ {\!!widtha\zeropoint}
+ {\!!widtha\@@frdistance}}
+ {\!!widtha#4}%
+ \advance\!!counta \minusone
+ \multiply\!!widtha \!!counta
+ \advance\hsize -\!!widtha
+ \divide\hsize #2\relax
+ \hsize#1\hsize}
+
+\setuphorizontaldivision
+ [\c!distance=\tfskipsize,
+ \c!n=\v!fit]
+
+%D This one is for Daniel Pittman, who wanted tight
+%D fractions. We show three versions. First the simple
+%D one using \type {\low} and \type {high}:
+%D
+%D \startbuffer
+%D \def\vfrac#1#2%
+%D {\hbox{\high{\tx#1\kern-.25em}/\low{\kern-.25em\tx#2}}}
+%D
+%D test \vfrac{1}{2} test \vfrac{123}{456} test
+%D \stopbuffer
+%D
+%D \typebuffer {\showmakeup\getbuffer}
+%D
+%D A better way to handle the kerning is the following, here
+%D we kind of assume that tye slash is symmetrical and has
+%D nearly zero width.
+%D
+%D \startbuffer
+%D \def\vfract#1#2%
+%D {\hbox{\high{\tx#1}\hbox to \zeropoint{\hss/\hss}\low{\tx#2}}}
+%D \stopbuffer
+%D
+%D \typebuffer {\showmakeup\getbuffer}
+%D
+%D The third and best alternative is the following:
+%D
+%D {\showmakeup\getbuffer}\crlf\getbuffer
+%D
+%D This time we measure the height of the \type {/} and
+%D shift over the maximum height and depths of this
+%D character and the fractional digits (we use 57 as
+%D sample). Here we combine all methods in one macros.
+
+\chardef\vulgarfractionmethod=3
+
+\definehspace[vulgarfraction][.25em] % [.15em]
+\definesymbol[vulgarfraction][/] % [\raise.2ex\hbox{/}]
+
+\unexpanded\def\vulgarfraction#1#2%
+ {\dontleavehmode
+ \hbox
+ {\def\vulgarfraction{vulgarfraction}%
+ \ifcase\vulgarfractionmethod
+ #1\symbol[\vulgarfraction]#2%
+ \or
+ \high{\tx#1\kern-\hspaceamount\empty\vulgarfraction}%
+ \symbol[\vulgarfraction]%
+ \low {\kern-\hspaceamount\empty\vulgarfraction\tx#2}%
+ \or
+ \high{\tx#1}%
+ \hbox to \zeropoint{\hss\symbol[\vulgarfraction]\hss}%
+ \low{\tx#2}%
+ \or
+ \setbox0\hbox{\symbol[\vulgarfraction]}%
+ \setbox2\hbox{\txx57}%
+ \raise\ht0\hbox{\lower\ht2\hbox{\txx#1}}%
+ \hbox to \zeropoint{\hss\symbol[\vulgarfraction]\hss}%
+ \lower\dp0\hbox{\raise\dp2\hbox{\txx#2}}%
+ \fi}}
+
+\ifx\vfrac\undefined \let\vfrac\vulgarfraction \fi
+
+%D \starttabulate
+%D \HL
+%D \NC \bf method \NC \bf visualization \NC\NR
+%D \HL
+%D \NC 0 \NC \chardef\vulgarfractionmethod0\vulgarfraction{1}{2} \NC\NR
+%D \NC 1 \NC \chardef\vulgarfractionmethod1\vulgarfraction{1}{2} \NC\NR
+%D \NC 2 \NC \chardef\vulgarfractionmethod2\vulgarfraction{1}{2} \NC\NR
+%D \NC 3 \NC \chardef\vulgarfractionmethod3\vulgarfraction{1}{2} \NC\NR
+%D \HL
+%D \stoptabulate
+
+%D Under construction:
+%D
+%D \starttyping
+%D \commalistsentence[aap,noot,mies]
+%D \commalistsentence[aap,noot]
+%D \commalistsentence[aap]
+%D \commalistsentence[a,b,c]
+%D \commalistsentence[a,b,c][{ \& },{ and }]
+%D \commalistsentence[a,b,c][+,-]
+%D \stoptyping
+
+\let\handlecommalistsentence\firstofoneargument
+
+\def\commalistsentenceone{and-1}
+\def\commalistsentencetwo{and-2}
+
+\def\commalistsentence
+ {\dodoubleempty\docommalistsentence}
+
+\def\docommalistsentence[#1][#2]%
+ {\bgroup
+ \getfromcommalist[#2][1]%
+ \ifx\commalistelement\empty
+ \def\@@commalistsentenceone{\labeltext\commalistsentenceone}%
+ \else
+ \let\@@commalistsentenceone\commalistelement
+ \fi
+ \getfromcommalist[#2][2]%
+ \ifx\commalistelement\empty
+ \def\@@commalistsentencetwo{\labeltext\commalistsentencetwo}%
+ \else
+ \let\@@commalistsentencetwo\commalistelement
+ \fi
+ \getcommalistsize[#1]%
+ \ifcase\commalistsize\relax
+ \def\serializedcommalist{#1}%
+ \else
+ \let\serializedcommalist\empty
+ \scratchcounter\zerocount
+ \def\docommand##1%
+ {\advance\scratchcounter \plusone
+ \ifnum\scratchcounter=\plusone
+ \scratchtoks{\handlecommalistsentence{##1}}%
+ \else
+ \ifnum\scratchcounter=\commalistsize
+ \appendtoks\@@commalistsentencetwo\handlecommalistsentence{##1}\to\scratchtoks
+ \else
+ \appendtoks\@@commalistsentenceone\handlecommalistsentence{##1}\to\scratchtoks
+ \fi
+ \fi}%
+ \processcommacommand[#1]\docommand
+ \edef\serializedcommalist{\the\scratchtoks}%
+ \fi
+ \serializedcommalist
+ \egroup}
+
+\def\commacommandsentence[#1]{\@EA\commalistsentence\@EA[#1]}
+
+\ifx\textcomma\undefined \def\textcomma{,} \fi
+
+\setuplabeltext [\s!nl] [and-1=\textcomma\ , and-2= en ]
+\setuplabeltext [\s!en] [and-1=\textcomma\ , and-2=\textcomma\ and ]
+\setuplabeltext [\s!de] [and-1=\textcomma\ , and-2= und ]
+
+%D \macros
+%D {somekindoftab}
+%D
+%D This macro can be used to create tabs:
+%D
+%D \starttyping
+%D \setupheadertexts[{\somekindoftab[alternative=horizontal]{\framed{\realfolio}}}]
+%D \setuptexttexts [{\somekindoftab[alternative=vertical] {\framed{\realfolio}}}]
+%D
+%D \starttext
+%D \showframe \dorecurse{10}{test\page}
+%D \stoptext
+%D \stoptyping
+
+\def\somekindoftab
+ {\dosingleempty\dosomekindoftab}
+
+\def\dosomekindoftab[#1]%
+ {\bgroup
+ \getparameters[xx]
+ [\c!alternative=\v!vertical,
+ \c!width=\textwidth,\c!height=\textheight,
+ \c!n=\lastpage,\c!m=\realpageno,
+ #1]%
+ \doifelse\xxalternative\v!vertical
+ {\dodosomekindoftab\vbox\vskip\xxheight}
+ {\dodosomekindoftab\hbox\hskip\xxwidth }}
+
+\def\dodosomekindoftab#1#2#3#4%
+ {#1 to #3 \bgroup
+ \forgetall
+ \ifnum\xxm>\plusone
+ #2\zeropoint \!!plus \the\numexpr\xxm -1\relax fill\relax
+ \fi
+ #4%
+ \ifnum\xxm<\xxn\relax
+ #2\zeropoint \!!plus \the\numexpr\xxn-\xxm\relax fill\relax
+ \fi
+ \egroup
+ \egroup}
+
+\protect \endinput
diff --git a/tex/context/base/core-mis.mkiv b/tex/context/base/core-mis.mkiv
new file mode 100644
index 000000000..e2bd28bd5
--- /dev/null
+++ b/tex/context/base/core-mis.mkiv
@@ -0,0 +1,2505 @@
+%D \module
+%D [ file=core-mis,
+%D version=1998.01.29,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Miscelaneous,
+%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 Core Macros / Misc Commands}
+
+% todo: kleur in legenda + letter
+
+% %D You would not expect the next macro in \CONTEXT,
+% %D wouldn't you? It's there to warn \LATEX\ users that
+% %D something is wrong.
+% %D
+% %D Obsolete now:
+% %
+% % \def\documentstyle{\showmessage\m!systems3\empty\stoptekst}
+% %
+% % \let\documentclass=\documentstyle
+% %D \macros
+% %D {simplifiedcommands, simplifycommands}
+% %D
+% %D I first needed this simplification in bookmarks. Users can
+% %D add their own if needed.
+
+\unprotect
+
+%D Sometimes (for instance in bookmarks) we need to simplify macro
+%D behaviour, so here is the hook.
+
+\ifx\simplifiedcommands\undefined \newtoks\simplifiedcommands \fi
+
+\def\simplifycommands{\the\simplifiedcommands}
+
+%D A possibly growing list:
+
+%appendtoks \def\executesynonym#1#2#3#4{#3}\to\simplifiedcommands
+%appendtoks \def\executesort#1#2#3{#3}\to\simplifiedcommands
+
+\appendtoks \def\ { }\to\simplifiedcommands
+\appendtoks \def\type#1{\letterbackslash\checkedstrippedcsname#1}\to\simplifiedcommands
+\appendtoks \def\tex#1{\letterbackslash#1}\to\simplifiedcommands
+\appendtoks \def\TeX{TeX}\to\simplifiedcommands
+\appendtoks \def\ConTeXt{ConTeXt}\to\simplifiedcommands
+\appendtoks \def\MetaPost{MetaPost}\to\simplifiedcommands
+\appendtoks \def\MetaFont{MetaFont}\to\simplifiedcommands
+\appendtoks \def\MetaFun{MetaFun}\to\simplifiedcommands
+%appendtoks \def||{-}\to\simplifiedcommands
+\appendtoks \def|#1|{\ifx#1\empty\empty-\else#1\fi}\to\simplifiedcommands
+
+\appendtoks\let\buildtextaccent\secondoftwoarguments\to\simplifiedcommands
+
+% THIS WAS MAIN-002.TEX
+
+%\def\checkinterlineskip
+% {\ifvmode
+% \ifdim\lastskip>\zeropoint
+% \nointerlineskip
+% \else\ifdim\lastkern>\zeropoint
+% \nointerlineskip
+% \fi\fi
+% \fi}
+
+\def\horitems#1#2% #1=breedte #2=commandos
+ {\scratchdimen#1%
+ \divide\scratchdimen \nofitems
+ \!!counta\zerocount
+ \def\docommand##1%
+ {\advance\!!counta \plusone
+ \processaction
+ [\@@isalign]
+ [ \v!left=>\hbox to \scratchdimen{\strut##1\hss},
+ \v!right=>\hbox to \scratchdimen{\hss\strut##1},
+ \v!middle=>\hbox to \scratchdimen{\hss\strut##1\hss},
+ \v!margin=>\ifnum\!!counta=\plusone\hss\else\hfill\fi
+ \strut##1%
+ \ifnum\!!counta=\nofitems\hss\else\hfill\fi,
+ \s!default=>\hbox to \scratchdimen{\hss\strut##1\hss}, % midden
+ \s!unknown=>\hbox to \scratchdimen{\strut##1\hss}]}% % links
+ \hbox to #1{\hss#2\hss}}
+
+\def\veritems#1#2% #1=breedte #2=commandos
+ {\scratchdimen#1%
+ \def\docommand##1%
+ {\ifdim\scratchdimen<\zeropoint % the - was a signal
+ \hbox to -\scratchdimen{\hss\strut##1}%
+ \else\ifdim\scratchdimen>\zeropoint
+ \hbox to \scratchdimen{\strut##1\hss}%
+ \else
+ \hbox{\strut##1}%
+ \fi\fi}%
+ \vbox{#2}}
+
+\def\dosetupitems[#1]%
+ {\getparameters[\??is][#1]%
+ \doif\@@iswidth\v!unknown
+ {\def\@@iswidth{\hsize}}%
+ \doifconversiondefinedelse\@@issymbol
+ {\def\doitembullet##1{\convertnumber{\@@issymbol}{##1}}}
+ {\doifsymboldefinedelse\@@issymbol
+ {\def\doitembullet##1{\symbol[\@@issymbol]}}{}}}
+
+\def\makeitemsandbullets#1%
+ {\doifelse\@@isn\v!unknown
+ {\getcommalistsize[#1]%
+ \edef\nofitems{\commalistsize}}
+ {\edef\nofitems{\@@isn}}%
+ \setbox0\hbox
+ {\doitems \@@iswidth
+ {\processcommalist[#1]\docommand}}%
+ \setbox2\hbox
+ {\doitems \@@isbulletbreedte
+ {\dorecurse\nofitems
+ {\docommand{\strut\doitembullet\recurselevel}}}}}
+
+\def\dostartitems#1#2#3%
+ {\let\doitems#2%
+ \def\@@isbulletbreedte{#3}%
+ \makeitemsandbullets{#1}%
+ \@@isbefore}
+
+\def\dostopitems
+ {\@@isafter
+ \egroup}
+
+\setvalue{doitems\v!top}#1%
+ {\dostartitems{#1}\horitems\@@iswidth
+ \noindent\vbox
+ {\forgetall
+ \doifsomething\@@issymbol
+ {\doifnot\@@issymbol\v!none
+ {\box2
+ \@@isinbetween
+ \nointerlineskip}}%
+ \box0}%
+ \dostopitems}
+
+\setvalue{doitems\v!bottom}#1%
+ {\dostartitems{#1}\horitems\@@iswidth
+ \noindent\vbox
+ {\forgetall
+ \box0
+ \doifsomething\@@issymbol
+ {\@@isinbetween
+ \nointerlineskip
+ \box2}}%
+ \dostopitems}
+
+\setvalue{doitems\v!inmargin}#1%
+ {\dostartitems{#1}\veritems{-1.5em}% - is a signal
+ \noindent\hbox{\llap{\box2\hskip\leftmargindistance}\box0}%
+ \dostopitems}
+
+\setvalue{doitems\v!left}#1%
+ {\advance\hsize -1.5em%
+ \dostartitems{#1}\veritems{1.5em}%
+ \noindent\hbox{\box2\box0}%
+ \dostopitems}
+
+\setvalue{doitems\v!right}#1%
+ {\dostartitems{#1}\veritems{0em}%
+ \noindent\hbox{\box0\hskip-\wd2\box2}%
+ \dostopitems}
+
+\unexpanded\def\setupitems
+ {\dosingleargument\dosetupitems}
+
+\def\complexitems[#1]%
+ {\bgroup
+ \setupitems[#1]%
+ \parindent\zeropoint
+ \setlocalhsize
+ \hsize\localhsize
+ \dontcomplain
+ %\doifundefined{doitems\@@islocation}%
+ % {\let\@@islocation\v!left}%
+ %\getvalue{doitems\@@islocation}}
+ \executeifdefined{doitems\@@islocation}{\let\@@islocation\v!left}}
+
+\definecomplexorsimpleempty\items
+
+\setupitems
+ [\c!location=\v!left,
+ \c!symbol=5,
+ \c!width=\hsize,
+ \c!align=\v!middle,
+ \c!n=\v!unknown,
+ \c!before=\blank,
+ \c!inbetween={\blank[\v!medium]},
+ \c!after=\blank]
+
+% \definieerplaats[naam][instellingen]
+% \stelplaatsin[naam][instellingen]
+% \plaats[[instellingen]]
+%
+% - still undocumented and also not in setupb yet
+% - kan ook intern/direct (scheelt duplicatie), zie \framedtext
+
+\def\dodefineplacement[#1][#2]%
+ {\getparameters
+ [\??pl#1]
+ [\c!left=\hss,
+ \c!right=\hss,
+ \c!linecorrection=\v!off,
+ \c!depthcorrection=\v!off,
+ \c!margin=\v!standard,
+ \c!grid=\v!middle,
+ %\c!before=,
+ %\c!after=,
+ #2]%
+ \setvalue{\e!place#1}{\doplacement[\??pl#1]}}
+
+\unexpanded\def\defineplacement
+ {\dodoubleempty\dodefineplacement}
+
+\unexpanded\def\setupplacement
+ {\dodoubleempty\dosetupplacement}
+
+\def\dosetupplacement[#1]%
+ {\dodoubleempty\getparameters[\??pl#1]}
+
+\def\doplacement
+ {\dodoubleempty\dodoplacement}
+
+\def\dodoplacement[#1][#2]% correctie moet mooier
+ {\bgroup
+ \dowithnextboxcontent
+ {\forgetall}
+ {\setlocalhsize
+ \getparameters[#1][#2]%
+ \getvalue{#1\c!before}%
+ \begingroup
+ \disableparpositions
+ \setbox\nextbox\hbox to \localhsize
+ {\getvalue{#1\c!left}%
+ \flushnextbox
+ \getvalue{#1\c!right}}%
+ \ifinsidefloat \else
+ \addlocalbackgroundtobox\nextbox
+ \fi
+ \ifgridsnapping
+ \doifundefined{#1\c!grid}{\letvalue{#1\c!grid}\v!middle}%
+ % unchecked
+ \doifinset{\getvalue{#1\c!margin}}{\v!standard,\v!yes}\noindent
+ \snaptogrid[\getvalue{#1\c!grid}]\hbox{\flushnextbox}%
+ \else
+ \doifvalue{#1\c!linecorrection}\v!on \startbaselinecorrection
+ \doifinset{\getvalue{#1\c!margin}}{\v!standard,\v!yes}\noindent
+ \flushnextbox
+ \doifvalue{#1\c!depthcorrection}\v!on\baselinecorrection
+ \doifvalue{#1\c!linecorrection }\v!on\stopbaselinecorrection
+ \fi
+ \endgroup
+ \getvalue{#1\c!after}%
+ \egroup}
+ \vbox}
+
+% Te zijner tijd [plaats=boven,onder,midden] implementeren,
+% in dat geval moet eerst de maximale hoogte worden bepaald.
+%
+% Overigens kan een en ander mooier met \halign.
+
+% there is quite some historic balast in this mechanism, the next variant
+% is a first cleanup
+
+\let\currentparagraph\empty
+
+\newcount\alcounter \newcount\alnsize \newdimen\alhsize
+
+\def\paragraphparameter#1% \checkedparameter\??al\currentparagraph#1
+ {\executeifdefined{\??al\currentparagraph#1}{\executeifdefined{\??al#1}\empty}}
+
+\def\paragraphcellmeter#1#2% \checkedparameter\??al\currentparagraph#1
+ {\executeifdefined{\??al\currentparagraph\number#1#2}{\paragraphparameter{#2}}}
+
+\def\dodefineparagraphs[#1][#2]%
+ {\edef\currentparagraph{#1}%
+ \setvalue{\s!do\s!next\currentparagraph}%
+ {\def\\{\getvalue\currentparagraph}}%
+ \setvalue\currentparagraph
+ {\getvalue{\s!do\s!next#1}%
+ \dostartparagraphs{#1}}%
+ \setvalue{\e!next\currentparagraph}%
+ {\getvalue{#1}}%
+ \setvalue{\e!start\currentparagraph}%
+ {\bgroup
+ \edef\currentparagraph{#1}%
+ \letvalue{\s!do\s!next\currentparagraph}\empty
+ \setvalue{\e!stop\currentparagraph}{\getvalue\currentparagraph\egroup}%
+ \getvalue\currentparagraph}%
+ \getparameters[\??al\currentparagraph]%
+ [%\c!n=3,
+ %\c!before=\blank,
+ %\c!after=\blank,
+ %\c!distance=1em,
+ %\c!height=\v!fit,
+ %\c!rule=\v!off,
+ %\c!command=,
+ %\c!align=,
+ %\c!tolerance=\v!tolerant,
+ %\c!rulethickness=\linewidth,
+ %\c!rulecolor=,
+ %\c!style=,
+ %\c!color=,
+ %\c!top=,
+ %\c!top=\vss,
+ %\c!bottom=\vfill,
+ #2]%
+ \setvalue{\e!setup#1\e!endsetup}%
+ {\setupparagraphs[#1]}%
+ \dorecurse
+ {\paragraphparameter\c!n}
+ {\setupparagraphs
+ [\currentparagraph]
+ [\recurselevel]
+ [\c!width=,
+ %\c!bottom=\paragraphparameter\c!bottom,
+ %\c!top=\paragraphparameter\c!top,
+ %\c!height=\paragraphparameter\c!height,
+ %\c!rule=\paragraphparameter\c!rule,
+ %\c!rulethickness=\paragraphparameter\c!rulethickness,
+ %\c!rulecolor=\paragraphparameter\c!rulecolor,
+ %\c!align=\paragraphparameter\c!align,
+ %\c!tolerance=\paragraphparameter\c!tolerance, % obsolete
+ %\c!distance=\paragraphparameter\c!distance,
+ \c!style=\paragraphparameter\c!style,
+ \c!color=\paragraphparameter\c!color]}%
+ \setupparagraphs[\currentparagraph][1][\c!distance=\zeropoint]}
+
+\unexpanded\def\defineparagraphs
+ {\dodoubleargument\dodefineparagraphs}
+
+\def\dosetupparagraphs[#1][#2][#3]%
+ {\edef\currentparagraph{#1}%
+ \ifsecondargument
+ \doifelse{#2}\v!each
+ {\dorecurse
+ {\paragraphparameter\c!n}
+ {\getparameters[\??al\currentparagraph\recurselevel][#3]}}
+ {\doifelsenothing{#3}
+ {\getparameters[\??al\currentparagraph][#2]}
+ {\def\docommand##1{\getparameters[\??al\currentparagraph##1][#3]}%
+ \processcommalist[#2]\docommand}}%
+ \else
+ \getparameters[\??al][#1]%
+ \fi}
+
+\unexpanded\def\setupparagraphs
+ {\dotripleempty\dosetupparagraphs}
+
+\setupparagraphs
+ [\c!n=3,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!distance=1em,
+ \c!height=\v!fit,
+ \c!rule=\v!off,
+ \c!command=,
+ \c!align=,
+ \c!tolerance=\v!tolerant, % obsolete
+ \c!rulethickness=\linewidth,
+ \c!rulecolor=,
+ \c!style=,
+ \c!color=,
+ \c!top=,
+ \c!top=\vss,
+ \c!bottom=\vfill]
+
+\def\doparagraphrule
+ {\doifelse{\paragraphcellmeter\alcounter\c!rule}\v!on
+ {\linewidth\paragraphcellmeter\alcounter\c!rulethickness
+ \scratchdimen\dimexpr(\paragraphcellmeter\alcounter\c!distance-\linewidth)/2\relax
+ \hskip\scratchdimen
+ \color[\paragraphcellmeter\alcounter\c!rulecolor]{\vrule\!!width\linewidth}%
+ \hskip\scratchdimen}
+ {\hskip\paragraphcellmeter\alcounter\c!distance}}
+
+\def\dostartparagraph
+ {\doifelsenothing{\paragraphcellmeter\alcounter\c!width}
+ {\!!widtha\alhsize
+ \divide\!!widtha \alnsize}
+ {\!!widtha\paragraphcellmeter\alcounter\c!width}%
+ \dostartattributes{\??al\currentparagraph\number\alcounter}\c!style\c!color\empty
+ \doifelse{\paragraphcellmeter\alcounter\c!height}\v!fit
+ {\setbox\scratchbox\vtop}
+ {\setbox\scratchbox\vtop to \paragraphcellmeter\alcounter\c!height}%
+ \bgroup
+ \blank[\v!disable]%
+ \forgetall
+ \paragraphcellmeter\alcounter\c!top
+ \paragraphparameter\c!inner
+ \hsize\!!widtha % setting \wd afterwards removed
+ \paragraphcellmeter\alcounter\c!inner % twice
+ \expanded{\setupalign [\paragraphcellmeter\alcounter\c!align ]}% {normal,verytolerant,stretch}
+ \expanded{\setuptolerance[\paragraphcellmeter\alcounter\c!tolerance]}% obsolete
+ \ignorespaces
+ \endgraf
+ \ignorespaces
+ %
+ % Nadeel van de onderstaande constructie is dat \everypar
+ % binnen een groep kan staan en zo steeds \begstruts
+ % worden geplaatst. Mooi is anders dus moet het anders!
+ %
+ % Hier is \Everypar niet nodig.
+ %
+ \everypar{\begstrut\everypar\emptytoks}%
+ %
+ \nospace % remove + ignore
+ \paragraphcellmeter\alcounter\c!command}
+
+\def\dostopparagraph
+ {\ifvmode
+ \removelastskip
+ \else
+ \unskip\endstrut\endgraf
+ \fi
+ \paragraphcellmeter\alcounter\c!bottom
+ \egroup
+ \ifdim\wd\scratchbox=\zeropoint % no data
+ \wd\scratchbox\!!widtha
+ \fi
+ \box\scratchbox
+ \dostopattributes
+ \ifnum\alcounter<\paragraphparameter\c!n\relax
+ \@EA\doparagraphcell
+ \else
+ \@EA\dostopparagraphs
+ \fi}
+
+\def\doparagraphcell
+ {\global\advance\alcounter \plusone
+ \doifelsenothing{\paragraphcellmeter\alcounter\c!distance}
+ {\ifnum\alcounter=\plusone\else
+ \hskip\paragraphparameter\c!distance
+ \fi}
+ {\ifnum\alcounter=\plusone
+ \hskip\paragraphcellmeter\alcounter\c!distance
+ \else
+ \doparagraphrule
+ \fi}%
+ \letvalue\currentparagraph\dostopparagraph
+ \dostartparagraph}
+
+\def\dostartparagraphs#1%
+ {\bgroup
+ \edef\currentparagraph{#1}%
+ \global\alcounter\zerocount
+ \parindent\zeropoint
+ \setlocalhsize
+ \alhsize\localhsize
+ \alnsize\paragraphparameter\c!n\relax
+ \dorecurse \alnsize
+ {\doifelsenothing{\paragraphcellmeter\recurselevel\c!distance}
+ {\ifnum\recurselevel=\plusone\else
+ \global\advance\alhsize -\paragraphparameter\c!distance
+ \fi}
+ {\global\advance\alhsize -\paragraphcellmeter\recurselevel\c!distance}%
+ \doifsomething{\paragraphcellmeter\recurselevel\c!width}
+ {\global\advance\alnsize \minusone
+ \global\advance\alhsize -\paragraphcellmeter\recurselevel\c!width}}%
+ %whitespace % gaat fout bij \framed
+ \paragraphparameter\c!before
+ \leavevmode % gaat wel goed bij \framed, brrr
+ \setbox\scratchbox\vbox\bgroup\hbox\bgroup\doparagraphcell}
+
+\def\dostopparagraphs
+ {\egroup
+ \egroup
+ \iftrue
+ \hbox{\raise\strutheight\box\scratchbox}% new
+ \else
+ \box\scratchbox % old
+ \fi
+ \par
+ \paragraphparameter\c!after
+ \egroup}
+
+\def\dosetuptab[#1]%
+ {\getparameters[\??ta]
+ [\c!headstyle=\v!normal,
+ \c!headcolor=,
+ \c!style=\v!normal,
+ \c!color=,
+ \c!width=\v!broad,
+ \c!sample={\hskip4em},
+ \c!before=,
+ \c!after=,
+ #1]%
+ \definedescription
+ [tab]
+ [\c!headstyle=\@@taheadstyle,
+ \c!headcolor=\@@tacolor,
+ \c!sample=\@@tasample,
+ \c!width=\@@tawidth,
+ \c!before=\@@tabefore,
+ \c!after=\@@taafter]}
+
+\unexpanded\def\setuptab
+ {\dosingleargument\dosetuptab}
+
+\setuptab
+ [\c!location=\v!left]
+
+\unexpanded\def\celsius #1{#1\mathematics{^\circ}C}
+\unexpanded\def\inch {\mathematics{\prime\prime}} % was: \hbox{\rm\char125\relax}
+\unexpanded\def\fraction#1#2{\mathematics{#1\over#2}}
+
+% very dutch
+
+\unexpanded\def\graden {\mathematics{^\circ}}
+
+\def\bedragprefix {\euro\normalfixedspace}
+\def\bedragsuffix {}
+\def\bedragempty {\euro}
+
+\unexpanded\def\bedrag#1%
+ {\strut\hbox\bgroup
+ \let\normalfixedspace\nonbreakablespace
+ \doifelsenothing{#1}
+ {\bedragempty}
+ {\bedragprefix\digits{#1}\bedragsuffix}%
+ \egroup}
+
+% \definieeralineas[test][n=3]
+%
+% \stelalineasin[test][3][breedte=4cm,uitlijnen=links]
+%
+% \startopelkaar
+% \test hans \\ ton \\ \bedrag{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{~.~~1,--} \\
+% \test hans \\ ton \\ \bedrag{~.~~1,~~} \\
+% \test hans \\ ton \\ \bedrag{~.100,--} \\
+% \test hans \\ ton \\ \subtot{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{1.000,--} \\
+% \test hans \\ ton \\ \totaal{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{nihil,--} \\
+% \test hans \\ ton \\ \totaal{nihil,--} \\
+% \test hans \\ ton \\ \subtot{nihil,--} \\
+% \stopopelkaar
+
+\def\periodswidth {.5em}
+\def\periodsdefault{3} % was 5, but now it's like \unknown
+
+\unexpanded\def\periods
+ {\dosingleempty\doperiods}
+
+\def\doperiods[#1]% todo: also n=,width= or maybe just #1,#2
+ {\dontleavehmode
+ \begingroup
+ \scratchdimen\periodswidth
+ \hbox to \iffirstargument#1\else\periodsdefault\fi \scratchdimen
+ {\leaders\hbox to \scratchdimen{\hss.\hss}\hss}%
+ \endgroup}
+
+\unexpanded\def\unknown
+ {\periods\relax} % relax prevents lookahead for []
+
+% Example by Wolfgang Schuster on the context list:
+%
+% \unexpanded\def\fourdots{{\def\periodswidth{.3em}\periods[4]}}
+%
+% Hello\fourdots\ World\fourdots \par Hello\fourdots\ World.
+
+% compatibility macros
+
+\def\doorsnede
+ {\hbox{\rlap/$\circ$} }
+
+\unexpanded\def\ongeveer
+ {\mathematics\pm}
+
+\chardef\boundarycharactermode\plusone
+
+\def\midboundarycharacter#1#2%
+ {\ifcase\boundarycharactermode
+ \or
+ %\nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \languageparameter#1%
+ %\nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \or
+ \languageparameter#1%
+ \fi
+ \chardef\boundarycharactermode\plusone}
+
+\def\leftboundarycharacter#1#2%
+ {\ifcase\boundarycharactermode
+ \or
+ \languageparameter#1%
+ \nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \or
+ \languageparameter#1%
+ \fi
+ \chardef\boundarycharactermode\plusone}
+
+\def\rightboundarycharacter#1#2%
+ {\ifcase\boundarycharactermode
+ \or
+ \prewordbreak %\nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \languageparameter#1%
+ \or
+ \languageparameter#1%
+ \fi
+ \chardef\boundarycharactermode\plusone}
+
+% actually this is pretty old, but temporary moved here
+%
+% obsolete:
+
+\unexpanded\def\setuphyphenmark
+ {\dodoubleargument\getparameters[\??kp]}
+
+\unexpanded\def\setuphyphenmark[#1]% sign=normal|wide
+ {\dodoubleargument\getparameters[\??kp][#1]%
+ \doifelse\@@kpsign {\v!normal}% was inset?
+ {\let\textmodehyphen\normalhyphen \let\textmodehyphendiscretionary\normalhyphendiscretionary}
+ {\let\textmodehyphen\composedhyphen\let\textmodehyphendiscretionary\composedhyphendiscretionary}}
+
+\setuphyphenmark[\c!sign=\v!wide]
+% % \setuphyphenmark[\c!sign=\v!normal]
+
+\definesymbol[\c!lefthyphen] [\languageparameter\c!lefthyphen]
+\definesymbol[\c!righthyphen] [\languageparameter\c!righthyphen]
+\definesymbol[\c!hyphen] [\languageparameter\c!hyphen]
+
+\def\normalhyphen
+ {\hbox{\directsymbol\empty\c!hyphen}}
+
+\def\composedhyphen
+ {\hbox{\directsymbol\empty\c!compoundhyphen}}
+
+\def\normalhyphendiscretionary
+ {\discretionary
+ {\hbox{\directsymbol\empty\c!righthyphen}}
+ {\hbox{\directsymbol\empty\c!lefthyphen}}
+ {\hbox{\directsymbol\empty\c!hyphen}}}
+
+\def\composedhyphendiscretionary
+ {\discretionary
+ {\hbox{\directsymbol\empty\c!rightcompoundhyphen}}
+ {\hbox{\directsymbol\empty\c!leftcompoundhyphen}}
+ {\hbox{\directsymbol\empty\c!compoundhyphen}}}
+
+\let\textmodehyphen \composedhyphen
+\let\textmodehyphendiscretionary\composedhyphendiscretionary
+
+\definesymbol[\c!leftcompoundhyphen] [\languageparameter\c!leftcompoundhyphen]
+\definesymbol[\c!rightcompoundhyphen] [\languageparameter\c!rightcompoundhyphen]
+\definesymbol[\c!compoundhyphen] [\languageparameter\c!compoundhyphen]
+
+\definehspace [sentence] [\zeropoint]
+\definehspace [intersentence] [.250em]
+
+\definesymbol
+ [\c!midsentence]
+ [\midboundarycharacter\c!midsentence{sentence}]
+
+\definesymbol
+ [\c!leftsentence]
+ [\leftboundarycharacter\c!leftsentence{sentence}]
+
+\definesymbol
+ [\c!rightsentence]
+ [\rightboundarycharacter\c!rightsentence{sentence}]
+
+\definesymbol
+ [\c!leftsubsentence]
+ [\leftboundarycharacter\c!leftsubsentence{sentence}]
+
+\definesymbol
+ [\c!rightsubsentence]
+ [\rightboundarycharacter\c!rightsubsentence{sentence}]
+
+\newsignal \subsentencesignal
+\newcount \subsentencelevel
+
+\let\beforesubsentence\donothing
+\let\aftersubsentence \donothing
+
+% todo: make this language option
+%
+% \def\beforesubsentence{\removeunwantedspaces}
+% \def\aftersubsentence {\ignorespaces}
+
+\def\midsentence
+ {\symbol[\c!midsentence]}
+
+\def\beginofsubsentence
+ {\beforesubsentence
+ \ifdim\lastkern=\subsentencesignal
+ \unskip
+ \kern\hspaceamount\currentlanguage{intersentence}%
+ \fi
+ \global\advance\subsentencelevel\plusone
+ \ifnum\subsentencelevel=\plusone
+ \dontleavehmode % was \leaveoutervmode
+ \fi
+ \symbol[\ifodd\subsentencelevel\c!leftsentence\else\c!leftsubsentence\fi]%
+ }% \ignorespaces}
+
+\def\endofsubsentence % relax prevents space gobbling
+ {\symbol[\ifodd\subsentencelevel\c!rightsentence\else\c!rightsubsentence\fi]%
+ \global\advance\subsentencelevel\minusone
+ \unskip
+ \kern\subsentencesignal\relax
+ \aftersubsentence}
+
+\def\beginofsubsentencespacing % relax prevents space gobbling
+ {\kern\subsentencesignal\relax}% \ignorespaces}
+
+\def\endofsubsentencespacing
+ {\ifdim\lastkern=\subsentencesignal
+ \unskip
+ \hskip\hspaceamount\currentlanguage{intersentence}%
+ % no good, actually language dependent:
+% \ignorespaces
+ \else
+ \unskip
+ \fi}
+
+%D \startbuffer
+%D test |<|test |<|test|>| test|>| test \par
+%D test|<|test|<|test|>|test|>|test \par
+%D test |<||<|test|>||>| test \par
+%D test \directdiscretionary{<}test\directdiscretionary{>} test \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \getbuffer
+
+\unexpanded\def\startsubsentence{\beginofsubsentence \prewordbreak\beginofsubsentencespacing}
+\unexpanded\def\stopsubsentence {\endofsubsentencespacing\prewordbreak\endofsubsentence}
+
+%D \defineXMLenvironment [subsentence]
+%D {|<|}
+%D {|>|}
+%D \defineXMLenvironment [subsentence]
+%D {\directdiscretionary{<}}
+%D {\directdiscretionary{>}}
+%D \defineXMLenvironment [subsentence]
+%D {\startsubsentence}
+%D {\stopsubsentence}
+%D
+%D \startbuffer
+%D test test test
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \processXMLbuffer
+
+\enableactivediscretionaries
+
+\definehspace [quotation] [\zeropoint]
+\definehspace [interquotation] [.125em]
+
+%definehspace [quote] [\zeropoint]
+%definehspace [speech] [\zeropoint]
+
+\definehspace [quote] [\hspaceamount\currentlanguage{quotation}]
+\definehspace [speech] [\hspaceamount\currentlanguage{quotation}]
+
+\definesymbol
+ [\c!leftquotation]
+ [\leftboundarycharacter\c!leftquotation{quotation}]
+
+\definesymbol
+ [\c!rightquotation]
+ [\rightboundarycharacter\c!rightquotation{quotation}]
+
+\definesymbol
+ [\c!leftquote]
+ [\leftboundarycharacter\c!leftquote{quote}]
+
+\definesymbol
+ [\c!rightquote]
+ [\rightboundarycharacter\c!rightquote{quote}]
+
+\definesymbol
+ [\c!leftspeech]
+ [\leftboundarycharacter\c!leftspeech{speech}]
+
+\definesymbol
+ [\c!rightspeech]
+ [\rightboundarycharacter\c!rightspeech{speech}]
+
+\definesymbol
+ [\c!middlespeech]
+ [\leftboundarycharacter\c!middlespeech{speech}]
+
+\appendtoks\def\quotation#1{"#1"}\to\simplifiedcommands
+\appendtoks\def\quote #1{'#1'}\to\simplifiedcommands
+
+%D The next features was so desperately needed by Giuseppe
+%D Bilotta that he made a module for it. Since this is a
+%D typical example of core functionality, I decided to extend
+%D the low level quotation macros in such a way that a speech
+%D feature could be build on top of it. The speech opening and
+%D closing symbols are defined per language. Italian is an
+%D example of a language that has them set.
+
+% this will replace the quotation and speed definitions
+
+\newsignal\delimitedtextsignal
+
+\let\currentdelimitedtext\s!unknown
+
+\def\delimitedtextlevel{\csname\??ci:\currentdelimitedtext:\c!level\endcsname}
+
+\def\doinitializetextlevel#1%
+ {\ifcsname\??ci:#1:\c!level\endcsname
+ \csname\??ci:#1:\c!level\endcsname\zerocount
+ \else
+ \expandafter\newcount\csname\??ci:#1:\c!level\endcsname
+ \fi}
+
+\def\delimitedtextparameter#1% will be sped up
+ {\executeifdefined{\??ci\currentdelimitedtext:\number\delimitedtextlevel#1}%
+ {\executeifdefined{\??ci\currentdelimitedtext#1}%
+ {\executeifdefined{\??ci#1}\empty}}}
+
+\unexpanded\def\definedelimitedtext
+ {\dodoubleempty\dodefinedelimitedtext}
+
+\def\dodefinedelimitedtext[#1][#2]%
+ {\doinitializetextlevel{#1}%
+ \doifassignmentelse{#2}
+ {\getparameters
+ [\??ci#1]
+ [\c!location=\v!margin, % \v!text \v!paragraph
+ \c!spacebefore=,
+ \c!spaceafter=\delimitedtextparameter\c!spacebefore,
+ \c!style=\v!normal,
+ \c!color=,
+ \c!leftmargin=\zeropoint,
+ \c!rightmargin=\delimitedtextparameter\c!leftmargin,
+ \c!indentnext=\v!yes,
+ \c!before=,
+ \c!after=,
+ \c!left=,
+ \c!right=,
+ %\c!level=0,
+ \c!repeat=\v!no,
+ \c!method=,
+ #2]}%
+ {\doifdefined{#2}
+ {\copyparameters[\??ci#1][\??ci#2]
+ [\c!location,\c!spacebefore,\c!spaceafter,\c!style,\c!color,
+ \c!leftmargin,\c!rightmargin,\c!indentnext,
+ \c!before,\c!after,\c!left,\c!right]}}%
+ \doifsomething{#1}
+ {\setuvalue{#1}{\delimitedtext[#1]}%
+ \setvalue{\e!start#1}{\startdelimitedtext[#1]}%
+ \setvalue{\e!stop #1}{\stopdelimitedtext}}}
+
+\unexpanded\def\setupdelimitedtext
+ {\dotripleargument\dosetupdelimitedtext}
+
+\def\dosetupdelimitedtext[#1][#2][#3]% #2 = optional level
+ {\ifthirdargument
+ \getparameters[\??ci#1:#2][#3]%
+ \else\ifsecondargument
+ \getparameters[\??ci#1][#2]%
+ \else
+ \getparameters[\??ci][#1]%
+ \fi\fi}
+
+\def\dorepeatdelimitedtext
+ {\relax\ifcase\delimitedtextlevel\else
+ \dohandledelimitedtext\c!middle % maybe better \dohandleleftdelimitedtext
+ \fi}
+
+\let\dohandlerepeatdelimitedtext\relax
+
+\unexpanded\def\startdelimitedtext[#1]%
+ {\bgroup
+ \pushdelimitedtext{#1}%
+ \doifelse{\delimitedtextparameter\c!method}\s!font
+ {\def\dostopdelimitedtext
+ {\removeunwantedspaces\ignoredelimitedtext\c!right}%
+ \ignoredelimitedtext\c!left\ignorespaces}
+ {\doifelse{\delimitedtextparameter\c!repeat}\v!yes
+ {\let\dohandlerepeatdelimitedtext\dorepeatdelimitedtext}%
+ {\let\dohandlerepeatdelimitedtext\relax}%
+ \doifinsetelse{\delimitedtextparameter\c!location}{\v!paragraph,\v!margin}%
+ {\dosingleempty\dostartdelimitedtextpar}\dostartdelimitedtexttxt}}
+
+% \def\dostartdelimitedtextpar[#1]%
+% {\let\dostopdelimitedtext\dostopdelimitedtextpar
+% \doifsomething{\delimitedtextparameter\c!spacebefore}
+% {\blank[\delimitedtextparameter\c!spacebefore]}%
+% \delimitedtextparameter\c!before
+% % nicer:
+% % \doadaptleftskip {\delimitedtextparameter\c!leftmargin}%
+% % \doadaptrightskip{\delimitedtextparameter\c!rightmargin}%
+% % backward compatible:
+% \doifelsenothing{#1}
+% {\endgraf
+% \doadaptleftskip {\delimitedtextparameter\c!leftmargin}%
+% \doadaptrightskip{\delimitedtextparameter\c!rightmargin}%
+% \let\dodostopdelimitedtextpar\endgraf}
+% {\startnarrower[#1]\let\dodostopdelimitedtextpar\stopnarrower}%
+% % so far
+% % \dochecknextindentation{\??ci\currentdelimitedtext}% AM: not here
+% \dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color\empty
+% \leftdelimitedtextmark
+% \ignorespaces}
+
+% \def\dostopdelimitedtextpar
+% {\removeunwantedspaces
+% \removelastskip
+% \rightdelimitedtextmark
+% \dostopattributes
+% \dodostopdelimitedtextpar
+% \delimitedtextparameter\c!after
+% \doifsomething{\delimitedtextparameter\c!spaceafter}
+% {\blank[\delimitedtextparameter\c!spaceafter]}%
+% \dochecknextindentation{\??ci\currentdelimitedtext}% AM: here
+% \dorechecknextindentation}% AM: This was missing!
+
+\def\dostartdelimitedtextpar[#1]%
+ {\let\dostopdelimitedtext\dostopdelimitedtextpar
+ \doifsomething{\delimitedtextparameter\c!spacebefore}
+ {\blank[\delimitedtextparameter\c!spacebefore]}%
+ \delimitedtextparameter\c!before
+ % nicer:
+ % \doadaptleftskip {\delimitedtextparameter\c!leftmargin}%
+ % \doadaptrightskip{\delimitedtextparameter\c!rightmargin}%
+ % backward compatible:
+ \doifelsenothing{#1}
+ {\endgraf
+ \doadaptleftskip {\delimitedtextparameter\c!leftmargin}%
+ \doadaptrightskip{\delimitedtextparameter\c!rightmargin}%
+ \let\dodostopdelimitedtextpar\endgraf}
+ {\startnarrower[#1]\let\dodostopdelimitedtextpar\stopnarrower}%
+ % so far
+ % \dochecknextindentation{\??ci\currentdelimitedtext}% AM: not here
+ \pushmacro\checkindentation
+ \doifsomething{\delimitedtextparameter\c!indenting} % WS
+ {\setupindenting[\delimitedtextparameter\c!indenting]}%
+ \dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color\empty
+ \leftdelimitedtextmark
+ \ignorespaces}
+
+\def\dostopdelimitedtextpar
+ {\removeunwantedspaces
+ \removelastskip
+ \rightdelimitedtextmark
+ \dostopattributes
+ \popmacro\checkindentation
+ \dodostopdelimitedtextpar
+ \delimitedtextparameter\c!after
+ \doifsomething{\delimitedtextparameter\c!spaceafter}
+ {\blank[\delimitedtextparameter\c!spaceafter]}%
+ \dochecknextindentation{\??ci\currentdelimitedtext}% AM: here
+ \dorechecknextindentation}% AM: This was missing!
+
+\def\dostartdelimitedtexttxt
+ {\let\dostopdelimitedtext\dostopdelimitedtexttxt
+ \dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color\empty
+ \dohandleleftdelimitedtext\c!left
+ \ignorespaces}
+
+\def\dostopdelimitedtexttxt
+ {\removeunwantedspaces
+ \dohandlerightdelimitedtext\c!right
+ \dostopattributes}
+
+\unexpanded\def\stopdelimitedtext
+ {\dostopdelimitedtext
+ \popdelimitedtext
+ \egroup}
+
+\def\pushdelimitedtext#1%
+ {\globalpushmacro\currentdelimitedtext
+ \def\currentdelimitedtext{#1}%
+ \global\advance\delimitedtextlevel\plusone}
+
+\def\popdelimitedtext
+ {\global\advance\delimitedtextlevel\minusone
+ \globalpopmacro\currentdelimitedtext}
+
+\unexpanded\def\delimitedtext[#1]%
+ {\dontleavehmode % following ones can be omited
+ \pushdelimitedtext{#1}%
+ \doifelse{\delimitedtextparameter\c!method}\s!font
+ {\dofontdrivendelimited}
+ {\doifinsetelse{\delimitedtextparameter\c!location}{\v!paragraph,\v!margin}%
+ \dodelimitedtextpar\dodelimitedtexttxt}}
+
+% shortcuts
+
+\unexpanded\def\startdelimited{\startdelimitedtext}
+\unexpanded\def\stopdelimited {\stopdelimitedtext} % no let, dynamically assigned
+\def\delimited {\delimitedtext}
+
+\def\leftdelimitedtextmark
+ {\doifsomething{\delimitedtextparameter\c!left}
+ {\setbox\scratchbox\hbox{\delimitedtextparameter\c!left}%
+ \dontleavehmode
+ \doif{\delimitedtextparameter\c!location}\v!margin{\hskip-\wd\scratchbox}%
+ \box\scratchbox}}
+
+\def\rightdelimitedtextmark
+ {\doifsomething{\delimitedtextparameter\c!right}
+ {\hsmash{\delimitedtextparameter\c!right}}}
+
+% \starttext
+% \hyphenatedword{groepsvrijstellingsverordeningen}\par
+% \hyphenatedword{\quote{groepsvrijstellingsverordeningen}}\par
+% \dorecurse{100}{\hskip300pt\hskip\recurselevel pt test \quote{xxx xxxx}.\par}
+% \page \setuppapersize[A5][A4]
+% \quotation {overly beautiful pusillanimous sesquipedalian
+% longwinded} test test test test test test test test test test test
+% test test test test test test test test test test test test test
+% test test test test test test test test test test test test test
+% test test test test test test test test test test test test test
+% test test test
+% \stoptext
+
+\def\dohandledelimitedtext#1#2%
+ {\begingroup
+ \setbox\scratchbox\hbox{\delimitedtextparameter#1}%
+ \ifdim\wd\scratchbox>\zeropoint
+% \ifdim\lastskip=\delimitedtextsignal
+% \unskip
+ \ifdim\lastkern=\delimitedtextsignal
+ \unkern
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else
+ #2%
+ \fi
+ \ifhmode % else funny pagebeaks
+ \penalty\plustenthousand
+ \hskip\zeropoint % == \prewordbreak
+ \fi
+ \strut % new, needed below
+ \delimitedtextparameter#1% unhbox\scratchbox
+% \penalty\plustenthousand % else overfull boxes, but that's better than dangling periods
+ \kern\delimitedtextsignal % +- \prewordbreak
+ \fi
+ \endgroup}
+
+\def\dohandleleftdelimitedtext#1#2%
+ {\begingroup
+ \setbox\scratchbox\hbox{\delimitedtextparameter#1}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \ifdim\lastkern=\delimitedtextsignal
+ \unkern
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else\ifdim\lastskip=\delimitedtextsignal
+ \unskip
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else
+ #2%
+ \fi\fi
+ \strut % new, needed below
+ \ifhmode % else funny pagebeaks
+ \penalty\plustenthousand
+ \hskip\zeropoint % == \prewordbreak
+ \fi
+ \strut % new, needed below
+ \delimitedtextparameter#1% unhbox\scratchbox
+ \hskip\delimitedtextsignal % +- \prewordbreak
+ \fi
+ \endgroup}
+
+\def\dohandlerightdelimitedtext#1#2%
+ {\begingroup
+ \setbox\scratchbox\hbox{\delimitedtextparameter#1}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \ifdim\lastkern=\delimitedtextsignal
+ \unkern
+ \penalty\plustenthousand
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else\ifdim\lastskip=\delimitedtextsignal
+ \unskip
+ \penalty\plustenthousand
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else
+ #2%
+ \fi\fi
+ \ifhmode % else funny pagebeaks
+ \penalty\plustenthousand
+ \hskip\zeropoint % == \prewordbreak
+ \fi
+ \strut % new, needed below
+ \delimitedtextparameter#1% unhbox\scratchbox
+ \kern\delimitedtextsignal % +- \prewordbreak
+ \fi
+ \endgroup}
+
+
+\def\ignoredelimitedtext#1%
+ {\delimitedtextparameter#1}
+
+\def\handledelimitedtext#1%
+ {\dohandledelimitedtext{#1}\relax}
+
+\def\handleleftdelimitedtext#1%
+ {\dohandleleftdelimitedtext{#1}\relax}
+
+\def\handlerightdelimitedtext#1%
+ {\dohandlerightdelimitedtext{#1}\relax}
+
+\unexpanded\def\dodelimitedtextpar
+ {\dohandleleftdelimitedtext\c!left\relax
+ \groupedcommand
+ \donothing
+ {\dohandlerightdelimitedtext\c!right\removelastskip
+ \popdelimitedtext}}
+
+\unexpanded\def\dodelimitedtexttxt
+ {\doifelse{\delimitedtextparameter\c!style}\v!normal
+ \doquoteddelimited\doattributeddelimited}
+
+\def\doquoteddelimited
+ {\dohandleleftdelimitedtext\c!left\relax
+ \groupedcommand
+ \donothing
+ {\dohandlerightdelimitedtext\c!right
+ \removelastskip
+ \popdelimitedtext}}
+
+\def\doattributeddelimited
+ {\groupedcommand
+ {\dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color}
+ {\dostopattributes
+ \popdelimitedtext}}
+
+\def\dofontdrivendelimited
+ {\simplegroupedcommand
+ {\languageparameter{\c!left\currentdelimitedtext}}
+ {\languageparameter{\c!right\currentdelimitedtext}%
+ \popdelimitedtext}}
+
+% testcase for nesting:
+%
+% \quotation{... \quotation{...} ...}
+% \startquotation ... \startquotation... \quotation{...} \stopquotation\space ...\stopquotation
+% \setupdelimitedtext[quotation][1][left=(,right=)]
+% \setupdelimitedtext[quotation][2][left={[},right={]}]
+% \setupdelimitedtext[quotation][3][left=\{,right=\}]
+% \quotation{... \quotation{...} ...}
+% \startquotation ... \startquotation... \quotation{...} \stopquotation\space ...\stopquotation
+
+\definedelimitedtext
+ [\v!quotation]
+ [\c!left={\symbol[\c!leftquotation]},
+ \c!right={\symbol[\c!rightquotation]},
+ \c!leftmargin=\v!standard]
+
+\definedelimitedtext
+ [\v!quote][\v!quotation]
+
+\setupdelimitedtext
+ [\v!quote]
+ [\c!location=\v!text,
+ \c!left={\symbol[\c!leftquote]},
+ \c!right={\symbol[\c!rightquote]}]
+
+\definedelimitedtext
+ [\v!blockquote][\v!quotation]
+
+\setupdelimitedtext
+ [\v!blockquote]
+ [\c!left=,
+ \c!right=]
+
+\definedelimitedtext
+ [\v!speech][\v!quotation]
+
+\setupdelimitedtext
+ [\v!speech]
+ [\c!repeat=\v!yes,
+ \c!left={\symbol[\c!leftspeech]},
+ \c!middle={\symbol[\c!middlespeech]},
+ \c!right={\symbol[\c!rightspeech]}]
+
+% how do we call an tight quote
+%
+% \definedelimitedtext
+% [\v!quotation][\v!quotation]
+%
+% \setupdelimitedtext
+% [\v!quotation]
+% [\c!indentnext=\v!no,
+% \c!spacebefore=\v!nowhite]
+
+\unexpanded\def\setupquotation{\setupdelimitedtext[\v!quotation]}
+\unexpanded\def\setupquote {\setupdelimitedtext[\v!quote]}
+
+% seldom used, move from kernel to run time module
+
+\ifx\tfx\undefined \let\tfx\relax \fi
+
+\def\basegrid
+ {\dosingleempty\dobasegrid}
+
+\def\dobasegrid[#1]%
+ {\begingroup
+ \getparameters[\??rt]
+ [\c!x=0,\c!y=0,
+ \c!nx=10,\c!ny=10,
+ \c!dx=.5,\c!dy=.5,
+ \c!xstep=0,\c!ystep=0,
+ \c!unit=\s!cm,
+ \c!scale=1,
+ \c!factor=1,
+ \c!offset=\v!yes,
+ \c!location=\v!left,
+ #1]%
+ \startpositioning
+ \dimen0=\@@rtdx\@@rtunit\relax
+ \dimen0=\@@rtscale\dimen0\relax
+ \dimen0=\@@rtfactor\dimen0\relax
+ \multiply\dimen0 \@@rtnx\relax
+ \dimen2=\@@rtdy\@@rtunit\relax
+ \dimen2=\@@rtscale\dimen2\relax
+ \dimen2=\@@rtfactor\dimen2\relax
+ \multiply\dimen2 \@@rtny\relax
+ \def\horline
+ {\vbox
+ {\hrule
+ \!!width \dimen0
+ \!!height \linewidth
+ \!!depth \!!zeropoint}}%
+ \def\verline%
+ {\vrule
+ \!!width \linewidth
+ \!!height \dimen2
+ \!!depth \!!zeropoint}%
+ \doglobal\newcounter\@@gridc
+ \doglobal\newcounter\@@gridd
+ \doglobal\newcounter\@@gride
+ \def\setlegend##1##2##3%
+ {\gdef\@@gridc{0}%
+ \dimen0=2em\relax
+ \dimen2=##2\@@rtunit\relax
+ \dimen2=\@@rtscale\dimen2\relax
+ \dimen2=\@@rtfactor\dimen2\relax
+ \divide\dimen0 \dimen2\relax
+ \xdef\@@gride{\number\dimen0}%
+ \ifnum\@@gride>50
+ \gdef\@@gride{100}%
+ \else\ifnum\@@gride>10
+ \gdef\@@gride{50}%
+ \else\ifnum\@@gride>5
+ \gdef\@@gride{10}%
+ \else\ifnum\@@gride>1
+ \gdef\@@gride{5}%
+ \else
+ \gdef\@@gride{1}%
+ \fi\fi\fi\fi
+ \gdef\@@gridd{0}%
+ \def\legend
+ {\ifnum\@@gridd=\zerocount
+ \vbox
+ {\increment(\@@gridc,##1)%
+ \hbox to 2em{\hss\@@gridc\hss}}%
+ \global\let\@@gridd=\@@gride
+ \fi
+ \doglobal\decrement\@@gridd
+ \doglobal\increment(\@@gridc,##1)}}%
+ \def\draw##1##2##3##4##5##6##7##8##9%
+ {\setuppositioning
+ [\c!state=##8,
+ \c!xstep=\v!absolute,
+ \c!ystep=\v!absolute,
+ \c!unit=\@@rtunit,
+ \c!scale=\@@rtscale,
+ \c!factor=\@@rtfactor,
+ \c!offset=\@@rtoffset,
+ \c!xoffset=##6,
+ \c!yoffset=##7]%
+ \doifelse{##9}\v!middle
+ {\scratchdimen##3pt\scratchdimen.5\scratchdimen
+ \edef\@@psxx{\withoutpt\the\scratchdimen}%
+ \scratchdimen##4pt\scratchdimen.5\scratchdimen
+ \edef\@@psyy{\withoutpt\the\scratchdimen}%
+ \scratchcounter##2\advance\scratchcounter -1
+ \edef\@@pszz{\the\scratchcounter}}
+ {\edef\@@psxx{0}\edef\@@psyy{0}\edef\@@pszz{##2}}%
+ \position(\@@psxx,\@@psyy){##1}%
+ \setuppositioning
+ [\c!state=##8,
+ \c!xstep=\v!relative,
+ \c!ystep=\v!relative,
+ \c!scale=\@@rtscale,
+ \c!factor=\@@rtfactor,
+ \c!offset=\@@rtoffset,
+ \c!unit=\@@rtunit]%
+ \dorecurse\@@pszz{\position(##3,##4){##5}}}%
+ \draw
+ \verline\@@rtnx\@@rtdx0\verline\!!zeropoint\!!zeropoint\v!start\empty
+ \draw
+ \horline\@@rtny0\@@rtdy\horline\!!zeropoint\!!zeropoint\v!start\empty
+ \tfx
+ \doifnot\@@rtxstep{0}
+ {\setlegend\@@rtxstep\@@rtdx\@@rtx
+ \draw\legend\@@rtnx\@@rtdx0\legend{-1em}{-1.5em}\v!overlay\@@rtlocation}%
+ \doifnot\@@rtystep{0}
+ {\setlegend\@@rtystep\@@rtdy\@@rty
+ \draw\legend\@@rtny0\@@rtdy\legend{-2em}{-.75ex}\v!overlay\@@rtlocation}%
+ \stoppositioning
+ \endgroup}
+
+\let\grid\basegrid
+
+% only used at pragma, move from kernel to run time module
+
+\def\referraldate
+ {\currentdate[\v!referral]}
+
+\def\doreferral[#1]%
+ {\noheaderandfooterlines
+ \bgroup
+ \getparameters
+ [\??km]
+ [\c!bet=\unknown,\c!dat=\unknown,\c!ken=\unknown,
+ \c!from=,\c!to=,\c!ref=,#1]%
+ % moet anders, hoort niet in 01b
+ \assigntranslation[\s!nl=referentie,\s!en=reference,\s!de=Referenz,\s!sp=referencia]\to\@@@kmref
+ \assigntranslation[\s!nl=van,\s!en=from,\s!de=Von,\s!sp=de]\to\@@@kmvan
+ \assigntranslation[\s!nl=aan,\s!en=to,\s!de=An,\s!sp=a]\to\@@@kmaan
+ \assigntranslation[\s!nl=betreft,\s!en=concerns,\s!de=Betreff,\s!sp=]\to\@@@kmbet
+ \assigntranslation[\s!nl=datum,\s!en=date,\s!de=Datum,\s!sp=fecha]\to\@@@kmdat
+ \assigntranslation[\s!nl=kenmerk,\s!en=mark,\s!de=Kennzeichen,\s!sp=]\to\@@@kmken
+ %
+ \definetabulate[\s!dummy][|l|p|]
+ \startdummy
+ \NC\@@@kmbet\EQ\@@kmbet\NC\NR
+ \NC\@@@kmdat\EQ\@@kmdat\NC\NR
+ \NC\@@@kmken\EQ\expanded{\smallcapped{\@@kmken}}\NC\NR
+ \doifsomething{\@@kmfrom\@@kmto}{\NC\NC\NC\NR}%
+ \doifsomething \@@kmfrom {\NC\@@@kmvan\EQ\@@kmfrom\NC\NR}%
+ \doifsomething \@@kmto {\NC\@@@kmaan\EQ\@@kmto\NC\NR}%
+ \doifsomething \@@kmref {\NC\NC\NC\NR\NC\@@@kmref\EQ\@@kmref\NC\NR}%
+ \stopdummy
+ \egroup}
+
+\def\referral
+ {\dosingleargument\doreferral}
+
+% FUZZY OLD STUFF: will be removed when not used in some manual;
+% rows instead of columns, i'd forgotten that this code exist
+%
+% \definesystemvariable{ri}
+%
+% \unexpanded\def\setuprows
+% {\dodoubleargument\getparameters[\??ri]}
+%
+% \definecomplexorsimpleempty\startrows
+%
+% \def\complexstartrows[#1]%
+% {\bgroup
+% \setuprows[#1]%
+% \let\do@@ribottom\relax
+% \def\row
+% {\do@@ribottom
+% \egroup
+% \dimen0\vsize
+% \divide\dimen0 \@@rin
+% \advance\dimen0 -\lineskip
+% \vbox to \dimen0
+% \bgroup
+% \@@ritop
+% \let\do@@ribottom\@@ribottom
+% \ignorespaces}%
+% \bgroup
+% \row}
+%
+% \unexpanded\def\stoprows
+% {\do@@ribottom
+% \egroup
+% \egroup}
+%
+% \setuprows
+% [\c!n=2,
+% \c!top=,
+% \c!bottom=\vfill]
+
+% THIS WAS MAIN-003.TEX
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+\definetabulate
+ [\v!legend]
+ [|emj1|i1|mR|]
+
+\setuptabulate
+ [\v!legend]
+ [\c!unit=.75em,\c!inner=\setquicktabulate\leg,EQ={=}]
+
+\definetabulate
+ [\v!legend][\v!two]
+ [|emj1|emk1|i1|mR|]
+
+\definetabulate
+ [\v!fact]
+ [|R|ecmj1|i1mR|]
+
+\setuptabulate
+ [\v!fact]
+ [\c!unit=.75em,\c!inner=\setquicktabulate\fact,EQ={=}]
+
+\unexpanded\def\xbox
+ {\bgroup\aftergroup\egroup\hbox\bgroup\tx\let\next=}
+
+\unexpanded\def\xxbox
+ {\bgroup\aftergroup\egroup\hbox\bgroup\txx\let\next=}
+
+% \def\mrm#1%
+% {$\rm#1$}
+
+%D \macros
+%D {definepairedbox, setuppairedbox, placepairedbox}
+%D
+%D Paired boxes, formally called legends, but from now on a
+%D legend is just an instance, are primarily meant for
+%D typesetting some text alongside an illustration. Although
+%D there is quite some variation possible, the functionality is
+%D kept simple, if only because in most cases such pairs are
+%D typeset sober.
+%D
+%D The location specification accepts a pair, where the first
+%D keyword specifies the arrangement, and the second one the
+%D alignment. The first key of the location pair is one of
+%D \type {left}, \type {right}, \type {top} or \type {bottom},
+%D while the second key can also be \type {middle}.
+%D
+%D The first box is just collected in an horizontal box, but
+%D the second one is a vertical box that gets passed the
+%D bodyfont and alignment settings.
+
+%D Today we would implement this using layers .... but for the
+%D moment we keep it this way.
+
+% \startbuffer[test]
+% \test left \test left,top \test left,bottom \test left,middle
+% \test right \test right,top \test right,bottom \test right,middle
+% \test top \test top,left \test top,right \test top,middle
+% \test bottom \test bottom,left \test bottom,right \test bottom,middle
+% \stopbuffer
+%
+% \def\showtest#1%
+% {\pagina
+% \typebuffer[demo]
+% \def\test##1
+% {\startlinecorrection[blank]
+% \getbuffer[demo]%
+% \ruledhbox\placelegend
+% [bodyfont=6pt,location={##1}]
+% {\framed[width=.25\textwidth]{\tttf##1}}
+% {#1}
+% \stoplinecorrection}
+% \getbuffer[test]}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=\hsize,maxwidth=\makeupwidth,
+% height=\vsize,maxheight=\makeupheight]
+% \stopbuffer
+%
+% \showtest{These examples demonstrate the default settings.}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=\textwidth,
+% maxwidth=\textwidth]
+% \stopbuffer
+%
+% \showtest{\input tufte }
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=.65\textwidth]
+% \stopbuffer
+%
+% \showtest{\input knuth }
+%
+% \startbuffer[demo]
+% \setuplegend
+% [height=2cm]
+% \stopbuffer
+%
+% \showtest{These examples demonstrate some other settings.}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=.65\textwidth,
+% height=2cm]
+% \stopbuffer
+%
+% \showtest{These examples demonstrate some other settings.}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [n=2,align=right,width=.5\textwidth]
+% \stopbuffer
+%
+% \showtest{\input zapf }
+
+%D \macros
+%D {setuplegend, placelegend}
+%D
+%D It makes sense to typeset a legend to a figure in \TEX\
+%D and not in a drawing package. The macro \type {\placelegend}
+%D combines a figure (or something else) and its legend. This
+%D command is just a paired box.
+%D
+%D The legend is placed according to \type {location}, being
+%D \type {bottom} or \type {right}. The macro macro is used as
+%D follows.
+%D
+%D \starttyping
+%D \placefigure
+%D {whow}
+%D {\placelegend
+%D {\externalfigure[cow]}
+%D {\starttabulation
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulation}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend
+%D {\externalfigure[cow]}
+%D {\starttabulation[|l|l|l|l|]
+%D \NC 1 \NC head \NC 3 \NC tail \NC \NR
+%D \NC 2 \NC legs \NC \NC \NC \NR
+%D \stoptabulation}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {\starttabulation
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulation}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {head \par legs \par tail}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {\startitemize[packed]
+%D \item head \item legs \item tail \item belly \item horns
+%D \stopitemize}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2,width=.8\hsize]
+%D {\externalfigure[cow]}
+%D {\startitemize[packed]
+%D \item head \item legs \item tail \item belly \item horns
+%D \stopitemize}}
+%D \stoptyping
+
+\newbox\firstpairedbox
+\newbox\secondpairedbox
+
+\unexpanded\def\definepairedbox
+ {\dodoubleempty\dodefinepairedbox}
+
+\def\dodefinepairedbox[#1][#2]%
+ {\getparameters
+ [\??ld#1]
+ [\c!n=1,
+ \c!distance=\bodyfontsize,
+ \c!before=,
+ \c!after=,
+ \c!color=,
+ \c!style=,
+ \c!inbetween={\blank[\v!medium]},
+ \c!width=\hsize,
+ \c!height=\vsize,
+ \c!maxwidth=\textwidth, % \makeupwidth,
+ \c!maxheight=\textheight, % \makeupheight,
+ \c!bodyfont=,
+ \c!align=,
+ \c!location=\v!bottom,
+ #2]%
+ \setvalue{\e!setup#1\e!endsetup}{\setuppairedbox[#1]}%
+ \setvalue{\e!place#1}{\placepairedbox[#1]}}
+
+\unexpanded\def\setuppairedbox
+ {\dodoubleempty\dosetuppairedbox}
+
+\def\dosetuppairedbox[#1]%
+ {\getparameters[\??ld#1]}
+
+\unexpanded\def\placepairedbox
+ {\bgroup\dodoubleempty\doplacepairedbox}
+
+\def\doplacepairedbox[#1][#2]% watch the hsize/vsize tricks
+ {\setuppairedbox[#1][#2]% % and don't change them
+ \copyparameters % brrr
+ [\??ld][\??ld#1]
+ [\c!n,\c!distance,\c!inbetween,\c!before,\c!after,
+ \c!width,\c!height,\c!maxwidth,\c!maxheight,
+ \c!color,\c!style,\c!bodyfont,\c!align,\c!location]%
+ \@@ldbefore\bgroup
+ \global\setsystemmode{pairedbox}%
+ \beforefirstpairedbox
+ \dowithnextbox
+ {\betweenbothpairedboxes
+ \dowithnextbox
+ {\afterbothpairedboxes
+ \egroup\@@ldafter
+ \egroup}
+ \vbox\bgroup
+ \insidesecondpairedbox
+ \let\next=}
+ \hbox}
+
+\def\beforefirstpairedbox
+ {\chardef\pairedlocationa1 % left
+ \chardef\pairedlocationb4 % middle
+ \getfromcommacommand[\@@ldlocation][1]%
+ \processaction
+ [\commalistelement]
+ [ \v!left=>\chardef\pairedlocationa0,
+ \v!right=>\chardef\pairedlocationa1,
+ \v!top=>\chardef\pairedlocationa2,
+ \v!bottom=>\chardef\pairedlocationa3]%
+ \getfromcommacommand[\@@ldlocation][2]%
+ \processaction
+ [\commalistelement]
+ [ \v!left=>\chardef\pairedlocationb0,
+ \v!right=>\chardef\pairedlocationb1,
+ \v!high=>\chardef\pairedlocationb2,
+ \v!top=>\chardef\pairedlocationb2,
+ \v!low=>\chardef\pairedlocationb3,
+ \v!bottom=>\chardef\pairedlocationb3,
+ \v!middle=>\chardef\pairedlocationb4]}
+
+\def\betweenbothpairedboxes
+ {\switchtobodyfont[\@@ldbodyfont]% split under same regime
+ \setbox\firstpairedbox\flushnextbox
+ \ifnum\pairedlocationa<2
+ \hsize\wd\firstpairedbox % trick
+ \hsize\@@ldwidth
+ \scratchdimen\wd\firstpairedbox
+ \advance\scratchdimen \@@lddistance
+ \bgroup\advance\scratchdimen \hsize
+ \ifdim\scratchdimen>\@@ldmaxwidth\relax
+ \egroup
+ \hsize\@@ldmaxwidth
+ \advance\hsize -\scratchdimen
+ \else
+ \egroup
+ \fi
+ \else
+ \hsize\wd\firstpairedbox
+ \hsize\@@ldwidth % can be \hsize
+ \ifdim\hsize>\@@ldmaxwidth\relax \hsize\@@ldmaxwidth \fi % can be \hsize
+ \fi
+ \ifnum\@@ldn>\plusone
+ \setrigidcolumnhsize\hsize\@@lddistance\@@ldn
+ \fi}
+
+\def\afterbothpairedboxes
+ {\setbox\secondpairedbox\vbox
+ {\ifnum\@@ldn>1
+ \rigidcolumnbalance\nextbox
+ \else
+ \flushnextbox
+ \fi}%
+ \ifnum\pairedlocationa<2\hbox\else\vbox\fi\bgroup % hide vsize
+ \forgetall
+ \ifnum\pairedlocationa<2
+ \scratchdimen\maxoftwoboxdimens\ht\firstpairedbox\secondpairedbox
+ \vsize\scratchdimen
+ \ifdim\scratchdimen<\@@ldheight\relax % can be \vsize
+ \scratchdimen\@@ldheight
+ \fi
+ \ifdim\scratchdimen>\@@ldmaxheight\relax
+ \scratchdimen\@@ldmaxheight
+ \fi
+ \valignpairedbox\firstpairedbox \scratchdimen
+ \valignpairedbox\secondpairedbox\scratchdimen
+ \else
+ \scratchdimen\maxoftwoboxdimens\wd\firstpairedbox\secondpairedbox
+ \halignpairedbox\firstpairedbox \scratchdimen
+ \halignpairedbox\secondpairedbox\scratchdimen
+ \scratchdimen\ht\secondpairedbox
+ \vsize\scratchdimen
+ \ifdim\ht\secondpairedbox<\@@ldheight\relax % can be \vsize
+ \scratchdimen\@@ldheight\relax % \relax needed
+ \fi
+ \ifdim\scratchdimen>\@@ldmaxheight\relax % todo: totale hoogte
+ \scratchdimen\@@ldmaxheight\relax % \relax needed
+ \fi
+ \ifdim\scratchdimen>\ht\secondpairedbox
+ \setbox\secondpairedbox\vbox to \scratchdimen
+ {\ifnum\pairedlocationa=3 \vss\fi %
+ \box\secondpairedbox
+ \ifnum\pairedlocationa=2 \vss\fi}% \kern\zeropoint
+ \fi
+ \fi
+ \ifcase\pairedlocationa
+ \box\secondpairedbox\hskip\@@lddistance\box\firstpairedbox \or
+ \box\firstpairedbox \hskip\@@lddistance\box\secondpairedbox\or
+ \box\secondpairedbox\endgraf \nointerlineskip \@@ldinbetween \box\firstpairedbox \or
+ \box\firstpairedbox \endgraf \nointerlineskip \@@ldinbetween \box\secondpairedbox\else
+ \fi
+ \egroup}
+
+\def\insidesecondpairedbox
+ {\forgetall
+ \setupalign[\@@ldalign]%
+ \tolerantTABLEbreaktrue % hm.
+ \blank[\v!disable]%
+ \everypar{\begstrut}}
+
+\def\maxoftwoboxdimens#1#2#3%
+ {#1\ifdim#1#2>#1#3 #2\else#3\fi}
+
+\def\valignpairedbox#1#2%
+ {\setbox#1\vbox to #2
+ {\ifcase\pairedlocationb\or\or\or\vss\or\vss\fi
+ \box#1\relax
+ \ifcase\pairedlocationb\or\or\vss\or\or\vss\fi}}
+
+\def\halignpairedbox#1#2%
+ {\setbox#1\hbox to #2
+ {\ifcase\pairedlocationb\or\hss\or\or\or\hss\fi
+ \box#1\relax
+ \ifcase\pairedlocationb\hss\or\or\or\or\hss\fi}}
+
+\definepairedbox[\v!legend]
+
+%D Goody:
+
+\appendtoks
+ \global\resetsystemmode{combination}%
+ \global\resetsystemmode{pairedbox}%
+\to \everyinsidefloat
+
+% todo: \startcombination \startcomb \stopcomb ...
+
+% needs to be mkiv'd
+
+\newcount\horcombination % counter
+\newcount\totcombination
+
+\unexpanded\def\definecombination
+ {\dodoubleempty\dodefinecombination}
+
+\def\dodefinecombination[#1][#2]%
+ {\copyparameters
+ [\??co#1][\??co]
+ [\c!width,\c!height,\c!distance,\c!location,%
+ \c!before,\c!inbetween,\c!after,\c!align,%
+ \c!style,\c!color]%
+ \getparameters
+ [\??co#1][#2]}
+
+\unexpanded\def\setupcombinations
+ {\dodoubleempty\dosetupcombinations}
+
+\def\dosetupcombinations[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??co#1][#2]%
+ \else
+ \getparameters[\??co][#1]%
+ \fi}
+
+\def\combinationparameter#1%
+ {\csname\??co\currentcombination#1\endcsname}%
+
+\unexpanded\def\startcombination
+ {\bgroup % so we can grab a group
+ \dodoubleempty\dostartcombination}
+
+% \startcombination {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[2*1] {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[1*2] {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[2] {alpha} {a} {beta} {b} \stopcombination
+
+\def\dostartcombination[#1][#2]%
+ {\global\setsystemmode{combination}%
+ \doifnothing{#1}\firstargumentfalse % to be sure (when called in macros)
+ \doifnothing{#2}\secondargumentfalse % to be sure (when called in macros)
+ \ifsecondargument
+ \def\currentcombination{#1}%
+ \edef\currentcombinationspec{#2*1*}%
+ \else % better : \doifcombinationelse ... \??co#1\c!location
+ \doifinstringelse{*}{#1}
+ {\let\currentcombination\empty
+ \edef\currentcombinationspec{#1*1*}}
+ {\doifnumberelse{#1}
+ {\let\currentcombination\empty
+ \edef\currentcombinationspec{#1*1*}}
+ {\def\currentcombination{#1}%
+ \edef\currentcombinationspec{2*1*}}}%
+ \fi
+ \forgetall
+ \doifelse{\combinationparameter\c!height}\v!fit
+ \vbox {\vbox to \combinationparameter\c!height}%
+ \bgroup
+ \expanded{\dodostartcombination[\currentcombinationspec]}}
+
+\long\def\dodostartcombination[#1*#2*#3]%
+ {\setuphorizontaldivision
+ [\c!n=\v!fit,\c!distance=\combinationparameter\c!distance]%
+ \global\horcombination#1%
+ \global\totcombination#2%
+ \global\setbox\combinationstack\emptybox
+ \xdef\maxhorcombination{\the\horcombination}%
+ \multiply\totcombination\horcombination
+ \tabskip\zeropoint
+ \doifelse{\combinationparameter\c!width}\v!fit
+ {\halign}{\halign to \combinationparameter\c!width}%
+ \bgroup&%
+ %\hfil##\hfil% now : location={left,top}
+ \expanded{\doifnotinset{\v!left}{\combinationparameter\c!location}}\hfil
+ ##%
+ \expanded{\doifnotinset{\v!right}{\combinationparameter\c!location}}\hfil
+ &\tabskip\zeropoint \!!plus 1fill##\cr
+ \docombination}
+
+\def\docombination % we want to add struts but still ignore an empty box
+ {\dowithnextbox
+ {\setbox0\flushnextbox
+ \dowithnextbox
+ {\setbox2\flushnextbox
+ \dodocombination}%
+ \vtop\bgroup
+ \def\next
+ {\futurelet\nexttoken\nextnext}%
+ \def\nextnext
+ {\ifx\nexttoken\egroup \else % the next box is empty
+ \hsize\wd0
+ \setupalign[\combinationparameter\c!align]%
+ \dostartattributes{\??co\currentcombination}\c!style\c!color\empty
+ \bgroup
+ \aftergroup\endstrut
+ \aftergroup\dostopattributes
+ \aftergroup\egroup
+ \begstrut
+ \fi}%
+ \afterassignment\next\let\nexttoken=}
+ \hbox}
+
+\def\depthonlybox
+ {\dowithnextbox{\vtop{\hsize\wd\nextbox\kern\zeropoint\box\nextbox}}\vbox}
+
+\def\dodocombination
+ {\vbox
+ {\forgetall % \setupwhitespace[\v!none]%
+ \let\next\vbox
+ \expanded{\processallactionsinset[\combinationparameter\c!location]}
+ [ \v!top=>\let\next\depthonlybox, % \tbox,
+ \v!middle=>\let\next\halfwaybox]%
+ \next{\copy0}%
+ % we need to save the caption for a next alignment line
+ \saveoncombinationstack2}%
+ \ifnum\totcombination>\plusone
+ \global\advance\totcombination\minusone
+ \global\advance\horcombination\minusone
+ \ifnum\horcombination=\zerocount
+ \def\next
+ {\cr
+ \flushcombinationstack
+ \noalign
+ {\forgetall % \setupwhitespace[\v!none]% no
+ \global\setbox\combinationstack\emptybox
+ \nointerlineskip
+ \combinationparameter\c!after
+ \combinationparameter\c!before
+ \vss
+ \nointerlineskip}%
+ \global\horcombination\maxhorcombination\relax
+ \docombination}%
+ \else
+ \def\next
+ {&&&\hskip\combinationparameter\c!distance&\docombination}%
+ \fi
+ \else
+ \def\next
+ {\cr
+ \flushcombinationstack
+ \egroup}%
+ \fi
+ \next}
+
+% formally ok:
+%
+% \unexpanded\def\stopcombination
+% {\egroup
+% \egroup}
+%
+% more robust:
+%
+% \unexpanded\def\stopcombination
+% {{}{}{}{}{}{}{}{}% catches (at most 4) missing entries
+% \egroup
+% \egroup}
+%
+% even better:
+
+\unexpanded\def\stopcombination
+ {{\scratchtoks{{}{}{}}\dorecurse\totcombination{\appendtoks{}{}{}{}\to\scratchtoks}\expandafter}\the\scratchtoks
+ \egroup
+ \egroup}
+
+\newbox\combinationstack
+
+\def\saveoncombinationstack#1%
+ {\global\setbox\combinationstack\hbox
+ {\hbox{\box#1}\unhbox\combinationstack}}
+
+\def\flushcombinationstack
+ {\noalign
+ {\ifdim\ht\combinationstack>\zeropoint
+\nointerlineskip % nieuw
+ \combinationparameter\c!inbetween
+ \global\horcombination\maxhorcombination
+ \globallet\doflushcombinationstack\dodoflushcombinationstack
+ \else
+ \global\setbox\combinationstack\emptybox
+ \globallet\doflushcombinationstack\donothing
+ \fi}%
+ \doflushcombinationstack\crcr}
+
+\gdef\dodoflushcombinationstack
+ {\global\setbox\combinationstack\hbox
+ {\unhbox\combinationstack
+ \global\setbox1\lastbox}%
+ \box1% \ruledhbox{\box1}%
+ \global\advance\horcombination\minusone\relax
+ \ifnum\horcombination>\zerocount
+ \def\next{&&&&\doflushcombinationstack}%
+ \else
+ \global\setbox\combinationstack\emptybox
+ %\let\next\relax
+ \@EA\gobbleoneargument
+ \fi
+ \next}
+
+\setupcombinations
+ [\c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!distance=1em,
+ \c!location=\v!bottom, % can be something {top,left}
+ \c!before=\blank,
+ \c!inbetween={\blank[\v!medium]},
+ \c!style=,
+ \c!color=,
+ \c!after=,
+ \c!align=\v!middle]
+
+%D \macros
+%D {startfloatcombination}
+%D
+%D \setupexternalfigures[directory={../sample}]
+%D \startbuffer
+%D \placefigure
+%D [left,none]
+%D {}
+%D {\startfloatcombination[2*2]
+%D \placefigure{alpha}{\externalfigure[cow.pdf][width=1cm]}
+%D \placefigure{beta} {\externalfigure[cow.pdf][width=2cm]}
+%D \placefigure{gamma}{\externalfigure[cow.pdf][width=3cm]}
+%D \placefigure{delta}{\externalfigure[cow.pdf][width=4cm]}
+%D \stopfloatcombination}
+%D
+%D \input tufte
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\unexpanded\def\startfloatcombination
+ {\dodoubleempty\dostartfloatcombination}
+
+\def\dostartfloatcombination[#1][#2]%
+ {\vbox\bgroup
+ %\insidecolumnstrue % trick, forces no centering, todo: proper switch/feature
+ \chardef\postcenterfloatmethod\zerocount
+ \forcelocalfloats
+ \unexpanded\def\stopfloatcombination
+ {\scratchtoks\emptytoks
+ \dorecurse\noflocalfloats
+ {\appendetoks{\noexpand\getlocalfloat{\recurselevel}}{}\to\scratchtoks}%
+ \expanded{\startcombination[#1]\the\scratchtoks}\stopcombination
+ \resetlocalfloats
+ \egroup}}
+
+\unexpanded\def\placerelativetoeachother#1#2%
+ {\bgroup
+ \dowithnextbox
+ {\bgroup
+ \setbox0\box\nextbox
+ \dowithnextbox
+ {\setbox2\box\nextbox
+ #1{#2#########2\cr\box0\cr\box2\cr}
+ \egroup
+ \egroup}
+ \hbox}
+ \hbox}
+
+\unexpanded\def\placeontopofeachother{\placerelativetoeachother\halign\hss}
+\unexpanded\def\placesidebyside {\placerelativetoeachother\valign\vss}
+
+%D A couple of examples, demonstrating how the depth is
+%D taken care of:
+%D
+%D \startbuffer
+%D test\rotate[frame=on, rotation=0] {gans}%
+%D test\rotate[frame=on, rotation=90] {gans}%
+%D test\rotate[frame=on, rotation=180]{gans}%
+%D test\rotate[frame=on, rotation=270]{gans}%
+%D test
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+% When we rotate over arbitrary angles, we need to relocate the
+% resulting box because rotation brings that box onto the negative
+% axis. The calculations (mostly sin and cosine) need to be tuned for
+% the way a box is packages (i.e. the refence point). A typical example
+% of drawing, scribbling, and going back to the days of school math.
+%
+% We do a bit more calculations than needed, simply because that way
+% it's easier to debug the code.
+
+\def\dododorotatenextbox
+ {\setbox\nextbox\vbox to \@@layerysiz
+ {\vfill
+ \hbox to \@@layerxsiz
+ {\dostartrotation\@@rorotation
+ \nextboxwd\zeropoint
+ \nextboxht\zeropoint
+ \flushnextbox
+ \dostoprotation
+ \hfill}%
+ \kern\@@layerypos}%
+ \setbox\nextbox\hbox
+ {\kern\@@layerxpos
+ \kern\@@layerxoff
+ \lower\@@layeryoff\flushnextbox}}
+
+\def\dodorotatenextbox#1#2% quite some trial and error -)
+ {\dontshowcomposition
+ \dontcomplain
+ \ifnum#2=\plusfour
+ % new, location=middle
+ \!!widthb \nextboxwd
+ \!!heightb\nextboxht
+ \!!depthb \nextboxdp
+ \setbox\nextbox\vbox{\vskip.5\nextboxht\hskip-.5\nextboxwd\flushnextbox}%
+ \smashbox\nextbox
+ \fi
+ \!!widtha \nextboxwd
+ \!!heighta\nextboxht
+ \!!deptha \nextboxdp
+ \!!doneafalse
+ \!!donebfalse
+ \ifcase#2\or
+ % 1: fit
+ \or
+ % 2: depth, not fit
+ \!!doneatrue
+ \!!donebtrue
+ \or
+ % 3: depth, fit
+ \!!donebtrue
+ \fi
+ \setbox\nextbox\vbox{\hbox{\raise\nextboxdp\flushnextbox}}%
+ \!!dimena \nextboxht
+ \setcalculatedcos\cos\@@rorotation
+ \setcalculatedsin\sin\@@rorotation
+ \@@layerxpos\zeropoint
+ \@@layerypos\zeropoint
+ \@@layerxoff\zeropoint
+ \@@layeryoff\zeropoint
+ \ifdim\sin\points>\zeropoint
+ \ifdim\cos\points>\zeropoint
+ \@@layerxsiz \cos\!!widtha
+ \@@layerysiz \sin\!!widtha
+ \advance\@@layerxsiz \sin\!!dimena
+ \advance\@@layerysiz \cos\!!dimena
+ \@@layerypos \cos\!!dimena
+ \if!!donea
+ \@@layerxoff \negated\sin\!!dimena
+ \advance\@@layerxoff \sin\!!deptha
+ \fi
+ \if!!doneb
+ \@@layeryoff \cos\!!deptha
+ \fi
+ \dododorotatenextbox
+ \else
+ \@@layerxsiz \negated\cos\!!widtha
+ \@@layerysiz \sin\!!widtha
+ \advance\@@layerxsiz \sin\!!dimena
+ \advance\@@layerysiz \negated\cos\!!dimena
+ \@@layerxpos \negated\cos\!!widtha
+ \if!!donea
+ \@@layerxoff -\@@layerxsiz
+ \advance\@@layerxoff \sin\!!deptha
+ \fi
+ \if!!doneb
+ \@@layeryoff \negated\cos\!!heighta
+ \fi
+ \dododorotatenextbox
+ \wd\nextbox\if!!donea\sin\!!deptha\else\@@layerxsiz\fi
+ \fi
+ \else
+ \ifdim\cos\points<\zeropoint
+ \@@layerxsiz \negated\cos\!!widtha
+ \@@layerysiz \negated\sin\!!widtha
+ \advance\@@layerxsiz \negated\sin\!!dimena
+ \advance\@@layerysiz \negated\cos\!!dimena
+ \@@layerxpos \@@layerxsiz
+ \@@layerypos \negated\sin\!!widtha
+ \if!!donea
+ \@@layerxoff -\@@layerxsiz
+ \advance\@@layerxoff \negated\sin\!!heighta
+ \fi
+ \if!!doneb
+ \@@layeryoff \@@layerysiz
+ \advance\@@layeryoff \cos\!!deptha
+ \fi
+ \dododorotatenextbox
+ \wd\nextbox\if!!donea\negated\sin\!!heighta\else\@@layerxsiz\fi
+ \else
+ \@@layerxsiz \cos\!!widtha
+ \@@layerysiz \negated\sin\!!widtha
+ \advance\@@layerxsiz \negated\sin\!!dimena
+ \advance\@@layerysiz \cos\!!dimena
+ \ifdim\sin\points=\zeropoint
+ \@@layerxpos \zeropoint
+ \@@layerxoff \zeropoint
+ \@@layerypos \@@layerysiz
+ \if!!doneb
+ \@@layeryoff \!!deptha
+ \fi
+ \else
+ \@@layerypos \@@layerysiz
+ \@@layerxpos \negated\sin\!!dimena
+ \if!!donea
+ \@@layerxoff -\@@layerxsiz
+ \advance\@@layerxoff \negated\sin\!!heighta
+ \fi
+ \if!!doneb
+ \@@layeryoff \negated\sin\!!deptha
+ \fi
+ \fi
+ \dododorotatenextbox
+ \ifdim\sin\points=\zeropoint
+ \else
+ \wd\nextbox\if!!donea\negated\sin\!!heighta\else\@@layerxsiz\fi
+ \fi
+ \fi
+ \fi
+ % new, location=middle
+ \ifnum#2=\plusfour
+ \setbox\nextbox\vbox{\vskip-.5\!!heightb\hskip.5\!!heightb\flushnextbox}%
+ \nextboxwd\!!widthb
+ \nextboxht\!!heightb
+ \nextboxdp\!!depthb
+ \fi}
+
+\def\dorotatenextbox#1#2%
+ {\doifsomething{#1}
+ {\edef\@@rorotation{\realnumber{#1}}% get rid of leading zeros and spaces
+ \setbox\nextbox\vbox{\flushnextbox}% not really needed
+ \dodorotatenextbox\@@rorotation#2}%
+ \hbox{\boxcursor\flushnextbox}}
+
+\def\dodorotatebox#1% {angle} \hbox/\vbox/\vtop
+ {\bgroup\hbox\bgroup % compatibility hack
+ \dowithnextbox
+ {\dorotatenextbox{#1}\plusone
+ \egroup\egroup}}
+
+\def\dorotatebox#1% {angle} \hbox/\vbox/\vtop
+ {\ifcase#1\relax
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\dodorotatebox
+ \fi{#1}}
+
+\unexpanded\def\rotate % \bgroup: \rotate kan argument zijn
+ {\bgroup\complexorsimpleempty\rotate}
+
+% \def\complexrotate[#1]% framed met diepte !
+% {\getparameters[\??ro][#1]%
+% \processaction
+% [\@@rolocation]
+% [ \v!depth=>\!!counta\plusthree\donefalse,% depth fit - raw box
+% \v!fit=>\!!counta\plustwo \donefalse,% depth tight - raw box
+% \v!broad=>\!!counta\plusone \donefalse,% nodepth fit - raw box
+% \v!high=>\!!counta\plusone \donetrue ,% nodepth fit - framed
+% \v!middle=>\!!counta\plusfour \donefalse,% centered, keep dimensions
+% \s!default=>\!!counta\plusthree\donetrue ,% depth fit - framed
+% \s!unknown=>\!!counta\plusthree\donetrue ]% depth fit - framed
+% \ifdone
+% \def\docommand{\localframed[\??ro][#1,\c!location=]}%
+% \else
+% \let\docommand\relax
+% \fi
+% \dowithnextbox{\dorotatenextbox\@@rorotation\!!counta\egroup}\vbox\docommand}
+
+\setvalue{\??ro::\c!location::\v!depth }{\!!counta\plusthree\donefalse} % depth fit - raw box
+\setvalue{\??ro::\c!location::\v!fit }{\!!counta\plustwo \donefalse} % depth tight - raw box
+\setvalue{\??ro::\c!location::\v!broad }{\!!counta\plusone \donefalse} % nodepth fit - raw box
+\setvalue{\??ro::\c!location::\v!high }{\!!counta\plusone \donetrue } % nodepth fit - framed
+\setvalue{\??ro::\c!location::\v!middle }{\!!counta\plusfour \donefalse} % centered, keep dimensions
+\setvalue{\??ro::\c!location::\v!default}{\!!counta\plusthree\donetrue } % depth fit - framed
+
+\def\complexrotate[#1]% framed met diepte !
+ {\getparameters[\??ro][#1]%
+ \executeifdefined{\??ro::\c!location::\@@rolocation}{\!!counta\plusthree\donetrue}%
+ \ifdone
+ \def\docommand{\localframed[\??ro][#1,\c!location=]}%
+ \else
+ \let\docommand\relax
+ \fi
+ \dowithnextbox{\dorotatenextbox\@@rorotation\!!counta\egroup}\vbox\docommand}
+
+\presetlocalframed[\??ro]
+
+\unexpanded\def\setuprotate
+ {\dodoubleargument\getparameters[\??ro]}
+
+\setuprotate
+ [\c!rotation=90,
+ \c!location=\v!normal,
+ \c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!offset=\v!overlay,
+ \c!frame=\v!off]
+
+% \dostepwiserecurse{0}{360}{10}
+% {\startlinecorrection[blank]
+% \hbox
+% {\expanded{\setuprotate[rotation=\recurselevel]}%
+% \traceboxplacementtrue
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=depth] {\ruledhbox{\bfb (depth)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=fit] {\ruledhbox{\bfb (fit)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=broad] {\ruledhbox{\bfb (broad)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=normal]{\ruledhbox{\bfb (normal)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=high] {\ruledhbox{\bfb (high)}}}}}
+% \stoplinecorrection}
+
+% to be used in some other places! todo!
+%
+% divides \hsize in fractions, will be made a bit more
+% clever and advanced when needed
+%
+% \horizontaldivision[n/m,elements,distance]
+%
+% \horizontaldivision[2/5,3,1em]
+% \horizontaldivision[2/5,3,1em]
+% \horizontaldivision[1/5,3,1em]
+%
+% \setuphorizontaldivision[afstand=,aantal=] (passend,passend)
+
+\def\??fr{@@fr}
+
+\unexpanded\def\setuphorizontaldivision
+ {\dodoubleargument\getparameters[\??fr]}
+
+\def\horizontaldivision
+ {\dosingleargument\dohorizontaldivision}
+
+\def\dohorizontaldivision[#1]%
+ {\dodohorizontaldivision[#1,,,,,,]}
+
+\def\dodohorizontaldivision[#1/#2,#3,#4,#5]%
+ {\doifelsenothing{#3}
+ {\doifelse\@@frn\v!fit
+ {\!!counta#2\relax}
+ {\!!counta\@@frn\relax}}
+ {\!!counta#3\relax}%
+ \doifelsenothing{#4}
+ {\doifelse\@@frdistance\v!fit
+ {\!!widtha\zeropoint}
+ {\!!widtha\@@frdistance}}
+ {\!!widtha#4}%
+ \advance\!!counta \minusone
+ \multiply\!!widtha \!!counta
+ \advance\hsize -\!!widtha
+ \divide\hsize #2\relax
+ \hsize#1\hsize}
+
+\setuphorizontaldivision
+ [\c!distance=\tfskipsize,
+ \c!n=\v!fit]
+
+%D This one is for Daniel Pittman, who wanted tight
+%D fractions. We show three versions. First the simple
+%D one using \type {\low} and \type {high}:
+%D
+%D \startbuffer
+%D \def\vfrac#1#2%
+%D {\hbox{\high{\tx#1\kern-.25em}/\low{\kern-.25em\tx#2}}}
+%D
+%D test \vfrac{1}{2} test \vfrac{123}{456} test
+%D \stopbuffer
+%D
+%D \typebuffer {\showmakeup\getbuffer}
+%D
+%D A better way to handle the kerning is the following, here
+%D we kind of assume that tye slash is symmetrical and has
+%D nearly zero width.
+%D
+%D \startbuffer
+%D \def\vfract#1#2%
+%D {\hbox{\high{\tx#1}\hbox to \zeropoint{\hss/\hss}\low{\tx#2}}}
+%D \stopbuffer
+%D
+%D \typebuffer {\showmakeup\getbuffer}
+%D
+%D The third and best alternative is the following:
+%D
+%D {\showmakeup\getbuffer}\crlf\getbuffer
+%D
+%D This time we measure the height of the \type {/} and
+%D shift over the maximum height and depths of this
+%D character and the fractional digits (we use 57 as
+%D sample). Here we combine all methods in one macros.
+
+\chardef\vulgarfractionmethod=3
+
+\definehspace[vulgarfraction][.25em] % [.15em]
+\definesymbol[vulgarfraction][/] % [\raise.2ex\hbox{/}]
+
+\unexpanded\def\vulgarfraction#1#2%
+ {\dontleavehmode
+ \hbox
+ {\def\vulgarfraction{vulgarfraction}%
+ \ifcase\vulgarfractionmethod
+ #1\symbol[\vulgarfraction]#2%
+ \or
+ \high{\tx#1\kern-\hspaceamount\empty\vulgarfraction}%
+ \symbol[\vulgarfraction]%
+ \low {\kern-\hspaceamount\empty\vulgarfraction\tx#2}%
+ \or
+ \high{\tx#1}%
+ \hbox to \zeropoint{\hss\symbol[\vulgarfraction]\hss}%
+ \low{\tx#2}%
+ \or
+ \setbox0\hbox{\symbol[\vulgarfraction]}%
+ \setbox2\hbox{\txx57}%
+ \raise\ht0\hbox{\lower\ht2\hbox{\txx#1}}%
+ \hbox to \zeropoint{\hss\symbol[\vulgarfraction]\hss}%
+ \lower\dp0\hbox{\raise\dp2\hbox{\txx#2}}%
+ \fi}}
+
+\ifx\vfrac\undefined \let\vfrac\vulgarfraction \fi
+
+%D \starttabulate
+%D \HL
+%D \NC \bf method \NC \bf visualization \NC\NR
+%D \HL
+%D \NC 0 \NC \chardef\vulgarfractionmethod0\vulgarfraction{1}{2} \NC\NR
+%D \NC 1 \NC \chardef\vulgarfractionmethod1\vulgarfraction{1}{2} \NC\NR
+%D \NC 2 \NC \chardef\vulgarfractionmethod2\vulgarfraction{1}{2} \NC\NR
+%D \NC 3 \NC \chardef\vulgarfractionmethod3\vulgarfraction{1}{2} \NC\NR
+%D \HL
+%D \stoptabulate
+
+%D Under construction:
+%D
+%D \starttyping
+%D \commalistsentence[aap,noot,mies]
+%D \commalistsentence[aap,noot]
+%D \commalistsentence[aap]
+%D \commalistsentence[a,b,c]
+%D \commalistsentence[a,b,c][{ \& },{ and }]
+%D \commalistsentence[a,b,c][+,-]
+%D \stoptyping
+
+\let\handlecommalistsentence\firstofoneargument
+
+\def\commalistsentenceone{and-1}
+\def\commalistsentencetwo{and-2}
+
+\def\commalistsentence
+ {\dodoubleempty\docommalistsentence}
+
+\def\docommalistsentence[#1][#2]%
+ {\bgroup
+ \getfromcommalist[#2][1]%
+ \ifx\commalistelement\empty
+ \def\@@commalistsentenceone{\labeltext\commalistsentenceone}%
+ \else
+ \let\@@commalistsentenceone\commalistelement
+ \fi
+ \getfromcommalist[#2][2]%
+ \ifx\commalistelement\empty
+ \def\@@commalistsentencetwo{\labeltext\commalistsentencetwo}%
+ \else
+ \let\@@commalistsentencetwo\commalistelement
+ \fi
+ \getcommalistsize[#1]%
+ \ifcase\commalistsize\relax
+ \def\serializedcommalist{#1}%
+ \else
+ \let\serializedcommalist\empty
+ \scratchcounter\zerocount
+ \def\docommand##1%
+ {\advance\scratchcounter \plusone
+ \ifnum\scratchcounter=\plusone
+ \scratchtoks{\handlecommalistsentence{##1}}%
+ \else
+ \ifnum\scratchcounter=\commalistsize
+ \appendtoks\@@commalistsentencetwo\handlecommalistsentence{##1}\to\scratchtoks
+ \else
+ \appendtoks\@@commalistsentenceone\handlecommalistsentence{##1}\to\scratchtoks
+ \fi
+ \fi}%
+ \processcommacommand[#1]\docommand
+ \edef\serializedcommalist{\the\scratchtoks}%
+ \fi
+ \serializedcommalist
+ \egroup}
+
+\def\commacommandsentence[#1]{\@EA\commalistsentence\@EA[#1]}
+
+\ifx\textcomma\undefined \def\textcomma{,} \fi
+
+\setuplabeltext [\s!nl] [and-1=\textcomma\ , and-2= en ]
+\setuplabeltext [\s!en] [and-1=\textcomma\ , and-2=\textcomma\ and ]
+\setuplabeltext [\s!de] [and-1=\textcomma\ , and-2= und ]
+
+%D \macros
+%D {somekindoftab}
+%D
+%D This macro can be used to create tabs:
+%D
+%D \starttyping
+%D \setupheadertexts[{\somekindoftab[alternative=horizontal]{\framed{\realfolio}}}]
+%D \setuptexttexts [{\somekindoftab[alternative=vertical] {\framed{\realfolio}}}]
+%D
+%D \starttext
+%D \showframe \dorecurse{10}{test\page}
+%D \stoptext
+%D \stoptyping
+
+\def\somekindoftab
+ {\dosingleempty\dosomekindoftab}
+
+\def\dosomekindoftab[#1]%
+ {\bgroup
+ \getparameters[xx]
+ [\c!alternative=\v!vertical,
+ \c!width=\textwidth,\c!height=\textheight,
+ \c!n=\lastpage,\c!m=\realpageno,
+ #1]%
+ \doifelse\xxalternative\v!vertical
+ {\dodosomekindoftab\vbox\vskip\xxheight}
+ {\dodosomekindoftab\hbox\hskip\xxwidth }}
+
+\def\dodosomekindoftab#1#2#3#4%
+ {#1 to #3 \bgroup
+ \forgetall
+ \ifnum\xxm>\plusone
+ #2\zeropoint \!!plus \the\numexpr\xxm -1\relax fill\relax
+ \fi
+ #4%
+ \ifnum\xxm<\xxn\relax
+ #2\zeropoint \!!plus \the\numexpr\xxn-\xxm\relax fill\relax
+ \fi
+ \egroup
+ \egroup}
+
+\protect \endinput
diff --git a/tex/context/base/core-par.mkii b/tex/context/base/core-par.mkii
new file mode 100644
index 000000000..0b283b294
--- /dev/null
+++ b/tex/context/base/core-par.mkii
@@ -0,0 +1,300 @@
+%D \module
+%D [ file=core-par,
+%D version=1997.03.31,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Paragraph Tricks,
+%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 Core Macros / Pararaph Tricks}
+
+\unprotect
+
+% \ifprocesspreviousparagraphs
+%
+% \nofskippedparagraphs
+% \paragraphnumber
+% \nofparagraphs
+%
+% \dosetparagraph
+% \doresetparagraph
+% \dobeforeparagraph
+% \doafterparagraph
+% \dobeforeskipparagraph
+% \doafterskipparagraph
+%
+% \pushparagraphs\endcommand alle alineas tot \endcommand laden
+% \pushmoreparagraphs\endcommand alle alineas tot \endcommand toevoegen
+% \popparagraphs alle alineas oproepen
+% \popparagraphs[a,b,c] enkele alineas oproepen [geen]
+%
+% tzt een optionele prefix:
+%
+% \pushparagraphs[xxx]\endcommand alle alineas tot \endcommand laden
+% \popparagraphs[xxx] alle alineas oproepen
+% \popparagraphs[xxx][a,b,c] enkele alineas oproepen
+%
+% \numberparagraphs
+% \numberparagraphlines
+% \resetparagraphlines
+
+\newif\ifprocesspreviousparagraphs % public
+\newif\ifprocessallparagraphs % private
+
+\newcounter\totalnofparagraphs % private
+\newcounter\globalparagraphnumber % private
+\newcounter\discardedparagraphs % private
+\newcounter\mostrecentparagraphtotal % public
+
+\let\dosetparagraph = \relax % public
+\let\doresetparagraph = \relax % public
+\let\dobeforeparagraph = \relax % public
+\let\doafterparagraph = \relax % public
+\let\dobeforeskipparagraph = \relax % public
+\let\doafterskipparagraph = \relax % public
+
+\def\paragraphnumber {} % public
+\def\nofparagraphs {} % public
+\def\nofskippedparagraphs {} % public
+
+\def\paragraphprefix {paragraph} % private
+
+% voorlopig, wordt nog class
+
+\def\resetparagraphlines
+ {\global\linenumber\plusone}
+
+\def\numberparagraphs % instelbaar maken en slimmer ivm breedte regelnummer !!!!!
+ {\processpreviousparagraphstrue
+ \def\dosetparagraph
+ {\bgroup
+ \resetparagraphlines
+ \EveryPar
+ {\strut\inleftmargin{\tf{\tx\paragraphnumber}\kern2em}%
+ \ignorespaces}}%
+ \def\doresetparagraph
+ {\resetparagraphlines
+ \egroup}}
+
+\def\numberparagraphlines
+ {\processpreviousparagraphstrue
+ \def\dosetparagraph
+ {\resetparagraphlines}%
+ \def\doresetparagraph
+ {\resetparagraphlines}%
+ \def\dobeforeparagraph
+ {\startlinenumbering[\v!continue]}%
+ \def\doafterparagraph
+ {\stoplinenumbering}%
+ \def\dobeforeskipparagraph
+ {\stoplinenumbering
+ \let\paragraphnumber\relax}%
+ \def\doafterskipparagraph
+ {\startlinenumbering[\v!continue]}}
+
+\long\def\directpushparagraph#1%
+ {\doglobal\increment\totalnofparagraphs
+ \ifnum\totalnofparagraphs>0\nofskippedparagraphs\relax
+ \setgvalue{\paragraphprefix\totalnofparagraphs}{#1}%
+ \else
+ \setgvalue{\paragraphprefix\totalnofparagraphs}{\skipparagraph#1\par}%
+ \fi}
+
+\long\def\directskipparagraph#1%
+ {\doglobal\increment\totalnofparagraphs
+ \setgvalue{\paragraphprefix\totalnofparagraphs}{\skipparagraph#1\par}}
+
+\def\dopushparagraphs#1%
+ {\global\let\mostrecentparagraphtotal\totalnofparagraphs
+ \ifx#1\undefined
+ \let#1\relax
+ \fi
+ \defconvertedargument\asciia{#1}%
+ \defconvertedargument\asciib{ }% % lege regel
+ \def\dopushparagraph##1\par
+ {\defconvertedargument\asciic{##1}%
+ \doifelse\asciic\asciia
+ {#1}
+ {\doifsomething\asciic % lege paragraaf
+ {\doifnot\asciic\asciib
+ {\directpushparagraph{#1}}}%
+ \dopushparagraph}}%
+ \dopushparagraph}
+
+\def\pushparagraphs
+ {\doglobal\newcounter\totalnofparagraphs
+ \dopushparagraphs}
+
+\def\pushmoreparagraphs
+ {\dopushparagraphs}
+
+\def\dododopopparagraph#1% no grouping, i.v.m. sidefloats
+ {\ifnum#1>\totalnofparagraphs\relax
+ \else
+ \let\paragraphnumber\globalparagraphnumber
+ \decrement(\paragraphnumber,\discardedparagraphs)%
+ \dobeforeparagraph
+ \ifhmode\indentation\fi\getvalue{\paragraphprefix#1}\par
+ \doafterparagraph
+ \fi}
+
+\long\def\skipparagraph#1\par
+ {\doglobal\increment\discardedparagraphs
+ \ifprocessallparagraphs
+ \dobeforeskipparagraph
+ \ifhmode\indentation\fi#1\par
+ \doafterskipparagraph
+ \fi}
+
+\def\dodopopparagraph
+ {\dododopopparagraph}
+
+\def\dodoprocessparagraph#1%
+ {\ifprocesspreviousparagraphs
+ \bgroup
+ \setbox0\vbox{\dododopopparagraph{#1}}%
+ \egroup
+ \fi}
+
+\def\processpreviousparagraphs[#1]% process previous ones
+ {\ifprocesspreviousparagraphs
+ \bgroup
+ \getfromcommacommand[#1][1]% tzt snelle \..command.. testen
+ \let\totalnofparagraphs\commalistelement
+ \decrement\totalnofparagraphs
+ \let\dodopopparagraph\dodoprocessparagraph
+ \popparagraphs
+ \egroup
+ \fi}
+
+\def\dopopparagraphs[#1]%
+ {\doifnotinset{#1}{\v!none,0}
+ {\dosetparagraph
+ \doglobal\newcounter\globalparagraphnumber
+ \doglobal\newcounter\discardedparagraphs
+ \doifelse{#1}{}
+ {\processallparagraphstrue}
+ {\processallparagraphsfalse}%
+ \def\dopopparagraph
+ {\doglobal\increment\globalparagraphnumber
+ \ifnum\globalparagraphnumber>\totalnofparagraphs\relax
+ \let\dopopparagraph\relax
+ \else\ifprocessallparagraphs
+ \ifnum\globalparagraphnumber>\mostrecentparagraphtotal\relax
+ \dodopopparagraph\globalparagraphnumber
+ \else
+ \dodoprocessparagraph\globalparagraphnumber
+ \fi
+ \else
+ \let\paragraphnumber\globalparagraphnumber
+ \decrement(\paragraphnumber,\discardedparagraphs)%
+ \ExpandBothAfter\doifinsetelse{\paragraphnumber}{#1}
+ {\dodopopparagraph\globalparagraphnumber}
+ {\dodoprocessparagraph\globalparagraphnumber}%
+ \fi\fi
+ \dopopparagraph}%
+ \dopopparagraph
+ \doresetparagraph}}
+
+\def\popparagraphs
+ {\dosingleempty\dopopparagraphs}
+
+\def\countparagraphs
+ {\popparagraphs[\!!maxcard]%
+ \global\let\nofparagraphs\totalnofparagraphs
+ \doglobal\decrement(\nofparagraphs,\discardedparagraphs)}
+
+% \showframe
+%
+% \numberparagraphlines
+% \numberparagraphs
+%
+% \def\nofskippedparagraphs{1}
+%
+% \pushparagraphs\ThatsIt
+%
+% \ruledbaseline eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste
+%
+% \ruledbaseline eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste eerste eerste eerste
+% eerste eerste eerste eerste eerste
+%
+% \ruledbaseline tweede tweede tweede tweede tweede tweede
+% tweede tweede tweede tweede tweede tweede tweede tweede
+% tweede tweede tweede tweede tweede tweede tweede tweede
+% tweede tweede tweede tweede tweede tweede tweede tweede
+% tweede tweede tweede tweede tweede tweede tweede tweede
+% tweede tweede tweede tweede tweede tweede tweede tweede
+% tweede tweede tweede tweede tweede
+%
+% \skipparagraph \ruledbaseline skipped skipped skipped
+% skipped skipped skipped skipped skipped skipped skipped
+% skipped skipped skipped skipped skipped skipped skipped
+% skipped skipped
+%
+% \ruledbaseline derde derde derde derde derde derde derde
+% derde derde derde derde derde derde derde derde derde derde
+% derde derde derde derde derde derde derde derde derde derde
+% derde derde derde derde derde derde derde derde derde derde
+% derde derde derde derde derde derde derde derde derde derde
+% derde derde derde derde derde derde derde derde derde derde
+%
+% \skipparagraph \ruledbaseline skipped skipped skipped
+% skipped skipped skipped skipped skipped skipped skipped
+% skipped skipped skipped skipped skipped skipped skipped
+% skipped skipped skipped
+%
+% \ruledbaseline vierde vierde vierde vierde vierde vierde
+% vierde vierde vierde vierde vierde vierde vierde vierde
+% vierde vierde vierde vierde vierde vierde vierde vierde
+% vierde vierde vierde vierde
+%
+% \ruledbaseline vijfde vijfde vijfde vijfde vijfde vijfde
+% vijfde vijfde vijfde vijfde vijfde vijfde vijfde vijfde
+% vijfde vijfde vijfde vijfde vijfde vijfde vijfde vijfde
+% vijfde vijfde vijfde vijfde vijfde vijfde vijfde vijfde
+% vijfde vijfde vijfde
+%
+% \skipparagraph \ruledbaseline skipped skipped skipped
+% skipped skipped skipped skipped skipped skipped skipped
+% skipped skipped skipped skipped skipped skipped skipped
+% skipped skipped skipped
+%
+% \ThatsIt
+%
+% \popparagraphs
+%
+% \countparagraphs
+%
+% \blanko[2*groot]
+%
+% nofparagraphs:~\nofparagraphs
+%
+% \pagina
+%
+% \popparagraphs[1]
+% \popparagraphs[2]
+% \popparagraphs[3]
+% \popparagraphs[4]
+% \popparagraphs[5]
+%
+% \pagina
+%
+% \ruledvbox{\popparagraphs[1,2,3,4,5]}
+%
+% \pagina
+
+\protect \endinput
diff --git a/tex/context/base/core-stg.mkii b/tex/context/base/core-stg.mkii
new file mode 100644
index 000000000..429e1e894
--- /dev/null
+++ b/tex/context/base/core-stg.mkii
@@ -0,0 +1,72 @@
+%D \module
+%D [ file=core-stg,
+%D version=2006.08.16,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Strategies,
+%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.
+
+%D This is a prelude to strategies. It is rather old code
+%D used in a project many years ago. Use with care since I
+%D will pick up this thread. (moved from cont-new)
+
+\unprotect
+
+\def\s!strategy{strategy}
+
+\def\currentstrategypass {1}
+\def\currentstrategyvariable{0}
+\def\maximumstrategypass {8}
+
+\newconditional\strategypassneeded
+\newconditional\strategypassforced
+
+\definetwopasslist{\s!strategy}
+
+\def\registerstrategypass
+ {\ifnum\currentstrategypass>\maximumstrategypass \else
+ \ifconditional\strategypassforced
+ \doglobal\increment\currentstrategypass
+ \else%\ifconditional\strategypassneeded
+ %\doglobal\increment\currentstrategypass
+ \fi%\fi
+ \fi
+ \savecurrentvalue\currentstrategypass{\currentstrategypass}}
+
+\appendtoks \registerstrategypass \to \everybye % \everylastshipout
+
+\def\setstrategyvariable#1#2% key value
+ {%\doifnotstrategyvariable{#1}{\global\settrue\strategypassneeded}%
+ \doglobal\increment\currentstrategyvariable
+ \savetaggedtwopassdata{\s!strategy}{\currentstrategyvariable}{#1}{#2}}
+
+\def\doifstrategyvariableelse#1#2#3%
+ {\getstrategyvariable{#1}\iftwopassdatafound#2\else#3\fi}
+
+\def\getstrategyvariable#1% key
+ {\findtwopassdata{\s!strategy}{#1}%
+ \setxvalue{\s!strategy:#1}{\twopassdata}}
+
+\def\retainstrategyvariable#1% key
+ {\expanded{\setstrategyvariable{#1}{\strategyvariable{#1}}}}
+
+\def\strategyvariable#1% key
+ {\csname\s!strategy:#1\endcsname}
+
+\let\stratvar\strategyvariable
+
+\def\forcestrategy{\global\settrue \strategypassforced}
+\def\abortstrategy{\global\setfalse\strategypassforced}
+
+\def\doifstrategyvariableelse#1#2#3%
+ {\getstrategyvariable{#1}\iftwopassdatafound#2\else#3\fi}
+
+\def\doifstrategyvariable #1#2{\doifstrategyvariableelse{#1}{#2}{}}
+\def\doifnotstrategyvariable#1#2{\doifstrategyvariableelse{#1}{}{#2}}
+
+\protect \endinput
diff --git a/tex/context/base/core-sys.lua b/tex/context/base/core-sys.lua
new file mode 100644
index 000000000..c5aa89d98
--- /dev/null
+++ b/tex/context/base/core-sys.lua
@@ -0,0 +1,22 @@
+if not modules then modules = { } end modules ['core-sys'] = {
+ version = 1.001,
+ comment = "companion to core-sys.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local lower, extname, basename, removesuffix = string.lower, file.extname, file.basename, file.removesuffix
+
+function commands.updatefilenames(inputfilename,outputfilename)
+ environment.inputfilename = inputfilename or ""
+ environment.outputfilename = outputfilename or ""
+ environment.jobfilename = inputfilename or tex.jobname or ""
+ environment.jobfilesuffix = lower(extname(environment.jobfilename))
+ environment.inputfilebarename = removesuffix(basename(inputfilename))
+ environment.inputfilesuffix = lower(extname(inputfilename))
+end
+
+statistics.register("result saved in file", function()
+ return string.format( "%s.%s", environment.outputfilename, (tex.pdfoutput>0 and "pdf") or "dvi")
+end)
diff --git a/tex/context/base/core-sys.mkii b/tex/context/base/core-sys.mkii
new file mode 100644
index 000000000..24975ffb6
--- /dev/null
+++ b/tex/context/base/core-sys.mkii
@@ -0,0 +1,396 @@
+%D \module
+%D [ file=core-sys, % moved from main-001
+%D version=1997.03.31,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=System,
+%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 Core Macros / System}
+
+\unprotect
+
+%D Version checking:
+
+\def\newcontextversion#1%
+ {\doifelse{#1}\contextversion
+ {\let\newcontextversion\gobbleoneargument}
+ {\writeline
+ \writestatus{Fatal Error}{Your format does not match the base files!}%
+ \writeline
+ \writestatus{Format Version}{\contextversion\space\contextmark}%
+ \writestatus{Files Version}{#1}%
+ \batchmode
+ \normalend}}
+
+%D End of lines to the output. \TEX\ will map this onto the platform specific
+%D line ending. I hate this mess.
+
+%newlinechar=10 \def\outputnewlinechar{\rawcharacter{10}}
+\newlinechar=10 \edef\outputnewlinechar{^^J}
+
+% in case formats are shared:
+
+\def\initializenewlinechar
+ {\bgroup\newlinechar=10\xdef\outputnewlinechar{^^J}\egroup}
+
+%D Job names.
+
+\def\outputfilename {\@@svfile}
+\def\inputfilename {\@@svinputfile}
+\def\operatingsystem{\@@svtype}
+
+\let\jobfilename \jobname
+\let\jobfilesuffix\c!tex
+
+\def\splitjobfilename % todo: mkiv
+ {\resetsystemmode{suffix-\jobfilesuffix}%
+ \edef\ascii{\inputfilename}\defconvertedcommand\ascii\ascii
+ \splitstring\ascii\at.\to\jobfilename\and\jobfilesuffix
+ \lowercasestring\jobfilesuffix\to\jobfilesuffix
+ \doifnothing\jobfilename {\let\jobfilename \jobname}%
+ % todo and totest: \defconvertedcommand\jobfilename\jobfilename
+ \doifnothing\jobfilesuffix{\let\jobfilesuffix\c!tex}%
+ \setsystemmode{suffix-\jobfilesuffix}}
+
+% Some mechanisms (see x-res-01) use either \jobfilename or
+% \jobfilename.somesuffix, in which case we need to use the
+% full name if given or a default (like \jobfilename.xml);
+% this comes down to replacing the default tex suffix.
+
+\def\jobfullname{\jobfilename.\jobfilesuffix}
+
+\def\setjobfullname#1% #1 = default if not given
+ {\doifelsenothing\jobfilename
+ {\let\jobfullname\empty}
+ {\doif\jobfilesuffix\c!tex{\edef\jobfullname{\jobfilename.#1}}}}
+
+% ...
+
+\def\dosetupsystem[#1]%
+ {\getparameters[\??sv][#1]%
+ \setuprandomize[\@@svrandom]%
+ \beforesplitstring\@@svresolution\at dpi\to\@@svresolution
+ \let\outputresolution\@@svresolution
+ \ifcase\@@svn
+ % % 0 : unknown
+ \or
+ \setsystemmode\v!first % 1 : first run
+ \or
+ % % 2 : successive run
+ \or
+ \setsystemmode\v!first % 3 : first and only run
+ \or
+ \setsystemmode\v!last % 4 : (extra) last run
+ \fi
+% \processaction
+% [\@@svtype]
+% %[ mswin=>\edef\@@svline{\rawcharacter{13}\rawcharacter{10}}, % crlf
+% [ mswin=>\edef\@@svline{\rawcharacter{13}}, % cr % crlf
+% darwin=>\edef\@@svline{\rawcharacter{13}}, % cr
+% \s!unknown=>\edef\@@svline{\rawcharacter{10}}]% % lf
+ \splitjobfilename}
+
+% \edef\@@svline{\rawcharacter{10}} % unix is the most critical/sensitive system
+
+\let\systemendofline\outputnewlinechar % will become obsolete
+
+\def\setupsystem
+ {\dosingleargument\dosetupsystem}
+
+\def\systemparameter#1{\executeifdefined{\??sv#1}\empty}
+
+%D The system modes set by the setup command can be used in
+%D situations like:
+%D
+%D \starttyping
+%D \startmode[*first]
+%D \executesystemcommand{cleanupxml text.xml clean-text.xml}
+%D \stopmode
+%D
+%D \starttext
+%D \typefile{clean-text.xml}
+%D \stoptext
+%D \stoptyping
+
+\def\setuprandomize[#1]%
+ {\doifsomething{#1}
+ {\bgroup
+ % tex's time is in minutes
+ \scratchcounter\normaltime
+ \processaction
+ [#1]
+ [ \v!small=>\divide\scratchcounter 15, % 900,
+ \v!medium=>\divide\scratchcounter 30, % 1800,
+ \v!big=>\divide\scratchcounter 60, % 3600,
+ \v!normal=>\getnewrandomseed\scratchcounter,
+ \s!default=>\getnewrandomseed\scratchcounter,
+ \s!unknown=>\scratchcounter#1]%
+ \expanded{\setrandomseed{\the\scratchcounter}}%
+% \writestatus\m!systems{randomseed: \the\scratchcounter}%
+ \egroup}}
+
+
+\setupsystem
+ [\c!directory=,
+ \c!n=0, % 0:unknown 1: one run 2: first 3: successive 4: final run
+ \c!resolution=600dpi,
+ \c!random=,
+ \c!file=\jobname,
+ \c!inputfile=\outputfilename,
+ \c!type=unix, % windows is normally less sensitive to handle
+ \c!bodyfont=\normalizedlocalbodyfontsize] % of iets anders
+
+%D Remark: windows programs normally handle \type {cr|lf|crlf} but unix
+%D is more picky, so we default to the \type {cr}. I never understood why
+%D \type {crlf} was not used in all systems, since it makes most sense.
+
+\def\dostartglobaldefs#1#2%
+ {\edef\!!stringa{\the\globaldefs}%
+ \ifnum\globaldefs#10
+ \globaldefs-\globaldefs
+ \fi
+ \advance\globaldefs #21
+ \setevalue{@gd@\the\globaldefs}{\!!stringa}}
+
+\def\dostopglobaldefs
+ {\doifdefinedelse{@gd@\the\globaldefs}
+ {\globaldefs\getvalue{@gd@\the\globaldefs}\relax}
+ {\globaldefs\zerocount}}
+
+\def\startlocal {\dostartglobaldefs>-}
+\def\stoplocal {\dostopglobaldefs}
+\def\startglobal {\dostartglobaldefs<+}
+\def\stopglobal {\dostopglobaldefs}
+
+\def\complexstart[#1]{\bgroup\getvalue{\e!start#1}}
+\def\complexstop [#1]{\getvalue{\e!stop #1}\egroup}
+
+\let\simplestart\bgroup
+\let\simplestop \egroup
+
+\definecomplexorsimple\start
+\definecomplexorsimple\stop
+
+\def\dododefinestartstop[#1][#2]% todo: use indirect commands
+ {\getparameters
+ [\??be#1]
+ [\c!before=,
+ \c!after=,
+ \c!inbetween=,
+ \c!commands=,
+ \c!style=,
+ #2]%
+ \unexpanded\setvalue{#1}%
+ {\groupedcommand
+ {\getvalue{\??be#1\c!commands}%
+ \dostartattributes{\??be#1}\c!style\c!color}
+ {\dostopattributes
+ \getvalue{\??be#1\c!inbetween}}}%
+ \setvalue{\e!start#1}%
+ {\getvalue{\??be#1\c!before}%
+ \bgroup
+ \getvalue{\??be#1\c!commands}%
+ \dostartattributes{\??be#1}\c!style\c!color\empty}%
+ \setvalue{\e!stop#1}%
+ {\dostopattributes
+ \egroup
+ \getvalue{\??be#1\c!after}}}
+
+\def\dodefinestartstop[#1][#2]%
+ {\def\docommand##1{\dododefinestartstop[##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\def\definestartstop
+ {\dodoubleargument\dodefinestartstop}
+
+\def\dosetupstartstop[#1][#2]%
+ {\def\docommand##1{\getparameters[\??be##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\def\setupstartstop
+ {\dodoubleargument\dosetupstartstop}
+
+% \docommand kan niet worden gebruikt omdat deze macro
+% soms lokaal wordt gebruikt
+
+% te zijner tijd:
+%
+% \definevariable {pc} % ProtectedCommand
+%
+% \def\executeprotected#1%
+% {\csname\??pc\string#1\endcsname}
+%
+% \def\defineprotected#1#2%
+% {\expandafter\def\csname\??pc\string#2\endcsname}
+%
+% \def\defineunprotected#1%
+% {\def#1}
+%
+% \def\doprotected%
+% {\ifx\next\define
+% \let\next=\defineprotected
+% \else
+% \let\next=\executeprotected
+% \fi
+% \next}
+%
+% \def\unexpanded%
+% {\futurelet\next\doprotected}
+%
+% \unexpanded\define\ziezo{ziezo}
+%
+% \unexpanded\ziezo
+
+\def\complexdefine[#1]#2#3%
+ {\ifx#2\undefined
+ \else
+ \showmessage\m!systems4{\string#2}%
+ \fi
+ \ifcase0#1\def#2{#3}%
+ \or\def#2##1{#3}%
+ \or\def#2##1##2{#3}%
+ \or\def#2##1##2##3{#3}%
+ \or\def#2##1##2##3##4{#3}%
+ \or\def#2##1##2##3##4##5{#3}%
+ \or\def#2##1##2##3##4##5##6{#3}%
+ \or\def#2##1##2##3##4##5##6##7{#3}%
+ \or\def#2##1##2##3##4##5##6##7##8{#3}%
+ \or\def#2##1##2##3##4##5##6##7##8##9{#3}%
+ \else\def#2{#3}%
+ \fi}
+
+\definecomplexorsimpleempty\define
+
+\unexpanded\def\macroname#1% brrr
+ {\executeifdefined{#1}\empty}
+
+\def\usecommands#1%
+ {\bgroup
+ \def\docommand##1{\setbox0\hbox{\getvalue{\string##1}##1}}%
+ \processcommalist[#1]\docommand
+ \egroup}
+
+\newif\ifforcefileexpansion % handy for document level overload
+
+%D The next implementation is about 4 times as faster than a
+%D processaction alternative on an string of average length.
+%D Since this feature is used in XML processing, it made sense
+%D to support this faster alternative. It's installable as well.
+
+\def\installexpander#1#2#3% changed, no longer \convert..\to...
+ {\setvalue{\s!do\c!expansion#1l}{#2}%
+ \setvalue{\s!do\c!expansion#1g}{#3}}%
+
+% \convertexpanded is obsolete
+
+\long\def\doconvertexpanded#1#2#3% #4 % [l|g] \cs {kind} {data}
+ {\csname % that we assign all exp a value
+ \s!do\c!expansion
+ \ifforcefileexpansion
+ \v!yes
+ \else\ifcsname\s!do\c!expansion#3#1\endcsname
+ #3%
+ \else
+ \s!default
+ \fi\fi
+ #1%
+ \endcsname#2}% #3
+
+\long\def\defconvertexpanded {\doconvertexpanded l}
+\long\def\gdefconvertexpanded{\doconvertexpanded g}
+
+\installexpander\v!command \defconvertedcommand \gdefconvertedcommand
+\installexpander\s!default \defconvertedargument \gdefconvertedargument
+\installexpander\empty \defconvertedargument \gdefconvertedargument
+\installexpander\v!no \defconvertedargument \gdefconvertedargument
+\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
+\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
+\installexpander\v!strict \defreducedargument \gdefreducedargument
+\installexpander {utf} \defreducedtoutf \gdefreducedtoutf
+
+%installexpander {xml} {see xtag-ext}
+
+\def\dodefconvertedmeaning#1#2#3% watch the double expansion !
+ {\bgroup
+ \honorunexpanded
+ \convertencodedtokens % can be overloaded
+ \xdef\@@globalexpanded{#3}%
+ \xdef\@@globalexpanded{\@@globalexpanded}%
+ \egroup
+ #1#2\@@globalexpanded}
+
+\def\defconvertedmeaning {\dodefconvertedmeaning\defconvertedcommand}
+\def\gdefconvertedmeaning{\dodefconvertedmeaning\gdefconvertedcommand}
+
+\def\dodefreducedargument#1#2#3%
+ {\begingroup
+ \reducetocoding[raw]%
+ \edef\ascii{#3}%
+ \expandafter\endgroup\expandafter#1\expandafter#2\expandafter{\ascii}}
+
+\def\defreducedargument {\dodefreducedargument\edef}
+\def\gdefreducedargument{\dodefreducedargument\xdef}
+
+% \setupindex[expansion=utf]\index{\eacute}
+
+\def\dodefreducedtoutf#1#2#3%
+ {\begingroup
+ \reducetocoding[uc]%
+ \let\uchar\uchartoutf
+ \let\unicodechar\numbertoutf
+ \edef\ascii{#3}%
+ \expandafter\endgroup\expandafter#1\expandafter#2\expandafter{\ascii}}
+
+\def\defreducedtoutf {\dodefreducedtoutf\edef}
+\def\gdefreducedtoutf{\dodefreducedtoutf\xdef}
+
+% old syntax:
+
+\def\convertmeaning#1\to#2% watch the double expansion !
+ {\bgroup
+ \honorunexpanded
+ \convertencodedtokens % can be overloaded
+ \xdef\@@globalexpanded{#1}%
+ \xdef\@@globalexpanded{\@@globalexpanded}%
+ \egroup
+ \defconvertedcommand#2\@@globalexpanded}
+
+\def\reduceargument#1\to#2%
+ {\begingroup
+ \reducetocoding[raw]%
+ \edef\ascii{#1}%
+ \expandafter\endgroup\expandafter\edef\expandafter#2\expandafter{\ascii}}
+
+\def\reducetoutf#1\to#2%
+ {\begingroup
+ \reducetocoding[uc]%
+ \let\uchar\uchartoutf
+ \let\unicodechar\numbertoutf
+ \edef\ascii{#1}%
+ \expandafter\endgroup\expandafter\edef\expandafter#2\expandafter{\ascii}}
+
+% \setvalue{statevalue\v!stop }{0}
+% \setvalue{statevalue\v!start }{1}
+% \setvalue{statevalue\v!normaal}{2}
+% \setvalue{statevalue\v!leeg }{3}
+% \setvalue{statevalue\v!geen }{4}
+%
+% \def\setcurrentstate#1%
+% {\chardef\currentstate=0\getvalue{statevalue\getvalue{#1\c!state}\relax}
+%
+% \ifcase\currentstate ...
+
+\def\redo{\dorepeat} % [n*10], kind of obsolete
+
+% obsolete, use \dorecurse instead
+%
+% \def\herhaler {\repeater}
+% \def\herhaalmetcommando {\dorepeatwithcommand}
+
+\protect \endinput
diff --git a/tex/context/base/core-sys.mkiv b/tex/context/base/core-sys.mkiv
new file mode 100644
index 000000000..649e5e65c
--- /dev/null
+++ b/tex/context/base/core-sys.mkiv
@@ -0,0 +1,432 @@
+%D \module
+%D [ file=core-sys, % moved from main-001
+%D version=1997.03.31,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=System,
+%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.
+
+% we need to mkiv-ize this file !
+
+\writestatus{loading}{ConTeXt Core Macros / System}
+
+\registerctxluafile{core-sys}{1.001}
+
+\unprotect
+
+%D Version checking:
+
+\def\newcontextversion#1%
+ {\doifelse{#1}\contextversion
+ {\let\newcontextversion\gobbleoneargument}
+ {\writeline
+ \writestatus{Fatal Error}{Your format does not match the base files!}%
+ \writeline
+ \writestatus{Format Version}{\contextversion\space\contextmark}%
+ \writestatus{Files Version}{#1}%
+ \batchmode
+ \normalend}}
+
+%D End of lines to the output. \TEX\ will map this onto the platform specific
+%D line ending. I hate this mess.
+
+%newlinechar=10 \def\outputnewlinechar{\rawcharacter{10}}
+\newlinechar=10 \edef\outputnewlinechar{^^J}
+
+\edef\operatingsystem {\ctxlua{tex.write(os.platform)}}
+
+\def\jobfilename {\ctxlua{tex.sprint(tex.texcatcodes,environment.jobfilename or "")}}
+\def\jobfilesuffix {\ctxlua{tex.sprint(tex.texcatcodes,environment.jobfilesuffix or "")}}
+\def\inputfilebarename{\ctxlua{tex.sprint(tex.texcatcodes,environment.inputfilebarename or "")}}
+\def\inputfilesuffix {\ctxlua{tex.sprint(tex.texcatcodes,environment.inputfilesuffix or "")}}
+\def\inputfilename {\ctxlua{tex.sprint(tex.texcatcodes,environment.inputfilename or "")}}
+\def\outputfilename {\ctxlua{tex.sprint(tex.texcatcodes,environment.outputfilename or "")}}
+
+\def\initializenewlinechar
+ {\bgroup\newlinechar=10\xdef\outputnewlinechar{^^J}\egroup}
+
+\newtoks \everysetupsystem
+
+\unexpanded\def\setupsystem
+ {\dosingleargument\dosetupsystem}
+
+\def\dosetupsystem[#1]%
+ {\getparameters[\??sv][#1]%
+ \the\everysetupsystem}
+
+\appendtoks
+ \edef\outputresolution{\@@svresolution}%
+\to \everysetupsystem
+
+\appendtoks
+ \ifcase\@@svn
+ % % 0 : unknown
+ \or
+ \setsystemmode\v!first % 1 : first run
+ \or
+ % % 2 : successive run
+ \or
+ \setsystemmode\v!first % 3 : first and only run
+ \or
+ \setsystemmode\v!last % 4 : (extra) last run
+ \fi
+\to \everysetupsystem
+
+\appendtoks
+ \edef\outputfilename{\@@svfile}%
+ \edef\inputfilename {\@@svinputfile}%
+\to \everysetupsystem
+
+\let\@@jobsuffix\s!unknown
+
+\appendtoks
+ \resetsystemmode{suffix-\@@jobsuffix}%
+ \edef\@@jobsuffix{\jobsuffix}%
+ \setsystemmode{suffix-\@@jobsuffix}%
+\to \everysetupsystem
+
+\appendtoks
+ \ctxlua {commands.updatefilenames("\inputfilename","\outputfilename")}%
+\to \everysetupsystem
+
+% Some mechanisms (see x-res-01) use either \jobfilename or
+% \jobfilename.somesuffix, in which case we need to use the
+% full name if given or a default (like \jobfilename.xml);
+% this comes down to replacing the default tex suffix.
+
+\def\jobfullname{\jobfilename.\jobfilesuffix}
+
+\def\setjobfullname#1% #1 = default if not given
+ {\doifelsenothing\jobfilename
+ {\let\jobfullname\empty}
+ {\doif\jobfilesuffix\c!tex{\edef\jobfullname{\jobfilename.#1}}}}
+
+\let\systemendofline\outputnewlinechar % will become obsolete
+
+\def\systemparameter#1{\executeifdefined{\??sv#1}\empty}
+
+%D There are a couple of system states avaiable:
+%D
+%D \starttabulate [|T|T|]
+%D \NC \type{\jobname} \NC \jobname \NC \NR
+%D \NC \type{\jobfilename} \NC \jobfilename \NC \NR
+%D \NC \type{\jobfilesuffix} \NC \jobfilesuffix \NC \NR
+%D \NC \type{\inputfilename} \NC \inputfilename \NC \NR
+%D \NC \type{\inputfilebarename} \NC \inputfilebarename \NC \NR
+%D \NC \type{\inputfilesuffix} \NC \inputfilesuffix \NC \NR
+%D \NC \type{\outputfilename} \NC \outputfilename \NC \NR
+%D \NC \type{\operatingsystem} \NC \operatingsystem \NC \NR
+%D \stoptabulate
+
+%D The system modes set by the setup command can be used in
+%D situations like:
+%D
+%D \starttyping
+%D \startmode[*first]
+%D \executesystemcommand{cleanupxml text.xml clean-text.xml}
+%D \stopmode
+%D
+%D \starttext
+%D \typefile{clean-text.xml}
+%D \stoptext
+%D \stoptyping
+
+\unexpanded\def\setuprandomize[#1]%
+ {\doifsomething{#1}
+ {\bgroup
+ % tex's time is in minutes
+ \scratchcounter\normaltime
+ \processaction
+ [#1]
+ [ \v!small=>\divide\scratchcounter 15, % 900,
+ \v!medium=>\divide\scratchcounter 30, % 1800,
+ \v!big=>\divide\scratchcounter 60, % 3600,
+ \v!normal=>\getnewrandomseed\scratchcounter,
+ \s!default=>\getnewrandomseed\scratchcounter,
+ \s!unknown=>\scratchcounter#1]%
+ \expanded{\setrandomseed{\the\scratchcounter}}%
+ % \writestatus\m!systems{randomseed: \the\scratchcounter}%
+ \egroup}}
+
+\setupsystem
+ [\c!directory=,
+ \c!n=0, % 0:unknown 1: one run 2: first 3: successive 4: final run
+ \c!resolution=600,% in dpi, no unit in mkiv
+ %c!random=, % obsolete here
+ \c!file=\jobname,
+ \c!inputfile=\outputfilename,
+ \c!type=unix, % windows is normally less sensitive to handle
+ \c!bodyfont=\normalizedlocalbodyfontsize] % of iets anders
+
+%D Remark: windows programs normally handle \type {cr|lf|crlf} but unix
+%D is more picky, so we default to the \type {cr}. I never understood why
+%D \type {crlf} was not used in all systems, since it makes most sense.
+
+\def\dostartglobaldefs#1#2%
+ {\edef\!!stringa{\the\globaldefs}%
+ \ifnum\globaldefs#10
+ \globaldefs-\globaldefs
+ \fi
+ \advance\globaldefs #21
+ \setevalue{@gd@\the\globaldefs}{\!!stringa}}
+
+\def\dostopglobaldefs
+ {\doifdefinedelse{@gd@\the\globaldefs}
+ {\globaldefs\getvalue{@gd@\the\globaldefs}\relax}
+ {\globaldefs\zerocount}}
+
+\unexpanded\def\startlocal {\dostartglobaldefs>-}
+\unexpanded\def\stoplocal {\dostopglobaldefs}
+\unexpanded\def\startglobal {\dostartglobaldefs<+}
+\unexpanded\def\stopglobal {\dostopglobaldefs}
+
+\def\complexstart[#1]{\bgroup\getvalue{\e!start#1}}
+\def\complexstop [#1]{\getvalue{\e!stop #1}\egroup}
+
+\let\simplestart\bgroup
+\let\simplestop \egroup
+
+\definecomplexorsimple\start
+\definecomplexorsimple\stop
+
+\def\dododefinestartstop[#1][#2]% todo: use indirect commands
+ {\getparameters
+ [\??be#1]
+ [\c!before=,
+ \c!after=,
+ \c!inbetween=,
+ \c!commands=,
+ \c!style=,
+ #2]%
+ \setuvalue{#1}%
+ {\groupedcommand
+ {\getvalue{\??be#1\c!commands}%
+ \dostartattributes{\??be#1}\c!style\c!color}
+ {\dostopattributes
+ \getvalue{\??be#1\c!inbetween}}}%
+ \setvalue{\e!start#1}%
+ {\getvalue{\??be#1\c!before}%
+ \bgroup
+ \getvalue{\??be#1\c!commands}%
+ \dostartattributes{\??be#1}\c!style\c!color\empty}%
+ \setvalue{\e!stop#1}%
+ {\dostopattributes
+ \egroup
+ \getvalue{\??be#1\c!after}}}
+
+\def\dodefinestartstop[#1][#2]%
+ {\def\docommand##1{\dododefinestartstop[##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\unexpanded\def\definestartstop
+ {\dodoubleargument\dodefinestartstop}
+
+\def\dosetupstartstop[#1][#2]%
+ {\def\docommand##1{\getparameters[\??be##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\unexpanded\def\setupstartstop
+ {\dodoubleargument\dosetupstartstop}
+
+% \docommand kan niet worden gebruikt omdat deze macro
+% soms lokaal wordt gebruikt
+
+% te zijner tijd:
+%
+% \definevariable {pc} % ProtectedCommand
+%
+% \def\executeprotected#1%
+% {\csname\??pc\string#1\endcsname}
+%
+% \unexpanded\def\defineprotected#1#2%
+% {\expandafter\def\csname\??pc\string#2\endcsname}
+%
+% \unexpanded\def\defineunprotected#1%
+% {\def#1}
+%
+% \def\doprotected%
+% {\ifx\next\define
+% \let\next=\defineprotected
+% \else
+% \let\next=\executeprotected
+% \fi
+% \next}
+%
+% \def\unexpanded%
+% {\futurelet\next\doprotected}
+%
+% \unexpanded\define\ziezo{ziezo}
+%
+% \unexpanded\ziezo
+
+\def\complexdefine[#1]#2#3%
+ {\ifx#2\undefined
+ \else
+ \showmessage\m!systems4{\string#2}%
+ \fi
+ \ifcase0#1\def#2{#3}%
+ \or\def#2##1{#3}%
+ \or\def#2##1##2{#3}%
+ \or\def#2##1##2##3{#3}%
+ \or\def#2##1##2##3##4{#3}%
+ \or\def#2##1##2##3##4##5{#3}%
+ \or\def#2##1##2##3##4##5##6{#3}%
+ \or\def#2##1##2##3##4##5##6##7{#3}%
+ \or\def#2##1##2##3##4##5##6##7##8{#3}%
+ \or\def#2##1##2##3##4##5##6##7##8##9{#3}%
+ \else\def#2{#3}%
+ \fi}
+
+\definecomplexorsimpleempty\define
+
+% \startluacode
+% local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+% local format, match, gmatch, rep = string.format, string.match, string.gmatch, string.rep
+% local empty = {
+% "single",
+% "double",
+% "triple",
+% "quadruple",
+% "quintuple",
+% }
+% local check = {
+% "first",
+% "second",
+% "third",
+% "fourth",
+% "fifth",
+% }
+% function commands.define(str)
+% -- we could store the defaults in lua and call lua instead but why bother
+% local arg, cmd = match(str,"(.*)\\(.-)$")
+% local a = { }
+% for s in gmatch(arg,"%[(.-)%]") do
+% a[#a+1] = s
+% end
+% local n = tonumber(a[#a])
+% if n then
+% a[#a] = nil
+% else
+% n = 0
+% end
+% texsprint(ctxcatcodes,format("\\unexpanded\\def\\%s",cmd))
+% if #a > 0 then
+% texsprint(ctxcatcodes,format("{\\do%sempty\\do%s}",empty[#a],cmd))
+% texsprint(ctxcatcodes,format("\\def\\do%s",cmd))
+% for i=1,#a do
+% texsprint(ctxcatcodes,"[#",i,"]")
+% end
+% texsprint(ctxcatcodes,"{")
+% for i=#a,1,-1 do
+% texsprint(ctxcatcodes,format("\\if%sargument",check[i]))
+% texsprint(ctxcatcodes,format("\\def\\next{\\dodo%s",cmd))
+% for j=1,#a-i do
+% texsprint(ctxcatcodes,format("[%s]",a[j]))
+% end
+% for j=1,i do
+% texsprint(ctxcatcodes,format("[#%s]",j))
+% end
+% texsprint(ctxcatcodes,"}")
+% if i == 1 then
+% texsprint(ctxcatcodes,rep("\\fi",#a))
+% else
+% texsprint(ctxcatcodes,"\\else")
+% end
+% end
+% texsprint(ctxcatcodes,"\\next}")
+% texsprint(ctxcatcodes,format("\\def\\dodo%s",cmd))
+% for i=1,#a do
+% texsprint(ctxcatcodes,"[#",i,"]")
+% end
+% end
+% for i=1,n do
+% texsprint(ctxcatcodes,"#",#a+i)
+% end
+% end
+% \stopluacode
+%
+% \unexpanded\def\define#1#{\ctxlua{commands.define([[\detokenize{#1}]])}}
+%
+% \starttext
+% \define[2]\whatevera{#1+#2}
+% \whatevera{A}{B}
+% \define[me][too][2]\whateverb{#1+#2+#3+#4}
+% \whateverb[A]{B}{C}
+% \whateverb[A][B]{C}{D}
+% \stoptext
+
+\unexpanded\def\macroname#1% brrr
+ {\executeifdefined{#1}\empty}
+
+\def\usecommands#1%
+ {\bgroup
+ \def\docommand##1{\setbox0\hbox{\getvalue{\string##1}##1}}%
+ \processcommalist[#1]\docommand
+ \egroup}
+
+\newif\ifforcefileexpansion % handy for document level overload
+
+%D The next implementation is about 4 times as faster than a
+%D processaction alternative on an string of average length.
+%D Since this feature is used in XML processing, it made sense
+%D to support this faster alternative. It's installable as well.
+%D
+%D We keep this around for \MKII\ \XML\ but it's not used in \MKIV\
+%D code as expansion is controlled in another way there.
+
+\def\installexpander#1#2#3% changed, no longer \convert..\to...
+ {\setvalue{\s!do\c!expansion#1l}{#2}%
+ \setvalue{\s!do\c!expansion#1g}{#3}}%
+
+% \convertexpanded is obsolete
+
+\long\def\doconvertexpanded#1#2#3% #4 % [l|g] \cs {kind} {data}
+ {\csname % that we assign all exp a value
+ \s!do\c!expansion
+ \ifforcefileexpansion
+ \v!yes
+ \else\ifcsname\s!do\c!expansion#3#1\endcsname
+ #3%
+ \else
+ \s!default
+ \fi\fi
+ #1%
+ \endcsname#2}% #3
+
+\long\def\defconvertexpanded {\doconvertexpanded l}
+\long\def\gdefconvertexpanded{\doconvertexpanded g}
+
+\installexpander\v!command \defconvertedcommand \gdefconvertedcommand
+\installexpander\s!default \defconvertedargument \gdefconvertedargument
+\installexpander\empty \defconvertedargument \gdefconvertedargument
+\installexpander\v!no \defconvertedargument \gdefconvertedargument
+\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
+\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
+\installexpander\v!strict \defreducedargument \gdefreducedargument
+\installexpander {utf} \defreducedtoutf \gdefreducedtoutf
+
+\def\dodefconvertedmeaning#1#2#3% watch the double expansion !
+ {\bgroup
+ \xdef\@@globalexpanded{#3}%
+ \xdef\@@globalexpanded{\@@globalexpanded}%
+ \egroup
+ #1#2\@@globalexpanded}
+
+\def\defconvertedmeaning {\dodefconvertedmeaning\defconvertedcommand}
+\def\gdefconvertedmeaning{\dodefconvertedmeaning\gdefconvertedcommand}
+
+\def\dodefreducedargument#1#2#3%
+ {\begingroup
+ \reducetocoding[raw]%
+ \edef\ascii{#3}%
+ \expandafter\endgroup\expandafter#1\expandafter#2\expandafter{\ascii}}
+
+\def\defreducedargument {\dodefreducedargument\edef}
+\def\gdefreducedargument{\dodefreducedargument\xdef}
+
+\protect \endinput
diff --git a/tex/context/base/core-two.lua b/tex/context/base/core-two.lua
new file mode 100644
index 000000000..24a3191a7
--- /dev/null
+++ b/tex/context/base/core-two.lua
@@ -0,0 +1,137 @@
+if not modules then modules = { } end modules ['core-two'] = {
+ version = 1.001,
+ comment = "companion to core-two.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local remove, concat = table.remove, table.concat
+
+local texprint = tex.print
+
+--[[ldx--
+
We save multi-pass information in the main utility table. This is a
+bit of a mess because we support old and new methods.
+--ldx]]--
+
+jobpasses = jobpasses or { }
+jobpasses.collected = jobpasses.collected or { }
+jobpasses.tobesaved = jobpasses.tobesaved or { }
+
+local collected, tobesaved = jobpasses.collected, jobpasses.tobesaved
+
+local function initializer()
+ collected, tobesaved = jobpasses.collected, jobpasses.tobesaved
+end
+
+job.register('jobpasses.collected', jobpasses.tobesaved, initializer, nil)
+
+local function allocate(id)
+ local p = tobesaved[id]
+ if not p then
+ p = { }
+ tobesaved[id] = p
+ end
+ return p
+end
+
+jobpasses.define = allocate
+
+function jobpasses.save(id,str)
+ local jti = allocate(id)
+ jti[#jti+1] = str
+end
+
+function jobpasses.savetagged(id,tag,str)
+ local jti = allocate(id)
+ jti[tag] = str
+end
+
+function jobpasses.getcollected(id)
+ return collected[id] or { }
+end
+
+function jobpasses.gettobesaved(id)
+ return allocate(id)
+end
+
+function jobpasses.get(id)
+ local jti = collected[id]
+ if jti and #jti > 0 then
+ texprint(remove(jti,1))
+ end
+end
+
+function jobpasses.first(id)
+ local jti = collected[id]
+ if jti and #jti > 0 then
+ texprint(jti[1])
+ end
+end
+
+function jobpasses.last(id)
+ local jti = collected[id]
+ if jti and #jti > 0 then
+ texprint(jti[#jti])
+ end
+end
+
+jobpasses.check = jobpasses.first
+
+function jobpasses.find(id,n)
+ local jti = collected[id]
+ if jti and jti[n] then
+ texprint(jti[n])
+ end
+end
+
+function jobpasses.count(id)
+ local jti = collected[id]
+ texprint((jti and #jti) or 0)
+end
+
+function jobpasses.list(id)
+ local jti = collected[id]
+ if jti then
+ texprint(concat(jti,','))
+ end
+end
+
+function jobpasses.doifinlistelse(id,str)
+ local jti = collected[id]
+ if jti then
+ local found = false
+ for _, v in next, jti do
+ if v == str then
+ found = true
+ break
+ end
+ end
+ commands.testcase(found)
+ else
+ commands.testcase(false)
+ end
+end
+
+--
+
+function jobpasses.savedata(id,data)
+ local jti = allocate(id)
+ jti[#jti+1] = data
+ return #jti
+end
+
+function jobpasses.getdata(id,index,default)
+ local jti = collected[id]
+ local value = jit and jti[index]
+ texprint((value ~= "" and value) or default or "")
+end
+
+function jobpasses.getfield(id,index,tag,default)
+ local jti = collected[id]
+ jti = jti and jti[index]
+ local value = jti and jti[tag]
+ texprint((value ~= "" and value) or default or "")
+end
+
diff --git a/tex/context/base/core-two.mkii b/tex/context/base/core-two.mkii
new file mode 100644
index 000000000..0f2e0048c
--- /dev/null
+++ b/tex/context/base/core-two.mkii
@@ -0,0 +1,206 @@
+%D \module
+%D [ file=core-two, % moved from core-uti
+%D version=1997.03.31,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Two Pass Data,
+%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 Core Macros / Two Pass Data}
+
+%D This is a rather old mechanism which has not changed much over
+%D time, apart from adding a few more selectors. This code used
+%D to be part of \type {core-uti}. The following examples demonstrate
+%D the interface.
+%D
+%D \startbuffer
+%D \definetwopasslist{test-1}
+%D
+%D \gettwopassdatalist{test-1} [\twopassdatalist=]
+%D \checktwopassdata {test-1} [\twopassdata=]
+%D \checktwopassdata {test-1} [\twopassdata=]
+%D \gettwopassdata {test-1} [\twopassdata=]
+%D \gettwopassdata {test-1} [\twopassdata=]
+%D
+%D \definetwopasslist{test-2}
+%D
+%D \lazysavetwopassdata{test-2}{1}{x}
+%D \lazysavetwopassdata{test-2}{2}{y}
+%D \lazysavetwopassdata{test-2}{3}{z}
+%D
+%D \gettwopassdatalist{test-2} [\twopassdatalist=x,y,z]
+%D \checktwopassdata {test-2} [\twopassdata=x]
+%D \checktwopassdata {test-2} [\twopassdata=x]
+%D \gettwopassdata {test-2} [\twopassdata=x]
+%D \gettwopassdata {test-2} [\twopassdata=y]
+%D \gettwopassdata {test-2} [\twopassdata=z]
+%D \gettwopassdata {test-2} [\twopassdata=]
+%D
+%D \definetwopasslist{test-3}
+%D
+%D \lazysavetaggedtwopassdata{test-3}{1}{x}{a}
+%D \lazysavetaggedtwopassdata{test-3}{2}{y}{b}
+%D \lazysavetaggedtwopassdata{test-3}{3}{z}{c}
+%D
+%D \findtwopassdata{test-3}{x} [\twopassdata=a]
+%D \findtwopassdata{test-3}{y} [\twopassdata=b]
+%D \findtwopassdata{test-3}{z} [\twopassdata=c]
+%D \findtwopassdata{test-3}{w} [\twopassdata=]
+%D
+%D \definetwopasslist{test-4}
+%D
+%D \lazysavetwopassdata{test-4}{1}{A}
+%D \lazysavetwopassdata{test-4}{2}{B}
+%D \lazysavetwopassdata{test-4}{3}{C}
+%D
+%D \getfirsttwopassdata{test-4} [\twopassdata=A]
+%D \getlasttwopassdata {test-4} [\twopassdata=C]
+%D \getfirsttwopassdata{test-4} [\twopassdata=A]
+%D \getlasttwopassdata {test-4} [\twopassdata=C]
+%D \getfromtwopassdata {test-4}{1} [\twopassdata=A]
+%D \getfromtwopassdata {test-4}{3} [\twopassdata=C]
+%D \getfromtwopassdata {test-4}{2} [\twopassdata=B]
+%D \stopbuffer
+%D
+%D \getbuffer \typebuffer
+
+\unprotect
+
+\let\alltwopasslists\empty
+\let\twopassentry \gobblethreearguments % permits loading a MK II file
+\let\twopassdata \empty
+\let\twopassdatalist\empty
+
+\newif\iftwopassdatafound
+
+\addutilityreset{twopassentries}
+
+\def\immediatesavetwopassdata #1#2#3{\immediatewriteutilitycommand{\twopassentry{#1}{#2}{#3}}}
+\def\savetwopassdata #1#2#3{\writeutilitycommand{\twopassentry{#1}{#2}{#3}}}
+\def\lazysavetwopassdata #1#2#3{\expanded{\writeutilitycommand{\noexpand\twopassentry{#1}{#2}{#3}}}} % expanded !
+\def\savetaggedtwopassdata #1#2#3#4{\immediatewriteutilitycommand{\twopassentry{#1}{#2}{#3::#4}}}
+\def\lazysavetaggedtwopassdata#1#2#3#4{\expanded{\writeutilitycommand{\noexpand\twopassentry{#1}{#2}{#3::#4}}}} % expanded !
+
+\def\resettwopassentries
+ {\let\twopassentry\gobblethreearguments}
+
+\def\settwopassentries
+ {\def\twopassentry##1{\executeifdefined{@@##1\s!pass}\gobbletwoarguments}}
+
+\resettwopassentries
+
+\def\appendtwopasselement#1#2#3% can sometimes become a large list
+ {%\debuggerinfo{\m!systems}{twopass data #1 - #2 = #3}%
+ \expandafter\xdef\csname#1:\s!list\endcsname
+ {\@EA\ifx\csname#1:\s!list\endcsname\empty \else
+ \csname#1:\s!list\endcsname,\fi#3}}
+
+\def\dodefinetwopasslist#1%
+ {\doifundefined{#1:\s!list}
+ {%\debuggerinfo\m!systems{defining twopass class #1}%
+ \doglobal\addutilityreset{#1\s!pass}%
+ \setgvalue{\s!set #1\s!pass}{\dosettwopasslist {#1}}%
+ \setgvalue{\s!reset#1\s!pass}{\doresettwopasslist{#1}}%
+ \getvalue {\s!reset#1\s!pass}}}
+
+\def\definetwopasslist#1%
+ {\expanded{\dodefinetwopasslist{#1}}%
+ \doglobal\addtocommalist{#1}\alltwopasslists}
+
+\def\dosettwopasslist#1%
+ {\letgvalue{\s!set#1\s!pass}\gobbletwoarguments
+ \setgvalue{@@#1\s!pass}{\appendtwopasselement{#1}}}
+
+\def\doresettwopasslist#1%
+ {\letgvalue{@@#1\s!pass}\gobbletwoarguments}
+
+\def\doloadtwopassdata#1%
+ {\doifundefined{#1:\s!list}
+ {\startnointerference
+ \letgvalueempty{#1:\s!list}%
+ \protectlabels
+ \doutilities{twopassentries,#1\s!pass}\jobname\empty\relax\relax
+ \stopnointerference}}
+
+\def\loadtwopassdata
+ {\ifx\alltwopasslists\empty\else
+ \processcommacommand[\alltwopasslists]\doloadtwopassdata
+ \globallet\alltwopasslists\empty
+ \fi}
+
+\def\dogettwopassdata[#1,#2]#3#4%
+ {\edef\twopassdata{#1}%
+ \ifx\twopassdata\empty
+ \twopassdatafoundfalse
+ \let\twopassdata\empty
+ \else
+ \twopassdatafoundtrue
+ \ifcase#4\or\setxvalue{#3:\s!list}{#2}\fi
+ \fi}
+
+\def\gettwopassdata#1%
+ {\loadtwopassdata \@EAEAEA\dogettwopassdata\@EA\@EA\@EA[\csname#1:\s!list\endcsname,]{#1}\plusone}
+
+\def\checktwopassdata#1%
+ {\loadtwopassdata \@EAEAEA\dogettwopassdata\@EA\@EA\@EA[\csname#1:\s!list\endcsname,]{#1}\zerocount}
+
+\def\findtwopassdata#1#2%
+ {\loadtwopassdata \expanded{\dofindtwopassdata{#1}{#2}}}
+
+\def\dofindtwopassdata#1#2%
+ {\def\dodofindtwopassdata[##1,##2#2::##3,##4]{\edef\twopassdata{##3}}%
+ \@EAEAEA\dodofindtwopassdata\@EA\@EA\@EA[\@EA\@EA\@EA,\csname#1:\s!list\endcsname,#2,#2::,]%
+ \ifx\twopassdata\empty
+ \twopassdatafoundfalse
+ \else
+ \twopassdatafoundtrue
+ \fi}
+
+\let\getfirsttwopassdata\checktwopassdata
+
+\def\getlasttwopassdata#1%
+ {\loadtwopassdata
+ \scratchcounter\zerocount
+ \@EAEAEA\rawprocesscommalist\@EA\@EA\@EA[\csname#1:\s!list\endcsname]\dogetlasttwopassdata
+ \edef\noftwopassitems{\the\scratchcounter}%
+ \iftwopassdatafound\else
+ \let\twopassdata\empty
+ \fi}
+
+\def\dogetlasttwopassdata#1%
+ {\edef\nexttwopassdata{#1}%
+ \ifx\nexttwopassdata\empty \else
+ \let\twopassdata\nexttwopassdata
+ \advance\scratchcounter \plusone
+ \twopassdatafoundtrue
+ \fi}
+
+\def\getfromtwopassdata#1#2%
+ {\loadtwopassdata
+ \@EAEAEA\getfromcommalist\@EA\@EA\@EA[\csname#1:\s!list\endcsname][#2]%
+ \ifx\commalistelement\empty
+ \twopassdatafoundfalse
+ \let\twopassdata\empty
+ \else
+ \twopassdatafoundtrue
+ \let\twopassdata\commalistelement
+ \fi}
+
+\def\gettwopassdatalist#1%
+ {\loadtwopassdata
+ \letcscsname\twopassdatalist\csname#1:\s!list\endcsname
+ \ifx\twopassdatalist\relax\let\twopassdatalist\empty\fi}
+
+\def\gettwopassdatalist
+ {\getnamedtwopassdatalist\twopassdatalist}
+
+\def\doifelseintwopassdata#1#2% tag dat
+ {\gettwopassdatalist{#1}%
+ \expanded{\doifinsetelse{#2}{\twopassdatalist}}}
+
+\protect \endinput
diff --git a/tex/context/base/core-two.mkiv b/tex/context/base/core-two.mkiv
new file mode 100644
index 000000000..2cc9412af
--- /dev/null
+++ b/tex/context/base/core-two.mkiv
@@ -0,0 +1,106 @@
+%D \module
+%D [ file=core-two, % moved from core-uti
+%D version=1997.03.31,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Two Pass Data,
+%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 Core Macros / Two Pass Data}
+
+%D This is a rather old mechanism which has not changed much over
+%D time, apart from adding a few more selectors. This code used
+%D to be part of \type {core-uti}. The following examples demonstrate
+%D the interface.
+%D
+%D \startbuffer
+%D \definetwopasslist{test-1}
+%D
+%D \gettwopassdatalist{test-1} [\twopassdatalist=]
+%D \checktwopassdata {test-1} [\twopassdata=]
+%D \checktwopassdata {test-1} [\twopassdata=]
+%D \gettwopassdata {test-1} [\twopassdata=]
+%D \gettwopassdata {test-1} [\twopassdata=]
+%D
+%D \definetwopasslist{test-2}
+%D
+%D \lazysavetwopassdata{test-2}{1}{x}
+%D \lazysavetwopassdata{test-2}{2}{y}
+%D \lazysavetwopassdata{test-2}{3}{z}
+%D
+%D \gettwopassdatalist{test-2} [\twopassdatalist=x,y,z]
+%D \checktwopassdata {test-2} [\twopassdata=x]
+%D \checktwopassdata {test-2} [\twopassdata=x]
+%D \gettwopassdata {test-2} [\twopassdata=x]
+%D \gettwopassdata {test-2} [\twopassdata=y]
+%D \gettwopassdata {test-2} [\twopassdata=z]
+%D \gettwopassdata {test-2} [\twopassdata=]
+%D
+%D \definetwopasslist{test-3}
+%D
+%D \lazysavetaggedtwopassdata{test-3}{1}{x}{a}
+%D \lazysavetaggedtwopassdata{test-3}{2}{y}{b}
+%D \lazysavetaggedtwopassdata{test-3}{3}{z}{c}
+%D
+%D \findtwopassdata{test-3}{x} [\twopassdata=a]
+%D \findtwopassdata{test-3}{y} [\twopassdata=b]
+%D \findtwopassdata{test-3}{z} [\twopassdata=c]
+%D \findtwopassdata{test-3}{w} [\twopassdata=]
+%D
+%D \definetwopasslist{test-4}
+%D
+%D \lazysavetwopassdata{test-4}{1}{A}
+%D \lazysavetwopassdata{test-4}{2}{B}
+%D \lazysavetwopassdata{test-4}{3}{C}
+%D
+%D \getfirsttwopassdata{test-4} [\twopassdata=A]
+%D \getlasttwopassdata {test-4} [\twopassdata=C]
+%D \getfirsttwopassdata{test-4} [\twopassdata=A]
+%D \getlasttwopassdata {test-4} [\twopassdata=C]
+%D \getfromtwopassdata {test-4}{1} [\twopassdata=A]
+%D \getfromtwopassdata {test-4}{3} [\twopassdata=C]
+%D \getfromtwopassdata {test-4}{2} [\twopassdata=B]
+%D \stopbuffer
+%D
+%D \getbuffer \typebuffer
+
+\unprotect
+
+\let\twopassdatalist\empty
+
+\newif\iftwopassdatafound
+
+\registerctxluafile{core-two}{1.001}
+
+%D I'm not that sure if this behaves exactly like mkii. This needs a cleanup.
+
+\def\immediatesavetwopassdata #1#2#3{\normalexpanded{\noexpand\ctxlua {jobpasses.save('#1',"#3")}}}
+\def\savetwopassdata #1#2#3{\normalexpanded{\noexpand\ctxlatelua{jobpasses.save('#1',"#3")}}}
+\def\lazysavetwopassdata #1#2#3{\normalexpanded{\noexpand\ctxlatelua{jobpasses.save('#1',"#3")}}}
+\def\savetaggedtwopassdata #1#2#3#4{\normalexpanded{\noexpand\ctxlua {jobpasses.savetagged('#1','#3',"#4")}}}
+\def\lazysavetaggedtwopassdata#1#2#3#4{\normalexpanded{\noexpand\ctxlatelua{jobpasses.savetagged('#1','#3',"#4")}}}
+
+% temp hack: needs a proper \starteverytimeluacode
+
+\def\testtwopassdata{\ifx\twopassdata\empty\twopassdatafoundfalse\else\twopassdatafoundtrue\fi}
+
+% todo: move the edef to lua
+
+\unexpanded\def\definetwopasslist #1{\ctxlua{jobpasses.define('#1')}}
+\def\gettwopassdata #1{\edef\twopassdata{\ctxlua{jobpasses.get("#1")}}\testtwopassdata}
+\def\checktwopassdata #1{\edef\twopassdata{\ctxlua{jobpasses.check("#1")}}\testtwopassdata}
+\def\findtwopassdata #1#2{\edef\twopassdata{\ctxlua{jobpasses.find("#1","#2")}}\testtwopassdata}
+\def\getfirsttwopassdata #1{\edef\twopassdata{\ctxlua{jobpasses.first("#1")}}\testtwopassdata}
+\def\getlasttwopassdata #1{\edef\twopassdata{\ctxlua{jobpasses.last("#1")}}\edef\noftwopassitems{\ctxlua{jobpasses.count("#1")}}\testtwopassdata}
+\def\getnamedtwopassdatalist#1#2{\edef#1{\ctxlua{jobpasses.list("#2")}}}
+\def\gettwopassdatalist #1{\edef\twopassdatalist{\ctxlua{jobpasses.list("#1")}}}
+\def\doifelseintwopassdata #1#2{\ctxlua{jobpasses.doifinlistelse("#1","#2")}}
+
+\let\getfromtwopassdata\findtwopassdata
+
+\protect \endinput
diff --git a/tex/context/base/core-uti.lua b/tex/context/base/core-uti.lua
new file mode 100644
index 000000000..01fd8522b
--- /dev/null
+++ b/tex/context/base/core-uti.lua
@@ -0,0 +1,294 @@
+if not modules then modules = { } end modules ['core-uti'] = {
+ version = 1.001,
+ comment = "companion to core-uti.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: keep track of changes here (hm, track access, and only true when
+-- accessed and changed)
+
+--[[ldx--
+
A utility file has always been part of and with
+the move to we also moved a lot of multi-pass info
+to a table. Instead of loading a based
+utility file under different setups, we now load a table once. This
+saves much runtime but at the cost of more memory usage.
+--ldx]]--
+
+local sort, concat, format, match = table.sort, table.concat, string.format, string.match
+local next, type, tostring = next, type, tostring
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+
+if not jobs then jobs = { } end
+if not job then jobs['main'] = { } end job = jobs['main']
+
+jobs.version = 1.10
+
+--[[ldx--
+
Variables are saved using in the previously defined table and passed
+onto using the following method. Of course one can also
+directly access the variable using a call.
+--ldx]]--
+
+local savelist, comment = { }, { }
+
+function job.comment(str)
+ comment[#comment+1] = str
+end
+
+job.comment(format("version: %1.2f",jobs.version))
+
+function job.initialize(loadname,savename)
+ job.load(loadname)
+ main.register_stop_actions(function()
+ if not status.lasterrorstring or status.lasterrorstring == "" then
+ job.save(savename)
+ end
+ end)
+end
+
+function job.register(...) -- collected, tobesaved, initializer, finalizer
+ savelist[#savelist+1] = { ... }
+end
+
+-- as an example we implement variables
+
+jobvariables = jobvariables or { }
+jobvariables.collected = jobvariables.collected or { }
+jobvariables.tobesaved = jobvariables.tobesaved or { }
+jobvariables.checksums = jobvariables.checksums or { }
+
+if not jobvariables.checksums.old then jobvariables.checksums.old = md5.HEX("old") end -- used in experiment
+if not jobvariables.checksums.new then jobvariables.checksums.new = md5.HEX("new") end -- used in experiment
+
+job.register('jobvariables.checksums', jobvariables.checksums)
+
+local function initializer()
+ local r = jobvariables.collected.randomseed
+ if not r then
+ r = math.random()
+ math.setrandomseedi(r,"initialize")
+ else
+ math.setrandomseedi(r,"previous run")
+ end
+ jobvariables.tobesaved.randomseed = r
+ for cs, value in next, jobvariables.collected do
+ texsprint(ctxcatcodes,format("\\xdef\\%s{%s}",cs,value))
+ end
+end
+
+job.register('jobvariables.collected', jobvariables.tobesaved, initializer)
+
+function jobvariables.save(cs,value)
+ jobvariables.tobesaved[cs] = value
+end
+
+-- experiment (bugged: some loop in running)
+
+-- for the moment here, very experimental stuff
+
+packer = packer or { }
+packer.version = 1.00
+
+local function hashed(t)
+ local s = { }
+ for k, v in next, t do
+ if type(v) == "table" then
+ s[#s+1] = k.."={"..hashed(v).."}"
+ else
+ s[#s+1] = k.."="..tostring(v)
+ end
+ end
+ sort(s)
+ return concat(s,",")
+end
+
+local function pack(t,keys,hash,index)
+ for k,v in next, t do
+ if type(v) == "table" then
+ pack(v,keys,hash,index)
+ end
+ if keys[k] and type(v) == "table" then
+ local h = hashed(v)
+ local i = hash[h]
+ if not i then
+ i = #index+1
+ index[i] = v
+ hash[h] = i
+ end
+ t[k] = i
+ end
+ end
+end
+
+local function unpack(t,keys,index)
+ for k,v in next, t do
+ if keys[k] and type(v) == "number" then
+ local iv = index[v]
+ if iv then
+ v = iv
+ t[k] = v
+ end
+ end
+ if type(v) == "table" then
+ unpack(v,keys,index)
+ end
+ end
+end
+
+function packer.new(keys,version)
+ return {
+ version = version or packer.version,
+ keys = table.tohash(keys),
+ hash = { },
+ index = { },
+ }
+end
+
+function packer.pack(t,p,shared)
+ if shared then
+ pack(t,p.keys,p.hash,p.index)
+ elseif not t.packer then
+ pack(t,p.keys,p.hash,p.index)
+ if #p.index > 0 then
+ t.packer = {
+ version = p.version or packer.version,
+ keys = p.keys,
+ index = p.index,
+ }
+ end
+ p.hash, p.index = { }, { }
+ end
+end
+
+function packer.unpack(t,p,shared)
+ if shared then
+ if p then
+ unpack(t,p.keys,p.index)
+ end
+ else
+ local tp = t.packer
+ if tp then
+ if tp.version == (p and p.version or packer.version) then
+ unpack(t,tp.keys,tp.index)
+ else
+ -- fatal error, wrong version
+ end
+ t.packer = nil
+ end
+ end
+end
+
+function packer.strip(p)
+ p.hash = nil
+end
+
+local packlist = {
+ "numbers",
+ "metadata",
+ "sectiondata",
+ "prefixdata",
+ "numberdata",
+ "pagedata",
+ "directives",
+ "specification",
+ "processors", -- might become key under directives or metadata
+-- "references", -- we need to rename of them as only one packs (not structure.lists.references)
+}
+
+local jobpacker = packer.new(packlist,1.01)
+
+job.pack = true
+
+job._save_, job._load_ = { }, { } -- registers timing
+
+function job.save(filename)
+ statistics.starttiming(job._save_)
+ local f = io.open(filename,'w')
+ if f then
+ for c=1,#comment do
+ f:write("-- ",comment[c],"\n")
+ end
+ f:write("\n")
+ for l=1,#savelist do
+ local list = savelist[l]
+ local target, data, finalizer = list[1], list[2], list[4]
+ if type(finalizer) == "function" then
+ finalizer()
+ end
+ if job.pack then
+ packer.pack(data,jobpacker,true)
+ end
+ f:write(aux.definetable(target),"\n")
+ f:write(table.serialize(data,target,true,true),"\n")
+ end
+ if job.pack then
+ packer.strip(jobpacker)
+ f:write(table.serialize(jobpacker,"job.packer",true,true),"\n")
+ end
+ f:close()
+ end
+ statistics.stoptiming(job._save_)
+end
+
+function job.load(filename)
+ statistics.starttiming(job._load_)
+ local data = io.loaddata(filename)
+ if data and data ~= "" then
+ local version = tonumber(match(data,"^-- version: ([%d%.]+)"))
+ if version ~= jobs.version then
+ logs.report("job","version mismatch with jobfile: %s <> %s", version or "?", jobs.version)
+ else
+ local data = loadstring(data)
+ if data then
+ data()
+ end
+ for l=1,#savelist do
+ local list = savelist[l]
+ local target, initializer = list[1], list[3]
+ packer.unpack(aux.accesstable(target),job.packer,true)
+ if type(initializer) == "function" then
+ initializer(aux.accesstable(target))
+ end
+ end
+ job.packer = nil
+ end
+ end
+ statistics.stoptiming(job._load_)
+end
+
+-- eventually this will end up in strc-ini
+
+statistics.register("startup time", function()
+ return statistics.elapsedseconds(ctx,"including runtime option file processing")
+end)
+
+statistics.register("jobdata time",function()
+ if statistics.elapsedindeed(job._save_) or statistics.elapsedindeed(job._load_) then
+ return format("%s seconds saving, %s seconds loading", statistics.elapsedtime(job._save_), statistics.elapsedtime(job._load_))
+ end
+end)
+
+statistics.register("callbacks", function()
+ local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
+ local pages = tex.count['realpageno'] - 1
+ if pages > 1 then
+ return format("direct: %s, indirect: %s, total: %s (%i per page)", total-indirect, indirect, total, total/pages)
+ else
+ return format("direct: %s, indirect: %s, total: %s", total-indirect, indirect, total)
+ end
+end)
+
+function statistics.formatruntime(runtime)
+ local shipped = tex.count['nofshipouts']
+ local pages = tex.count['realpageno'] - 1
+ if shipped > 0 or pages > 0 then
+ local persecond = shipped / runtime
+ if pages == 0 then pages = shipped end
+ return format("%s seconds, %i processed pages, %i shipped pages, %.3f pages/second",runtime,pages,shipped,persecond)
+ else
+ return format("%s seconds",runtime)
+ end
+end
diff --git a/tex/context/base/core-uti.mkii b/tex/context/base/core-uti.mkii
new file mode 100644
index 000000000..5b8f66f50
--- /dev/null
+++ b/tex/context/base/core-uti.mkii
@@ -0,0 +1,349 @@
+%D \module
+%D [ file=core-uti,
+%D version=1997.03.31,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Utility File Handling,
+%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 Core Macros / Utility File Handling}
+
+\unprotect
+
+% todo : safe lan etc too
+% todo : load all commands at once (tok)
+% todo : merge status info patch into tui file (language, encoding, etc),
+
+% Utility-file
+%
+% De onderstaande macro's ondersteunen het gebruik van de
+% zogeheten utility-file. Alle extern onder te brengen
+% informatie wordt opgeslagen in de file \jobname.tui, tenzij
+% er selectief pagina's worden gezet. In dat geval wordt de
+% file \jobname.tmp gebruikt. Informatie wordt ingelezen uit
+% de file \jobname.tuo, welke door TeXUtil wordt aangemaakt.
+
+\edef\utilityversion{1998.07.07} % was: 1996.03.15 % status variables
+\edef\utilityversion{1998.12.20} % was: 1998.07.07 % index attributes
+\edef\utilityversion{2003.07.19} % was: 1998.12.20 % object pages
+\edef\utilityversion{2006.06.23} % was: 2003.07.19 % -- instead of :
+\edef\utilityversion{2006.09.21} % pt in pos
+\edef\utilityversion{2008.10.14} % moved more to lua in mkiv
+
+% Bepaalde commando's worden als string weggeschreven. Deze
+% zijn aan het eind van deze file gedefinieerd.
+
+% Om een opbouw van spaties te voorkomen (???) moet ^^M een
+% andere betekenis krijgen:
+%
+% \catcode`\^^M=14 (comment)
+%
+% read file
+%
+% \catcode`\^^M=5 (end of line)
+
+\newwrite\utility@tui
+\newif\ifutilitydone
+
+\ifx\sectionseparator\undefined \def\sectionseparator{-} \fi
+
+\def\@@utilityerrormessage
+ {\showmessage\m!systems8\empty
+ \globallet\@@utilityerrormessage\relax}
+
+\def\thisisutilityversion#1%
+ {\doifelse\utilityversion{#1}%
+ {\checksectionseparator}
+ {\@@utilityerrormessage\resetutilities\endinput}}
+
+\def\checksectionseparator % catches backward compatibility conflict
+ {}% \doifnot\sectionseparator:\endinput} % this dependency may go in a few years
+
+\def\dosplitofffoliopart[#1--#2--#3]{#3}
+
+\def\thisissectionseparator#1%
+ {\bgroup
+ \globallet\checksectionseparator\relax
+ \defconvertedcommand \asciia\sectionseparator
+ \defconvertedargument\asciib{#1}%
+ \expanded{\gdef\noexpand\dosplitofffoliopart[####1\sectionseparator
+ \sectionseparator####2\sectionseparator\sectionseparator####3]{####3}}%
+ \ifx\asciia\asciib
+ \egroup
+ \else
+ \egroup
+ % todo \@@utilityerrormessage
+ \resetutilities
+ \endinput
+ \fi}
+
+\def\writeutility {\write\utility@tui}
+\def\writeutilitycommand#1{\write\utility@tui{c \string#1}}
+
+% less tokens
+%
+% \def\immediatewriteutility {\immediate\writeutility}
+% \def\immediatewriteutilitycommand{\immediate\writeutilitycommand}
+%
+% more flexible (for overloading)
+
+\def\immediatewriteutility {\immediate\write\utility@tui}
+\def\immediatewriteutilitycommand#1{\immediate\write\utility@tui{c \string#1}}
+
+% as in:
+
+\def\cwriteutility#1%
+ {\write\utility@tui{\noexpand\checkedutility{\number\nofshipouts}{#1}}}
+
+\def\cwriteutilitycommand#1%
+ {\write\utility@tui{\noexpand\checkedutility{\number\nofshipouts}{c \string#1}}}
+
+\let\checkedutility\secondoftwoarguments
+
+\def\docheckedutility#1#2{\ifnum#1=\nofshipouts#2\else\letterpercent\fi}
+
+\prependtoks
+ \let\checkedutility\docheckedutility
+\to \everybeforeshipout
+
+% Better use marks.
+
+\newtoks \everyopenutilities
+\newtoks \everycloseutilities
+\newtoks \everycheckutilities
+
+\def\openutilities {\the\everyopenutilities } % \global\everyopenutilities\emptytoks
+\def\closeutilities{\the\everycloseutilities}
+\def\checkutilities{\the\everycheckutilities}
+
+\appendtoks
+ \let\writeutility \cwriteutility
+ \let\writeutilitycommand \cwriteutilitycommand
+ %\let\immediatewriteutility \cimmediatewriteutility
+ %\let\immediatewriteutilitycommand\cimmediatewriteutilitycommand
+ \let\checkutilities \relax
+\to \everycheckutilities
+
+\appendtoks
+ \immediate\openout\utility@tui\jobname.\f!inputextension
+ \immediatewriteutilitycommand{\thisissectionseparator{\sectionseparator}}% for the moment
+ \immediatewriteutilitycommand{\thisisutilityversion {\utilityversion }}% in this order
+\to \everyopenutilities
+
+\appendtoks
+% \immediate\closeout\utility@tui % niet echt nodig
+ \reportutilityproblems
+ % should be a message :
+ \let\writeutilitycommand \gobbleoneargument
+ \let\writeutility \gobbleoneargument
+ \let\immediatewriteutilitycommand\gobbleoneargument
+ \let\immediatewriteutility \gobbleoneargument
+\to \everycloseutilities
+
+% \def\reopenutilities
+% {\immediate\closeout\utility@tui
+% \openutilities}
+
+\def\abortutilitygeneration
+ {\immediatewriteutilitycommand\utilitygenerationaborted
+ \immediatewriteutility{q {quit}}}
+
+\def\utilitygenerationaborted
+ {\showmessage\m!systems{21}\empty
+ \globallet\utilitygenerationaborted\endinput
+ \gdef\reportutilityproblems{\showmessage\m!systems{22}\empty}%
+ \endinput}
+
+\def\savecurrentvalue#1#2%
+ {\immediatewriteutilitycommand{\initializevariable\string#1{#2}}}
+
+\let\initializevariable\gdef
+
+\appendtoks
+ \globallet\initializevariable\gobbletwoarguments
+\to \everyafterutilityread
+
+\let\reportutilityproblems\relax
+
+\newtoks\utilityresetlist
+
+\def\addutilityreset#1%
+ {\@EA\appendtoks\csname\s!reset#1\endcsname\to\utilityresetlist}
+
+\def\resetutilities
+ {\the\utilityresetlist}
+
+% #1=type #2=file #3=melding #4=voor #5=na
+%
+% Er wordt gegroepeerd. Als binnen een lijst (bijvoorbeeld) de
+% \leftskip is aangepast, maar nog geen \par is gegeven, dan
+% geldt buiten de groep de oude \leftskip. Aan #5 kan dan
+% ook \par worden meegegeven om de paragraaf af te sluiten.
+
+\newif\ifdoinpututilities
+\newif\ifunprotectutilities % voor't geval er \v!xxxxxx's zijn
+
+\def\currentutilityfilename{\jobname}
+
+% we need to pop and push, else problems with reading
+% utility files (toc) in xml mode and (e.g.) in a toc
+% entry doing a doifmode
+%
+% the following is not ok because we have no way to signal
+% xml content (yet), so for the moment we use this:
+
+\appendtoks
+ \ifprocessingXML
+ \processingXMLfalse
+ \enableXML
+ \catcode`\\=\@@escape
+ \catcode`\{=\@@begingroup
+ \catcode`\}=\@@endgroup
+ \catcode`\%=\@@comment\relax
+ \fi
+\to \everybeforeutilityread
+
+% \edef\testbytesequence
+% {\rawcharacter{7}%
+% \rawcharacter{27}%
+% %rawcharacter{227}% invalid in xetex, which expects utf
+% \rawcharacter{195}\rawcharacter{128}} % valid utf code
+%
+% \def\thisisbytesequence#1%
+% {\ifx\testbytesequence\empty\else
+% \defconvertedcommand\testbytesequence\testbytesequence
+% \defconvertedargument\ascii{#1}%
+% \ifx\testbytesequence\ascii \else
+% \writestatus\m!systems{possible problem with 8 bit output}%
+% \fi
+% \fi
+% \global\let\thisisbytesequence\gobbleoneargument}
+%
+% \ifnum\texengine=\xetexengine
+% \let\testbytesequence\empty
+% \fi
+%
+% \appendtoks
+% \immediatewriteutilitycommand{\thisisbytesequence{\testbytesequence}}%
+% \to \everyopenutilities
+
+\let\testbytesequence \empty % keep this
+\let\thisisbytesequence\gobbleoneargument % keep this
+
+\long\def\doutilities#1#2#3#4#5% % introduceren in utility file
+ {\resetutilities
+ % more than one utility thing can be handled in one pass,
+ % for instance lists, so we process ##1 as list
+ \def\douticommand##1{\csname\s!set##1\endcsname}%
+ \processcommacommand[#1]\douticommand
+ \begingroup
+ \def\currentutilityfilename{#2}%
+ \notesenabledfalse
+ \doinpututilitiestrue
+ \global\utilitydonefalse
+ \pushendofline % geeft problemen zodra andere file wordt ingelezen
+ \pushcatcodetable
+ \setcatcodetable\ctxcatcodes
+ \ifunprotectutilities % nog nodig ?
+ \unprotect
+ \fi
+ #4%
+ \the\everybeforeutilityread
+ \readjobfile{#2.\f!outputextension}\donothing\donothing
+ \the\everyafterutilityread
+ \popcatcodetable
+ #5%
+ \relax
+ \ifunprotectutilities
+ \protect
+ \fi
+ \popendofline
+ \ifutilitydone\else
+ \doifsomething{#3}
+ {\showmessage\m!systems9{{#3}}%
+ \doifconcepttracing
+ {\blank
+ \setmessagetext\m!systems9{{#3}}%
+ \type{[\currentmessagetext]}%
+ \blank}}%
+ \fi
+ \endgroup}
+
+% Default-instellingen (verborgen)
+
+\prependtoks \resetutilities \to \everyjob
+
+% Experiment
+%
+% \installprogram{Hello World}
+% \installprogram[hw]{Hello World}
+% \installedprogram[hw]
+
+\def\installprogram
+ {\dosingleempty\doinstallprogram}
+
+\def\doinstallprogram[#1]#2%
+ {\doifelsenothing{#1}
+ {\dodoinstallprogram{#2}}
+ {\setvalue{\??up#1}{\dodoinstallprogram{#2}}}}
+
+\def\dodoinstallprogram#1%
+ {\immediatewriteutility{e p {#1}}}
+
+\def\installedprogram[#1]%
+ {\getvalue{\??up#1}}
+
+% \writeplugindata{texutil}{{alpha}}
+% \writeplugindata{texutil}{{beta}}
+% \writeplugindata{texutil}{{gamma}}
+% \writeplugindata{texutil}{{delta}}
+%
+% \loadplugindata {plugintest}
+
+\def\immediatewriteplugindata#1#2%
+ {\immediatewriteutility{p u {#1} #2}}
+
+\def\writeplugindata#1#2%
+ {\writeutility{p u {#1} #2}}
+
+\def\loadplugindata#1%
+ {\doutilities{#1}\jobname\empty\relax\relax}
+
+% \plugincommand{\command{}{}{}}
+%
+% this way we can catch undefined commands
+
+\long\def\plugincommand#1%
+ {\doplugincommand#1\relax}
+
+\long\def\doplugincommand#1%
+ {\ifx#1\undefined
+ \expandafter\noplugincommand
+ \else
+ \expandafter#1%
+ \fi}
+
+\long\def\noplugincommand#1\relax
+ {}
+
+% \addutilityreset{plugintest}
+%
+% \def\resetplugintest{\let\plugintest\gobbletwoarguments}
+% \def\setplugintest {\let\plugintest\writestatus}
+%
+% \installplugin
+% {plugintest}
+% {\let\plugintest\gobbletwoarguments}
+% {\let\plugintest\writestatus}
+
+\long\def\installplugin#1#2#3%
+ {\addutilityreset {#1}%
+ \long\setvalue{\s!reset#1}{#2}%
+ \long\setvalue{\s!set #1}{#3}}
+
+\protect \endinput
diff --git a/tex/context/base/core-uti.mkiv b/tex/context/base/core-uti.mkiv
new file mode 100644
index 000000000..6b2dae2c9
--- /dev/null
+++ b/tex/context/base/core-uti.mkiv
@@ -0,0 +1,66 @@
+%D \module
+%D [ file=core-uti,
+%D version=1997.03.31, % 2006.09.19 mkiv
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Utility File Handling,
+%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 Core Macros / Utility File Handling}
+
+\unprotect
+
+\registerctxluafile{core-uti}{1.001}
+
+\def\savecurrentvalue#1#2%
+ {\ctxlua{jobvariables.save("\strippedcsname#1","#2")}}
+
+\appendtoks
+ \ctxlua{storage.dump()}% will move to lua
+\to \everydump
+
+\appendtoks
+ \ctxlua{storage.finalize()}% will move to lua
+\to \everyfinalizeluacode
+
+\appendtoks
+ \ctxlua{nodes.cleanup_reserved()}% will move to lua
+\to \everydump
+
+\appendtoks
+ \ctxlua {
+ job.comment("file: \jobname")
+ job.comment("format: \contextformat")
+ job.comment("stamp: \contextversion")
+ job.comment("escape: \!!bs\space...\space\!!es")
+ job.initialize("\jobname.tuc","\jobname.tua")
+ }%
+\to \everystarttext
+
+\def\notuccompression{\ctxlua{job.pack=false}}
+
+% cleaner, for the moment
+
+% \appendtoks
+% \ctxlua {
+% os.remove("\jobname.tui")
+% os.remove("\jobname.tuo")
+% }%
+% \to \everystarttext
+
+%D Some styles might use these use these commands:
+
+\newif \ifutilitydone
+\let \checkutilities \relax
+\let \currentutilityfilename \jobname
+\def \installprogram {\dosingleempty\doinstallprogram}
+\def \doinstallprogram [#1]{\gobbleoneargument}
+\def \installedprogram [#1]{}
+\let \installplugin \gobblethreearguments
+
+\protect \endinput
diff --git a/tex/context/base/core-var.mkii b/tex/context/base/core-var.mkii
new file mode 100644
index 000000000..4de1b8718
--- /dev/null
+++ b/tex/context/base/core-var.mkii
@@ -0,0 +1,286 @@
+%D \module
+%D [ file=core-var,
+%D version=1998.02.21,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Variables,
+%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 Core Macros / Variables}
+
+\unprotect
+
+%D We introduce a couple of variables that are used all over
+%D \CONTEXT. Alternatively we could define them in each module
+%D but as they are part of the bigger picture we prefer to do
+%D it here.
+
+%D \macros
+%D {every...}
+%D
+%D A few every's. Some are only used in \MKII\ or \MKIV.
+
+%D Output routine:
+
+\newtoks \everybeforeoutput
+\newtoks \everyafteroutput
+
+%D Shipout:
+
+\newtoks \everyshipout
+\newtoks \everybeforeshipout
+\newtoks \everyaftershipout
+\newtoks \everyfirstshipout
+\newtoks \everylastshipout
+
+%D End of run:
+
+\newtoks \everybye
+\newtoks \everygoodbye
+\newtoks \everynotabene
+
+%D Document
+
+\newtoks \everysetupdocument
+\newtoks \everyendoftextbody
+
+\newtoks \everystarttext
+\newtoks \everystoptext
+
+%D Purity:
+
+\newtoks \everyforgetall
+\newtoks \everycleanupfeatures
+
+\def\cleanupfeatures{\the\everycleanupfeatures}
+\def\forgetall {\the\everyforgetall}
+
+%D Page building:
+
+\newtoks \everybeforepagebody
+\newtoks \everyafterpagebody
+
+\let \everypagebody \everybeforepagebody % backward compatible
+
+%D Multipass:
+
+\newtoks \everybeforeutilityread
+\newtoks \everyafterutilityread
+
+%D Floats:
+
+\newtoks \everyinsidefloat
+
+%D Sectioning:
+
+\newtoks \everyheadstart
+
+%D Par building (experimental, used in xml
..
)
+
+\newtoks \everybeginofpar
+\newtoks \everyendofpar
+%newtoks \everyparflush
+
+\def\bpar{\the\everybeginofpar\ignorespaces} % may interfere with \everypar
+\def\epar{\ifhmode\removeunwantedspaces\the\everyendofpar\fi} % test prevents problems with \bpar\epar
+
+%D Lists:
+
+\newtoks \everylistentry
+\newtoks \everysavesortkeys
+
+%D Marks:
+
+\newtoks \everymarking
+
+%D Fonts:
+
+\newtoks \everyfont
+\newtoks \everyglobalbodyfont
+\newtoks \everydefinedfont
+
+\newevery \everybodyfont \EveryBodyFont
+\newevery \everyfontswitch \EveryFontSwitch
+
+%D Math:
+
+\newtoks \everybeforedisplayformula
+\newtoks \everymathematics
+
+\prependtoks \the\everymathematics \to \everymath
+\prependtoks \the\everymathematics \to \everydisplay
+
+%D Tables
+
+\newtoks \everytable
+
+%D State mess:
+
+\newtoks \everypushsomestate
+\newtoks \everypopsomestate
+
+\def\pushsomestates{\the\everypushsomestate}
+\def\popsomestates {\the\everypopsomestate }
+
+%D More generic (used to be pushcolor etc)
+
+\newtoks\everypushproperties
+\newtoks\everypopproperties
+\newtoks\everypopsplitproperties
+
+\newtoks\everystarttextproperties
+\newtoks\everystoptextproperties
+
+\def\pushproperties {\the\everypushproperties}
+\def\popproperties {\the\everypopproperties}
+\def\popsplitproperties {\the\everypopsplitproperties}
+
+\def\starttextproperties{\the\everystarttextproperties}
+\def\stoptextproperties {\the\everystoptextproperties}
+
+%D This is pretty important (esp since we now ignore shipouts).
+%D Actually we should nil all writes, marks, specials.
+
+\appendtoks \globallet\popproperties \relax \to \everylastshipout
+\appendtoks \globallet\popsplitproperties\relax \to \everylastshipout
+
+%D \macros
+%D {defineinputmode,setinputmode}
+%D
+%D New. Some work needs to be done.
+
+% not in mkiv
+
+\def\defineinputmode[#1]{\@EA\newtoks\csname every#1inputmode\endcsname}
+\def\setinputmode [#1]{\the\executeifdefined{every#1inputmode}\emptytoks}
+
+\defineinputmode [TEX]
+\defineinputmode [XML]
+
+\setinputmode [TEX]
+
+%D \macros
+%D {trialtypesetting}
+%D
+%D We disable trial typesetting in the output routine,
+%D just to be sure.
+
+\newif\iftrialtypesetting
+
+\prependtoks \trialtypesettingfalse \to \everybeforepagebody
+
+%D \macros
+%D {ifinpagebody,ifinsidecolumns,ifdoublesided,ifsinglesided}
+
+\newif \ifinpagebody
+\newif \ifinsidecolumns
+\newif \ifdoublesided \doublesidedfalse
+\newif \ifsinglesided \singlesidedtrue
+\newif \ifinsidefloat
+\newif \ifdoingblocks
+\newif \ifgridsnapping
+
+%D \macros
+%D {ifprocessingXML}
+%D
+%D We need this one even if no \XML\ is supported.
+
+\newif\ifprocessingXML % old way
+
+%D \macros
+%D {ifproductionrun}
+%D
+%D This boolean can be used to bypass certain
+%D initializations.
+
+\ifx\protectionlevel\undefined \newcount\protectionlevel \fi
+
+\newif\ifproductionrun
+
+\appendtoks \productionruntrue \to \everydump
+
+\appendtoks \ifcase\protectionlevel\else\reportunprotection\fi \to \everydump
+
+%D \macros
+%D {everyboxedcontent, ifboxedcontent,
+%D startboxedcontent, stopboxedcontent}
+%D
+%D This one is relatively new and will be used as a more
+%D robust test for inner situations.
+
+\newif \ifboxedcontent
+\newtoks\everyboxedcontent
+
+\appendtoks \boxedcontenttrue \to \everyboxedcontent
+
+\def\startboxedcontent{\bgroup\the\everyboxedcontent}
+\let\stopboxedcontent \egroup
+
+%D \macros
+%D {fastmode,silentmode}
+%D
+%D These commands are obsolete.
+
+\let\fastmode \relax
+\let\silentmode\relax
+
+%D \macros
+%D {defineselector,setupselector}
+%D
+%D \starttyping
+%D \defineselector[caption][max=2,n=2]
+%D
+%D \start
+%D \setupselector[caption][n=1]
+%D \placelist[figure][criterium=all]
+%D \stop
+%D
+%D \starttext
+%D \placefigure
+%D {\select{caption}{zapf}{\input zapf \relax}}
+%D {}
+%D \stoptext
+%D \stoptyping
+
+\def\defineselector{\dodoubleargument\dodefineselector}
+\def\setupselector {\dodoubleargument\dosetupselector}
+
+\def\dodefineselector[#1][#2]{\getparameters[\??sx#1][\c!max=2,\c!n=1,#2]}
+\def\dosetupselector [#1][#2]{\getparameters[\??sx#1][#2]}
+
+\unexpanded\def\select#1%
+ {\filterfromnext
+ {\executeifdefined{\??sx#1\c!max}1}
+ {\executeifdefined{\??sx#1\c!n }1}}
+
+%D We store some original meanings, maybe in \type
+%D {math-ini}.
+
+\let\normalat \at
+\let\normalin \in
+\let\normalfrom \from
+%let\normalover \over
+\let\normalabout\about
+
+%D Add-ons:
+
+\let\startlayoutcomponent\gobbletwoarguments
+\let\stoplayoutcomponent \relax
+
+%D Concepts:
+
+\chardef\conceptmode\zerocount
+
+\def\doifconcepttracing
+ {\ifnum\conceptmode>\plustwo
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\protect \endinput
diff --git a/tex/context/base/core-var.mkiv b/tex/context/base/core-var.mkiv
new file mode 100644
index 000000000..62cc9fc50
--- /dev/null
+++ b/tex/context/base/core-var.mkiv
@@ -0,0 +1,270 @@
+%D \module
+%D [ file=core-var,
+%D version=1998.02.21,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Variables,
+%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 Core Macros / Variables}
+
+\unprotect
+
+%D We introduce a couple of variables that are used all over
+%D \CONTEXT. Alternatively we could define them in each module
+%D but as they are part of the bigger picture we prefer to do
+%D it here.
+
+%D \macros
+%D {every...}
+%D
+%D A few every's. Some are only used in \MKII\ or \MKIV.
+
+%D Output routine:
+
+\newtoks \everybeforeoutput
+\newtoks \everyafteroutput
+
+%D Shipout:
+
+\newtoks \everyshipout
+\newtoks \everybeforeshipout
+\newtoks \everyaftershipout
+\newtoks \everyfirstshipout
+\newtoks \everylastshipout
+
+%D End of run:
+
+\newtoks \everybye
+\newtoks \everygoodbye
+\newtoks \everynotabene
+
+%D Document
+
+\newtoks \everysetupdocument
+\newtoks \everyendoftextbody
+
+\newtoks \everystarttext
+\newtoks \everystoptext
+
+%D Purity:
+
+\newtoks \everyforgetall
+\newtoks \everycleanupfeatures
+
+\def\cleanupfeatures{\the\everycleanupfeatures}
+\def\forgetall {\the\everyforgetall}
+
+%D Page building:
+
+\newtoks \everybeforepagebody
+\newtoks \everyafterpagebody
+
+\let \everypagebody \everybeforepagebody % backward compatible
+
+%D Multipass:
+
+\newtoks \everybeforeutilityread
+\newtoks \everyafterutilityread
+
+%D Floats:
+
+\newtoks \everyinsidefloat
+
+%D Sectioning:
+
+\newtoks \everyheadstart
+
+%D Par building (experimental, used in xml
..
)
+
+\newtoks \everybeginofpar
+\newtoks \everyendofpar
+%newtoks \everyparflush
+
+\def\bpar{\the\everybeginofpar\ignorespaces} % may interfere with \everypar
+\def\epar{\ifhmode\removeunwantedspaces\the\everyendofpar\fi} % test prevents problems with \bpar\epar
+
+%D Lists:
+
+\newtoks \everylistentry
+\newtoks \everysavesortkeys
+
+%D Marks:
+
+\newtoks \everymarking
+
+%D Fonts:
+
+\newtoks \everyfont
+\newtoks \everyglobalbodyfont
+\newtoks \everydefinedfont
+
+\newevery \everybodyfont \EveryBodyFont
+\newevery \everyfontswitch \EveryFontSwitch
+
+\newtoks \everysetupbodyfont
+\newtoks \everyswitchtobodyfont
+
+%D Math:
+
+\newtoks \everybeforedisplayformula
+\newtoks \everymathematics
+
+\prependtoks \the\everymathematics \to \everymath
+\prependtoks \the\everymathematics \to \everydisplay
+
+%D Tables
+
+\newtoks \everytable
+
+%D State mess:
+
+\newtoks \everypushsomestate
+\newtoks \everypopsomestate
+
+\def\pushsomestates{\the\everypushsomestate}
+\def\popsomestates {\the\everypopsomestate }
+
+%D More generic (used to be pushcolor etc)
+
+\newtoks\everystarttextproperties
+\newtoks\everystoptextproperties
+
+\unexpanded\def\starttextproperties{\the\everystarttextproperties}
+\unexpanded\def\stoptextproperties {\the\everystoptextproperties}
+
+%D \macros
+%D {defineinputmode,setinputmode}
+%D
+%D New. Some work needs to be done.
+
+% not in mkiv
+
+\unexpanded\def\defineinputmode[#1]{\@EA\newtoks\csname every#1inputmode\endcsname}
+\def\setinputmode [#1]{\the\executeifdefined{every#1inputmode}\emptytoks}
+
+\defineinputmode [TEX]
+\defineinputmode [XML]
+
+\setinputmode [TEX]
+
+%D \macros
+%D {trialtypesetting}
+%D
+%D We disable trial typesetting in the output routine,
+%D just to be sure.
+
+\newif\iftrialtypesetting
+
+\prependtoks \trialtypesettingfalse \to \everybeforepagebody
+
+%D \macros
+%D {ifinpagebody,ifinsidecolumns,ifdoublesided,ifsinglesided}
+
+\newif \ifinpagebody
+\newif \ifinsidecolumns
+\newif \ifdoublesided \doublesidedfalse
+\newif \ifsinglesided \singlesidedtrue
+\newif \ifinsidefloat
+\newif \ifdoingblocks
+\newif \ifgridsnapping
+
+%D \macros
+%D {ifprocessingXML}
+%D
+%D We need this one even if no \XML\ is supported.
+
+\newif\ifprocessingXML % old way
+
+%D \macros
+%D {ifproductionrun}
+%D
+%D This boolean can be used to bypass certain
+%D initializations.
+
+\newif\ifproductionrun \appendtoks \productionruntrue \to \everydump
+
+%D \macros
+%D {everyboxedcontent, ifboxedcontent,
+%D startboxedcontent, stopboxedcontent}
+%D
+%D This one is relatively new and will be used as a more
+%D robust test for inner situations.
+
+\newif \ifboxedcontent
+\newtoks\everyboxedcontent
+
+\appendtoks \boxedcontenttrue \to \everyboxedcontent
+
+\unexpanded\def\startboxedcontent{\bgroup\the\everyboxedcontent}
+\let\stopboxedcontent \egroup
+
+%D \macros
+%D {fastmode,silentmode}
+%D
+%D These commands are obsolete.
+
+\let\fastmode \relax
+\let\silentmode\relax
+
+%D \macros
+%D {defineselector,setupselector}
+%D
+%D \starttyping
+%D \defineselector[caption][max=2,n=2]
+%D
+%D \start
+%D \setupselector[caption][n=1]
+%D \placelist[figure][criterium=all]
+%D \stop
+%D
+%D \starttext
+%D \placefigure
+%D {\select{caption}{zapf}{\input zapf \relax}}
+%D {}
+%D \stoptext
+%D \stoptyping
+
+\unexpanded\def\defineselector{\dodoubleargument\dodefineselector}
+\unexpanded\def\setupselector {\dodoubleargument\dosetupselector}
+
+\def\dodefineselector[#1][#2]{\getparameters[\??sx#1][\c!max=2,\c!n=1,#2]}
+\def\dosetupselector [#1][#2]{\getparameters[\??sx#1][#2]}
+
+\unexpanded\def\select#1%
+ {\filterfromnext
+ {\executeifdefined{\??sx#1\c!max}1}
+ {\executeifdefined{\??sx#1\c!n }1}}
+
+%D We store some original meanings, maybe in \type
+%D {math-ini}.
+
+\let\normalat \at
+\let\normalin \in
+\let\normalfrom \from
+%let\normalover \over
+\let\normalabout\about
+
+%D Add-ons:
+
+\let\setlayoutcomponentattribute \gobbletwoarguments
+\let\resetlayoutcomponentattribute\relax
+\let\layoutcomponentboxattribute \empty
+
+%D Concepts:
+
+\chardef\conceptmode\zerocount
+
+\def\doifconcepttracing
+ {\ifnum\conceptmode>\plustwo
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\protect \endinput
diff --git a/tex/context/base/data-aux.lua b/tex/context/base/data-aux.lua
new file mode 100644
index 000000000..26e1f551c
--- /dev/null
+++ b/tex/context/base/data-aux.lua
@@ -0,0 +1,57 @@
+if not modules then modules = { } end modules ['data-aux'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
+
+function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
+ local scriptpath = "scripts/context/lua"
+ newname = file.addsuffix(newname,"lua")
+ local oldscript = resolvers.clean_path(oldname)
+ if trace_locating then
+ logs.report("fileio","to be replaced old script %s", oldscript)
+ end
+ local newscripts = resolvers.find_files(newname) or { }
+ if #newscripts == 0 then
+ if trace_locating then
+ logs.report("fileio","unable to locate new script")
+ end
+ else
+ for i=1,#newscripts do
+ local newscript = resolvers.clean_path(newscripts[i])
+ if trace_locating then
+ logs.report("fileio","checking new script %s", newscript)
+ end
+ if oldscript == newscript then
+ if trace_locating then
+ logs.report("fileio","old and new script are the same")
+ end
+ elseif not find(newscript,scriptpath) then
+ if trace_locating then
+ logs.report("fileio","new script should come from %s",scriptpath)
+ end
+ elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+ if trace_locating then
+ logs.report("fileio","invalid new script name")
+ end
+ else
+ local newdata = io.loaddata(newscript)
+ if newdata then
+ if trace_locating then
+ logs.report("fileio","old script content replaced by new content")
+ end
+ io.savedata(oldscript,newdata)
+ break
+ elseif trace_locating then
+ logs.report("fileio","unable to load new script")
+ end
+ end
+ end
+ end
+end
diff --git a/tex/context/base/data-bin.lua b/tex/context/base/data-bin.lua
new file mode 100644
index 000000000..5e4397a54
--- /dev/null
+++ b/tex/context/base/data-bin.lua
@@ -0,0 +1,27 @@
+if not modules then modules = { } end modules ['data-bin'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+local unpack = unpack or table.unpack
+
+function resolvers.findbinfile(filename, filetype)
+ return resolvers.methodhandler('finders',filename, filetype)
+end
+
+function resolvers.openbinfile(filename)
+ return resolvers.methodhandler('loaders',filename)
+end
+
+function resolvers.loadbinfile(filename, filetype)
+ local fname = resolvers.methodhandler('finders',filename, filetype)
+ if fname and fname ~= "" then
+ return resolvers.openbinfile(fname)
+ else
+ return unpack(loaders.notfound)
+ end
+end
diff --git a/tex/context/base/data-con.lua b/tex/context/base/data-con.lua
new file mode 100644
index 000000000..fabe0baa1
--- /dev/null
+++ b/tex/context/base/data-con.lua
@@ -0,0 +1,120 @@
+if not modules then modules = { } end modules ['data-con'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
+local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
+
+--[[ldx--
+
Once we found ourselves defining similar cache constructs
+several times, containers were introduced. Containers are used
+to collect tables in memory and reuse them when possible based
+on (unique) hashes (to be provided by the calling function).
+
+
Caching to disk is disabled by default. Version numbers are
+stored in the saved table which makes it possible to change the
+table structures without bothering about the disk cache.
+
+
Examples of usage can be found in the font related code.
+--ldx]]--
+
+containers = containers or { }
+
+containers.usecache = true
+
+local function report(container,tag,name)
+ if trace_cache or trace_containers then
+ logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
+ end
+end
+
+local allocated = { }
+
+-- tracing
+
+function containers.define(category, subcategory, version, enabled)
+ return function()
+ if category and subcategory then
+ local c = allocated[category]
+ if not c then
+ c = { }
+ allocated[category] = c
+ end
+ local s = c[subcategory]
+ if not s then
+ s = {
+ category = category,
+ subcategory = subcategory,
+ storage = { },
+ enabled = enabled,
+ version = version or 1.000,
+ trace = false,
+ path = caches and caches.setpath and caches.setpath(category,subcategory),
+ }
+ c[subcategory] = s
+ end
+ return s
+ else
+ return nil
+ end
+ end
+end
+
+function containers.is_usable(container, name)
+ return container.enabled and caches and caches.iswritable(container.path, name)
+end
+
+function containers.is_valid(container, name)
+ if name and name ~= "" then
+ local storage = container.storage[name]
+ return storage and storage.cache_version == container.version
+ else
+ return false
+ end
+end
+
+function containers.read(container,name)
+ if container.enabled and caches and not container.storage[name] and containers.usecache then
+ container.storage[name] = caches.loaddata(container.path,name)
+ if containers.is_valid(container,name) then
+ report(container,"loaded",name)
+ else
+ container.storage[name] = nil
+ end
+ end
+ if container.storage[name] then
+ report(container,"reusing",name)
+ end
+ return container.storage[name]
+end
+
+function containers.write(container, name, data)
+ if data then
+ data.cache_version = container.version
+ if container.enabled and caches then
+ local unique, shared = data.unique, data.shared
+ data.unique, data.shared = nil, nil
+ caches.savedata(container.path, name, data)
+ report(container,"saved",name)
+ data.unique, data.shared = unique, shared
+ end
+ report(container,"stored",name)
+ container.storage[name] = data
+ end
+ return data
+end
+
+function containers.content(container,name)
+ return container.storage[name]
+end
+
+function containers.cleanname(name)
+ return (gsub(lower(name),"[^%w%d]+","-"))
+end
diff --git a/tex/context/base/data-crl.lua b/tex/context/base/data-crl.lua
new file mode 100644
index 000000000..55b1a8fad
--- /dev/null
+++ b/tex/context/base/data-crl.lua
@@ -0,0 +1,60 @@
+if not modules then modules = { } end modules ['data-crl'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local gsub = string.gsub
+
+curl = curl or { }
+
+curl.cached = { }
+curl.cachepath = caches.definepath("curl")
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+function curl.fetch(protocol, name)
+ local cachename = curl.cachepath() .. "/" .. gsub(name,"[^%a%d%.]+","-")
+-- cachename = gsub(cachename,"[\\/]", io.fileseparator)
+ cachename = gsub(cachename,"[\\]", "/") -- cleanup
+ if not curl.cached[name] then
+ if not io.exists(cachename) then
+ curl.cached[name] = cachename
+ local command = "curl --silent --create-dirs --output " .. cachename .. " " .. name -- no protocol .. "://"
+ os.spawn(command)
+ end
+ if io.exists(cachename) then
+ curl.cached[name] = cachename
+ else
+ curl.cached[name] = ""
+ end
+ end
+ return curl.cached[name]
+end
+
+function finders.curl(protocol,filename)
+ local foundname = curl.fetch(protocol, filename)
+ return finders.generic(protocol,foundname,filetype)
+end
+
+function openers.curl(protocol,filename)
+ return openers.generic(protocol,filename)
+end
+
+function loaders.curl(protocol,filename)
+ return loaders.generic(protocol,filename)
+end
+
+-- todo: metamethod
+
+function curl.install(protocol)
+ finders[protocol] = function (filename,filetype) return finders.curl(protocol,filename) end
+ openers[protocol] = function (filename) return openers.curl(protocol,filename) end
+ loaders[protocol] = function (filename) return loaders.curl(protocol,filename) end
+end
+
+curl.install('http')
+curl.install('https')
+curl.install('ftp')
diff --git a/tex/context/base/data-ctx.lua b/tex/context/base/data-ctx.lua
new file mode 100644
index 000000000..89eb2742d
--- /dev/null
+++ b/tex/context/base/data-ctx.lua
@@ -0,0 +1,31 @@
+if not modules then modules = { } end modules ['data-ctx'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+function resolvers.save_used_files_in_trees(filename,jobname)
+ if not filename then filename = 'luatex.jlg' end
+ local found = instance.foundintrees
+ local f = io.open(filename,'w')
+ if f then
+ f:write("\n")
+ f:write("\n")
+ if jobname then
+ f:write(format("\t%s\n",jobname))
+ end
+ f:write("\t\n")
+ local sorted = table.sortedkeys(found)
+ for k=1,#sorted do
+ local v = sorted[k]
+ f:write(format("\t\t%s\n",found[v],v))
+ end
+ f:write("\t\n")
+ f:write("\n")
+ f:close()
+ end
+end
diff --git a/tex/context/base/data-gen.lua b/tex/context/base/data-gen.lua
new file mode 100644
index 000000000..5a0755831
--- /dev/null
+++ b/tex/context/base/data-gen.lua
@@ -0,0 +1,9 @@
+if not modules then modules = { } end modules ['data-gen'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- move generators here
diff --git a/tex/context/base/data-inp.lua b/tex/context/base/data-inp.lua
new file mode 100644
index 000000000..b7354e1ae
--- /dev/null
+++ b/tex/context/base/data-inp.lua
@@ -0,0 +1,15 @@
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+resolvers.finders = resolvers.finders or { }
+resolvers.openers = resolvers.openers or { }
+resolvers.loaders = resolvers.loaders or { }
+
+resolvers.finders.notfound = { nil }
+resolvers.openers.notfound = { nil }
+resolvers.loaders.notfound = { false, nil, 0 }
diff --git a/tex/context/base/data-kps.lua b/tex/context/base/data-kps.lua
new file mode 100644
index 000000000..09d502409
--- /dev/null
+++ b/tex/context/base/data-kps.lua
@@ -0,0 +1,101 @@
+if not modules then modules = { } end modules ['luat-kps'] = {
+ version = 1.001,
+ comment = "companion to luatools.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+
This file is used when we want the input handlers to behave like
+kpsewhich. What to do with the following:
If you wondered abou tsome of the previous mappings, how about
+the next bunch:
+--ldx]]--
+
+formats['bib'] = ''
+formats['bst'] = ''
+formats['mft'] = ''
+formats['ist'] = ''
+formats['web'] = ''
+formats['cweb'] = ''
+formats['MetaPost support'] = ''
+formats['TeX system documentation'] = ''
+formats['TeX system sources'] = ''
+formats['Troff fonts'] = ''
+formats['dvips config'] = ''
+formats['graphic/figure'] = ''
+formats['ls-R'] = ''
+formats['other text files'] = ''
+formats['other binary files'] = ''
+
+formats['gf'] = ''
+formats['pk'] = ''
+formats['base'] = 'MFBASES'
+formats['cnf'] = ''
+formats['mem'] = 'MPMEMS'
+formats['mf'] = 'MFINPUTS'
+formats['mfpool'] = 'MFPOOL'
+formats['mppool'] = 'MPPOOL'
+formats['texpool'] = 'TEXPOOL'
+formats['PostScript header'] = 'TEXPSHEADERS'
+formats['cmap files'] = 'CMAPFONTS'
+formats['type42 fonts'] = 'T42FONTS'
+formats['web2c files'] = 'WEB2C'
+formats['pdftex config'] = 'PDFTEXCONFIG'
+formats['texmfscripts'] = 'TEXMFSCRIPTS'
+formats['bitmap font'] = ''
+formats['lig files'] = 'LIGFONTS'
diff --git a/tex/context/base/data-lst.lua b/tex/context/base/data-lst.lua
new file mode 100644
index 000000000..82f675486
--- /dev/null
+++ b/tex/context/base/data-lst.lua
@@ -0,0 +1,63 @@
+if not modules then modules = { } end modules ['data-lst'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- used in mtxrun
+
+local find, concat, upper, format = string.find, table.concat, string.upper, string.format
+
+resolvers.listers = resolvers.listers or { }
+
+local function tabstr(str)
+ if type(str) == 'table' then
+ return concat(str," | ")
+ else
+ return str
+ end
+end
+
+local function list(list,report)
+ local instance = resolvers.instance
+ local pat = upper(pattern or "","")
+ local report = report or texio.write_nl
+ local sorted = table.sortedkeys(list)
+ for i=1,#sorted do
+ local key = sorted[i]
+ if instance.pattern == "" or find(upper(key),pat) then
+ if instance.kpseonly then
+ if instance.kpsevars[key] then
+ report(format("%s=%s",key,tabstr(list[key])))
+ end
+ else
+ report(format('%s %s=%s',(instance.kpsevars[key] and 'K') or 'E',key,tabstr(list[key])))
+ end
+ end
+ end
+end
+
+function resolvers.listers.variables () list(resolvers.instance.variables ) end
+function resolvers.listers.expansions() list(resolvers.instance.expansions) end
+
+function resolvers.listers.configurations(report)
+ local report = report or texio.write_nl
+ local instance = resolvers.instance
+ local sorted = table.sortedkeys(instance.kpsevars)
+ for i=1,#sorted do
+ local key = sorted[i]
+ if not instance.pattern or (instance.pattern=="") or find(key,instance.pattern) then
+ report(format("%s\n",key))
+ local order = instance.order
+ for i=1,#order do
+ local str = order[i][key]
+ if str then
+ report(format("\t%s\t%s",i,str))
+ end
+ end
+ report("")
+ end
+ end
+end
diff --git a/tex/context/base/data-lua.lua b/tex/context/base/data-lua.lua
new file mode 100644
index 000000000..988133fbe
--- /dev/null
+++ b/tex/context/base/data-lua.lua
@@ -0,0 +1,152 @@
+if not modules then modules = { } end modules ['data-lua'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- some loading stuff ... we might move this one to slot 2 depending
+-- on the developments (the loaders must not trigger kpse); we could
+-- of course use a more extensive lib path spec
+
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
+
+local gsub, insert = string.gsub, table.insert
+local unpack = unpack or table.unpack
+
+local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs'
+local clibformats = { 'lib' }
+
+local _path_, libpaths, _cpath_, clibpaths
+
+function package.libpaths()
+ if not _path_ or package.path ~= _path_ then
+ _path_ = package.path
+ libpaths = file.split_path(_path_,";")
+ end
+ return libpaths
+end
+
+function package.clibpaths()
+ if not _cpath_ or package.cpath ~= _cpath_ then
+ _cpath_ = package.cpath
+ clibpaths = file.split_path(_cpath_,";")
+ end
+ return clibpaths
+end
+
+local function thepath(...)
+ local t = { ... } t[#t+1] = "?.lua"
+ local path = file.join(unpack(t))
+ if trace_locating then
+ logs.report("fileio","! appending '%s' to 'package.path'",path)
+ end
+ return path
+end
+
+local p_libpaths, a_libpaths = { }, { }
+
+function package.append_libpath(...)
+ insert(a_libpath,thepath(...))
+end
+
+function package.prepend_libpath(...)
+ insert(p_libpaths,1,thepath(...))
+end
+
+-- beware, we need to return a loadfile result !
+
+local function loaded(libpaths,name,simple)
+ for i=1,#libpaths do -- package.path, might become option
+ local libpath = libpaths[i]
+ local resolved = gsub(libpath,"%?",simple)
+ if trace_locating then -- more detail
+ logs.report("fileio","! checking for '%s' on 'package.path': '%s' => '%s'",simple,libpath,resolved)
+ end
+ if resolvers.isreadable.file(resolved) then
+ if trace_locating then
+ logs.report("fileio","! lib '%s' located via 'package.path': '%s'",name,resolved)
+ end
+ return loadfile(resolved)
+ end
+ end
+end
+
+
+package.loaders[2] = function(name) -- was [#package.loaders+1]
+ if trace_locating then -- mode detail
+ logs.report("fileio","! locating '%s'",name)
+ end
+ for i=1,#libformats do
+ local format = libformats[i]
+ local resolved = resolvers.find_file(name,format) or ""
+ if trace_locating then -- mode detail
+ logs.report("fileio","! checking for '%s' using 'libformat path': '%s'",name,format)
+ end
+ if resolved ~= "" then
+ if trace_locating then
+ logs.report("fileio","! lib '%s' located via environment: '%s'",name,resolved)
+ end
+ return loadfile(resolved)
+ end
+ end
+ -- libpaths
+ local libpaths, clibpaths = package.libpaths(), package.clibpaths()
+ local simple = gsub(name,"%.lua$","")
+ local simple = gsub(simple,"%.","/")
+ local resolved = loaded(p_libpaths,name,simple) or loaded(libpaths,name,simple) or loaded(a_libpaths,name,simple)
+ if resolved then
+ return resolved
+ end
+ --
+ local libname = file.addsuffix(simple,os.libsuffix)
+ for i=1,#clibformats do
+ -- better have a dedicated loop
+ local format = clibformats[i]
+ local paths = resolvers.expanded_path_list_from_var(format)
+ for p=1,#paths do
+ local path = paths[p]
+ local resolved = file.join(path,libname)
+ if trace_locating then -- mode detail
+ logs.report("fileio","! checking for '%s' using 'clibformat path': '%s'",libname,path)
+ end
+ if resolvers.isreadable.file(resolved) then
+ if trace_locating then
+ logs.report("fileio","! lib '%s' located via 'clibformat': '%s'",libname,resolved)
+ end
+ return package.loadlib(resolved,name)
+ end
+ end
+ end
+ for i=1,#clibpaths do -- package.path, might become option
+ local libpath = clibpaths[i]
+ local resolved = gsub(libpath,"?",simple)
+ if trace_locating then -- more detail
+ logs.report("fileio","! checking for '%s' on 'package.cpath': '%s'",simple,libpath)
+ end
+ if resolvers.isreadable.file(resolved) then
+ if trace_locating then
+ logs.report("fileio","! lib '%s' located via 'package.cpath': '%s'",name,resolved)
+ end
+ return package.loadlib(resolved,name)
+ end
+ end
+ -- just in case the distribution is messed up
+ if trace_loading then -- more detail
+ logs.report("fileio","! checking for '%s' using 'luatexlibs': '%s'",name)
+ end
+ local resolved = resolvers.find_file(file.basename(name),'luatexlibs') or ""
+ if resolved ~= "" then
+ if trace_locating then
+ logs.report("fileio","! lib '%s' located by basename via environment: '%s'",name,resolved)
+ end
+ return loadfile(resolved)
+ end
+ if trace_locating then
+ logs.report("fileio",'? unable to locate lib: %s',name)
+ end
+-- return "unable to locate " .. name
+end
+
+resolvers.loadlualib = require
diff --git a/tex/context/base/data-out.lua b/tex/context/base/data-out.lua
new file mode 100644
index 000000000..f73ff9bdc
--- /dev/null
+++ b/tex/context/base/data-out.lua
@@ -0,0 +1,10 @@
+if not modules then modules = { } end modules ['data-out'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+outputs = outputs or { }
+
diff --git a/tex/context/base/data-pre.lua b/tex/context/base/data-pre.lua
new file mode 100644
index 000000000..9348f6cd3
--- /dev/null
+++ b/tex/context/base/data-pre.lua
@@ -0,0 +1,109 @@
+if not modules then modules = { } end modules ['data-res'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--~ print(resolvers.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex"))
+
+local upper, lower, gsub = string.upper, string.lower, string.gsub
+
+local prefixes = { }
+
+prefixes.environment = function(str)
+ return resolvers.clean_path(os.getenv(str) or os.getenv(upper(str)) or os.getenv(lower(str)) or "")
+end
+
+prefixes.relative = function(str,n)
+ if io.exists(str) then
+ -- nothing
+ elseif io.exists("./" .. str) then
+ str = "./" .. str
+ else
+ local p = "../"
+ for i=1,n or 2 do
+ if io.exists(p .. str) then
+ str = p .. str
+ break
+ else
+ p = p .. "../"
+ end
+ end
+ end
+ return resolvers.clean_path(str)
+end
+
+prefixes.auto = function(str)
+ local fullname = prefixes.relative(str)
+ if not lfs.isfile(fullname) then
+ fullname = prefixes.locate(str)
+ end
+ return fullname
+end
+
+prefixes.locate = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path((fullname ~= "" and fullname) or str)
+end
+
+prefixes.filename = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.basename((fullname ~= "" and fullname) or str))
+end
+
+prefixes.pathname = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.dirname((fullname ~= "" and fullname) or str))
+end
+
+prefixes.env = prefixes.environment
+prefixes.rel = prefixes.relative
+prefixes.loc = prefixes.locate
+prefixes.kpse = prefixes.locate
+prefixes.full = prefixes.locate
+prefixes.file = prefixes.filename
+prefixes.path = prefixes.pathname
+
+function resolvers.allprefixes(separator)
+ local all = table.sortedkeys(prefixes)
+ if separator then
+ for i=1,#all do
+ all[i] = all[i] .. ":"
+ end
+ end
+ return all
+end
+
+local function _resolve_(method,target)
+ if prefixes[method] then
+ return prefixes[method](target)
+ else
+ return method .. ":" .. target
+ end
+end
+
+local function resolve(str)
+ if type(str) == "table" then
+ for k=1,#str do
+ local v = str[k]
+ str[k] = resolve(v) or v
+ end
+ elseif str and str ~= "" then
+ str = gsub(str,"([a-z]+):([^ \"\']*)",_resolve_)
+ end
+ return str
+end
+
+resolvers.resolve = resolve
+
+if os.uname then
+
+ for k, v in next, os.uname() do
+ if not prefixes[k] then
+ prefixes[k] = function() return v end
+ end
+ end
+
+end
diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua
new file mode 100644
index 000000000..ecef14188
--- /dev/null
+++ b/tex/context/base/data-res.lua
@@ -0,0 +1,2181 @@
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- After a few years using the code the large luat-inp.lua file
+-- has been split up a bit. In the process some functionality was
+-- dropped:
+--
+-- * support for reading lsr files
+-- * selective scanning (subtrees)
+-- * some public auxiliary functions were made private
+--
+-- TODO: os.getenv -> os.env[]
+-- TODO: instances.[hashes,cnffiles,configurations,522]
+-- TODO: check escaping in find etc, too much, too slow
+
+-- This lib is multi-purpose and can be loaded again later on so that
+-- additional functionality becomes available. We will split thislogs.report("fileio",
+-- module in components once we're done with prototyping. This is the
+-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
+-- something in this module one can best check with Taco or Hans first; there
+-- is some nasty trickery going on that relates to traditional kpse support.
+
+-- To be considered: hash key lowercase, first entry in table filename
+-- (any case), rest paths (so no need for optimization). Or maybe a
+-- separate table that matches lowercase names to mixed case when
+-- present. In that case the lower() cases can go away. I will do that
+-- only when we run into problems with names ... well ... Iwona-Regular.
+
+-- Beware, loading and saving is overloaded in luat-tmp!
+
+local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
+local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys
+local next, type = next, type
+local lpegmatch = lpeg.match
+
+local trace_locating, trace_detail, trace_expansions = false, false, false
+
+trackers.register("resolvers.locating", function(v) trace_locating = v end)
+trackers.register("resolvers.details", function(v) trace_detail = v end)
+trackers.register("resolvers.expansions", function(v) trace_expansions = v end) -- todo
+
+if not resolvers then
+ resolvers = {
+ suffixes = { },
+ formats = { },
+ dangerous = { },
+ suffixmap = { },
+ alternatives = { },
+ locators = { }, -- locate databases
+ hashers = { }, -- load databases
+ generators = { }, -- generate databases
+ }
+end
+
+local resolvers = resolvers
+
+resolvers.locators .notfound = { nil }
+resolvers.hashers .notfound = { nil }
+resolvers.generators.notfound = { nil }
+
+resolvers.cacheversion = '1.0.1'
+resolvers.cnfname = 'texmf.cnf'
+resolvers.luaname = 'texmfcnf.lua'
+resolvers.homedir = os.env[os.type == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+resolvers.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+local dummy_path_expr = "^!*unset/*$"
+
+local formats = resolvers.formats
+local suffixes = resolvers.suffixes
+local dangerous = resolvers.dangerous
+local suffixmap = resolvers.suffixmap
+local alternatives = resolvers.alternatives
+
+formats['afm'] = 'AFMFONTS' suffixes['afm'] = { 'afm' }
+formats['enc'] = 'ENCFONTS' suffixes['enc'] = { 'enc' }
+formats['fmt'] = 'TEXFORMATS' suffixes['fmt'] = { 'fmt' }
+formats['map'] = 'TEXFONTMAPS' suffixes['map'] = { 'map' }
+formats['mp'] = 'MPINPUTS' suffixes['mp'] = { 'mp' }
+formats['ocp'] = 'OCPINPUTS' suffixes['ocp'] = { 'ocp' }
+formats['ofm'] = 'OFMFONTS' suffixes['ofm'] = { 'ofm', 'tfm' }
+formats['otf'] = 'OPENTYPEFONTS' suffixes['otf'] = { 'otf' } -- 'ttf'
+formats['opl'] = 'OPLFONTS' suffixes['opl'] = { 'opl' }
+formats['otp'] = 'OTPINPUTS' suffixes['otp'] = { 'otp' }
+formats['ovf'] = 'OVFFONTS' suffixes['ovf'] = { 'ovf', 'vf' }
+formats['ovp'] = 'OVPFONTS' suffixes['ovp'] = { 'ovp' }
+formats['tex'] = 'TEXINPUTS' suffixes['tex'] = { 'tex' }
+formats['tfm'] = 'TFMFONTS' suffixes['tfm'] = { 'tfm' }
+formats['ttf'] = 'TTFONTS' suffixes['ttf'] = { 'ttf', 'ttc', 'dfont' }
+formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', 'pfa' }
+formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' }
+
+formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' }
+formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' }
+
+formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
+suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
+
+formats ['lua'] = 'LUAINPUTS' -- new
+suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+
+-- backward compatible ones
+
+alternatives['map files'] = 'map'
+alternatives['enc files'] = 'enc'
+alternatives['cid maps'] = 'cid' -- great, why no cid files
+alternatives['font feature files'] = 'fea' -- and fea files here
+alternatives['opentype fonts'] = 'otf'
+alternatives['truetype fonts'] = 'ttf'
+alternatives['truetype collections'] = 'ttc'
+alternatives['truetype dictionary'] = 'dfont'
+alternatives['type1 fonts'] = 'pfb'
+
+-- obscure ones
+
+formats ['misc fonts'] = ''
+suffixes['misc fonts'] = { }
+
+formats ['sfd'] = 'SFDFONTS'
+suffixes ['sfd'] = { 'sfd' }
+alternatives['subfont definition files'] = 'sfd'
+
+-- lib paths
+
+formats ['lib'] = 'CLUAINPUTS' -- new (needs checking)
+suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' }
+
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
+
+-- here we catch a few new thingies (todo: add these paths to context.tmf)
+--
+-- FONTFEATURES = .;$TEXMF/fonts/fea//
+-- FONTCIDMAPS = .;$TEXMF/fonts/cid//
+
+-- we always have one instance active
+
+resolvers.instance = resolvers.instance or nil -- the current one (slow access)
+local instance = resolvers.instance or nil -- the current one (fast access)
+
+function resolvers.newinstance()
+
+ -- store once, freeze and faster (once reset we can best use
+ -- instance.environment) maybe better have a register suffix
+ -- function
+
+ for k, v in next, suffixes do
+ for i=1,#v do
+ local vi = v[i]
+ if vi then
+ suffixmap[vi] = k
+ end
+ end
+ end
+
+ -- because vf searching is somewhat dangerous, we want to prevent
+ -- too liberal searching esp because we do a lookup on the current
+ -- path anyway; only tex (or any) is safe
+
+ for k, v in next, formats do
+ dangerous[k] = true
+ end
+ dangerous.tex = nil
+
+ -- the instance
+
+ local newinstance = {
+ rootpath = '',
+ treepath = '',
+ progname = 'context',
+ engine = 'luatex',
+ format = '',
+ environment = { },
+ variables = { },
+ expansions = { },
+ files = { },
+ remap = { },
+ configuration = { },
+ setup = { },
+ order = { },
+ found = { },
+ foundintrees = { },
+ kpsevars = { },
+ hashes = { },
+ cnffiles = { },
+ luafiles = { },
+ lists = { },
+ remember = true,
+ diskcache = true,
+ renewcache = false,
+ scandisk = true,
+ cachepath = nil,
+ loaderror = false,
+ sortdata = false,
+ savelists = true,
+ cleanuppaths = true,
+ allresults = false,
+ pattern = nil, -- lists
+ data = { }, -- only for loading
+ force_suffixes = true,
+ fakepaths = { },
+ }
+
+ local ne = newinstance.environment
+
+ for k,v in next, os.env do
+ ne[k] = resolvers.bare_variable(v)
+ end
+
+ return newinstance
+
+end
+
+function resolvers.setinstance(someinstance)
+ instance = someinstance
+ resolvers.instance = someinstance
+ return someinstance
+end
+
+function resolvers.reset()
+ return resolvers.setinstance(resolvers.newinstance())
+end
+
+local function reset_hashes()
+ instance.lists = { }
+ instance.found = { }
+end
+
+local function check_configuration() -- not yet ok, no time for debugging now
+ local ie, iv = instance.environment, instance.variables
+ local function fix(varname,default)
+ local proname = varname .. "." .. instance.progname or "crap"
+ local p, v = ie[proname], ie[varname] or iv[varname]
+ if not ((p and p ~= "") or (v and v ~= "")) then
+ iv[varname] = default -- or environment?
+ end
+ end
+ local name = os.name
+ if name == "windows" then
+ fix("OSFONTDIR", "c:/windows/fonts//")
+ elseif name == "macosx" then
+ fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+ else
+ -- bad luck
+ end
+ fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
+ -- this will go away some day
+ fix("FONTFEATURES", ".;$TEXMF/fonts/{data,fea}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("FONTCIDMAPS" , ".;$TEXMF/fonts/{data,cid}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ --
+ fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//")
+end
+
+function resolvers.bare_variable(str) -- assumes str is a string
+ return (gsub(str,"\s*([\"\']?)(.+)%1\s*", "%2"))
+end
+
+function resolvers.settrace(n) -- no longer number but: 'locating' or 'detail'
+ if n then
+ trackers.disable("resolvers.*")
+ trackers.enable("resolvers."..n)
+ end
+end
+
+resolvers.settrace(os.getenv("MTX_INPUT_TRACE"))
+
+function resolvers.osenv(key)
+ local ie = instance.environment
+ local value = ie[key]
+ if value == nil then
+ -- local e = os.getenv(key)
+ local e = os.env[key]
+ if e == nil then
+ -- value = "" -- false
+ else
+ value = resolvers.bare_variable(e)
+ end
+ ie[key] = value
+ end
+ return value or ""
+end
+
+function resolvers.env(key)
+ return instance.environment[key] or resolvers.osenv(key)
+end
+
+--
+
+local function expand_vars(lst) -- simple vars
+ local variables, env = instance.variables, resolvers.env
+ local function resolve(a)
+ return variables[a] or env(a)
+ end
+ for k=1,#lst do
+ lst[k] = gsub(lst[k],"%$([%a%d%_%-]+)",resolve)
+ end
+end
+
+local function expanded_var(var) -- simple vars
+ local function resolve(a)
+ return instance.variables[a] or resolvers.env(a)
+ end
+ return (gsub(var,"%$([%a%d%_%-]+)",resolve))
+end
+
+local function entry(entries,name)
+ if name and (name ~= "") then
+ name = gsub(name,'%$','')
+ local result = entries[name..'.'..instance.progname] or entries[name]
+ if result then
+ return result
+ else
+ result = resolvers.env(name)
+ if result then
+ instance.variables[name] = result
+ resolvers.expand_variables()
+ return instance.expansions[name] or ""
+ end
+ end
+ end
+ return ""
+end
+
+local function is_entry(entries,name)
+ if name and name ~= "" then
+ name = gsub(name,'%$','')
+ return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+ else
+ return false
+ end
+end
+
+-- {a,b,c,d}
+-- a,b,c/{p,q,r},d
+-- a,b,c/{p,q,r}/d/{x,y,z}//
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {a,b,c/{p,q,r}/d/{x,y,z}//}
+-- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
+-- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
+
+-- this one is better and faster, but it took me a while to realize
+-- that this kind of replacement is cleaner than messy parsing and
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
+
+local function do_first(a,b)
+ local t = { }
+ for s in gmatch(b,"[^,]+") do t[#t+1] = a .. s end
+ return "{" .. concat(t,",") .. "}"
+end
+
+local function do_second(a,b)
+ local t = { }
+ for s in gmatch(a,"[^,]+") do t[#t+1] = s .. b end
+ return "{" .. concat(t,",") .. "}"
+end
+
+local function do_both(a,b)
+ local t = { }
+ for sa in gmatch(a,"[^,]+") do
+ for sb in gmatch(b,"[^,]+") do
+ t[#t+1] = sa .. sb
+ end
+ end
+ return "{" .. concat(t,",") .. "}"
+end
+
+local function do_three(a,b,c)
+ return a .. b.. c
+end
+
+local function splitpathexpr(str, t, validate)
+ -- no need for further optimization as it is only called a
+ -- few times, we can use lpeg for the sub
+ if trace_expansions then
+ logs.report("fileio","expanding variable '%s'",str)
+ end
+ t = t or { }
+ str = gsub(str,",}",",@}")
+ str = gsub(str,"{,","{@,")
+ -- str = "@" .. str .. "@"
+ local ok, done
+ while true do
+ done = false
+ while true do
+ str, ok = gsub(str,"([^{},]+){([^{}]+)}",do_first)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}([^{},]+)",do_second)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}{([^{}]+)}",do_both)
+ if ok > 0 then done = true else break end
+ end
+ str, ok = gsub(str,"({[^{}]*){([^{}]+)}([^{}]*})",do_three)
+ if ok > 0 then done = true end
+ if not done then break end
+ end
+ str = gsub(str,"[{}]", "")
+ str = gsub(str,"@","")
+ if validate then
+ for s in gmatch(str,"[^,]+") do
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end
+ else
+ for s in gmatch(str,"[^,]+") do
+ t[#t+1] = s
+ end
+ end
+ if trace_expansions then
+ for k=1,#t do
+ logs.report("fileio","% 4i: %s",k,t[k])
+ end
+ end
+ return t
+end
+
+local function expanded_path_from_list(pathlist) -- maybe not a list, just a path
+ -- a previous version fed back into pathlist
+ local newlist, ok = { }, false
+ for k=1,#pathlist do
+ if find(pathlist[k],"[{}]") then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ local function validate(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not find(s,dummy_path_expr) and s
+ end
+ for k=1,#pathlist do
+ splitpathexpr(pathlist[k],newlist,validate)
+ end
+ else
+ for k=1,#pathlist do
+ for p in gmatch(pathlist[k],"([^,]+)") do
+ p = file.collapse_path(p)
+ if p ~= "" then newlist[#newlist+1] = p end
+ end
+ end
+ end
+ return newlist
+end
+
+-- we follow a rather traditional approach:
+--
+-- (1) texmf.cnf given in TEXMFCNF
+-- (2) texmf.cnf searched in default variable
+--
+-- also we now follow the stupid route: if not set then just assume *one*
+-- cnf file under texmf (i.e. distribution)
+
+local args = environment and environment.original_arguments or arg -- this needs a cleanup
+
+resolvers.ownbin = resolvers.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex"
+resolvers.ownbin = gsub(resolvers.ownbin,"\\","/")
+
+function resolvers.getownpath()
+ local ownpath = resolvers.ownpath or os.selfdir
+ if not ownpath or ownpath == "" or ownpath == "unset" then
+ ownpath = args[-1] or arg[-1]
+ ownpath = ownpath and file.dirname(gsub(ownpath,"\\","/"))
+ if not ownpath or ownpath == "" then
+ ownpath = args[-0] or arg[-0]
+ ownpath = ownpath and file.dirname(gsub(ownpath,"\\","/"))
+ end
+ local binary = resolvers.ownbin
+ if not ownpath or ownpath == "" then
+ ownpath = ownpath and file.dirname(binary)
+ end
+ if not ownpath or ownpath == "" then
+ if os.binsuffix ~= "" then
+ binary = file.replacesuffix(binary,os.binsuffix)
+ end
+ for p in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+ local b = file.join(p,binary)
+ if lfs.isfile(b) then
+ -- we assume that after changing to the path the currentdir function
+ -- resolves to the real location and use this side effect here; this
+ -- trick is needed because on the mac installations use symlinks in the
+ -- path instead of real locations
+ local olddir = lfs.currentdir()
+ if lfs.chdir(p) then
+ local pp = lfs.currentdir()
+ if trace_locating and p ~= pp then
+ logs.report("fileio","following symlink '%s' to '%s'",p,pp)
+ end
+ ownpath = pp
+ lfs.chdir(olddir)
+ else
+ if trace_locating then
+ logs.report("fileio","unable to check path '%s'",p)
+ end
+ ownpath = p
+ end
+ break
+ end
+ end
+ end
+ if not ownpath or ownpath == "" then
+ ownpath = "."
+ logs.report("fileio","forcing fallback ownpath .")
+ elseif trace_locating then
+ logs.report("fileio","using ownpath '%s'",ownpath)
+ end
+ end
+ resolvers.ownpath = ownpath
+ function resolvers.getownpath()
+ return resolvers.ownpath
+ end
+ return ownpath
+end
+
+local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
+
+local function identify_own()
+ local ownpath = resolvers.getownpath() or dir.current()
+ local ie = instance.environment
+ if ownpath then
+ if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
+ if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
+ if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+ else
+ logs.report("fileio","error: unable to locate ownpath")
+ os.exit()
+ end
+ if resolvers.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = resolvers.cnfdefault end
+ if resolvers.env('TEXOS') == "" then os.env['TEXOS'] = resolvers.env('SELFAUTODIR') end
+ if resolvers.env('TEXROOT') == "" then os.env['TEXROOT'] = resolvers.env('SELFAUTOPARENT') end
+ if trace_locating then
+ for i=1,#own_places do
+ local v = own_places[i]
+ logs.report("fileio","variable '%s' set to '%s'",v,resolvers.env(v) or "unknown")
+ end
+ end
+ identify_own = function() end
+end
+
+function resolvers.identify_cnf()
+ if #instance.cnffiles == 0 then
+ -- fallback
+ identify_own()
+ -- the real search
+ resolvers.expand_variables()
+ local t = resolvers.split_path(resolvers.env('TEXMFCNF'))
+ t = expanded_path_from_list(t)
+ expand_vars(t) -- redundant
+ local function locate(filename,list)
+ for i=1,#t do
+ local ti = t[i]
+ local texmfcnf = file.collapse_path(file.join(ti,filename))
+ if lfs.isfile(texmfcnf) then
+ list[#list+1] = texmfcnf
+ end
+ end
+ end
+ locate(resolvers.luaname,instance.luafiles)
+ locate(resolvers.cnfname,instance.cnffiles)
+ end
+end
+
+local function load_cnf_file(fname)
+ fname = resolvers.clean_path(fname)
+ local lname = file.replacesuffix(fname,'lua')
+ if lfs.isfile(lname) then
+ local dname = file.dirname(fname) -- fname ?
+ if not instance.configuration[dname] then
+ resolvers.load_data(dname,'configuration',lname and file.basename(lname))
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ else
+ f = io.open(fname)
+ if f then
+ if trace_locating then
+ logs.report("fileio","loading configuration file %s", fname)
+ end
+ local line, data, n, k, v
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ instance.configuration[dname] = { }
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ local data = instance.configuration[dname]
+ while true do
+ local line, n = f:read(), 0
+ if line then
+ while true do -- join lines
+ line, n = gsub(line,"\\%s*$", "")
+ if n > 0 then
+ line = line .. f:read()
+ else
+ break
+ end
+ end
+ if not find(line,"^[%%#]") then
+ local l = gsub(line,"%s*%%.*$","")
+ local k, v = match(l,"%s*(.-)%s*=%s*(.-)%s*$")
+ if k and v and not data[k] then
+ v = gsub(v,"[%%#].*",'')
+ data[k] = gsub(v,"~","$HOME")
+ instance.kpsevars[k] = true
+ end
+ end
+ else
+ break
+ end
+ end
+ f:close()
+ elseif trace_locating then
+ logs.report("fileio","skipping configuration file '%s'", fname)
+ end
+ end
+end
+
+local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+ local order = instance.order
+ for i=1,#order do
+ local c = order[i]
+ for k,v in next, c do
+ if not instance.variables[k] then
+ if instance.environment[k] then
+ instance.variables[k] = instance.environment[k]
+ else
+ instance.kpsevars[k] = true
+ instance.variables[k] = resolvers.bare_variable(v)
+ end
+ end
+ end
+ end
+end
+
+function resolvers.load_cnf()
+ local function loadoldconfigdata()
+ local cnffiles = instance.cnffiles
+ for i=1,#cnffiles do
+ load_cnf_file(cnffiles[i])
+ end
+ end
+ -- instance.cnffiles contain complete names now !
+ -- we still use a funny mix of cnf and new but soon
+ -- we will switch to lua exclusively as we only use
+ -- the file to collect the tree roots
+ if #instance.cnffiles == 0 then
+ if trace_locating then
+ logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
+ end
+ else
+ local cnffiles = instance.cnffiles
+ instance.rootpath = cnffiles[1]
+ for k=1,#cnffiles do
+ instance.cnffiles[k] = file.collapse_path(cnffiles[k])
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadoldconfig(instance.cnffiles)
+ if instance.loaderror then
+ loadoldconfigdata()
+ resolvers.saveoldconfig()
+ end
+ else
+ loadoldconfigdata()
+ if instance.renewcache then
+ resolvers.saveoldconfig()
+ end
+ end
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+function resolvers.load_lua()
+ if #instance.luafiles == 0 then
+ -- yet harmless
+ else
+ instance.rootpath = instance.luafiles[1]
+ local luafiles = instance.luafiles
+ for k=1,#luafiles do
+ instance.luafiles[k] = file.collapse_path(luafiles[k])
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ resolvers.loadnewconfig()
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+-- database loading
+
+function resolvers.load_hash()
+ resolvers.locatelists()
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadfiles()
+ if instance.loaderror then
+ resolvers.loadlists()
+ resolvers.savefiles()
+ end
+ else
+ resolvers.loadlists()
+ if instance.renewcache then
+ resolvers.savefiles()
+ end
+ end
+end
+
+function resolvers.append_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","hash '%s' appended",tag)
+ end
+ insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.prepend_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","hash '%s' prepended",tag)
+ end
+ insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.extend_texmf_var(specification) -- crap, we could better prepend the hash
+-- local t = resolvers.expanded_path_list('TEXMF') -- full expansion
+ local t = resolvers.split_path(resolvers.env('TEXMF'))
+ insert(t,1,specification)
+ local newspec = concat(t,";")
+ if instance.environment["TEXMF"] then
+ instance.environment["TEXMF"] = newspec
+ elseif instance.variables["TEXMF"] then
+ instance.variables["TEXMF"] = newspec
+ else
+ -- weird
+ end
+ resolvers.expand_variables()
+ reset_hashes()
+end
+
+-- locators
+
+function resolvers.locatelists()
+ local texmfpaths = resolvers.clean_path_list('TEXMF')
+ for i=1,#texmfpaths do
+ local path = texmfpaths[i]
+ if trace_locating then
+ logs.report("fileio","locating list of '%s'",path)
+ end
+ resolvers.locatedatabase(file.collapse_path(path))
+ end
+end
+
+function resolvers.locatedatabase(specification)
+ return resolvers.methodhandler('locators', specification)
+end
+
+function resolvers.locators.tex(specification)
+ if specification and specification ~= '' and lfs.isdir(specification) then
+ if trace_locating then
+ logs.report("fileio","tex locator '%s' found",specification)
+ end
+ resolvers.append_hash('file',specification,filename)
+ elseif trace_locating then
+ logs.report("fileio","tex locator '%s' not found",specification)
+ end
+end
+
+-- hashers
+
+function resolvers.hashdatabase(tag,name)
+ return resolvers.methodhandler('hashers',tag,name)
+end
+
+function resolvers.loadfiles()
+ instance.loaderror = false
+ instance.files = { }
+ if not instance.renewcache then
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ resolvers.hashdatabase(hash.tag,hash.name)
+ if instance.loaderror then break end
+ end
+ end
+end
+
+function resolvers.hashers.tex(tag,name)
+ resolvers.load_data(tag,'files')
+end
+
+-- generators:
+
+function resolvers.loadlists()
+ local hashes = instance.hashes
+ for i=1,#hashes do
+ resolvers.generatedatabase(hashes[i].tag)
+ end
+end
+
+function resolvers.generatedatabase(specification)
+ return resolvers.methodhandler('generators', specification)
+end
+
+-- starting with . or .. etc or funny char
+
+local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+
+--~ local l_forbidden = lpeg.S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t")
+--~ local l_confusing = lpeg.P(" ")
+--~ local l_character = lpeg.patterns.utf8
+--~ local l_dangerous = lpeg.P(".")
+
+--~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * lpeg.P(-1)
+--~ ----- l_normal = l_normal * lpeg.Cc(true) + lpeg.Cc(false)
+
+--~ local function test(str)
+--~ print(str,lpeg.match(l_normal,str))
+--~ end
+--~ test("ヒラギノ明朝 Pro W3")
+--~ test("..ヒラギノ明朝 Pro W3")
+--~ test(":ヒラギノ明朝 Pro W3;")
+--~ test("ヒラギノ明朝 /Pro W3;")
+--~ test("ヒラギノ明朝 Pro W3")
+
+function resolvers.generators.tex(specification)
+ local tag = specification
+ if trace_locating then
+ logs.report("fileio","scanning path '%s'",specification)
+ end
+ instance.files[tag] = { }
+ local files = instance.files[tag]
+ local n, m, r = 0, 0, 0
+ local spec = specification .. '/'
+ local attributes = lfs.attributes
+ local directory = lfs.dir
+ local function action(path)
+ local full
+ if path then
+ full = spec .. path .. '/'
+ else
+ full = spec
+ end
+ for name in directory(full) do
+ if not lpegmatch(weird,name) then
+ -- if lpegmatch(l_normal,name) then
+ local mode = attributes(full..name,'mode')
+ if mode == 'file' then
+ if path then
+ n = n + 1
+ local f = files[name]
+ if f then
+ if type(f) == 'string' then
+ files[name] = { f, path }
+ else
+ f[#f+1] = path
+ end
+ else -- probably unique anyway
+ files[name] = path
+ local lower = lower(name)
+ if name ~= lower then
+ files["remap:"..lower] = name
+ r = r + 1
+ end
+ end
+ end
+ elseif mode == 'directory' then
+ m = m + 1
+ if path then
+ action(path..'/'..name)
+ else
+ action(name)
+ end
+ end
+ end
+ end
+ end
+ action()
+ if trace_locating then
+ logs.report("fileio","%s files found on %s directories with %s uppercase remappings",n,m,r)
+ end
+end
+
+-- savers, todo
+
+function resolvers.savefiles()
+ resolvers.save_data('files')
+end
+
+-- A config (optionally) has the paths split in tables. Internally
+-- we join them and split them after the expansion has taken place. This
+-- is more convenient.
+
+--~ local checkedsplit = string.checkedsplit
+
+local cache = { }
+
+local splitter = lpeg.Ct(lpeg.splitat(lpeg.S(os.type == "windows" and ";" or ":;")))
+
+local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
+ local found = cache[str]
+ if not found then
+ if str == "" then
+ found = { }
+ else
+ str = gsub(str,"\\","/")
+--~ local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
+local split = lpegmatch(splitter,str)
+ found = { }
+ for i=1,#split do
+ local s = split[i]
+ if not find(s,"^{*unset}*") then
+ found[#found+1] = s
+ end
+ end
+ if trace_expansions then
+ logs.report("fileio","splitting path specification '%s'",str)
+ for k=1,#found do
+ logs.report("fileio","% 4i: %s",k,found[k])
+ end
+ end
+ cache[str] = found
+ end
+ end
+ return found
+end
+
+resolvers.split_kpse_path = split_kpse_path
+
+function resolvers.splitconfig()
+ for i=1,#instance do
+ local c = instance[i]
+ for k,v in next, c do
+ if type(v) == 'string' then
+ local t = split_kpse_path(v)
+ if #t > 1 then
+ c[k] = t
+ end
+ end
+ end
+ end
+end
+
+function resolvers.joinconfig()
+ local order = instance.order
+ for i=1,#order do
+ local c = order[i]
+ for k,v in next, c do -- indexed?
+ if type(v) == 'table' then
+ c[k] = file.join_path(v)
+ end
+ end
+ end
+end
+
+function resolvers.split_path(str)
+ if type(str) == 'table' then
+ return str
+ else
+ return split_kpse_path(str)
+ end
+end
+
+function resolvers.join_path(str)
+ if type(str) == 'table' then
+ return file.join_path(str)
+ else
+ return str
+ end
+end
+
+function resolvers.splitexpansions()
+ local ie = instance.expansions
+ for k,v in next, ie do
+ local t, h, p = { }, { }, split_kpse_path(v)
+ for kk=1,#p do
+ local vv = p[kk]
+ if vv ~= "" and not h[vv] then
+ t[#t+1] = vv
+ h[vv] = true
+ end
+ end
+ if #t > 1 then
+ ie[k] = t
+ else
+ ie[k] = t[1]
+ end
+ end
+end
+
+-- end of split/join code
+
+function resolvers.saveoldconfig()
+ resolvers.splitconfig()
+ resolvers.save_data('configuration')
+ resolvers.joinconfig()
+end
+
+resolvers.configbanner = [[
+-- This is a Luatex configuration file created by 'luatools.lua' or
+-- 'luatex.exe' directly. For comment, suggestions and questions you can
+-- contact the ConTeXt Development Team. This configuration file is
+-- not copyrighted. [HH & TH]
+]]
+
+function resolvers.serialize(files)
+ -- This version is somewhat optimized for the kind of
+ -- tables that we deal with, so it's much faster than
+ -- the generic serializer. This makes sense because
+ -- luatools and mtxtools are called frequently. Okay,
+ -- we pay a small price for properly tabbed tables.
+ local t = { }
+ local function dump(k,v,m) -- could be moved inline
+ if type(v) == 'string' then
+ return m .. "['" .. k .. "']='" .. v .. "',"
+ elseif #v == 1 then
+ return m .. "['" .. k .. "']='" .. v[1] .. "',"
+ else
+ return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'},"
+ end
+ end
+ t[#t+1] = "return {"
+ if instance.sortdata then
+ local sortedfiles = sortedkeys(files)
+ for i=1,#sortedfiles do
+ local k = sortedfiles[i]
+ local fk = files[k]
+ if type(fk) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ local sortedfk = sortedkeys(fk)
+ for j=1,#sortedfk do
+ local kk = sortedfk[j]
+ t[#t+1] = dump(kk,fk[kk],"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,fk,"\t")
+ end
+ end
+ else
+ for k, v in next, files do
+ if type(v) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for kk,vv in next, v do
+ t[#t+1] = dump(kk,vv,"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,v,"\t")
+ end
+ end
+ end
+ t[#t+1] = "}"
+ return concat(t,"\n")
+end
+
+local data_state = { }
+
+function resolvers.data_state()
+ return data_state or { }
+end
+
+function resolvers.save_data(dataname, makename) -- untested without cache overload
+ for cachename, files in next, instance[dataname] do
+ local name = (makename or file.join)(cachename,dataname)
+ local luaname, lucname = name .. ".lua", name .. ".luc"
+ if trace_locating then
+ logs.report("fileio","preparing '%s' for '%s'",dataname,cachename)
+ end
+ for k, v in next, files do
+ if type(v) == "table" and #v == 1 then
+ files[k] = v[1]
+ end
+ end
+ local data = {
+ type = dataname,
+ root = cachename,
+ version = resolvers.cacheversion,
+ date = os.date("%Y-%m-%d"),
+ time = os.date("%H:%M:%S"),
+ content = files,
+ uuid = os.uuid(),
+ }
+ local ok = io.savedata(luaname,resolvers.serialize(data))
+ if ok then
+ if trace_locating then
+ logs.report("fileio","'%s' saved in '%s'",dataname,luaname)
+ end
+ if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
+ if trace_locating then
+ logs.report("fileio","'%s' compiled to '%s'",dataname,lucname)
+ end
+ else
+ if trace_locating then
+ logs.report("fileio","compiling failed for '%s', deleting file '%s'",dataname,lucname)
+ end
+ os.remove(lucname)
+ end
+ elseif trace_locating then
+ logs.report("fileio","unable to save '%s' in '%s' (access error)",dataname,luaname)
+ end
+ end
+end
+
+function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload
+ filename = ((not filename or (filename == "")) and dataname) or filename
+ filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
+ local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
+ if blob then
+ local data = blob()
+ if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then
+ data_state[#data_state+1] = data.uuid
+ if trace_locating then
+ logs.report("fileio","loading '%s' for '%s' from '%s'",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = data.content
+ else
+ if trace_locating then
+ logs.report("fileio","skipping '%s' for '%s' from '%s'",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_locating then
+ logs.report("fileio","skipping '%s' for '%s' from '%s'",dataname,pathname,filename)
+ end
+end
+
+-- some day i'll use the nested approach, but not yet (actually we even drop
+-- engine/progname support since we have only luatex now)
+--
+-- first texmfcnf.lua files are located, next the cached texmf.cnf files
+--
+-- return {
+-- TEXMFBOGUS = 'effe checken of dit werkt',
+-- }
+
+function resolvers.resetconfig()
+ identify_own()
+ instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
+end
+
+function resolvers.loadnewconfig()
+ local luafiles = instance.luafiles
+ for i=1,#luafiles do
+ local cnf = luafiles[i]
+ local pathname = file.dirname(cnf)
+ local filename = file.join(pathname,resolvers.luaname)
+ local blob = loadfile(filename)
+ if blob then
+ local data = blob()
+ if data then
+ if trace_locating then
+ logs.report("fileio","loading configuration file '%s'",filename)
+ end
+ if true then
+ -- flatten to variable.progname
+ local t = { }
+ for k, v in next, data do -- v = progname
+ if type(v) == "string" then
+ t[k] = v
+ else
+ for kk, vv in next, v do -- vv = variable
+ if type(vv) == "string" then
+ t[vv.."."..v] = kk
+ end
+ end
+ end
+ end
+ instance['setup'][pathname] = t
+ else
+ instance['setup'][pathname] = data
+ end
+ else
+ if trace_locating then
+ logs.report("fileio","skipping configuration file '%s'",filename)
+ end
+ instance['setup'][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_locating then
+ logs.report("fileio","skipping configuration file '%s'",filename)
+ end
+ instance.order[#instance.order+1] = instance.setup[pathname]
+ if instance.loaderror then break end
+ end
+end
+
+function resolvers.loadoldconfig()
+ if not instance.renewcache then
+ local cnffiles = instance.cnffiles
+ for i=1,#cnffiles do
+ local cnf = cnffiles[i]
+ local dname = file.dirname(cnf)
+ resolvers.load_data(dname,'configuration')
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ if instance.loaderror then break end
+ end
+ end
+ resolvers.joinconfig()
+end
+
+function resolvers.expand_variables()
+ local expansions, environment, variables = { }, instance.environment, instance.variables
+ local env = resolvers.env
+ instance.expansions = expansions
+ if instance.engine ~= "" then environment['engine'] = instance.engine end
+ if instance.progname ~= "" then environment['progname'] = instance.progname end
+ for k,v in next, environment do
+ local a, b = match(k,"^(%a+)%_(.*)%s*$")
+ if a and b then
+ expansions[a..'.'..b] = v
+ else
+ expansions[k] = v
+ end
+ end
+ for k,v in next, environment do -- move environment to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ for k,v in next, variables do -- move variables to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ local busy = false
+ local function resolve(a)
+ busy = true
+ return expansions[a] or env(a)
+ end
+ while true do
+ busy = false
+ for k,v in next, expansions do
+ local s, n = gsub(v,"%$([%a%d%_%-]+)",resolve)
+ local s, m = gsub(s,"%$%{([%a%d%_%-]+)%}",resolve)
+ if n > 0 or m > 0 then
+ expansions[k]= s
+ end
+ end
+ if not busy then break end
+ end
+ for k,v in next, expansions do
+ expansions[k] = gsub(v,"\\", '/')
+ end
+end
+
+function resolvers.variable(name)
+ return entry(instance.variables,name)
+end
+
+function resolvers.expansion(name)
+ return entry(instance.expansions,name)
+end
+
+function resolvers.is_variable(name)
+ return is_entry(instance.variables,name)
+end
+
+function resolvers.is_expansion(name)
+ return is_entry(instance.expansions,name)
+end
+
+function resolvers.unexpanded_path_list(str)
+ local pth = resolvers.variable(str)
+ local lst = resolvers.split_path(pth)
+ return expanded_path_from_list(lst)
+end
+
+function resolvers.unexpanded_path(str)
+ return file.join_path(resolvers.unexpanded_path_list(str))
+end
+
+do -- no longer needed
+
+ local done = { }
+
+ function resolvers.reset_extra_path()
+ local ep = instance.extra_paths
+ if not ep then
+ ep, done = { }, { }
+ instance.extra_paths = ep
+ elseif #ep > 0 then
+ instance.lists, done = { }, { }
+ end
+ end
+
+ function resolvers.register_extra_path(paths,subpaths)
+ local ep = instance.extra_paths or { }
+ local n = #ep
+ if paths and paths ~= "" then
+ if subpaths and subpaths ~= "" then
+ for p in gmatch(paths,"[^,]+") do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = p .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ else
+ for p in gmatch(paths,"[^,]+") do
+ if not done[p] then
+ ep[#ep+1] = resolvers.clean_path(p)
+ done[p] = true
+ end
+ end
+ end
+ elseif subpaths and subpaths ~= "" then
+ for i=1,n do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = ep[i] .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ end
+ if #ep > 0 then
+ instance.extra_paths = ep -- register paths
+ end
+ if #ep > n then
+ instance.lists = { } -- erase the cache
+ end
+ end
+
+end
+
+local function made_list(instance,list)
+ local ep = instance.extra_paths
+ if not ep or #ep == 0 then
+ return list
+ else
+ local done, new = { }, { }
+ -- honour . .. ../.. but only when at the start
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ if find(v,"^[%.%/]$") then
+ done[v] = true
+ new[#new+1] = v
+ else
+ break
+ end
+ end
+ end
+ -- first the extra paths
+ for k=1,#ep do
+ local v = ep[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ -- next the formal paths
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ return new
+ end
+end
+
+function resolvers.clean_path_list(str)
+ local t = resolvers.expanded_path_list(str)
+ if t then
+ for i=1,#t do
+ t[i] = file.collapse_path(resolvers.clean_path(t[i]))
+ end
+ end
+ return t
+end
+
+function resolvers.expand_path(str)
+ return file.join_path(resolvers.expanded_path_list(str))
+end
+
+function resolvers.expanded_path_list(str)
+ if not str then
+ return ep or { } -- ep ?
+ elseif instance.savelists then
+ -- engine+progname hash
+ str = gsub(str,"%$","")
+ if not instance.lists[str] then -- cached
+ local lst = made_list(instance,resolvers.split_path(resolvers.expansion(str)))
+ instance.lists[str] = expanded_path_from_list(lst)
+ end
+ return instance.lists[str]
+ else
+ local lst = resolvers.split_path(resolvers.expansion(str))
+ return made_list(instance,expanded_path_from_list(lst))
+ end
+end
+
+function resolvers.expanded_path_list_from_var(str) -- brrr
+ local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
+ if tmp ~= "" then
+ return resolvers.expanded_path_list(tmp)
+ else
+ return resolvers.expanded_path_list(str)
+ end
+end
+
+function resolvers.expand_path_from_var(str)
+ return file.join_path(resolvers.expanded_path_list_from_var(str))
+end
+
+function resolvers.format_of_var(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+function resolvers.format_of_suffix(str)
+ return suffixmap[file.extname(str)] or 'tex'
+end
+
+function resolvers.variable_of_format(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+
+function resolvers.var_of_format_or_suffix(str)
+ local v = formats[str]
+ if v then
+ return v
+ end
+ v = formats[alternatives[str]]
+ if v then
+ return v
+ end
+ v = suffixmap[file.extname(str)]
+ if v then
+ return formats[isf]
+ end
+ return ''
+end
+
+function resolvers.expand_braces(str) -- output variable and brace expansion of STRING
+ local ori = resolvers.variable(str)
+ local pth = expanded_path_from_list(resolvers.split_path(ori))
+ return file.join_path(pth)
+end
+
+resolvers.isreadable = { }
+
+function resolvers.isreadable.file(name)
+ local readable = lfs.isfile(name) -- brrr
+ if trace_detail then
+ if readable then
+ logs.report("fileio","file '%s' is readable",name)
+ else
+ logs.report("fileio","file '%s' is not readable", name)
+ end
+ end
+ return readable
+end
+
+resolvers.isreadable.tex = resolvers.isreadable.file
+
+-- name
+-- name/name
+
+local function collect_files(names)
+ local filelist = { }
+ for k=1,#names do
+ local fname = names[k]
+ if trace_detail then
+ logs.report("fileio","checking name '%s'",fname)
+ end
+ local bname = file.basename(fname)
+ local dname = file.dirname(fname)
+ if dname == "" or find(dname,"^%.") then
+ dname = false
+ else
+ dname = "/" .. dname .. "$"
+ end
+ local hashes = instance.hashes
+ for h=1,#hashes do
+ local hash = hashes[h]
+ local blobpath = hash.tag
+ local files = blobpath and instance.files[blobpath]
+ if files then
+ if trace_detail then
+ logs.report("fileio","deep checking '%s' (%s)",blobpath,bname)
+ end
+ local blobfile = files[bname]
+ if not blobfile then
+ local rname = "remap:"..bname
+ blobfile = files[rname]
+ if blobfile then
+ bname = files[rname]
+ blobfile = files[bname]
+ end
+ end
+ if blobfile then
+ if type(blobfile) == 'string' then
+ if not dname or find(blobfile,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,blobfile,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ }
+ end
+ else
+ for kk=1,#blobfile do
+ local vv = blobfile[kk]
+ if not dname or find(vv,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,vv,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,vv,bname) -- result
+ }
+ end
+ end
+ end
+ end
+ elseif trace_locating then
+ logs.report("fileio","no match in '%s' (%s)",blobpath,bname)
+ end
+ end
+ end
+ if #filelist > 0 then
+ return filelist
+ else
+ return nil
+ end
+end
+
+function resolvers.suffix_of_format(str)
+ if suffixes[str] then
+ return suffixes[str][1]
+ else
+ return ""
+ end
+end
+
+function resolvers.suffixes_of_format(str)
+ if suffixes[str] then
+ return suffixes[str]
+ else
+ return {}
+ end
+end
+
+function resolvers.register_in_trees(name)
+ if not find(name,"^%.") then
+ instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
+ end
+end
+
+-- split the next one up for readability (bu this module needs a cleanup anyway)
+
+local function can_be_dir(name) -- can become local
+ local fakepaths = instance.fakepaths
+ if not fakepaths[name] then
+ if lfs.isdir(name) then
+ fakepaths[name] = 1 -- directory
+ else
+ fakepaths[name] = 2 -- no directory
+ end
+ end
+ return (fakepaths[name] == 1)
+end
+
+local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)
+ local result = collected or { }
+ local stamp = nil
+ filename = file.collapse_path(filename)
+ -- speed up / beware: format problem
+ if instance.remember then
+ stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
+ if instance.found[stamp] then
+ if trace_locating then
+ logs.report("fileio","remembering file '%s'",filename)
+ end
+ return instance.found[stamp]
+ end
+ end
+ if not dangerous[instance.format or "?"] then
+ if resolvers.isreadable.file(filename) then
+ if trace_detail then
+ logs.report("fileio","file '%s' found directly",filename)
+ end
+ instance.found[stamp] = { filename }
+ return { filename }
+ end
+ end
+ if find(filename,'%*') then
+ if trace_locating then
+ logs.report("fileio","checking wildcard '%s'", filename)
+ end
+ result = resolvers.find_wildcard_files(filename)
+ elseif file.is_qualified_path(filename) then
+ if resolvers.isreadable.file(filename) then
+ if trace_locating then
+ logs.report("fileio","qualified name '%s'", filename)
+ end
+ result = { filename }
+ else
+ local forcedname, ok, suffix = "", false, file.extname(filename)
+ if suffix == "" then -- why
+ if instance.format == "" then
+ forcedname = filename .. ".tex"
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio","no suffix, forcing standard filetype 'tex'")
+ end
+ result, ok = { forcedname }, true
+ end
+ else
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ forcedname = filename .. "." .. s
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio","no suffix, forcing format filetype '%s'", s)
+ end
+ result, ok = { forcedname }, true
+ break
+ end
+ end
+ end
+ end
+ if not ok and suffix ~= "" then
+ -- try to find in tree (no suffix manipulation), here we search for the
+ -- matching last part of the name
+ local basename = file.basename(filename)
+ local pattern = gsub(filename .. "$","([%.%-])","%%%1")
+ local savedformat = instance.format
+ local format = savedformat or ""
+ if format == "" then
+ instance.format = resolvers.format_of_suffix(suffix)
+ end
+ if not format then
+ instance.format = "othertextfiles" -- kind of everything, maybe texinput is better
+ end
+ --
+ if basename ~= filename then
+ local resolved = collect_instance_files(basename)
+ if #result == 0 then
+ local lowered = lower(basename)
+ if filename ~= lowered then
+ resolved = collect_instance_files(lowered)
+ end
+ end
+ resolvers.format = savedformat
+ --
+ for r=1,#resolved do
+ local rr = resolved[r]
+ if find(rr,pattern) then
+ result[#result+1], ok = rr, true
+ end
+ end
+ end
+ -- a real wildcard:
+ --
+ -- if not ok then
+ -- local filelist = collect_files({basename})
+ -- for f=1,#filelist do
+ -- local ff = filelist[f][3] or ""
+ -- if find(ff,pattern) then
+ -- result[#result+1], ok = ff, true
+ -- end
+ -- end
+ -- end
+ end
+ if not ok and trace_locating then
+ logs.report("fileio","qualified name '%s'", filename)
+ end
+ end
+ else
+ -- search spec
+ local filetype, extra, done, wantedfiles, ext = '', nil, false, { }, file.extname(filename)
+ if ext == "" then
+ if not instance.force_suffixes then
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ else
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ if instance.format == "" then
+ if ext == "" then
+ local forcedname = filename .. '.tex'
+ wantedfiles[#wantedfiles+1] = forcedname
+ filetype = resolvers.format_of_suffix(forcedname)
+ if trace_locating then
+ logs.report("fileio","forcing filetype '%s'",filetype)
+ end
+ else
+ filetype = resolvers.format_of_suffix(filename)
+ if trace_locating then
+ logs.report("fileio","using suffix based filetype '%s'",filetype)
+ end
+ end
+ else
+ if ext == "" then
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ wantedfiles[#wantedfiles+1] = filename .. "." .. s
+ end
+ end
+ filetype = instance.format
+ if trace_locating then
+ logs.report("fileio","using given filetype '%s'",filetype)
+ end
+ end
+ local typespec = resolvers.variable_of_format(filetype)
+ local pathlist = resolvers.expanded_path_list(typespec)
+ if not pathlist or #pathlist == 0 then
+ -- no pathlist, access check only / todo == wildcard
+ if trace_detail then
+ logs.report("fileio","checking filename '%s', filetype '%s', wanted files '%s'",filename, filetype or '?',concat(wantedfiles," | "))
+ end
+ for k=1,#wantedfiles do
+ local fname = wantedfiles[k]
+ if fname and resolvers.isreadable.file(fname) then
+ filename, done = fname, true
+ result[#result+1] = file.join('.',fname)
+ break
+ end
+ end
+ -- this is actually 'other text files' or 'any' or 'whatever'
+ local filelist = collect_files(wantedfiles)
+ local fl = filelist and filelist[1]
+ if fl then
+ filename = fl[3]
+ result[#result+1] = filename
+ done = true
+ end
+ else
+ -- list search
+ local filelist = collect_files(wantedfiles)
+ local dirlist = { }
+ if filelist then
+ for i=1,#filelist do
+ dirlist[i] = file.dirname(filelist[i][2]) .. "/"
+ end
+ end
+ if trace_detail then
+ logs.report("fileio","checking filename '%s'",filename)
+ end
+ -- a bit messy ... esp the doscan setting here
+ local doscan
+ for k=1,#pathlist do
+ local path = pathlist[k]
+ if find(path,"^!!") then doscan = false else doscan = true end
+ local pathname = gsub(path,"^!+", '')
+ done = false
+ -- using file list
+ if filelist then
+ local expression
+ -- compare list entries with permitted pattern -- /xx /xx//
+ if not find(pathname,"/$") then
+ expression = pathname .. "/"
+ else
+ expression = pathname
+ end
+ expression = gsub(expression,"([%-%.])","%%%1") -- this also influences
+ expression = gsub(expression,"//+$", '/.*') -- later usage of pathname
+ expression = gsub(expression,"//", '/.-/') -- not ok for /// but harmless
+ expression = "^" .. expression .. "$"
+ if trace_detail then
+ logs.report("fileio","using pattern '%s' for path '%s'",expression,pathname)
+ end
+ for k=1,#filelist do
+ local fl = filelist[k]
+ local f = fl[2]
+ local d = dirlist[k]
+ if find(d,expression) then
+ --- todo, test for readable
+ result[#result+1] = fl[3]
+ resolvers.register_in_trees(f) -- for tracing used files
+ done = true
+ if instance.allresults then
+ if trace_detail then
+ logs.report("fileio","match in hash for file '%s' on path '%s', continue scanning",f,d)
+ end
+ else
+ if trace_detail then
+ logs.report("fileio","match in hash for file '%s' on path '%s', quit scanning",f,d)
+ end
+ break
+ end
+ elseif trace_detail then
+ logs.report("fileio","no match in hash for file '%s' on path '%s'",f,d)
+ end
+ end
+ end
+ if not done and doscan then
+ -- check if on disk / unchecked / does not work at all / also zips
+ if resolvers.splitmethod(pathname).scheme == 'file' then -- ?
+ local pname = gsub(pathname,"%.%*$",'')
+ if not find(pname,"%*") then
+ local ppname = gsub(pname,"/+$","")
+ if can_be_dir(ppname) then
+ for k=1,#wantedfiles do
+ local w = wantedfiles[k]
+ local fname = file.join(ppname,w)
+ if resolvers.isreadable.file(fname) then
+ if trace_detail then
+ logs.report("fileio","found '%s' by scanning",fname)
+ end
+ result[#result+1] = fname
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ else
+ -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
+ end
+ end
+ end
+ end
+ if not done and doscan then
+ -- todo: slow path scanning
+ end
+ if done and not instance.allresults then break end
+ end
+ end
+ end
+ for k=1,#result do
+ result[k] = file.collapse_path(result[k])
+ end
+ if instance.remember then
+ instance.found[stamp] = result
+ end
+ return result
+end
+
+if not resolvers.concatinators then resolvers.concatinators = { } end
+
+resolvers.concatinators.tex = file.join
+resolvers.concatinators.file = resolvers.concatinators.tex
+
+function resolvers.find_files(filename,filetype,mustexist)
+ if type(mustexist) == boolean then
+ -- all set
+ elseif type(filetype) == 'boolean' then
+ filetype, mustexist = nil, false
+ elseif type(filetype) ~= 'string' then
+ filetype, mustexist = nil, false
+ end
+ instance.format = filetype or ''
+ local result = collect_instance_files(filename)
+ if #result == 0 then
+ local lowered = lower(filename)
+ if filename ~= lowered then
+ return collect_instance_files(lowered)
+ end
+ end
+ instance.format = ''
+ return result
+end
+
+function resolvers.find_file(filename,filetype,mustexist)
+ return (resolvers.find_files(filename,filetype,mustexist)[1] or "")
+end
+
+function resolvers.find_given_files(filename)
+ local bname, result = file.basename(filename), { }
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local files = instance.files[hash.tag] or { }
+ local blist = files[bname]
+ if not blist then
+ local rname = "remap:"..bname
+ blist = files[rname]
+ if blist then
+ bname = files[rname]
+ blist = files[bname]
+ end
+ end
+ if blist then
+ if type(blist) == 'string' then
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,blist,bname) or ""
+ if not instance.allresults then break end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,vv,bname) or ""
+ if not instance.allresults then break end
+ end
+ end
+ end
+ end
+ return result
+end
+
+function resolvers.find_given_file(filename)
+ return (resolvers.find_given_files(filename)[1] or "")
+end
+
+local function doit(path,blist,bname,tag,kind,result,allresults)
+ local done = false
+ if blist and kind then
+ if type(blist) == 'string' then
+ -- make function and share code
+ if find(lower(blist),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,blist,bname) or ""
+ done = true
+ end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ if find(lower(vv),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,vv,bname) or ""
+ done = true
+ if not allresults then break end
+ end
+ end
+ end
+ end
+ return done
+end
+
+function resolvers.find_wildcard_files(filename) -- todo: remap:
+ local result = { }
+ local bname, dname = file.basename(filename), file.dirname(filename)
+ local path = gsub(dname,"^*/","")
+ path = gsub(path,"*",".*")
+ path = gsub(path,"-","%%-")
+ if dname == "" then
+ path = ".*"
+ end
+ local name = bname
+ name = gsub(name,"*",".*")
+ name = gsub(name,"-","%%-")
+ path = lower(path)
+ name = lower(name)
+ local files, allresults, done = instance.files, instance.allresults, false
+ if find(name,"%*") then
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ for kk, hh in next, files[hash.tag] do
+ if not find(kk,"^remap:") then
+ if find(lower(kk),name) then
+ if doit(path,hh,kk,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ end
+ end
+ else
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ if doit(path,files[tag][bname],bname,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ -- we can consider also searching the paths not in the database, but then
+ -- we end up with a messy search (all // in all path specs)
+ return result
+end
+
+function resolvers.find_wildcard_file(filename)
+ return (resolvers.find_wildcard_files(filename)[1] or "")
+end
+
+-- main user functions
+
+function resolvers.automount()
+ -- implemented later
+end
+
+function resolvers.load(option)
+ statistics.starttiming(instance)
+ resolvers.resetconfig()
+ resolvers.identify_cnf()
+ resolvers.load_lua() -- will become the new method
+ resolvers.expand_variables()
+ resolvers.load_cnf() -- will be skipped when we have a lua file
+ resolvers.expand_variables()
+ if option ~= "nofiles" then
+ resolvers.load_hash()
+ resolvers.automount()
+ end
+ statistics.stoptiming(instance)
+end
+
+function resolvers.for_files(command, files, filetype, mustexist)
+ if files and #files > 0 then
+ local function report(str)
+ if trace_locating then
+ logs.report("fileio",str) -- has already verbose
+ else
+ print(str)
+ end
+ end
+ if trace_locating then
+ report('') -- ?
+ end
+ for f=1,#files do
+ local file = files[f]
+ local result = command(file,filetype,mustexist)
+ if type(result) == 'string' then
+ report(result)
+ else
+ for i=1,#result do
+ report(result[i]) -- could be unpack
+ end
+ end
+ end
+ end
+end
+
+-- strtab
+
+resolvers.var_value = resolvers.variable -- output the value of variable $STRING.
+resolvers.expand_var = resolvers.expansion -- output variable expansion of STRING.
+
+function resolvers.show_path(str) -- output search path for file type NAME
+ return file.join_path(resolvers.expanded_path_list(resolvers.format_of_var(str)))
+end
+
+-- resolvers.find_file(filename)
+-- resolvers.find_file(filename, filetype, mustexist)
+-- resolvers.find_file(filename, mustexist)
+-- resolvers.find_file(filename, filetype)
+
+function resolvers.register_file(files, name, path)
+ if files[name] then
+ if type(files[name]) == 'string' then
+ files[name] = { files[name], path }
+ else
+ files[name] = path
+ end
+ else
+ files[name] = path
+ end
+end
+
+function resolvers.splitmethod(filename)
+ if not filename then
+ return { } -- safeguard
+ elseif type(filename) == "table" then
+ return filename -- already split
+ elseif not find(filename,"://") then
+ return { scheme="file", path = filename, original=filename } -- quick hack
+ else
+ return url.hashed(filename)
+ end
+end
+
+function table.sequenced(t,sep) -- temp here
+ local s = { }
+ for k, v in next, t do -- indexed?
+ s[#s+1] = k .. "=" .. tostring(v)
+ end
+ return concat(s, sep or " | ")
+end
+
+function resolvers.methodhandler(what, filename, filetype) -- ...
+ filename = file.collapse_path(filename)
+ local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb
+ local scheme = specification.scheme
+ if resolvers[what][scheme] then
+ if trace_locating then
+ logs.report("fileio","handler '%s' -> '%s' -> '%s'",specification.original,what,table.sequenced(specification))
+ end
+ return resolvers[what][scheme](filename,filetype) -- todo: specification
+ else
+ return resolvers[what].tex(filename,filetype) -- todo: specification
+ end
+end
+
+function resolvers.clean_path(str)
+ if str then
+ str = gsub(str,"\\","/")
+ str = gsub(str,"^!+","")
+ str = gsub(str,"^~",resolvers.homedir)
+ return str
+ else
+ return nil
+ end
+end
+
+function resolvers.do_with_path(name,func)
+ local pathlist = resolvers.expanded_path_list(name)
+ for i=1,#pathlist do
+ func("^"..resolvers.clean_path(pathlist[i]))
+ end
+end
+
+function resolvers.do_with_var(name,func)
+ func(expanded_var(name))
+end
+
+function resolvers.with_files(pattern,handle)
+ local hashes = instance.hashes
+ for i=1,#hashes do
+ local hash = hashes[i]
+ local blobpath = hash.tag
+ local blobtype = hash.type
+ if blobpath then
+ local files = instance.files[blobpath]
+ if files then
+ for k,v in next, files do
+ if find(k,"^remap:") then
+ k = files[k]
+ v = files[k] -- chained
+ end
+ if find(k,pattern) then
+ if type(v) == "string" then
+ handle(blobtype,blobpath,v,k)
+ else
+ for _,vv in next, v do -- indexed
+ handle(blobtype,blobpath,vv,k)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function resolvers.locate_format(name)
+ local barename, fmtname = gsub(name,"%.%a+$",""), ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
+ end
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
+ end
+ fmtname = resolvers.clean_path(fmtname)
+ if fmtname ~= "" then
+ local barename = file.removesuffix(fmtname)
+ local luaname, lucname, luiname = barename .. ".lua", barename .. ".luc", barename .. ".lui"
+ if lfs.isfile(luiname) then
+ return barename, luiname
+ elseif lfs.isfile(lucname) then
+ return barename, lucname
+ elseif lfs.isfile(luaname) then
+ return barename, luaname
+ end
+ end
+ return nil, nil
+end
+
+function resolvers.boolean_variable(str,default)
+ local b = resolvers.expansion(str)
+ if b == "" then
+ return default
+ else
+ b = toboolean(b)
+ return (b == nil and default) or b
+ end
+end
+
+texconfig.kpse_init = false
+
+kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] end } )
+
+-- for a while
+
+input = resolvers
diff --git a/tex/context/base/data-sch.lua b/tex/context/base/data-sch.lua
new file mode 100644
index 000000000..e68b6cd01
--- /dev/null
+++ b/tex/context/base/data-sch.lua
@@ -0,0 +1,142 @@
+if not modules then modules = { } end modules ['data-sch'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local http = require("socket.http")
+local ltn12 = require("ltn12")
+
+local gsub, concat, format = string.gsub, table.concat, string.format
+
+local trace_schemes = false trackers.register("resolvers.schemes",function(v) trace_schemes = v end)
+
+schemes = schemes or { }
+
+schemes.cached = { }
+schemes.cachepath = caches.definepath("schemes")
+schemes.threshold = 24 * 60 * 60
+
+directives.register("schemes.threshold", function(v) schemes.threshold = tonumber(v) or schemes.threshold end)
+
+local cached, loaded, reused = schemes.cached, { }, { }
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+function schemes.curl(name,cachename)
+ local command = "curl --silent --create-dirs --output " .. cachename .. " " .. name -- no protocol .. "://"
+ os.spawn(command)
+end
+
+function schemes.fetch(protocol,name,handler)
+ local cachename = schemes.cachepath() .. "/" .. gsub(name,"[^%a%d%.]+","-")
+ cachename = gsub(cachename,"[\\]", "/") -- cleanup
+ if not cached[name] then
+ statistics.starttiming(schemes)
+ if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification) > schemes.threshold) then
+ cached[name] = cachename
+ if handler then
+ if trace_schemes then
+ logs.report("schemes","fetching '%s', protocol '%s', method 'built-in'",name,protocol)
+ end
+ io.flush()
+ handler(protocol,name,cachename)
+ else
+ if trace_schemes then
+ logs.report("schemes","fetching '%s', protocol '%s', method 'curl'",name,protocol)
+ end
+ io.flush()
+ schemes.curl(name,cachename)
+ end
+ end
+ if io.exists(cachename) then
+ cached[name] = cachename
+ if trace_schemes then
+ logs.report("schemes","using cached '%s', protocol '%s', cachename '%s'",name,protocol,cachename)
+ end
+ else
+ cached[name] = ""
+ if trace_schemes then
+ logs.report("schemes","using missing '%s', protocol '%s'",name,protocol)
+ end
+ end
+ loaded[protocol] = loaded[protocol] + 1
+ statistics.stoptiming(schemes)
+ else
+ if trace_schemes then
+ logs.report("schemes","reusing '%s', protocol '%s'",name,protocol)
+ end
+ reused[protocol] = reused[protocol] + 1
+ end
+ return cached[name]
+end
+
+function finders.schemes(protocol,filename,handler)
+ local foundname = schemes.fetch(protocol,filename,handler)
+ return finders.generic(protocol,foundname,filetype)
+end
+
+function openers.schemes(protocol,filename)
+ return openers.generic(protocol,filename)
+end
+
+function loaders.schemes(protocol,filename)
+ return loaders.generic(protocol,filename)
+end
+
+-- could be metatable
+
+function schemes.install(protocol,handler)
+ loaded [protocol] = 0
+ reused [protocol] = 0
+ finders[protocol] = function (filename,filetype) return finders.schemes(protocol,filename,handler) end
+ openers[protocol] = function (filename) return openers.schemes(protocol,filename) end
+ loaders[protocol] = function (filename) return loaders.schemes(protocol,filename) end
+end
+
+local function http_handler(protocol,name,cachename)
+ local tempname = cachename .. ".tmp"
+ local f = io.open(tempname,"wb")
+ local status, message = http.request {
+ url = name,
+ sink = ltn12.sink.file(f)
+ }
+ if not status then
+ os.remove(tempname)
+ else
+ os.remove(cachename)
+ os.rename(tempname,cachename)
+ end
+end
+
+schemes.install('http',http_handler)
+schemes.install('https')
+schemes.install('ftp')
+
+statistics.register("scheme handling time", function()
+ local l, r = { }, { }
+ for k, v in table.sortedhash(loaded) do
+ if v > 0 then
+ l[#l+1] = k .. ":" .. v
+ end
+ end
+ for k, v in table.sortedhash(reused) do
+ if v > 0 then
+ r[#r+1] = k .. ":" .. v
+ end
+ end
+ local n = #l + #r
+ if n > 0 then
+ l = (#l > 0 and concat(l)) or "none"
+ r = (#r > 0 and concat(r)) or "none"
+ return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s",
+ statistics.elapsedtime(schemes), n, schemes.threshold, l, r)
+ else
+ return nil
+ end
+end)
+
+--~ trace_schemes = true
+--~ print(schemes.fetch("http","http://www.pragma-ade.com/show-man.pdf",http_handler))
diff --git a/tex/context/base/data-tex.lua b/tex/context/base/data-tex.lua
new file mode 100644
index 000000000..c9fa3625a
--- /dev/null
+++ b/tex/context/base/data-tex.lua
@@ -0,0 +1,226 @@
+if not modules then modules = { } end modules ['data-tex'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- special functions that deal with io
+
+local format, lower = string.format, string.lower
+local unpack = unpack or table.unpack
+
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
+
+local texiowrite_nl = (texio and texio.write_nl) or print
+local texiowrite = (texio and texio.write) or print
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+function finders.generic(tag,filename,filetype)
+ local foundname = resolvers.find_file(filename,filetype)
+ if foundname and foundname ~= "" then
+ if trace_locating then
+ logs.report("fileio","%s finder: file '%s' found",tag,filename)
+ end
+ return foundname
+ else
+ if trace_locating then
+ logs.report("fileio","%s finder: unknown file '%s'",tag,filename)
+ end
+ return unpack(finders.notfound)
+ end
+end
+
+--~ local lpegmatch = lpeg.match
+--~ local getlines = lpeg.Ct(lpeg.patterns.textline)
+
+local input_translator, utf_translator, user_translator = nil, nil, nil
+
+function resolvers.install_text_filter(name,func)
+ if name == "input" then input_translator = func
+ elseif name == "utf" then utf_translator = func
+ elseif name == "user" then user_translator = func end
+end
+
+function openers.text_opener(filename,file_handle,tag)
+ local u = unicode.utftype(file_handle)
+ local t = { }
+ if u > 0 then
+ if trace_locating then
+ logs.report("fileio","%s opener, file '%s' opened using method '%s'",tag,filename,unicode.utfname[u])
+ end
+ local l
+ if u > 2 then
+ l = unicode.utf32_to_utf8(file_handle:read("*a"),u==4)
+ else
+ l = unicode.utf16_to_utf8(file_handle:read("*a"),u==2)
+ end
+ file_handle:close()
+ t = {
+ utftype = u, -- may go away
+ lines = l,
+ current = 0, -- line number, not really needed
+ handle = nil,
+ noflines = #l,
+ close = function()
+ if trace_locating then
+ logs.report("fileio","%s closer, file '%s' closed",tag,filename)
+ end
+ logs.show_close(filename)
+ t = nil
+ end,
+ reader = function(self)
+ self = self or t
+ local current, lines = self.current, self.lines
+ if current >= #lines then
+ return nil
+ else
+ current = current + 1
+ self.current = current
+ local line = lines[current]
+ if not line then
+ return nil
+ elseif line == "" then
+ return ""
+ else
+ if input_translator then
+ line = input_translator(line)
+ end
+ if utf_translator then
+ line = utf_translator(line)
+ end
+ if user_translator then
+ line = user_translator(line)
+ end
+ return line
+ end
+ end
+ end
+ }
+ else
+ if trace_locating then
+ logs.report("fileio","%s opener, file '%s' opened",tag,filename)
+ end
+ -- todo: file;name -> freeze / eerste regel scannen -> freeze
+ --~ local data = lpegmatch(getlines,file_handle:read("*a"))
+ --~ local n = 0
+ t = {
+ reader = function() -- self
+ local line = file_handle:read()
+ --~ n = n + 1
+ --~ local line = data[n]
+ --~ print(line)
+ if not line then
+ return nil
+ elseif line == "" then
+ return ""
+ else
+ if input_translator then
+ line = input_translator(line)
+ end
+ if utf_translator then
+ line = utf_translator(line)
+ end
+ if user_translator then
+ line = user_translator(line)
+ end
+ return line
+ end
+ end,
+ close = function()
+ if trace_locating then
+ logs.report("fileio","%s closer, file '%s' closed",tag,filename)
+ end
+ logs.show_close(filename)
+ file_handle:close()
+ t = nil
+ collectgarbage("step") -- saves some memory
+ end,
+ handle = function()
+ return file_handle
+ end,
+ noflines = function()
+ t.noflines = io.noflines(file_handle)
+ return t.noflines
+ end
+ }
+ end
+ return t
+end
+
+function openers.generic(tag,filename)
+ if filename and filename ~= "" then
+ local f = io.open(filename,"r")
+ if f then
+ logs.show_open(filename) -- todo
+ if trace_locating then
+ logs.report("fileio","%s opener, file '%s' opened",tag,filename)
+ end
+ return openers.text_opener(filename,f,tag)
+ end
+ end
+ if trace_locating then
+ logs.report("fileio","%s opener, file '%s' not found",tag,filename)
+ end
+ return unpack(openers.notfound)
+end
+
+function loaders.generic(tag,filename)
+ if filename and filename ~= "" then
+ local f = io.open(filename,"rb")
+ if f then
+ logs.show_load(filename)
+ if trace_locating then
+ logs.report("fileio","%s loader, file '%s' loaded",tag,filename)
+ end
+ local s = f:read("*a")
+ if garbagecollector and garbagecollector.check then garbagecollector.check(#s) end
+ f:close()
+ if s then
+ return true, s, #s
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio","%s loader, file '%s' not found",tag,filename)
+ end
+ return unpack(loaders.notfound)
+end
+
+function finders.tex(filename,filetype)
+ return finders.generic('tex',filename,filetype)
+end
+
+function openers.tex(filename)
+ return openers.generic('tex',filename)
+end
+
+function loaders.tex(filename)
+ return loaders.generic('tex',filename)
+end
+
+function resolvers.findtexfile(filename, filetype)
+ return resolvers.methodhandler('finders',filename, filetype)
+end
+
+function resolvers.opentexfile(filename)
+ return resolvers.methodhandler('openers',filename)
+end
+
+function resolvers.openfile(filename)
+ local fullname = resolvers.findtexfile(filename)
+ if fullname and (fullname ~= "") then
+ return resolvers.opentexfile(fullname)
+ else
+ return nil
+ end
+end
+
+function resolvers.texdatablob(filename, filetype)
+ local ok, data, size = resolvers.loadbinfile(filename, filetype)
+ return data or ""
+end
+
+resolvers.loadtexfile = resolvers.texdatablob
diff --git a/tex/context/base/data-tmf.lua b/tex/context/base/data-tmf.lua
new file mode 100644
index 000000000..7421eacfc
--- /dev/null
+++ b/tex/context/base/data-tmf.lua
@@ -0,0 +1,75 @@
+if not modules then modules = { } end modules ['data-tmf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find, gsub, match = string.find, string.gsub, string.match
+local getenv, setenv = os.getenv, os.setenv
+
+-- loads *.tmf files in minimal tree roots (to be optimized and documented)
+
+function resolvers.check_environment(tree)
+ logs.simpleline()
+ setenv('TMP', getenv('TMP') or getenv('TEMP') or getenv('TMPDIR') or getenv('HOME'))
+ setenv('TEXOS', getenv('TEXOS') or ("texmf-" .. os.platform))
+ setenv('TEXPATH', gsub(tree or "tex","\/+$",''))
+ setenv('TEXMFOS', getenv('TEXPATH') .. "/" .. getenv('TEXOS'))
+ logs.simpleline()
+ logs.simple("preset : TEXPATH => %s", getenv('TEXPATH'))
+ logs.simple("preset : TEXOS => %s", getenv('TEXOS'))
+ logs.simple("preset : TEXMFOS => %s", getenv('TEXMFOS'))
+ logs.simple("preset : TMP => %s", getenv('TMP'))
+ logs.simple('')
+end
+
+function resolvers.load_environment(name) -- todo: key=value as well as lua
+ local f = io.open(name)
+ if f then
+ for line in f:lines() do
+ if find(line,"^[%%%#]") then
+ -- skip comment
+ else
+ local key, how, value = match(line,"^(.-)%s*([<=>%?]+)%s*(.*)%s*$")
+ if how then
+ value = gsub(value,"%%(.-)%%", function(v) return getenv(v) or "" end)
+ if how == "=" or how == "<<" then
+ setenv(key,value)
+ elseif how == "?" or how == "??" then
+ setenv(key,getenv(key) or value)
+ elseif how == "<" or how == "+=" then
+ if getenv(key) then
+ setenv(key,getenv(key) .. io.fileseparator .. value)
+ else
+ setenv(key,value)
+ end
+ elseif how == ">" or how == "=+" then
+ if getenv(key) then
+ setenv(key,value .. io.pathseparator .. getenv(key))
+ else
+ setenv(key,value)
+ end
+ end
+ end
+ end
+ end
+ f:close()
+ end
+end
+
+function resolvers.load_tree(tree)
+ if tree and tree ~= "" then
+ local setuptex = 'setuptex.tmf'
+ if lfs.attributes(tree, "mode") == "directory" then -- check if not nil
+ setuptex = tree .. "/" .. setuptex
+ else
+ setuptex = tree
+ end
+ if io.exists(setuptex) then
+ resolvers.check_environment(tree)
+ resolvers.load_environment(setuptex)
+ end
+ end
+end
diff --git a/tex/context/base/data-tmp.lua b/tex/context/base/data-tmp.lua
new file mode 100644
index 000000000..25f5b975c
--- /dev/null
+++ b/tex/context/base/data-tmp.lua
@@ -0,0 +1,178 @@
+if not modules then modules = { } end modules ['data-tmp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+
This module deals with caching data. It sets up the paths and
+implements loaders and savers for tables. Best is to set the
+following variable. When not set, the usual paths will be
+checked. Personally I prefer the (users) temporary path.
Currently we do no locking when we write files. This is no real
+problem because most caching involves fonts and the chance of them
+being written at the same time is small. We also need to extend
+luatools with a recache feature.
+--ldx]]--
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end) -- not used yet
+
+caches = caches or { }
+
+caches.path = caches.path or nil
+caches.base = caches.base or "luatex-cache"
+caches.more = caches.more or "context"
+caches.direct = false -- true is faster but may need huge amounts of memory
+caches.tree = false
+caches.paths = caches.paths or nil
+caches.force = false
+caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+
+function caches.temp()
+ local cachepath = nil
+ local function check(list,isenv)
+ if not cachepath then
+ for k=1,#list do
+ local v = list[k]
+ cachepath = (isenv and (os.env[v] or "")) or v or ""
+ if cachepath == "" then
+ -- next
+ else
+ cachepath = resolvers.clean_path(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+ break
+ elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
+ dir.mkdirs(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then
+ break
+ end
+ end
+ end
+ cachepath = nil
+ end
+ end
+ end
+ check(resolvers.clean_path_list("TEXMFCACHE") or { })
+ check(caches.defaults,true)
+ if not cachepath then
+ print("\nfatal error: there is no valid (writable) cache path defined\n")
+ os.exit()
+ elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory"
+ print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
+ os.exit()
+ end
+ cachepath = file.collapse_path(cachepath)
+ function caches.temp()
+ return cachepath
+ end
+ return cachepath
+end
+
+function caches.configpath()
+ return table.concat(resolvers.instance.cnffiles,";")
+end
+
+function caches.hashed(tree)
+ return md5.hex(gsub(lower(tree),"[\\\/]+","/"))
+end
+
+function caches.treehash()
+ local tree = caches.configpath()
+ if not tree or tree == "" then
+ return false
+ else
+ return caches.hashed(tree)
+ end
+end
+
+function caches.setpath(...)
+ if not caches.path then
+ if not caches.path then
+ caches.path = caches.temp()
+ end
+ caches.path = resolvers.clean_path(caches.path) -- to be sure
+ caches.tree = caches.tree or caches.treehash()
+ if caches.tree then
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
+ else
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
+ end
+ end
+ if not caches.path then
+ caches.path = '.'
+ end
+ caches.path = resolvers.clean_path(caches.path)
+ local dirs = { ... }
+ if #dirs > 0 then
+ local pth = dir.mkdirs(caches.path,...)
+ return pth
+ end
+ caches.path = dir.expand_name(caches.path)
+ return caches.path
+end
+
+function caches.definepath(category,subcategory)
+ return function()
+ return caches.setpath(category,subcategory)
+ end
+end
+
+function caches.setluanames(path,name)
+ return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc"
+end
+
+function caches.loaddata(path,name)
+ local tmaname, tmcname = caches.setluanames(path,name)
+ local loader = loadfile(tmcname) or loadfile(tmaname)
+ if loader then
+ loader = loader()
+ collectgarbage("step")
+ return loader
+ else
+ return false
+ end
+end
+
+--~ function caches.loaddata(path,name)
+--~ local tmaname, tmcname = caches.setluanames(path,name)
+--~ return dofile(tmcname) or dofile(tmaname)
+--~ end
+
+function caches.iswritable(filepath,filename)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ return file.iswritable(tmaname)
+end
+
+function caches.savedata(filepath,filename,data,raw)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ local reduce, simplify = true, true
+ if raw then
+ reduce, simplify = false, false
+ end
+ data.cache_uuid = os.uuid()
+ if caches.direct then
+ file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex
+ else
+ table.tofile(tmaname, data,'return',false,true,false) -- maybe not the last true
+ end
+ local cleanup = resolvers.boolean_variable("PURGECACHE", false)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
+ utils.lua.compile(tmaname, tmcname, cleanup, strip)
+end
+
+-- here we use the cache for format loading (texconfig.[formatname|jobname])
+
+--~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and resolvers.instance then
+ if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
+ texconfig.formatname = caches.setpath("formats") .. "/" .. gsub(texconfig.luaname,"%.lu.$",".fmt")
+end
diff --git a/tex/context/base/data-tre.lua b/tex/context/base/data-tre.lua
new file mode 100644
index 000000000..d5ca258e4
--- /dev/null
+++ b/tex/context/base/data-tre.lua
@@ -0,0 +1,47 @@
+if not modules then modules = { } end modules ['data-tre'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- \input tree://oeps1/**/oeps.tex
+
+local find, gsub = string.find, string.gsub
+local unpack = unpack or table.unpack
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+local done, found = { }, { }
+
+function finders.tree(specification,filetype)
+ local fnd = found[specification]
+ if not fnd then
+ local spec = resolvers.splitmethod(specification).path or ""
+ if spec ~= "" then
+ local path, name = file.dirname(spec), file.basename(spec)
+ if path == "" then path = "." end
+ local hash = done[path]
+ if not hash then
+ local pattern = path .. "/*" -- we will use the proper splitter
+ hash = dir.glob(pattern)
+ done[path] = hash
+ end
+ local pattern = "/" .. gsub(name,"([%.%-%+])", "%%%1") .. "$"
+ for k=1,#hash do
+ local v = hash[k]
+ if find(v,pattern) then
+ found[specification] = v
+ return v
+ end
+ end
+ end
+ fnd = unpack(finders.notfound)
+ found[specification] = fnd
+ end
+ return fnd
+end
+
+openers.tree = openers.generic
+loaders.tree = loaders.generic
diff --git a/tex/context/base/data-use.lua b/tex/context/base/data-use.lua
new file mode 100644
index 000000000..5ecd7805f
--- /dev/null
+++ b/tex/context/base/data-use.lua
@@ -0,0 +1,129 @@
+if not modules then modules = { } end modules ['data-use'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub, find = string.format, string.lower, string.gsub, string.find
+
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
+
+-- since we want to use the cache instead of the tree, we will now
+-- reimplement the saver.
+
+local save_data = resolvers.save_data
+local load_data = resolvers.load_data
+
+resolvers.cachepath = nil -- public, for tracing
+resolvers.usecache = true -- public, for tracing
+
+function resolvers.save_data(dataname)
+ save_data(dataname, function(cachename,dataname)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(cachename))
+ else
+ return file.join(cachename,dataname)
+ end
+ end)
+end
+
+function resolvers.load_data(pathname,dataname,filename)
+ load_data(pathname,dataname,filename,function(dataname,filename)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(pathname))
+ else
+ if not filename or (filename == "") then
+ filename = dataname
+ end
+ return file.join(pathname,filename)
+ end
+ end)
+end
+
+-- we will make a better format, maybe something xml or just text or lua
+
+resolvers.automounted = resolvers.automounted or { }
+
+function resolvers.automount(usecache)
+ local mountpaths = resolvers.clean_path_list(resolvers.expansion('TEXMFMOUNT'))
+ if (not mountpaths or #mountpaths == 0) and usecache then
+ mountpaths = { caches.setpath("mount") }
+ end
+ if mountpaths and #mountpaths > 0 then
+ statistics.starttiming(resolvers.instance)
+ for k=1,#mountpaths do
+ local root = mountpaths[k]
+ local f = io.open(root.."/url.tmi")
+ if f then
+ for line in f:lines() do
+ if line then
+ if find(line,"^[%%#%-]") then -- or %W
+ -- skip
+ elseif find(line,"^zip://") then
+ if trace_locating then
+ logs.report("fileio","mounting %s",line)
+ end
+ table.insert(resolvers.automounted,line)
+ resolvers.usezipfile(line)
+ end
+ end
+ end
+ f:close()
+ end
+ end
+ statistics.stoptiming(resolvers.instance)
+ end
+end
+
+-- status info
+
+statistics.register("used config path", function() return caches.configpath() end)
+statistics.register("used cache path", function() return caches.temp() or "?" end)
+
+-- experiment (code will move)
+
+function statistics.save_fmt_status(texname,formatbanner,sourcefile) -- texname == formatname
+ local enginebanner = status.list().banner
+ if formatbanner and enginebanner and sourcefile then
+ local luvname = file.replacesuffix(texname,"luv")
+ local luvdata = {
+ enginebanner = enginebanner,
+ formatbanner = formatbanner,
+ sourcehash = md5.hex(io.loaddata(resolvers.find_file(sourcefile)) or "unknown"),
+ sourcefile = sourcefile,
+ }
+ io.savedata(luvname,table.serialize(luvdata,true))
+ end
+end
+
+function statistics.check_fmt_status(texname)
+ local enginebanner = status.list().banner
+ if enginebanner and texname then
+ local luvname = file.replacesuffix(texname,"luv")
+ if lfs.isfile(luvname) then
+ local luv = dofile(luvname)
+ if luv and luv.sourcefile then
+ local sourcehash = md5.hex(io.loaddata(resolvers.find_file(luv.sourcefile)) or "unknown")
+ local luvbanner = luv.enginebanner or "?"
+ if luvbanner ~= enginebanner then
+ return string.format("engine mismatch (luv:%s <> bin:%s)",luvbanner,enginebanner)
+ end
+ local luvhash = luv.sourcehash or "?"
+ if luvhash ~= sourcehash then
+ return string.format("source mismatch (luv:%s <> bin:%s)",luvhash,sourcehash)
+ end
+ else
+ return "invalid status file"
+ end
+ else
+ return "missing status file"
+ end
+ end
+ return true
+end
diff --git a/tex/context/base/data-zip.lua b/tex/context/base/data-zip.lua
new file mode 100644
index 000000000..aa3740a83
--- /dev/null
+++ b/tex/context/base/data-zip.lua
@@ -0,0 +1,241 @@
+if not modules then modules = { } end modules ['data-zip'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, find, match = string.format, string.find, string.match
+local unpack = unpack or table.unpack
+
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
+
+-- zip:///oeps.zip?name=bla/bla.tex
+-- zip:///oeps.zip?tree=tex/texmf-local
+-- zip:///texmf.zip?tree=/tex/texmf
+-- zip:///texmf.zip?tree=/tex/texmf-local
+-- zip:///texmf-mine.zip?tree=/tex/texmf-projects
+
+zip = zip or { }
+zip.archives = zip.archives or { }
+zip.registeredfiles = zip.registeredfiles or { }
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+local locators, hashers, concatinators = resolvers.locators, resolvers.hashers, resolvers.concatinators
+
+local archives = zip.archives
+
+local function validzip(str) -- todo: use url splitter
+ if not find(str,"^zip://") then
+ return "zip:///" .. str
+ else
+ return str
+ end
+end
+
+function zip.openarchive(name)
+ if not name or name == "" then
+ return nil
+ else
+ local arch = archives[name]
+ if not arch then
+ local full = resolvers.find_file(name) or ""
+ arch = (full ~= "" and zip.open(full)) or false
+ archives[name] = arch
+ end
+ return arch
+ end
+end
+
+function zip.closearchive(name)
+ if not name or (name == "" and archives[name]) then
+ zip.close(archives[name])
+ archives[name] = nil
+ end
+end
+
+function locators.zip(specification) -- where is this used? startup zips (untested)
+ specification = resolvers.splitmethod(specification)
+ local zipfile = specification.path
+ local zfile = zip.openarchive(name) -- tricky, could be in to be initialized tree
+ if trace_locating then
+ if zfile then
+ logs.report("fileio","zip locator, archive '%s' found",specification.original)
+ else
+ logs.report("fileio","zip locator, archive '%s' not found",specification.original)
+ end
+ end
+end
+
+function hashers.zip(tag,name)
+ if trace_locating then
+ logs.report("fileio","loading zip file '%s' as '%s'",name,tag)
+ end
+ resolvers.usezipfile(format("%s?tree=%s",tag,name))
+end
+
+function concatinators.zip(tag,path,name)
+ if not path or path == "" then
+ return format('%s?name=%s',tag,name)
+ else
+ return format('%s?name=%s/%s',tag,path,name)
+ end
+end
+
+function resolvers.isreadable.zip(name)
+ return true
+end
+
+function finders.zip(specification,filetype)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio","zip finder, archive '%s' found",specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ dfile = zfile:close()
+ if trace_locating then
+ logs.report("fileio","zip finder, file '%s' found",q.name)
+ end
+ return specification.original
+ elseif trace_locating then
+ logs.report("fileio","zip finder, file '%s' not found",q.name)
+ end
+ elseif trace_locating then
+ logs.report("fileio","zip finder, unknown archive '%s'",specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio","zip finder, '%s' not found",filename)
+ end
+ return unpack(finders.notfound)
+end
+
+function openers.zip(specification)
+ local zipspecification = resolvers.splitmethod(specification)
+ if zipspecification.path then
+ local q = url.query(zipspecification.query)
+ if q.name then
+ local zfile = zip.openarchive(zipspecification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio","zip opener, archive '%s' opened",zipspecification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_open(specification)
+ if trace_locating then
+ logs.report("fileio","zip opener, file '%s' found",q.name)
+ end
+ return openers.text_opener(specification,dfile,'zip')
+ elseif trace_locating then
+ logs.report("fileio","zip opener, file '%s' not found",q.name)
+ end
+ elseif trace_locating then
+ logs.report("fileio","zip opener, unknown archive '%s'",zipspecification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio","zip opener, '%s' not found",filename)
+ end
+ return unpack(openers.notfound)
+end
+
+function loaders.zip(specification)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio","zip loader, archive '%s' opened",specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_load(filename)
+ if trace_locating then
+ logs.report("fileio","zip loader, file '%s' loaded",filename)
+ end
+ local s = dfile:read("*all")
+ dfile:close()
+ return true, s, #s
+ elseif trace_locating then
+ logs.report("fileio","zip loader, file '%s' not found",q.name)
+ end
+ elseif trace_locating then
+ logs.report("fileio","zip loader, unknown archive '%s'",specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio","zip loader, '%s' not found",filename)
+ end
+ return unpack(openers.notfound)
+end
+
+-- zip:///somefile.zip
+-- zip:///somefile.zip?tree=texmf-local -> mount
+
+function resolvers.usezipfile(zipname)
+ zipname = validzip(zipname)
+ local specification = resolvers.splitmethod(zipname)
+ local zipfile = specification.path
+ if zipfile and not zip.registeredfiles[zipname] then
+ local tree = url.query(specification.query).tree or ""
+ local z = zip.openarchive(zipfile)
+ if z then
+ local instance = resolvers.instance
+ if trace_locating then
+ logs.report("fileio","zip registering, registering archive '%s'",zipname)
+ end
+ statistics.starttiming(instance)
+ resolvers.prepend_hash('zip',zipname,zipfile)
+ resolvers.extend_texmf_var(zipname) -- resets hashes too
+ zip.registeredfiles[zipname] = z
+ instance.files[zipname] = resolvers.register_zip_file(z,tree or "")
+ statistics.stoptiming(instance)
+ elseif trace_locating then
+ logs.report("fileio","zip registering, unknown archive '%s'",zipname)
+ end
+ elseif trace_locating then
+ logs.report("fileio","zip registering, '%s' not found",zipname)
+ end
+end
+
+function resolvers.register_zip_file(z,tree)
+ local files, filter = { }, ""
+ if tree == "" then
+ filter = "^(.+)/(.-)$"
+ else
+ filter = format("^%s/(.+)/(.-)$",tree)
+ end
+ if trace_locating then
+ logs.report("fileio","zip registering, using filter '%s'",filter)
+ end
+ local register, n = resolvers.register_file, 0
+ for i in z:files() do
+ local path, name = match(i.filename,filter)
+ if path then
+ if name and name ~= '' then
+ register(files, name, path)
+ n = n + 1
+ else
+ -- directory
+ end
+ else
+ register(files, i.filename, '')
+ n = n + 1
+ end
+ end
+ logs.report("fileio","zip registering, %s files registered",n)
+ return files
+end
diff --git a/tex/context/base/enco-032.mkii b/tex/context/base/enco-032.mkii
new file mode 100644
index 000000000..d7e15126c
--- /dev/null
+++ b/tex/context/base/enco-032.mkii
@@ -0,0 +1,82 @@
+%D \module
+%D [ file=enco-032,
+%D version=2006.03.30,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Unicode Goodies,
+%D author={Taco Hoekwater},
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+% unicode table 32 (= hex 20)
+
+\startencoding [default]
+
+ \definecommand unic@threeperemspace {\hskip .33333em }
+ \definecommand unic@fourperemspace {\hskip .25em }
+ \definecommand unic@sixperemspace {\hskip .16667em }
+ \definecommand unic@figurespace {\hphantom{0}}
+ \definecommand unic@punctuationspace {\hphantom{,}}
+ \definecommand unic@hairspace {\hskip .08333em }
+ \definecommand unic@zerowidthspace {\hskip 0em plus 1sp }
+ \definecommand unic@zerowidthjoiner {\kern 0em }
+ \definecommand unic@zerowidthnonjoiner {\hskip 0em }
+
+ \definecommand unic@quotedblleftreversed {\mirror{\quotedblright}}
+ \definecommand unic@quoteleftreversed {\mirror{\quoteright}}
+
+ \definecommand unic@onedotleader {{\periods[1]}}
+ \definecommand unic@twodotleader {{\periods[2]}}
+ \definecommand unic@hyphenationpoint {.\allowbreak }
+
+ \definecommand unic@doubleexclamationmark {!!}
+ \definecommand unic@exclamationquestionmark {!?}
+ \definecommand unic@questionexclamationmark {?!}
+ \definecommand unic@doublequestionmark {??}
+
+ \definecommand unic@reversedpilcrowsign {\mirror{\P}}
+ \definecommand unic@reversedsemicolon {\mirror{;}}
+
+ \definecommand unic@superscriptzero {\high{0}}
+ \definecommand unic@superscripti {\high{i}}
+ \definecommand unic@superscriptfour {\high{4}}
+ \definecommand unic@superscriptfive {\high{5}}
+ \definecommand unic@superscriptsix {\high{6}}
+ \definecommand unic@superscriptseven {\high{7}}
+ \definecommand unic@superscripteight {\high{8}}
+ \definecommand unic@superscriptnine {\high{9}}
+ \definecommand unic@superscriptplus {\high{+}}
+ \definecommand unic@superscriptminus {\high{\textminus}}
+ \definecommand unic@superscriptequals {\high{=}}
+ \definecommand unic@superscriptleft {\high{(}}
+ \definecommand unic@superscriptright {\high{)}}
+ \definecommand unic@superscriptn {\high{n}}
+ \definecommand unic@subscriptzero {\low{0}}
+ \definecommand unic@subscriptone {\low{1}}
+ \definecommand unic@subscripttwo {\low{2}}
+ \definecommand unic@subscriptthree {\low{3}}
+ \definecommand unic@subscriptfour {\low{4}}
+ \definecommand unic@subscriptfive {\low{5}}
+ \definecommand unic@subscriptsix {\low{6}}
+ \definecommand unic@subscriptseven {\low{7}}
+ \definecommand unic@subscripteight {\low{8}}
+ \definecommand unic@subscriptnine {\low{9}}
+ \definecommand unic@subscriptplus {\low{+}}
+ \definecommand unic@subscriptminus {\low{\textminus}}
+ \definecommand unic@subscriptequals {\low{=}}
+ \definecommand unic@subscriptleft {\low{(}}
+ \definecommand unic@subscriptright {\low{)}}
+ \definecommand unic@subscripta {\low{a}}
+ \definecommand unic@subscripte {\low{e}}
+ \definecommand unic@subscripto {\low{o}}
+ \definecommand unic@subscriptx {\low{x}}
+ \definecommand unic@subscriptschwa {\low{\schwa}}
+
+\stopencoding
+
+\protect \endinput
diff --git a/tex/context/base/enco-037.mkii b/tex/context/base/enco-037.mkii
new file mode 100644
index 000000000..d9fc653b2
--- /dev/null
+++ b/tex/context/base/enco-037.mkii
@@ -0,0 +1,276 @@
+%D \module
+%D [ file=enco-037,
+%D version=2006.02.13,
+%D title=\CONTEXT\ \UNICODE\ Macros,
+%D subtitle=Encoding for vector 37,
+%D author=Luigi Scarso,
+%D date=\currentdate,
+%D copyright={PRAGMA}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\startencoding[default]
+
+\definecharacter UnicodeLightHorizontal {\uchar{37}{000}} %%BOX DRAWINGS LIGHT HORIZONTAL
+\definecharacter UnicodeHeavyHorizontal {\uchar{37}{001}} %%BOX DRAWINGS HEAVY HORIZONTAL
+\definecharacter UnicodeLightVertical {\uchar{37}{002}} %%BOX DRAWINGS LIGHT VERTICAL
+\definecharacter UnicodeHeavyVertical {\uchar{37}{003}} %%BOX DRAWINGS HEAVY VERTICAL
+\definecharacter UnicodeLightTripleDashHorizontal {\uchar{37}{004}} %%BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL
+\definecharacter UnicodeHeavyTripleDashHorizontal {\uchar{37}{005}} %%BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL
+\definecharacter UnicodeLightTripleDashVertical {\uchar{37}{006}} %%BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL
+\definecharacter UnicodeHeavyTripleDashVertical {\uchar{37}{007}} %%BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL
+\definecharacter UnicodeLightQuadrupleDashHorizontal {\uchar{37}{008}} %%BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL
+\definecharacter UnicodeHeavyQuadrupleDashHorizontal {\uchar{37}{009}} %%BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL
+\definecharacter UnicodeLightQuadrupleDashVertical {\uchar{37}{010}} %%BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL
+\definecharacter UnicodeHeavyQuadrupleDashVertical {\uchar{37}{011}} %%BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL
+\definecharacter UnicodeLightDownAndRight {\uchar{37}{012}} %%BOX DRAWINGS LIGHT DOWN AND RIGHT
+\definecharacter UnicodeDownLightAndRightHeavy {\uchar{37}{013}} %%BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY
+\definecharacter UnicodeDownHeavyAndRightLight {\uchar{37}{014}} %%BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT
+\definecharacter UnicodeHeavyDownAndRight {\uchar{37}{015}} %%BOX DRAWINGS HEAVY DOWN AND RIGHT
+\definecharacter UnicodeLightDownAndLeft {\uchar{37}{016}} %%BOX DRAWINGS LIGHT DOWN AND LEFT
+\definecharacter UnicodeDownLightAndLeftHeavy {\uchar{37}{017}} %%BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY
+\definecharacter UnicodeDownHeavyAndLeftLight {\uchar{37}{018}} %%BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT
+\definecharacter UnicodeHeavyDownAndLeft {\uchar{37}{019}} %%BOX DRAWINGS HEAVY DOWN AND LEFT
+\definecharacter UnicodeLightUpAndRight {\uchar{37}{020}} %%BOX DRAWINGS LIGHT UP AND RIGHT
+\definecharacter UnicodeUpLightAndRightHeavy {\uchar{37}{021}} %%BOX DRAWINGS UP LIGHT AND RIGHT HEAVY
+\definecharacter UnicodeUpHeavyAndRightLight {\uchar{37}{022}} %%BOX DRAWINGS UP HEAVY AND RIGHT LIGHT
+\definecharacter UnicodeHeavyUpAndRight {\uchar{37}{023}} %%BOX DRAWINGS HEAVY UP AND RIGHT
+\definecharacter UnicodeLightUpAndLeft {\uchar{37}{024}} %%BOX DRAWINGS LIGHT UP AND LEFT
+\definecharacter UnicodeUpLightAndLeftHeavy {\uchar{37}{025}} %%BOX DRAWINGS UP LIGHT AND LEFT HEAVY
+\definecharacter UnicodeUpHeavyAndLeftLight {\uchar{37}{026}} %%BOX DRAWINGS UP HEAVY AND LEFT LIGHT
+\definecharacter UnicodeHeavyUpAndLeft {\uchar{37}{027}} %%BOX DRAWINGS HEAVY UP AND LEFT
+\definecharacter UnicodeLightVerticalAndRight {\uchar{37}{028}} %%BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+\definecharacter UnicodeVerticalLightAndRightHeavy {\uchar{37}{029}} %%BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY
+\definecharacter UnicodeUpHeavyAndRightDownLight {\uchar{37}{030}} %%BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT
+\definecharacter UnicodeDownHeavyAndRightUpLight {\uchar{37}{031}} %%BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT
+\definecharacter UnicodeVerticalHeavyAndRightLight {\uchar{37}{032}} %%BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT
+\definecharacter UnicodeDownLightAndRightUpHeavy {\uchar{37}{033}} %%BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY
+\definecharacter UnicodeUpLightAndRightDownHeavy {\uchar{37}{034}} %%BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY
+\definecharacter UnicodeHeavyVerticalAndRight {\uchar{37}{035}} %%BOX DRAWINGS HEAVY VERTICAL AND RIGHT
+\definecharacter UnicodeLightVerticalAndLeft {\uchar{37}{036}} %%BOX DRAWINGS LIGHT VERTICAL AND LEFT
+\definecharacter UnicodeVerticalLightAndLeftHeavy {\uchar{37}{037}} %%BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY
+\definecharacter UnicodeUpHeavyAndLeftDownLight {\uchar{37}{038}} %%BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT
+\definecharacter UnicodeDownHeavyAndLeftUpLight {\uchar{37}{039}} %%BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT
+\definecharacter UnicodeVerticalHeavyAndLeftLight {\uchar{37}{040}} %%BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT
+\definecharacter UnicodeDownLightAndLeftUpHeavy {\uchar{37}{041}} %%BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY
+\definecharacter UnicodeUpLightAndLeftDownHeavy {\uchar{37}{042}} %%BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY
+\definecharacter UnicodeHeavyVerticalAndLeft {\uchar{37}{043}} %%BOX DRAWINGS HEAVY VERTICAL AND LEFT
+\definecharacter UnicodeLightDownAndHorizontal {\uchar{37}{044}} %%BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+\definecharacter UnicodeLeftHeavyAndRightDownLight {\uchar{37}{045}} %%BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT
+\definecharacter UnicodeRightHeavyAndLeftDownLight {\uchar{37}{046}} %%BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT
+\definecharacter UnicodeDownLightAndHorizontalHeavy {\uchar{37}{047}} %%BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY
+\definecharacter UnicodeDownHeavyAndHorizontalLight {\uchar{37}{048}} %%BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT
+\definecharacter UnicodeRightLightAndLeftDownHeavy {\uchar{37}{049}} %%BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY
+\definecharacter UnicodeLeftLightAndRightDownHeavy {\uchar{37}{050}} %%BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY
+\definecharacter UnicodeHeavyDownAndHorizontal {\uchar{37}{051}} %%BOX DRAWINGS HEAVY DOWN AND HORIZONTAL
+\definecharacter UnicodeLightUpAndHorizontal {\uchar{37}{052}} %%BOX DRAWINGS LIGHT UP AND HORIZONTAL
+\definecharacter UnicodeLeftHeavyAndRightUpLight {\uchar{37}{053}} %%BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT
+\definecharacter UnicodeRightHeavyAndLeftUpLight {\uchar{37}{054}} %%BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT
+\definecharacter UnicodeUpLightAndHorizontalHeavy {\uchar{37}{055}} %%BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY
+\definecharacter UnicodeUpHeavyAndHorizontalLight {\uchar{37}{056}} %%BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT
+\definecharacter UnicodeRightLightAndLeftUpHeavy {\uchar{37}{057}} %%BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY
+\definecharacter UnicodeLeftLightAndRightUpHeavy {\uchar{37}{058}} %%BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY
+\definecharacter UnicodeHeavyUpAndHorizontal {\uchar{37}{059}} %%BOX DRAWINGS HEAVY UP AND HORIZONTAL
+\definecharacter UnicodeLightVerticalAndHorizontal {\uchar{37}{060}} %%BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+\definecharacter UnicodeLeftHeavyAndRightVerticalLight {\uchar{37}{061}} %%BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT
+\definecharacter UnicodeRightHeavyAndLeftVerticalLight {\uchar{37}{062}} %%BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT
+\definecharacter UnicodeVerticalLightAndHorizontalHeavy {\uchar{37}{063}} %%BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY
+\definecharacter UnicodeUpHeavyAndDownHorizontalLight {\uchar{37}{064}} %%BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT
+\definecharacter UnicodeDownHeavyAndUpHorizontalLight {\uchar{37}{065}} %%BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT
+\definecharacter UnicodeVerticalHeavyAndHorizontalLight {\uchar{37}{066}} %%BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT
+\definecharacter UnicodeLeftUpHeavyAndRightDownLight {\uchar{37}{067}} %%BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT
+\definecharacter UnicodeRightUpHeavyAndLeftDownLight {\uchar{37}{068}} %%BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT
+\definecharacter UnicodeLeftDownHeavyAndRightUpLight {\uchar{37}{069}} %%BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT
+\definecharacter UnicodeRightDownHeavyAndLeftUpLight {\uchar{37}{070}} %%BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT
+\definecharacter UnicodeDownLightAndUpHorizontalHeavy {\uchar{37}{071}} %%BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY
+\definecharacter UnicodeUpLightAndDownHorizontalHeavy {\uchar{37}{072}} %%BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY
+\definecharacter UnicodeRightLightAndLeftVerticalHeavy {\uchar{37}{073}} %%BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY
+\definecharacter UnicodeLeftLightAndRightVerticalHeavy {\uchar{37}{074}} %%BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY
+\definecharacter UnicodeHeavyVerticalAndHorizontal {\uchar{37}{075}} %%BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL
+\definecharacter UnicodeLightDoubleDashHorizontal {\uchar{37}{076}} %%BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL
+\definecharacter UnicodeHeavyDoubleDashHorizontal {\uchar{37}{077}} %%BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL
+\definecharacter UnicodeLightDoubleDashVertical {\uchar{37}{078}} %%BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL
+\definecharacter UnicodeHeavyDoubleDashVertical {\uchar{37}{079}} %%BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL
+\definecharacter UnicodeDoubleHorizontal {\uchar{37}{080}} %%BOX DRAWINGS DOUBLE HORIZONTAL
+\definecharacter UnicodeDoubleVertical {\uchar{37}{081}} %%BOX DRAWINGS DOUBLE VERTICAL
+\definecharacter UnicodeDownSingleAndRightDouble {\uchar{37}{082}} %%BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+\definecharacter UnicodeDownDoubleAndRightSingle {\uchar{37}{083}} %%BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+\definecharacter UnicodeDoubleDownAndRight {\uchar{37}{084}} %%BOX DRAWINGS DOUBLE DOWN AND RIGHT
+\definecharacter UnicodeDownSingleAndLeftDouble {\uchar{37}{085}} %%BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+\definecharacter UnicodeDownDoubleAndLeftSingle {\uchar{37}{086}} %%BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+\definecharacter UnicodeDoubleDownAndLeft {\uchar{37}{087}} %%BOX DRAWINGS DOUBLE DOWN AND LEFT
+\definecharacter UnicodeUpSingleAndRightDouble {\uchar{37}{088}} %%BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+\definecharacter UnicodeUpDoubleAndRightSingle {\uchar{37}{089}} %%BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+\definecharacter UnicodeDoubleUpAndRight {\uchar{37}{090}} %%BOX DRAWINGS DOUBLE UP AND RIGHT
+\definecharacter UnicodeUpSingleAndLeftDouble {\uchar{37}{091}} %%BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+\definecharacter UnicodeUpDoubleAndLeftSingle {\uchar{37}{092}} %%BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+\definecharacter UnicodeDoubleUpAndLeft {\uchar{37}{093}} %%BOX DRAWINGS DOUBLE UP AND LEFT
+\definecharacter UnicodeVerticalSingleAndRightDouble {\uchar{37}{094}} %%BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+\definecharacter UnicodeVerticalDoubleAndRightSingle {\uchar{37}{095}} %%BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+\definecharacter UnicodeDoubleVerticalAndRight {\uchar{37}{096}} %%BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+\definecharacter UnicodeVerticalSingleAndLeftDouble {\uchar{37}{097}} %%BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+\definecharacter UnicodeVerticalDoubleAndLeftSingle {\uchar{37}{098}} %%BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+\definecharacter UnicodeDoubleVerticalAndLeft {\uchar{37}{099}} %%BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+\definecharacter UnicodeDownSingleAndHorizontalDouble {\uchar{37}{100}} %%BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+\definecharacter UnicodeDownDoubleAndHorizontalSingle {\uchar{37}{101}} %%BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+\definecharacter UnicodeDoubleDownAndHorizontal {\uchar{37}{102}} %%BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+\definecharacter UnicodeUpSingleAndHorizontalDouble {\uchar{37}{103}} %%BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+\definecharacter UnicodeUpDoubleAndHorizontalSingle {\uchar{37}{104}} %%BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+\definecharacter UnicodeDoubleUpAndHorizontal {\uchar{37}{105}} %%BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+\definecharacter UnicodeVerticalSingleAndHorizontalDouble {\uchar{37}{106}} %%BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+\definecharacter UnicodeVerticalDoubleAndHorizontalSingle {\uchar{37}{107}} %%BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+\definecharacter UnicodeDoubleVerticalAndHorizontal {\uchar{37}{108}} %%BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+\definecharacter UnicodeLightArcDownAndRight {\uchar{37}{109}} %%BOX DRAWINGS LIGHT ARC DOWN AND RIGHT
+\definecharacter UnicodeLightArcDownAndLeft {\uchar{37}{110}} %%BOX DRAWINGS LIGHT ARC DOWN AND LEFT
+\definecharacter UnicodeLightArcUpAndLeft {\uchar{37}{111}} %%BOX DRAWINGS LIGHT ARC UP AND LEFT
+\definecharacter UnicodeLightArcUpAndRight {\uchar{37}{112}} %%BOX DRAWINGS LIGHT ARC UP AND RIGHT
+\definecharacter UnicodeLightDiagonalUpperRightToLowerLeft {\uchar{37}{113}} %%BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT
+\definecharacter UnicodeLightDiagonalUpperLeftToLowerRight {\uchar{37}{114}} %%BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT
+\definecharacter UnicodeLightDiagonalCross {\uchar{37}{115}} %%BOX DRAWINGS LIGHT DIAGONAL CROSS
+\definecharacter UnicodeLightLeft {\uchar{37}{116}} %%BOX DRAWINGS LIGHT LEFT
+\definecharacter UnicodeLightUp {\uchar{37}{117}} %%BOX DRAWINGS LIGHT UP
+\definecharacter UnicodeLightRight {\uchar{37}{118}} %%BOX DRAWINGS LIGHT RIGHT
+\definecharacter UnicodeLightDown {\uchar{37}{119}} %%BOX DRAWINGS LIGHT DOWN
+\definecharacter UnicodeHeavyLeft {\uchar{37}{120}} %%BOX DRAWINGS HEAVY LEFT
+\definecharacter UnicodeHeavyUp {\uchar{37}{121}} %%BOX DRAWINGS HEAVY UP
+\definecharacter UnicodeHeavyRight {\uchar{37}{122}} %%BOX DRAWINGS HEAVY RIGHT
+\definecharacter UnicodeHeavyDown {\uchar{37}{123}} %%BOX DRAWINGS HEAVY DOWN
+\definecharacter UnicodeLightLeftAndHeavyRight {\uchar{37}{124}} %%BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT
+\definecharacter UnicodeLightUpAndHeavyDown {\uchar{37}{125}} %%BOX DRAWINGS LIGHT UP AND HEAVY DOWN
+\definecharacter UnicodeHeavyLeftAndLightRight {\uchar{37}{126}} %%BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT
+\definecharacter UnicodeHeavyUpAndLightDown {\uchar{37}{127}} %%BOX DRAWINGS HEAVY UP AND LIGHT DOWN
+\definecharacter UnicodeUpperHalfBlock {\uchar{37}{128}} %%UPPER HALF BLOCK
+\definecharacter UnicodeLowerOneEighthBlock {\uchar{37}{129}} %%LOWER ONE EIGHTH BLOCK
+\definecharacter UnicodeLowerOneQuarterBlock {\uchar{37}{130}} %%LOWER ONE QUARTER BLOCK
+\definecharacter UnicodeLowerThreeEighthsBlock {\uchar{37}{131}} %%LOWER THREE EIGHTHS BLOCK
+\definecharacter UnicodeLowerHalfBlock {\uchar{37}{132}} %%LOWER HALF BLOCK
+\definecharacter UnicodeLowerFiveEighthsBlock {\uchar{37}{133}} %%LOWER FIVE EIGHTHS BLOCK
+\definecharacter UnicodeLowerThreeQuartersBlock {\uchar{37}{134}} %%LOWER THREE QUARTERS BLOCK
+\definecharacter UnicodeLowerSevenEighthsBlock {\uchar{37}{135}} %%LOWER SEVEN EIGHTHS BLOCK
+\definecharacter UnicodeFullBlock {\uchar{37}{136}} %%FULL BLOCK
+\definecharacter UnicodeLeftSevenEighthsBlock {\uchar{37}{137}} %%LEFT SEVEN EIGHTHS BLOCK
+\definecharacter UnicodeLeftThreeQuartersBlock {\uchar{37}{138}} %%LEFT THREE QUARTERS BLOCK
+\definecharacter UnicodeLeftFiveEighthsBlock {\uchar{37}{139}} %%LEFT FIVE EIGHTHS BLOCK
+\definecharacter UnicodeLeftHalfBlock {\uchar{37}{140}} %%LEFT HALF BLOCK
+\definecharacter UnicodeLeftThreeEighthsBlock {\uchar{37}{141}} %%LEFT THREE EIGHTHS BLOCK
+\definecharacter UnicodeLeftOneQuarterBlock {\uchar{37}{142}} %%LEFT ONE QUARTER BLOCK
+\definecharacter UnicodeLeftOneEighthBlock {\uchar{37}{143}} %%LEFT ONE EIGHTH BLOCK
+\definecharacter UnicodeRightHalfBlock {\uchar{37}{144}} %%RIGHT HALF BLOCK
+\definecharacter UnicodeLightShade {\uchar{37}{145}} %%LIGHT SHADE
+\definecharacter UnicodeMediumShade {\uchar{37}{146}} %%MEDIUM SHADE
+\definecharacter UnicodeDarkShade {\uchar{37}{147}} %%DARK SHADE
+\definecharacter UnicodeUpperOneEighthBlock {\uchar{37}{148}} %%UPPER ONE EIGHTH BLOCK
+\definecharacter UnicodeRightOneEighthBlock {\uchar{37}{149}} %%RIGHT ONE EIGHTH BLOCK
+\definecharacter UnicodeQuadrantLowerLeft {\uchar{37}{150}} %%[Unassigned U+2596]
+\definecharacter UnicodeQuadrantLowerRight {\uchar{37}{151}} %%[Unassigned U+2597]
+\definecharacter UnicodeQuadrantUpperLeft {\uchar{37}{152}} %%[Unassigned U+2598]
+\definecharacter UnicodeQuadrantUpperLeftAndLowerLeftAndLowerRight {\uchar{37}{153}} %%[Unassigned U+2599]
+\definecharacter UnicodeQuadrantUpperLeftAndLowerRight {\uchar{37}{154}} %%[Unassigned U+259A]
+\definecharacter UnicodeQuadrantUpperLeftAndUpperRightandLowerLeft {\uchar{37}{155}} %%[Unassigned U+259B]
+\definecharacter UnicodeQuadrantUpperLeftAndUpperRightAndLowerRight {\uchar{37}{156}} %%[Unassigned U+259C]
+\definecharacter UnicodeQuadrantUpperRight {\uchar{37}{157}} %%[Unassigned U+259D]
+\definecharacter UnicodeQuadrantUpperRightAndLowerLeft {\uchar{37}{158}} %%[Unassigned U+259E]
+\definecharacter UnicodeQuadrantUpperRightAndLowerLeftAndLowerRight {\uchar{37}{159}} %%[Unassigned U+259F]
+\definecharacter UnicodeBlackSquare {\uchar{37}{160}} %%BLACK SQUARE
+\definecharacter UnicodeWhiteSquare {\uchar{37}{161}} %%WHITE SQUARE
+\definecharacter UnicodeWhiteSquareWithRoundedCorners {\uchar{37}{162}} %%WHITE SQUARE WITH ROUNDED CORNERS
+\definecharacter UnicodeWhiteSquareContainingBlackSmallSquare {\uchar{37}{163}} %%WHITE SQUARE CONTAINING BLACK SMALL SQUARE
+\definecharacter UnicodeSquareWithHorizontalFill {\uchar{37}{164}} %%SQUARE WITH HORIZONTAL FILL
+\definecharacter UnicodeSquareWithVerticalFill {\uchar{37}{165}} %%SQUARE WITH VERTICAL FILL
+\definecharacter UnicodeSquareWithOrthogonalCrosshatchFill {\uchar{37}{166}} %%SQUARE WITH ORTHOGONAL CROSSHATCH FILL
+\definecharacter UnicodeSquareWithUpperLeftToLowerRightFill {\uchar{37}{167}} %%SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL
+\definecharacter UnicodeSquareWithUpperRightToLowerLeftFill {\uchar{37}{168}} %%SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL
+\definecharacter UnicodeSquareWithDiagonalCrosshatchFill {\uchar{37}{169}} %%SQUARE WITH DIAGONAL CROSSHATCH FILL
+\definecharacter UnicodeBlackSmallSquare {\uchar{37}{170}} %%BLACK SMALL SQUARE
+\definecharacter UnicodeWhiteSmallSquare {\uchar{37}{171}} %%WHITE SMALL SQUARE
+\definecharacter UnicodeBlackRectangle {\uchar{37}{172}} %%BLACK RECTANGLE
+\definecharacter UnicodeWhiteRectangle {\uchar{37}{173}} %%WHITE RECTANGLE
+\definecharacter UnicodeBlackVerticalRectangle {\uchar{37}{174}} %%BLACK VERTICAL RECTANGLE
+\definecharacter UnicodeWhiteVerticalRectangle {\uchar{37}{175}} %%WHITE VERTICAL RECTANGLE
+\definecharacter UnicodeBlackParallelogram {\uchar{37}{176}} %%BLACK PARALLELOGRAM
+\definecharacter UnicodeWhiteParallelogram {\uchar{37}{177}} %%WHITE PARALLELOGRAM
+\definecharacter UnicodeBlackUpPointingTriangle {\uchar{37}{178}} %%BLACK UP-POINTING TRIANGLE
+\definecharacter UnicodeWhiteUpPointingTriangle {\uchar{37}{179}} %%WHITE UP-POINTING TRIANGLE
+\definecharacter UnicodeBlackUpPointingSmallTriangle {\uchar{37}{180}} %%BLACK UP-POINTING SMALL TRIANGLE
+\definecharacter UnicodeWhiteUpPointingSmallTriangle {\uchar{37}{181}} %%WHITE UP-POINTING SMALL TRIANGLE
+\definecharacter UnicodeBlackRightPointingTriangle {\uchar{37}{182}} %%BLACK RIGHT-POINTING TRIANGLE
+\definecharacter UnicodeWhiteRightPointingTriangle {\uchar{37}{183}} %%WHITE RIGHT-POINTING TRIANGLE
+\definecharacter UnicodeBlackRightPointingSmallTriangle {\uchar{37}{184}} %%BLACK RIGHT-POINTING SMALL TRIANGLE
+\definecharacter UnicodeWhiteRightPointingSmallTriangle {\uchar{37}{185}} %%WHITE RIGHT-POINTING SMALL TRIANGLE
+\definecharacter UnicodeBlackRightPointingPointer {\uchar{37}{186}} %%BLACK RIGHT-POINTING POINTER
+\definecharacter UnicodeWhiteRightPointingPointer {\uchar{37}{187}} %%WHITE RIGHT-POINTING POINTER
+\definecharacter UnicodeBlackDownPointingTriangle {\uchar{37}{188}} %%BLACK DOWN-POINTING TRIANGLE
+\definecharacter UnicodeWhiteDownPointingTriangle {\uchar{37}{189}} %%WHITE DOWN-POINTING TRIANGLE
+\definecharacter UnicodeBlackDownPointingSmallTriangle {\uchar{37}{190}} %%BLACK DOWN-POINTING SMALL TRIANGLE
+\definecharacter UnicodeWhiteDownPointingSmallTriangle {\uchar{37}{191}} %%WHITE DOWN-POINTING SMALL TRIANGLE
+\definecharacter UnicodeBlackLeftPointingTriangle {\uchar{37}{192}} %%BLACK LEFT-POINTING TRIANGLE
+\definecharacter UnicodeWhiteLeftPointingTriangle {\uchar{37}{193}} %%WHITE LEFT-POINTING TRIANGLE
+\definecharacter UnicodeBlackLeftPointingSmallTriangle {\uchar{37}{194}} %%BLACK LEFT-POINTING SMALL TRIANGLE
+\definecharacter UnicodeWhiteLeftPointingSmallTriangle {\uchar{37}{195}} %%WHITE LEFT-POINTING SMALL TRIANGLE
+\definecharacter UnicodeBlackLeftPointingPointer {\uchar{37}{196}} %%BLACK LEFT-POINTING POINTER
+\definecharacter UnicodeWhiteLeftPointingPointer {\uchar{37}{197}} %%WHITE LEFT-POINTING POINTER
+\definecharacter UnicodeBlackDiamond {\uchar{37}{198}} %%BLACK DIAMOND
+\definecharacter UnicodeWhiteDiamond {\uchar{37}{199}} %%WHITE DIAMOND
+\definecharacter UnicodeWhiteDiamondContainingBlackSmallDiamond {\uchar{37}{200}} %%WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND
+\definecharacter UnicodeFisheye {\uchar{37}{201}} %%FISHEYE
+\definecharacter UnicodeLozenge {\uchar{37}{202}} %%LOZENGE
+\definecharacter UnicodeWhiteCircle {\uchar{37}{203}} %%WHITE CIRCLE
+\definecharacter UnicodeDottedCircle {\uchar{37}{204}} %%DOTTED CIRCLE
+\definecharacter UnicodeCircleWithVerticalFill {\uchar{37}{205}} %%CIRCLE WITH VERTICAL FILL
+\definecharacter UnicodeBullseye {\uchar{37}{206}} %%BULLSEYE
+\definecharacter UnicodeBlackCircle {\uchar{37}{207}} %%BLACK CIRCLE
+\definecharacter UnicodeCircleWithLeftHalfBlack {\uchar{37}{208}} %%CIRCLE WITH LEFT HALF BLACK
+\definecharacter UnicodeCircleWithRightHalfBlack {\uchar{37}{209}} %%CIRCLE WITH RIGHT HALF BLACK
+\definecharacter UnicodeCircleWithLowerHalfBlack {\uchar{37}{210}} %%CIRCLE WITH LOWER HALF BLACK
+\definecharacter UnicodeCircleWithUpperHalfBlack {\uchar{37}{211}} %%CIRCLE WITH UPPER HALF BLACK
+\definecharacter UnicodeCircleWithUpperRightQuadrantBlack {\uchar{37}{212}} %%CIRCLE WITH UPPER RIGHT QUADRANT BLACK
+\definecharacter UnicodeCircleWithAllButUpperLeftQuadrantBlack {\uchar{37}{213}} %%CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK
+\definecharacter UnicodeLeftHalfBlackCircle {\uchar{37}{214}} %%LEFT HALF BLACK CIRCLE
+\definecharacter UnicodeRightHalfBlackCircle {\uchar{37}{215}} %%RIGHT HALF BLACK CIRCLE
+\definecharacter UnicodeInverseBullet {\uchar{37}{216}} %%INVERSE BULLET
+\definecharacter UnicodeInverseWhiteCircle {\uchar{37}{217}} %%INVERSE WHITE CIRCLE
+\definecharacter UnicodeUpperHalfInverseWhiteCircle {\uchar{37}{218}} %%UPPER HALF INVERSE WHITE CIRCLE
+\definecharacter UnicodeLowerHalfInverseWhiteCircle {\uchar{37}{219}} %%LOWER HALF INVERSE WHITE CIRCLE
+\definecharacter UnicodeUpperLeftQuadrantCircularArc {\uchar{37}{220}} %%UPPER LEFT QUADRANT CIRCULAR ARC
+\definecharacter UnicodeUpperRightQuadrantCircularArc {\uchar{37}{221}} %%UPPER RIGHT QUADRANT CIRCULAR ARC
+\definecharacter UnicodeLowerRightQuadrantCircularArc {\uchar{37}{222}} %%LOWER RIGHT QUADRANT CIRCULAR ARC
+\definecharacter UnicodeLowerLeftQuadrantCircularArc {\uchar{37}{223}} %%LOWER LEFT QUADRANT CIRCULAR ARC
+\definecharacter UnicodeUpperHalfCircle {\uchar{37}{224}} %%UPPER HALF CIRCLE
+\definecharacter UnicodeLowerHalfCircle {\uchar{37}{225}} %%LOWER HALF CIRCLE
+\definecharacter UnicodeBlackLowerRightTriangle {\uchar{37}{226}} %%BLACK LOWER RIGHT TRIANGLE
+\definecharacter UnicodeBlackLowerLeftTriangle {\uchar{37}{227}} %%BLACK LOWER LEFT TRIANGLE
+\definecharacter UnicodeBlackUpperLeftTriangle {\uchar{37}{228}} %%BLACK UPPER LEFT TRIANGLE
+\definecharacter UnicodeBlackUpperRightTriangle {\uchar{37}{229}} %%BLACK UPPER RIGHT TRIANGLE
+\definecharacter UnicodeWhiteBullet {\uchar{37}{230}} %%WHITE BULLET
+\definecharacter UnicodeSquareWithLeftHalfBlack {\uchar{37}{231}} %%SQUARE WITH LEFT HALF BLACK
+\definecharacter UnicodeSquareWithRightHalfBlack {\uchar{37}{232}} %%SQUARE WITH RIGHT HALF BLACK
+\definecharacter UnicodeSquareWithUpperLeftDiagonalHalfBlack {\uchar{37}{233}} %%SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK
+\definecharacter UnicodeSquareWithLowerRightDiagonalHalfBlack {\uchar{37}{234}} %%SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK
+\definecharacter UnicodeWhiteSquareWithVerticalBisectingLine {\uchar{37}{235}} %%WHITE SQUARE WITH VERTICAL BISECTING LINE
+\definecharacter UnicodeWhiteUpPointingTriangleWithDot {\uchar{37}{236}} %%WHITE UP-POINTING TRIANGLE WITH DOT
+\definecharacter UnicodeUpPointingTriangleWithLeftHalfBlack {\uchar{37}{237}} %%UP-POINTING TRIANGLE WITH LEFT HALF BLACK
+\definecharacter UnicodeUpPointingTriangleWithRightHalfBlack {\uchar{37}{238}} %%UP-POINTING TRIANGLE WITH RIGHT HALF BLACK
+\definecharacter UnicodeLargeCircle {\uchar{37}{239}} %%LARGE CIRCLE
+\definecharacter UnicodeWhiteSquareWithUpperLeftQuadrant {\uchar{37}{240}} %%WHITE SQUARE WITH UPPER LEFT QUADRANT
+\definecharacter UnicodeWhiteSquareWithLowerLeftQuadrant {\uchar{37}{241}} %%WHITE SQUARE WITH LOWER LEFT QUADRANT
+\definecharacter UnicodeWhiteSquareWithLowerRightQuadrant {\uchar{37}{242}} %%WHITE SQUARE WITH LOWER RIGHT QUADRANT
+\definecharacter UnicodeWhiteSquareWithUpperRightQuadrant {\uchar{37}{243}} %%WHITE SQUARE WITH UPPER RIGHT QUADRANT
+\definecharacter UnicodeWhiteCircleWithUpperLeftQuadrant {\uchar{37}{244}} %%WHITE CIRCLE WITH UPPER LEFT QUADRANT
+\definecharacter UnicodeWhiteCircleWithLowerLeftQuadrant {\uchar{37}{245}} %%WHITE CIRCLE WITH LOWER LEFT QUADRANT
+\definecharacter UnicodeWhiteCircleWithLowerRightQuadrant {\uchar{37}{246}} %%WHITE CIRCLE WITH LOWER RIGHT QUADRANT
+\definecharacter UnicodeWhiteCircleWithUpperRightQuadrant {\uchar{37}{247}} %%WHITE CIRCLE WITH UPPER RIGHT QUADRANT
+\definecharacter UnicodeUpperLeftTriangle {\uchar{37}{248}} %%[Unassigned U+25F8]
+\definecharacter UnicodeUpperRightTriangle {\uchar{37}{249}} %%[Unassigned U+25F9]
+\definecharacter UnicodeLowerLeftTriangle {\uchar{37}{250}} %%[Unassigned U+25FA]
+\definecharacter UnicodeWhiteMediumSquare {\uchar{37}{251}} %%[Unassigned U+25FB]
+\definecharacter UnicodeBlackMediumSquare {\uchar{37}{252}} %%[Unassigned U+25FC]
+\definecharacter UnicodeWhiteMediumSmallSquare {\uchar{37}{253}} %%[Unassigned U+25FD]
+\definecharacter UnicodeBlackMediumSmallSquare {\uchar{37}{254}} %%[Unassigned U+25FE]
+\definecharacter UnicodeLowerRightTriangle {\uchar{37}{255}} %%[Unassigned U+25FF]
+
+\stopencoding
+
+\endinput
+
diff --git a/tex/context/base/enco-acc.mkii b/tex/context/base/enco-acc.mkii
new file mode 100644
index 000000000..e02536be6
--- /dev/null
+++ b/tex/context/base/enco-acc.mkii
@@ -0,0 +1,139 @@
+%D \module
+%D [ file=enco-acc,
+%D version=2000.20.12, % split from base file
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Composed Characters Commands,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=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.
+
+%D Although it is technically possible to redefine the commands
+%D that are responsible for building composed characters, this
+%D is seldom needed, since they map onto named glyphs. The
+%D meaning of these names glyphs may change, although their
+%D visual appearance seldom will.
+
+\startencoding[default]
+
+\defineaccent ^ A {\Acircumflex} \defineaccent ^ a {\acircumflex}
+\defineaccent ^ C {\Ccircumflex} \defineaccent ^ c {\ccircumflex}
+\defineaccent ^ E {\Ecircumflex} \defineaccent ^ e {\ecircumflex}
+\defineaccent ^ G {\Gcircumflex} \defineaccent ^ g {\gcircumflex}
+\defineaccent ^ H {\Hcircumflex} \defineaccent ^ h {\hcircumflex}
+\defineaccent ^ I {\Icircumflex} \defineaccent ^ i {\icircumflex} \defineaccent ^ {\i} {\icircumflex}
+\defineaccent ^ J {\Jcircumflex} \defineaccent ^ j {\jcircumflex} \defineaccent ^ {\j} {\jcircumflex}
+\defineaccent ^ O {\Ocircumflex} \defineaccent ^ o {\ocircumflex}
+\defineaccent ^ S {\Scircumflex} \defineaccent ^ s {\scircumflex}
+\defineaccent ^ U {\Ucircumflex} \defineaccent ^ u {\ucircumflex}
+\defineaccent ^ W {\Wcircumflex} \defineaccent ^ w {\wcircumflex}
+\defineaccent ^ Y {\Ycircumflex} \defineaccent ^ y {\ycircumflex}
+
+\defineaccent ` A {\Agrave} \defineaccent ` a {\agrave}
+\defineaccent ` E {\Egrave} \defineaccent ` e {\egrave}
+\defineaccent ` I {\Igrave} \defineaccent ` i {\igrave} \defineaccent ` {\i} {\igrave}
+\defineaccent ` O {\Ograve} \defineaccent ` o {\ograve}
+\defineaccent ` U {\Ugrave} \defineaccent ` u {\ugrave}
+\defineaccent ` Y {\Ygrave} \defineaccent ` y {\ygrave}
+
+\defineaccent ~ A {\Atilde} \defineaccent ~ a {\atilde}
+\defineaccent ~ I {\Itilde} \defineaccent ~ i {\itilde} \defineaccent ~ {\i} {\itilde}
+\defineaccent ~ O {\Otilde} \defineaccent ~ o {\otilde}
+\defineaccent ~ U {\Utilde} \defineaccent ~ u {\utilde}
+
+\defineaccent " A {\Adiaeresis} \defineaccent " a {\adiaeresis}
+\defineaccent " E {\Ediaeresis} \defineaccent " e {\ediaeresis}
+\defineaccent " I {\Idiaeresis} \defineaccent " i {\idiaeresis} \defineaccent " {\i} {\idiaeresis}
+\defineaccent " O {\Odiaeresis} \defineaccent " o {\odiaeresis}
+\defineaccent " U {\Udiaeresis} \defineaccent " u {\udiaeresis}
+\defineaccent " Y {\Ydiaeresis} \defineaccent " y {\ydiaeresis}
+
+\defineaccent ' A {\Aacute} \defineaccent ' a {\aacute}
+\defineaccent ' C {\Cacute} \defineaccent ' c {\cacute}
+\defineaccent ' E {\Eacute} \defineaccent ' e {\eacute}
+\defineaccent ' I {\Iacute} \defineaccent ' i {\iacute} \defineaccent ' {\i} {\iacute}
+\defineaccent ' L {\Lacute} \defineaccent ' l {\lacute}
+\defineaccent ' N {\Nacute} \defineaccent ' n {\nacute}
+\defineaccent ' O {\Oacute} \defineaccent ' o {\oacute}
+\defineaccent ' R {\Racute} \defineaccent ' r {\racute}
+\defineaccent ' S {\Sacute} \defineaccent ' s {\sacute}
+\defineaccent ' U {\Uacute} \defineaccent ' u {\uacute}
+\defineaccent ' Y {\Yacute} \defineaccent ' y {\yacute}
+\defineaccent ' Z {\Zacute} \defineaccent ' z {\zacute}
+
+\defineaccent . C {\Cdotaccent} \defineaccent . c {\cdotaccent}
+\defineaccent . E {\Edotaccent} \defineaccent . e {\edotaccent}
+\defineaccent . G {\Gdotaccent} \defineaccent . g {\gdotaccent}
+\defineaccent . I {\Idotaccent} \defineaccent . i {\idotaccent} \defineaccent . {\i} {\idotaccent}
+\defineaccent . Z {\Zdotaccent} \defineaccent . z {\zdotaccent}
+
+\defineaccent = A {\Amacron} \defineaccent = a {\amacron}
+\defineaccent = E {\Emacron} \defineaccent = e {\emacron}
+\defineaccent = I {\Imacron} \defineaccent = i {\imacron} \defineaccent = {\i} {\imacron}
+\defineaccent = O {\Omacron} \defineaccent = o {\omacron}
+\defineaccent = U {\Umacron} \defineaccent = u {\umacron}
+
+\defineaccent c C {\Ccedilla} \defineaccent c c {\ccedilla}
+\defineaccent c K {\Kcedilla} \defineaccent c k {\kcedilla}
+\defineaccent c L {\Lcedilla} \defineaccent c l {\lcedilla}
+\defineaccent c N {\Ncedilla} \defineaccent c n {\ncedilla}
+\defineaccent c R {\Rcedilla} \defineaccent c r {\rcedilla}
+\defineaccent c S {\Scedilla} \defineaccent c s {\scedilla}
+\defineaccent c T {\Tcedilla} \defineaccent c t {\tcedilla}
+
+\defineaccent H O {\Ohungarumlaut} \defineaccent H o {\ohungarumlaut}
+\defineaccent H u {\uhungarumlaut} \defineaccent H U {\Uhungarumlaut}
+
+\defineaccent k A {\Aogonek} \defineaccent k a {\aogonek}
+\defineaccent k E {\Eogonek} \defineaccent k e {\eogonek}
+\defineaccent k I {\Iogonek} \defineaccent k i {\iogonek}
+\defineaccent k U {\Uogonek} \defineaccent k u {\uogonek}
+
+\defineaccent r A {\Aring} \defineaccent r a {\aring}
+\defineaccent r U {\Uring} \defineaccent r u {\uring}
+
+\defineaccent u A {\Abreve} \defineaccent u a {\abreve}
+\defineaccent u E {\Ebreve} \defineaccent u e {\ebreve}
+\defineaccent u G {\Gbreve} \defineaccent u g {\gbreve}
+\defineaccent u I {\Ibreve} \defineaccent u i {\ibreve} \defineaccent u {\i} {\ibreve}
+\defineaccent u O {\Obreve} \defineaccent u o {\obreve}
+\defineaccent u U {\Ubreve} \defineaccent u u {\ubreve}
+
+\defineaccent v C {\Ccaron} \defineaccent v c {\ccaron}
+\defineaccent v D {\Dcaron} \defineaccent v d {\dcaron}
+\defineaccent v E {\Ecaron} \defineaccent v e {\ecaron}
+\defineaccent v L {\Lcaron} \defineaccent v l {\lcaron}
+\defineaccent v N {\Ncaron} \defineaccent v n {\ncaron}
+\defineaccent v R {\Rcaron} \defineaccent v r {\rcaron}
+\defineaccent v S {\Scaron} \defineaccent v s {\scaron}
+\defineaccent v T {\Tcaron} \defineaccent v t {\tcaron}
+\defineaccent v Z {\Zcaron} \defineaccent v z {\zcaron}
+
+\stopencoding
+
+\startencoding[default]
+
+% vietnamese: if needed, \useencoding[enco-vna]
+
+\stopencoding
+
+% For Tobias Burnus, who wants:
+%
+% \starttypen
+% \setupinteraction[state=start]
+% \setupinteractionscreen[option=bookmark]
+% \placebookmarks[chapter]
+%
+% \starttext \chapter{F\"ur Na\"ive und Na\"\i ve} \stoptext
+% \stoptypen
+
+\startencoding[default]
+
+ \defineaccent " {\i} {\idiaeresis}
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-agr.mkii b/tex/context/base/enco-agr.mkii
new file mode 100644
index 000000000..cfd86dfd3
--- /dev/null
+++ b/tex/context/base/enco-agr.mkii
@@ -0,0 +1,364 @@
+%D \module
+%D [ file=enco-agr,
+%D version=2005.02.20,
+%D title=\CONTEXT\ \UNICODE\ Macros,
+%D subtitle=Ancient Greek,
+%D author=Thomas A. Schmitz,
+%D date=\currentdate]
+
+\startmapping[agr]
+
+ \definecasemaps 13 to 64 lc 0 uc 0
+ \definecasemaps 65 to 66 lc +32 uc 0
+ \definecasemaps 67 to 67 lc 0 uc 0
+ \definecasemaps 68 to 85 lc +32 uc 0
+ \definecasemaps 86 to 86 lc 0 uc 0
+ \definecasemaps 87 to 90 lc +32 uc 0
+ \definecasemaps 91 to 255 lc 0 uc 0
+
+\stopmapping
+
+\startencoding[agr]
+
+\definecharacter greeksigmalunate 1
+\definecharacter endash 2
+\definecharacter emdash 3
+\definecharacter apostrophe 4
+\definecharacter greekaltbeta 5
+\definecharacter epih 6
+
+\definecharacter textbraceleft 8
+\definecharacter textbraceright 9
+\definecharacter textbreve 10
+
+\definecharacter greekSigmalunate 13
+\definecharacter greekIotadialytika 14
+\definecharacter greekUpsilondialytika 15
+
+\definecharacter greekepsilonperispomeni 18
+\definecharacter greekomicronperispomeni 19
+\definecharacter greekepsilondasiaperispomeni 20
+\definecharacter greekomicrondasiaperispomeni 21
+\definecharacter greekepsilonpsiliperispomeni 22
+\definecharacter greekomicronpsiliperispomeni 23
+\definecharacter greekiotadialytikaperispomeni 24
+\definecharacter greekupsilondialytikaperispomeni 25
+\definecharacter greekdialytikaperispomeni 26
+
+\definecharacter textbottomdot 33
+\definecharacter greeksampi 34
+\definecharacter greekdigamma 35
+\definecharacter greekstigma 36
+\definecharacter greeknumkoppa 37
+\definecharacter greekkoppa 38
+\definecharacter guilsingleright 39
+
+\definecharacter textdag 43
+
+\definecharacter greekoxia 47
+
+\definecharacter greekanoteleia 59
+\definecharacter greekdasia 60
+
+\definecharacter greekpsili 62
+\definecharacter greekquestionmark 63
+\definecharacter dialytika 64
+\definecharacter greekAlpha 65
+\definecharacter greekBeta 66
+\definecharacter greekomegaiotasub 67
+\definecharacter greekDelta 68
+\definecharacter greekEpsilon 69
+\definecharacter greekPhi 70
+\definecharacter greekGamma 71
+\definecharacter greekEta 72
+\definecharacter greekIota 73
+\definecharacter greekTheta 74
+\definecharacter greekKappa 75
+\definecharacter greekLambda 76
+\definecharacter greekMu 77
+\definecharacter greekNu 78
+\definecharacter greekOmicron 79
+\definecharacter greekPi 80
+\definecharacter greekChi 81
+\definecharacter greekRho 82
+\definecharacter greekSigma 83
+\definecharacter greekTau 84
+\definecharacter greekUpsilon 85
+\definecharacter greeketaiotasub 86
+\definecharacter greekOmega 87
+\definecharacter greekXi 88
+\definecharacter greekPsi 89
+\definecharacter greekZeta 90
+\definecharacter bracketleft 91
+\definecharacter greekvaria 92
+\definecharacter bracketright 93
+\definecharacter greekperispomeni 94
+
+\definecharacter guilsingleleft 96
+
+% the above is a quote character
+\definecharacter greekalpha 97
+\definecharacter greekbeta 98
+\definecharacter greekfinalsigma 99
+\definecharacter greekdelta 100
+\definecharacter greekepsilon 101
+\definecharacter greekphi 102
+\definecharacter greekgamma 103
+\definecharacter greeketa 104
+\definecharacter greekiota 105
+\definecharacter greektheta 106
+\definecharacter greekkappa 107
+\definecharacter greeklambda 108
+\definecharacter greekmu 109
+\definecharacter greeknu 110
+\definecharacter greekomicron 111
+\definecharacter greekpi 112
+\definecharacter greekchi 113
+\definecharacter greekrho 114
+\definecharacter greeksigma 115
+\definecharacter greektau 116
+\definecharacter greekupsilon 117
+\definecharacter greekalphaiotasub 118
+\definecharacter greekomega 119
+\definecharacter greekxi 120
+\definecharacter greekpsi 121
+\definecharacter greekzeta 122
+\definecharacter floorleft 123
+\definecharacter textbar 124
+\definecharacter floorright 125
+\definecharacter greekperispomeni 126
+
+\definecharacter quotedblleft 128
+\definecharacter quotedblright 129
+\definecharacter exclam 130
+\definecharacter greekiotadasia 131
+\definecharacter greekiotapsili 132
+\definecharacter greekiotaoxia 133
+\definecharacter greekiotadasiatonos 134
+\definecharacter greekiotapsilitonos 135
+\definecharacter greekiotavaria 136
+\definecharacter greekiotadasiavaria 137
+\definecharacter greekiotapsilivaria 138
+\definecharacter greekiotaperispomeni 139
+\definecharacter greekiotadasiaperispomeni 140
+\definecharacter greekiotapsiliperispomeni 141
+\definecharacter greekiotadialytika 142
+\definecharacter greekiotadialytikatonos 143
+\definecharacter greekiotadialytikavaria 144
+\definecharacter greekdasiaperispomeni 145
+\definecharacter greekpsiliperispomeni 146
+\definecharacter greekdasiatonos 147
+\definecharacter greekpsilitonos 148
+\definecharacter greekdasiavaria 149
+\definecharacter greekpsilivaria 150
+\definecharacter greekdialytikatonos 151
+\definecharacter greekepsilondasia 152
+\definecharacter greekepsilonpsili 153
+\definecharacter greekepsilonoxia 154
+\definecharacter greekepsilondasiatonos 155
+\definecharacter greekepsilonpsilitonos 156
+\definecharacter greekepsilonvaria 157
+\definecharacter greekepsilondasiavaria 158
+\definecharacter greekepsilonpsilivaria 159
+\definecharacter greekdialytikavaria 160
+\definecharacter greekalphadasia 161
+\definecharacter greekalphapsili 162
+\definecharacter greekalphaoxia 163
+\definecharacter greekalphadasiatonos 164
+\definecharacter greekalphapsilitonos 165
+\definecharacter greekalphavaria 166
+\definecharacter greekalphadasiavaria 167
+\definecharacter greekalphapsilivaria 168
+\definecharacter greekalphaperispomeni 169
+\definecharacter greekalphadasiaperispomeni 170
+\definecharacter greekalphapsiliperispomeni 171
+\definecharacter greekalphaiotasubdasia 172
+\definecharacter greekalphaiotasubpsili 173
+\definecharacter greekalphaiotasubtonos 174
+\definecharacter greekalphaiotasubdasiatonos 175
+\definecharacter greekalphaiotasubpsilitonos 176
+\definecharacter greekalphaiotasubvaria 177
+\definecharacter greekalphaiotasubdasiavaria 178
+\definecharacter greekalphaiotasubpsilivaria 179
+\definecharacter greekalphaiotasubperispomeni 180
+\definecharacter greekalphaiotasubdasiaperispomeni 181
+\definecharacter greekalphaiotasubpsiliperispomeni 182
+\definecharacter greekrhodasia 183
+\definecharacter greekrhopsili 184
+\definecharacter greeketadasia 185
+\definecharacter greeketapsili 186
+\definecharacter greeketaoxia 187
+\definecharacter greeketadasiatonos 188
+\definecharacter greeketapsilitonos 189
+\definecharacter greeketavaria 190
+\definecharacter greeketadasiavaria 191
+\definecharacter greeketapsilivaria 192
+\definecharacter greeketaperispomeni 193
+\definecharacter greeketadasiaperispomeni 194
+\definecharacter greeketapsiliperispomeni 195
+\definecharacter textslash 196
+\definecharacter greeketaiotasubdasia 197
+\definecharacter greeketaiotasubpsili 198
+\definecharacter greeketaiotasubtonos 199
+\definecharacter greeketaiotasubdasiatonos 200
+\definecharacter greeketaiotasubpsilitonos 201
+\definecharacter greeketaiotasubvaria 202
+\definecharacter greeketaiotasubdasiavaria 203
+\definecharacter greeketaiotasubpsilivaria 204
+\definecharacter greeketaiotasubperispomeni 205
+\definecharacter greeketaiotasubdasiaperispomeni 206
+\definecharacter greeketaiotasubpsiliperispomeni 207
+\definecharacter greekomicrondasia 208
+\definecharacter greekomicronpsili 209
+\definecharacter greekomicronoxia 210
+\definecharacter greekomicrondasiatonos 211
+\definecharacter greekomicronpsilitonos 212
+\definecharacter greekomicronvaria 213
+\definecharacter greekomicrondasiavaria 214
+\definecharacter greekomicronpsilivaria 215
+\definecharacter greekupsilondasia 216
+\definecharacter greekupsilonpsili 217
+\definecharacter greekupsilonoxia 218
+\definecharacter greekupsilondasiatonos 219
+\definecharacter greekupsilonpsilitonos 220
+\definecharacter greekupsilonvaria 221
+\definecharacter greekupsilondasiavaria 222
+\definecharacter greekupsilonpsilivaria 223
+\definecharacter greekupsilonperispomeni 224
+\definecharacter greekupsilondasiaperispomeni 225
+\definecharacter greekupsilonpsiliperispomeni 226
+\definecharacter greekupsilondiaeresis 227
+\definecharacter greekupsilondialytikatonos 228
+\definecharacter greekupsilondialytikavaria 229
+\definecharacter greekomegadasia 230
+\definecharacter greekomegapsili 231
+\definecharacter greekomegaoxia 232
+\definecharacter greekomegadasiatonos 233
+\definecharacter greekomegapsilitonos 234
+\definecharacter greekomegavaria 235
+\definecharacter greekomegadasiavaria 236
+\definecharacter greekomegapsilivaria 237
+\definecharacter greekomegaperispomeni 238
+\definecharacter greekomegadasiaperispomeni 239
+\definecharacter greekomegapsiliperispomeni 240
+\definecharacter greekomegaiotasubdasia 241
+\definecharacter greekomegaiotasubpsili 242
+\definecharacter greekomegaiotasubtonos 243
+\definecharacter greekomegaiotasubdasiatonos 244
+\definecharacter greekomegaiotasubpsilitonos 245
+\definecharacter greekomegaiotasubvaria 246
+\definecharacter greekomegaiotasubdasiavaria 247
+\definecharacter greekomegaiotasubpsilivaria 248
+\definecharacter greekomegaiotasubperispomeni 249
+\definecharacter greekomegaiotasubdasiaperispomeni 250
+\definecharacter greekomegaiotasubpsiliperispomeni 251
+\definecharacter greeknumeralsign 254
+\definecharacter greeknumeralsignlower 255
+
+\stopencoding
+
+\startencoding[default]
+
+\definecharacter greekAlphapsili {\greekpsili \greekAlpha}
+\definecharacter greekAlphadasia {\greekdasia \greekAlpha}
+\definecharacter greekAlphapsilivaria {\greekpsilivaria \greekAlpha}
+\definecharacter greekAlphadasiavaria {\greekdasiavaria \greekAlpha}
+\definecharacter greekAlphapsilitonos {\greekpsilitonos \greekAlpha}
+\definecharacter greekAlphadasiatonos {\greekdasiatonos \greekAlpha}
+\definecharacter greekAlphapsiliperispomeni {\greekpsiliperispomeni \greekAlpha}
+\definecharacter greekAlphadasiaperispomeni {\greekdasiaperispomeni \greekAlpha}
+\definecharacter greekEpsilonpsili {\greekpsili \greekEpsilon}
+\definecharacter greekEpsilondasia {\greekdasia \greekEpsilon}
+\definecharacter greekEpsilonpsilivaria {\greekpsilivaria \greekEpsilon}
+\definecharacter greekEpsilondasiavaria {\greekdasiavaria \greekEpsilon}
+\definecharacter greekEpsilonpsilitonos {\greekpsilitonos \greekEpsilon}
+\definecharacter greekEpsilondasiatonos {\greekdasiatonos \greekEpsilon}
+\definecharacter greekEtapsili {\greekpsili \greekEta}
+\definecharacter greekEtadasia {\greekdasia \greekEta}
+\definecharacter greekEtapsilivaria {\greekpsilivaria \greekEta}
+\definecharacter greekEtadasiavaria {\greekdasiavaria \greekEta}
+\definecharacter greekEtapsilitonos {\greekpsilitonos \greekEta}
+\definecharacter greekEtadasiatonos {\greekdasiatonos \greekEta}
+\definecharacter greekEtapsiliperispomeni {\greekpsiliperispomeni \greekEta}
+\definecharacter greekEtadasiaperispomeni {\greekdasiaperispomeni \greekEta}
+\definecharacter greekIotapsili {\greekpsili \greekIota}
+\definecharacter greekIotadasia {\greekdasia \greekIota}
+\definecharacter greekIotapsilivaria {\greekpsilivaria \greekIota}
+\definecharacter greekIotadasiavaria {\greekdasiavaria \greekIota}
+\definecharacter greekIotapsilitonos {\greekpsilitonos \greekIota}
+\definecharacter greekIotadasiatonos {\greekdasiatonos \greekIota}
+\definecharacter greekIotapsiliperispomeni {\greekpsiliperispomeni \greekIota}
+\definecharacter greekIotadasiaperispomeni {\greekdasiaperispomeni \greekIota}
+\definecharacter greekOmicronpsili {\greekpsili \greekOmicron}
+\definecharacter greekOmicrondasia {\greekdasia \greekOmicron}
+\definecharacter greekOmicronpsilivaria {\greekpsilivaria \greekOmicron}
+\definecharacter greekOmicrondasiavaria {\greekdasiavaria \greekOmicron}
+\definecharacter greekOmicronpsilitonos {\greekpsilitonos \greekOmicron}
+\definecharacter greekOmicrondasiatonos {\greekdasiatonos \greekOmicron}
+\definecharacter greekUpsilondasia {\greekdasia \greekUpsilon}
+\definecharacter greekUpsilondasiavaria {\greekdasiavaria \greekUpsilon}
+\definecharacter greekUpsilondasiatonos {\greekdasiatonos \greekUpsilon}
+\definecharacter greekUpsilondasiaperispomeni {\greekdasiaperispomeni \greekUpsilon}
+\definecharacter greekOmegapsili {\greekpsili \greekOmega}
+\definecharacter greekOmegadasia {\greekdasia \greekOmega}
+\definecharacter greekOmegapsilivaria {\greekpsilivaria \greekOmega}
+\definecharacter greekOmegadasiavaria {\greekdasiavaria \greekOmega}
+\definecharacter greekOmegapsilitonos {\greekpsilitonos \greekOmega}
+\definecharacter greekOmegadasiatonos {\greekdasiatonos \greekOmega}
+\definecharacter greekOmegapsiliperispomeni {\greekpsiliperispomeni \greekOmega}
+\definecharacter greekOmegadasiaperispomeni {\greekdasiaperispomeni \greekOmega}
+\definecharacter greekAlphaiotasubpsili {\greekpsili \greekAlpha \greekiota}
+\definecharacter greekAlphaiotasubdasia {\greekdasia \greekAlpha \greekiota}
+\definecharacter greekAlphaiotasubpsilivaria {\greekpsilivaria \greekAlpha \greekiota}
+\definecharacter greekAlphaiotasubdasiavaria {\greekdasiavaria \greekAlpha \greekiota}
+\definecharacter greekAlphaiotasubpsilitonos {\greekpsilitonos \greekAlpha \greekiota}
+\definecharacter greekAlphaiotasubdasiatonos {\greekdasiatonos \greekAlpha \greekiota}
+\definecharacter greekAlphaiotasubpsiliperispomeni {\greekpsiliperispomeni \greekAlpha \greekiota}
+\definecharacter greekAlphaiotasubdasiaperispomeni {\greekdasiaperispomeni \greekAlpha \greekiota}
+\definecharacter greekEtaiotasubpsili {\greekpsili \greekEta \greekiota}
+\definecharacter greekEtaiotasubdasia {\greekdasia \greekEta \greekiota}
+\definecharacter greekEtaiotasubpsilivaria {\greekpsilivaria \greekEta \greekiota}
+\definecharacter greekEtaiotasubdasiavaria {\greekdasiavaria \greekEta \greekiota}
+\definecharacter greekEtaiotasubpsilitonos {\greekpsilitonos \greekEta \greekiota}
+\definecharacter greekEtaiotasubdasiatonos {\greekdasiatonos \greekEta \greekiota}
+\definecharacter greekEtaiotasubpsiliperispomeni {\greekpsiliperispomeni \greekEta \greekiota}
+\definecharacter greekEtaiotasubdasiaperispomeni {\greekdasiaperispomeni \greekEta \greekiota}
+\definecharacter greekOmegaiotasubpsili {\greekpsili \greekOmega \greekiota}
+\definecharacter greekOmegaiotasubdasia {\greekdasia \greekOmega \greekiota}
+\definecharacter greekOmegaiotasubpsilivaria {\greekpsilivaria \greekOmega \greekiota}
+\definecharacter greekOmegaiotasubdasiavaria {\greekdasiavaria \greekOmega \greekiota}
+\definecharacter greekOmegaiotasubpsilitonos {\greekpsilitonos \greekOmega \greekiota}
+\definecharacter greekOmegaiotasubdasiatonos {\greekdasiatonos \greekOmega \greekiota}
+\definecharacter greekOmegaiotasubpsiliperispomeni {\greekpsiliperispomeni \greekOmega \greekiota}
+\definecharacter greekOmegaiotasubdasiaperispomeni {\greekdasiaperispomeni \greekOmega \greekiota}
+\definecharacter greekAlphavaria {\greekvaria \greekAlpha}
+\definecharacter greekAlphaoxia {\greekoxia \greekAlpha}
+\definecharacter greekAlphaiotasub {\greekAlpha \greekiota}
+\definecharacter greekEpsilonvaria {\greekvaria \greekEpsilon}
+\definecharacter greekEpsilonoxia {\greekoxia \greekEpsilon}
+\definecharacter greekEtavaria {\greekvaria \greekEta}
+\definecharacter greekEtaoxia {\greekoxia \greekEta}
+\definecharacter greekEtaiotasub {\greekEta \greekiota}
+\definecharacter greekIotavaria {\greekvaria \greekIota}
+\definecharacter greekIotaoxia {\greekoxia \greekIota}
+\definecharacter greekUpsilonvaria {\greekvaria \greekUpsilon}
+\definecharacter greekUpsilonoxia {\greekoxia \greekUpsilon}
+\definecharacter greekOmicronvaria {\greekvaria \greekOmicron}
+\definecharacter greekOmicronoxia {\greekoxia \greekOmicron}
+\definecharacter greekOmegavaria {\greekvaria \greekOmega}
+\definecharacter greekOmegaoxia {\greekoxia \greekOmega}
+\definecharacter greekOmegaiotasub {\greekOmega \greekiota}
+\definecharacter greekRhodasia {\greekdasia \greekRho}
+\definecharacter digamma {\greekdigamma}
+\definecharacter sampi {\greeksampi}
+\definecharacter stigma {\greekstigma}
+\definecharacter koppa {\greeknumkoppa}
+\definecharacter lunars {\greeksigmalunate}
+\definecharacter lunarS {\greekSigmalunate}
+\definecharacter halfbraceleft {\floorleft}
+\definecharacter halfbraceright {\floorright}
+\definecharacter crux {\textdag}
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-ans.mkii b/tex/context/base/enco-ans.mkii
new file mode 100644
index 000000000..7a48b5b55
--- /dev/null
+++ b/tex/context/base/enco-ans.mkii
@@ -0,0 +1,237 @@
+%D \module
+%D [ file=enco-ans,
+%D version=2000.05.07, % 1995.01.01,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=\YandY\ texnansi Encoding,
+%D author={Patrick Gundlach, Hans Hagen},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is \YandY's texnansi encoding vector, which combines
+%D the best of the ansi encoding vector (prebuilt accented
+%D characters etc.) and some of \TEX's vectors.
+
+\startmapping[texnansi]
+
+\resetcaserange 128 to 158
+\resetcaserange 160 to 191
+\resetcaserange 215 to 215
+\resetcaserange 247 to 247
+
+\definecasemaps 192 to 214 lc +32 uc 0
+\definecasemaps 224 to 246 lc 0 uc -32
+\definecasemaps 216 to 222 lc +32 uc 0
+\definecasemaps 248 to 254 lc 0 uc -32
+
+\definecaseself 223
+\definecaseswap 156 140
+\definecaseswap 255 159
+
+% needed by some patterns:
+
+% \definecaseself 34 % quotedbl
+% \definecaseself 132 % quotedblbase
+% \definecaseself 147 % quotedblleft
+% \definecaseself 148 % quotedblright
+% \definecaseself 129 % quotesingle
+% \definecaseself 130 % quotesinglebase
+% \definecaseself 145 % quoteleft
+% \definecaseself 146 % quoteright
+
+\stopmapping
+
+\startencoding[texnansi]
+
+\definecharacter textacute 19
+\definecharacter textbreve 21
+\definecharacter textcaron 20
+\definecharacter textcedilla 184
+\definecharacter textcircumflex 94 % 136
+\definecharacter textdiaeresis 168
+\definecharacter textdotaccent 5
+\definecharacter textgrave 18
+\definecharacter texthungarumlaut 6
+\definecharacter textmacron 175
+\definecharacter textogonek 7
+\definecharacter textring 23
+\definecharacter texttilde 152
+
+\definecharacter dotlessi 16 % 105
+\definecharacter dotlessj 17
+
+\definecharacter endash 150 % lig
+\definecharacter emdash 151 % lig
+
+\definecharacter aeligature 230
+\definecharacter AEligature 198
+\definecharacter oeligature 156
+\definecharacter OEligature 140
+
+\definecharacter ssharp 223
+
+\definecharacter thorn 254
+\definecharacter Thorn 222
+
+\definecharacter Dstroke 208 % also Eth, mapped in enco-def
+\definecharacter eth 240
+
+\definecharacter exclamdown 161
+\definecharacter questiondown 191
+
+\definecharacter copyright 169
+\definecharacter registered 174
+\definecharacter trademark 153
+
+\definecharacter sectionmark 167
+\definecharacter paragraphmark 182
+
+\definecharacter onequarter 188
+\definecharacter onehalf 189
+\definecharacter threequarter 190
+
+\definecharacter onesuperior 185
+\definecharacter twosuperior 178
+\definecharacter threesuperior 179
+
+\definecharacter textcent 162 % ?
+\definecharacter textcurrency 164
+\definecharacter texteuro 1
+\definecharacter textflorin 131
+\definecharacter textsterling 163
+\definecharacter textyen 165
+
+\definecharacter percent 37
+\definecharacter perthousand 137
+
+\definecharacter softhyphen 45
+\definecharacter periodcentered 183
+
+\definecharacter textasciicircum 142
+\definecharacter textasciitilde 158
+\definecharacter textbackslash 92
+\definecharacter textbraceleft 123
+\definecharacter textbar 124
+\definecharacter textbraceright 125
+\definecharacter textunderscore 95
+
+\definecharacter textbrokenbar 166
+\definecharacter textbullet 149
+\definecharacter textdag 134
+\definecharacter textddag 135
+\definecharacter textdegree 176
+\definecharacter textdiv 247
+\definecharacter textellipsis 133
+\definecharacter textfraction 4
+\definecharacter textlognot 172
+\definecharacter textminus 143
+\definecharacter textmu 181
+\definecharacter textmultiply 215
+\definecharacter textpm 177
+
+\definecharacter quotedbl 34
+\definecharacter quotedblbase 132
+\definecharacter quotedblleft 147
+\definecharacter quotedblright 148
+
+\definecharacter quotesingle 129
+\definecharacter quotesinglebase 130
+
+\definecharacter quoteleft 145
+\definecharacter quoteright 146
+
+\definecharacter guilsingleleft 139
+\definecharacter guilsingleright 155
+\definecharacter leftguillemot 171
+\definecharacter rightguillemot 187
+
+\definecharacter aacute 225
+\definecharacter Aacute 193
+\definecharacter eacute 233
+\definecharacter Eacute 201
+\definecharacter iacute 237
+\definecharacter Iacute 205
+\definecharacter oacute 243
+\definecharacter Oacute 211
+\definecharacter uacute 250
+\definecharacter Uacute 218
+\definecharacter yacute 253
+\definecharacter Yacute 221
+
+\definecharacter scaron 154
+\definecharacter Scaron 138
+\definecharacter zcaron 157
+\definecharacter Zcaron 141
+
+\definecharacter ccedilla 231
+\definecharacter Ccedilla 199
+
+\definecharacter acircumflex 226
+\definecharacter Acircumflex 194
+\definecharacter ecircumflex 234
+\definecharacter Ecircumflex 202
+\definecharacter icircumflex 238
+\definecharacter Icircumflex 206
+\definecharacter ocircumflex 244
+\definecharacter Ocircumflex 212
+\definecharacter ucircumflex 251
+\definecharacter Ucircumflex 219
+
+\definecharacter adiaeresis 228
+\definecharacter Adiaeresis 196
+\definecharacter ediaeresis 235
+\definecharacter Ediaeresis 203
+\definecharacter idiaeresis 239
+\definecharacter Idiaeresis 207
+\definecharacter odiaeresis 246
+\definecharacter Odiaeresis 214
+\definecharacter udiaeresis 252
+\definecharacter Udiaeresis 220
+\definecharacter ydiaeresis 255
+\definecharacter Ydiaeresis 159
+
+\definecharacter agrave 224
+\definecharacter Agrave 192
+\definecharacter egrave 232
+\definecharacter Egrave 200
+\definecharacter igrave 236
+\definecharacter Igrave 204
+\definecharacter ograve 242
+\definecharacter Ograve 210
+\definecharacter ugrave 249
+\definecharacter Ugrave 217
+
+\definecharacter aring 229
+\definecharacter Aring 197
+
+\definecharacter Lstroke 128
+\definecharacter lstroke 144
+\definecharacter ostroke 248
+\definecharacter Ostoke 216
+
+\definecharacter atilde 227
+\definecharacter Atilde 195
+\definecharacter ntilde 241
+\definecharacter Ntilde 209
+\definecharacter otilde 245
+\definecharacter Otilde 213
+
+\stopencoding
+
+% will be replaced by math collection, fails anyway
+
+\startencoding[texnansi]
+
+\definecharacter mathgrave "7060
+\definecharacter mathacute "70B4
+\definecharacter mathhat "7088
+\definecharacter mathtilde "7098
+\definecharacter mathddot "70A8
+\definecharacter mathbar "70AF
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-cas.mkii b/tex/context/base/enco-cas.mkii
new file mode 100644
index 000000000..38d12f9fa
--- /dev/null
+++ b/tex/context/base/enco-cas.mkii
@@ -0,0 +1,143 @@
+%D \module
+%D [ file=enco-cas,
+%D version=2005.08.23,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Named Glyph Case Mapping,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D For quite some years \CONTEXT\ used a rather compact way of
+%D defining encoded characters as well as case maps. When late
+%D 2000 more advanced remapping features were needed (like pdf
+%D unicode remapping), named glyphs were introduced to keep the
+%D coding tables more readable. At the same time, we introduced
+%D named glyph case mapping.
+
+\defineULcharacter Acircumflex acircumflex
+\defineULcharacter Ccircumflex ccircumflex
+\defineULcharacter Ecircumflex ecircumflex
+\defineULcharacter Gcircumflex gcircumflex
+\defineULcharacter Hcircumflex hcircumflex
+\defineULcharacter Icircumflex icircumflex
+\defineULcharacter Jcircumflex jcircumflex
+\defineULcharacter Ocircumflex ocircumflex
+\defineULcharacter Scircumflex scircumflex
+\defineULcharacter Ucircumflex ucircumflex
+\defineULcharacter Wcircumflex wcircumflex
+\defineULcharacter Ycircumflex ycircumflex
+
+\defineULcharacter Agrave agrave
+\defineULcharacter Egrave egrave
+\defineULcharacter Igrave igrave
+\defineULcharacter Ograve ograve
+\defineULcharacter Ugrave ugrave
+\defineULcharacter Ygrave ygrave
+
+\defineULcharacter Atilde atilde
+\defineULcharacter Itilde itilde
+\defineULcharacter Otilde otilde
+\defineULcharacter Ntilde ntilde
+\defineULcharacter Utilde utilde
+
+\defineULcharacter Adiaeresis adiaeresis
+\defineULcharacter Ediaeresis ediaeresis
+\defineULcharacter Idiaeresis idiaeresis
+\defineULcharacter Odiaeresis odiaeresis
+\defineULcharacter Udiaeresis udiaeresis
+\defineULcharacter Ydiaeresis ydiaeresis
+
+\defineULcharacter Aacute aacute
+\defineULcharacter Cacute cacute
+\defineULcharacter Eacute eacute
+\defineULcharacter Iacute iacute
+\defineULcharacter Lacute lacute
+\defineULcharacter Nacute nacute
+\defineULcharacter Oacute oacute
+\defineULcharacter Racute racute
+\defineULcharacter Sacute sacute
+\defineULcharacter Uacute uacute
+\defineULcharacter Yacute yacute
+\defineULcharacter Zacute zacute
+
+\defineULcharacter Dstroke dstroke
+\defineULcharacter Hstroke hstroke
+\defineULcharacter Lstroke lstroke
+\defineULcharacter Lslash lslash
+\defineULcharacter Ostroke ostroke
+\defineULcharacter Tstroke tstroke
+
+\defineULcharacter Cdotaccent cdotaccent
+\defineULcharacter Edotaccent edotaccent
+\defineULcharacter Gdotaccent gdotaccent
+\defineULcharacter Idotaccent idotaccent
+\defineULcharacter Zdotaccent zdotaccent
+
+\defineULcharacter Amacron amacron
+\defineULcharacter Emacron emacron
+\defineULcharacter Imacron imacron
+\defineULcharacter Omacron omacron
+\defineULcharacter Umacron umacron
+
+\defineULcharacter Ccedilla ccedilla
+\defineULcharacter Gcedilla gcedilla
+\defineULcharacter Kcedilla kcedilla
+\defineULcharacter Lcedilla lcedilla
+\defineULcharacter Ncedilla ncedilla
+\defineULcharacter Rcedilla rcedilla
+\defineULcharacter Scedilla scedilla
+\defineULcharacter Tcedilla tcedilla
+
+\defineULcharacter Ccommaaccent ccommaaccent
+\defineULcharacter Gcommaaccent gcommaaccent
+\defineULcharacter Kcommaaccent kcommaaccent
+\defineULcharacter Lcommaaccent lcommaaccent
+\defineULcharacter Ncommaaccent ncommaaccent
+\defineULcharacter Rcommaaccent rcommaaccent
+\defineULcharacter Scommaaccent scommaaccent
+\defineULcharacter Tcommaaccent tcommaaccent
+
+\defineULcharacter Ohungarumlaut ohungarumlaut
+\defineULcharacter Uhungarumlaut uhungarumlaut
+
+\defineULcharacter Aogonek aogonek
+\defineULcharacter Eogonek eogonek
+\defineULcharacter Iogonek iogonek
+\defineULcharacter Uogonek uogonek
+
+\defineULcharacter Aring aring
+\defineULcharacter Uring uring
+
+\defineULcharacter Abreve abreve
+\defineULcharacter Ebreve ebreve
+\defineULcharacter Gbreve gbreve
+\defineULcharacter Ibreve ibreve
+\defineULcharacter Obreve obreve
+\defineULcharacter Ubreve ubreve
+
+\defineULcharacter Ccaron ccaron
+\defineULcharacter Dcaron dcaron
+\defineULcharacter Ecaron ecaron
+\defineULcharacter Lcaron lcaron
+\defineULcharacter Ncaron ncaron
+\defineULcharacter Rcaron rcaron
+\defineULcharacter Scaron scaron
+\defineULcharacter Tcaron tcaron
+\defineULcharacter Zcaron zcaron
+
+\defineULcharacter dotlessI dotlessi
+\defineULcharacter dotlessJ dotlessj
+
+\defineULcharacter AEligature aeligature
+\defineULcharacter OEligature oeligature
+\defineULcharacter Ssharp ssharp
+\defineULcharacter IJligature ijligature
+
+\defineULcharacter Eth eth
+\defineULcharacter Thorn thorn
+
+\endinput
diff --git a/tex/context/base/enco-chi.mkii b/tex/context/base/enco-chi.mkii
new file mode 100644
index 000000000..9d77893a0
--- /dev/null
+++ b/tex/context/base/enco-chi.mkii
@@ -0,0 +1,371 @@
+%D \module
+%D [ file=enco-chi,
+%D version=1999.12.02,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Traditional and Simplified Chinese,
+%D author={Wang Lei \& Hans Hagen},
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% actually this is also a filter -> enco-fcn.tex
+
+%D This is an experimental definition. Since we are dealing
+%D with unicode's, the registered values are not saved, so
+%D actually we're dealing with an pseudo encoding. The digits
+%D on the other hand are encoding specific.
+
+% chinese classes: left=1|right=2|center=3
+
+% untested, probably wrong
+
+\startencoding[cjk-uni]
+
+\defineuclass 1 32 24
+\defineuclass 1 32 28
+\defineuclass 1 48 20
+\defineuclass 1 48 8
+\defineuclass 1 48 10
+\defineuclass 1 48 12
+\defineuclass 1 48 14
+\defineuclass 1 48 22
+\defineuclass 1 48 16
+\defineuclass 1 255 8
+\defineuclass 1 255 59
+\defineuclass 1 255 64
+\defineuclass 1 255 91
+
+\defineuclass 3 0 183
+\defineuclass 3 0 168
+\defineuclass 3 32 38
+\defineuclass 3 255 30
+
+\defineuclass 2 48 1
+\defineuclass 2 48 2
+\defineuclass 2 32 20
+\defineuclass 2 255 94
+\defineuclass 2 32 25
+\defineuclass 2 32 29
+\defineuclass 2 48 21
+\defineuclass 2 48 9
+\defineuclass 2 48 11
+\defineuclass 2 48 13
+\defineuclass 2 48 15
+\defineuclass 2 48 23
+\defineuclass 2 48 17
+\defineuclass 2 34 55
+\defineuclass 2 0 176
+\defineuclass 2 32 50
+\defineuclass 2 32 51
+\defineuclass 2 255 1
+\defineuclass 2 255 2
+\defineuclass 2 255 7
+\defineuclass 2 255 9
+\defineuclass 2 255 12
+\defineuclass 2 255 14
+\defineuclass 2 255 26
+\defineuclass 2 255 27
+\defineuclass 2 255 31
+\defineuclass 2 255 61
+\defineuclass 2 255 93
+
+\defineudigit 0 37 203
+\defineudigit 1 78 0
+\defineudigit 2 78 140
+\defineudigit 3 78 9
+\defineudigit 4 86 219
+\defineudigit 5 78 148
+\defineudigit 6 81 109
+\defineudigit 7 78 3
+\defineudigit 8 81 107
+\defineudigit 9 78 93
+\defineudigit 10 83 65
+\defineudigit 100 118 126
+\defineudigit 1000 83 67
+\defineudigit 10000 78 7
+\defineudigit 100000000 78 191
+
+\defineudigit 0* 150 246
+\defineudigit 1* 88 249
+\defineudigit 2* 141 48
+\defineudigit 3* 83 193
+\defineudigit 4* 128 134
+\defineudigit 5* 79 13
+\defineudigit 6* 150 70
+\defineudigit 7* 103 210
+\defineudigit 8* 99 76
+\defineudigit 9* 115 150
+\defineudigit 10* 98 254
+\defineudigit 100* 79 112
+\defineudigit 1000* 78 223
+\defineudigit 10000* 132 44
+\defineudigit 100000000* 78 191
+
+\defineudigit 20 94 255
+\defineudigit 21 78 0
+\defineudigit 22 78 140
+\defineudigit 23 78 9
+\defineudigit 24 86 219
+\defineudigit 25 78 148
+\defineudigit 26 81 109
+\defineudigit 27 78 3
+\defineudigit 28 81 107
+\defineudigit 29 78 93
+
+\defineudigit 30 83 69
+\defineudigit 31 78 0
+\defineudigit 32 78 140
+\defineudigit 33 78 9
+\defineudigit 34 86 219
+\defineudigit 35 78 148
+\defineudigit 36 81 109
+\defineudigit 37 78 3
+\defineudigit 38 81 107
+\defineudigit 39 78 93
+
+\stopencoding
+
+% \doif \currentregime {utf} \endinput
+
+\startencoding[big5]
+
+\defineuclass 1 161 93
+\defineuclass 1 161 95
+\defineuclass 1 161 97
+\defineuclass 1 161 99
+\defineuclass 1 161 101
+\defineuclass 1 161 103
+\defineuclass 1 161 105
+\defineuclass 1 161 107
+\defineuclass 1 161 111
+\defineuclass 1 161 111
+\defineuclass 1 161 113
+\defineuclass 1 161 115
+\defineuclass 1 161 117
+\defineuclass 1 161 119
+\defineuclass 1 161 121
+\defineuclass 1 161 123
+\defineuclass 1 161 125
+\defineuclass 1 161 161
+\defineuclass 1 161 163
+\defineuclass 1 161 165
+\defineuclass 1 161 167
+\defineuclass 1 161 169
+\defineuclass 1 161 171
+
+\defineuclass 3 161 69
+\defineuclass 3 161 75
+\defineuclass 3 161 76
+
+\defineuclass 2 161 65
+\defineuclass 2 161 66
+\defineuclass 2 161 67
+\defineuclass 2 161 68
+\defineuclass 2 161 70
+\defineuclass 2 161 71
+\defineuclass 2 161 72
+\defineuclass 2 161 73
+\defineuclass 2 161 74
+\defineuclass 2 161 77
+\defineuclass 2 161 78
+\defineuclass 2 161 79
+\defineuclass 2 161 80
+\defineuclass 2 161 81
+\defineuclass 2 161 82
+\defineuclass 2 161 83
+\defineuclass 2 161 84
+\defineuclass 2 161 88
+\defineuclass 2 161 94
+\defineuclass 2 161 96
+\defineuclass 2 161 98
+\defineuclass 2 161 100
+\defineuclass 2 161 102
+\defineuclass 2 161 104
+\defineuclass 2 161 106
+\defineuclass 2 161 108
+\defineuclass 2 161 110
+\defineuclass 2 161 112
+\defineuclass 2 161 114
+\defineuclass 2 161 116
+\defineuclass 2 161 118
+\defineuclass 2 161 120
+\defineuclass 2 161 122
+\defineuclass 2 161 124
+\defineuclass 2 161 126
+\defineuclass 2 161 162
+\defineuclass 2 161 164
+\defineuclass 2 161 166
+\defineuclass 2 161 168
+\defineuclass 2 161 170
+\defineuclass 2 161 172
+\defineuclass 2 161 196
+\defineuclass 2 161 227
+\defineuclass 2 162 88
+\defineuclass 2 163 223
+
+\defineudigit 0 162 179
+\defineudigit 1 164 64
+\defineudigit 2 164 71
+\defineudigit 3 164 84
+\defineudigit 4 165 124
+\defineudigit 5 164 173
+\defineudigit 6 164 187
+\defineudigit 7 164 67
+\defineudigit 8 164 75
+\defineudigit 9 164 69
+\defineudigit 10 164 81
+\defineudigit 100 166 202
+\defineudigit 1000 164 100
+\defineudigit 10000 201 69
+\defineudigit 100000000 187 245
+
+\defineudigit 0* 185 115
+\defineudigit 1* 179 252
+\defineudigit 2* 182 76
+\defineudigit 3* 176 209
+\defineudigit 4* 184 118
+\defineudigit 5* 165 238
+\defineudigit 6* 179 176
+\defineudigit 7* 172 110
+\defineudigit 8* 174 195
+\defineudigit 9* 168 104
+\defineudigit 10* 172 66
+\defineudigit 100* 168 213
+\defineudigit 1000* 165 97
+\defineudigit 10000* 184 85
+\defineudigit 100000000* 187 245
+
+\defineudigit 20 164 220
+\defineudigit 21 164 64
+\defineudigit 22 164 71
+\defineudigit 23 164 84
+\defineudigit 24 165 124
+\defineudigit 25 164 173
+\defineudigit 26 164 187
+\defineudigit 27 164 67
+\defineudigit 28 164 75
+\defineudigit 29 164 69
+
+\defineudigit 30 164 202
+\defineudigit 31 164 64
+\defineudigit 32 164 71
+\defineudigit 33 164 84
+\defineudigit 34 165 124
+\defineudigit 35 164 173
+\defineudigit 36 164 187
+\defineudigit 37 164 67
+\defineudigit 38 164 75
+\defineudigit 39 164 69
+
+\stopencoding
+
+\startencoding[gbk]
+
+\defineuclass 1 161 174
+\defineuclass 1 161 176
+\defineuclass 1 161 178
+\defineuclass 1 161 180
+\defineuclass 1 161 182
+\defineuclass 1 161 184
+\defineuclass 1 161 186
+\defineuclass 1 161 188
+\defineuclass 1 161 190
+\defineuclass 1 163 168
+\defineuclass 1 163 219
+\defineuclass 1 163 224
+\defineuclass 1 163 251
+
+\defineuclass 3 161 164
+\defineuclass 3 161 167
+\defineuclass 3 161 173
+\defineuclass 3 163 190
+
+\defineuclass 2 161 162
+\defineuclass 2 161 163
+\defineuclass 2 161 170
+\defineuclass 2 161 171
+\defineuclass 2 161 175
+\defineuclass 2 161 177
+\defineuclass 2 161 179
+\defineuclass 2 161 181
+\defineuclass 2 161 183
+\defineuclass 2 161 185
+\defineuclass 2 161 187
+\defineuclass 2 161 189
+\defineuclass 2 161 191
+\defineuclass 2 161 203
+\defineuclass 2 161 227
+\defineuclass 2 161 228
+\defineuclass 2 161 229
+\defineuclass 2 163 161
+\defineuclass 2 163 162
+\defineuclass 2 163 167
+\defineuclass 2 163 169
+\defineuclass 2 163 172
+\defineuclass 2 163 174
+\defineuclass 2 163 186
+\defineuclass 2 163 187
+\defineuclass 2 163 191
+\defineuclass 2 163 221
+\defineuclass 2 163 253
+
+\defineudigit 0 161 240
+\defineudigit 1 210 187
+\defineudigit 2 182 254
+\defineudigit 3 200 253
+\defineudigit 4 203 196
+\defineudigit 5 206 229
+\defineudigit 6 193 249
+\defineudigit 7 198 223
+\defineudigit 8 176 203
+\defineudigit 9 190 197
+\defineudigit 10 202 174
+\defineudigit 100 176 217
+\defineudigit 1000 199 167
+\defineudigit 10000 205 242
+\defineudigit 100000000 210 218
+
+\defineudigit 0* 193 227
+\defineudigit 1* 210 188
+\defineudigit 2* 183 161
+\defineudigit 3* 200 254
+\defineudigit 4* 203 193
+\defineudigit 5* 206 233
+\defineudigit 6* 194 189
+\defineudigit 7* 198 226
+\defineudigit 8* 176 198
+\defineudigit 9* 190 193
+\defineudigit 10* 202 176
+\defineudigit 100* 176 219
+\defineudigit 1000* 199 170
+\defineudigit 10000* 200 102
+\defineudigit 100000000* 210 218
+
+\defineudigit 20 216 165
+\defineudigit 21 210 187
+\defineudigit 22 182 254
+\defineudigit 23 200 253
+\defineudigit 24 203 196
+\defineudigit 25 206 229
+\defineudigit 26 193 249
+\defineudigit 27 198 223
+\defineudigit 28 176 203
+\defineudigit 29 190 197
+
+\defineudigit 30 216 166
+\defineudigit 31 210 187
+\defineudigit 32 182 254
+\defineudigit 33 200 253
+\defineudigit 34 203 196
+\defineudigit 35 206 229
+\defineudigit 36 193 249
+\defineudigit 37 198 223
+\defineudigit 38 176 203
+\defineudigit 39 190 197
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-com.mkii b/tex/context/base/enco-com.mkii
new file mode 100644
index 000000000..42d0d4774
--- /dev/null
+++ b/tex/context/base/enco-com.mkii
@@ -0,0 +1,37 @@
+%D \module
+%D [ file=enco-com,
+%D version=2000.20.12, % split from base file
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Composed Characters Commands,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=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.
+
+%D Here we map some \quote {short} names onto the more
+%D verbose glyph names.
+
+\def\AA{\Aring}
+\def\aa{\aring}
+\def\AE{\AEligature}
+\def\ae{\aeligature}
+\def\CC{\Ccedilla}
+\def\cc{\ccedilla}
+\def \L{\Lstroke}
+\def \l{\lstroke}
+\def \O{\Ostroke}
+\def \o{\ostroke}
+\def\OE{\OEligature}
+\def\oe{\oeligature}
+\def\SZ{\Ssharp}
+\def\sz{\ssharp}
+\def\SS{\ssharp}
+\def\IJ{\IJligature}
+\def\ij{\ijligature}
+\def \i{\dotlessi}
+\def \j{\dotlessj}
+
+\endinput
diff --git a/tex/context/base/enco-cyr.mkii b/tex/context/base/enco-cyr.mkii
new file mode 100644
index 000000000..36bca82b5
--- /dev/null
+++ b/tex/context/base/enco-cyr.mkii
@@ -0,0 +1,1037 @@
+%D \module
+%D [ file=enco-cyr,
+%D version=2003.01.24,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Cyrillic,
+%D author=...,
+%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.
+
+%D The following kerning test is inspired by a test file
+%D provided by Victor Figurnov. I hope he still recognizes
+%D some bit and pieces.
+%D
+%D \starttyping
+%D \setupoutput[pdftex]
+%D
+%D \startMPenvironment[global]
+%D \useregime[cyr]
+%D \useencoding[cyr]
+%D \mainlanguage[ru]
+%D \enableregime[cp1251]
+%D \setupbodyfont[cyr]
+%D \stopMPenvironment
+%D
+%D \startbuffer
+%D \starttabulate[|l|l|l|]
+%D \NC \ruledhbox{} \NC \ruledhbox{AV} \NC with kerning \NC \NR
+%D \NC \ruledhbox{{}{}} \NC \ruledhbox{A{}V} \NC without kerning \NC \NR
+%D \NC \ruledhbox{\tfd } \NC \ruledhbox{\tfd AV} \NC with kerning \NC \NR
+%D \NC \ruledhbox{\tfd {}{}} \NC \ruledhbox{\tfd A{}V} \NC without kerning \NC \NR
+%D \stoptabulate
+%D
+%D \showkerning{ }
+%D \stopbuffer
+%D
+%D \starttext
+%D
+%D \title{Kerning test}
+%D
+%D \typebuffer
+%D
+%D \rm \subject{Serif font} \getbuffer
+%D \ss \subject{SansSerif font} \getbuffer
+%D \tt \subject{MonoSpacec font} \getbuffer
+%D
+%D \stoptext
+%D \stoptyping
+
+%D We start with a fallback, define by HH, who assumes that
+%D this is phonetic.
+
+\startmapping[t2a]
+
+\resetcaserange 128 to 255
+
+\definecasemaps 192 to 223 lc +32 uc 0 % base letters (russian)
+\definecasemaps 224 to 255 lc 0 uc -32
+
+\definecasemaps 128 to 156 lc +32 uc 0 % extra letters (cyrillic and old-slav)
+\definecasemaps 160 to 188 lc 0 uc -32
+
+\definecasemap 73 105 73 \definecasemap 105 105 73 % cyrillicII
+\definecasemap 74 106 74 \definecasemap 106 106 74 % cyrillicJE
+\definecasemap 81 113 81 \definecasemap 113 113 81 % cyrillicQ
+\definecasemap 87 119 87 \definecasemap 119 119 87 % cyrillicW
+
+\stopmapping
+
+\startencoding[t2a]
+
+\definecharacter textgrave 0
+\definecharacter textacute 1
+\definecharacter textcircumflex 2
+\definecharacter texttilde 3
+\definecharacter textdiaeresis 4
+\definecharacter texthungarumlaut 5
+\definecharacter textring 6
+\definecharacter textcaron 7
+\definecharacter textbreve 8
+\definecharacter textmacron 9
+\definecharacter textdotaccent 10
+\definecharacter textcedilla 11
+\definecharacter textogonek 12
+
+\definecharacter textcyrillicflex 18
+\definecharacter textdblgrave 19
+\definecharacter textcyrillicbreve 20
+
+\definecharacter endash 21
+\definecharacter emdash 22
+
+\definecharacter textcompwordmark 23
+\definecharacter textbackslash 92
+\definecharacter textasciicircum 94
+\definecharacter textunderscore 95
+\definecharacter textbraceleft 123
+\definecharacter textbraceright 125
+\definecharacter textasciitilde 126
+\definecharacter textnumero 157
+\definecharacter textcurrency 158
+\definecharacter sectionmark 159
+
+\definecharacter quotedbl 34
+\definecharacter quoteleft 96
+\definecharacter upperleftsingleninequote 39
+\definecharacter quotedblleft 16
+\definecharacter quotedblright 17
+\definecharacter lowerleftdoubleninequote 189
+\definecharacter upperrightdoublesixquote 16
+\definecharacter upperrightdoubleninequote 17
+\definecharacter quotedblbase 189
+
+\definecharacter cyrillicpalochka 13
+\definecharacter cyrilliclangle 14
+\definecharacter cyrillicrangle 15
+
+\definecharacter leftguillemot 190
+\definecharacter rightguillemot 191
+\definecharacter dotlessi 25
+
+\definecharacter cyrillicA 192
+\definecharacter cyrillica 224
+\definecharacter cyrillicB 193
+\definecharacter cyrillicb 225
+\definecharacter cyrillicV 194
+\definecharacter cyrillicv 226
+\definecharacter cyrillicG 195
+\definecharacter cyrillicg 227
+\definecharacter cyrillicD 196
+\definecharacter cyrillicd 228
+\definecharacter cyrillicE 197
+\definecharacter cyrillice 229
+\definecharacter cyrillicZH 198
+\definecharacter cyrilliczh 230
+\definecharacter cyrillicZ 199
+\definecharacter cyrillicz 231
+\definecharacter cyrillicI 200
+\definecharacter cyrillici 232
+\definecharacter cyrillicISHRT 201
+\definecharacter cyrillicishrt 233
+\definecharacter cyrillicK 202
+\definecharacter cyrillick 234
+\definecharacter cyrillicL 203
+\definecharacter cyrillicl 235
+\definecharacter cyrillicM 204
+\definecharacter cyrillicm 236
+\definecharacter cyrillicN 205
+\definecharacter cyrillicn 237
+\definecharacter cyrillicO 206
+\definecharacter cyrillico 238
+\definecharacter cyrillicP 207
+\definecharacter cyrillicp 239
+\definecharacter cyrillicR 208
+\definecharacter cyrillicr 240
+\definecharacter cyrillicS 209
+\definecharacter cyrillics 241
+\definecharacter cyrillicT 210
+\definecharacter cyrillict 242
+\definecharacter cyrillicU 211
+\definecharacter cyrillicu 243
+\definecharacter cyrillicF 212
+\definecharacter cyrillicf 244
+\definecharacter cyrillicH 213
+\definecharacter cyrillich 245
+\definecharacter cyrillicC 214
+\definecharacter cyrillicc 246
+\definecharacter cyrillicCH 215
+\definecharacter cyrillicch 247
+\definecharacter cyrillicSH 216
+\definecharacter cyrillicsh 248
+\definecharacter cyrillicSHCH 217
+\definecharacter cyrillicshch 249
+\definecharacter cyrillicHRDSN 218
+\definecharacter cyrillichrdsn 250
+\definecharacter cyrillicERY 219
+\definecharacter cyrillicery 251
+\definecharacter cyrillicSFTSN 220
+\definecharacter cyrillicsftsn 252
+\definecharacter cyrillicEREV 221
+\definecharacter cyrillicerev 253
+\definecharacter cyrillicYU 222
+\definecharacter cyrillicyu 254
+\definecharacter cyrillicYA 223
+\definecharacter cyrillicya 255
+\definecharacter cyrillicGUP 128
+\definecharacter cyrillicgup 160
+\definecharacter cyrillicGHCRS 129
+\definecharacter cyrillicghcrs 161
+\definecharacter cyrillicDJE 130
+\definecharacter cyrillicdje 162
+\definecharacter cyrillicTSHE 131
+\definecharacter cyrillictshe 163
+\definecharacter cyrillicSHHA 132
+\definecharacter cyrillicshha 164
+\definecharacter cyrillicZHDSC 133
+\definecharacter cyrilliczhdsc 165
+\definecharacter cyrillicZDSC 134
+\definecharacter cyrilliczdsc 166
+\definecharacter cyrillicLJE 135
+\definecharacter cyrilliclje 167
+\definecharacter cyrillicYI 136
+\definecharacter cyrillicyi 168
+\definecharacter cyrillicKDSC 137
+\definecharacter cyrillickdsc 169
+\definecharacter cyrillicKBEAK 138
+\definecharacter cyrillickbeak 170
+\definecharacter cyrillicKVCRS 139
+\definecharacter cyrillickvcrs 171
+\definecharacter cyrillicAE 140
+\definecharacter cyrillicae 172
+\definecharacter cyrillicNDSC 141
+\definecharacter cyrillicndsc 173
+\definecharacter cyrillicNG 142
+\definecharacter cyrillicng 174
+\definecharacter cyrillicDZE 143
+\definecharacter cyrillicdze 175
+\definecharacter cyrillicOTLD 144
+\definecharacter cyrillicotld 176
+\definecharacter cyrillicSDSC 145
+\definecharacter cyrillicsdsc 177
+\definecharacter cyrillicUSHRT 146
+\definecharacter cyrillicushrt 178
+\definecharacter cyrillicY 147
+\definecharacter cyrillicy 179
+\definecharacter cyrillicYHCRS 148
+\definecharacter cyrillicyhcrs 180
+\definecharacter cyrillicHDSC 149
+\definecharacter cyrillichdsc 181
+\definecharacter cyrillicDZHE 150
+\definecharacter cyrillicdzhe 182
+\definecharacter cyrillicCHVCRS 151
+\definecharacter cyrillicchvcrs 183
+\definecharacter cyrillicCHRDSC 152
+\definecharacter cyrillicchrdsc 184
+\definecharacter cyrillicIE 153
+\definecharacter cyrillicie 185
+\definecharacter cyrillicSCHWA 154
+\definecharacter cyrillicschwa 186
+\definecharacter cyrillicNJE 155
+\definecharacter cyrillicnje 187
+\definecharacter cyrillicYO 156
+\definecharacter cyrillicyo 188
+\definecharacter cyrillicII 73
+\definecharacter cyrillicii 105
+\definecharacter cyrillicJE 74
+\definecharacter cyrillicje 106
+\definecharacter cyrillicQ 81
+\definecharacter cyrillicq 113
+\definecharacter cyrillicW 87
+\definecharacter cyrillicw 119
+
+% \definecharacter textperthousand {\%\char 24 }
+% \definecharacter textpertenthousand {\%\char 24\char 24 }
+
+\definecharacter cyrillicgheupturn 160 % to satisfy the patterns
+
+\stopencoding
+
+\startmapping[t2b]
+
+\resetcaserange 128 to 255
+
+\definecasemaps 192 to 223 lc +32 uc 0 % base letters (russian)
+\definecasemaps 224 to 255 lc 0 uc -32
+
+\definecasemaps 128 to 156 lc +32 uc 0 % extra letters (cyrillic and old-slav)
+\definecasemaps 160 to 188 lc 0 uc -32
+
+\definecasemap 73 105 73 \definecasemap 105 105 73 % cyrillicII
+\definecasemap 74 106 74 \definecasemap 106 106 74 % cyrillicJE
+\definecasemap 81 113 81 \definecasemap 113 113 81 % cyrillicQ
+\definecasemap 83 115 83 \definecasemap 115 115 83 % cyrillicDZE
+\definecasemap 87 119 87 \definecasemap 119 119 87 % cyrillicW
+
+\stopmapping
+
+\startencoding[t2b]
+
+\definecharacter textgrave 0
+\definecharacter textacute 1
+\definecharacter textcircumflex 2
+\definecharacter texttilde 3
+\definecharacter textdiaeresis 4
+\definecharacter texthungarumlaut 5
+\definecharacter textring 6
+\definecharacter textcaron 7
+\definecharacter textbreve 8
+\definecharacter textmacron 9
+\definecharacter textdotaccent 10
+\definecharacter textcedilla 11
+\definecharacter textogonek 12
+
+\definecharacter textcyrillicflex 18
+\definecharacter textdblgrave 19
+\definecharacter textcyrillicbreve 20
+
+\definecharacter endash 21
+\definecharacter emdash 22
+
+\definecharacter textcompwordmark 23
+\definecharacter textbackslash 92
+\definecharacter textasciicircum 94
+\definecharacter textunderscore 95
+\definecharacter textbraceleft 123
+\definecharacter textbraceright 125
+\definecharacter textasciitilde 126
+\definecharacter textnumero 157
+\definecharacter textcurrency 158
+\definecharacter sectionmark 159
+\definecharacter quotedbl 34
+\definecharacter quoteleft 96
+\definecharacter upperleftsingleninequote 39
+\definecharacter quotedblleft 16
+\definecharacter quotedblright 17
+\definecharacter lowerleftdoubleninequote 189
+
+\definecharacter upperrightdoublesixquote 16
+\definecharacter upperrightdoubleninequote 17
+\definecharacter quotedblbase 189
+
+\definecharacter cyrillicpalochka 13
+\definecharacter cyrilliclangle 14
+\definecharacter cyrillicrangle 15
+
+\definecharacter leftguillemot 190
+\definecharacter rightguillemot 191
+\definecharacter dotlessi 25
+
+\definecharacter cyrillicA 192
+\definecharacter cyrillica 224
+\definecharacter cyrillicB 193
+\definecharacter cyrillicb 225
+\definecharacter cyrillicV 194
+\definecharacter cyrillicv 226
+\definecharacter cyrillicG 195
+\definecharacter cyrillicg 227
+\definecharacter cyrillicD 196
+\definecharacter cyrillicd 228
+\definecharacter cyrillicE 197
+\definecharacter cyrillice 229
+\definecharacter cyrillicZH 198
+\definecharacter cyrilliczh 230
+\definecharacter cyrillicZ 199
+\definecharacter cyrillicz 231
+\definecharacter cyrillicI 200
+\definecharacter cyrillici 232
+\definecharacter cyrillicISHRT 201
+\definecharacter cyrillicishrt 233
+\definecharacter cyrillicK 202
+\definecharacter cyrillick 234
+\definecharacter cyrillicL 203
+\definecharacter cyrillicl 235
+\definecharacter cyrillicM 204
+\definecharacter cyrillicm 236
+\definecharacter cyrillicN 205
+\definecharacter cyrillicn 237
+\definecharacter cyrillicO 206
+\definecharacter cyrillico 238
+\definecharacter cyrillicP 207
+\definecharacter cyrillicp 239
+\definecharacter cyrillicR 208
+\definecharacter cyrillicr 240
+\definecharacter cyrillicS 209
+\definecharacter cyrillics 241
+\definecharacter cyrillicT 210
+\definecharacter cyrillict 242
+\definecharacter cyrillicU 211
+\definecharacter cyrillicu 243
+\definecharacter cyrillicF 212
+\definecharacter cyrillicf 244
+\definecharacter cyrillicH 213
+\definecharacter cyrillich 245
+\definecharacter cyrillicC 214
+\definecharacter cyrillicc 246
+\definecharacter cyrillicCH 215
+\definecharacter cyrillicch 247
+\definecharacter cyrillicSH 216
+\definecharacter cyrillicsh 248
+\definecharacter cyrillicSHCH 217
+\definecharacter cyrillicshch 249
+\definecharacter cyrillicHRDSN 218
+\definecharacter cyrillichrdsn 250
+\definecharacter cyrillicERY 219
+\definecharacter cyrillicery 251
+\definecharacter cyrillicSFTSN 220
+\definecharacter cyrillicsftsn 252
+\definecharacter cyrillicEREV 221
+\definecharacter cyrillicerev 253
+\definecharacter cyrillicYU 222
+\definecharacter cyrillicyu 254
+\definecharacter cyrillicYA 223
+\definecharacter cyrillicya 255
+\definecharacter cyrillicGDSCHCRS 128
+\definecharacter cyrillicgdschcrs 160
+\definecharacter cyrillicGHCRS 129
+\definecharacter cyrillicghcrs 161
+\definecharacter cyrillicGDSC 130
+\definecharacter cyrillicgdsc 162
+\definecharacter cyrillicGHK 131
+\definecharacter cyrillicghk 163
+\definecharacter cyrillicSHHA 132
+\definecharacter cyrillicshha 164
+\definecharacter cyrillicZHDSC 133
+\definecharacter cyrilliczhdsc 165
+\definecharacter cyrillicDELTA 134
+\definecharacter cyrillicdelta 166
+\definecharacter cyrillicABHDZE 135
+\definecharacter cyrillicabhdze 167
+\definecharacter cyrillicLJE 136
+\definecharacter cyrilliclje 168
+\definecharacter cyrillicKDSC 137
+\definecharacter cyrillickdsc 169
+\definecharacter cyrillicLDSC 138
+\definecharacter cyrillicldsc 170
+\definecharacter cyrillicKHK 139
+\definecharacter cyrillickhk 171
+\definecharacter cyrillicLHK 140
+\definecharacter cyrilliclhk 172
+\definecharacter cyrillicNDSC 141
+\definecharacter cyrillicndsc 173
+\definecharacter cyrillicNG 142
+\definecharacter cyrillicng 174
+\definecharacter cyrillicNHK 143
+\definecharacter cyrillicnhk 175
+\definecharacter cyrillicOTLD 144
+\definecharacter cyrillicotld 176
+\definecharacter cyrillicSACRS 145
+\definecharacter cyrillicsacrs 177
+\definecharacter cyrillicUSHRT 146
+\definecharacter cyrillicushrt 178
+\definecharacter cyrillicY 147
+\definecharacter cyrillicy 179
+\definecharacter cyrillicHHCRS 148
+\definecharacter cyrillichhcrs 180
+\definecharacter cyrillicHDSC 149
+\definecharacter cyrillichdsc 181
+\definecharacter cyrillicHHK 150
+\definecharacter cyrillichhk 182
+\definecharacter cyrillicCHLDSC 151
+\definecharacter cyrillicchldsc 183
+\definecharacter cyrillicCHRDSC 152
+\definecharacter cyrillicchrdsc 184
+\definecharacter cyrillicNJE 153
+\definecharacter cyrillicnje 185
+\definecharacter cyrillicSCHWA 154
+\definecharacter cyrillicschwa 186
+\definecharacter cyrillicEPS 155
+\definecharacter cyrilliceps 187
+\definecharacter cyrillicYO 156
+\definecharacter cyrillicyo 188
+\definecharacter cyrillicII 73
+\definecharacter cyrillicii 105
+\definecharacter cyrillicJE 74
+\definecharacter cyrillicje 106
+\definecharacter cyrillicQ 81
+\definecharacter cyrillicq 113
+\definecharacter cyrillicDZE 83
+\definecharacter cyrillicdze 115
+\definecharacter cyrillicW 87
+\definecharacter cyrillicw 119
+
+\stopencoding
+
+\startmapping[t2c]
+
+\resetcaserange 128 to 255
+
+\definecasemaps 192 to 223 lc +32 uc 0 % base letters (russian)
+\definecasemaps 224 to 255 lc 0 uc -32
+
+\definecasemaps 128 to 156 lc +32 uc 0 % extra letters (cyrillic and old-slav)
+\definecasemaps 160 to 188 lc 0 uc -32
+
+\definecasemap 73 105 73 \definecasemap 105 105 73 % cyrillicII
+\definecasemap 74 106 74 \definecasemap 106 106 74 % cyrillicJE
+\definecasemap 81 113 81 \definecasemap 113 113 81 % cyrillicQ
+\definecasemap 83 115 83 \definecasemap 115 115 83 % cyrillicDZE
+\definecasemap 87 119 87 \definecasemap 119 119 87 % cyrillicW
+
+\stopmapping
+
+\startencoding[t2c]
+
+\definecharacter textgrave 0
+\definecharacter textacute 1
+\definecharacter textcircumflex 2
+\definecharacter texttilde 3
+\definecharacter textdiaeresis 4
+\definecharacter texthungarumlaut 5
+\definecharacter textring 6
+\definecharacter textcaron 7
+\definecharacter textbreve 8
+\definecharacter textmacron 9
+\definecharacter textdotaccent 10
+\definecharacter textcedilla 11
+\definecharacter textogonek 12
+
+\definecharacter textcyrillicflex 18
+\definecharacter textdblgrave 19
+\definecharacter textcyrillicbreve 20
+
+\definecharacter endash 21
+\definecharacter emdash 22
+
+\definecharacter textcompwordmark 23
+\definecharacter textbackslash 92
+\definecharacter textasciicircum 94
+\definecharacter textunderscore 95
+\definecharacter textbraceleft 123
+\definecharacter textbraceright 125
+\definecharacter textasciitilde 126
+\definecharacter textnumero 157
+\definecharacter textcurrency 158
+\definecharacter sectionmark 159
+\definecharacter quotedbl 34
+\definecharacter quoteleft 96
+\definecharacter upperleftsingleninequote 39
+\definecharacter quotedblleft 16
+\definecharacter quotedblright 17
+\definecharacter lowerleftdoubleninequote 189
+\definecharacter upperrightdoublesixquote 16
+\definecharacter upperrightdoubleninequote 17
+\definecharacter quotedblbase 189
+
+\definecharacter cyrillicpalochka 13
+\definecharacter cyrilliclangle 14
+\definecharacter cyrillicrangle 15
+
+\definecharacter leftguillemot 190
+\definecharacter rightguillemot 191
+
+\definecharacter dotlessi 25
+
+\definecharacter cyrillicA 192
+\definecharacter cyrillica 224
+\definecharacter cyrillicB 193
+\definecharacter cyrillicb 225
+\definecharacter cyrillicV 194
+\definecharacter cyrillicv 226
+\definecharacter cyrillicG 195
+\definecharacter cyrillicg 227
+\definecharacter cyrillicD 196
+\definecharacter cyrillicd 228
+\definecharacter cyrillicE 197
+\definecharacter cyrillice 229
+\definecharacter cyrillicZH 198
+\definecharacter cyrilliczh 230
+\definecharacter cyrillicZ 199
+\definecharacter cyrillicz 231
+\definecharacter cyrillicI 200
+\definecharacter cyrillici 232
+\definecharacter cyrillicISHRT 201
+\definecharacter cyrillicishrt 233
+\definecharacter cyrillicK 202
+\definecharacter cyrillick 234
+\definecharacter cyrillicL 203
+\definecharacter cyrillicl 235
+\definecharacter cyrillicM 204
+\definecharacter cyrillicm 236
+\definecharacter cyrillicN 205
+\definecharacter cyrillicn 237
+\definecharacter cyrillicO 206
+\definecharacter cyrillico 238
+\definecharacter cyrillicP 207
+\definecharacter cyrillicp 239
+\definecharacter cyrillicR 208
+\definecharacter cyrillicr 240
+\definecharacter cyrillicS 209
+\definecharacter cyrillics 241
+\definecharacter cyrillicT 210
+\definecharacter cyrillict 242
+\definecharacter cyrillicU 211
+\definecharacter cyrillicu 243
+\definecharacter cyrillicF 212
+\definecharacter cyrillicf 244
+\definecharacter cyrillicH 213
+\definecharacter cyrillich 245
+\definecharacter cyrillicC 214
+\definecharacter cyrillicc 246
+\definecharacter cyrillicCH 215
+\definecharacter cyrillicch 247
+\definecharacter cyrillicSH 216
+\definecharacter cyrillicsh 248
+\definecharacter cyrillicSHCH 217
+\definecharacter cyrillicshch 249
+\definecharacter cyrillicHRDSN 218
+\definecharacter cyrillichrdsn 250
+\definecharacter cyrillicERY 219
+\definecharacter cyrillicery 251
+\definecharacter cyrillicSFTSN 220
+\definecharacter cyrillicsftsn 252
+\definecharacter cyrillicEREV 221
+\definecharacter cyrillicerev 253
+\definecharacter cyrillicYU 222
+\definecharacter cyrillicyu 254
+\definecharacter cyrillicYA 223
+\definecharacter cyrillicya 255
+\definecharacter cyrillicPHK 128
+\definecharacter cyrillicphk 160
+\definecharacter cyrillicTETSE 129
+\definecharacter cyrillictetse 161
+\definecharacter cyrillicTDSC 130
+\definecharacter cyrillictdsc 162
+\definecharacter cyrillicGHK 131
+\definecharacter cyrillicghk 163
+\definecharacter cyrillicSHHA 132
+\definecharacter cyrillicshha 164
+\definecharacter cyrillicRDSC 133
+\definecharacter cyrillicrdsc 165
+\definecharacter cyrillicRTICK 134
+\definecharacter cyrillicrtick 166
+\definecharacter cyrillicABHDZE 135
+\definecharacter cyrillicabhdze 167
+\definecharacter cyrillicMDSC 136
+\definecharacter cyrillicmdsc 168
+\definecharacter cyrillicKDSC 137
+\definecharacter cyrillickdsc 169
+\definecharacter cyrillicLDSC 138
+\definecharacter cyrillicldsc 170
+\definecharacter cyrillicKHCRS 139
+\definecharacter cyrillickhcrs 171
+\definecharacter cyrillicLHK 140
+\definecharacter cyrilliclhk 172
+\definecharacter cyrillicNDSC 141
+\definecharacter cyrillicndsc 173
+\definecharacter cyrillicMHK 142
+\definecharacter cyrillicmhk 174
+\definecharacter cyrillicNHK 143
+\definecharacter cyrillicnhk 175
+\definecharacter cyrillicOTLD 144
+\definecharacter cyrillicotld 176
+\definecharacter cyrillicABHCH 145
+\definecharacter cyrillicabhch 177
+\definecharacter cyrillicABHCHDSC 146
+\definecharacter cyrillicabhchdsc 178
+\definecharacter cyrillicSEMISFTSN 147
+\definecharacter cyrillicsemisftsn 179
+\definecharacter cyrillicISHRTDSC 148
+\definecharacter cyrillicishrtdsc 180
+\definecharacter cyrillicHDSC 149
+\definecharacter cyrillichdsc 181
+\definecharacter cyrillicDZHE 150
+\definecharacter cyrillicdzhe 182
+\definecharacter cyrillicABHHA 151
+\definecharacter cyrillicabhha 183
+\definecharacter cyrillicCHRDSC 152
+\definecharacter cyrillicchrdsc 184
+\definecharacter cyrillicNLHK 153
+\definecharacter cyrillicnlhk 185
+\definecharacter cyrillicSCHWA 154
+\definecharacter cyrillicschwa 186
+\definecharacter cyrillicRHK 155
+\definecharacter cyrillicrhk 187
+\definecharacter cyrillicYO 156
+\definecharacter cyrillicyo 188
+\definecharacter cyrillicII 73
+\definecharacter cyrillicii 105
+\definecharacter cyrillicJE 74
+\definecharacter cyrillicje 106
+\definecharacter cyrillicQ 81
+\definecharacter cyrillicq 113
+\definecharacter cyrillicDZE 83
+\definecharacter cyrillicdze 115
+\definecharacter cyrillicW 87
+\definecharacter cyrillicw 119
+
+\stopencoding
+
+\startmapping[x2]
+
+\resetcaserange 128 to 255
+
+\definecasemaps 192 to 223 lc +32 uc 0 % base letters (russian)
+\definecasemaps 224 to 255 lc 0 uc -32
+
+\definecasemaps 128 to 156 lc +32 uc 0 % extra letters (cyrillic and old-slav)
+\definecasemaps 160 to 188 lc 0 uc -32
+
+\definecasemaps 65 to 90 lc +32 uc 0 % more extra letters (cyrillic and old-slav)
+\definecasemaps 97 to 122 lc 0 uc -32
+
+\definecasemap 28 29 28 \definecasemap 29 29 28 % cyrillicNLHK
+\definecasemap 30 31 30 \definecasemap 31 31 30 % cyrillicDELTA
+
+\stopmapping
+
+\startencoding[x2]
+
+\definecharacter textgrave 0
+\definecharacter textacute 1
+\definecharacter textcircumflex 2
+\definecharacter texttilde 3
+\definecharacter textdiaeresis 4
+\definecharacter texthungarumlaut 5
+\definecharacter textring 6
+\definecharacter textcaron 7
+\definecharacter textbreve 8
+\definecharacter textmacron 9
+\definecharacter textdotaccent 10
+\definecharacter textcedilla 11
+\definecharacter textogonek 12
+
+\definecharacter endash 21
+\definecharacter emdash 22
+
+\definecharacter textcompwordmark 23
+\definecharacter textvisiblespace 32
+\definecharacter textdollar 36
+\definecharacter textless 60
+\definecharacter textgreater 62
+\definecharacter textbackslash 92
+\definecharacter textasciicircum 94
+\definecharacter textunderscore 95
+\definecharacter textbraceleft 123
+\definecharacter textbar 124
+\definecharacter textbraceright 125
+\definecharacter textasciitilde 126
+\definecharacter textnumero 157
+\definecharacter textcurrency 158
+\definecharacter textsection 159
+\definecharacter sectionmark 159
+\definecharacter textquotedbl 34
+
+\definecharacter cyrillicpalochka 13
+\definecharacter cyrilliclangle 14
+\definecharacter cyrillicrangle 15
+
+\definecharacter leftguillemot 190
+\definecharacter rightguillemot 191
+
+\definecharacter upperleftsinglesixquote 96
+\definecharacter upperleftsingleninequote 39
+\definecharacter upperleftdoublesixquote 16
+\definecharacter upperleftdoubleninequote 17
+\definecharacter lowerleftdoubleninequote 189
+
+\definecharacter upperrightsinglesixquote 96
+\definecharacter upperrightsingleninequote 39
+\definecharacter upperrightdoublesixquote 16
+\definecharacter upperrightdoubleninequote 17
+\definecharacter lowerrightdoubleninequote 189
+
+\definecharacter cyrillicA 192
+\definecharacter cyrillica 224
+\definecharacter cyrillicB 193
+\definecharacter cyrillicb 225
+\definecharacter cyrillicV 194
+\definecharacter cyrillicv 226
+\definecharacter cyrillicG 195
+\definecharacter cyrillicg 227
+\definecharacter cyrillicD 196
+\definecharacter cyrillicd 228
+\definecharacter cyrillicE 197
+\definecharacter cyrillice 229
+\definecharacter cyrillicZH 198
+\definecharacter cyrilliczh 230
+\definecharacter cyrillicZ 199
+\definecharacter cyrillicz 231
+\definecharacter cyrillicI 200
+\definecharacter cyrillici 232
+\definecharacter cyrillicISHRT 201
+\definecharacter cyrillicishrt 233
+\definecharacter cyrillicK 202
+\definecharacter cyrillick 234
+\definecharacter cyrillicL 203
+\definecharacter cyrillicl 235
+\definecharacter cyrillicM 204
+\definecharacter cyrillicm 236
+\definecharacter cyrillicN 205
+\definecharacter cyrillicn 237
+\definecharacter cyrillicO 206
+\definecharacter cyrillico 238
+\definecharacter cyrillicP 207
+\definecharacter cyrillicp 239
+\definecharacter cyrillicR 208
+\definecharacter cyrillicr 240
+\definecharacter cyrillicS 209
+\definecharacter cyrillics 241
+\definecharacter cyrillicT 210
+\definecharacter cyrillict 242
+\definecharacter cyrillicU 211
+\definecharacter cyrillicu 243
+\definecharacter cyrillicF 212
+\definecharacter cyrillicf 244
+\definecharacter cyrillicH 213
+\definecharacter cyrillich 245
+\definecharacter cyrillicC 214
+\definecharacter cyrillicc 246
+\definecharacter cyrillicCH 215
+\definecharacter cyrillicch 247
+\definecharacter cyrillicSH 216
+\definecharacter cyrillicsh 248
+\definecharacter cyrillicSHCH 217
+\definecharacter cyrillicshch 249
+\definecharacter cyrillicHRDSN 218
+\definecharacter cyrillichrdsn 250
+\definecharacter cyrillicERY 219
+\definecharacter cyrillicery 251
+\definecharacter cyrillicSFTSN 220
+\definecharacter cyrillicsftsn 252
+\definecharacter cyrillicEREV 221
+\definecharacter cyrillicerev 253
+\definecharacter cyrillicYU 222
+\definecharacter cyrillicyu 254
+\definecharacter cyrillicYA 223
+\definecharacter cyrillicya 255
+\definecharacter cyrillicGUP 128
+\definecharacter cyrillicgup 160
+\definecharacter cyrillicGHCRS 129
+\definecharacter cyrillicghcrs 161
+\definecharacter cyrillicGDSC 130
+\definecharacter cyrillicgdsc 162
+\definecharacter cyrillicGHK 131
+\definecharacter cyrillicghk 163
+\definecharacter cyrillicSHHA 132
+\definecharacter cyrillicshha 164
+\definecharacter cyrillicZHDSC 133
+\definecharacter cyrilliczhdsc 165
+\definecharacter cyrillicZDSC 134
+\definecharacter cyrilliczdsc 166
+\definecharacter cyrillicABHDZE 135
+\definecharacter cyrillicabhdze 167
+\definecharacter cyrillicYI 136
+\definecharacter cyrillicyi 168
+\definecharacter cyrillicKDSC 137
+\definecharacter cyrillickdsc 169
+\definecharacter cyrillicKBEAK 138
+\definecharacter cyrillickbeak 170
+\definecharacter cyrillicKHK 139
+\definecharacter cyrillickhk 171
+\definecharacter cyrillicLHK 140
+\definecharacter cyrilliclhk 172
+\definecharacter cyrillicNDSC 141
+\definecharacter cyrillicndsc 173
+\definecharacter cyrillicNG 142
+\definecharacter cyrillicng 174
+\definecharacter cyrillicNHK 143
+\definecharacter cyrillicnhk 175
+\definecharacter cyrillicOTLD 144
+\definecharacter cyrillicotld 176
+\definecharacter cyrillicSDSC 145
+\definecharacter cyrillicsdsc 177
+\definecharacter cyrillicUSHRT 146
+\definecharacter cyrillicushrt 178
+\definecharacter cyrillicY 147
+\definecharacter cyrillicy 179
+\definecharacter cyrillicYHCRS 148
+\definecharacter cyrillicyhcrs 180
+\definecharacter cyrillicHDSC 149
+\definecharacter cyrillichdsc 181
+\definecharacter cyrillicHHK 150
+\definecharacter cyrillichhk 182
+\definecharacter cyrillicCHLDSC 151
+\definecharacter cyrillicchldsc 183
+\definecharacter cyrillicCHRDSC 152
+\definecharacter cyrillicchrdsc 184
+\definecharacter cyrillicIE 153
+\definecharacter cyrillicie 185
+\definecharacter cyrillicSCHWA 154
+\definecharacter cyrillicschwa 186
+\definecharacter cyrillicEPS 155
+\definecharacter cyrilliceps 187
+\definecharacter cyrillicYO 156
+\definecharacter cyrillicyo 188
+\definecharacter cyrillicAE 65
+\definecharacter cyrillicae 97
+\definecharacter cyrillicDJE 66
+\definecharacter cyrillicdje 98
+\definecharacter cyrillicTSHE 67
+\definecharacter cyrillictshe 99
+\definecharacter cyrillicABHCH 68
+\definecharacter cyrillicabhch 100
+\definecharacter cyrillicABHCHDSC 69
+\definecharacter cyrillicabhchdsc 101
+\definecharacter cyrillicKVCRS 70
+\definecharacter cyrillickvcrs 102
+\definecharacter cyrillicKHCRS 71
+\definecharacter cyrillickhcrs 103
+\definecharacter cyrillicLDSC 72
+\definecharacter cyrillicldsc 104
+\definecharacter cyrillicII 73
+\definecharacter cyrillicii 105
+\definecharacter cyrillicJE 74
+\definecharacter cyrillicje 106
+\definecharacter cyrillicLJE 75
+\definecharacter cyrilliclje 107
+\definecharacter cyrillicMDSC 76
+\definecharacter cyrillicmdsc 108
+\definecharacter cyrillicNJE 77
+\definecharacter cyrillicnje 109
+\definecharacter cyrillicABHHA 78
+\definecharacter cyrillicabhha 110
+\definecharacter cyrillicPHK 79
+\definecharacter cyrillicphk 111
+\definecharacter cyrillicRDSC 80
+\definecharacter cyrillicrdsc 112
+\definecharacter cyrillicQ 81
+\definecharacter cyrillicq 113
+\definecharacter cyrillicTDSC 82
+\definecharacter cyrillictdsc 114
+\definecharacter cyrillicDZE 83
+\definecharacter cyrillicdze 115
+\definecharacter cyrillicTETSE 84
+\definecharacter cyrillictetse 116
+\definecharacter cyrillicDZHE 85
+\definecharacter cyrillicdzhe 117
+\definecharacter cyrillicCHVCRS 86
+\definecharacter cyrillicchvcrs 118
+\definecharacter cyrillicW 87
+\definecharacter cyrillicw 119
+\definecharacter cyrillicYAT 88
+\definecharacter cyrillicyat 120
+\definecharacter cyrillicBYUS 89
+\definecharacter cyrillicbyus 121
+\definecharacter cyrillicIZH 90
+\definecharacter cyrillicizh 122
+\definecharacter cyrillicNLHK 28
+\definecharacter cyrillicnlhk 29
+\definecharacter cyrillicDELTA 30
+\definecharacter cyrillicdelta 31
+
+\stopencoding
+
+\startmapping[lcy]
+
+\resetcaserange 128 to 255
+
+\definecasemaps 128 to 143 lc +32 uc 0
+\definecasemaps 160 to 175 lc 0 uc -32
+
+\definecasemaps 144 to 159 lc +80 uc 0
+\definecasemaps 224 to 239 lc 0 uc -80
+
+\definecasemap 240 241 240 \definecasemap 241 241 240 % cyrillicYO
+\definecasemap 242 243 242 \definecasemap 243 243 242 % cyrillicGUP
+\definecasemap 244 245 244 \definecasemap 245 245 244 % cyrillicIE
+\definecasemap 244 247 244 \definecasemap 247 247 244 % cyrillicII
+\definecasemap 248 249 248 \definecasemap 249 249 248 % cyrillicYI
+\definecasemap 250 251 240 \definecasemap 241 241 240 % cyrillicUSHRT
+
+\stopmapping
+
+\startencoding[lcy]
+
+%D Characters 0 to 127 are as in normal cmr slots
+
+\definecharacter cyrillicA 128
+\definecharacter cyrillicB 129
+\definecharacter cyrillicV 130
+\definecharacter cyrillicG 131
+\definecharacter cyrillicD 132
+\definecharacter cyrillicE 133
+\definecharacter cyrillicZH 134
+\definecharacter cyrillicZ 135
+\definecharacter cyrillicI 136
+\definecharacter cyrillicISHRT 137
+\definecharacter cyrillicK 138
+\definecharacter cyrillicL 139
+\definecharacter cyrillicM 140
+\definecharacter cyrillicN 141
+\definecharacter cyrillicO 142
+\definecharacter cyrillicP 143
+\definecharacter cyrillicR 144
+\definecharacter cyrillicS 145
+\definecharacter cyrillicT 146
+\definecharacter cyrillicU 147
+\definecharacter cyrillicF 148
+\definecharacter cyrillicH 149
+\definecharacter cyrillicC 150
+\definecharacter cyrillicCH 151
+\definecharacter cyrillicSH 152
+\definecharacter cyrillicSHCH 153
+\definecharacter cyrillicHRDSN 154
+\definecharacter cyrillicERY 155
+\definecharacter cyrillicSFTSN 156
+\definecharacter cyrillicEREV 157
+\definecharacter cyrillicYU 158
+\definecharacter cyrillicYA 159
+\definecharacter cyrillica 160
+\definecharacter cyrillicb 161
+\definecharacter cyrillicv 162
+\definecharacter cyrillicg 163
+\definecharacter cyrillicd 164
+\definecharacter cyrillice 165
+\definecharacter cyrilliczh 166
+\definecharacter cyrillicz 167
+\definecharacter cyrillici 168
+\definecharacter cyrillicishrt 169
+\definecharacter cyrillick 170
+\definecharacter cyrillicl 171
+\definecharacter cyrillicm 172
+\definecharacter cyrillicn 173
+\definecharacter cyrillico 174
+\definecharacter cyrillicp 175
+\definecharacter cyrillicr 224
+\definecharacter cyrillics 225
+\definecharacter cyrillict 226
+\definecharacter cyrillicu 227
+\definecharacter cyrillicf 228
+\definecharacter cyrillich 229
+\definecharacter cyrillicc 230
+\definecharacter cyrillicch 231
+\definecharacter cyrillicsh 232
+\definecharacter cyrillicshch 233
+\definecharacter cyrillichrdsn 234
+\definecharacter cyrillicery 235
+\definecharacter cyrillicsftsn 236
+\definecharacter cyrillicerev 237
+\definecharacter cyrillicyu 238
+\definecharacter cyrillicya 239
+\definecharacter cyrillicYO 240
+\definecharacter cyrillicyo 241
+\definecharacter cyrillicGUP 242
+\definecharacter cyrillicgup 243
+\definecharacter cyrillicIE 244
+\definecharacter cyrillicie 245
+\definecharacter cyrillicII 246
+\definecharacter cyrillicii 247
+\definecharacter cyrillicYI 248
+\definecharacter cyrillicyi 249
+\definecharacter cyrillicUSHRT 250
+\definecharacter cyrillicushrt 251
+
+\definecharacter emdash 196
+\definecharacter textcurrency 197
+\definecharacter textnumero 252
+\definecharacter leftguillemot 253
+\definecharacter rightguillemot 254
+\definecharacter quotedblbase 255
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-def.mkii b/tex/context/base/enco-def.mkii
new file mode 100644
index 000000000..4d8e280cb
--- /dev/null
+++ b/tex/context/base/enco-def.mkii
@@ -0,0 +1,922 @@
+%D \module
+%D [ file=enco-def,
+%D version=2000.05.07, % 2000.20.12, % split from less verbose base file
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Default Character Definitions,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Instead of overloading plain \TEX\ macros (and keeping them
+%D available as an escape), we now use the more verbose
+%D definitions in this file. Since memory is less a problem
+%D these days, this verbosity has only a small price, but we
+%D gain readability. The following definitions are based on
+%D usage of the the original \TEX\ fonts, where composed
+%D characters were not part of the design. So, occasionally
+%D we have to revert to hacks. Thanks to all those users who
+%D helped me to fill in the details.
+
+\startencoding[default]
+
+\definecharacter textcomma ,
+\definecharacter textperiod .
+
+\definecharacter textacute 19
+\definecharacter textbottomdot 46
+\definecharacter textbreve 21
+\definecharacter textcaron 20
+\definecharacter textcedilla 24
+\definecharacter textcircumflex 94
+\definecharacter textdiaeresis 127
+\definecharacter textdotaccent 95
+\definecharacter textgrave 18
+\definecharacter texthungarumlaut 125
+\definecharacter textmacron 22
+\definecharacter textogonek 24 % fake
+\definecharacter textring 23
+\definecharacter texttilde 126
+
+\definecharacter textat 64 % for mojca
+
+\definecharacter textbottomcomma {\hbox{\lower.35ex\hbox{\tx,}}} % for mojca
+
+\definecharacter dotlessi {\char"10 }
+\definecharacter dotlessj {\char"11 }
+\definecharacter dotlessI {I}
+\definecharacter dotlessJ {J}
+
+\definecharacter endash 123
+\definecharacter emdash 124
+
+\definecharacter aeligature {\char26 } % "1A
+\definecharacter AEligature {\char29 } % "1D
+\definecharacter ijligature {ij}
+\definecharacter IJligature {IJ}
+\definecharacter oeligature {\char27 } % "1B
+\definecharacter OEligature {\char30 } % "1E
+
+\definecharacter ssharp {\char25 } % "19
+\definecharacter Ssharp {SS}
+
+\definecharacter thorn {\unknownchar}
+\definecharacter Thorn {\unknownchar}
+
+\definecharacter eth {\unknownchar} % mojca prefers this (was \dstroke)
+%definecharacter Eth {\unknownchar}
+\definecharacter Eth {\Dstroke} % mojca prefers this too
+
+\definecharacter exclamdown 60
+\definecharacter questiondown 62
+
+\definecharacter copyright {\encircled{\txx C}}
+\definecharacter registered {\encircled{\txx R}}
+\definecharacter trademark {\high{\txx TM}}
+
+\definecharacter sectionmark {\mathematics{\mathhexbox278}}
+\definecharacter paragraphmark {\mathematics{\mathhexbox27B}}
+
+\definecharacter onequarter {\vulgarfraction{1}{4}}
+\definecharacter onehalf {\vulgarfraction{1}{2}}
+\definecharacter threequarter {\vulgarfraction{3}{4}}
+
+\definecharacter onesuperior {\high{1}}
+\definecharacter twosuperior {\high{2}}
+\definecharacter threesuperior {\high{3}}
+
+\definecharacter textcent {c}
+\definecharacter textcurrency {\unknownchar}
+\definecharacter textdollar {\fakedollar}
+\definecharacter texteuro {E}
+\definecharacter textflorin {\fakeflorin}
+\definecharacter textsterling {\fakesterling}
+\definecharacter textyen {Y}
+
+\definecharacter ordfeminine {\high{\txx a}}
+\definecharacter ordmasculine {\high{\txx o}}
+
+\definecharacter percent {\fakepercent}
+\definecharacter perthousand {\fakeperthousand}
+
+\definecharacter softhyphen 45
+\definecharacter periodcentered {\hbox{\mathematics\cdot}}
+\definecharacter compoundwordmark 23
+
+\definecharacter textasciicircum 94
+\definecharacter textasciitilde 126
+\definecharacter textslash 47
+\definecharacter textbackslash {\tex{}} % todo
+\definecharacter textbraceleft {\mathematics\{}
+\definecharacter textbraceright {\mathematics\}}
+\definecharacter textunderscore {\fakeunderscore}
+\definecharacter textvisiblespace {\fakevisiblespace}
+
+\definecharacter textbrokenbar {\mathematics\vert}
+\definecharacter textbullet {\mathematics\bullet}
+\definecharacter textdag {\mathematics\dag}
+\definecharacter textddag {\mathematics\ddag}
+\definecharacter textdegree {\mathematics{{}^{\circ}}}
+\definecharacter textdiv {\mathematics\div}
+\definecharacter textellipsis {\mathematics\cdots}
+\definecharacter textfraction {\mathematics/}
+\definecharacter textlognot {\mathematics\neg}
+\definecharacter textminus {\mathematics-}
+\definecharacter textmu {\mathematics\mu}
+\definecharacter textmultiply {\mathematics\times}
+\definecharacter textpm {\mathematics\pm}
+
+\definecharacter quotedbl {"}
+\definecharacter quotedblbase {,,}
+\definecharacter quotedblleft {``}
+\definecharacter quotedblright {''}
+
+\definecharacter quotesingle {`}
+\definecharacter quotesinglebase {,}
+
+\definecharacter quoteleft {`}
+\definecharacter quoteright {'}
+
+\definecharacter guilsingleleft {\fakeleftsubguillemot }
+\definecharacter guilsingleright {\fakerightsubguillemot}
+
+\definecharacter leftguillemot {\fakeleftguillemot }
+\definecharacter rightguillemot {\fakerightguillemot}
+
+\definecharacter Acircumflex {\buildtextaccent\textcircumflex A}
+\definecharacter acircumflex {\buildtextaccent\textcircumflex a}
+\definecharacter Ccircumflex {\buildtextaccent\textcircumflex C}
+\definecharacter ccircumflex {\buildtextaccent\textcircumflex c}
+\definecharacter Ecircumflex {\buildtextaccent\textcircumflex E}
+\definecharacter ecircumflex {\buildtextaccent\textcircumflex e}
+\definecharacter Gcircumflex {\buildtextaccent\textcircumflex G}
+\definecharacter gcircumflex {\buildtextaccent\textcircumflex g}
+\definecharacter Hcircumflex {\buildtextaccent\textcircumflex H}
+\definecharacter hcircumflex {\buildtextaccent\textcircumflex h}
+\definecharacter Icircumflex {\buildtextaccent\textcircumflex \dotlessI}
+\definecharacter icircumflex {\buildtextaccent\textcircumflex \dotlessi}
+\definecharacter Jcircumflex {\buildtextaccent\textcircumflex \dotlessJ}
+\definecharacter jcircumflex {\buildtextaccent\textcircumflex \dotlessj}
+\definecharacter Ocircumflex {\buildtextaccent\textcircumflex O}
+\definecharacter ocircumflex {\buildtextaccent\textcircumflex o}
+\definecharacter Scircumflex {\buildtextaccent\textcircumflex S}
+\definecharacter scircumflex {\buildtextaccent\textcircumflex s}
+\definecharacter Ucircumflex {\buildtextaccent\textcircumflex U}
+\definecharacter ucircumflex {\buildtextaccent\textcircumflex u}
+\definecharacter Wcircumflex {\buildtextaccent\textcircumflex W}
+\definecharacter wcircumflex {\buildtextaccent\textcircumflex w}
+\definecharacter Ycircumflex {\buildtextaccent\textcircumflex Y}
+\definecharacter ycircumflex {\buildtextaccent\textcircumflex y}
+
+\definecharacter Agrave {\buildtextaccent\textgrave A}
+\definecharacter agrave {\buildtextaccent\textgrave a}
+\definecharacter Egrave {\buildtextaccent\textgrave E}
+\definecharacter egrave {\buildtextaccent\textgrave e}
+\definecharacter Igrave {\buildtextaccent\textgrave \dotlessI}
+\definecharacter igrave {\buildtextaccent\textgrave \dotlessi}
+\definecharacter Ograve {\buildtextaccent\textgrave O}
+\definecharacter ograve {\buildtextaccent\textgrave o}
+\definecharacter Ugrave {\buildtextaccent\textgrave U}
+\definecharacter ugrave {\buildtextaccent\textgrave u}
+\definecharacter Ygrave {\buildtextaccent\textgrave Y}
+\definecharacter ygrave {\buildtextaccent\textgrave y}
+
+\definecharacter Atilde {\buildtextaccent\texttilde A}
+\definecharacter atilde {\buildtextaccent\texttilde a}
+\definecharacter Itilde {\buildtextaccent\texttilde \dotlessI}
+\definecharacter itilde {\buildtextaccent\texttilde \dotlessi}
+\definecharacter Ntilde {\buildtextaccent\texttilde N}
+\definecharacter ntilde {\buildtextaccent\texttilde n}
+\definecharacter Otilde {\buildtextaccent\texttilde O}
+\definecharacter otilde {\buildtextaccent\texttilde o}
+\definecharacter Utilde {\buildtextaccent\texttilde U}
+\definecharacter utilde {\buildtextaccent\texttilde u}
+\definecharacter Ytilde {\buildtextaccent\texttilde Y}
+\definecharacter ytilde {\buildtextaccent\texttilde y}
+
+\definecharacter Adiaeresis {\buildtextaccent\textdiaeresis A}
+\definecharacter adiaeresis {\buildtextaccent\textdiaeresis a}
+\definecharacter Ediaeresis {\buildtextaccent\textdiaeresis E}
+\definecharacter ediaeresis {\buildtextaccent\textdiaeresis e}
+\definecharacter Idiaeresis {\buildtextaccent\textdiaeresis \dotlessI}
+\definecharacter idiaeresis {\buildtextaccent\textdiaeresis \dotlessi}
+\definecharacter Odiaeresis {\buildtextaccent\textdiaeresis O}
+\definecharacter odiaeresis {\buildtextaccent\textdiaeresis o}
+\definecharacter Udiaeresis {\buildtextaccent\textdiaeresis U}
+\definecharacter udiaeresis {\buildtextaccent\textdiaeresis u}
+\definecharacter Ydiaeresis {\buildtextaccent\textdiaeresis Y}
+\definecharacter ydiaeresis {\buildtextaccent\textdiaeresis y}
+
+\definecharacter Aacute {\buildtextaccent\textacute A}
+\definecharacter aacute {\buildtextaccent\textacute a}
+\definecharacter Cacute {\buildtextaccent\textacute C}
+\definecharacter cacute {\buildtextaccent\textacute c}
+\definecharacter Eacute {\buildtextaccent\textacute E}
+\definecharacter eacute {\buildtextaccent\textacute e}
+\definecharacter Iacute {\buildtextaccent\textacute \dotlessI}
+\definecharacter iacute {\buildtextaccent\textacute \dotlessi}
+\definecharacter Lacute {\buildtextaccent\textacute L}
+\definecharacter lacute {\buildtextaccent\textacute l}
+\definecharacter Nacute {\buildtextaccent\textacute N}
+\definecharacter nacute {\buildtextaccent\textacute n}
+\definecharacter Oacute {\buildtextaccent\textacute O}
+\definecharacter oacute {\buildtextaccent\textacute o}
+\definecharacter Racute {\buildtextaccent\textacute R}
+\definecharacter racute {\buildtextaccent\textacute r}
+\definecharacter Sacute {\buildtextaccent\textacute S}
+\definecharacter sacute {\buildtextaccent\textacute s}
+\definecharacter Uacute {\buildtextaccent\textacute U}
+\definecharacter uacute {\buildtextaccent\textacute u}
+\definecharacter Yacute {\buildtextaccent\textacute Y}
+\definecharacter yacute {\buildtextaccent\textacute y}
+\definecharacter Zacute {\buildtextaccent\textacute Z}
+\definecharacter zacute {\buildtextaccent\textacute z}
+
+%definecharacter Dstroke {D}
+%definecharacter dstroke {d}
+
+\definecharacter dstroke {\pseudoencodeddj}
+\definecharacter Dstroke {\pseudoencodedDJ}
+\definecharacter Hstroke {H}
+\definecharacter hstroke {h}
+\definecharacter Tstroke {T}
+\definecharacter tstroke {t}
+
+\definecharacter Cdotaccent {\buildtextaccent\textdotaccent C}
+\definecharacter cdotaccent {\buildtextaccent\textdotaccent c}
+\definecharacter Edotaccent {\buildtextaccent\textdotaccent E}
+\definecharacter edotaccent {\buildtextaccent\textdotaccent e}
+\definecharacter Gdotaccent {\buildtextaccent\textdotaccent G}
+\definecharacter gdotaccent {\buildtextaccent\textdotaccent g}
+\definecharacter Idotaccent {\buildtextaccent\textdotaccent \dotlessI}
+\definecharacter idotaccent {\buildtextaccent\textdotaccent \dotlessi}
+\definecharacter Zdotaccent {\buildtextaccent\textdotaccent Z}
+\definecharacter zdotaccent {\buildtextaccent\textdotaccent z}
+
+\definecharacter Amacron {\buildtextaccent\textmacron A}
+\definecharacter amacron {\buildtextaccent\textmacron a}
+\definecharacter Emacron {\buildtextaccent\textmacron E}
+\definecharacter emacron {\buildtextaccent\textmacron e}
+\definecharacter Imacron {\buildtextaccent\textmacron \dotlessI}
+\definecharacter imacron {\buildtextaccent\textmacron \dotlessi}
+\definecharacter Omacron {\buildtextaccent\textmacron O}
+\definecharacter omacron {\buildtextaccent\textmacron o}
+\definecharacter Umacron {\buildtextaccent\textmacron U}
+\definecharacter umacron {\buildtextaccent\textmacron u}
+
+\definecharacter Ccedilla {\buildtextcedilla C}
+\definecharacter ccedilla {\buildtextcedilla c}
+\definecharacter Kcedilla {\buildtextcedilla K}
+\definecharacter kcedilla {\buildtextcedilla k}
+\definecharacter Lcedilla {\buildtextcedilla L}
+\definecharacter lcedilla {\buildtextcedilla l}
+\definecharacter Ncedilla {\buildtextcedilla N}
+\definecharacter ncedilla {\buildtextcedilla n}
+\definecharacter Rcedilla {\buildtextcedilla R}
+\definecharacter rcedilla {\buildtextcedilla r}
+\definecharacter Scedilla {\buildtextcedilla S}
+\definecharacter scedilla {\buildtextcedilla s}
+\definecharacter Tcedilla {\buildtextcedilla T}
+\definecharacter tcedilla {\buildtextcedilla t}
+
+\definecharacter Ohungarumlaut {\buildtextaccent\texthungarumlaut O}
+\definecharacter ohungarumlaut {\buildtextaccent\texthungarumlaut o}
+\definecharacter Uhungarumlaut {\buildtextaccent\texthungarumlaut U}
+\definecharacter uhungarumlaut {\buildtextaccent\texthungarumlaut u}
+
+\definecharacter Aogonek {\buildtextogonek A}
+\definecharacter aogonek {\buildtextogonek a}
+\definecharacter Eogonek {\buildtextogonek E}
+\definecharacter eogonek {\buildtextogonek e}
+\definecharacter Iogonek {\buildtextogonek I}
+\definecharacter iogonek {\buildtextogonek i}
+\definecharacter Uogonek {\buildtextogonek U}
+\definecharacter uogonek {\buildtextogonek u}
+
+\definecharacter Aring {\buildtextaccent\textring A}
+\definecharacter aring {\buildtextaccent\textring a}
+\definecharacter Uring {\buildtextaccent\textring U}
+\definecharacter uring {\buildtextaccent\textring u}
+
+\definecharacter Abreve {\buildtextaccent\textbreve A}
+\definecharacter abreve {\buildtextaccent\textbreve a}
+\definecharacter Ebreve {\buildtextaccent\textbreve E}
+\definecharacter ebreve {\buildtextaccent\textbreve e}
+\definecharacter Gbreve {\buildtextaccent\textbreve G}
+\definecharacter gbreve {\buildtextaccent\textbreve g}
+\definecharacter Ibreve {\buildtextaccent\textbreve \dotlessI}
+\definecharacter ibreve {\buildtextaccent\textbreve \dotlessi}
+\definecharacter Obreve {\buildtextaccent\textbreve O}
+\definecharacter obreve {\buildtextaccent\textbreve o}
+\definecharacter Ubreve {\buildtextaccent\textbreve U}
+\definecharacter ubreve {\buildtextaccent\textbreve u}
+
+\definecharacter Ccaron {\buildtextaccent\textcaron C}
+\definecharacter ccaron {\buildtextaccent\textcaron c}
+\definecharacter Dcaron {\buildtextaccent\textcaron D}
+\definecharacter dcaron {\buildtextaccent\textcaron d}
+\definecharacter Ecaron {\buildtextaccent\textcaron E}
+\definecharacter ecaron {\buildtextaccent\textcaron e}
+\definecharacter Lcaron {\buildtextaccent\textcaron L}
+\definecharacter lcaron {\buildtextaccent\textcaron l}
+\definecharacter Ncaron {\buildtextaccent\textcaron N}
+\definecharacter ncaron {\buildtextaccent\textcaron n}
+\definecharacter Rcaron {\buildtextaccent\textcaron R}
+\definecharacter rcaron {\buildtextaccent\textcaron r}
+\definecharacter Scaron {\buildtextaccent\textcaron S}
+\definecharacter scaron {\buildtextaccent\textcaron s}
+\definecharacter Tcaron {\buildtextaccent\textcaron T}
+\definecharacter tcaron {\buildtextaccent\textcaron t}
+\definecharacter Ycaron {\buildtextaccent\textcaron Y}
+\definecharacter ycaron {\buildtextaccent\textcaron y}
+\definecharacter Zcaron {\buildtextaccent\textcaron Z}
+\definecharacter zcaron {\buildtextaccent\textcaron z}
+
+\definecharacter Lstroke {\hsmash{\char32}L}
+\definecharacter lstroke {\hsmash{\char32}l}
+\definecharacter Ostroke {\char31 } % "1F
+\definecharacter ostroke {\char28 } % "1C
+
+\definecharacter aumlaut {\moveaccent{-.1ex}\adiaeresis}
+\definecharacter eumlaut {\moveaccent{-.1ex}\ediaeresis}
+\definecharacter iumlaut {\moveaccent{-.1ex}\idiaeresis}
+\definecharacter oumlaut {\moveaccent{-.1ex}\odiaeresis}
+\definecharacter uumlaut {\moveaccent{-.1ex}\udiaeresis}
+
+\definecharacter Aumlaut {\smashaccent\Adiaeresis}
+\definecharacter Eumlaut {\smashaccent\Ediaeresis}
+\definecharacter Iumlaut {\smashaccent\Idiaeresis}
+\definecharacter Oumlaut {\smashaccent\Odiaeresis}
+\definecharacter Uumlaut {\smashaccent\Udiaeresis}
+
+\definecharacter scommaaccent {\buildtextbottomcomma s}
+\definecharacter Scommaaccent {\buildtextbottomcomma S}
+\definecharacter tcommaaccent {\buildtextbottomcomma t}
+\definecharacter Tcommaaccent {\buildtextbottomcomma T}
+\definecharacter lcommaaccent {\buildtextbottomcomma l}
+\definecharacter Lcommaaccent {\buildtextbottomcomma L}
+
+\definecharacter Etilde {\buildtextaccent\texttilde E}
+\definecharacter etilde {\buildtextaccent\texttilde e}
+
+\definecharacter Ahook {A}
+\definecharacter ahook {a}
+\definecharacter Ehook {E}
+\definecharacter ehook {e}
+\definecharacter Ihook {I}
+\definecharacter ihook {i}
+\definecharacter Ohook {O}
+\definecharacter ohook {o}
+\definecharacter Uhook {U}
+\definecharacter uhook {u}
+\definecharacter Yhook {Y}
+\definecharacter yhook {y}
+
+\definecharacter Acircumflexgrave {\Acircumflex}
+\definecharacter Acircumflexacute {\Acircumflex}
+\definecharacter Acircumflextilde {\Acircumflex}
+\definecharacter Acircumflexhook {\Acircumflex}
+\definecharacter acircumflexgrave {\acircumflex}
+\definecharacter acircumflexacute {\acircumflex}
+\definecharacter acircumflextilde {\acircumflex}
+\definecharacter acircumflexhook {\acircumflex}
+\definecharacter Ecircumflexgrave {\Ecircumflex}
+\definecharacter Ecircumflexacute {\Ecircumflex}
+\definecharacter Ecircumflextilde {\Ecircumflex}
+\definecharacter Ecircumflexhook {\Ecircumflex}
+\definecharacter ecircumflexgrave {\ecircumflex}
+\definecharacter ecircumflexacute {\ecircumflex}
+\definecharacter ecircumflextilde {\ecircumflex}
+\definecharacter ecircumflexhook {\ecircumflex}
+\definecharacter Ocircumflexgrave {\Ocircumflex}
+\definecharacter Ocircumflexacute {\Ocircumflex}
+\definecharacter Ocircumflextilde {\Ocircumflex}
+\definecharacter Ocircumflexhook {\Ocircumflex}
+\definecharacter ocircumflexgrave {\ocircumflex}
+\definecharacter ocircumflexacute {\ocircumflex}
+\definecharacter ocircumflextilde {\ocircumflex}
+\definecharacter ocircumflexhook {\ocircumflex}
+
+\definecharacter Abrevegrave {\Abreve}
+\definecharacter Abreveacute {\Abreve}
+\definecharacter Abrevetilde {\Abreve}
+\definecharacter Abrevehook {\Abreve}
+\definecharacter abrevegrave {\abreve}
+\definecharacter abreveacute {\abreve}
+\definecharacter abrevetilde {\abreve}
+\definecharacter abrevehook {\abreve}
+
+\definecharacter Adotbelow {\buildtextbottomdot A}
+\definecharacter adotbelow {\buildtextbottomdot a}
+\definecharacter Edotbelow {\buildtextbottomdot E}
+\definecharacter edotbelow {\buildtextbottomdot e}
+\definecharacter Idotbelow {\buildtextbottomdot I}
+\definecharacter idotbelow {\buildtextbottomdot i}
+\definecharacter Odotbelow {\buildtextbottomdot O}
+\definecharacter odotbelow {\buildtextbottomdot o}
+\definecharacter Udotbelow {\buildtextbottomdot U}
+\definecharacter udotbelow {\buildtextbottomdot u}
+\definecharacter Ydotbelow {\buildtextbottomdot Y}
+\definecharacter ydotbelow {\buildtextbottomdot y}
+
+\definecharacter Ohorndotbelow {\buildtextbottomdot\Ohorn}
+\definecharacter ohorndotbelow {\buildtextbottomdot\ohorn}
+\definecharacter Uhorndotbelow {\buildtextbottomdot\Uhorn}
+\definecharacter uhorndotbelow {\buildtextbottomdot\uhorn}
+
+\definecharacter Acircumflexdotbelow {\buildtextbottomdot\Acircumflex}
+\definecharacter acircumflexdotbelow {\buildtextbottomdot\acircumflex}
+\definecharacter Ecircumflexdotbelow {\buildtextbottomdot\Ecircumflex}
+\definecharacter ecircumflexdotbelow {\buildtextbottomdot\ecircumflex}
+\definecharacter Ocircumflexdotbelow {\buildtextbottomdot\Ocircumflex}
+\definecharacter ocircumflexdotbelow {\buildtextbottomdot\ocircumflex}
+\definecharacter Abrevedotbelow {\buildtextbottomdot\Abreve}
+\definecharacter abrevedotbelow {\buildtextbottomdot\abreve}
+
+\definecharacter Ohorn {O}
+\definecharacter Ohorngrave {\Ograve}
+\definecharacter Ohornacute {\Oacute}
+\definecharacter Ohorntilde {\Otilde}
+\definecharacter Ohornhook {O}
+\definecharacter ohorn {o}
+\definecharacter ohorngrave {\ograve}
+\definecharacter ohornacute {\oacute}
+\definecharacter ohorntilde {\otilde}
+\definecharacter ohornhook {o}
+\definecharacter Uhorn {U}
+\definecharacter Uhorngrave {\Ugrave}
+\definecharacter Uhornacute {\Uacute}
+\definecharacter Uhorntilde {\Utilde}
+\definecharacter Uhornhook {U}
+\definecharacter uhorn {u}
+\definecharacter uhorngrave {\ugrave}
+\definecharacter uhornacute {\uacute}
+\definecharacter uhorntilde {\utilde}
+\definecharacter uhornhook {u}
+
+\stopencoding
+
+%D Needed for transliterated chinese (provided by Tobias Burnus).
+
+\startencoding[default]
+
+\definecharacter acaron {\buildtextaccent\textcaron a} % U+01CE
+\definecharacter icaron {\buildtextaccent\textcaron \dotlessi} % U+01D0
+\definecharacter ocaron {\buildtextaccent\textcaron o} % U+01D2
+\definecharacter ucaron {\buildtextaccent\textcaron u} % U+01D4
+
+\stopencoding
+
+%D Greek (moved to here):
+
+\startencoding[default]
+
+% Uppercase Greek letters
+
+\definecharacter greekAlpha {\Alpha}
+\definecharacter greekBeta {\Beta}
+\definecharacter greekGamma {\Gamma}
+\definecharacter greekDelta {\Delta}
+\definecharacter greekEpsilon {\Epsilon}
+\definecharacter greekZeta {\Zeta}
+\definecharacter greekEta {\Eta}
+\definecharacter greekTheta {\Theta}
+\definecharacter greekIota {\Iota}
+\definecharacter greekKappa {\Kappa}
+\definecharacter greekLambda {\Lambda}
+\definecharacter greekMu {\Mu}
+\definecharacter greekNu {\Nu}
+\definecharacter greekXi {\Xi}
+\definecharacter greekOmicron {\Omicron}
+\definecharacter greekPi {\Pi}
+\definecharacter greekRho {\Rho}
+\definecharacter greekSigma {\Sigma}
+\definecharacter greekTau {\Tau}
+\definecharacter greekUpsilon {\Upsilon}
+\definecharacter greekPhi {\Phi}
+\definecharacter greekChi {\Chi}
+\definecharacter greekPsi {\Psi}
+\definecharacter greekOmega {\Omega}
+
+% Lowercase Greek letters
+
+\definecharacter greekalpha {\alpha}
+\definecharacter greekbeta {\beta}
+\definecharacter greekgamma {\gamma}
+\definecharacter greekdelta {\delta}
+\definecharacter greekepsilon {\varepsilon}
+\definecharacter greekepsilonalt {\epsilon}
+\definecharacter greekzeta {\zeta}
+\definecharacter greeketa {\eta}
+\definecharacter greektheta {\theta}
+\definecharacter greekthetaalt {\vartheta}
+\definecharacter greekiota {\iota}
+\definecharacter greekkappa {\kappa}
+\definecharacter greeklambda {\lambda}
+\definecharacter greekmu {\mu}
+\definecharacter greeknu {\nu}
+\definecharacter greekxi {\xi}
+\definecharacter greekomicron {\omicron}
+\definecharacter greekpi {\pi}
+\definecharacter greekrho {\rho}
+\definecharacter greeksigma {\sigma}
+\definecharacter greekfinalsigma {\varsigma}
+\definecharacter greektau {\tau}
+\definecharacter greekupsilon {\upsilon}
+\definecharacter greekphi {\varphi}
+\definecharacter greekphialt {\phi}
+\definecharacter greekchi {\chi}
+\definecharacter greekpsi {\psi}
+\definecharacter greekomega {\omega}
+
+% Accented Uppercase Greek letters
+
+\definecharacter greekAlphatonos {'A}
+\definecharacter greekEpsilontonos {'E}
+\definecharacter greekEtatonos {'H}
+\definecharacter greekIotatonos {'I}
+\definecharacter greekOmicrontonos {'O}
+\definecharacter greekUpsilontonos {'U}
+\definecharacter greekOmegatonos {'W}
+\definecharacter greekIotadialytika {"I}
+\definecharacter greekUpsilondialytika {"U}
+
+% Accented Lowercase Greek letters
+
+\definecharacter greekalphatonos {'a}
+\definecharacter greekepsilontonos {'e}
+\definecharacter greeketatonos {'h}
+\definecharacter greekiotatonos {'i}
+\definecharacter greekomicrontonos {'o}
+\definecharacter greekupsilontonos {'u}
+\definecharacter greekomegatonos {'w}
+\definecharacter greekiotadialytika {"i}
+\definecharacter greekupsilondialytika {"u}
+\definecharacter greekiotadialytikatonos {'"i}
+\definecharacter greekupsilondialytikatonos {'"u}
+
+% Miscellaneous Greek symbols
+
+\definecharacter greekleftquot {((}
+\definecharacter greekrightquot {))}
+\definecharacter greektonos {'}
+\definecharacter greekdialytikatonos {'"}
+\definecharacter greekapostrophos {''}
+
+\stopencoding
+
+%D Cyrillic (moved to here):
+
+\startencoding[default]
+
+\definecharacter cyrillicA {A}
+\definecharacter cyrillicB {B}
+\definecharacter cyrillicV {V}
+\definecharacter cyrillicG {G}
+\definecharacter cyrillicD {D}
+\definecharacter cyrillicE {E}
+\definecharacter cyrillicZH {ZH}
+\definecharacter cyrillicZ {Z}
+\definecharacter cyrillicI {I}
+\definecharacter cyrillicISHRT {ISHRT}
+\definecharacter cyrillicK {K}
+\definecharacter cyrillicL {L}
+\definecharacter cyrillicM {M}
+\definecharacter cyrillicN {N}
+\definecharacter cyrillicO {O}
+\definecharacter cyrillicP {P}
+\definecharacter cyrillicR {R}
+\definecharacter cyrillicS {S}
+\definecharacter cyrillicT {T}
+\definecharacter cyrillicU {U}
+\definecharacter cyrillicF {F}
+\definecharacter cyrillicH {H}
+\definecharacter cyrillicC {C}
+\definecharacter cyrillicCH {CH}
+\definecharacter cyrillicSH {SH}
+\definecharacter cyrillicSHCH {SHCH}
+\definecharacter cyrillicHRDSN {HRDSN}
+\definecharacter cyrillicERY {ERY}
+\definecharacter cyrillicSFTSN {SFTSN}
+\definecharacter cyrillicEREV {EREV}
+\definecharacter cyrillicYU {YU}
+\definecharacter cyrillicYA {YA}
+\definecharacter cyrillicGUP {GUP}
+\definecharacter cyrillicGHCRS {GHCRS}
+\definecharacter cyrillicDJE {DJE}
+\definecharacter cyrillicTSHE {TSHE}
+\definecharacter cyrillicSHHA {SHHA}
+\definecharacter cyrillicZHDSC {ZHDSC}
+\definecharacter cyrillicZDSC {ZDSC}
+\definecharacter cyrillicLJE {LJE}
+\definecharacter cyrillicYI {YI}
+\definecharacter cyrillicKDSC {KDSC}
+\definecharacter cyrillicKBEAK {KBEAK}
+\definecharacter cyrillicKVCRS {KVCRS}
+\definecharacter cyrillicAE {AE}
+\definecharacter cyrillicNDSC {NDSC}
+\definecharacter cyrillicNG {NG}
+\definecharacter cyrillicDZE {DZE}
+\definecharacter cyrillicOTLD {OTLD}
+\definecharacter cyrillicSDSC {SDSC}
+\definecharacter cyrillicUSHRT {USHRT}
+\definecharacter cyrillicY {Y}
+\definecharacter cyrillicYHCRS {YHCRS}
+\definecharacter cyrillicHDSC {HDSC}
+\definecharacter cyrillicDZHE {DZHE}
+\definecharacter cyrillicCHVCRS {CHVCRS}
+\definecharacter cyrillicCHRDSC {CHRDSC}
+\definecharacter cyrillicIE {IE}
+\definecharacter cyrillicSCHWA {SCHWA}
+\definecharacter cyrillicNJE {NJE}
+\definecharacter cyrillicYO {YO}
+\definecharacter cyrillicII {II}
+\definecharacter cyrillicJE {JE}
+\definecharacter cyrillicQ {Q}
+\definecharacter cyrillicW {W}
+
+\definecharacter cyrillica {a}
+\definecharacter cyrillicb {b}
+\definecharacter cyrillicv {v}
+\definecharacter cyrillicg {g}
+\definecharacter cyrillicd {d}
+\definecharacter cyrillice {e}
+\definecharacter cyrilliczh {zh}
+\definecharacter cyrillicz {z}
+\definecharacter cyrillici {i}
+\definecharacter cyrillicishrt {ishrt}
+\definecharacter cyrillick {k}
+\definecharacter cyrillicl {l}
+\definecharacter cyrillicm {m}
+\definecharacter cyrillicn {n}
+\definecharacter cyrillico {o}
+\definecharacter cyrillicp {p}
+\definecharacter cyrillicr {r}
+\definecharacter cyrillics {s}
+\definecharacter cyrillict {t}
+\definecharacter cyrillicu {u}
+\definecharacter cyrillicf {f}
+\definecharacter cyrillich {h}
+\definecharacter cyrillicc {c}
+\definecharacter cyrillicch {ch}
+\definecharacter cyrillicsh {sh}
+\definecharacter cyrillicshch {shch}
+\definecharacter cyrillichrdsn {hrdsn}
+\definecharacter cyrillicery {ery}
+\definecharacter cyrillicsftsn {sftsn}
+\definecharacter cyrillicerev {erev}
+\definecharacter cyrillicyu {yu}
+\definecharacter cyrillicya {ya}
+\definecharacter cyrillicgup {gup}
+\definecharacter cyrillicghcrs {ghcrs}
+\definecharacter cyrillicdje {dje}
+\definecharacter cyrillictshe {tshe}
+\definecharacter cyrillicshha {shha}
+\definecharacter cyrilliczhdsc {zhdsc}
+\definecharacter cyrilliczdsc {zdsc}
+\definecharacter cyrilliclje {lje}
+\definecharacter cyrillicyi {yi}
+\definecharacter cyrillickdsc {kdsc}
+\definecharacter cyrillickbeak {kbeak}
+\definecharacter cyrillickvcrs {kvcrs}
+\definecharacter cyrillicae {ae}
+\definecharacter cyrillicndsc {ndsc}
+\definecharacter cyrillicng {ng}
+\definecharacter cyrillicdze {dze}
+\definecharacter cyrillicotld {otld}
+\definecharacter cyrillicsdsc {sdsc}
+\definecharacter cyrillicushrt {ushrt}
+\definecharacter cyrillicy {y}
+\definecharacter cyrillicyhcrs {yhcrs}
+\definecharacter cyrillichdsc {hdsc}
+\definecharacter cyrillicdzhe {dzhe}
+\definecharacter cyrillicchvcrs {chvcrs}
+\definecharacter cyrillicchrdsc {chrdsc}
+\definecharacter cyrillicie {ie}
+\definecharacter cyrillicschwa {schwa}
+\definecharacter cyrillicnje {nje}
+\definecharacter cyrillicyo {yo}
+\definecharacter cyrillicii {ii}
+\definecharacter cyrillicje {je}
+\definecharacter cyrillicq {q}
+\definecharacter cyrillicw {w}
+
+\definecharacter cyrillicGJE {\'\cyrillicG}
+\definecharacter cyrillicgje {\'\cyrillicg}
+\definecharacter cyrillicKJE {\'\cyrillicK}
+\definecharacter cyrillickje {\'\cyrillick}
+
+\stopencoding
+
+\def\cyrillicio{\cyrillicyo}
+\def\cyrillicIO{\cyrillicYO}
+
+%D Hebrew:
+
+\startencoding[default]
+
+\definecharacter hebrewAlef {'}
+\definecharacter hebrewBet {b}
+\definecharacter hebrewGimel {g}
+\definecharacter hebrewDalet {d}
+\definecharacter hebrewHe {h}
+\definecharacter hebrewVav {w}
+\definecharacter hebrewZayin {z}
+\definecharacter hebrewHet {\hstroke}
+\definecharacter hebrewTet {\tcedilla}
+\definecharacter hebrewYod {y}
+\definecharacter hebrewKaffinal {k}
+\definecharacter hebrewKaf {k}
+\definecharacter hebrewLamed {l}
+\definecharacter hebrewMemfinal {m}
+\definecharacter hebrewMem {m}
+\definecharacter hebrewNunfinal {n}
+\definecharacter hebrewNun {n}
+\definecharacter hebrewSamekh {s}
+\definecharacter hebrewAyin {\gdotaccent}
+\definecharacter hebrewPefinal {p}
+\definecharacter hebrewPe {p}
+\definecharacter hebrewTsadifinal {\scedilla}
+\definecharacter hebrewTsadi {\scedilla}
+\definecharacter hebrewQof {q}
+\definecharacter hebrewResh {r}
+\definecharacter hebrewShin {\scaron}
+\definecharacter hebrewTav {th}
+
+\stopencoding
+
+%D A few goodies:
+
+\def\eszett{\ssharp}
+\def\Eszett{\Ssharp}
+
+\def\lslash{\lstroke}
+\def\Lslash{\Lstroke}
+\def\dslash{\dstroke}
+\def\Dslash{\Dstroke}
+\def\oslash{\ostroke}
+\def\Oslash{\Ostroke}
+
+\def\dcroat{\dstroke}
+\def\Dcroat{\Dstroke}
+
+% \startencoding [default]
+%
+% \definecharacter scommaaccent {\scedilla}
+% \definecharacter Scommaaccent {\Scedilla}
+% \definecharacter tcommaaccent {\tcedilla}
+% \definecharacter Tcommaaccent {\Tcedilla}
+%
+% \stopencoding
+
+% for plain tex's sake
+
+\def\S {\sectionmark }
+\def\P {\paragraphmark}
+
+% for latex users sake
+
+\def\textS {\sectionmark }
+\def\textP {\paragraphmark}
+
+% for old times sake
+
+\def\florin {\textflorin } \def\florijn{\textflorin}
+\def\dollar {\textdollar }
+\def\pound {\textsterling}
+\def\sterling{\textsterling}
+
+% idem
+
+\def\promille{\perthousand}
+\def\permille{\perthousand}
+\def\procent {\percent }
+\def\permine {\fakepermine}
+
+% some more
+
+\def\hyphen {\softhyphen}
+\def\cwm {\compoundwordmark}
+\def\nonbreakinghyphen {\hyphen}
+\def\breakinghyphen {\hyphen\prewordbreak}
+
+% quotes
+
+\def\lowerleftsingleninequote {\quotesinglebase}
+\def\lowerleftdoubleninequote {\quotedblbase}
+\def\lowerrightsingleninequote {\quotesinglebase}
+\def\lowerrightdoubleninequote {\quotedblbase}
+
+\def\upperleftsingleninequote {\quoteright}
+\def\upperleftdoubleninequote {\quotedblright}
+\def\upperrightsingleninequote {\quoteright}
+\def\upperrightdoubleninequote {\quotedblright}
+
+\def\upperleftsinglesixquote {\quoteleft}
+\def\upperleftdoublesixquote {\quotedblleft}
+\def\upperrightsinglesixquote {\quoteleft}
+\def\upperrightdoublesixquote {\quotedblleft}
+
+\def\leftsubguillemot {\guilsingleleft}
+\def\rightsubguillemot {\guilsingleright}
+
+%D A couple of fallbacks suggestion by users, slightly
+%D adapted and obscured by memory saving hacks.
+
+\unprotect
+
+\startencoding[default]
+
+\definecharacter textcent {c\rlap{\hskip-.2\s!em
+ \vrule\!!width.2\s!pt\!!height1.2\s!ex\!!depth.2\s!ex}}
+
+\definecharacter texteuro {C\rlap{\hskip-.75\s!em
+ \vrule\!!width.4\s!em\!!height.85\s!ex\!!depth-.8\s!ex}}
+
+\definecharacter textblacksquare {\dontleavehmode\hbox{%
+ \vrule\!!width.3\s!em\!!height.4\s!em\!!depth-.1\s!em}}
+
+\definecharacter textbrokenbar {\dontleavehmode\hbox{\kern.05\s!em
+ \vrule\!!width.4\s!pt\!!height1.8\s!ex\!!depth-.85\s!ex
+ \llap{%
+ \vrule\!!width.4\s!pt\!!height.35\s!ex\!!depth.6\s!ex}%
+ \kern.05\s!em}}
+
+\stopencoding
+
+\protect
+
+%D We also use symbolic names for math accents.
+
+\startencoding[default]
+
+\definecharacter mathacute "7013
+\definecharacter mathgrave "7012
+\definecharacter mathddot "707F
+\definecharacter mathtilde "707E
+\definecharacter mathbar "7016
+\definecharacter mathbreve "7015
+\definecharacter mathcheck "7014
+\definecharacter mathhat "705E
+\definecharacter mathvec "017E
+\definecharacter mathdot "705F
+\definecharacter mathwidetilde "0365
+\definecharacter mathwidehat "0362
+
+\stopencoding
+
+% \startencoding [default]
+
+% \definecommand prime {\mathematics{'}}
+% \definecommand doubleprime {\mathematics{''}}
+% \definecommand tripleprime {\mathematics{'''}}
+
+% \stopencoding
+
+\ifx\zdot\undefined \def\zdot{\zdotaccent} \fi
+\ifx\Zdot\undefined \def\Zdot{\Zdotaccent} \fi
+
+\ifx\greeklamda\undefined \def\greeklamda{\greeklambda} \fi
+\ifx\greekLamda\undefined \def\greekLamda{\greekLambda} \fi
+
+\ifx\leftguillemet \undefined \def\leftguillemet {\leftguillemot } \fi
+\ifx\rightguillemet\undefined \def\rightguillemet{\rightguillemot} \fi
+
+%D New:
+
+\startencoding[\s!default]
+
+\definecharacter schwa {\hbox{\rotate[\c!rotation=180,\c!location=\v!high]{\hbox{e}}}}
+\definecharacter schwagrave {\buildtextgrave\schwa}
+
+\stopencoding
+
+%D Also new, from Taco, for Mojca, who wanted another 8~regimes.
+
+\startencoding[\s!default]
+
+\definecharacter texthorizontalbar {{\endash\kern\zeropoint\endash}}
+\definecharacter textdong {\underbar{\dstroke}}
+
+\stopencoding
+
+%D Goodie (makes more sense):
+
+\def\normalcontrolspace
+ {\getglyph{ComputerModernMono}{\char32}}
+
+\def\fakedcontrolspace % can be virtual in luatex
+ {\dontleavehmode\hbox
+ {\scratchdimen.1ex%
+ \kern\scratchdimen
+ \vrule \!!width\scratchdimen \!!height5.5\scratchdimen \!!depth3\scratchdimen
+ \vrule \!!width\dimexpr.5em-4\scratchdimen\relax \!!height-2\scratchdimen \!!depth3\scratchdimen
+ \vrule \!!width\scratchdimen \!!height5.5\scratchdimen \!!depth3\scratchdimen
+ \kern\scratchdimen}}
+
+\def\fakecontrolspace{\let\normalcontrolspace\fakedcontrolspace}
+
+\endinput
diff --git a/tex/context/base/enco-ec.mkii b/tex/context/base/enco-ec.mkii
new file mode 100644
index 000000000..1ac41cadf
--- /dev/null
+++ b/tex/context/base/enco-ec.mkii
@@ -0,0 +1,295 @@
+%D \module
+%D [ file=enco-ec,
+%D version=2000.05.07, % 1999.16.07,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=\LATEX\ EC Encoding,
+%D author={Patrick Gundlach, Hans Hagen, Taco Hoekwater, Mojca Miklavec},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is \LATEX2e's T1 encoding vector. All standard \LATEX\
+%D accents will work, including \type{\k}. The only accent that
+%D does not work is \type{\t} (there is no tie in T1 encoding).
+%D
+%D Annoyingly, most \POSTSCRIPT\ fonts do not have \type
+%D {\dotlessj}, and T1 encoding does not make the various
+%D prebuilts with \type {j} available. When this is the case:
+%D
+%D \starttyping
+%D \startencoding[ec]
+%D \definecharacter dotlessj {j}
+%D \stopencoding
+%D \stoptyping
+%D
+%D is a way out.
+
+%D There is hardly a point in supporting TS1 encoding.
+
+\startmapping[ec]
+
+% a problem is that the uppercase of dstroke (158) and eth (240)
+% is the same glyph (208) so we cannot do lowercase mapping there
+
+\definecasemaps 128 to 156 lc +32 uc 0
+\definecasemap 157 `i 157 % Idotaccent i
+\definecasemap 158 158 208 % dstroke Eth
+\definecasemap 159 159 159 % sectionmark
+\definecasemaps 160 to 187 lc 0 uc -32
+\resetcaserange 189 to 191 % exclamdown, questiondown, textsterling
+\definecasemaps 192 to 223 lc +32 uc 0
+\definecasemaps 224 to 254 lc 0 uc -32
+\definecaseswap 255 223 % ssharp (else patterns fail)
+\definecaseswap 25 `I % dotless i
+
+% 156 vs. 188 IJligature
+
+%D Some languages need this:
+
+% \definecaseself 34 % quotedbl
+% \definecaseself 18 % quotedblbase
+% \definecaseself 16 % quotedblleft
+% \definecaseself 17 % quotedblright
+% \definecaseself 39 % quotesingle
+% \definecaseself 13 % quotesinglebase
+% \definecaseself 96 % quoteleft
+% \definecaseself 39 % quoteright
+
+%D So far for the mapping.
+
+%D The following characters are kind of dangerous,
+%D that is, they are normally not part of fonts, unless
+%D explicitly constructed.
+%D
+%D \startitemize[columns,two]
+%D \item \type{\dotlessj} - but then it may not be defined!!!!
+%D \item \type{\IJligature}
+%D \item \type{\ijligature}
+%D \item \type{\Ssharp}
+%D \item \type{\perthousand}
+%D \item \type{\compoundwordmark}
+% \item \type{\textvisiblespace}
+%D \stopitemize
+
+%D So, for the moment we nil them; we can always create
+%D another vector if needed.
+
+\stopmapping
+
+\startencoding[ec][ec] % second arg defines auto regime, needed here ?
+
+\definecharacter textgrave 0
+\definecharacter textacute 1
+\definecharacter textcircumflex 2
+\definecharacter texttilde 3
+\definecharacter textdiaeresis 4
+\definecharacter texthungarumlaut 5
+\definecharacter textring 6
+\definecharacter textcaron 7
+\definecharacter textbreve 8
+\definecharacter textmacron 9
+\definecharacter textdotaccent 10
+\definecharacter textcedilla 11
+\definecharacter textogonek 12
+\definecharacter quotesinglebase 13
+\definecharacter guilsingleleft 14
+\definecharacter guilsingleright 15
+\definecharacter quotedblleft 16
+\definecharacter quotedblright 17
+\definecharacter quotedblbase 18
+\definecharacter leftguillemot 19
+\definecharacter rightguillemot 20
+\definecharacter endash 21
+\definecharacter emdash 22
+%definecharacter compoundwordmark 23
+%definecharacter perthousand 24
+\definecharacter dotlessi 25 % or when missing: {j}
+\definecharacter dotlessj 26
+% ff 27
+% fi 28
+% fl 29
+% ffi 30
+% ffl 31
+%definecharacter textvisiblespace 32
+% exclam ! 33
+\definecharacter quotedbl 34
+% numbersign # 35
+% dollar $ 36
+\definecharacter percent 37
+% ampersand & 38
+%definecharacter quotesingle 39 % fake 'm TODO:enco-def!!!!
+\definecharacter quoteright 39
+% parenleft ( 40
+% parenright ) 41
+% asterisk * 42
+% plus + 43
+% comma , 44
+\definecharacter softhyphen 45
+% period . 46
+% slash / 47
+% 0-9 48-57
+% colon : 58
+% semicolon ; 59
+% less < 60
+% equal = 61
+% greater > 62
+% question ? 63
+% at @ 64
+% A-Z 65-90
+% bracketleft [ 91
+\definecharacter textbackslash 92
+% bracketright ] 93
+\definecharacter textasciicircum 94
+\definecharacter textunderscore 95
+\definecharacter quoteleft 96
+% a-z 97-122
+\definecharacter textbraceleft 123
+\definecharacter textbraceright 125
+\definecharacter textasciitilde 126
+%definecharacter softhyphen 127 % -> 45 (127 often undefined)
+\definecharacter Abreve 128 % abreve 160
+\definecharacter Aogonek 129 % aogonek 161
+\definecharacter Cacute 130 % cacute 162
+\definecharacter Ccaron 131 % ccaron 163
+\definecharacter Dcaron 132 % dcaron 164
+\definecharacter Ecaron 133 % ecaron 165
+\definecharacter Eogonek 134 % eogonek 166
+\definecharacter Gbreve 135 % gbreve 167
+\definecharacter Lacute 136 % lacute 168
+\definecharacter Lcaron 137 % lcaron 169
+\definecharacter Lstroke 138 % lstroke 170
+\definecharacter Nacute 139 % nacute 171
+\definecharacter Ncaron 140 % ncaron 172
+\definecharacter Eng 141 % eng 173
+\definecharacter Neng 141 % Neng 173
+\definecharacter Ohungarumlaut 142 % ohungarumlaut 174
+\definecharacter Racute 143 % racute 175
+\definecharacter Rcaron 144 % rcaron 176
+\definecharacter Sacute 145 % sacute 177
+\definecharacter Scaron 146 % scaron 178
+\definecharacter Scedilla 147 % scedilla 179
+\definecharacter Tcaron 148 % tcaron 180
+\definecharacter Tcedilla 149 % tcedilla 181
+\definecharacter Uhungarumlaut 150 % uhungarumlaut 182
+\definecharacter Uring 151 % uring 183
+\definecharacter Ydiaeresis 152 % ydiaeresis 184
+\definecharacter Zacute 153 % zacute 185
+\definecharacter Zcaron 154 % zcaron 186
+\definecharacter Zdotaccent 155 % zdotaccent 187
+\definecharacter IJligature 156 % ijligature 188
+\definecharacter Idotaccent 157
+\definecharacter dstroke 158 % Dstroke 208
+\definecharacter sectionmark 159
+\definecharacter abreve 160 % Abreve 128
+\definecharacter aogonek 161 % Aogonek 129
+\definecharacter cacute 162 % Cacute 130
+\definecharacter ccaron 163 % Ccaron 131
+\definecharacter dcaron 164 % Dcaron 132
+\definecharacter ecaron 165 % Ecaron 133
+\definecharacter eogonek 166 % Eogonek 134
+\definecharacter gbreve 167 % Gbreve 135
+\definecharacter lacute 168 % Lacute 136
+\definecharacter lcaron 169 % Lcaron 137
+\definecharacter lstroke 170 % Lstroke 138
+\definecharacter nacute 171 % Nacute 139
+\definecharacter ncaron 172 % Ncaron 140
+\definecharacter eng 173 % Eng 141
+\definecharacter ohungarumlaut 174 % Ohungarumlaut 142
+\definecharacter racute 175 % Racute 143
+\definecharacter rcaron 176 % Rcaron 144
+\definecharacter sacute 177 % Sacute 145
+\definecharacter scaron 178 % Scaron 146
+\definecharacter scedilla 179 % Scedilla 147
+\definecharacter tcaron 180 % Tcaron 148
+\definecharacter tcedilla 181 % Tcedilla 149
+\definecharacter uhungarumlaut 182 % Uhungarumlaut 150
+\definecharacter uring 183 % Uring 151
+\definecharacter ydiaeresis 184 % Ydiaeresis 152
+\definecharacter zacute 185 % Zacute 153
+\definecharacter zcaron 186 % Zcaron 154
+\definecharacter zdotaccent 187 % Zdotaccent 155
+\definecharacter ijligature 188 % IJligature 156
+\definecharacter exclamdown 189
+\definecharacter questiondown 190
+\definecharacter textsterling 191
+\definecharacter Agrave 192 % agrave 224
+\definecharacter Aacute 193 % aacute 225
+\definecharacter Acircumflex 194 % acircumflex 226
+\definecharacter Atilde 195 % atilde 227
+\definecharacter Adiaeresis 196 % adiaeresis 228
+\definecharacter Aring 197 % aring 229
+\definecharacter AEligature 198 % aeligature 230
+\definecharacter Ccedilla 199 % ccedilla 231
+\definecharacter Egrave 200 % egrave 232
+\definecharacter Eacute 201 % eacute 233
+\definecharacter Ecircumflex 202 % ecircumflex 234
+\definecharacter Ediaeresis 203 % ediaeresis 235
+\definecharacter Igrave 204 % igrave 236
+\definecharacter Iacute 205 % iacute 237
+\definecharacter Icircumflex 206 % icircumflex 238
+\definecharacter Idiaeresis 207 % idiaeresis 239
+\definecharacter Eth 208 % eth 240
+\definecharacter Dstroke 208 % dstroke 158
+\definecharacter Ntilde 209 % ntilde 241
+\definecharacter Ograve 210 % ograve 242
+\definecharacter Oacute 211 % oacute 243
+\definecharacter Ocircumflex 212 % ocircumflex 244
+\definecharacter Otilde 213 % otilde 245
+\definecharacter Odiaeresis 214 % odiaeresis 246
+\definecharacter OEligature 215 % oeligature 247
+\definecharacter Ostroke 216 % ostroke 248
+\definecharacter Ugrave 217 % ugrave 249
+\definecharacter Uacute 218 % uacute 250
+\definecharacter Ucircumflex 219 % ucircumflex 251
+\definecharacter Udiaeresis 220 % udiaeresis 252
+\definecharacter Yacute 221 % yacute 253
+\definecharacter Thorn 222 % thorn 254
+\definecharacter Ssharp 223 % ssharp 255
+\definecharacter agrave 224 % Agrave 192
+\definecharacter aacute 225 % Aacute 193
+\definecharacter acircumflex 226 % Acircumflex 194
+\definecharacter atilde 227 % Atilde 195
+\definecharacter adiaeresis 228 % Adiaeresis 196
+\definecharacter aring 229 % Aring 197
+\definecharacter aeligature 230 % AEligature 198
+\definecharacter ccedilla 231 % Ccedilla 199
+\definecharacter egrave 232 % Egrave 200
+\definecharacter eacute 233 % Eacute 201
+\definecharacter ecircumflex 234 % Ecircumflex 202
+\definecharacter ediaeresis 235 % Ediaeresis 203
+\definecharacter igrave 236 % Igrave 204
+\definecharacter iacute 237 % Iacute 205
+\definecharacter icircumflex 238 % Icircumflex 206
+\definecharacter idiaeresis 239 % Idiaeresis 207
+\definecharacter eth 240 % Eth 208
+\definecharacter ntilde 241 % Ntilde 209
+\definecharacter ograve 242 % Ograve 210
+\definecharacter oacute 243 % Oacute 211
+\definecharacter ocircumflex 244 % Ocircumflex 212
+\definecharacter otilde 245 % Otilde 213
+\definecharacter odiaeresis 246 % Odiaeresis 214
+\definecharacter oeligature 247 % OEligature 215
+\definecharacter ostroke 248 % Ostroke 216
+\definecharacter ugrave 249 % Ugrave 217
+\definecharacter uacute 250 % Uacute 218
+\definecharacter ucircumflex 251 % Ucircumflex 219
+\definecharacter udiaeresis 252 % Udiaeresis 220
+\definecharacter yacute 253 % Yacute 221
+\definecharacter thorn 254 % Thorn 222
+\definecharacter ssharp 255 % Ssharp 223
+
+\stopencoding
+
+\startencoding[ec]
+
+\definecharacter Scommaaccent {\Scedilla}
+\definecharacter scommaaccent {\scedilla}
+\definecharacter Tcommaaccent {\Tcedilla}
+\definecharacter tcommaaccent {\tcedilla}
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-ecm.mkii b/tex/context/base/enco-ecm.mkii
new file mode 100644
index 000000000..b74473960
--- /dev/null
+++ b/tex/context/base/enco-ecm.mkii
@@ -0,0 +1,33 @@
+%D \module
+%D [ file=enco-ec,
+%D version=2000.05.07,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Glyphs that may not be present in EC,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D The next typescript removes a few problematic characters
+%D from the ec encoding vector. So, in case of troubles, say
+%D
+%D \starttyping
+%D \useencoding[ecm] % ec minus
+%D \stoptyping
+
+\startencoding[ec][ec]
+
+\definecharacter ijligature {ij}
+\definecharacter IJligature {IJ}
+\definecharacter Ssharp {SS}
+\definecharacter tcaron {\buildtextaccent\textcaron t}
+\definecharacter Tcedilla {\buildtextcedilla T}
+\definecharacter tcedilla {\buildtextcedilla t}
+\definecharacter ydiaeresis {\buildtextaccent\textdiaeresis y}
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-el.mkii b/tex/context/base/enco-el.mkii
new file mode 100644
index 000000000..24729967b
--- /dev/null
+++ b/tex/context/base/enco-el.mkii
@@ -0,0 +1,272 @@
+%D \module
+%D [ file=enco-el,
+%D version=2005.08.24,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=EuroLetter,
+%D author={Several Users},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This EuroLetter encoding vector, also known as Dense Encoding is
+%D the result of discussion among users, most noticably Adam Lindsay,
+%D Mojka Miklavec, Patrick Gundlach, Taco Hoekwater and \unknown.
+%D It was a follow up of a thread started long ago where we
+%D discussed an encoding without the weird, never used symbols, but
+%D with as many characters as possible in order to support the utf-8
+%D input regime.
+
+\startencoding[el]
+
+\definecasemaps 1 to 15 lc +16 uc 0
+\definecasemaps 17 to 31 lc 0 uc -16
+
+\definecasemaps 128 to 159 lc +32 uc 0
+\definecasemaps 160 to 191 lc 0 uc -32
+
+\definecasemaps 192 to 223 lc +32 uc 0
+\definecasemaps 224 to 255 lc 0 uc -32
+
+\definecasemap 92 92 124
+\definecasemap 92 124 92
+
+\definecharacter dotlessi 160
+\definecharacter endash 32
+\definecharacter emdash 16
+
+\definecharacter aeligature 230
+\definecharacter AEligature 198
+\definecharacter oeligature 247
+\definecharacter OEligature 215
+
+\definecharacter ssharp 38
+
+\definecharacter thorn 254
+\definecharacter Thorn 222
+
+\definecharacter eth 240
+\definecharacter Eth 208
+
+\definecharacter exclamdown 42
+\definecharacter questiondown 43
+
+\definecharacter quotedbl 35
+\definecharacter quotedblbase 36
+\definecharacter quotedblleft 34
+\definecharacter quotedblright 35
+
+\definecharacter quotesingle 39
+\definecharacter quotesinglebase 0
+
+\definecharacter quoteleft 96
+\definecharacter quoteright 39
+
+\definecharacter guilsingleleft 60
+\definecharacter guilsingleright 62
+
+\definecharacter leftguillemot 123
+\definecharacter rightguillemot 125
+
+\definecharacter Acircumflex 194
+\definecharacter acircumflex 226
+%definecharacter Ccircumflex {\buildtextaccent\textcircumflex C}
+%definecharacter ccircumflex {\buildtextaccent\textcircumflex c}
+\definecharacter Ecircumflex 202
+\definecharacter ecircumflex 234
+%definecharacter Gcircumflex {\buildtextaccent\textcircumflex G}
+%definecharacter gcircumflex {\buildtextaccent\textcircumflex g}
+%definecharacter Hcircumflex {\buildtextaccent\textcircumflex H}
+%definecharacter hcircumflex {\buildtextaccent\textcircumflex h}
+\definecharacter Icircumflex 206
+\definecharacter icircumflex 238
+%definecharacter Jcircumflex {\buildtextaccent\textcircumflex \dotlessJ}
+%definecharacter jcircumflex {\buildtextaccent\textcircumflex \dotlessj}
+\definecharacter Ocircumflex 212
+\definecharacter ocircumflex 244
+%definecharacter Scircumflex {\buildtextaccent\textcircumflex S}
+%definecharacter scircumflex {\buildtextaccent\textcircumflex s}
+\definecharacter Ucircumflex 219
+\definecharacter ucircumflex 251
+\definecharacter Wcircumflex 154
+\definecharacter wcircumflex 186
+\definecharacter Ycircumflex 156
+\definecharacter ycircumflex 188
+
+\definecharacter Agrave 192
+\definecharacter agrave 224
+\definecharacter Egrave 200
+\definecharacter egrave 232
+\definecharacter Igrave 204
+\definecharacter igrave 236
+\definecharacter Ograve 210
+\definecharacter ograve 242
+\definecharacter Ugrave 217
+\definecharacter ugrave 249
+\definecharacter Ygrave 155
+\definecharacter ygrave 187
+
+\definecharacter Atilde 195
+\definecharacter atilde 227
+%definecharacter Itilde {\buildtextaccent\texttilde \dotlessI}
+%definecharacter itilde {\buildtextaccent\texttilde \dotlessi}
+\definecharacter Ntilde 209
+\definecharacter ntilde 241
+\definecharacter Otilde 213
+\definecharacter otilde 245
+%definecharacter Utilde {\buildtextaccent\texttilde U}
+%definecharacter utilde {\buildtextaccent\texttilde u}
+%definecharacter Ytilde {\buildtextaccent\texttilde Y}
+%definecharacter ytilde {\buildtextaccent\texttilde y}
+
+\definecharacter Adiaeresis 196
+\definecharacter adiaeresis 228
+\definecharacter Ediaeresis 203
+\definecharacter ediaeresis 235
+\definecharacter Idiaeresis 207
+\definecharacter idiaeresis 239
+\definecharacter Odiaeresis 214
+\definecharacter odiaeresis 246
+\definecharacter Udiaeresis 220
+\definecharacter udiaeresis 252
+\definecharacter Ydiaeresis 223
+\definecharacter ydiaeresis 255
+
+\definecharacter Aacute 193
+\definecharacter aacute 225
+\definecharacter Cacute 4
+\definecharacter cacute 20
+\definecharacter Eacute 201
+\definecharacter eacute 233
+\definecharacter Iacute 205
+\definecharacter iacute 237
+\definecharacter Lacute 132
+\definecharacter lacute 164
+\definecharacter Nacute 136
+\definecharacter nacute 168
+\definecharacter Oacute 211
+\definecharacter oacute 243
+\definecharacter Racute 141
+\definecharacter racute 173
+\definecharacter Sacute 144
+\definecharacter sacute 176
+\definecharacter Uacute 218
+\definecharacter uacute 250
+\definecharacter Yacute 221
+\definecharacter yacute 253
+\definecharacter Zacute 157
+\definecharacter zacute 189
+
+\definecharacter Dstroke 8
+\definecharacter dstroke 24
+\definecharacter Hstroke 92
+\definecharacter hstroke 124
+%definecharacter Tstroke {T}
+%definecharacter tstroke {t}
+
+\definecharacter Cdotaccent 6
+\definecharacter cdotaccent 22
+\definecharacter Edotaccent 10
+\definecharacter edotaccent 26
+\definecharacter Gdotaccent 15
+\definecharacter gdotaccent 31
+\definecharacter Idotaccent 128
+%definecharacter idotaccent {\buildtextaccent\textdotaccent \dotlessi}
+\definecharacter Zdotaccent 159
+\definecharacter zdotaccent 191
+
+\definecharacter Amacron 2
+\definecharacter amacron 18
+\definecharacter Emacron 11
+\definecharacter emacron 27
+\definecharacter Imacron 129
+\definecharacter imacron 161
+\definecharacter Omacron 140
+\definecharacter omacron 172
+\definecharacter Umacron 152
+\definecharacter umacron 184
+
+\definecharacter Ccedilla 199
+\definecharacter ccedilla 231
+\definecharacter Scedilla 146
+\definecharacter scedilla 178
+
+\definecharacter Gcommaaccent 14
+\definecharacter gcommaaccent 30
+\definecharacter Kcommaaccent 131
+\definecharacter kcommaaccent 163
+\definecharacter Lcommaaccent 135
+\definecharacter lcommaaccent 167
+\definecharacter Ncommaaccent 138
+\definecharacter ncommaaccent 170
+\definecharacter Rcommaaccent 143
+\definecharacter rcommaaccent 175
+%definecharacter Tcedilla 149 % there is no tcedilla in encoding
+%definecharacter tcedilla 181
+
+\definecharacter Scommaaccent 147
+\definecharacter scommaaccent 179
+\definecharacter Tcommaaccent 149
+\definecharacter tcommaaccent 181
+
+\definecharacter Ohungarumlaut 139
+\definecharacter ohungarumlaut 171
+\definecharacter Uhungarumlaut 150
+\definecharacter uhungarumlaut 182
+
+\definecharacter Aogonek 3
+\definecharacter aogonek 19
+\definecharacter Eogonek 12
+\definecharacter eogonek 28
+\definecharacter Iogonek 130
+\definecharacter iogonek 162
+\definecharacter Uogonek 153
+\definecharacter uogonek 185
+
+\definecharacter Aring 197
+\definecharacter aring 229
+\definecharacter Uring 151
+\definecharacter uring 183
+
+\definecharacter Abreve 1
+\definecharacter abreve 17
+%definecharacter Ebreve {\buildtextaccent\textbreve E}
+%definecharacter ebreve {\buildtextaccent\textbreve e}
+\definecharacter Gbreve 13
+\definecharacter gbreve 29
+%definecharacter Ibreve {\buildtextaccent\textbreve \dotlessI}
+%definecharacter ibreve {\buildtextaccent\textbreve \dotlessi}
+%definecharacter Obreve {\buildtextaccent\textbreve O}
+%definecharacter obreve {\buildtextaccent\textbreve o}
+%definecharacter Ubreve {\buildtextaccent\textbreve U}
+%definecharacter ubreve {\buildtextaccent\textbreve u}
+
+\definecharacter Ccaron 5
+\definecharacter ccaron 21
+\definecharacter Dcaron 7
+\definecharacter dcaron 23
+\definecharacter Ecaron 9
+\definecharacter ecaron 25
+\definecharacter Lcaron 133
+\definecharacter lcaron 165
+\definecharacter Ncaron 137
+\definecharacter ncaron 169
+\definecharacter Rcaron 142
+\definecharacter rcaron 174
+\definecharacter Scaron 145
+\definecharacter scaron 177
+\definecharacter Tcaron 148
+\definecharacter tcaron 180
+%definecharacter Ycaron {\buildtextaccent\textcaron Y}
+%definecharacter ycaron {\buildtextaccent\textcaron y}
+\definecharacter Zcaron 158
+\definecharacter zcaron 190
+
+\definecharacter Lstroke 134
+\definecharacter lstroke 166
+\definecharacter Ostroke 216
+\definecharacter ostroke 248
+
+\stopencoding
diff --git a/tex/context/base/enco-fde.mkii b/tex/context/base/enco-fde.mkii
new file mode 100644
index 000000000..a7c11abfc
--- /dev/null
+++ b/tex/context/base/enco-fde.mkii
@@ -0,0 +1,128 @@
+%D \module
+%D [ file=enco-fde,
+%D version=2000.08.20,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=German Input Filter,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\doifmode{mkiv}{\endinput}
+
+\unprotect
+
+\installactivecharacter "
+
+\startlanguagespecifics[\s!de]
+
+ \installcompoundcharacter "a {\aumlaut\midworddiscretionary}
+ \installcompoundcharacter "e {\eumlaut\midworddiscretionary}
+ \installcompoundcharacter "i {\iumlaut\midworddiscretionary}
+ \installcompoundcharacter "o {\oumlaut\midworddiscretionary}
+ \installcompoundcharacter "u {\uumlaut\midworddiscretionary}
+ \installcompoundcharacter "s {\ssharp}
+ \installcompoundcharacter "z {\ssharp}
+
+ \installcompoundcharacter "A {\Aumlaut}
+ \installcompoundcharacter "E {\Eumlaut}
+ \installcompoundcharacter "I {\Iumlaut}
+ \installcompoundcharacter "O {\Oumlaut}
+ \installcompoundcharacter "U {\Uumlaut}
+ \installcompoundcharacter "Z {SZ}
+ \installcompoundcharacter "S {SS}
+
+\stoplanguagespecifics
+
+\startlanguagespecifics[\s!de]
+
+ \installcompoundcharacter "ck {\discretionary {k-}{k}{ck}}
+ \installcompoundcharacter "ff {\discretionary{ff-}{f}{ff}}
+ \installcompoundcharacter "ll {\discretionary{ll-}{l}{ll}}
+ \installcompoundcharacter "mm {\discretionary{mm-}{m}{mm}}
+ \installcompoundcharacter "nn {\discretionary{nn-}{n}{nn}}
+ \installcompoundcharacter "pp {\discretionary{pp-}{p}{pp}}
+ \installcompoundcharacter "rr {\discretionary{rr-}{r}{rr}}
+ \installcompoundcharacter "tt {\discretionary{tt-}{t}{tt}}
+
+ \installcompoundcharacter "CK {\discretionary {K-}{K}{CK}}
+ \installcompoundcharacter "FF {\discretionary{FF-}{F}{FF}}
+ \installcompoundcharacter "LL {\discretionary{LL-}{L}{LL}}
+ \installcompoundcharacter "MM {\discretionary{MM-}{M}{MM}}
+ \installcompoundcharacter "NN {\discretionary{NN-}{N}{NN}}
+ \installcompoundcharacter "PP {\discretionary{PP-}{P}{PP}}
+ \installcompoundcharacter "RR {\discretionary{RR-}{R}{RR}}
+ \installcompoundcharacter "TT {\discretionary{TT-}{T}{TT}}
+
+\stoplanguagespecifics
+
+\startlanguagespecifics[\s!de]
+
+ \installcompoundcharacter "` {\startdelimitedtext[\v!quotation]}
+ \installcompoundcharacter "' {\stopdelimitedtext}
+ \installcompoundcharacter ". {\kern.1em\ignorespaces}
+
+ %installcompoundcharacter "` {\languageparameter\c!leftquotation }
+ %installcompoundcharacter "' {\languageparameter\c!rightquotation}
+
+ \def\setupDElanguage
+ {\setuplanguage
+ [\s!de]
+ [\c!leftsentence=\leftguillemot,
+ \c!rightsentence=\rightguillemot,
+ \c!leftsubsentence=\leftsubguillemot,
+ \c!rightsubsentence=\rightsubguillemot]}
+
+ \installcompoundcharacter "< {{\setupDElanguage|<|}}
+ \installcompoundcharacter "> {{\setupDElanguage|>|}}
+ \installcompoundcharacter "| {|*|}
+
+\stoplanguagespecifics
+
+% \hyphenatedword{hinauff|*|liegen}
+% \hyphenatedword{hinauff"|liegen}
+
+%D An experimental hack:
+
+% no {\simplifiedcompoundcharacter"}
+
+% \startencoding[pdfdoc]
+% \startlanguagespecifics[\s!de]% hm, a % is needed
+% \defineactivecharacter " {\"}
+% \stoplanguagespecifics
+% \stopencoding
+
+\startencoding[ec]
+ \startlanguagespecifics[\s!de]%
+ \installcompoundcharacter "a {\adiaeresis}
+ \installcompoundcharacter "e {\ediaeresis}
+ \installcompoundcharacter "i {\idiaeresis}
+ \installcompoundcharacter "o {\odiaeresis}
+ \installcompoundcharacter "u {\udiaeresis}
+ \installcompoundcharacter "A {\Adiaeresis}
+ \installcompoundcharacter "E {\Ediaeresis}
+ \installcompoundcharacter "I {\Idiaeresis}
+ \installcompoundcharacter "O {\Odiaeresis}
+ \installcompoundcharacter "U {\Udiaeresis}
+ \stoplanguagespecifics
+\stopencoding
+
+\startencoding[texnansi]
+ \startlanguagespecifics[\s!de]%
+ \installcompoundcharacter "a {\adiaeresis}
+ \installcompoundcharacter "e {\ediaeresis}
+ \installcompoundcharacter "i {\idiaeresis}
+ \installcompoundcharacter "o {\odiaeresis}
+ \installcompoundcharacter "u {\udiaeresis}
+ \installcompoundcharacter "A {\Adiaeresis}
+ \installcompoundcharacter "E {\Ediaeresis}
+ \installcompoundcharacter "I {\Idiaeresis}
+ \installcompoundcharacter "O {\Odiaeresis}
+ \installcompoundcharacter "U {\Udiaeresis}
+ \stoplanguagespecifics
+\stopencoding
+
+\protect \endinput
diff --git a/tex/context/base/enco-ffr.mkii b/tex/context/base/enco-ffr.mkii
new file mode 100644
index 000000000..093cc6500
--- /dev/null
+++ b/tex/context/base/enco-ffr.mkii
@@ -0,0 +1,57 @@
+%D \module
+%D [ file=enco-ffr,
+%D version=2002.05.07,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=French Input Filter,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\doifmode{mkiv}{\endinput}
+
+% \definehspace[fr][:][.25em]
+% \definehspace[fr][;][.25em]
+% \definehspace[fr][!][.25em]
+% \definehspace[fr][?][.25em]
+
+\enablemode[activecolon] \usemodule[tryout] % for the moment
+
+\installactivecharacter :
+\installactivecharacter ;
+\installactivecharacter ?
+\installactivecharacter !
+
+\unprotect
+
+\startlanguagespecifics[\s!fr]
+ \definetextmodediscretionary : {\removeunwantedspaces\prewordbreak\kern\hspaceamount\currentmainlanguage{:}:}
+ \definetextmodediscretionary ; {\removeunwantedspaces\prewordbreak\kern\hspaceamount\currentmainlanguage{;};}
+ \definetextmodediscretionary ? {\removeunwantedspaces\prewordbreak\kern\hspaceamount\currentmainlanguage{?}?}
+ \definetextmodediscretionary ! {\removeunwantedspaces\prewordbreak\kern\hspaceamount\currentmainlanguage{!}!}
+\stoplanguagespecifics
+
+\startlanguagespecifics[\s!fr]
+ \defineactivecharacter : {\mathortext{:}{\directdiscretionary{:}}}
+ \defineactivecharacter ; {\mathortext{;}{\directdiscretionary{;}}}
+ \defineactivecharacter ! {\mathortext{!}{\directdiscretionary{!}}}
+ \defineactivecharacter ? {\mathortext{?}{\directdiscretionary{?}}}
+\stoplanguagespecifics
+
+\appendtoks % maybe everywhere
+ \chardef\activecharactermode\zerocount
+\to\everyMPgraphic
+
+% maybe tricky due to possible name clashes:
+%
+% \def\ieme {\highordinalstr{e}}
+% \def\iemes{\highordinalstr{es}}
+% \def\ier {\highordinalstr{er}}
+% \def\iers {\highordinalstr{ers}}
+% \def\iere {\highordinalstr{re}}
+% \def\ieres{\highordinalstr{res}}
+
+\protect \endinput
diff --git a/tex/context/base/enco-fpl.mkii b/tex/context/base/enco-fpl.mkii
new file mode 100644
index 000000000..14d102ff1
--- /dev/null
+++ b/tex/context/base/enco-fpl.mkii
@@ -0,0 +1,98 @@
+%D \module
+%D [ file=enco-fpl,
+%D version=2000.08.20,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Polish Input Filter,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D These definitions used to be part of lang-sla.tex.
+
+\unprotect
+
+% todo : named glyphs
+
+\installactivecharacter /
+
+\startlanguagespecifics[\s!pl]
+
+% \appendtoks \makecharacteractive / \to \everynormalcatcodes % obsolete
+
+ \installcompoundcharacter /a {\aogonek}
+ \installcompoundcharacter /c {\cacute}
+ \installcompoundcharacter /e {\eogonek}
+ \installcompoundcharacter /l {\lstroke}
+ \installcompoundcharacter /n {\nacute}
+ \installcompoundcharacter /o {\oacute}
+ \installcompoundcharacter /s {\sacute}
+ \installcompoundcharacter /x {\zacute}
+ \installcompoundcharacter /z {\zdotaccent}
+ \installcompoundcharacter /A {\Aogonek}
+ \installcompoundcharacter /C {\Cacute}
+ \installcompoundcharacter /E {\Eogonek}
+ \installcompoundcharacter /L {\Lstroke}
+ \installcompoundcharacter /N {\Nacute}
+ \installcompoundcharacter /O {\Oacute}
+ \installcompoundcharacter /S {\Sacute}
+ \installcompoundcharacter /X {\Zacute}
+ \installcompoundcharacter /Z {\Zdotaccent}
+
+\stoplanguagespecifics
+
+\startlanguagespecifics[\s!pl]
+
+ \installcompoundcharacter /, {\handlequotation\c!leftquotation}
+ \installcompoundcharacter /' {\handlequotation\c!rightquotation}
+
+ \def\setupPLlanguage%
+ {\setuplanguage
+ [\s!pl]
+ [\c!leftsentence=\leftguillemot,
+ \c!rightsentence=\rightguillemot,
+ \c!leftsubsentence=\leftsubguillemot,
+ \c!rightsubsentence=\rightsubguillemot]}
+
+ \installcompoundcharacter /< {{\setupPLlanguage|<|}}
+ \installcompoundcharacter /> {{\setupPLlanguage|>|}}
+
+ \installcompoundcharacter /- {|-|}
+
+\stoplanguagespecifics
+
+% obsolete
+%
+% \startlanguagespecifics[\s!pl]
+%
+% \definesortkey {/a}{a}{a}{\k a}
+% \definesortkey {/A}{a}{a}{\k a}
+% \definesortkey {/c}{c}{a}{\'c}
+% \definesortkey {/C}{c}{a}{\'c}
+% \definesortkey {/e}{e}{a}{\k e}
+% \definesortkey {/E}{e}{a}{\k e}
+% \definesortkey {/l}{l}{a}{\l }
+% \definesortkey {/L}{l}{a}{\l }
+% \definesortkey {/n}{n}{a}{\'n}
+% \definesortkey {/N}{n}{a}{\'n}
+% \definesortkey {/o}{o}{a}{\'o}
+% \definesortkey {/O}{o}{a}{\'o}
+% \definesortkey {/s}{s}{a}{\'s}
+% \definesortkey {/S}{s}{a}{\'s}
+% \definesortkey {/x}{z}{a}{\'x}
+% \definesortkey {/X}{z}{a}{\'x}
+% \definesortkey {/z}{z}{b}{\.z}
+% \definesortkey {/Z}{z}{b}{\.z}
+%
+% \stoplanguagespecifics
+
+\startencoding[pdfdoc]
+ \startlanguagespecifics[pl]% hm
+ \defineactivecharacter / {\simplifiedcompoundcharacter/}
+ \stoplanguagespecifics
+\stopencoding
+
+\protect \endinput
diff --git a/tex/context/base/enco-fro.mkii b/tex/context/base/enco-fro.mkii
new file mode 100644
index 000000000..e5f5e1257
--- /dev/null
+++ b/tex/context/base/enco-fro.mkii
@@ -0,0 +1,35 @@
+%D \module
+%D [ file=enco-fro,
+%D version=2000.08.20,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Romanian Input Filter,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D These definitions used to be part of lang-ita.tex.
+
+\unprotect
+
+\installactivecharacter "
+
+\startlanguagespecifics[\s!ro]
+
+ \installcompoundcharacter "a {\acircumflex}
+ \installcompoundcharacter "i {\icircumflex}
+ \installcompoundcharacter "s {\scedilla}
+ \installcompoundcharacter "t {\tcedilla}
+ \installcompoundcharacter "A {\Acircumflex}
+ \installcompoundcharacter "I {\Icircumflex}
+ \installcompoundcharacter "S {\Scedilla}
+ \installcompoundcharacter "T {\Tcedilla}
+ \installcompoundcharacter "` {\startdelimitedtext[\v!quotation]}
+ \installcompoundcharacter "' {\stopdelimitedtext}
+
+\stoplanguagespecifics
+
+\protect \endinput
diff --git a/tex/context/base/enco-fsl.mkii b/tex/context/base/enco-fsl.mkii
new file mode 100644
index 000000000..86a41c88a
--- /dev/null
+++ b/tex/context/base/enco-fsl.mkii
@@ -0,0 +1,32 @@
+%D \module
+%D [ file=enco-fsl,
+%D version=2005.08.17,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Slovenian Specialities,
+%D author={Hans Hagen, Mojka Miklavec},
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Usage:
+%D
+%D \starttyping
+%D \useencoding[fsl]
+%D
+%D \starttext
+%D \dstroke \language[sl] \dstroke
+%D \stoptext
+%D \stoptyping
+
+\unprotect
+
+\startlanguagespecifics[\s!sl]
+ \startencoding[\s!default]
+ \definecharacter dstroke {d\zcaron} % hm, expects a space delimiter
+ \stopencoding
+\stoplanguagespecifics
+
+\protect \endinput
diff --git a/tex/context/base/enco-grk.mkii b/tex/context/base/enco-grk.mkii
new file mode 100644
index 000000000..882a3c9b0
--- /dev/null
+++ b/tex/context/base/enco-grk.mkii
@@ -0,0 +1,190 @@
+%D \module
+%D [ file=enco-grk,
+%D version=2003.03.01,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Greek,
+%D author=Apostolos Syropoulos,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\startmapping[iso-8859-7]
+
+% Uppercase Greek letters
+
+\definecasemap 193 193 225 % greekAlpha
+\definecasemap 194 194 226 % greekBeta
+\definecasemap 195 195 227 % greekGamma
+\definecasemap 196 196 228 % greekDelta
+\definecasemap 197 197 229 % greekEpsilon
+\definecasemap 198 198 230 % greekZeta
+\definecasemap 199 199 213 % greekEta
+\definecasemap 200 200 232 % greekTheta
+\definecasemap 201 201 233 % greekIota
+\definecasemap 202 202 234 % greekKappa
+\definecasemap 203 203 235 % greekLambda
+\definecasemap 204 204 236 % greekMu
+\definecasemap 205 205 237 % greekNu
+\definecasemap 206 206 238 % greekXi
+\definecasemap 207 207 239 % greekOmicron
+\definecasemap 208 208 240 % greekPi
+\definecasemap 209 209 241 % greekRho
+\definecasemap 211 211 243 % greekSigma
+\definecasemap 212 212 244 % greekTau
+\definecasemap 213 213 245 % greekUpsilon
+\definecasemap 214 214 246 % greekPhi
+\definecasemap 215 215 247 % greekChi
+\definecasemap 216 216 248 % greekPsi
+\definecasemap 217 217 249 % greekOmega
+
+% Lowercase Greek letters
+
+\definecasemap 225 193 225 % greekalpha
+\definecasemap 226 194 226 % greekbeta
+\definecasemap 227 195 227 % greekgamma
+\definecasemap 228 196 228 % greekdelta
+\definecasemap 229 197 229 % greekepsilon
+\definecasemap 230 198 230 % greekzeta
+\definecasemap 213 199 213 % greeketa
+\definecasemap 232 200 232 % greektheta
+\definecasemap 233 201 233 % greekiota
+\definecasemap 234 202 234 % greekkappa
+\definecasemap 235 203 235 % greeklambda
+\definecasemap 236 204 236 % greekmu
+\definecasemap 237 205 237 % greeknu
+\definecasemap 238 206 238 % greekxi
+\definecasemap 239 207 239 % greekomicron
+\definecasemap 240 208 240 % greekpi
+\definecasemap 241 209 241 % greekrho
+\definecasemap 242 211 242 % greekfinalsigma
+\definecasemap 243 211 243 % greekSigma
+\definecasemap 244 212 244 % greekTau
+\definecasemap 245 213 245 % greekUpsilon
+\definecasemap 246 214 246 % greekPhi
+\definecasemap 247 215 247 % greekChi
+\definecasemap 248 216 248 % greekPsi
+\definecasemap 249 217 249 % greekOmega
+
+% Accented Uppercase Greek letters
+
+\definecasemap 182 193 220 % greekAlphatonos
+\definecasemap 184 197 221 % greekEpsilontonos
+\definecasemap 185 199 222 % greekEtatonos
+\definecasemap 186 201 223 % greekIotatonos
+\definecasemap 188 207 252 % greekOmicrontonos
+\definecasemap 190 213 253 % greekUpsilontonos
+\definecasemap 191 217 254 % greekOmegatonos
+\definecasemap 218 218 250 % greekIotadialytika
+\definecasemap 219 219 251 % greekUpsilondialytika
+
+% Accented Lowercase Greek letters
+
+\definecasemap 220 193 220 % greekalphatonos
+\definecasemap 221 197 221 % greekepsilontonos
+\definecasemap 222 199 222 % greeketatonos
+\definecasemap 223 201 223 % greekiotatonos
+\definecasemap 252 207 252 % greekomicrontonos
+\definecasemap 253 213 253 % greekupsilontonos
+\definecasemap 254 217 254 % greekomegatonos
+\definecasemap 250 218 250 % greekiotadialytika
+\definecasemap 251 219 251 % greekupsilondialytika
+\definecasemap 192 218 192 % greekiotadialytikatonos
+\definecasemap 224 219 224 % greekupsilondialytikatonos
+
+\stopmapping
+
+\startencoding[iso-8859-7]
+
+% Uppercase Greek letters
+
+\definecharacter greekAlpha 193
+\definecharacter greekBeta 194
+\definecharacter greekGamma 195
+\definecharacter greekDelta 196
+\definecharacter greekEpsilon 197
+\definecharacter greekZeta 198
+\definecharacter greekEta 199
+\definecharacter greekTheta 200
+\definecharacter greekIota 201
+\definecharacter greekKappa 202
+\definecharacter greekLambda 203
+\definecharacter greekMu 204
+\definecharacter greekNu 205
+\definecharacter greekXi 206
+\definecharacter greekOmicron 207
+\definecharacter greekPi 208
+\definecharacter greekRho 209
+\definecharacter greekSigma 211
+\definecharacter greekTau 212
+\definecharacter greekUpsilon 213
+\definecharacter greekPhi 214
+\definecharacter greekChi 215
+\definecharacter greekPsi 216
+\definecharacter greekOmega 217
+
+% Lowercase Greek letters
+
+\definecharacter greekalpha 225
+\definecharacter greekbeta 226
+\definecharacter greekgamma 227
+\definecharacter greekdelta 228
+\definecharacter greekepsilon 229
+\definecharacter greekzeta 230
+\definecharacter greeketa 231
+\definecharacter greektheta 232
+\definecharacter greekiota 233
+\definecharacter greekkappa 234
+\definecharacter greeklambda 235
+\definecharacter greekmu 236
+\definecharacter greeknu 237
+\definecharacter greekxi 238
+\definecharacter greekomicron 239
+\definecharacter greekpi 240
+\definecharacter greekrho 241
+\definecharacter greekfinalsigma 242
+\definecharacter greeksigma 243
+\definecharacter greektau 244
+\definecharacter greekupsilon 245
+\definecharacter greekphi 246
+\definecharacter greekchi 247
+\definecharacter greekpsi 248
+\definecharacter greekomega 249
+
+% Accented Uppercase Greek letters
+
+\definecharacter greekAlphatonos 182
+\definecharacter greekEpsilontonos 184
+\definecharacter greekEtatonos 185
+\definecharacter greekIotatonos 186
+\definecharacter greekOmicrontonos 188
+\definecharacter greekUpsilontonos 190
+\definecharacter greekOmegatonos 191
+\definecharacter greekIotadialytika 218
+\definecharacter greekUpsilondialytika 219
+
+% Accented Lowercase Greek letters
+
+\definecharacter greekalphatonos 220
+\definecharacter greekepsilontonos 221
+\definecharacter greeketatonos 222
+\definecharacter greekiotatonos 223
+\definecharacter greekomicrontonos 252
+\definecharacter greekupsilontonos 253
+\definecharacter greekomegatonos 254
+\definecharacter greekiotadialytika 250
+\definecharacter greekupsilondialytika 251
+\definecharacter greekiotadialytikatonos 192
+\definecharacter greekupsilondialytikatonos 224
+
+% Miscellaneous Greek symbols
+
+\definecharacter greekleftquot 171
+\definecharacter greekrightquot 187
+\definecharacter greektonos 180
+\definecharacter greekdialytikatonos 181
+\definecharacter greekapostrophos 162
+
+\stopencoding
diff --git a/tex/context/base/enco-heb.mkii b/tex/context/base/enco-heb.mkii
new file mode 100644
index 000000000..443745752
--- /dev/null
+++ b/tex/context/base/enco-heb.mkii
@@ -0,0 +1,16 @@
+%D \module
+%D [ file=enco-heb,
+%D version=2005.01.27,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Hebrew,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D To be done.
+
+\endinput
diff --git a/tex/context/base/enco-ibm.mkii b/tex/context/base/enco-ibm.mkii
new file mode 100644
index 000000000..48695ca52
--- /dev/null
+++ b/tex/context/base/enco-ibm.mkii
@@ -0,0 +1,7 @@
+% temporary module, needed for downward compatibility
+
+%\input regi-ibm.tex
+
+\enableregime[ibm]
+
+\endinput
diff --git a/tex/context/base/enco-il2.mkii b/tex/context/base/enco-il2.mkii
new file mode 100644
index 000000000..9fb87b2fd
--- /dev/null
+++ b/tex/context/base/enco-il2.mkii
@@ -0,0 +1,157 @@
+%D \module
+%D [ file=enco-il2,
+%D version=2000.05.07, % 1998.12.01,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Czech and Slovak ISO Latin 2 Encoding,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% This encoding will go but the regime will remain.
+
+%D This Czech/Slovak encoding is dedicated to Han The Thanh.
+%D The numbers are derived from some files he sent me. This
+%D definition file is (still) sort of beta.
+
+\startmapping[il2]
+
+\resetcaserange 127 to 255 % we map them all to themselves
+
+\definecaseswap 184 152
+\definecaseswap 181 165
+\definecaseswap 185 169
+\definecaseswap 187 171
+\definecaseswap 190 174
+\definecaseswap 224 192
+\definecaseswap 225 193
+\definecaseswap 228 196
+\definecaseswap 229 197
+\definecaseswap 232 200
+\definecaseswap 233 201
+\definecaseswap 236 204
+\definecaseswap 237 205
+\definecaseswap 239 207
+\definecaseswap 242 210
+\definecaseswap 243 211
+\definecaseswap 244 212
+\definecaseswap 246 214
+\definecaseswap 248 216
+\definecaseswap 249 217
+\definecaseswap 250 218
+\definecaseswap 252 220
+\definecaseswap 253 221
+
+\stopmapping
+
+\startencoding[il2][il2]
+
+\definecharacter textgrave 18
+\definecharacter textacute 19
+\definecharacter textcaron 20
+\definecharacter textbreve 21
+\definecharacter textmacron 22
+\definecharacter textring 23
+\definecharacter textcedilla 24
+\definecharacter textcircumflex 94
+\definecharacter textdotaccent 95
+\definecharacter texthungarumlaut 125
+\definecharacter texttilde 126
+\definecharacter textdiaeresis 127
+
+\definecharacter dotlessi 16
+\definecharacter dotlessj 17
+
+\definecharacter aeligature 26
+\definecharacter AEligature 29
+\definecharacter oeligature 27
+\definecharacter OEligature 30
+
+\definecharacter ssharp 25
+
+\definecharacter Racute 192
+\definecharacter Aacute 193
+\definecharacter Lacute 197
+\definecharacter Eacute 201
+\definecharacter Iacute 205
+\definecharacter Oacute 211
+\definecharacter Uacute 218
+\definecharacter Yacute 221
+\definecharacter racute 224
+\definecharacter aacute 225
+\definecharacter lacute 229
+\definecharacter eacute 233
+\definecharacter iacute 237
+\definecharacter oacute 243
+\definecharacter uacute 250
+\definecharacter yacute 253
+
+\definecharacter Lcaron 165
+\definecharacter Scaron 169
+\definecharacter Tcaron 171
+\definecharacter Zcaron 174
+\definecharacter lcaron 181
+\definecharacter scaron 185
+\definecharacter tcaron 187
+\definecharacter zcaron 190
+\definecharacter Ccaron 200
+\definecharacter Ecaron 204
+\definecharacter Dcaron 207
+\definecharacter Ncaron 210
+\definecharacter Rcaron 216
+\definecharacter ccaron 232
+\definecharacter ecaron 236
+\definecharacter dcaron 239
+\definecharacter ncaron 242
+\definecharacter rcaron 248
+
+\definecharacter Ocircumflex 212
+\definecharacter ocircumflex 244
+
+\definecharacter Adiaeresis 196
+\definecharacter Odiaeresis 214
+\definecharacter Udiaeresis 220
+\definecharacter adiaeresis 228
+\definecharacter odiaeresis 246
+\definecharacter udiaeresis 252
+
+\definecharacter Agrave 152
+\definecharacter agrave 184
+
+\definecharacter Ohungarumlaut 213
+\definecharacter Uhungarumlaut 219
+\definecharacter ohungarumlaut 245
+\definecharacter uhungarumlaut 251
+
+\definecharacter Uring 217
+\definecharacter uring 249
+\definecharacter Aring {\ilencodedrA}
+
+\definecharacter ostroke 28
+\definecharacter Ostroke 31
+\definecharacter Lstroke {\ilencodedL}
+\definecharacter lstroke {\ilencodedl}
+
+\def\ilencodedrA
+ {\dontleavehmode\hbox\bgroup
+ \setbox0\hbox{h}%
+ \dimen0=\ht0
+ \advance\dimen0 by -1ex
+ \rlap{\raise.67\dimen0\hbox{\char'27}}A%
+ \egroup}
+
+\def\ilencodedl
+ {\dontleavehmode{\char32l}}
+
+\def\ilencodedL
+ {\dontleavehmode\hbox\bgroup
+ \setbox0\hbox{L}%
+ \hbox to\wd0{\hss\char32L}%
+ \egroup}
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-ini.mkii b/tex/context/base/enco-ini.mkii
new file mode 100644
index 000000000..33825f94d
--- /dev/null
+++ b/tex/context/base/enco-ini.mkii
@@ -0,0 +1,1137 @@
+%D \module
+%D [ file=enco-ini,
+%D version=2007.02.19, % 2000.12.27, % 1998.12.03,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Initialization,
+%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.
+
+%D Quite some code will be moved to the mk files once we're ready
+%D for it.
+
+%D This module is a reimplementation of the module that handled
+%D composed characters and non \ASCII\ characters. The changed
+%D are not that fundamental, and mainly concerns moving
+%D definitions of specific glyphs and accents to other files as
+%D well as moving plain handling of accents to this module
+%D instead of overloading plain \TEX\ commands.
+
+%D Patterns are kind of mixed with font encodings and
+%D mappings. Alas.
+
+\ifx\synchronizepatterns\undefined \let\synchronizepatterns\relax \fi
+
+%D While dealing with input (the text source) and output (the
+%D glyphs), encoding comes into view. To summarize a few:
+%D
+%D \startitemize
+%D \item Bytes in the input file are mapped to an internal
+%D representation. An~\type {a} often stays an~\type {a},
+%D but~\type {\"e} can become either one code or become
+%D two codes (ending in overlapping glyphs).
+%D \item Characters can be made active and mapped onto another
+%D character.
+%D \item When changing case, characters are mapped onto
+%D themselves, their case||counterpart or a reasonable
+%D alternative, like~\"e onto~e.
+%D \item Single character representations in a \DVI\ file can
+%D be mapped onto one or more characters, either of not
+%D in more than one font file (virtual fonts).
+%D \item In the final format, fonts collections can be
+%D partially embedded, thereby losing the one||to||one
+%D relation between several instances of one font.
+%D \item For special purposes, individual characters should be
+%D mapped onto a dedicated encoding vector, for instance
+%D \PDF\ document encoding.
+%D \stopitemize
+%D
+%D These and other kind of mappings are to be dealt with, and
+%D the exact way of dealing often depends on the language to be
+%D typeset.
+
+\writestatus{loading}{ConTeXt Encoding Macros / Initialization}
+
+\unprotect
+
+%D First we define a few local or not yet initialized constants.
+
+\def\@map@{@m@ap@} % mapping prefix
+\def\@fha@{@f@ha@} % font prefix
+\def\@cas@{@c@as@} % casecom prefix
+
+\ifx\currentlanguage\undefined \let\currentlanguage\s!en \fi
+
+%D \macros
+%D {setupencoding}
+%D
+%D The following setup command is used to tune encoding
+%D handling.
+
+\def\setupencoding
+ {\dosingleargument\dosetupencoding}
+
+\def\dosetupencoding[#1]%
+ {\getparameters[\??ec][#1]%
+ \edef\defaultencoding
+ {\ifx\@@ecdefault\empty\s!default\else\@@ecdefault\fi}}
+
+%D \macros
+%D {useencoding}
+%D
+%D Encodings things are defined in separate files and are
+%D loaded only once, using:
+%D
+%D \showsetup{useencoding}
+
+\def\douseencoding#1%
+ {\doifundefined{\c!file\f!encodingprefix#1}%
+ {\letvalue{\c!file\f!encodingprefix#1}\empty
+ \makeshortfilename[\truefilename{\f!encodingprefix#1}]%
+ \startreadingfile
+ \readsysfile{\shortfilename.mkii}
+ {\showmessage\m!encodings2{#1}}
+ {\showmessage\m!encodings3{#1}}%
+ \stopreadingfile}}
+
+\def\useencoding[#1]%
+ {\processcommalist[#1]\douseencoding}
+
+%D \macros
+%D {startmapping,enablemapping}
+%D
+%D In order to process patterns, convert from lower to
+%D uppercase and vise versa and some more, we provide a
+%D mechanism to define mappings. The first real application
+%D of this command was:
+%D
+%D \starttyping
+%D \startmapping [something]
+%D \definecasemap 165 181 165
+%D \definecasemap 171 187 171
+%D ...
+%D \defineuppercasecom \i {I}
+%D \defineuppercasecom \l \L
+%D \definelowercasecom \AE \ae
+%D ...
+%D \stopmapping
+%D \stoptyping
+%D
+%D So, character 165 becomes 181 in uppercase and 165 in
+%D lowercase. A mapping is activated with \type {\enablemapping}.
+
+\def\startsavingmappingtoks#1%
+ {\bgroup
+ \edef\charactermapping{@#1@}%
+ \checkmappingtoks
+ \setmappingtoks
+ \the\mappingtoks}
+
+\def\stopsavingmappingtoks
+ {\global\mappingtoks\emptytoks
+ \dostepwiserecurse{0}{255}\plusone
+ {\edef\@@expanded
+ {\the\mappingtoks
+ \ifnum\recurselevel>127
+ \noexpand\settoletterunlessactive{\recurselevel}%
+ \fi
+ \lccode\recurselevel\ifnum\lccode\recurselevel=\zerocount\zerocount\else\space\the\lccode\recurselevel\space\fi
+ \uccode\recurselevel\ifnum\uccode\recurselevel=\zerocount\zerocount\else\space\the\uccode\recurselevel\space\fi
+ \ifnum\sfcode\recurselevel=\plusthousand\else\sfcode\recurselevel=\the\sfcode\recurselevel\space\fi
+ }%
+ \global\mappingtoks\expandafter{\@@expanded}}%
+ \egroup
+ \let\enabledmapping\empty
+ \enablemapping[\currentmapping]}
+
+\def\startmapping[#1]%
+ {\startsavingmappingtoks{#1}}
+
+\def\stopmapping
+ {\stopsavingmappingtoks}
+
+\def\optimizemapping[#1]%
+ {\startsavingmappingtoks{#1}%
+ % nothing, just an automatic cleanup
+ \stopsavingmappingtoks
+ % we need to resync
+ %\let\enabledmapping\relax
+ }%\enablemapping[\currentmapping]}
+
+\def\setmappingtoks
+ {\@EA\let\@EA\mappingtoks\csname\@map@\charactermapping\endcsname
+ \@EA\let\@EA\casecomtoks\csname\@cas@\charactermapping\endcsname}
+
+\def\checkmappingtoks
+ {\ifundefined{\@map@\charactermapping}%
+ \expandafter\newtoks\csname\@map@\charactermapping\endcsname
+ \fi
+ \ifundefined{\@cas@\charactermapping}%
+ \expandafter\newtoks\csname\@cas@\charactermapping\endcsname
+ \fi}
+
+\def\definecasemap #1 #2 #3 % code lower upper
+ {\doifelse{#2}{to}
+ {\presetcaserange{#1}{#3}}
+ {\lccode#1=#2\relax
+ \uccode#1=#3\relax}%
+ \ignorespaces}
+
+%D Saves a few tokens
+
+\def\definecaseswap #1 #2 % lower upper
+ {\lccode#1=#1\relax
+ \uccode#2=#2\relax
+ \lccode#2=#1\relax
+ \uccode#1=#2\relax
+ \ignorespaces}
+
+\def\definecaseself #1 % lower=upper=self
+ {\lccode#1=#1\relax
+ \uccode#1=#1\relax
+ \ignorespaces}
+
+%D Watch the \type {\definecasemap 127 to 255} option!
+%D Dedicated to Taco there is also:
+
+\def\definecasemaps #1 to #2 lc #3 uc #4 % from to lc+ uc+
+ {\dostepwiserecurse{#1}{#2}\plusone
+ {\scratchcounter\recurselevel\advance\scratchcounter#3\lccode\recurselevel=\scratchcounter
+ \scratchcounter\recurselevel\advance\scratchcounter#4\uccode\recurselevel=\scratchcounter}%
+ \ignorespaces}
+
+%D This can be used like:
+%D
+%D \starttyping
+%D \definecasemaps 128 to 156 lc 32 uc 0
+%D \definecasemaps 160 to 188 lc -32 uc 0
+%D \definecasemaps 160 to 188 lc -32 uc 0
+%D \definecasemaps 192 to 255 lc 32 uc 0
+%D \stoptyping
+%D
+%D and saves a lot of typing (copying).
+
+\def\resetcaserange #1 to #2
+ {\dostepwiserecurse{#1}{#2}\plusone
+ {\lccode\recurselevel\zerocount
+ \uccode\recurselevel\zerocount}%
+ \ignorespaces}
+
+\def\presetcaserange#1#2% could be pre-expanded
+ {\dostepwiserecurse{#1}{#2}\plusone
+ {\lccode\recurselevel=\recurselevel
+ \uccode\recurselevel=\recurselevel}%
+ \ignorespaces}
+
+\def\setcasemap #1 #2 #3 %
+ {\settoletterunlessactive{#1}%
+ \lccode #1=#2
+ \uccode #1=#3 }
+
+\def\setcaseswap #1 #2 %
+ {\settoletterunlessactive{#1}%
+ \settoletterunlessactive{#2}%
+ \lccode #1=#1
+ \uccode #2=#2
+ \lccode #2=#1
+ \uccode #1=#2 }
+
+\def\setcaseself #1 %
+ {\settoletterunlessactive{#1}%
+ \lccode #1=#1
+ \uccode #1=#1 }
+
+\def\definespacemap #1 #2 % code sfcode
+ {\sfcode#1=#2%
+ \ignorespaces}
+
+\def\setspacemap #1 #2 %
+ {\settootherunlessactive{#1}%
+ %\lccode #1=\zerocount
+ %\uccode #1=\zerocount
+ \sfcode #1=#2 }
+
+\def\defineuppercasecom#1#2%
+ {\global\casecomtoks\expandafter{\the\casecomtoks\setuppercasecom#1{#2}}%
+ \ignorespaces}
+
+\def\definelowercasecom#1#2%
+ {\global\casecomtoks\expandafter{\the\casecomtoks\setlowercasecom#1{#2}}%
+ \ignorespaces}
+
+\let\setuppercasecom\gobbletwoarguments
+\let\setlowercasecom\gobbletwoarguments
+
+\def\setcasecom#1#2{\def#1{#2}}
+
+\let\enabledmapping\empty % indirect, needed to handle default too
+
+\def\enablemapping[#1]%
+ {\edef\charactermapping{@#1@}%
+ \ifx\enabledmapping\charactermapping \else
+ \doifdefined{\@map@\charactermapping}
+ {%\expandafter\showthe\csname\@map@\charactermapping\endcsname\endcsname
+ \the\csname\@map@\charactermapping\endcsname}%
+ % == \the\executeifdefined{\@map@\charactermapping}\emptytoks
+ \edef\enabledmapping{\charactermapping}%
+ \enablelanguagespecifics[\currentlanguage]% new
+ % \edef\enabledmapping{\charactermapping\currentlanguage}% can be comma list
+ \fi
+ \synchronizepatterns}
+
+% on behalf of font switching:
+
+\def\fastenablemapping#1%
+ {\edef\charactermapping{@#1@}%
+ \ifx\enabledmapping\charactermapping \else
+ \@EA\ifx\csname\@map@\charactermapping\endcsname\relax\else
+ \the\csname\@map@\charactermapping\endcsname
+ \fi
+ % == \the\executeifdefined{\@map@\charactermapping}\emptytoks
+ \let\enabledmapping\charactermapping
+ \enablelanguagespecifics[\currentlanguage]% to faster
+ \fi}
+
+%D This macro wil be implemented in \type {lang-ini.tex}.
+
+\ifx\enablelanguagespecifics\undefined
+ \def\enablelanguagespecifics[#1]{}
+\fi
+
+%D Further on we have to take some precautions when dealing
+%D with special characters like~\type{~}, \type{_}
+%D and~\type{^}, so let us define ourselve some handy macros
+%D first.
+
+\def\protectfontcharacters
+ {\edef\unprotectfontcharacters
+ {\catcode`\noexpand ~=\the\catcode`~\relax
+ \catcode`\noexpand _=\the\catcode`_\relax
+ \catcode`\noexpand ^=\the\catcode`^\relax}%
+ \catcode`~=\@@letter
+ \catcode`_=\@@letter
+ \catcode`^=\@@letter\relax}
+
+%D The completeness of the Computer Modern Roman typefaces
+%D makes clear how incomplete other faces are. To honour 7~bit
+%D \ASCII, these fonts were designed using only the first 127
+%D values of the 256 ones that can be presented by one byte.
+%D Nowadays 8~bit character codings are more common, mainly
+%D because they permit us to predefine some composed
+%D characters, which are needed in most european languages.
+%D
+%D Supporting more than the standard \TEX\ encoding vector
+%D |<|which in itself is far from standard and differs per
+%D font|>| puts a burden on the fonts mechanism. The \CONTEXT\
+%D mechanism is far from complete, but can handle several
+%D schemes at once. The main problem lays in the accented
+%D characters and ligatures like~ff, although handling
+%D ligatures is not the responsibility of this module.
+%D
+%D By default, we use \PLAIN\ \TEX's approach of placing
+%D accents. All other schemes sooner or later give problems
+%D when we distribute \DVI||files are distributed across
+%D machines and platforms. Nevertheless, we have to take care
+%D of different encoding vectors, which tell us where to find
+%D the characters we need. This means that all kind of
+%D character placement macro's like \type{\"} and \type{\ae}
+%D have to be implemented and adapted in a way that suits
+%D these vectors.
+%D
+%D The main difference between different vector is the way
+%D accents are ordered and/or the availability of prebuilt
+%D accented characters. Accented characters can for instance be
+%D called for by sequences like \type{\"e}. Here the \type{\"}
+%D is defined as:
+%D
+%D \starttyping
+%D \def\"#1{{\accent"7F #1}}
+%D \stoptyping
+%D
+%D This macro places the accent \accent"7F {} on top of an~e
+%D gives \"e. Some fonts however can have prebuild accents and
+%D use a more direct approach like
+%D
+%D \starttyping
+%D \def\"#1{\if#1e\char 235\else ... \fi}
+%D \stoptyping
+%D
+%D The latter approach is not used in \CONTEXT, because we
+%D store relevant combinations of accents and characters in
+%D individual macros.
+
+%D We define character substitutes and commands with definition
+%D commands like:
+%D
+%D \starttyping
+%D \startcoding[texnansi]
+%D
+%D \defineaccent " a 228
+%D \defineaccent ^ e 234
+%D \defineaccent ' {\dotlessi} 237
+%D
+%D \definecharacter ae 230
+%D \definecharacter oe 156
+%D
+%D \definecommand b \texnansiencodedb
+%D \definecommand c \texnansiencodedc
+%D
+%D \stopcoding
+%D \stoptyping
+%D
+%D The last argument of \type{\defineaccent} and
+%D \type{\definecharacter} tells \TEX\ the position of the
+%D accented character in the encoding vector. In order to
+%D complish this, we tag each implementation with the character
+%D coding identifier. We therefore need two auxiliary variables
+%D \type{\characterencoding} and \type{\nocharacterencoding}. These
+%D contain the current and default encoding vectors and both
+%D default to the \PLAIN\ one.
+
+\edef\characterencoding {@\s!default @}
+\edef\nocharacterencoding {@\s!default @}
+\edef\charactermapping {@\s!default @}
+
+% todo, else \d j == \dj, print file and check
+
+\def\accentprefix {}%{*}
+\def\commandprefix {}%{=}
+\def\characterprefix{}%{-}
+
+%D \macros
+%D {startcoding, reducetocoding}
+%D
+%D Before we can redefine accents and special characters, we
+%D have to tell \CONTEXT\ what encoding is in force. The next
+%D command is responsible for doing this and also takes care of
+%D the definition of the recoding commands. We use the \type
+%D {\start}||\type {\stop}||commands for definitions and the
+%D \type {\reduceto}||command for local switching to
+%D simplified commands.
+
+% etex : \ifcsname
+
+\def\justhandleaccent#1#2% \empty makes #2={} save % no \unexpanded
+ {\ifundefined{\accentprefix\characterencoding#1\string#2\empty}%
+ #2%
+ \else
+ \csname\accentprefix\characterencoding#1\string#2\empty\endcsname
+ \fi}
+
+\def\justhandlecommand#1% % no \unexpanded, otherwise pdfdoc will fail
+ {\ifundefined{\commandprefix\characterencoding#1}% as well as hyph patterns
+ #1%
+ \else
+ \csname\commandprefix\characterencoding#1\endcsname
+ \fi}
+
+\def\enableencoding
+ {\dodoubleempty\doenableencoding}
+
+\def\doenableencoding[#1][#2]% main fallback
+ {\iffirstargument\edef\characterencoding{@#1@}\fi
+ \edef\nocharacterencoding{@\ifsecondargument#2\else\s!default\fi @}%
+ \synchronizepatterns}
+
+\edef\xnocharacterencoding{@\s!default @}
+
+\def\fastenableencoding#1%
+ {\edef\characterencoding{@#1@}%
+ \let\nocharacterencoding\xnocharacterencoding}
+
+\def\startencoding
+ {\dodoubleempty\dostartencoding}
+
+\def\dostartencoding[#1][#2]% encoding regime
+ {%\showmessage\m!encodings1{#1}%
+ \pushmacro\characterencoding
+ \pushmacro\currentregime
+ \pushmacro\dohandleaccent % still needed?
+ \pushmacro\dohandlecommand % still needed?
+ \pushmacro\doautosetregime
+ \let\dohandleaccent\donthandleaccent % still needed?
+ \let\dohandlecommand\donthandlecommand % still needed?
+ %let\definesortkey\savesortkey
+ \edef\characterencoding{@#1@}%
+ \doifelsenothing{#2}%
+ {\let\doautosetregime\gobbletwoarguments}
+ {\def\currentregime{#2}}}
+
+\def\stopencoding
+ {\popmacro\doautosetregime
+ \popmacro\dohandlecommand % still needed?
+ \popmacro\dohandleaccent % still needed?
+ \popmacro\currentregime
+ \popmacro\characterencoding}
+
+% probably obsolete (hm, not yet)
+
+\def\reducetocoding[#1]% use grouped!
+ {\doifsomething{#1}
+ {\let\dohandleaccent \justhandleaccent
+ \let\dohandlecommand\justhandlecommand
+ \enableencoding[#1]%
+ \enablelanguagespecifics[\currentlanguage]}}
+
+\let\startcoding \startencoding
+\def\stopcoding {\stopencoding}
+\let\enablecoding \enableencoding
+
+%D The use of these macros are not limited to font
+%D definition files, but may also be used when loading
+%D patterns.
+
+%D \macros
+%D {definesortkey,flushsortkeys,flushsortkey}
+%D
+%D Yet another definition concerns sorting of indexes and
+%D lists.
+%D
+%D \starttyping
+%D \definesortkey {\'e} {e} {a} {\'e}
+%D \stoptyping
+%D
+%D The first argument denotes the string to be treated. The
+%D second argument is the raw replacement, while the third
+%D argument determines the sort order given the replacement.
+%D The last argument is used as entry in the index (a, b, etc).
+%D
+%D The keys can be flushed using \type {\flushsortkeys}
+%D which in turn results in a sequence of calls to \type
+%D {\flushsortkey}, a macro taking 4~arguments.
+%D
+%D This mechanism is currently being tested and subjected to
+%D changes! Obsolete:
+
+\let\definesortkey\gobblefourarguments
+\let\savesortkey \gobblefourarguments
+\let\flushsortkeys\relax
+\let\flushsortkey \relax
+
+%D \macros
+%D {defineaccent, definecharacter, definecommand}
+%D
+%D The actual definition of accents, special characters and
+%D commands is done with the next three commands.
+
+\def\defineaccent
+ {\protectfontcharacters
+ \dodefineaccent}
+
+\def\dodefineaccent#1 #2 %
+ {\unprotectfontcharacters
+ \dododefineaccent#1 #2 }
+
+\def\dododefineaccent#1 #2 #3 %
+ {\setvalue{#1}{\dohandleaccent{#1}}%
+ \doifnumberelse{\string#3}
+ {\setvalue{\accentprefix\characterencoding#1\string#2}{\char#3 }} % space added
+ {\setvalue{\accentprefix\characterencoding#1\string#2}{#3}}}
+
+\def\dohandleaccent#1#2%
+ {\ifcsname\accentprefix\characterencoding#1\string#2\empty\endcsname
+ \csname\accentprefix\characterencoding#1\string#2\empty\endcsname
+ \else\ifcsname\accentprefix\nocharacterencoding#1\string#2\empty\endcsname
+ \csname\accentprefix\nocharacterencoding#1\string#2\empty\endcsname
+ \else\ifcsname\accentprefix\characterencoding#1\endcsname
+ \csname\accentprefix\characterencoding#1\endcsname{#2}%
+ \else%\ifcsname\accentprefix\nocharacterencoding#1\endcsname
+ \csname\accentprefix\nocharacterencoding#1\endcsname{#2}%
+% \else
+% \donormaltextaccent{#1}{#2}%
+ \fi\fi\fi}%\fi}
+
+\def\patternchar#1 {\rawcharacter{#1}} % space is part of character definition !
+
+% \ifx \enablepatterntokens\undefined
+% \def\handlepatterntoken#1]{\csname#1\endcsname}
+% \fi
+
+% we need to postpone catcode changes, e.g. hr patterns
+% have \catcode" -> which fails when " is letter
+
+\def\pathypsettings
+ {\ifx \enablepatterntokens\undefined
+ \defineactivecharacter [ {\handlepatterntoken}%
+ \else
+ \enablepatterntokens
+ \fi
+ \let\dochar\thechr
+ \lccode16=16 % brrr, extra quote in ec (turkish)
+ \lccode17=17 % brrr, extra quote in ec (turkish)
+ \lccode`\-=`\-
+ \lccode`\'=`\'
+ \lccode`\"=`\"
+ \relax}
+
+\def\patterns {\pathypsettings\normalpatterns }
+\def\hyphenation{\pathypsettings\normalhyphenation}
+
+%D Because we don't want to use the second command grouped, we
+%D (re)define it as follows:
+
+\def\hyphenation
+ {\begingroup\def\hyphenation{\normalhyphenation{\the\scratchtoks}\endgroup}%
+ \pathypsettings\afterassignment\hyphenation\scratchtoks=}
+
+%D This is not needed for patterns because they are loaded grouped
+%D anyway and it saves us an assignment. Can go ... no longer
+%D shared patterns.
+
+\def\startpatternloading#1#2#3% % we should use \everypatternloading
+ {\startreadingfile
+ \bgroup
+ % let's get rid of interfering stuff
+ \let\everyjob\scratchtoks
+ \let\message \gobbleoneargument
+ % we want direct characters
+ \let\char\patternchar
+ \doifelsenothing{#2}{\enableencoding[ec]}{\enableencoding[#2]}%
+ \doifelsenothing{#3}{\enablemapping [ec]}{\enablemapping [#3]}%
+ \expanded{\doifinstring{\f!languageprefix}{#1}}
+ {\ifx \enablepatternxml\undefined \else
+ \enablepatternxml
+ \fi}%
+ \let\dohandleaccent\normaldohandleaccent}
+
+\def\stoppatternloading
+ {\egroup
+ \stopreadingfile}
+
+ \def\thechr#1{\char#1 } % just in case \relax interferes
+\unexpanded\def\numchr#1{\char#1\relax}
+\unexpanded\def\strchr#1{\csname#1\endcsname}
+
+\let\dochar\numchr
+
+\def\startdirectcharacters {\pushmacro\dochar \let\dochar\thechr}
+\def\stopdirectcharacters {\popmacro \dochar}
+
+\def\definecharacter#1 #2 %
+ {\ifundefined{#1}\setvalue{#1}{\dohandlecharacter{#1}}\fi
+ \doifnumberelse{\string#2}
+ {\setvalue{\characterprefix\characterencoding\string#1}{\dochar{#2}}%
+ \doautosetregime{#1}{#2}}
+ {\setvalue{\characterprefix\characterencoding\string#1}{#2}}}
+
+\def\dohandlecharacter#1%
+ {\csname\characterprefix\ifcsname\characterprefix\characterencoding#1\endcsname
+ \characterencoding\else\nocharacterencoding\fi#1\endcsname}
+
+% \def\fallbackpatternchar{x} % makes no sense, duplicate patterns
+
+\def\defaultcharacter#1%
+ {\csname\characterprefix\nocharacterencoding\strippedcsname#1\endcsname}
+
+%D Instead of numbers, a command may be entered.
+
+\def\definecommand#1 #2 %
+ {\setvalue{\string#1}{\dohandlecommand{#1}}%
+ %\redefinecommand #1 % just to be sure
+ \setvalue{\commandprefix\characterencoding\string#1}{#2}}
+
+%D Here we see that redefining accents is characters is more
+%D or less the same as redefining commands. We also could have
+%D said:
+%D
+%D \starttyping
+%D \def\defineaccent#1 #2 {\definecommand#1\string#2 \char}
+%D \def\definecharacter#1 {\definecommand#1 \char}
+%D \stoptyping
+
+%D \macros
+%D {defineaccentcommand}
+%D
+%D When needed, one can overload the default positions of the
+%D accents. The \PLAIN\ \TEX\ defaults are:
+%D
+%D \starttyping
+%D \defineaccentcommand ` 18
+%D \defineaccentcommand ' 19
+%D \defineaccentcommand v 20
+%D \defineaccentcommand u 21
+%D \defineaccentcommand = 22
+%D \defineaccentcommand ^ 94
+%D \defineaccentcommand . 95
+%D \defineaccentcommand H 125 % "7D
+%D \defineaccentcommand ~ 126 % "7E
+%D \defineaccentcommand " 127 % "7F
+%D \stoptyping
+
+\def\defineaccentcommand
+ {\protectfontcharacters
+ \dodefineaccentcommand}
+
+\def\dodefineaccentcommand#1 #2 % \string toegevoegd
+ {\doifnumberelse{\string#2}
+ {\setvalue{\accentprefix\characterencoding\string#1}##1{{\accent#2 ##1}}}
+ {\setvalue{\accentprefix\characterencoding\string#1}##1{{#2##1}}}%
+ \unprotectfontcharacters}
+
+%D We don't have to define them for the default \PLAIN\ case.
+%D Commands may be used instead of character codes.
+
+%D \macros
+%D {redefinecommand}
+%D
+%D Redefinition of encoding dependant commands like \type{\b}
+%D and \type{\c} can be triggered by:
+%D
+%D \starttyping
+%D \redefinecommand b % something math
+%D \redefinecommand c % something math
+%D \stoptyping
+%D
+%D Handling of characters is easier than handling accents
+%D because here we don't have to take care of arguments. We
+%D just call for the right glyph in the right place.
+%D
+%D The \type{\next} construction permits handling of commands
+%D that take arguments. This means that we can use this
+%D command to redefine accent handling commands too
+%D (although today the next is not needed any longer in test
+%D macros).
+
+\def\redefinecommand#1 %
+ {% no \unexpanded, else pdfdoc fails
+ \setvalue{\string#1}{\dohandlecommand{#1}}}%
+
+\def\dohandlecommand#1%
+ {\csname\commandprefix
+ \ifcsname\commandprefix\characterencoding#1\endcsname
+ \characterencoding
+ \else
+ \nocharacterencoding
+ \fi
+ #1\endcsname}
+
+%D \macros
+%D {currentencoding, currentmapping}
+%D
+%D When we show 'm, we don't want to see the protection
+%D measures.
+
+\def\currentencoding{\@EA\dopureencodingname\characterencoding}
+\def\currentmapping {\@EA\dopureencodingname\charactermapping }
+
+\def\dopureencodingname @#1@{#1}
+
+\def\pureencodingname#1{\@EA\dopureencodingname#1}
+
+%D \macros
+%D {showaccents, showcharacters,
+%D showcharacterbounds, showhyphenations}
+%D
+%D Encoding is a tricky business. Therefore we provide a
+%D a few macros that show most of the characters involved. The
+%D next two tables show the result of \type {\showaccents}.
+%D
+%D \placetable
+%D {The special glyphs in default encoding.}
+%D {\showaccents}
+%D
+%D \placetable
+%D {The special glyphs in texnansi encoding.}
+%D {\switchtobodyfont[lbr]\showaccents}
+%D
+%D The command
+%D
+%D \starttyping
+%D \showhyphenations{doordefini\"eren}
+%D \stoptyping
+%D
+%D can be used to check the correct loading of hyphenation
+%D patterns.
+
+\fetchruntimecommand \showaccents {\f!encodingprefix\s!run.mkii}
+\fetchruntimecommand \showcharacters {\f!encodingprefix\s!run.mkii}
+\fetchruntimecommand \showcharacterbounds {\f!encodingprefix\s!run.mkii}
+\fetchruntimecommand \showhyphenations {\f!encodingprefix\s!run.mkii}
+\fetchruntimecommand \showmapping {\f!encodingprefix\s!run.mkii}
+
+%D \macros
+%D {everyuppercase, EveryUppercase,
+%D everyuppercase, EveryUppercase}
+%D
+%D When we want to uppercase strings of characters, we have to
+%D take care of those characters that have a special meaning or
+%D are only accessible by means of macros. The next hack was
+%D introduced when Tobias Burnus started translating head and
+%D label texts into spanish and italian. The first application
+%D of this token register therefore can be found in the module
+%D that deals with these texts.
+
+\newevery \everyuppercase \EveryUppercase
+\newevery \everylowercase \EveryLowercase
+
+%D This magic trick maps takes care of mapping from lower to
+%D upper case and reverse.
+
+\def\reloadmapping{\the\executeifdefined{\@cas@\charactermapping}\emptytoks}
+
+\appendtoks\let\setuppercasecom\setcasecom\to\everyuppercase
+\appendtoks\let\setlowercasecom\setcasecom\to\everylowercase
+
+\appendtoks\reloadmapping\to\everyuppercase % slow, will be sped up
+\appendtoks\reloadmapping\to\everylowercase % slow, will be sped up
+
+\newtoks\everyULmap
+
+\appendtoks\let\remapcase\remapuppercase\the\everyULmap\to\everyuppercase
+\appendtoks\let\remapcase\remaplowercase\the\everyULmap\to\everylowercase
+
+\let\remapcase\gobbletwoarguments
+
+\def\remapuppercase#1#2{\let#2#1} % more efficient:
+\def\remaplowercase#1#2{\let#1#2} \let\remaplowercase\let
+
+\def\defineLCcharacter #1 #2 %
+ {\appendtoks\let\to\everylowercase
+ \@EA\appendtoks\csname#1\endcsname\to\everylowercase
+ \@EA\appendtoks\csname#2\endcsname\to\everylowercase}
+
+\def\defineUCcharacter #1 #2 %
+ {\appendtoks\let\to\everyuppercase
+ \@EA\appendtoks\csname#1\endcsname\to\everyuppercase
+ \@EA\appendtoks\csname#2\endcsname\to\everyuppercase}
+
+\def\defineULcharacter #1 #2 %
+ {\appendtoks\remapcase\to\everyULmap
+ \@EA\appendtoks\csname#1\endcsname\to\everyULmap
+ \@EA\appendtoks\csname#2\endcsname\to\everyULmap}
+
+% slightly faster with \smallcapped's but far more hash and stringspace
+%
+% \newif\ifuppercase \appendtoks\uppercasetrue\to\everyuppercase
+% \newif\iflowercase \appendtoks\lowercasetrue\to\everylowercase
+%
+% \def\defineULcharacter #1 #2 %
+% {\def\!!stringa{@#1}\@EA\letvalue\@EA\!!stringa\csname#1\endcsname
+% \def\!!stringa{@#2}\@EA\letvalue\@EA\!!stringa\csname#2\endcsname
+% \setvalue{#1}{\getvalue{@\ifuppercase#2\else#1\fi}}%
+% \setvalue{#2}{\getvalue{@\iflowercase#1\else#2\fi}}}
+
+% 2 = tricky, since expanding \definedfont[lowcasename] ... goes wrong
+
+\chardef\uppercasemode\plusthree % 0=ignore 1=normal 2=expand 3=auto
+\chardef\casecommode \plusone % 0=noexpand 1=expand
+
+\def\setcasecom #1#2{\def#1{\ifcase\casecommode\noexpand#1\else#2\fi}}
+
+% \def\OEPS{whatever}
+%
+% \startmapping[ec]
+% \defineuppercasecom \oeps {\getvalue{OEPS}}
+% \stopmapping
+%
+% \WORD{xx \oeps}
+
+\def\douppercase#1%
+ {\bgroup
+ \let\douppercase\firstofoneargument
+ \the\everyuppercase % currently also checks uppercasemode
+ \let\dochar\rawcharacter
+ \ifcase\uppercasemode
+ #1%
+ \or % No expansion here, otherwise \getvalue problems! Default!!!
+ %\edef\next{#1}% keep this to prevent roll back
+ %\uppercase\expandafter{\next}% keep this to prevent roll back
+ \uppercase{#1}%
+ \or
+ \chardef\casecommode\zerocount
+ \let\docasecom\firstoftwoarguments
+ \edef\ascii{#1}%
+ \edef\ascii{\expandafter\uppercase\expandafter{\ascii}}% needed when in regime
+ \chardef\casecommode\plusone
+ \ascii
+ \else
+ % mode three may trigger setting 2 elsewhere (e.g. regime test)
+ \uppercase{#1}%
+ \fi
+ \egroup}
+
+\prependtoksonce
+ \doifnot\currentregime\s!default
+ {\ifnum\uppercasemode=\plusthree \chardef\uppercasemode\plustwo \fi}%
+\to \everyuppercase
+
+%D \macros
+%D {everysanitize, EverySanitize}
+%D
+%D Whenever we are sanitizing strings, like we sometimes do
+%D when we deal with specials, the next token register can be
+%D called.
+
+\newevery \everysanitize \EverySanitize
+
+%D \macros
+%D {defineuclass,defineudigit,udigit}
+%D
+%D The next few macros are experimental and needed for unicoded
+%D chinese characters.
+
+\def\defineuclass #1 #2 #3 %
+ {\setvalue{uc\the\numexpr#2*256+#3\relax}{#1}}
+
+\def\defineudigit #1 #2 #3 {\setvalue{\characterencoding uc#1}{\uchar{#2}{#3}}}
+
+%D It may look strange, but for the moment, we want the encoding
+%D to be part of the digit specification. This may change!
+
+\unexpanded\def\udigit#1#2{\getvalue{@#1@uc\number#2}}
+
+%D \macros
+%D {uchar, octuchar, hexuchar}
+
+\ifx\uchar\undefined \def\uchar#1#2{(\number#1,\number#2)} \fi
+
+\def\octuchar#1#2{\uchar{`#1}{`#2}}
+\def\hexuchar#1#2{\uchar{"#1}{"#2}}
+
+%D Basics and fallbacks.
+
+\newif\ifignoreaccent
+
+\let\textaccent \accent
+\let\normaltextaccent\textaccent
+
+% ** we will explicitly embrace the two arguments, since in definitions
+% this may not be the case, and we don't want faulty expansions like
+% "\dobuildtextaccent \char 18 a" but "\dobuildtextaccent {\char 18}{a}"
+% instead
+
+\def\buildmathaccent#1%
+ {\mathaccent#1 }
+
+\def\buildtextaccent#1#2% **
+ {\ifignoreaccent
+ \expandafter\nobuildtextaccent
+ \else
+ \expandafter\dobuildtextaccent
+ \fi{#1}{#2}}
+
+\unexpanded\def\nobuildtextaccent#1#2%
+ {#2}
+
+\unexpanded\def\dobuildtextaccent#1#2%
+ {{\let\char\normalaccent#1\let\char\normalchar#2}}
+
+% some fake ones, name will change into build
+
+\unexpanded\def\bottomaccent#1#2#3#4#5% down right slantcorrection accent char
+ {\dontleavehmode % why this align mess
+ \vtop
+ {\forgetall
+ \baselineskip\zeropoint
+ \lineskip#1%
+ \everycr\emptytoks
+ \tabskip\zeropoint
+ \lineskiplimit\zeropoint
+ \setbox0\hbox{#4}%
+ \halign
+ {##\crcr\hbox{#5}\crcr
+ \hidewidth
+ \hskip#2\wd0
+ \hskip-#3\slantperpoint % in plain 1ex * dimenless value
+ \vbox to .2ex{\box0\vss}\hidewidth
+ \crcr}}}
+
+\def\buildtextmacron {\bottomaccent{.25ex}{0}{15}{\textmacron}}
+\def\buildtextbottomdot{\bottomaccent{.25ex}{0}{5}{\textbottomdot}}
+\def\buildtextcedilla {\bottomaccent{0ex}{0}{5}{\textcedilla}}
+\def\buildtextogonek {\bottomaccent{-.1ex}{.5}{0}{\textogonek}}
+
+%D A collectors item:
+
+\def\buildtextbottomcomma{\bottomaccent{.15ex}{0}{5}{\tx,}}
+
+%D Rarely needed but there:
+
+\unexpanded\def\topaccent#1#2#3#4#5% down right slantcorrection accent char
+ {\dontleavehmode
+ \bgroup
+ \setbox0\hbox{#4}%
+ \setbox2\hbox{#5}%
+ \hbox to \wd2 \bgroup
+ \hss\copy2\hss
+ \hskip-\wd2
+ \hss\hskip#2\wd0\hskip-#3\slantperpoint\raise#1\hbox{#4}\hss
+ \egroup
+ \egroup}
+
+\def\buildtextgrave{\topaccent{0pt}{0}{15}{\textgrave}} % e.g.
+
+% \definecharacter schwa {\hbox{\rotate[rotation=180,location=high]{\hbox{e}}}}
+% \definecharacter schwagrave {\buildtextgrave\schwa}
+
+% math stuff, will change
+
+\def\definemathaccent#1 #2%
+ {\setvalue{\string#1}{#2}%
+ \setvalue{normalmathaccent\string#1}{#2}}
+
+\def\donormalmathaccent#1%
+ {\getvalue{normalmathaccent\string#1}}
+
+%D Some precautions:
+
+\ifx\usepdffontresource\undefined
+ \def\usepdffontresource #1 {} % this will be defined elsewhere
+\fi
+
+\def\donthandleaccent #1{\expandafter\string\csname#1\endcsname\space}
+\def\donthandlecommand #1{\expandafter\string\csname#1\endcsname\space}
+\def\donthandlecharacter #1{\expandafter\string\csname#1\endcsname\space}
+
+\def\stringifyhandleaccent #1{\strchr{#1}}
+\def\stringifyhandlecommand #1{\strchr{#1}}
+\def\stringifyhandlecharacter#1{\strchr{#1}}
+
+\def\keephandleaccent #1{\expandafter\noexpand\csname#1\endcsname}
+\def\keephandlecommand #1{\expandafter\noexpand\csname#1\endcsname}
+\def\keephandlecharacter #1{\expandafter\noexpand\csname#1\endcsname}
+
+\def\handleaccent #1{\csname#1\endcsname}
+\def\handlecommand #1{\csname#1\endcsname}
+\def\handlecharacter #1{\csname#1\endcsname}
+
+\def\dontexpandencoding
+ {\let\dohandleaccent \donthandleaccent
+ \let\dohandlecommand \donthandlecommand
+ \let\dohandlecharacter\donthandlecharacter}
+
+\def\keepencodedtokens
+ {\let\dohandleaccent \keephandleaccent
+ \let\dohandlecommand \keephandlecommand
+ \let\dohandlecharacter\keephandlecharacter}
+
+\def\literateencodedtokens
+ {% \let\dohandleaccent \keephandleaccent
+ % \let\dohandlecommand \keephandlecommand
+ \let\dohandlecharacter\keephandlecharacter}
+
+\def\stringifyencodedtokens
+ {% \let\dohandleaccent \stringifyhandleaccent
+ % \let\dohandlecommand \stringifyhandlecommand
+ \let\dohandlecharacter\stringifyhandlecharacter}
+
+\unexpanded\def\uhandleaccent #1{\csname#1\endcsname}
+\unexpanded\def\uhandlecommand #1{\csname#1\endcsname}
+\unexpanded\def\uhandlecharacter#1{\csname#1\endcsname}
+
+\def\dontexpandencodedtokens
+ {\def\dohandleaccent {\uhandleaccent}%
+ \def\dohandlecommand {\uhandlecommand}%
+ \def\dohandlecharacter{\uhandlecharacter}}
+
+% no longer: \def\convertencodedtokens{\dontexpandencoding} but:
+
+\def\convertencodedtokens{\stringifyencodedtokens}
+
+% test case:
+%
+% \enableregime[cp1250]
+% \mainlanguage[cz]
+%
+% \starttext
+%
+% \title{Ϭuޯu餭 kon졺p
+% \placelist[chapter][criterium=all]
+%
+% \startbuffer
+%
+% Ϭuޯu餭 kon졺pitle>
+%
+% \stopbuffer
+%
+% \defineXMLenvironment
+% [chapter]
+% {\defineXMLsave[title]}
+% {\expanded{\chapter{\XMLflush{title}}}}
+% \processXMLbuffer
+%
+% \setuphead[chapter][expansion=yes]
+% \defineXMLenvironment
+% [chapter]
+% {\defineXMLsave[title]}
+% {\chapter{\XMLflush{title}}}
+% \processXMLbuffer
+%
+% \stoptext
+
+%D Still valid? To be checked:
+
+\def\doignoreaccent #1#2{\string#1\string#2}%
+\def\doignorecommand #1{\string#1}
+\def\doignorecharacter#1{\string#1}
+
+\def\ignoreencoding
+ {\let\dohandleaccent \doignoreaccent
+ \let\dohandlecommand \doignorecommand
+ \let\dohandlecharacter\doignorecharacter}
+
+\appendtoks
+ \ignoreencoding
+\to \everycleanupfeatures
+
+\appendtoks
+ \keepencodedtokens
+\to \everysafeexpanded
+
+%D Now we will not redefine any more, so:
+
+\let\normaldohandleaccent \dohandleaccent
+\let\normaldohandlecharacter\dohandlecharacter
+
+\definecommand ` {\buildtextaccent\textgrave}
+\definecommand ' {\buildtextaccent\textacute}
+\definecommand r {\buildtextaccent\textring}
+\definecommand v {\buildtextaccent\textcaron}
+\definecommand u {\buildtextaccent\textbreve}
+\definecommand = {\buildtextaccent\textmacron}
+\definecommand ^ {\buildtextaccent\textcircumflex}
+\definecommand . {\buildtextaccent\textdotaccent}
+\definecommand H {\buildtextaccent\texthungarumlaut}
+\definecommand ~ {\buildtextaccent\texttilde}
+\definecommand " {\buildtextaccent\textdiaeresis}
+
+\definecommand c {\buildtextcedilla}
+\definecommand b {\buildtextmacron}
+\definecommand d {\buildtextbottomdot}
+\definecommand k {\buildtextogonek}
+
+\definemathaccent acute {\buildmathaccent\mathacute}
+\definemathaccent grave {\buildmathaccent\mathgrave}
+\definemathaccent ddot {\buildmathaccent\mathddot}
+\definemathaccent tilde {\buildmathaccent\mathtilde}
+\definemathaccent bar {\buildmathaccent\mathbar}
+\definemathaccent breve {\buildmathaccent\mathbreve}
+\definemathaccent check {\buildmathaccent\mathcheck}
+\definemathaccent hat {\buildmathaccent\mathhat}
+\definemathaccent vec {\buildmathaccent\mathvec}
+\definemathaccent dot {\buildmathaccent\mathdot}
+\definemathaccent widetilde {\buildmathaccent\mathwidetilde}
+\definemathaccent widehat {\buildmathaccent\mathwidehat}
+
+\useencoding[def] % defaults (partly simplified)
+\useencoding[acc] % accent commands
+\useencoding[raw] % simplified (incomplete)
+\useencoding[com] % a few commands
+\useencoding[cas] % case mapping, not needed in mkiv
+\useencoding[mis] % a few commands
+
+%D We preload several encodings:
+
+\ifnum\texengine=\xetexengine
+ \setupencoding[\s!default=\s!default]
+\else
+ \useencoding[ans,il2,ec,tbo,pdf,pol,qx,t5,l7x,cyr,agr] % pol and il2 will go away, not needed in mkiv, uc removed
+ \useencoding[032,033,037] % fallbacks for some unicode chars
+ \setupencoding[\s!default=ec] % was: [\s!default=\s!default]
+\fi
+
+\protect \endinput
diff --git a/tex/context/base/enco-ini.mkiv b/tex/context/base/enco-ini.mkiv
new file mode 100644
index 000000000..da1892faf
--- /dev/null
+++ b/tex/context/base/enco-ini.mkiv
@@ -0,0 +1,536 @@
+%D \module
+%D [ file=enco-ini,
+%D version=2007.02.19, % 2000.12.27, % 1998.12.03,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Initialization,
+%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.
+
+%D This is stripped down version of th eoriginal enco-ini.tex
+%D file. For more details you might want to study the \MKII\ file
+%D but since \LUATEX\ is unicode inside we need less code.
+
+% When dealing with characters we have four cases to take into account
+% when moving from mkii to mkiv:
+
+% 1. => ref to slot 200 in current font
+% 2. \char 200 => ref to slot 200 in current font
+% 3. => can (e.g.) map to another slot in current font
+% 4. \namedglyph => can map to some slot in some font
+
+% Using case 2 for special characters is doomed to fail because we are not going
+% to intercept these on the fly as happens automatically with traditional font
+% encoding handling. We could do that in a node pass but it's not worth the effort
+% because we seldom use this case in a document source.
+
+% We can consider using utf as internal format for mkii. The main reason for not
+% doing this before was that it was slow. On the other hand, it would make dealing
+% with utility files easier. However, we've now kind of frozen mkii.
+
+\writestatus{loading}{ConTeXt Encoding Macros / Initialization}
+
+\unprotect
+
+%D Quite some commands are now obsolete. We keep only a few commands
+%D around, just in case they are used in styles (and in for instance
+%D symb and xtag files).
+
+\unexpanded\def\startencoding [#1]{} % used in symb
+\let\stopencoding \relax
+\unexpanded\def\setupencoding [#1]{}
+\def\enablemapping [#1]{}
+\def\enableencoding[#1]{}
+
+\def\currentencoding{utf}
+\def\currentmapping {utf}
+\let\defaultencoding\s!default
+
+% todo:
+
+% \def\showaccents {\f!encodingprefix\s!run}
+% \def\showcharacters {\f!encodingprefix\s!run}
+% \def\showcharacterbounds {\f!encodingprefix\s!run}
+% \def\showhyphenations {\f!encodingprefix\s!run}
+% \def\showmapping {\f!encodingprefix\s!run}
+
+%D \macros
+%D {defineaccent, definecharacter, definecommand}
+
+\unexpanded\def\defineaccent#1 #2 #3 %
+ {\setevalue{\string#1}{\noexpand\dohandleaccent{\string#1}}%
+ \setvalue{\??ac\string#1\string#2}{#3}}
+
+\def\dohandleaccent#1#2%
+ {\csname\??ac\string#1\string#2\empty\endcsname}
+
+\unexpanded\def\definecharacter#1 #2 %
+ {\doifnumberelse{\string#2}
+ {\setevalue{\string#1}{\utfchar{#2}}} % or {\expandafter\chardef\csname#1\endcsname#2\relax}
+ {\setuvalue {\string#1}{#2}}}
+
+\unexpanded\def\definecommand#1 #2 %
+ {\setuvalue{\string#1}{#2}}
+
+%D \macros
+%D {everyuppercase, EveryUppercase,
+%D everyuppercase, EveryUppercase,
+%D everysanitize, EverySanitize}
+
+\newevery \everyuppercase \EveryUppercase
+\newevery \everylowercase \EveryLowercase
+\newevery \everysanitize \EverySanitize
+
+%D Some saved meanings (not really needed):
+
+\let\textaccent \accent
+\let\normaltextaccent\accent
+
+%D Accent handling (try to avoid this):
+
+\newbox\accenttestbox
+
+\def\buildmathaccent#1%
+ {\mathaccent#1 }
+
+\unexpanded\def\buildtextaccent#1#2%
+ {\begingroup
+ \global\setbox\accenttestbox\hbox{#1}%
+ \scratchcounter\ctxlua{characters.charcode(\number\accenttestbox)}%
+ \ifcase\scratchcounter\else\accent\scratchcounter\fi
+ \relax#2%
+ \endgroup}
+
+\unexpanded\def\bottomaccent#1#2#3#4#5% down right slantcorrection accent char
+ {\dontleavehmode % why this align mess
+ \vtop
+ {\forgetall
+ \baselineskip\zeropoint
+ \lineskip#1%
+ \everycr\emptytoks
+ \tabskip\zeropoint
+ \lineskiplimit\zeropoint
+ \setbox0\hbox{#4}%
+ \halign
+ {##\crcr\hbox{#5}\crcr
+ \hidewidth
+ \hskip#2\wd0
+ \hskip-#3\slantperpoint % in plain 1ex * dimenless value
+ \vbox to .2ex{\box0\vss}\hidewidth
+ \crcr}}}
+
+\unexpanded\def\buildtextmacron {\bottomaccent{.25ex}{0}{15}{\textmacron}}
+\unexpanded\def\buildtextbottomdot {\bottomaccent{.25ex}{0}{5}{\textbottomdot}}
+\unexpanded\def\buildtextcedilla {\bottomaccent{0ex}{0}{5}{\textcedilla}}
+\unexpanded\def\buildtextogonek {\bottomaccent{-.1ex}{.5}{0}{\textogonek}}
+\unexpanded\def\buildtextbottomcomma{\bottomaccent{.15ex}{0}{5}{\tx,}}
+
+\let\d\buildtextbottomdot
+
+\unexpanded\def\topaccent#1#2#3#4#5% down right slantcorrection accent char
+ {\dontleavehmode
+ \bgroup
+ \setbox0\hbox{#4}%
+ \setbox2\hbox{#5}%
+ \hbox to \wd2 \bgroup
+ \hss\copy2\hss
+ \hskip-\wd2
+ \hss\hskip#2\wd0\hskip-#3\slantperpoint\raise#1\hbox{#4}\hss
+ \egroup
+ \egroup}
+
+\def\buildtextgrave{\topaccent{0pt}{0}{15}{\textgrave}} % e.g.
+
+\unexpanded\def\definemathaccent#1 #2%
+ {\setvalue{#1}{\mathaccent#2 }}
+
+%D Math (will move):
+
+\definemathaccent acute \mathacute
+\definemathaccent grave \mathgrave
+\definemathaccent ddot \mathddot
+\definemathaccent tilde \mathtilde
+\definemathaccent bar \mathbar
+\definemathaccent breve \mathbreve
+\definemathaccent check \mathcheck
+\definemathaccent hat \mathhat
+\definemathaccent vec \mathvec
+\definemathaccent dot \mathdot
+\definemathaccent widetilde \mathwidetilde
+\definemathaccent widehat \mathwidehat
+
+% from enco-com:
+
+\def\AA{\Aring}
+\def\aa{\aring}
+\def\AE{\AEligature}
+\def\ae{\aeligature}
+\def\CC{\Ccedilla}
+\def\cc{\ccedilla}
+\def \L{\Lstroke}
+\def \l{\lstroke}
+\def \O{\Ostroke}
+\def \o{\ostroke}
+\def\OE{\OEligature}
+\def\oe{\oeligature}
+\def\SZ{\Ssharp}
+\def\sz{\ssharp}
+\def\SS{\ssharp}
+\def\IJ{\IJligature}
+\def\ij{\ijligature}
+\def \i{\dotlessi}
+\def \j{\dotlessj}
+
+% from enco-def:
+
+\def\dotlessI {I}
+\def\dotlessJ {J}
+
+\def\Ssharp {SS}
+
+\def\eszett {\ssharp}
+\def\Eszett {\Ssharp}
+
+\def\lslash {\lstroke}
+\def\Lslash {\Lstroke}
+\def\dslash {\dstroke}
+\def\Dslash {\Dstroke}
+\def\oslash {\ostroke}
+\def\Oslash {\Ostroke}
+\def\dcroat {\dstroke}
+\def\Dcroat {\Dstroke}
+
+\def\Kcedilla {\Kcommaaccent}
+\def\kcedilla {\kcommaaccent}
+\def\Lcedilla {\Lcommaaccent}
+\def\lcedilla {\lcommaaccent}
+\def\Ncedilla {\Ncommaaccent}
+\def\ncedilla {\ncommaaccent}
+\def\Rcedilla {\Rcommaaccent}
+\def\rcedilla {\rcommaaccent}
+
+\def\S {\sectionmark}
+\def\P {\paragraphmark}
+
+\def\aumlaut {\adiaeresis}
+\def\eumlaut {\ediaeresis}
+\def\iumlaut {\idiaeresis}
+\def\oumlaut {\odiaeresis}
+\def\uumlaut {\udiaeresis}
+\def\Aumlaut {\Adiaeresis}
+\def\Eumlaut {\Ediaeresis}
+\def\Iumlaut {\Idiaeresis}
+\def\Oumlaut {\Odiaeresis}
+\def\Uumlaut {\Udiaeresis}
+
+% for latex users
+
+\def\textS {\sectionmark}
+\def\textP {\paragraphmark}
+
+% for old times sake
+
+\def\textflorin{\fhook}
+\def\florin {\textflorin}
+\def\dollar {\textdollar}
+\def\pound {\textsterling}
+\def\sterling {\textsterling}
+\def\promille {\perthousand}
+\def\permille {\perthousand}
+\def\procent {\percent}
+\def\permine {\fakepermine}
+
+% some more
+
+\def\hyphen {\softhyphen}
+\def\compoundwordmark {\hyphen}
+\def\cwm {\hyphen}
+\def\nonbreakinghyphen{\hyphen}
+\def\breakinghyphen {\hyphen\prewordbreak}
+
+% quotes
+
+\def\lowerleftsingleninequote {\quotesinglebase}
+\def\lowerleftdoubleninequote {\quotedblbase}
+\def\lowerrightsingleninequote {\quotesinglebase}
+\def\lowerrightdoubleninequote {\quotedblbase}
+
+\def\upperleftsingleninequote {\quoteright}
+\def\upperleftdoubleninequote {\quotedblright}
+\def\upperrightsingleninequote {\quoteright}
+\def\upperrightdoubleninequote {\quotedblright}
+
+\def\upperleftsinglesixquote {\quoteleft}
+\def\upperleftdoublesixquote {\quotedblleft}
+\def\upperrightsinglesixquote {\quoteleft}
+\def\upperrightdoublesixquote {\quotedblleft}
+
+\def\leftsubguillemot {\guilsingleleft}
+\def\rightsubguillemot {\guilsingleright}
+
+% obsolete:
+
+% \greekleftquot {[obsolete]}
+% \greekrightquot {[obsolete]}
+% \greekapostrophos {[obsolete]}
+% \greekupsilondialytika{[obsolete]}
+% \Ycaron {[obsolete]}
+% \ycaron {[obsolete]}
+
+% to be done in char-def:
+
+% \definecharacter cyrillicGUP {GUP}
+% \definecharacter cyrillicGHCRS {GHCRS}
+% \definecharacter cyrillicZHDSC {ZHDSC}
+% \definecharacter cyrillicKDSC {KDSC}
+% \definecharacter cyrillicKBEAK {KBEAK}
+% \definecharacter cyrillicKVCRS {KVCRS}
+% \definecharacter cyrillicNG {NG}
+% \definecharacter cyrillicOTLD {OTLD}
+% \definecharacter cyrillicY {Y}
+% \definecharacter cyrillicYHCRS {YHCRS}
+% \definecharacter cyrillicHDSC {HDSC}
+% \definecharacter cyrillicCHVCRS {CHVCRS}
+% \definecharacter cyrillicCHRDSC {CHRDSC}
+% \definecharacter cyrillicQ {Q}
+% \definecharacter cyrillicW {W}
+%
+% \definecharacter cyrillicgup {gup}
+% \definecharacter cyrillicghcrs {ghcrs}
+% \definecharacter cyrilliczhdsc {zhdsc}
+% \definecharacter cyrillickdsc {kdsc}
+% \definecharacter cyrillickbeak {kbeak}
+% \definecharacter cyrillickvcrs {kvcrs}
+% \definecharacter cyrillicng {ng}
+% \definecharacter cyrillicotld {otld}
+% \definecharacter cyrillicy {y}
+% \definecharacter cyrillicyhcrs {yhcrs}
+% \definecharacter cyrillichdsc {hdsc}
+% \definecharacter cyrillicchvcrs {chvcrs}
+% \definecharacter cyrillicchrdsc {chrdsc}
+% \definecharacter cyrillicq {q}
+% \definecharacter cyrillicw {w}
+
+% \definecharacter softhyphen 45
+% \definecharacter compoundwordmark 23
+
+% left-overs (some day in private unicode space, so that we can roundtrip)
+
+\unexpanded\def\textblacksquare {\dontleavehmode\hbox{\vrule\!!width.3\s!em\!!height.4\s!em\!!depth-.1\s!em}}
+\unexpanded\def\schwa {\hbox{\rotate[\c!rotation=180,\c!location=\v!high]{\hbox{e}}}}
+\unexpanded\def\schwagrave {\buildtextgrave\schwa}
+
+\chardef\textcontrolspace"2423
+
+\unexpanded\def\fallbackcontrolspace
+ %{\getglyph{ComputerModernMono}\textcontrolspace}
+ {\getglyph{LMTypewriter10-Regular}\textcontrolspace}
+
+\unexpanded\def\normalcontrolspace
+ {\iffontchar\font\textcontrolspace
+ \textcontrolspace
+ \else
+ \fallbackcontrolspace
+ \fi}
+
+\let\textvisiblespace\normalcontrolspace
+
+\unexpanded\def\fastcontrolspace % no glyph resolving after first (use grouped)
+ {\dofastcontrolspace}
+
+\def\dofastcontrolspace
+ {\iffontchar\font\textcontrolspace
+ \nofastfallbackcontrolspace
+ \else
+ \dofastfallbackcontrolspace
+ \fi
+ \dofastcontrolspace}
+
+\newbox\controlspacebox
+
+\def\nofastfallbackcontrolspace
+ {\let\dofastcontrolspace\textcontrolspace}
+
+\def\dofastfallbackcontrolspace
+ {\setbox\controlspacebox\hbox{\space}%
+ \setbox\controlspacebox\hbox to \wd\controlspacebox{\hss\fallbackcontrolspace\hss}%
+ \let\dofastcontrolspace\flushcontrolspacebox}
+
+\def\flushcontrolspacebox
+ {\copy\controlspacebox}
+
+% a few defaults (\{}), we really need the verbose \empty as it will be
+% stringified
+
+\defineaccent ^ {\empty} {\textcircumflex}
+\defineaccent ` {\empty} {\textgrave}
+\defineaccent ~ {\empty} {\texttilde}
+\defineaccent " {\empty} {\textdiaeresis}
+\defineaccent ' {\empty} {\textacute}
+\defineaccent . {\empty} {\textdotaccent}
+\defineaccent = {\empty} {\textmacron}
+\defineaccent c {\empty} {\textcedilla}
+\defineaccent H {\empty} {\texthungarumlaut}
+\defineaccent k {\empty} {\textogonek}
+\defineaccent r {\empty} {\textring}
+\defineaccent u {\empty} {\textbreve}
+\defineaccent v {\empty} {\textcaron}
+
+% from enco-acc:
+%
+% we should to this at the lua end and share code ..
+
+\defineaccent ^ A {\Acircumflex} \defineaccent ^ a {\acircumflex}
+\defineaccent ^ C {\Ccircumflex} \defineaccent ^ c {\ccircumflex}
+\defineaccent ^ E {\Ecircumflex} \defineaccent ^ e {\ecircumflex}
+\defineaccent ^ G {\Gcircumflex} \defineaccent ^ g {\gcircumflex}
+\defineaccent ^ H {\Hcircumflex} \defineaccent ^ h {\hcircumflex}
+\defineaccent ^ I {\Icircumflex} \defineaccent ^ i {\icircumflex} \defineaccent ^ {\i} {\icircumflex}
+\defineaccent ^ J {\Jcircumflex} \defineaccent ^ j {\jcircumflex} \defineaccent ^ {\j} {\jcircumflex}
+\defineaccent ^ O {\Ocircumflex} \defineaccent ^ o {\ocircumflex}
+\defineaccent ^ S {\Scircumflex} \defineaccent ^ s {\scircumflex}
+\defineaccent ^ U {\Ucircumflex} \defineaccent ^ u {\ucircumflex}
+\defineaccent ^ W {\Wcircumflex} \defineaccent ^ w {\wcircumflex}
+\defineaccent ^ Y {\Ycircumflex} \defineaccent ^ y {\ycircumflex}
+
+\defineaccent ` A {\Agrave} \defineaccent ` a {\agrave}
+\defineaccent ` E {\Egrave} \defineaccent ` e {\egrave}
+\defineaccent ` I {\Igrave} \defineaccent ` i {\igrave} \defineaccent ` {\i} {\igrave}
+\defineaccent ` O {\Ograve} \defineaccent ` o {\ograve}
+\defineaccent ` U {\Ugrave} \defineaccent ` u {\ugrave}
+\defineaccent ` Y {\Ygrave} \defineaccent ` y {\ygrave}
+
+\defineaccent ~ A {\Atilde} \defineaccent ~ a {\atilde}
+\defineaccent ~ I {\Itilde} \defineaccent ~ i {\itilde} \defineaccent ~ {\i} {\itilde}
+\defineaccent ~ O {\Otilde} \defineaccent ~ o {\otilde}
+\defineaccent ~ U {\Utilde} \defineaccent ~ u {\utilde}
+\defineaccent ~ N {\Ntilde} \defineaccent ~ n {\ntilde}
+
+\defineaccent " A {\Adiaeresis} \defineaccent " a {\adiaeresis}
+\defineaccent " E {\Ediaeresis} \defineaccent " e {\ediaeresis}
+\defineaccent " I {\Idiaeresis} \defineaccent " i {\idiaeresis} \defineaccent " {\i} {\idiaeresis}
+\defineaccent " O {\Odiaeresis} \defineaccent " o {\odiaeresis}
+\defineaccent " U {\Udiaeresis} \defineaccent " u {\udiaeresis}
+\defineaccent " Y {\Ydiaeresis} \defineaccent " y {\ydiaeresis}
+
+\defineaccent ' A {\Aacute} \defineaccent ' a {\aacute}
+\defineaccent ' C {\Cacute} \defineaccent ' c {\cacute}
+\defineaccent ' E {\Eacute} \defineaccent ' e {\eacute}
+\defineaccent ' I {\Iacute} \defineaccent ' i {\iacute} \defineaccent ' {\i} {\iacute}
+\defineaccent ' L {\Lacute} \defineaccent ' l {\lacute}
+\defineaccent ' N {\Nacute} \defineaccent ' n {\nacute}
+\defineaccent ' O {\Oacute} \defineaccent ' o {\oacute}
+\defineaccent ' R {\Racute} \defineaccent ' r {\racute}
+\defineaccent ' S {\Sacute} \defineaccent ' s {\sacute}
+\defineaccent ' U {\Uacute} \defineaccent ' u {\uacute}
+\defineaccent ' Y {\Yacute} \defineaccent ' y {\yacute}
+\defineaccent ' Z {\Zacute} \defineaccent ' z {\zacute}
+
+\defineaccent . C {\Cdotaccent} \defineaccent . c {\cdotaccent}
+\defineaccent . E {\Edotaccent} \defineaccent . e {\edotaccent}
+\defineaccent . G {\Gdotaccent} \defineaccent . g {\gdotaccent}
+\defineaccent . I {\Idotaccent} \defineaccent . i {\idotaccent} \defineaccent . {\i} {\idotaccent}
+\defineaccent . Z {\Zdotaccent} \defineaccent . z {\zdotaccent}
+
+\defineaccent = A {\Amacron} \defineaccent = a {\amacron}
+\defineaccent = E {\Emacron} \defineaccent = e {\emacron}
+\defineaccent = I {\Imacron} \defineaccent = i {\imacron} \defineaccent = {\i} {\imacron}
+\defineaccent = O {\Omacron} \defineaccent = o {\omacron}
+\defineaccent = U {\Umacron} \defineaccent = u {\umacron}
+
+\defineaccent c C {\Ccedilla} \defineaccent c c {\ccedilla}
+\defineaccent c K {\Kcedilla} \defineaccent c k {\kcedilla}
+\defineaccent c L {\Lcedilla} \defineaccent c l {\lcedilla}
+\defineaccent c N {\Ncedilla} \defineaccent c n {\ncedilla}
+\defineaccent c R {\Rcedilla} \defineaccent c r {\rcedilla}
+\defineaccent c S {\Scedilla} \defineaccent c s {\scedilla}
+\defineaccent c T {\Tcedilla} \defineaccent c t {\tcedilla}
+
+\defineaccent H O {\Ohungarumlaut} \defineaccent H o {\ohungarumlaut}
+\defineaccent H u {\uhungarumlaut} \defineaccent H U {\Uhungarumlaut}
+
+\defineaccent k A {\Aogonek} \defineaccent k a {\aogonek}
+\defineaccent k E {\Eogonek} \defineaccent k e {\eogonek}
+\defineaccent k I {\Iogonek} \defineaccent k i {\iogonek}
+\defineaccent k U {\Uogonek} \defineaccent k u {\uogonek}
+
+\defineaccent r A {\Aring} \defineaccent r a {\aring}
+\defineaccent r U {\Uring} \defineaccent r u {\uring}
+
+\defineaccent u A {\Abreve} \defineaccent u a {\abreve}
+\defineaccent u E {\Ebreve} \defineaccent u e {\ebreve}
+\defineaccent u G {\Gbreve} \defineaccent u g {\gbreve}
+\defineaccent u I {\Ibreve} \defineaccent u i {\ibreve} \defineaccent u {\i} {\ibreve}
+\defineaccent u O {\Obreve} \defineaccent u o {\obreve}
+\defineaccent u U {\Ubreve} \defineaccent u u {\ubreve}
+
+\defineaccent v C {\Ccaron} \defineaccent v c {\ccaron}
+\defineaccent v D {\Dcaron} \defineaccent v d {\dcaron}
+\defineaccent v E {\Ecaron} \defineaccent v e {\ecaron}
+\defineaccent v L {\Lcaron} \defineaccent v l {\lcaron}
+\defineaccent v N {\Ncaron} \defineaccent v n {\ncaron}
+\defineaccent v R {\Rcaron} \defineaccent v r {\rcaron}
+\defineaccent v S {\Scaron} \defineaccent v s {\scaron}
+\defineaccent v T {\Tcaron} \defineaccent v t {\tcaron}
+\defineaccent v Z {\Zcaron} \defineaccent v z {\zcaron}
+
+% from enco-mis:
+
+\def\fakepercent
+ {\mathematics{^{\scriptscriptstyle0}\kern-.25em/\kern-.2em_{\scriptscriptstyle0}}}
+
+\def\fakeperthousand
+ {\mathematics{^{\scriptscriptstyle0}\kern-.25em/\kern-.2em_{\scriptscriptstyle00}}}
+
+\def\fakepermine
+ {\dontleavehmode
+ \bgroup
+ \setbox\scratchbox\hbox
+ {\mathematics{+}}%
+ \hbox to \wd\scratchbox
+ {\hss
+ \mathematics{^{\scriptscriptstyle-}\kern-.4em/\kern-.3em_{\scriptscriptstyle-}}%
+ \hss}%
+ \egroup}
+
+%D A smaller and bolder variant, more like the math and monospaced ones.
+
+% \def\fakeunderscore
+% {\dontleavehmode\hbox % was \leavevmode
+% {\setbox\scratchbox\hbox{(}%
+% \scratchdimen.2\dp\scratchbox
+% \setbox\scratchbox\hbox{\space}%
+% \vrule
+% \!!depth \scratchdimen
+% \!!width \wd\scratchbox
+% \!!height\zeropoint}}
+
+% \startTEXpage
+% \ruledhbox{\strut$1\fakeunderscore^{1\fakeunderscore}$}
+% \ruledhbox{\strut$1\xfakeunderscore^{1\xfakeunderscore}$}
+% \stopTEXpage
+
+\def\fakeunderscore
+ {\relax\ifmmode
+ \vrule\!!depth .12\fontexheight\mathstylefont\normalmathstyle\!!width \fontinterwordspace\mathstylefont\normalmathstyle\!!height\zeropoint\relax
+ \else
+ \dontleavehmode\hbox{\vrule\!!depth .12\fontexheight\font\!!width \fontinterwordspace\font\!!height\zeropoint}%
+ \fi}
+
+\def\fakeunderscores{\let\_\fakeunderscore}
+\def\textunderscores{\let\_\textunderscore}
+
+\textunderscores
+
+\ifx\mathunderscore\undefined \let\mathunderscore\fakeunderscore \fi
+\ifx\textunderscore\undefined \let\textunderscore\fakeunderscore \fi
+
+\unexpanded\def\normalunderscore{\ifmmode\mathunderscore\else\textunderscore\fi}
+
+\let\_\normalunderscore
+
+\protect \endinput
diff --git a/tex/context/base/enco-l7x.mkii b/tex/context/base/enco-l7x.mkii
new file mode 100644
index 000000000..8f355317b
--- /dev/null
+++ b/tex/context/base/enco-l7x.mkii
@@ -0,0 +1,236 @@
+%D \module
+%D [ file=enco-l7x,
+%D version=2010.01.22,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=\LATEX\ L7x Encoding,
+%D author={Hans Hagen \& Mojca Miklavec},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Encoding vector to support Latvian and Lithuanian. The first
+%D part is taken from EC encoding, the rest has not been tested
+%D extensively.
+
+\startmapping[l7x]
+
+\definecaseswap 25 `I % dotless i (TODO - probably wrong; maybe use \defineuppercasecom)
+\definecaseswap 156 140 % oeligature
+\definecaseswap 184 168 % ostroke
+\definecaseswap 186 170 % rcommaaccent
+\definecaseswap 191 175 % aeligature
+\definecaseself 223 % ssharp (this is wrong, but no better way)
+
+\definecasemaps 192 to 222 lc +32 uc 0
+\definecasemaps 224 to 254 lc 0 uc -32
+\resetcaserange 215 to 215 % textmultiply
+\resetcaserange 247 to 247 % textdiv
+
+\stopmapping
+
+\startencoding[l7x]
+
+\definecharacter textgrave 0
+\definecharacter textacute 1
+\definecharacter textcircumflex 2
+\definecharacter texttilde 3
+\definecharacter textdiaeresis 4
+\definecharacter texthungarumlaut 5
+\definecharacter textring 6
+\definecharacter textcaron 7
+\definecharacter textbreve 8
+\definecharacter textmacron 9
+\definecharacter textdotaccent 10
+\definecharacter textcedilla 11
+\definecharacter textogonek 12
+\definecharacter quotesinglebase 13
+\definecharacter guilsingleleft 14
+\definecharacter guilsingleright 15
+\definecharacter quotedblleft 16
+\definecharacter quotedblright 17
+\definecharacter quotedblbase 18
+\definecharacter leftguillemot 19
+\definecharacter rightguillemot 20
+\definecharacter endash 21
+\definecharacter emdash 22
+%definecharacter compoundwordmark 23
+%definecharacter perthousand 24
+\definecharacter dotlessi 25 % or when missing: {j}
+\definecharacter dotlessj 26
+% ff 27
+% fi 28
+% fl 29
+% ffi 30
+% ffl 31
+%definecharacter textvisiblespace 32
+% exclam ! 33
+\definecharacter quotedbl 34
+% numbersign # 35
+% dollar $ 36
+\definecharacter percent 37
+% ampersand & 38
+%definecharacter quotesingle 39 % fake 'm TODO:enco-def!!!!
+\definecharacter quoteright 39
+% parenleft ( 40
+% parenright ) 41
+% asterisk * 42
+% plus + 43
+% comma , 44
+\definecharacter softhyphen 45
+% period . 46
+% slash / 47
+% 0-9 48-57
+% colon : 58
+% semicolon ; 59
+% less < 60
+% equal = 61
+% greater > 62
+% question ? 63
+% at @ 64
+% A-Z 65-90
+% bracketleft [ 91
+\definecharacter textbackslash 92
+% bracketright ] 93
+\definecharacter textasciicircum 94
+\definecharacter textunderscore 95
+\definecharacter quoteleft 96
+% a-z 97-122
+\definecharacter textbraceleft 123
+\definecharacter textbraceright 125
+\definecharacter textasciitilde 126
+% .notdef 127
+\definecharacter texteuro 128
+% .notdef 129
+\definecharacter quotesinglebase 130
+\definecharacter textflorin 131 \definecharacter fhook 131
+\definecharacter quotedblbase 132
+\definecharacter textellipsis 133
+\definecharacter textdag 134
+\definecharacter textddag 135
+% .notdef 136
+\definecharacter perthousand 137
+% .notdef 138
+\definecharacter guilsingleleft 139
+\definecharacter OEligature 140 % TODO: also \OE???
+\definecharacter textdiaeresis 141
+\definecharacter textcaron 142
+\definecharacter textcedilla 143
+% .notdef 144
+\definecharacter quoteleft 145
+\definecharacter quoteright 146
+\definecharacter quotedblleft 147
+\definecharacter quotedblright 148
+\definecharacter textbullet 149
+\definecharacter endash 150
+\definecharacter emdash 151
+% .notdef 152
+\definecharacter trademark 153
+% .notdef 154
+\definecharacter guilsingleright 155
+\definecharacter oeligature 156
+\definecharacter textmacron 157
+\definecharacter textogonek 158
+% .notdef 159
+%definecharacter space 160 % TODO!!!
+\definecharacter quotedblright 161
+\definecharacter textcent 162
+\definecharacter textsterling 163
+\definecharacter textcurrency 164
+\definecharacter quotedblbase 165
+\definecharacter textbrokenbar 166
+\definecharacter sectionmark 167
+\definecharacter Ostroke 168
+\definecharacter copyright 169
+\definecharacter Rcommaaccent 170
+\definecharacter leftguillemot 171
+\definecharacter textlognot 172
+%definecharacter softhyphen 173 % -> 45 (TODO!!!)
+\definecharacter registered 174
+\definecharacter AEligature 175
+\definecharacter textdegree 176
+\definecharacter textpm 177
+\definecharacter twosuperior 178
+\definecharacter threesuperior 179
+\definecharacter quotedblleft 180
+\definecharacter textmu 181
+\definecharacter paragraphmark 182
+\definecharacter periodcentered 183
+\definecharacter ostroke 184
+\definecharacter onesuperior 185
+\definecharacter rcommaaccent 186
+\definecharacter rightguillemot 187
+\definecharacter onequarter 188
+\definecharacter onehalf 189
+\definecharacter threequarter 190
+\definecharacter aeligature 191
+\definecharacter Aogonek 192
+\definecharacter Iogonek 193
+\definecharacter Amacron 194
+\definecharacter Cacute 195
+\definecharacter Adiaeresis 196
+\definecharacter Aring 197
+\definecharacter Eogonek 198
+\definecharacter Emacron 199
+\definecharacter Ccaron 200
+\definecharacter Eacute 201
+\definecharacter Zacute 202
+\definecharacter Edotaccent 203
+\definecharacter Gcommaaccent 204
+\definecharacter Kcommaaccent 205
+\definecharacter Imacron 206
+\definecharacter Lcommaaccent 207
+\definecharacter Scaron 208
+\definecharacter Nacute 209
+\definecharacter Ncommaaccent 210
+\definecharacter Oacute 211
+\definecharacter Omacron 212
+\definecharacter Otilde 213
+\definecharacter Odiaeresis 214
+\definecharacter textmultiply 215
+\definecharacter Uogonek 216
+\definecharacter Lstroke 217
+\definecharacter Sacute 218
+\definecharacter Umacron 219
+\definecharacter Udiaeresis 220
+\definecharacter Zdotaccent 221
+\definecharacter Zcaron 222
+\definecharacter ssharp 223
+\definecharacter aogonek 224
+\definecharacter iogonek 225
+\definecharacter amacron 226
+\definecharacter cacute 227
+\definecharacter adiaeresis 228
+\definecharacter aring 229
+\definecharacter eogonek 230
+\definecharacter emacron 231
+\definecharacter ccaron 232
+\definecharacter eacute 233
+\definecharacter zacute 234
+\definecharacter edotaccent 235
+\definecharacter gcommaaccent 236
+\definecharacter kcommaaccent 237
+\definecharacter imacron 238
+\definecharacter lcommaaccent 239
+\definecharacter scaron 240
+\definecharacter nacute 241
+\definecharacter ncommaaccent 242
+\definecharacter oacute 243
+\definecharacter omacron 244
+\definecharacter otilde 245
+\definecharacter odiaeresis 246
+\definecharacter textdiv 247
+\definecharacter uogonek 248
+\definecharacter lstroke 249
+\definecharacter sacute 250
+\definecharacter umacron 251
+\definecharacter udiaeresis 252
+\definecharacter zdotaccent 253
+\definecharacter zcaron 254
+\definecharacter quoteright 255
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-lat.mkii b/tex/context/base/enco-lat.mkii
new file mode 100644
index 000000000..2623aae8d
--- /dev/null
+++ b/tex/context/base/enco-lat.mkii
@@ -0,0 +1,7 @@
+% temporary module, needed for downward compatibility
+
+\input regi-lat.tex
+
+\enableregime[latin2]
+
+\endinput
diff --git a/tex/context/base/enco-mis.mkii b/tex/context/base/enco-mis.mkii
new file mode 100644
index 000000000..92dc61b3f
--- /dev/null
+++ b/tex/context/base/enco-mis.mkii
@@ -0,0 +1,188 @@
+%D \module
+%D [ file=enco-mis,
+%D version=2000.05.07, % 1999.11.11,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Missing Glyphs,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D In this file we collect some definitions that construct
+%D pseudo characters. Some day we will move some definitions
+%D from \type {plain.tex} to this file. Some definitions are
+%D derived from definitions in the \LATEX\ distribution,
+%D especially Johannes Braams' Babel system.
+
+\startmapping[\s!default]
+
+\defineuppercasecom \dj \DJ
+\defineuppercasecom \Dj \dj
+\defineuppercasecom \DJ \dj
+
+\definecharacter dstroke {\pseudoencodeddj}
+\definecharacter Dstroke {\pseudoencodedDJ}
+
+\stopmapping
+
+%D We need proper names like in enco-com.tex!
+
+\definecharacter dj {\dstroke} % {\pseudoencodeddj}
+\definecharacter Dj {\Dstroke} % {\pseudoencodedDJ}
+\definecharacter DJ {\Dstroke} % {\pseudoencodedDJ}
+
+\unprotect
+
+\def\pseudoencodeddj % like in babel, but safer
+ {\dontleavehmode\hbox\bgroup
+ \setbox\scratchbox\hbox{d}%
+ \scratchdimen\ht\scratchbox
+ \advance\scratchdimen 1ex
+ \scratchdimen.45\scratchdimen
+ \dimen2=\withoutpt\the\slantperpoint\dimen0
+ \advance\dimen2 .5ex
+ \hbox to \wd\scratchbox
+ {\box\scratchbox\hss
+ \raise\scratchdimen\hbox{\kern\dimen2\vbox{\hrule\!!height0.1ex\!!width0.3em}}}%
+ \egroup}
+
+\def\pseudoencodedDJ % design: taco; quality assurance: mojca; cleanup: hans
+ {\dontleavehmode
+ \hbox\bgroup
+ \setbox\scratchbox\hbox{D}%
+ \dimen2=1.1ex
+ \dimen2=\withoutpt\the\slantperpoint\dimen2
+ \hbox to \wd\scratchbox
+ {\rlap
+ {\raise.52\ht\scratchbox
+ \hbox
+ {\kern\dimen2
+ \vbox{\hrule\!!height.04ex\!!depth.04ex\!!width.4\wd\scratchbox}}}%
+ \box\scratchbox}%
+ \egroup}
+
+% currency
+
+\def\fakedollar % pretty cmr dependent
+ {\bgroup
+ \ifnum\fam=\itfam
+ \sl
+ \else\ifnum\fam=\bifam
+ \bs
+ \fi\fi
+ \$%
+ \egroup}
+
+\def\fakesterling % pretty cmr dependent
+ {\bgroup
+ \ifnum\fam=\bffam
+ \bi
+ \else\ifnum\fam=\bifam
+ \bi
+ \else\ifnum\fam=\bsfam
+ \bi
+ \else
+ \it
+ \fi\fi\fi
+ \$%
+ \egroup}
+
+\def\fakeflorin
+ {\bgroup
+ \ifnum\fam=\bffam
+ \bi
+ \else\ifnum\fam=\bifam
+ \bi
+ \else\ifnum\fam=\bsfam
+ \bi
+ \else
+ \it
+ \fi\fi\fi
+ f%
+ \egroup}
+
+% perthings
+
+\def\fakepercent
+ {\mathematics{^{\scriptscriptstyle0}\kern-.25em/\kern-.2em_{\scriptscriptstyle0}}}
+
+\def\fakeperthousand
+ {\mathematics{^{\scriptscriptstyle0}\kern-.25em/\kern-.2em_{\scriptscriptstyle00}}}
+
+\def\fakepermine
+ {\dontleavehmode
+ \bgroup
+ \setbox\scratchbox\hbox
+ {\mathematics{+}}%
+ \hbox to \wd\scratchbox
+ {\hss
+ \mathematics{^{\scriptscriptstyle-}\kern-.4em/\kern-.3em_{\scriptscriptstyle-}}%
+ \hss}%
+ \egroup}
+
+% guillemots
+
+%D Yes I know, they are ugly:
+
+\def\fakeleftguillemot
+ {\dontleavehmode\hbox{\raise.25ex\hbox{$\scriptscriptstyle\ll$}}}
+
+\def\fakerightguillemot
+ {\hbox{\raise.25ex\hbox{$\scriptscriptstyle\gg$}}}
+
+\def\fakeleftsubguillemot
+ {\dontleavehmode\hbox{\raise.25ex\hbox{$\scriptscriptstyle<$}}}
+
+\def\fakerightsubguillemot
+ {\hbox{\raise.25ex\hbox{$\scriptscriptstyle>$}}}
+
+%D Needed:
+
+\def\fakevisiblespace
+ {\leavevmode\hbox
+ {\setbox\scratchbox\hbox{(}%
+ \scratchdimen.1\dp\scratchbox
+ \setbox\scratchbox\hbox{\space}%
+ \hbox to \wd\scratchbox
+ {\vrule
+ \!!depth 5\scratchdimen
+ \!!width \scratchdimen
+ \!!height \zeropoint
+ \hss
+ \vrule
+ \!!depth 5\scratchdimen
+ \!!width \wd\scratchbox
+ \!!height-4\scratchdimen
+ \hss
+ \vrule
+ \!!depth 5\scratchdimen
+ \!!width \scratchdimen
+ \!!height \zeropoint}}}
+
+%\def\fakeunderscore{\leavevmode\kern.06em\vbox{\hrule\!!width.3em}}
+
+\def\fakeunderscore
+ {\leavevmode\hbox
+ {\setbox\scratchbox\hbox{(}%
+ \scratchdimen.2\dp\scratchbox
+ \setbox\scratchbox\hbox{\space}%
+ \vrule
+ \!!depth \scratchdimen
+ \!!width \wd\scratchbox
+ \!!height\zeropoint}}
+
+\ifx\mathunderscore\undefined \let\mathunderscore\fakeunderscore \fi
+\ifx\textunderscore\undefined \let\textunderscore\fakeunderscore \fi
+
+\unexpanded\def\normalunderscore{\ifmmode\mathunderscore\else\textunderscore\fi}
+
+\let\_\normalunderscore
+
+% Handy but obsolete, replaced by \unknownchar:
+%
+% \def\missingglyph{\ruledhbox{?}}
+
+\protect \endinput
diff --git a/tex/context/base/enco-pdf.mkii b/tex/context/base/enco-pdf.mkii
new file mode 100644
index 000000000..a03e81df2
--- /dev/null
+++ b/tex/context/base/enco-pdf.mkii
@@ -0,0 +1,278 @@
+%D \module
+%D [ file=enco-pdf,
+%D version=1995.01.01,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=\YandY\ texnansi Encoding,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is the \PDF\ document encoding.
+
+\startencoding[pdfdoc] % \rawcharacter{number}
+
+\definecharacter oeligature ^^9c
+
+\definecharacter leftguillemot ^^ab
+\definecharacter rightguillemot ^^bb
+
+\definecharacter Agrave ^^c0
+\definecharacter Aacute ^^c1
+\definecharacter Acircumflex ^^c2
+\definecharacter Atilde ^^c3
+\definecharacter Adiaeresis ^^c4
+\definecharacter OAligature ^^c5
+\definecharacter AEligature ^^c6
+\definecharacter Ccedilla ^^c7
+\definecharacter Egrave ^^c8
+\definecharacter Eacute ^^c9
+\definecharacter Ecircumflex ^^ca
+\definecharacter Ediaeresis ^^cb
+\definecharacter Igrave ^^cc
+\definecharacter Iacute ^^cd
+\definecharacter Icircumflex ^^ce
+\definecharacter Idiaeresis ^^cf
+
+\definecharacter Ntilde ^^d1
+\definecharacter Ograve ^^d2
+\definecharacter Oacute ^^d3
+\definecharacter Ocircumflex ^^d4
+\definecharacter Otilde ^^d5
+\definecharacter Odiaeresis ^^d6
+
+\definecharacter Ugrave ^^d9
+\definecharacter Uacute ^^da
+\definecharacter Ucircumflex ^^db
+\definecharacter Udiaeresis ^^dc
+\definecharacter Yacute ^^dd
+
+\definecharacter ssharp ^^df
+\definecharacter agrave ^^e0
+\definecharacter aacute ^^e1
+\definecharacter acircumflex ^^e2
+\definecharacter atilde ^^e3
+\definecharacter adiaeresis ^^e4
+\definecharacter oaligature ^^e5
+\definecharacter aeligature ^^e6
+\definecharacter ccedilla ^^e7
+\definecharacter egrave ^^e8
+\definecharacter eacute ^^e9
+\definecharacter ecircumflex ^^ea
+\definecharacter ediaeresis ^^eb
+\definecharacter igrave ^^ec
+\definecharacter iacute ^^ed
+\definecharacter icircumflex ^^ee
+\definecharacter idiaeresis ^^ef
+
+\definecharacter ntilde ^^f1
+\definecharacter ograve ^^f2
+\definecharacter oacute ^^f3
+\definecharacter ocircumflex ^^f4
+\definecharacter otilde ^^f5
+\definecharacter odiaeresis ^^f6
+
+\definecharacter ugrave ^^f9
+\definecharacter uacute ^^fa
+\definecharacter ucircumflex ^^fb
+\definecharacter udiaeresis ^^fc
+\definecharacter yacute ^^fd
+
+\definecharacter ydiaeresis ^^ff
+
+\definecharacter leftsubguillemot {\leftguillemot}
+\definecharacter rightsubguillemot {\rightguillemot}
+
+\definecharacter Uhungarumlaut {\Ucircumflex}
+\definecharacter uhungarumlaut {\ucircumflex}
+\definecharacter Ohungarumlaut {\Ocircumflex}
+\definecharacter ohungarumlaut {\ocircumflex}
+
+\definecharacter Aogonek {A}
+\definecharacter aogonek {a}
+\definecharacter Eogonek {E}
+\definecharacter eogonek {e}
+\definecharacter Iogonek {I}
+\definecharacter iogonek {i}
+\definecharacter Uogonek {U}
+\definecharacter uogonek {u}
+
+\definecharacter Aring {A}
+\definecharacter aring {a}
+\definecharacter Uring {U}
+\definecharacter uring {u}
+
+\definecharacter Abreve {A}
+\definecharacter abreve {a}
+\definecharacter Ebreve {E}
+\definecharacter ebreve {e}
+\definecharacter Gbreve {G}
+\definecharacter gbreve {g}
+\definecharacter Ibreve {I}
+\definecharacter ibreve {i}
+\definecharacter Obreve {O}
+\definecharacter obreve {o}
+\definecharacter Ubreve {U}
+\definecharacter ubreve {u}
+
+\definecharacter Ccaron {C}
+\definecharacter ccaron {c}
+\definecharacter Dcaron {D}
+\definecharacter dcaron {d}
+\definecharacter Ecaron {E}
+\definecharacter ecaron {e}
+\definecharacter Lcaron {L}
+\definecharacter lcaron {l}
+\definecharacter Ncaron {N}
+\definecharacter ncaron {n}
+\definecharacter Rcaron {R}
+\definecharacter rcaron {r}
+\definecharacter Scaron {S}
+\definecharacter scaron {s}
+\definecharacter Tcaron {T}
+\definecharacter tcaron {t}
+\definecharacter Ycaron {Y}
+\definecharacter ycaron {y}
+\definecharacter Zcaron {Z}
+\definecharacter zcaron {z}
+
+\definecharacter Lstroke {L}
+\definecharacter lstroke {l}
+\definecharacter Ostroke {O}
+\definecharacter ostroke {o}
+
+\definecharacter aumlaut {\adiaeresis}
+\definecharacter eumlaut {\ediaeresis}
+\definecharacter iumlaut {\idiaeresis}
+\definecharacter oumlaut {\odiaeresis}
+\definecharacter uumlaut {\udiaeresis}
+
+\definecharacter Aumlaut {\Adiaeresis}
+\definecharacter Eumlaut {\Ediaeresis}
+\definecharacter Iumlaut {\Idiaeresis}
+\definecharacter Oumlaut {\Odiaeresis}
+\definecharacter Uumlaut {\Udiaeresis}
+
+\definecharacter scommaaccent {s}
+\definecharacter Scommaaccent {S}
+\definecharacter tcommaaccent {t}
+\definecharacter Tcommaaccent {T}
+
+\definecharacter Etilde {E}
+\definecharacter etilde {e}
+
+\definecharacter Ahook {A}
+\definecharacter ahook {a}
+\definecharacter Ehook {E}
+\definecharacter ehook {e}
+\definecharacter Ihook {I}
+\definecharacter ihook {i}
+\definecharacter Ohook {O}
+\definecharacter ohook {o}
+\definecharacter Uhook {U}
+\definecharacter uhook {u}
+\definecharacter Yhook {Y}
+\definecharacter yhook {y}
+
+\definecharacter Acircumflexgrave {\Acircumflex}
+\definecharacter Acircumflexacute {\Acircumflex}
+\definecharacter Acircumflextilde {\Acircumflex}
+\definecharacter Acircumflexhook {\Acircumflex}
+\definecharacter acircumflexgrave {\acircumflex}
+\definecharacter acircumflexacute {\acircumflex}
+\definecharacter acircumflextilde {\acircumflex}
+\definecharacter acircumflexhook {\acircumflex}
+\definecharacter Ecircumflexgrave {\Ecircumflex}
+\definecharacter Ecircumflexacute {\Ecircumflex}
+\definecharacter Ecircumflextilde {\Ecircumflex}
+\definecharacter Ecircumflexhook {\Ecircumflex}
+\definecharacter ecircumflexgrave {\ecircumflex}
+\definecharacter ecircumflexacute {\ecircumflex}
+\definecharacter ecircumflextilde {\ecircumflex}
+\definecharacter ecircumflexhook {\ecircumflex}
+\definecharacter Ocircumflexgrave {\Ocircumflex}
+\definecharacter Ocircumflexacute {\Ocircumflex}
+\definecharacter Ocircumflextilde {\Ocircumflex}
+\definecharacter Ocircumflexhook {\Ocircumflex}
+\definecharacter ocircumflexgrave {\ocircumflex}
+\definecharacter ocircumflexacute {\ocircumflex}
+\definecharacter ocircumflextilde {\ocircumflex}
+\definecharacter ocircumflexhook {\ocircumflex}
+
+\definecharacter Abrevegrave {A}
+\definecharacter Abreveacute {A}
+\definecharacter Abrevetilde {A}
+\definecharacter Abrevehook {A}
+\definecharacter abrevegrave {a}
+\definecharacter abreveacute {a}
+\definecharacter abrevetilde {a}
+\definecharacter abrevehook {a}
+
+\definecharacter Adotbelow {A}
+\definecharacter adotbelow {a}
+\definecharacter Edotbelow {E}
+\definecharacter edotbelow {e}
+\definecharacter Idotbelow {I}
+\definecharacter idotbelow {i}
+\definecharacter Odotbelow {O}
+\definecharacter odotbelow {o}
+\definecharacter Udotbelow {U}
+\definecharacter udotbelow {u}
+\definecharacter Ydotbelow {Y}
+\definecharacter ydotbelow {y}
+\definecharacter Ohorndotbelow {O}
+\definecharacter ohorndotbelow {o}
+\definecharacter Uhorndotbelow {U}
+\definecharacter uhorndotbelow {u}
+
+\definecharacter Acircumflexdotbelow {\Acircumflex}
+\definecharacter acircumflexdotbelow {\acircumflex}
+\definecharacter Ecircumflexdotbelow {\Ecircumflex}
+\definecharacter ecircumflexdotbelow {\ecircumflex}
+\definecharacter Ocircumflexdotbelow {\Ocircumflex}
+\definecharacter ocircumflexdotbelow {\ocircumflex}
+\definecharacter Abrevedotbelow {\Abreve}
+\definecharacter abrevedotbelow {\abreve}
+
+\definecharacter Ohorn {O}
+\definecharacter Ohorngrave {O}
+\definecharacter Ohornacute {O}
+\definecharacter Ohorntilde {O}
+\definecharacter Ohornhook {O}
+
+\definecharacter ohorn {o}
+\definecharacter ohorngrave {o}
+\definecharacter ohornacute {o}
+\definecharacter ohorntilde {o}
+\definecharacter ohornhook {o}
+
+\definecharacter Uhorn {U}
+\definecharacter Uhorngrave {U}
+\definecharacter Uhornacute {U}
+\definecharacter Uhorntilde {U}
+\definecharacter Uhornhook {U}
+
+\definecharacter uhorn {u}
+\definecharacter uhorngrave {u}
+\definecharacter uhornacute {u}
+\definecharacter uhorntilde {u}
+\definecharacter uhornhook {u}
+
+\definecharacter Utilde {U}
+\definecharacter utilde {u}
+\definecharacter Itilde {I}
+\definecharacter itilde {i}
+\definecharacter Ygrave {Y}
+\definecharacter ygrave {y}
+\definecharacter Ytilde {Y}
+\definecharacter ytilde {y}
+
+\definecharacter dstroke {d}
+\definecharacter Dstroke {D}
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-pfr.mkii b/tex/context/base/enco-pfr.mkii
new file mode 100644
index 000000000..b279e40aa
--- /dev/null
+++ b/tex/context/base/enco-pfr.mkii
@@ -0,0 +1,305 @@
+%D \module
+%D [ file=enco-pfr,
+%D version=2000.12.10, % adapted 2005.08.14 to more delayed loading
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=PDF Resources,
+%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.
+
+\ifnum\texengine>\pdftexengine
+ \expandafter \endinput
+\fi
+
+\ifdefined\pdffontresource \else
+ \expandafter \endinput
+\fi
+
+\writestatus{loading}{ConTeXt Encoding Macros / PDF Resources}
+
+%D This is an experimental module in which we implement
+%D font resource inclusion in \PDF. One reason to include
+%D font resources is that it enables a search engine to
+%D perform a search (I'm told). This feature ws requested by
+%D Petr Ferdus from Czech.
+
+%D A simple test file may look like this (watch how we first
+%D load the encoding and then the font; previous font
+%D definitions are left untouched.)
+%D
+%D \starttyping
+%D % output=pdftex interface=en
+%D
+%D \useencoding[pfr]
+%D \setupbodyfont[csr]
+%D
+%D \starttext
+%D test \`z \'z \bf test \sl test \bs quite funny \`z \page
+%D test \`z \'z \bf test \sl test \bs quite funny \`z \page
+%D \stoptext
+%D \stoptyping
+%D
+%D We do our best to include a (often large) font resources
+%D only once. The current implementation is not that
+%D general which is also due to the fact that \type
+%D {\pdffontattr} is expanded instantly and persistent. A
+%D more versatile (but also slower) approach is to keep track
+%D of the fonts and either flush the information at shipout
+%D time, or at the end of the document.
+
+%D \macros
+%D {ifincludepdffontresources}
+%D
+%D You can turn of this feature using the following switch.
+
+\newif\ifincludepdffontresources \includepdffontresourcestrue
+
+\ifx\pdfglyphtounicode\undefined \else
+ \appendtoks
+ \doif\jobsuffix{pdf}{\readfile{pdfr-def.mkii}\donothing\donothing}%
+ \to \everystarttext
+\fi
+
+% somehow we cannot preload this beast; also, it's mk dependent
+%
+% \appendtoks
+% \doifelse{\jobsuffix}{pdf}{\loadmkiifile{pdfr-def.mkii}}%
+% \to \everystarttext
+
+% ugly, this should go to the driver spec-tpd
+
+\ifx\pdfgentounicode\undefined \else
+ \ifcase\pdfgentounicode \else
+ \expandafter \expandafter \expandafter \endinput
+ \fi
+\fi
+
+\unprotect
+
+% a problem is that there is always an ec vector added even when
+% we switch to texnansi early; this has to do with the fact that
+% we need to setup fonts at startup; this a pain when we have
+% textless documents, so we should have a way around, i.e. an
+% extension to pdftex where we can tag numbers inside user specs
+% and attributes.
+%
+% currently we need to use immediate so we end up with entries
+
+%D The name of the resource is stored in a macro, as is its
+%D object reference. A resource is only processed once. When
+%D done, the resource name is erased, and we use this fact to
+%D prevent redefinition as well as well as reloading. So, a
+%D macro defined with \type {\pdffontfileresource} can have
+%D three states:
+%D
+%D \startitemize[packed]
+%D \item undefined: not yet loaded, and not yet included
+%D \item some value: loaded, but not yet included
+%D \item empty: loaded, and already included
+%D \stopitemize
+
+\def\pdffontresource {pdfr:\currentencoding}
+\def\pdffontfileresource{pdff:\pdffontresource}
+
+%D A resource is defined in a file prefixed by \type {pdfr-}.
+%D The following \PDF\ code is composed by Ondrej Koala Vacha (I
+%D probably mispelled this name).
+%D
+%D \starttyping
+%D \startpdffontresource[il2]
+%D /CIDInit /ProcSet findresource begin
+%D 12 dict begin
+%D begincmap
+%D /CIDSystemInfo
+%D << /Registry (Adobe)
+%D /Ordering (T1UV)
+%D /Supplement 0
+%D >> def
+%D /CMapName /Adobe-Identity-UCS def
+%D /CMapType 1 def
+%D 1 begincodespacerange
+%D <00>
+%D endcodespacerange
+%D %%FontSpecificEncoding
+%D 191 beginbfrange
+%D <20> <20> <0020> % space dec: 32 oct:040 hex:20
+%D .... .... ...... . ........ .... .. ....... ......
+%D <00ff> % dotaccent dec:255 oct:377 hex:ff
+%D endbfrange
+%D endcmap
+%D CMapName currentdict /CMap defineresource pop end
+%D end
+%D \stoppdffontresource
+%D \stoptyping
+%D
+%D We don't preload such huge definitions, and process them
+%D run||time to save memory. Therefore, in the encoding
+%D vector, we only add an entry like:
+%D
+%D \starttyping
+%D \startencoding [il2]
+%D \usepdffontresource il2
+%D \stopencoding
+%D \stoptyping
+%D
+%D This macro is defined as follows.
+
+\def\usepdffontresource #1 %
+ {\doifundefinedelse\pdffontfileresource % okay, undefined, so either
+ {\setxvalue\pdffontfileresource{#1}} % brand new, or not yet loaded
+ {\doifvaluesomething\pdffontfileresource % only if not loaded in which
+ {\setxvalue\pdffontfileresource{#1}}}} % case it's made empty
+
+%D Watch how we check for duplicated loading. The resource
+%D itself, when asked for, is included immediately, after which
+%D we save its reference. Normally a document will have one
+%D such a resource.
+
+% \long\def\startpdffontresource[#1]#2\stoppdffontresource
+% {\doif{#1}\currentencoding
+% {\immediate\pdfobj useobjnum \getvalue{\pdffontresource} stream {#2}}}
+
+% alternatively we can use object references
+
+% fails when we switch back and forward between dvi/pdf mode
+%
+% \long\def\startpdffontresource[#1]#2\stoppdffontresource
+% {\doif{#1}\currentencoding{\doifdefined\pdffontresource
+% {\immediate\pdfobj useobjnum \getvalue{\pdffontresource} stream {#2}}}}
+
+\long\def\startpdffontresource[#1]#2\stoppdffontresource
+ {\doif{#1}\currentencoding{\doifdefined\pdffontresource
+ {\expanded{\doshipoutpdffontresource{\getvalue{\pdffontresource}}{#2}}}}}
+
+\def\doshipoutpdffontresource#1#2%
+ {\ifnum\realpageno<\plustwo
+ \doglobal\appendtoks
+ \ifcase\pdfoutput\else\immediate\pdfobj useobjnum #1 stream {#2}\fi
+ \to\everyfirstshipout
+ \else
+ \ifcase\pdfoutput\else\immediate\pdfobj useobjnum #1 stream {#2}\fi
+ \fi}
+
+% cleaner but not better:
+%
+% \newtoks \collectedpdffontresources
+%
+% \def\doshipoutpdffontresource#1#2%
+% {\doglobal\appendtoks
+% \ifcase\pdfoutput\else\immediate\pdfobj useobjnum #1 stream {#2}\fi
+% \to \collectedpdffontresources}
+%
+% \def\dofluspdffontresources
+% {\the\collectedpdffontresources
+% \global\collectedpdffontresources\emptytoks}
+%
+% \appendtoks \dofluspdffontresources \to \everybeforeshipout
+
+%D The reference to such a vector is to be handled at font
+%D definition time, which is why we hook it into the font
+%D loading routine. A little bit of indirectness speeds up
+%D the process when this feature is disabled and keeps the
+%D macros readable.
+
+% \newevery \everyfont \relax
+
+\appendtoksonce \includepdffontresource \to \everyfont
+
+% \def\includepdffontresource
+% {\ifincludepdffontresources
+% \ifx\pdffontattr\undefined
+% % we're not using (a recent version of) pdftex
+% \else\ifcase\pdfoutput
+% % we're not in pdf mode
+% \else
+% \doincludepdffontresource
+% \fi\fi
+% \fi}
+
+\def\includepdffontresource
+ {\ifx\pdfgentounicode\undefined
+ \expandafter\ifx\the\font\nullfont \else
+ \ifx\pdffontattr\undefined
+ % we're not using (a recent version of) pdftex
+ \else\ifcase\pdfoutput
+ % we're not in pdf mode
+ \else
+ \doincludepdffontresource
+ \fi\fi
+ \fi
+ \else\ifcase\pdfgentounicode
+ \ifincludepdffontresources
+ \expandafter\ifx\the\font\nullfont \else
+ \ifx\pdffontattr\undefined
+ % we're not using (a recent version of) pdftex
+ \else\ifcase\pdfoutput
+ % we're not in pdf mode
+ \else
+ \doincludepdffontresource
+ \fi\fi
+ \fi
+ \fi
+ \or
+ \global\let\includepdffontresource\relax % automatic, built in
+ \fi\fi}
+
+\def\dododoincludepdffontresource#1% encoding
+ {\bgroup
+ \edef\currentencoding{#1}%
+ \doifvaluesomething\pdffontfileresource
+ {\startreadingfile
+ \ignorelines % just in case \par is redefined; this thing can get called anywhere
+ \readsysfile{pdfr-\getvalue\pdffontfileresource.mkii}\donothing\donothing
+ \stopreadingfile
+ \letgvalue\pdffontfileresource\empty}%
+ \egroup}
+
+\def\doincludepdffontresource
+ {\ifcsname\s!ucmap\fontfile\endcsname\else
+ \dodoincludepdffontresource
+ \fi}
+
+\def\dodoincludepdffontresource
+ {% does this font has an encoding specified vector
+ \doifsomething\currentencoding % no \ifx
+ {% is there a pdf font encoding resource file defined
+ \ifcsname\pdffontresource\endcsname
+ % (fake) object defined
+ \else\ifcsname\pdffontfileresource\endcsname
+ % is there a resource already included
+ \doifsomething\pdffontfileresource
+ {\pdfobj reserveobjnum {}%
+ \setxvalue\pdffontresource{\the\pdflastobj}%
+ \flushatshipout{\dododoincludepdffontresource{\currentencoding}}}%
+% \doglobal\appendetoks
+% \noexpand\dododoincludepdffontresource{\currentencoding}%
+% \to \everybeforeshipout}% prevent multiple loading
+ \fi\fi
+ \ifcsname\pdffontresource\endcsname
+ \expanded{\pdffontattr\font{/ToUnicode \csname\pdffontresource\endcsname\space0 R}}%
+ % do it only once for each font
+ \letgvalue{\s!ucmap\fontfile}\empty
+ \fi}}
+
+%D For the moment, we keep this definition here, if only
+%D because \type {\usepdffontencoding} is not defined in the
+%D core. In the end, this will go to \type {enco-*.tex}.
+%D
+%D Test:
+%D
+%D \starttyping
+%D \useencoding[pfr] \usetypescript[palatino][ec] \setupbodyfont[palatino]
+%D
+%D \starttext
+%D fi ff ffi
+%D \stoptext
+%D \stoptyping
+
+\startencoding [il2] \usepdffontresource il2 \stopencoding
+\startencoding [ec] \usepdffontresource ec \stopencoding
+
+\protect \endinput
diff --git a/tex/context/base/enco-pol.mkii b/tex/context/base/enco-pol.mkii
new file mode 100644
index 000000000..a012f0370
--- /dev/null
+++ b/tex/context/base/enco-pol.mkii
@@ -0,0 +1,276 @@
+%D \module
+%D [ file=enco-pol,
+%D version=2000.05.07, % 1999.28.8,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Polish Mixed Encoding,
+%D author={Taco Hoekwater \& Hans Hagen},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% This encoding will go but the regime will remain.
+
+%D Polish native encoding; normally polish users will use
+%D translate=cp1250pl in combination with ec encoding.
+
+\startmapping[pl0]
+
+\resetcaserange 128 to 255
+
+\definecaseswap 161 129 % a ogonek
+\definecaseswap 162 130 % c acute
+\definecaseswap 166 134 % e ogonek
+\definecaseswap 170 138 % l crossed
+\definecaseswap 171 139 % n acute
+\definecaseswap 177 145 % s acute
+\definecaseswap 185 153 % z acute
+\definecaseswap 187 155 % z dotaccent
+\definecaseswap 243 211 % o acute
+
+% \definecasemap 161 161 129 % a ogonek
+% \definecasemap 162 162 130 % c acute
+% \definecasemap 166 166 134 % e ogonek
+% \definecasemap 170 170 138 % l crossed
+% \definecasemap 171 171 139 % n acute
+% \definecasemap 177 177 145 % s acute
+% \definecasemap 185 185 153 % z acute
+% \definecasemap 187 187 155 % z dotaccent
+% \definecasemap 243 243 211 % o acute
+
+% \definecasemap 129 161 129 % A ogonek
+% \definecasemap 130 162 130 % C acute
+% \definecasemap 134 166 134 % E ogonek
+% \definecasemap 138 170 138 % L crossed
+% \definecasemap 139 171 139 % N acute
+% \definecasemap 145 177 145 % S acute
+% \definecasemap 153 185 153 % Z acute
+% \definecasemap 155 187 155 % Z dotaccent
+% \definecasemap 211 243 211 % O acute
+
+\stopmapping
+
+\startmapping[pl0]
+
+\definespacemap 129 999 % A ogonek
+\definespacemap 130 999 % C acute
+\definespacemap 134 999 % E ogonek
+\definespacemap 138 999 % L crossed
+\definespacemap 139 999 % N acute
+\definespacemap 211 999 % O acute
+\definespacemap 145 999 % S acute
+\definespacemap 153 999 % Z acute
+\definespacemap 155 999 % Z dot
+
+\stopmapping
+
+\startencoding[pl0][pl0]
+
+\definecharacter Aogonek 129
+\definecharacter Cacute 130
+\definecharacter Eogonek 134
+\definecharacter Lstroke 138
+\definecharacter Nacute 139
+\definecharacter Sacute 145
+\definecharacter Zacute 153
+\definecharacter Zdotaccent 155
+\definecharacter aogonek 161
+\definecharacter cacute 162
+\definecharacter eogonek 166
+\definecharacter lstroke 170
+\definecharacter nacute 171
+\definecharacter sacute 177
+\definecharacter zacute 185
+\definecharacter zdotaccent 187
+\definecharacter Oacute 211
+\definecharacter oacute 243
+
+\stopencoding
+
+\startencoding[pl0][pl0]
+
+\definecharacter leftguillemot 174
+\definecharacter rightguillemot 175
+\definecharacter guilsingleleft 174
+\definecharacter guilsingleright 175
+
+\stopencoding
+
+% obsolete
+%
+% \startencoding[pl0]
+%
+% \definesortkey {161} {a}{a}{\k a} \definesortkey {129} {a}{a}{\k a}
+% \definesortkey {162} {c}{a}{\'c} \definesortkey {130} {c}{a}{\'c}
+% \definesortkey {166} {e}{a}{\k e} \definesortkey {134} {e}{a}{\k e}
+% \definesortkey {170} {l}{a}{\l } \definesortkey {138} {l}{a}{\l }
+% \definesortkey {171} {n}{a}{\'n} \definesortkey {139} {n}{a}{\'n}
+% \definesortkey {177} {s}{a}{\'s} \definesortkey {145} {s}{a}{\'s}
+% \definesortkey {185} {z}{a}{\'z} \definesortkey {153} {z}{a}{\'z}
+% \definesortkey {187} {z}{b}{\.z} \definesortkey {155} {z}{b}{\.z}
+% \definesortkey {243} {o}{a}{\'o} \definesortkey {211} {o}{a}{\'o}
+%
+% \definesortkey {\'c} {c}{a}{\'c} \definesortkey {\'C} {c}{a}{\'c}
+% \definesortkey {\'n} {n}{a}{\'n} \definesortkey {\'N} {n}{a}{\'n}
+% \definesortkey {\'o} {o}{a}{\'o} \definesortkey {\'O} {o}{a}{\'o}
+% \definesortkey {\'s} {s}{a}{\'s} \definesortkey {\'S} {s}{a}{\'s}
+% \definesortkey {\'z} {z}{a}{\'z} \definesortkey {\'Z} {z}{a}{\'z}
+% \definesortkey {\.z} {z}{b}{\.z} \definesortkey {\.Z} {z}{b}{\.z}
+% \definesortkey {\k a}{a}{a}{\k a} \definesortkey {\k A}{a}{a}{\k a}
+% \definesortkey {\k e}{e}{a}{\k e} \definesortkey {\k E}{e}{a}{\k e}
+% \definesortkey {\l } {l}{a}{\l} \definesortkey {\L } {l}{a}{\l}
+%
+% \stopencoding
+
+%D Polish CP-1250 encoding.
+
+% \startmapping[pl1]
+%
+%
+% \resetcaserange 128 to 255
+%
+% \definecasemap 185 185 165 % a ogonek
+% \definecasemap 230 230 198 % c acute
+% \definecasemap 234 234 202 % e ogonek
+% \definecasemap 179 179 163 % l crossed
+% \definecasemap 241 241 209 % n acute
+% \definecasemap 243 243 211 % o acute
+% \definecasemap 156 156 140 % s acute
+% \definecasemap 159 159 143 % z acute
+% \definecasemap 191 191 175 % z dot
+%
+% \definecasemap 165 165 185 % A ogonek
+% \definecasemap 198 198 230 % C acute
+% \definecasemap 202 202 234 % E ogonek
+% \definecasemap 163 163 179 % L crossed
+% \definecasemap 209 209 241 % N acute
+% \definecasemap 211 211 243 % O acute
+% \definecasemap 140 140 156 % S acute
+% \definecasemap 143 143 159 % Z acute
+% \definecasemap 175 175 191 % Z dot
+%
+% \stopmapping
+%
+% \startmapping[pl1]
+%
+% \definespacemap 165 999 % A ogonek
+% \definespacemap 198 999 % C acute
+% \definespacemap 202 999 % E ogonek
+% \definespacemap 163 999 % L crossed
+% \definespacemap 209 999 % N acute
+% \definespacemap 211 999 % O acute
+% \definespacemap 140 999 % S acute
+% \definespacemap 143 999 % Z acute
+% \definespacemap 175 999 % Z dot
+%
+% \stopmapping
+%
+% \startencoding[pl1]
+%
+% \definecharacter Sacute 140
+% \definecharacter Zacute 143
+% \definecharacter sacute 156
+% \definecharacter zacute 159
+% \definecharacter Lstroke 163
+% \definecharacter Aogonek 165
+% \definecharacter Zdotaccent 175
+% \definecharacter lstroke 179
+% \definecharacter aogonek 185
+% \definecharacter zdotaccent 191
+% \definecharacter Cacute 198
+% \definecharacter Eogonek 202
+% \definecharacter Nacute 209
+% \definecharacter Oacute 211
+% \definecharacter cacute 230
+% \definecharacter eogonek 234
+% \definecharacter nacute 241
+% \definecharacter oacute 243
+%
+% \stopencoding
+%
+% \startencoding[pl1]
+%
+% \definecharacter leftguillemot 174
+% \definecharacter rightguillemot 175
+% \definecharacter guilsingleleft 174
+% \definecharacter guilsingleright 175
+%
+% \stopencoding
+
+%D Polish ISO-8859-2 encoding.
+
+% \startmapping[pl2]
+%
+% \resetcaserange 128 to 255
+%
+% \definecasemap 177 177 161 % a ogonek
+% \definecasemap 230 230 198 % c acute
+% \definecasemap 234 234 202 % e ogonek
+% \definecasemap 179 179 163 % l crossed
+% \definecasemap 241 241 209 % n acute
+% \definecasemap 243 243 211 % o acute
+% \definecasemap 182 182 166 % s acute
+% \definecasemap 188 188 172 % z acute
+% \definecasemap 191 191 175 % z dotaccent
+%
+% \definecasemap 161 161 177 % A ogonek
+% \definecasemap 198 198 230 % C acute
+% \definecasemap 202 202 234 % E ogonek
+% \definecasemap 163 163 179 % L crossed
+% \definecasemap 209 209 241 % N acute
+% \definecasemap 211 211 243 % O acute
+% \definecasemap 166 166 182 % S acute
+% \definecasemap 172 172 188 % Z acute
+% \definecasemap 175 175 191 % Z dotaccent
+%
+% \stopmapping
+%
+% \startmapping[pl2]
+%
+% \definespacemap 161 999 % A ogonek
+% \definespacemap 198 999 % C acute
+% \definespacemap 202 999 % E ogonek
+% \definespacemap 163 999 % L crossed
+% \definespacemap 209 999 % N acute
+% \definespacemap 211 999 % O acute
+% \definespacemap 166 999 % S acute
+% \definespacemap 172 999 % Z acute
+% \definespacemap 175 999 % Z dot
+%
+% \stopmapping
+%
+% \startencoding[pl2]
+%
+% \definecharacter Aogonek 161
+% \definecharacter Lstroke 163
+% \definecharacter Sacute 166
+% \definecharacter Zacute 172
+% \definecharacter Zdotaccent 175
+% \definecharacter aogonek 177
+% \definecharacter lstroke 179
+% \definecharacter sacute 182
+% \definecharacter zacute 188
+% \definecharacter zdotaccent 191
+% \definecharacter Cacute 198
+% \definecharacter Eogonek 202
+% \definecharacter Nacute 209
+% \definecharacter Oacute 211
+% \definecharacter cacute 230
+% \definecharacter eogonek 234
+% \definecharacter nacute 241
+% \definecharacter oacute 243
+%
+% \stopencoding
+%
+% \startencoding[pl2]
+%
+% \definecharacter leftguillemot 174
+% \definecharacter rightguillemot 175
+% \definecharacter guilsingleleft 174
+% \definecharacter guilsingleright 175
+%
+% \stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-qx.mkii b/tex/context/base/enco-qx.mkii
new file mode 100644
index 000000000..407d60bd7
--- /dev/null
+++ b/tex/context/base/enco-qx.mkii
@@ -0,0 +1,266 @@
+%D \module
+%D [ file=enco-qx,
+%D version=2004.04.03,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Polish QX Encoding,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% to be done
+
+% 35 numbersign
+% 95 dotaccent
+% 132 greaterequal
+% 133 approxequal
+% 137 lessequal
+% 142 ell
+% 156 IJ
+% 173 infinity
+% 182 threequartersemdash
+% 188 ij
+% 247 anglearc
+% 248 diameter
+
+\startmapping[qx] % to be done
+
+\resetcaserange 128 to 128
+\resetcaserange 131 to 133
+\resetcaserange 136 to 137
+\resetcaserange 140 to 144
+\resetcaserange 148 to 148
+\resetcaserange 150 to 150
+\resetcaserange 157 to 160
+\resetcaserange 163 to 165
+\resetcaserange 168 to 169
+\resetcaserange 172 to 176
+\resetcaserange 180 to 180
+\resetcaserange 182 to 182
+\resetcaserange 189 to 191
+\resetcaserange 198 to 198
+\resetcaserange 215 to 216
+\resetcaserange 223 to 223
+\resetcaserange 230 to 230
+\resetcaserange 247 to 248
+\resetcaserange 255 to 255
+
+\definecaseswap 161 129
+\definecaseswap 162 130
+
+\definecaseswap 166 134
+\definecaseswap 167 135
+
+\definecaseswap 170 138
+\definecaseswap 171 139
+
+\definecaseswap 177 145
+\definecaseswap 178 146
+\definecaseswap 179 147
+
+\definecaseswap 181 149
+
+\definecasemaps 151 to 156 lc +32 uc 0
+\definecasemaps 183 to 188 lc 0 uc -32
+
+\definecasemaps 192 to 197 lc +32 uc 0
+\definecasemaps 224 to 229 lc 0 uc -32
+
+\definecasemaps 199 to 214 lc +32 uc 0
+\definecasemaps 231 to 246 lc 0 uc -32
+
+\definecasemaps 217 to 222 lc +32 uc 0
+\definecasemaps 249 to 254 lc 0 uc -32
+
+\stopmapping
+
+\startencoding[qx]
+
+\definecharacter textacute 19
+\definecharacter textbreve 21
+\definecharacter textcaron 20
+\definecharacter textcedilla 24
+\definecharacter textcircumflex 94
+\definecharacter textdiaeresis 127
+\definecharacter textdotaccent 94
+\definecharacter textgrave 18
+\definecharacter texthungarumlaut 125
+\definecharacter textmacron 22
+\definecharacter textogonek 150
+\definecharacter textring 23
+\definecharacter texttilde 126
+
+\definecharacter dotlessi 16
+\definecharacter dotlessj 17
+
+\definecharacter endash 123
+\definecharacter emdash 124
+
+\definecharacter aeligature 26
+\definecharacter AEligature 29
+\definecharacter oeligature 27
+\definecharacter OEligature 30
+
+\definecharacter ssharp 25
+%definecharacter Ssharp 25
+
+\definecharacter thorn 254
+\definecharacter Thorn 222
+
+\definecharacter Dstroke 208 % also Eth, mapped into enco-def
+\definecharacter eth 240
+
+\definecharacter exclamdown 60
+\definecharacter questiondown 62
+
+\definecharacter sectionmark 159
+
+\definecharacter percent 37
+\definecharacter perthousand 216
+
+\definecharacter textasciicircum 141
+\definecharacter textasciitilde 140
+\definecharacter textbackslash 198
+\definecharacter textbraceleft 157
+\definecharacter textbraceright 158
+\definecharacter textunderscore 230
+
+\definecharacter textcurrency 215
+\definecharacter textdollar 36
+\definecharacter texteuro 128
+
+\definecharacter periodcentered 189
+\definecharacter textdag 143
+\definecharacter textddag 144
+\definecharacter textdegree 148
+\definecharacter textbullet 180
+
+\definecharacter paragraphmark 176
+
+\definecharacter copyright 164
+\definecharacter registered 163
+
+\definecharacter textbrokenbar 223
+\definecharacter textellipsis 8
+\definecharacter textslash 47
+\definecharacter textpm 172
+\definecharacter textdiv 165
+\definecharacter textminus 168
+\definecharacter textmultiply 169
+\definecharacter textmu 7
+
+\definecharacter quotedbl 190
+\definecharacter quotedblbase 255
+\definecharacter quotedblleft 92
+\definecharacter quotedblright 34
+
+\definecharacter quotesingle 191
+
+\definecharacter quoteleft 96
+\definecharacter quoteright 39
+
+\definecharacter leftguillemot 174
+\definecharacter rightguillemot 175
+
+\definecharacter aacute 225
+\definecharacter Aacute 193
+\definecharacter cacute 162
+\definecharacter Cacute 130
+\definecharacter eacute 233
+\definecharacter Eacute 201
+\definecharacter iacute 237
+\definecharacter Iacute 205
+\definecharacter Nacute 139
+\definecharacter Oacute 211
+\definecharacter nacute 171
+\definecharacter oacute 243
+\definecharacter sacute 177
+\definecharacter Sacute 145
+\definecharacter uacute 250
+\definecharacter Uacute 218
+\definecharacter yacute 253
+\definecharacter Yacute 221
+\definecharacter zacute 185
+\definecharacter Zacute 153
+
+\definecharacter scaron 178
+\definecharacter Scaron 146
+\definecharacter zcaron 186
+\definecharacter Zcaron 154
+
+\definecharacter ccedilla 231
+\definecharacter Ccedilla 199
+
+\definecharacter acircumflex 226
+\definecharacter Acircumflex 194
+\definecharacter ecircumflex 234
+\definecharacter Ecircumflex 202
+\definecharacter icircumflex 238
+\definecharacter Icircumflex 206
+\definecharacter ocircumflex 244
+\definecharacter Ocircumflex 212
+\definecharacter ucircumflex 251
+\definecharacter Ucircumflex 219
+
+\definecharacter adiaeresis 228
+\definecharacter Adiaeresis 196
+\definecharacter ediaeresis 235
+\definecharacter Ediaeresis 203
+\definecharacter idiaeresis 239
+\definecharacter Idiaeresis 207
+\definecharacter odiaeresis 246
+\definecharacter Odiaeresis 214
+\definecharacter udiaeresis 252
+\definecharacter Udiaeresis 220
+\definecharacter ydiaeresis 184
+\definecharacter Ydiaeresis 152
+
+\definecharacter zdotaccent 187
+\definecharacter Zdotaccent 155
+
+\definecharacter agrave 224
+\definecharacter Agrave 192
+\definecharacter egrave 232
+\definecharacter Egrave 200
+\definecharacter igrave 236
+\definecharacter Igrave 204
+\definecharacter ograve 242
+\definecharacter Ograve 210
+\definecharacter ugrave 249
+\definecharacter Ugrave 217
+
+\definecharacter aogonek 161
+\definecharacter Aogonek 129
+\definecharacter eogonek 166
+\definecharacter Eogonek 134
+\definecharacter iogonek 167
+\definecharacter Iogonek 135
+\definecharacter uogonek 183
+\definecharacter Uogonek 151
+
+\definecharacter aring 229
+\definecharacter Aring 197
+
+\definecharacter lstroke 170
+\definecharacter Lstroke 138
+\definecharacter ostroke 28
+\definecharacter Ostroke 31
+
+\definecharacter atilde 227
+\definecharacter Atilde 195
+\definecharacter ntilde 241
+\definecharacter Ntilde 209
+\definecharacter otilde 245
+\definecharacter Otilde 213
+
+\definecharacter scommaaccent 179
+\definecharacter Scommaaccent 147
+\definecharacter tcommaaccent 181
+\definecharacter Tcommaaccent 149
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-raw.mkii b/tex/context/base/enco-raw.mkii
new file mode 100644
index 000000000..e3a46e3d7
--- /dev/null
+++ b/tex/context/base/enco-raw.mkii
@@ -0,0 +1,119 @@
+% default instelbaar maken: \enableencoding[main][fallback]
+
+\startencoding[raw]
+
+\definecharacter Acircumflex {A} \definecharacter acircumflex {a}
+\definecharacter Ccircumflex {C} \definecharacter ccircumflex {c}
+\definecharacter Ecircumflex {E} \definecharacter ecircumflex {e}
+\definecharacter Gcircumflex {G} \definecharacter gcircumflex {g}
+\definecharacter Hcircumflex {H} \definecharacter hcircumflex {h}
+\definecharacter Icircumflex {I} \definecharacter icircumflex {i}
+\definecharacter Jcircumflex {J} \definecharacter jcircumflex {j}
+\definecharacter Ocircumflex {O} \definecharacter ocircumflex {o}
+\definecharacter Scircumflex {S} \definecharacter scircumflex {s}
+\definecharacter Ucircumflex {U} \definecharacter ucircumflex {u}
+\definecharacter Wcircumflex {W} \definecharacter wcircumflex {w}
+\definecharacter Ycircumflex {Y} \definecharacter ycircumflex {y}
+
+\definecharacter Agrave {A} \definecharacter agrave {a}
+\definecharacter Egrave {E} \definecharacter egrave {e}
+\definecharacter Igrave {I} \definecharacter igrave {i}
+\definecharacter Ograve {O} \definecharacter ograve {o}
+\definecharacter Ugrave {U} \definecharacter ugrave {u}
+\definecharacter Ygrave {Y} \definecharacter ygrave {y}
+
+\definecharacter Atilde {A} \definecharacter atilde {a}
+\definecharacter Itilde {I} \definecharacter itilde {i}
+\definecharacter Otilde {O} \definecharacter otilde {o}
+\definecharacter Utilde {U} \definecharacter utilde {u}
+\definecharacter Utilde {N} \definecharacter utilde {n}
+
+\definecharacter Adiaeresis {A} \definecharacter adiaeresis {a}
+\definecharacter Ediaeresis {E} \definecharacter ediaeresis {e}
+\definecharacter Idiaeresis {I} \definecharacter idiaeresis {i}
+\definecharacter Odiaeresis {O} \definecharacter odiaeresis {o}
+\definecharacter Udiaeresis {U} \definecharacter udiaeresis {u}
+\definecharacter Ydiaeresis {Y} \definecharacter ydiaeresis {y}
+
+\definecharacter Aacute {A} \definecharacter aacute {a}
+\definecharacter Cacute {C} \definecharacter cacute {c}
+\definecharacter Eacute {E} \definecharacter eacute {e}
+\definecharacter Iacute {I} \definecharacter iacute {i}
+\definecharacter Lacute {L} \definecharacter lacute {l}
+\definecharacter Nacute {N} \definecharacter nacute {n}
+\definecharacter Oacute {O} \definecharacter oacute {o}
+\definecharacter Racute {R} \definecharacter racute {r}
+\definecharacter Sacute {S} \definecharacter sacute {s}
+\definecharacter Uacute {U} \definecharacter uacute {u}
+\definecharacter Yacute {Y} \definecharacter yacute {y}
+\definecharacter Zacute {Z} \definecharacter zacute {z}
+
+\definecharacter Dstroke {D} \definecharacter dstroke {d}
+\definecharacter Hstroke {H} \definecharacter hstroke {h}
+\definecharacter Tstroke {T} \definecharacter tstroke {t}
+
+\definecharacter Cdotaccent {C} \definecharacter cdotaccent {c}
+\definecharacter Edotaccent {E} \definecharacter edotaccent {e}
+\definecharacter Gdotaccent {G} \definecharacter gdotaccent {g}
+\definecharacter Idotaccent {I} \definecharacter idotaccent {i}
+\definecharacter Zdotaccent {Z} \definecharacter zdotaccent {z}
+
+\definecharacter Amacron {A} \definecharacter amacron {a}
+\definecharacter Emacron {E} \definecharacter emacron {e}
+\definecharacter Imacron {I} \definecharacter imacron {i}
+\definecharacter Omacron {O} \definecharacter omacron {o}
+\definecharacter Umacron {U} \definecharacter umacron {u}
+
+\definecharacter Ccedilla {C} \definecharacter ccedilla {c}
+\definecharacter Kcedilla {K} \definecharacter kcedilla {k}
+\definecharacter Lcedilla {L} \definecharacter lcedilla {l}
+\definecharacter Ncedilla {N} \definecharacter ncedilla {n}
+\definecharacter Rcedilla {R} \definecharacter rcedilla {r}
+\definecharacter Scedilla {S} \definecharacter scedilla {s}
+\definecharacter Tcedilla {T} \definecharacter tcedilla {t}
+
+\definecharacter Ohungarumlaut {O} \definecharacter ohungarumlaut {o}
+\definecharacter Uhungarumlaut {U} \definecharacter uhungarumlaut {u}
+
+\definecharacter Aogonek {A} \definecharacter aogonek {a}
+\definecharacter Eogonek {E} \definecharacter eogonek {e}
+\definecharacter Iogonek {I} \definecharacter iogonek {i}
+\definecharacter Uogonek {U} \definecharacter uogonek {u}
+
+\definecharacter Aring {A} \definecharacter aring {a}
+\definecharacter Uring {U} \definecharacter uring {u}
+
+\definecharacter Abreve {A} \definecharacter abreve {a}
+\definecharacter Ebreve {E} \definecharacter ebreve {e}
+\definecharacter Gbreve {G} \definecharacter gbreve {g}
+\definecharacter Ibreve {I} \definecharacter ibreve {i}
+\definecharacter Obreve {O} \definecharacter obreve {o}
+\definecharacter Ubreve {U} \definecharacter ubreve {u}
+
+\definecharacter Ccaron {C} \definecharacter ccaron {c}
+\definecharacter Dcaron {D} \definecharacter dcaron {d}
+\definecharacter Ecaron {E} \definecharacter ecaron {e}
+\definecharacter Lcaron {L} \definecharacter lcaron {l}
+\definecharacter Ncaron {N} \definecharacter ncaron {n}
+\definecharacter Rcaron {R} \definecharacter rcaron {r}
+\definecharacter Scaron {S} \definecharacter scaron {s}
+\definecharacter Tcaron {T} \definecharacter tcaron {t}
+\definecharacter Zcaron {Z} \definecharacter zcaron {z}
+
+\definecharacter dotlessI {I} \definecharacter dotlessi {i}
+\definecharacter dotlessJ {J} \definecharacter dotlessj {j}
+
+\definecharacter AEligature {AE} \definecharacter aeligature {ae}
+\definecharacter Lstroke {L} \definecharacter lstroke {l}
+\definecharacter Ostroke {O} \definecharacter ostroke {o}
+\definecharacter OEligature {OE} \definecharacter oeligature {oe}
+\definecharacter Ssharp {SS} \definecharacter ssharp {ss}
+\definecharacter IJligature {IJ} \definecharacter ijligature {ij}
+
+\definecharacter Aumlaut {A} \definecharacter aumlaut {a}
+\definecharacter Eumlaut {E} \definecharacter eumlaut {e}
+\definecharacter Iumlaut {I} \definecharacter iumlaut {i}
+\definecharacter Oumlaut {O} \definecharacter oumlaut {o}
+\definecharacter Uumlaut {U} \definecharacter uumlaut {u}
+
+\stopencoding
diff --git a/tex/context/base/enco-run.mkii b/tex/context/base/enco-run.mkii
new file mode 100644
index 000000000..50fb52e15
--- /dev/null
+++ b/tex/context/base/enco-run.mkii
@@ -0,0 +1,149 @@
+%D \module
+%D [ file=enco-run,
+%D version=2000.27.12, % moved to runtime module
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Runtime Macros,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=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.
+
+\unprotect
+
+\gdef\visualizecharacters% {}'s needed
+ {\def\uchar##1##2{\hbox to 2.5em
+ {\ifcase##1\relax\red\or\blue\else\green\fi##1\hss##2}}%
+ \let\normalbuildtextaccent\buildtextaccent
+ \let\normalbottomaccent \bottomaccent
+ %\def\char{\green\normalchar}%
+ \def\char % can be used in \oalign
+ {\bgroup\def\char{\green\normalchar\scratchcounter\egroup}%
+ \afterassignment\char\scratchcounter}%
+ \def\buildtextaccent{\let\green\empty\blue\normalbuildtextaccent}%
+ \def\bottomaccent{\let\green\empty\red\normalbottomaccent}}
+
+\unexpanded\gdef\visualizecharacterslegend
+ {\hbox
+ {\edef\banner{\currentencoding\space\fontname\font}%
+ \tttf\banner:\space
+ {\blue composed}\space{\red bottom}\space{\green char}\space raw}}
+
+\gdef\showaccents
+ {\bgroup
+ \savefont
+ \setuptextrules[\c!bodyfont=,\c!style=]
+ \starttextrule{\visualizecharacterslegend}
+ \whitespace
+ \restorefont\setupinterlinespace
+ \visualizecharacters
+ \def\do##1%
+ {{\def\dodo####1%
+ {\hss\hbox to 1em{\hss\expanded{##1####1\recurselevel}\hss}}%
+ \hbox to \hsize
+ {\strut
+ \localcolortrue
+ \hbox to 2em{\tttf\string##1\hss}%
+ \dorecurse{26}{\dodo\character}}%
+ \hbox to \hsize
+ {\strut
+ \localcolortrue
+ \hskip2em
+ \dorecurse{26}{\dodo\Character}}}%
+ \par}
+ \do\'\do\`\do\^\do\~\do\"
+ \do\H\do\r\do\v\do\u\do\=
+ \do\.\do\b\do\d\do\k\do\c
+ \stoptextrule
+ \egroup}
+
+\gdef\showcharacters
+ {\bgroup
+ \savefont
+ \setuptextrules[\c!bodyfont=,\c!style=]
+ \starttextrule{\visualizecharacterslegend}
+ \whitespace
+ \dontcomplain
+ \forgetall
+ \def\startencoding[##1]{}
+ \def\stopencoding{\endinput}
+ \dimen0=\zeropoint
+ \dimen2=\zeropoint
+ \def\definecharacter ##1 ##2 %
+ {\setbox0=\hbox spread 1em{\getvalue{##1}}%
+ \ifdim\wd0>\dimen0 \dimen0=\wd0 \fi
+ \setbox2=\hbox spread 1em{\box0 \tttf##1}
+ \ifdim\wd2>\dimen2 \dimen2=\wd2 \fi}%
+ \readsysfile{\f!encodingprefix def}{}{}
+ \edef\encwidth{\the\dimen0}
+ \dimen0=\hsize
+ \advance\dimen0 2em
+ \advance\dimen2 2em
+ \divide \dimen0 by \dimen2 \advance\dimen0 1sp
+ \edef\enccols{\number\dimen0}
+ \visualizecharacters
+ \startcolumns[\c!n=\enccols,\c!distance=2em]
+ \restorefont\setupinterlinespace
+ \def\definecharacter ##1 ##2 %
+ {\setbox0=\hbox to \hsize{\localcolortrue\hbox to \encwidth{\getvalue{##1}\hss}\tttf##1}%
+ \ht0\strutheight \dp0\strutdepth \box0 \allowbreak}
+ \readsysfile{\f!encodingprefix def}{}{}
+ \stopcolumns
+ \stoptextrule
+ \egroup}
+
+% \hbox
+% {\font\test=uplr8t \test \ruledhbox{t}
+% \font\test=uplr8r \test \ruledhbox{t}}
+
+\ifnum\texengine=\pdftexengine
+
+ \gdef\showhyphenations#1%
+ {\starttabulate[|le|l|]
+ \NC language \NC \currentlanguage\ (internal code:\the\normallanguage) \NC \NR
+ \NC font \NC \fontname\font \NC \NR
+ \NC encoding \NC \ifx\@@fontencoding\empty not set\else\@@fontencoding\fi \NC \NR
+ \NC mapping \NC \ifx\@@fontmapping \empty not set\else\@@fontmapping \fi \NC \NR
+ \NC handling \NC \ifx\@@fonthandling\empty not set\else\@@fonthandling\fi \NC \NR
+ \NC sample \NC \hyphenatedword{#1} \NC \NR
+ \stoptabulate}
+
+ \gdef\showmapping
+ {\dostepwiserecurse{128}{255}{1}
+ {\hbox\bgroup
+ \hbox to 2em{\hss\recurselevel}%
+ \hbox to 2em{\hss\char\recurselevel\hss}%
+ \hbox to 3em{\hss\ifcase\lccode\recurselevel\else\the \lccode\recurselevel\fi}%
+ \hbox to 2em{\hss\ifcase\lccode\recurselevel\else\char\lccode\recurselevel\fi\hss}%
+ \hbox to 3em{\hss\ifcase\lccode\recurselevel\else\the \uccode\recurselevel\fi}%
+ \hbox to 2em{\hss\ifcase\uccode\recurselevel\else\char\uccode\recurselevel\fi\hss}%
+ \egroup
+ \endgraf}}
+
+ \gdef\showcharacterbounds
+ {\bgroup
+ \localcolortrue
+ \dorecurse{255}
+ {\ifdim\fontcharwd\font\recurselevel>\zeropoint
+ \noindent\ruledhbox{\darkgray\char\recurselevel}\space
+ \fi}\unskip
+ \egroup}
+
+\else
+
+ \gdef\showhyphenations#1%
+ {\starttabulate[|le|l|]
+ \NC language \NC \currentlanguage\ (internal code:\the\normallanguage) \NC \NR
+ \NC font \NC \fontname\font \NC \NR
+ \NC sample \NC \hyphenatedword{#1} \NC \NR
+ \stoptabulate}
+
+ \globallet\showmapping\relax
+
+ \globallet\showcharacterbounds\relax
+
+\fi
+
+\protect \endinput
diff --git a/tex/context/base/enco-t5.mkii b/tex/context/base/enco-t5.mkii
new file mode 100644
index 000000000..251c68765
--- /dev/null
+++ b/tex/context/base/enco-t5.mkii
@@ -0,0 +1,244 @@
+%D \module
+%D [ file=enco-t5,
+%D version=2004.11.16,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=New Vietnamese Encoding,
+%D author=Hans Hagen \& Adam Lindsay,
+%D date=\currentdate,
+%D copyright=PRAGMA \& Adam Lindsay]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module is derived from the enco-x5 encoding, but now
+%D approaches the world with named glyphs.
+
+\startencoding[t5]
+
+\definecasemaps 128 to 159 lc +32 uc 0
+
+\definecasemaps 160 to 191 lc 0 uc -32
+
+\definecasemaps 192 to 223 lc +32 uc 0
+
+\definecasemaps 224 to 225 lc 0 uc -32
+
+\definecasemap 26 26 27 \definecasemap 27 26 27
+\definecasemap 28 28 29 \definecasemap 29 28 29
+\definecasemap 30 30 31 \definecasemap 31 30 31
+
+\definecharacter textgrave 0
+\definecharacter textacute 1
+\definecharacter textcircumflex 2
+\definecharacter texttilde 3
+\definecharacter textdiaeresis 4
+\definecharacter textbottomdot 5
+\definecharacter textring 6
+\definecharacter textcaron 7
+\definecharacter textbreve 8
+\definecharacter textmacron 9
+\definecharacter textdotaccent 10
+\definecharacter textcedilla 11
+\definecharacter texthookabove 12
+\definecharacter textogonek {}
+
+\definecharacter quotesinglebase 13
+\definecharacter guilsingleleft 14
+\definecharacter guilsingleright 15
+\definecharacter quotedblleft 16
+\definecharacter quotedblright 17
+\definecharacter quotedblbase 18
+\definecharacter leftguillemot 19
+\definecharacter rightguillemot 20
+\definecharacter endash 21
+\definecharacter emdash 22
+
+\definecharacter cwm 23
+\definecharacter zeroinferior 24
+\definecharacter Yhook 26
+\definecharacter yhook 27
+\definecharacter Ydotbelow 28
+\definecharacter ydotbelow 29
+\definecharacter Dstroke 30
+\definecharacter dstroke 31
+\definecharacter textvisiblespace 32
+
+\definecharacter dotlessi 25
+%definecharacter DJ 30
+%definecharacter dj 31
+\definecharacter Agrave 128
+\definecharacter Aacute 129
+\definecharacter Atilde 130
+\definecharacter Ahook 131
+\definecharacter Adotbelow 132
+\definecharacter Acircumflex 133
+\definecharacter Acircumflexgrave 134
+\definecharacter Acircumflexacute 135
+\definecharacter Acircumflextilde 136
+\definecharacter Acircumflexhook 137
+\definecharacter Acircumflexdotbelow 138
+\definecharacter Abreve 139
+\definecharacter Abrevegrave 140
+\definecharacter Abreveacute 141
+\definecharacter Abrevetilde 142
+\definecharacter Abrevehook 143
+\definecharacter Abrevedotbelow 144
+\definecharacter Egrave 145
+\definecharacter Eacute 146
+\definecharacter Etilde 147
+\definecharacter Ehook 148
+\definecharacter Edotbelow 149
+\definecharacter Ecircumflex 150
+\definecharacter Ecircumflexgrave 151
+\definecharacter Ecircumflexacute 152
+\definecharacter Ecircumflextilde 153
+\definecharacter Ecircumflexhook 154
+\definecharacter Ecircumflexdotbelow 155
+\definecharacter Igrave 156
+\definecharacter Iacute 157
+\definecharacter Itilde 158
+\definecharacter Ihook 159
+\definecharacter agrave 160
+\definecharacter aacute 161
+\definecharacter atilde 162
+\definecharacter ahook 163
+\definecharacter adotbelow 164
+\definecharacter acircumflex 165
+\definecharacter acircumflexgrave 166
+\definecharacter acircumflexacute 167
+\definecharacter acircumflextilde 168
+\definecharacter acircumflexhook 169
+\definecharacter acircumflexdotbelow 170
+\definecharacter abreve 171
+\definecharacter abrevegrave 172
+\definecharacter abreveacute 173
+\definecharacter abrevetilde 174
+\definecharacter abrevehook 175
+\definecharacter abrevedotbelow 176
+\definecharacter egrave 177
+\definecharacter eacute 178
+\definecharacter etilde 179
+\definecharacter ehook 180
+\definecharacter edotbelow 181
+\definecharacter ecircumflex 182
+\definecharacter ecircumflexgrave 183
+\definecharacter ecircumflexacute 184
+\definecharacter ecircumflextilde 185
+\definecharacter ecircumflexhook 186
+\definecharacter ecircumflexdotbelow 187
+\definecharacter igrave 188
+\definecharacter iacute 189
+\definecharacter itilde 190
+\definecharacter ihook 191
+\definecharacter Idotbelow 192
+\definecharacter Ograve 193
+\definecharacter Oacute 194
+\definecharacter Otilde 195
+\definecharacter Ohook 196
+\definecharacter Odotbelow 197
+\definecharacter Ocircumflex 198
+\definecharacter Ocircumflexgrave 199
+\definecharacter Ocircumflexacute 200
+\definecharacter Ocircumflextilde 201
+\definecharacter Ocircumflexhook 202
+\definecharacter Ocircumflexdotbelow 203
+\definecharacter Ohorn 204
+\definecharacter Ohorngrave 205
+\definecharacter Ohornacute 206
+\definecharacter Ohorntilde 207
+\definecharacter Ohornhook 208
+\definecharacter Ohorndotbelow 209
+\definecharacter Ugrave 210
+\definecharacter Uacute 211
+\definecharacter Utilde 212
+\definecharacter Uhook 213
+\definecharacter Udotbelow 214
+\definecharacter Uhorn 215
+\definecharacter Uhorngrave 216
+\definecharacter Uhornacute 217
+\definecharacter Uhorntilde 218
+\definecharacter Uhornhook 219
+\definecharacter Uhorndotbelow 220
+\definecharacter Ytilde 223
+\definecharacter idotbelow 224
+\definecharacter ograve 225
+\definecharacter oacute 226
+\definecharacter otilde 227
+\definecharacter ohook 228
+\definecharacter odotbelow 229
+\definecharacter ocircumflex 230
+\definecharacter ocircumflexgrave 231
+\definecharacter ocircumflexacute 232
+\definecharacter ocircumflextilde 233
+\definecharacter ocircumflexhook 234
+\definecharacter ocircumflexdotbelow 235
+\definecharacter ohorn 236
+\definecharacter ohorngrave 237
+\definecharacter ohornacute 238
+\definecharacter ohorntilde 239
+\definecharacter ohornhook 240
+\definecharacter ohorndotbelow 241
+\definecharacter ugrave 242
+\definecharacter uacute 243
+\definecharacter utilde 244
+\definecharacter uhook 245
+\definecharacter udotbelow 246
+\definecharacter uhorn 247
+\definecharacter uhorngrave 248
+\definecharacter uhornacute 249
+\definecharacter uhorntilde 250
+\definecharacter uhornhook 251
+\definecharacter uhorndotbelow 252
+\definecharacter ygrave 253
+\definecharacter yacute 254
+\definecharacter ytilde 255
+
+\stopencoding
+
+\endinput
+
+% \startencoding [x5]
+%
+% \definecharacter aa {\xfiveencodedaa}
+% \definecharacter AA {\xfiveencodedAA}
+%
+% \stopencoding
+%
+% \def\xfiveencodedaa%
+% {\accent23a}
+%
+% \def\xfiveencodedAA%
+% {\leavevmode
+% \setbox\zerocount\hbox{h}%
+% \dimen@\ht\zerocount
+% \advance\dimen@ -1ex
+% \rlap{\raise.67\dimen@\hbox{\char23}}A}
+
+% \quotesinglbase 13
+% \guilsinglleft 14
+% \guilsinglright 15
+% \textquotedblleft 16
+% \textquotedblright 17
+% \quotedblbase 18
+% \guillemotleft 19
+% \guillemotright 20
+% \textendash 21
+% \textemdash 22
+% \textcompwordmark 23
+% \textperthousand \% \char 24
+% \textpertenthousand \%\char 24\char 24
+% \textvisiblespace 32
+% \textquotedbl `\"
+% \textdollar `\$
+% \textquoteright `\'
+% \textless `\<
+% \textgreater `\>
+% \textbackslash `\
+% \textasciicircum `\^
+% \textunderscore 95
+% \textquoteleft `\`
+% \textbraceleft `\{
+% \textbar `\|
+% \textbraceright `\}
+% \textasciitilde `\~
diff --git a/tex/context/base/enco-tbo.mkii b/tex/context/base/enco-tbo.mkii
new file mode 100644
index 000000000..475be4602
--- /dev/null
+++ b/tex/context/base/enco-tbo.mkii
@@ -0,0 +1,222 @@
+%D \module
+%D [ file=enco-tbo,
+%D version=2000.05.07, % 2001.8.4,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=TeXBaseOne Encoding,
+%D author={Patrick Gundlach, Hans Hagen},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\startmapping[8r]
+
+\resetcaserange 128 to 255
+
+\definecasemap 228 228 196 \definecasemap 196 228 196
+\definecasemap 235 235 203 \definecasemap 203 235 203
+\definecasemap 239 239 207 \definecasemap 207 239 207
+\definecasemap 246 246 214 \definecasemap 214 246 214
+\definecasemap 252 252 220 \definecasemap 220 252 220
+\definecasemap 255 255 159 \definecasemap 159 255 159
+
+\definecasemap 225 225 193 \definecasemap 193 225 193
+\definecasemap 233 233 201 \definecasemap 201 233 201
+\definecasemap 237 237 205 \definecasemap 205 237 205
+\definecasemap 243 243 211 \definecasemap 211 243 211
+\definecasemap 250 250 218 \definecasemap 218 250 218
+\definecasemap 253 253 221 \definecasemap 221 253 221
+
+\definecasemap 224 224 192 \definecasemap 192 224 192
+\definecasemap 232 232 200 \definecasemap 200 232 200
+\definecasemap 236 236 204 \definecasemap 204 236 204
+\definecasemap 242 242 210 \definecasemap 210 242 210
+\definecasemap 249 249 217 \definecasemap 217 249 217
+
+\definecasemap 226 226 194 \definecasemap 194 226 194
+\definecasemap 234 234 202 \definecasemap 202 234 202
+\definecasemap 238 238 206 \definecasemap 206 238 206
+\definecasemap 244 244 212 \definecasemap 212 244 212
+\definecasemap 251 251 219 \definecasemap 219 251 219
+
+\definecasemap 227 227 195 \definecasemap 195 227 195
+\definecasemap 241 241 209 \definecasemap 209 241 209
+\definecasemap 245 245 213 \definecasemap 213 245 213
+
+\stopmapping
+
+\startencoding[8r]
+
+\definecharacter textacute 180
+\definecharacter textbreve 11
+\definecharacter textcaron 16
+\definecharacter textcedilla 184
+\definecharacter textcircumflex 136
+\definecharacter textdiaeresis 168
+\definecharacter textdotaccent 1
+\definecharacter textgrave 30
+\definecharacter texthungarumlaut 5
+\definecharacter textmacron 175
+\definecharacter textogonek 8
+\definecharacter textring 9
+\definecharacter texttilde 152
+
+\definecharacter dotlessi 17
+%definecharacter dotlessj 18
+
+\definecharacter endash 150
+\definecharacter emdash 151
+
+\definecharacter oeligature 156
+\definecharacter OEligature 140
+\definecharacter aeligature 230
+\definecharacter AEligature 198
+
+\definecharacter ssharp 223
+
+\definecharacter thorn 254
+\definecharacter Thorn 222
+
+\definecharacter exclamdown 161
+\definecharacter questiondown 191
+
+\definecharacter copyright 169
+\definecharacter registered 174
+\definecharacter trademark 153
+
+\definecharacter sectionmark 167
+\definecharacter paragraphmark 182
+
+\definecharacter onequarter 188
+\definecharacter onehalf 189
+\definecharacter threequarter 190
+\definecharacter onesuperior 185
+\definecharacter twosuperior 178
+\definecharacter threesuperior 179
+
+\definecharacter textcent 162
+\definecharacter textcurrency 164
+\definecharacter texteuro 128
+\definecharacter textflorin 131
+\definecharacter textsterling 163
+\definecharacter textyen 165
+
+\definecharacter percent 37
+\definecharacter perthousand 137
+
+\definecharacter periodcentered 183
+\definecharacter softhyphen 173
+
+\definecharacter textasciicircum 94
+\definecharacter textasciitilde 126
+\definecharacter textslash 47
+\definecharacter textbackslash 92
+\definecharacter textbraceleft 123
+\definecharacter textbraceright 125
+\definecharacter textunderscore 95
+
+\definecharacter textbrokenbar 166
+\definecharacter textbullet 149
+\definecharacter textdag 134
+\definecharacter textddag 135
+\definecharacter textdegree 176
+\definecharacter textdiv 247
+\definecharacter textellipsis 133
+\definecharacter textfraction 4
+\definecharacter textlognot 172
+\definecharacter textminus 12
+\definecharacter textmu 181
+\definecharacter textmultiply 215
+\definecharacter textpm 177
+
+\definecharacter quotedbl 34
+\definecharacter quotedblbase 132
+\definecharacter quotedblleft 147
+\definecharacter quotedblright 148
+
+\definecharacter quotesingle 31
+\definecharacter quotesinglebase 130
+
+\definecharacter quoteleft 96
+\definecharacter quoteright 39
+
+\definecharacter guilsingleleft 139
+\definecharacter guilsingleright 155
+\definecharacter leftguillemot 171
+\definecharacter rightguillemot 187
+
+\definecharacter aacute 225
+\definecharacter Aacute 193
+\definecharacter eacute 233
+\definecharacter Eacute 201
+\definecharacter iacute 237
+\definecharacter Iacute 205
+\definecharacter oacute 243
+\definecharacter Oacute 211
+\definecharacter uacute 250
+\definecharacter Uacute 218
+\definecharacter Yacute 221
+\definecharacter yacute 253
+
+\definecharacter scaron 154
+\definecharacter Scaron 138
+%definecharacter Zcaron 141
+
+\definecharacter ccedilla 231
+\definecharacter Ccedilla 199
+
+\definecharacter acircumflex 226
+\definecharacter Acircumflex 194
+\definecharacter ecircumflex 234
+\definecharacter Ecircumflex 202
+\definecharacter icircumflex 238
+\definecharacter Icircumflex 206
+\definecharacter ocircumflex 244
+\definecharacter Ocircumflex 212
+\definecharacter ucircumflex 251
+\definecharacter Ucircumflex 219
+
+\definecharacter adiaeresis 228
+\definecharacter Adiaeresis 196
+\definecharacter ediaeresis 235
+\definecharacter Ediaeresis 203
+\definecharacter idiaeresis 239
+\definecharacter Idiaeresis 207
+\definecharacter odiaeresis 246
+\definecharacter Odiaeresis 214
+\definecharacter udiaeresis 252
+\definecharacter Udiaeresis 220
+\definecharacter ydiaeresis 255
+\definecharacter Ydiaeresis 159
+
+\definecharacter agrave 224
+\definecharacter Agrave 192
+\definecharacter egrave 232
+\definecharacter Egrave 200
+\definecharacter igrave 236
+\definecharacter Igrave 204
+\definecharacter ograve 242
+\definecharacter Ograve 210
+\definecharacter ugrave 249
+\definecharacter Ugrave 217
+
+\definecharacter aring 229
+\definecharacter Aring 197
+
+\definecharacter lstroke 7
+\definecharacter Lstroke 6
+\definecharacter ostroke 248
+\definecharacter Ostroke 216
+
+\definecharacter atilde 227
+\definecharacter Atilde 195
+\definecharacter ntilde 241
+\definecharacter Ntilde 209
+\definecharacter otilde 245
+\definecharacter Otilde 213
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-uc.mkii b/tex/context/base/enco-uc.mkii
new file mode 100644
index 000000000..981eb6ae4
--- /dev/null
+++ b/tex/context/base/enco-uc.mkii
@@ -0,0 +1,1091 @@
+%D \module
+%D [ file=enco-uc,
+%D version=2000.xx.xx, % and later
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Unicode (backwards mapping),
+%D author={Adam Lindsay \& Hans Hagen},
+%D date=\currentdate,
+%D copyright=PRAGMA ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D An alternative approach would be to misuse the utf vectors, but they
+%D don't carry enough info around.
+
+% todo : \defineucharacter hebrewAlef 5 "D0
+
+\startencoding[uc]
+
+\definecharacter Agrave {\uchar0{192}}
+\definecharacter Aacute {\uchar0{193}}
+\definecharacter Acircumflex {\uchar0{194}}
+\definecharacter Atilde {\uchar0{195}}
+\definecharacter Adiaeresis {\uchar0{196}}
+\definecharacter Aring {\uchar0{197}}
+\definecharacter AEligature {\uchar0{198}}
+\definecharacter Ccedilla {\uchar0{199}}
+\definecharacter Egrave {\uchar0{200}}
+\definecharacter Eacute {\uchar0{201}}
+\definecharacter Ediaeresis {\uchar0{203}}
+\definecharacter Igrave {\uchar0{204}}
+\definecharacter Iacute {\uchar0{205}}
+\definecharacter Icircumflex {\uchar0{206}}
+\definecharacter Idiaeresis {\uchar0{207}}
+\definecharacter Eth {\uchar0{208}}
+\definecharacter Ntilde {\uchar0{209}}
+\definecharacter Ograve {\uchar0{210}}
+\definecharacter Oacute {\uchar0{211}}
+\definecharacter Ocircumflex {\uchar0{212}}
+\definecharacter Otilde {\uchar0{213}}
+\definecharacter Odiaeresis {\uchar0{214}}
+
+\definecharacter Ostroke {\uchar0{216}}
+\definecharacter Ugrave {\uchar0{217}}
+\definecharacter Uacute {\uchar0{218}}
+\definecharacter Uhungarumlaut {\uchar0{219}}
+\definecharacter Udiaeresis {\uchar0{220}}
+\definecharacter Yacute {\uchar0{221}}
+\definecharacter Thorn {\uchar0{222}}
+\definecharacter ssharp {\uchar0{223}}
+\definecharacter agrave {\uchar0{224}}
+\definecharacter aacute {\uchar0{225}}
+\definecharacter acircumflex {\uchar0{226}}
+\definecharacter atilde {\uchar0{227}}
+\definecharacter adiaeresis {\uchar0{228}}
+\definecharacter aring {\uchar0{229}}
+\definecharacter aeligature {\uchar0{230}}
+\definecharacter ccedilla {\uchar0{231}}
+\definecharacter egrave {\uchar0{232}}
+\definecharacter eacute {\uchar0{233}}
+\definecharacter ecircumflex {\uchar0{234}}
+\definecharacter ediaeresis {\uchar0{235}}
+\definecharacter igrave {\uchar0{236}}
+\definecharacter iacute {\uchar0{237}}
+\definecharacter icircumflex {\uchar0{238}}
+\definecharacter idiaeresis {\uchar0{239}}
+\definecharacter eth {\uchar0{240}}
+\definecharacter ntilde {\uchar0{241}}
+\definecharacter ograve {\uchar0{242}}
+\definecharacter oacute {\uchar0{243}}
+\definecharacter ocircumflex {\uchar0{244}}
+\definecharacter otilde {\uchar0{245}}
+\definecharacter odiaeresis {\uchar0{246}}
+
+\definecharacter ostroke {\uchar0{248}}
+\definecharacter ugrave {\uchar0{249}}
+\definecharacter uacute {\uchar0{250}}
+\definecharacter ucircumflex {\uchar0{251}}
+\definecharacter udiaeresis {\uchar0{252}}
+\definecharacter yacute {\uchar0{253}}
+\definecharacter thorn {\uchar0{254}}
+\definecharacter ydiaeresis {\uchar0{255}}
+
+\definecharacter Amacron {\uchar1{0}}
+\definecharacter amacron {\uchar1{1}}
+\definecharacter Abreve {\uchar1{2}}
+\definecharacter abreve {\uchar1{3}}
+\definecharacter Aogonek {\uchar1{4}}
+\definecharacter aogonek {\uchar1{5}}
+\definecharacter Cacute {\uchar1{6}}
+\definecharacter cacute {\uchar1{7}}
+\definecharacter Ccircumflex {\uchar1{8}}
+\definecharacter ccircumflex {\uchar1{9}}
+\definecharacter Cdotaccent {\uchar1{10}}
+\definecharacter cdotaccent {\uchar1{11}}
+\definecharacter Ccaron {\uchar1{12}}
+\definecharacter ccaron {\uchar1{13}}
+\definecharacter Dcaron {\uchar1{14}}
+\definecharacter dcaron {\uchar1{15}}
+\definecharacter Dstroke {\uchar1{16}}
+\definecharacter dstroke {\uchar1{17}}
+\definecharacter Emacron {\uchar1{18}}
+\definecharacter emacron {\uchar1{19}}
+\definecharacter Ebreve {\uchar1{20}}
+\definecharacter ebreve {\uchar1{21}}
+\definecharacter Edotaccent {\uchar1{22}}
+\definecharacter edotaccent {\uchar1{23}}
+\definecharacter Eogonek {\uchar1{24}}
+\definecharacter eogonek {\uchar1{25}}
+\definecharacter Ecaron {\uchar1{26}}
+\definecharacter ecaron {\uchar1{27}}
+\definecharacter Gcircumflex {\uchar1{28}}
+\definecharacter gcircumflex {\uchar1{29}}
+\definecharacter Gbreve {\uchar1{30}}
+\definecharacter gbreve {\uchar1{31}}
+\definecharacter Gdotaccent {\uchar1{32}}
+\definecharacter gdotaccent {\uchar1{33}}
+\definecharacter Gcommaaccent {\uchar1{34}}
+\definecharacter gcommaaccent {\uchar1{35}}
+\definecharacter Hcircumflex {\uchar1{36}}
+\definecharacter hcircumflex {\uchar1{37}}
+\definecharacter Hstroke {\uchar1{38}}
+\definecharacter hstroke {\uchar1{39}}
+\definecharacter Itilde {\uchar1{40}}
+\definecharacter itilde {\uchar1{41}}
+\definecharacter Imacron {\uchar1{42}}
+\definecharacter imacron {\uchar1{43}}
+\definecharacter Ibreve {\uchar1{44}}
+\definecharacter ibreve {\uchar1{45}}
+\definecharacter Iogonek {\uchar1{46}}
+\definecharacter iogonek {\uchar1{47}}
+\definecharacter Idotaccent {\uchar1{48}}
+\definecharacter dotlessi {\uchar1{49}}
+\definecharacter IJligature {\uchar1{50}}
+\definecharacter ijligature {\uchar1{51}}
+\definecharacter Jcircumflex {\uchar1{52}}
+\definecharacter jcircumflex {\uchar1{53}}
+\definecharacter Kcommaaccent {\uchar1{54}}
+\definecharacter kcommaaccent {\uchar1{55}}
+\definecharacter kkra {\uchar1{56}}
+\definecharacter Lacute {\uchar1{57}}
+\definecharacter lacute {\uchar1{58}}
+\definecharacter Lcommaaccent {\uchar1{59}}
+\definecharacter lcommaaccent {\uchar1{60}}
+\definecharacter Lcaron {\uchar1{61}}
+\definecharacter lcaron {\uchar1{62}}
+\definecharacter Ldotmiddle {\uchar1{63}}
+\definecharacter ldotmiddle {\uchar1{64}}
+\definecharacter Lstroke {\uchar1{65}}
+\definecharacter lstroke {\uchar1{66}}
+\definecharacter Nacute {\uchar1{67}}
+\definecharacter nacute {\uchar1{68}}
+\definecharacter Ncommaaccent {\uchar1{69}}
+\definecharacter ncommaaccent {\uchar1{70}}
+\definecharacter Ncaron {\uchar1{71}}
+\definecharacter ncaron {\uchar1{72}}
+\definecharacter napostrophe {\uchar1{73}}
+\definecharacter Neng {\uchar1{74}}
+\definecharacter neng {\uchar1{75}}
+\definecharacter Omacron {\uchar1{76}}
+\definecharacter omacron {\uchar1{77}}
+\definecharacter Obreve {\uchar1{78}}
+\definecharacter obreve {\uchar1{79}}
+\definecharacter Ohungarumlaut {\uchar1{80}}
+\definecharacter ohungarumlaut {\uchar1{81}}
+\definecharacter OEligature {\uchar1{82}}
+\definecharacter oeligature {\uchar1{83}}
+\definecharacter Racute {\uchar1{84}}
+\definecharacter racute {\uchar1{85}}
+\definecharacter Rcommaaccent {\uchar1{86}}
+\definecharacter rcommaaccent {\uchar1{87}}
+\definecharacter Rcaron {\uchar1{88}}
+\definecharacter rcaron {\uchar1{89}}
+\definecharacter Sacute {\uchar1{90}}
+\definecharacter sacute {\uchar1{91}}
+\definecharacter Scircumflex {\uchar1{92}}
+\definecharacter scircumflex {\uchar1{93}}
+\definecharacter Scedilla {\uchar1{94}}
+\definecharacter scedilla {\uchar1{95}}
+\definecharacter Scaron {\uchar1{96}}
+\definecharacter scaron {\uchar1{97}}
+\definecharacter Tcedilla {\uchar1{98}}
+\definecharacter tcedilla {\uchar1{99}}
+\definecharacter Tcaron {\uchar1{100}}
+\definecharacter tcaron {\uchar1{101}}
+\definecharacter Tstroke {\uchar1{102}}
+\definecharacter tstroke {\uchar1{103}}
+\definecharacter Utilde {\uchar1{104}}
+\definecharacter utilde {\uchar1{105}}
+\definecharacter Umacron {\uchar1{106}}
+\definecharacter umacron {\uchar1{107}}
+\definecharacter Ubreve {\uchar1{108}}
+\definecharacter ubreve {\uchar1{109}}
+\definecharacter Uring {\uchar1{110}}
+\definecharacter uring {\uchar1{111}}
+\definecharacter Uhungarumlaut {\uchar1{112}}
+\definecharacter uhungarumlaut {\uchar1{113}}
+\definecharacter Uogonek {\uchar1{114}}
+\definecharacter uogonek {\uchar1{115}}
+\definecharacter Wcircumflex {\uchar1{116}}
+\definecharacter wcircumflex {\uchar1{117}}
+\definecharacter Ycircumflex {\uchar1{118}}
+\definecharacter ycircumflex {\uchar1{119}}
+\definecharacter Ydiaeresis {\uchar1{120}}
+\definecharacter Zacute {\uchar1{121}}
+\definecharacter zacute {\uchar1{122}}
+\definecharacter Zdotaccent {\uchar1{123}}
+\definecharacter zdotaccent {\uchar1{124}}
+\definecharacter Zcaron {\uchar1{125}}
+\definecharacter zcaron {\uchar1{126}}
+\definecharacter slong {\uchar1{127}}
+
+\stopencoding
+
+\startencoding[uc]
+
+\definecharacter endash {\uchar{32}{19}}
+\definecharacter emdash {\uchar{32}{20}}
+\definecharacter quoteleft {\uchar{32}{24}}
+\definecharacter quoteright {\uchar{32}{25}}
+\definecharacter quotesinglebase {\uchar{32}{26}}
+
+\definecharacter quotedblleft {\uchar{32}{28}}
+\definecharacter quotedblright {\uchar{32}{29}}
+\definecharacter quotedblbase {\uchar{32}{30}}
+
+\definecharacter leftguillemot {\uchar0{171}}
+\definecharacter rightguillemot {\uchar0{187}}
+
+\definecharacter guilsingleleft {\uchar{32}{57}}
+\definecharacter guilsingleright {\uchar{32}{58}}
+
+\stopencoding
+
+%D Adam Lindsay's additions
+
+\startencoding[uc]
+
+\definecharacter exclamdown {\uchar0{161}}
+\definecharacter textcent {\uchar0{162}}
+\definecharacter textsterling {\uchar0{163}}
+\definecharacter textcurrency {\uchar0{164}}
+\definecharacter textyen {\uchar0{165}}
+\definecharacter textbrokenbar {\uchar0{166}}
+\definecharacter sectionmark {\uchar0{167}}
+\definecharacter textdiaresis {\uchar0{168}}
+\definecharacter copyright {\uchar0{169}}
+
+\definecharacter textlognot {\uchar0{172}}
+\definecharacter softhyphen {\uchar0{173}}
+\definecharacter registered {\uchar0{174}}
+\definecharacter textmacron {\uchar0{175}}
+\definecharacter textdegree {\uchar0{176}}
+\definecharacter textpm {\uchar0{177}}
+\definecharacter twosuperior {\uchar0{178}}
+\definecharacter threesuperior {\uchar0{179}}
+\definecharacter textacute {\uchar0{180}}
+\definecharacter textmu {\uchar0{181}}
+\definecharacter paragraphmark {\uchar0{182}}
+\definecharacter periodcentered {\uchar0{183}}
+\definecharacter textcedilla {\uchar0{184}}
+\definecharacter onesuperior {\uchar0{185}}
+
+\definecharacter textgrave {\uchar3{0}}
+\definecharacter textacute {\uchar3{1}}
+\definecharacter textcircumflex {\uchar3{2}}
+\definecharacter texttilde {\uchar3{3}}
+\definecharacter textmacron {\uchar3{4}}
+\definecharacter textbreve {\uchar3{6}}
+\definecharacter textdotaccent {\uchar3{7}}
+\definecharacter textdiaeresis {\uchar3{8}}
+\definecharacter textring {\uchar3{10}}
+\definecharacter texthungarumlaut {\uchar3{11}}
+\definecharacter textcaron {\uchar3{12}}
+\definecharacter textogonek {\uchar3{40}}
+
+\definecharacter percent {\uchar0{37}}
+\definecharacter textunderscore {\uchar0{95}}
+
+\definecharacter ordfeminine {\uchar0{170}}
+\definecharacter ordmasculine {\uchar0{186}}
+\definecharacter onequarter {\uchar0{188}}
+\definecharacter onehalf {\uchar0{189}}
+\definecharacter threequarter {\uchar0{190}}
+\definecharacter questiondown {\uchar0{191}}
+
+\definecharacter textmultiply {\uchar0{215}}
+\definecharacter textdiv {\uchar0{247}}
+
+\definecharacter textminus {\uchar{32}{18}}
+\definecharacter textdag {\uchar{32}{32}}
+\definecharacter textddag {\uchar{32}{33}}
+\definecharacter textbullet {\uchar{32}{34}}
+\definecharacter textellipsis {\uchar{32}{38}}
+\definecharacter perthousand {\uchar{32}{48}}
+
+%new:
+\definecharacter Scommaaccent {\uchar2{24}}
+\definecharacter scommaaccent {\uchar2{25}}
+\definecharacter Tcommaaccent {\uchar2{26}}
+\definecharacter tcommaaccent {\uchar2{27}}
+
+\stopencoding
+
+%D Mojca's and Taco's additions:
+
+\startencoding[uc]
+
+\definecharacter textasciicircum {\uchar{0}{94}} % 5e
+\definecharacter textgrave {\uchar{0}{96}} % 60
+\definecharacter textdiaeresis {\uchar{0}{168}} % a8
+%definecharacter textmacron {\uchar{0}{175}} % af
+%definecharacter textacute {\uchar{0}{180}} % b4
+%definecharacter textcedilla {\uchar{0}{184}} % b8
+\definecharacter textcircumflex {\uchar{2}{198}} % c6
+\definecharacter textcaron {\uchar{2}{199}} % c7
+\definecharacter textbreve {\uchar{2}{216}} % d8
+\definecharacter textdotaccent {\uchar{2}{217}} % d9
+\definecharacter textring {\uchar{2}{218}} % da
+\definecharacter textogonek {\uchar{2}{219}} % db
+\definecharacter texttilde {\uchar{2}{220}} % dc
+\definecharacter texthungarumlaut {\uchar{2}{221}} % dd
+
+\stopencoding
+
+%D Vietnamese:
+
+\startencoding[uc]
+
+\definecharacter Ohorn {\uchar1{160}}
+\definecharacter ohorn {\uchar1{161}}
+\definecharacter Uhorn {\uchar1{175}}
+\definecharacter uhorn {\uchar1{176}}
+
+\definecharacter Yhook {\uchar{30}{246}}
+\definecharacter yhook {\uchar{30}{247}}
+\definecharacter Ydotbelow {\uchar{30}{244}}
+\definecharacter ydotbelow {\uchar{30}{245}}
+\definecharacter Ahook {\uchar{30}{162}}
+\definecharacter Adotbelow {\uchar{30}{160}}
+\definecharacter Acircumflexgrave {\uchar{30}{166}}
+\definecharacter Acircumflexacute {\uchar{30}{164}}
+\definecharacter Acircumflextilde {\uchar{30}{170}}
+\definecharacter Acircumflexhook {\uchar{30}{168}}
+\definecharacter Acircumflexdotbelow {\uchar{30}{172}}
+\definecharacter Abrevegrave {\uchar{30}{176}}
+\definecharacter Abreveacute {\uchar{30}{174}}
+\definecharacter Abrevetilde {\uchar{30}{180}}
+\definecharacter Abrevehook {\uchar{30}{178}}
+\definecharacter Abrevedotbelow {\uchar{30}{182}}
+\definecharacter Ehook {\uchar{30}{186}}
+\definecharacter Edotbelow {\uchar{30}{184}}
+\definecharacter Ecircumflexgrave {\uchar{30}{192}}
+\definecharacter Ecircumflexacute {\uchar{30}{190}}
+\definecharacter Ecircumflextilde {\uchar{30}{196}}
+\definecharacter Ecircumflexhook {\uchar{30}{194}}
+\definecharacter Ecircumflexdotbelow {\uchar{30}{198}}
+\definecharacter Ihook {\uchar{30}{200}}
+\definecharacter ahook {\uchar{30}{163}}
+\definecharacter adotbelow {\uchar{30}{161}}
+\definecharacter acircumflexgrave {\uchar{30}{167}}
+\definecharacter acircumflexacute {\uchar{30}{165}}
+\definecharacter acircumflextilde {\uchar{30}{171}}
+\definecharacter acircumflexhook {\uchar{30}{169}}
+\definecharacter acircumflexdotbelow {\uchar{30}{173}}
+\definecharacter abrevegrave {\uchar{30}{177}}
+\definecharacter abreveacute {\uchar{30}{175}}
+\definecharacter abrevetilde {\uchar{30}{181}}
+\definecharacter abrevehook {\uchar{30}{179}}
+\definecharacter abrevedotbelow {\uchar{30}{183}}
+\definecharacter ehook {\uchar{30}{187}}
+\definecharacter edotbelow {\uchar{30}{185}}
+\definecharacter ecircumflexgrave {\uchar{30}{193}}
+\definecharacter ecircumflexacute {\uchar{30}{191}}
+\definecharacter ecircumflextilde {\uchar{30}{197}}
+\definecharacter ecircumflexhook {\uchar{30}{195}}
+\definecharacter ecircumflexdotbelow {\uchar{30}{199}}
+\definecharacter ihook {\uchar{30}{201}}
+\definecharacter Idotbelow {\uchar{30}{202}}
+\definecharacter Ohook {\uchar{30}{206}}
+\definecharacter Odotbelow {\uchar{30}{204}}
+\definecharacter Ocircumflexgrave {\uchar{30}{210}}
+\definecharacter Ocircumflexacute {\uchar{30}{208}}
+\definecharacter Ocircumflextilde {\uchar{30}{214}}
+\definecharacter Ocircumflexhook {\uchar{30}{212}}
+\definecharacter Ocircumflexdotbelow {\uchar{30}{216}}
+\definecharacter Ohorngrave {\uchar{30}{220}}
+\definecharacter Ohornacute {\uchar{30}{218}}
+\definecharacter Ohorntilde {\uchar{30}{224}}
+\definecharacter Ohornhook {\uchar{30}{222}}
+\definecharacter Ohorndotbelow {\uchar{30}{226}}
+\definecharacter Uhook {\uchar{30}{230}}
+\definecharacter Udotbelow {\uchar{30}{228}}
+\definecharacter Uhorngrave {\uchar{30}{234}}
+\definecharacter Uhornacute {\uchar{30}{232}}
+\definecharacter Uhorntilde {\uchar{30}{238}}
+\definecharacter Uhornhook {\uchar{30}{236}}
+\definecharacter Uhorndotbelow {\uchar{30}{240}}
+\definecharacter Ytilde {\uchar{30}{248}}
+\definecharacter idotbelow {\uchar{30}{203}}
+\definecharacter ohook {\uchar{30}{207}}
+\definecharacter odotbelow {\uchar{30}{205}}
+\definecharacter ocircumflexgrave {\uchar{30}{211}}
+\definecharacter ocircumflexacute {\uchar{30}{209}}
+\definecharacter ocircumflextilde {\uchar{30}{215}}
+\definecharacter ocircumflexhook {\uchar{30}{213}}
+\definecharacter ocircumflexdotbelow {\uchar{30}{217}}
+\definecharacter ohorngrave {\uchar{30}{221}}
+\definecharacter ohornacute {\uchar{30}{219}}
+\definecharacter ohorntilde {\uchar{30}{225}}
+\definecharacter ohornhook {\uchar{30}{223}}
+\definecharacter ohorndotbelow {\uchar{30}{227}}
+\definecharacter uhook {\uchar{30}{231}}
+\definecharacter udotbelow {\uchar{30}{229}}
+\definecharacter uhorngrave {\uchar{30}{235}}
+\definecharacter uhornacute {\uchar{30}{233}}
+\definecharacter uhorntilde {\uchar{30}{239}}
+\definecharacter uhornhook {\uchar{30}{237}}
+\definecharacter uhorndotbelow {\uchar{30}{241}}
+\definecharacter ytilde {\uchar{30}{249}}
+
+\definecharacter Etilde {\uchar{30}{188}}
+\definecharacter etilde {\uchar{30}{189}}
+\definecharacter Ygrave {\uchar{30}{242}}
+\definecharacter ygrave {\uchar{30}{243}}
+
+\stopencoding
+
+% Greek:
+
+\startencoding[uc]
+
+\definecharacter greekAlphatonos {\uchar3{134}}
+\definecharacter greekEpsilontonos {\uchar3{136}}
+\definecharacter greekEtatonos {\uchar3{137}}
+\definecharacter greekIotatonos {\uchar3{138}}
+\definecharacter greekOmicrontonos {\uchar3{140}}
+\definecharacter greekUpsilontonos {\uchar3{142}}
+\definecharacter greekOmegatonos {\uchar3{143}}
+\definecharacter greekiotadialytikatonos {\uchar3{144}}
+\definecharacter greekAlpha {\uchar3{145}}
+\definecharacter greekBeta {\uchar3{146}}
+\definecharacter greekGamma {\uchar3{147}}
+\definecharacter greekDelta {\uchar3{148}}
+\definecharacter greekEpsilon {\uchar3{149}}
+\definecharacter greekZeta {\uchar3{150}}
+\definecharacter greekEta {\uchar3{151}}
+\definecharacter greekTheta {\uchar3{152}}
+\definecharacter greekIota {\uchar3{153}}
+\definecharacter greekKappa {\uchar3{154}}
+\definecharacter greekLambda {\uchar3{155}}
+\definecharacter greekMu {\uchar3{156}}
+\definecharacter greekNu {\uchar3{157}}
+\definecharacter greekXi {\uchar3{158}}
+\definecharacter greekOmicron {\uchar3{159}}
+\definecharacter greekPi {\uchar3{160}}
+\definecharacter greekRho {\uchar3{161}}
+\definecharacter greekSigma {\uchar3{163}}
+\definecharacter greekTau {\uchar3{164}}
+\definecharacter greekUpsilon {\uchar3{165}}
+\definecharacter greekPhi {\uchar3{166}}
+\definecharacter greekChi {\uchar3{167}}
+\definecharacter greekPsi {\uchar3{168}}
+\definecharacter greekOmega {\uchar3{169}}
+
+\definecharacter greekalpha {\uchar3{177}}
+\definecharacter greekbeta {\uchar3{178}}
+\definecharacter greekgamma {\uchar3{179}}
+\definecharacter greekdelta {\uchar3{180}}
+\definecharacter greekepsilon {\uchar3{181}}
+\definecharacter greekzeta {\uchar3{182}}
+\definecharacter greeketa {\uchar3{183}}
+\definecharacter greektheta {\uchar3{184}}
+\definecharacter greekiota {\uchar3{185}}
+\definecharacter greekkappa {\uchar3{186}}
+\definecharacter greeklambda {\uchar3{187}}
+\definecharacter greekmu {\uchar3{188}}
+\definecharacter greeknu {\uchar3{189}}
+\definecharacter greekxi {\uchar3{190}}
+\definecharacter greekomicron {\uchar3{191}}
+\definecharacter greekpi {\uchar3{192}}
+\definecharacter greekrho {\uchar3{193}}
+\definecharacter greekfinalsigma {\uchar3{194}}
+\definecharacter greeksigma {\uchar3{195}}
+\definecharacter greektau {\uchar3{196}}
+\definecharacter greekupsilon {\uchar3{197}}
+\definecharacter greekphi {\uchar3{198}}
+\definecharacter greekchi {\uchar3{199}}
+\definecharacter greekpsi {\uchar3{200}}
+\definecharacter greekomega {\uchar3{201}}
+\definecharacter greekiotadialytika {\uchar3{202}}
+\definecharacter greekupsilondialytika {\uchar3{203}}
+\definecharacter greekomicrontonos {\uchar3{204}}
+\definecharacter greekupsilontonos {\uchar3{205}}
+\definecharacter greekomegatonos {\uchar3{206}}
+
+\definecharacter greekIotadialytika {\uchar3{170}}
+\definecharacter greekUpsilondialytika {\uchar3{171}}
+
+\definecharacter greekalphatonos {\uchar3{172}}
+\definecharacter greekepsilontonos {\uchar3{173}}
+\definecharacter greeketatonos {\uchar3{174}}
+\definecharacter greekiotatonos {\uchar3{175}}
+\definecharacter greekupsilondialytikatonos {\uchar3{176}}
+
+% new:
+\definecharacter greekthetaalt {\uchar3{209}}
+\definecharacter greekphialt {\uchar3{213}}
+\definecharacter greekpialt {\uchar3{214}}
+\definecharacter greekrhoalt {\uchar3{241}}
+\definecharacter greekepsilonalt {\uchar3{245}}
+
+\stopencoding
+
+% Cyrillic:
+
+\startencoding[uc]
+
+\definecharacter cyrillicA {\uchar4{16}}
+\definecharacter cyrillicB {\uchar4{17}}
+\definecharacter cyrillicV {\uchar4{18}}
+\definecharacter cyrillicG {\uchar4{19}}
+\definecharacter cyrillicD {\uchar4{20}}
+\definecharacter cyrillicE {\uchar4{21}}
+\definecharacter cyrillicZH {\uchar4{22}}
+\definecharacter cyrillicZ {\uchar4{23}}
+\definecharacter cyrillicI {\uchar4{24}}
+\definecharacter cyrillicISHRT {\uchar4{25}}
+\definecharacter cyrillicK {\uchar4{26}}
+\definecharacter cyrillicL {\uchar4{27}}
+\definecharacter cyrillicM {\uchar4{28}}
+\definecharacter cyrillicN {\uchar4{29}}
+\definecharacter cyrillicO {\uchar4{30}}
+\definecharacter cyrillicP {\uchar4{31}}
+\definecharacter cyrillicR {\uchar4{32}}
+\definecharacter cyrillicS {\uchar4{33}}
+\definecharacter cyrillicT {\uchar4{34}}
+\definecharacter cyrillicU {\uchar4{35}}
+\definecharacter cyrillicF {\uchar4{36}}
+\definecharacter cyrillicH {\uchar4{37}}
+\definecharacter cyrillicC {\uchar4{38}}
+\definecharacter cyrillicCH {\uchar4{39}}
+\definecharacter cyrillicSH {\uchar4{40}}
+\definecharacter cyrillicSHCH {\uchar4{41}}
+\definecharacter cyrillicHRDSN {\uchar4{42}}
+\definecharacter cyrillicERY {\uchar4{43}}
+\definecharacter cyrillicSFTSN {\uchar4{44}}
+\definecharacter cyrillicEREV {\uchar4{45}}
+\definecharacter cyrillicYU {\uchar4{46}}
+\definecharacter cyrillicYA {\uchar4{47}}
+
+\definecharacter cyrillica {\uchar4{48}}
+\definecharacter cyrillicb {\uchar4{49}}
+\definecharacter cyrillicv {\uchar4{50}}
+\definecharacter cyrillicg {\uchar4{51}}
+\definecharacter cyrillicd {\uchar4{52}}
+\definecharacter cyrillice {\uchar4{53}}
+\definecharacter cyrilliczh {\uchar4{54}}
+\definecharacter cyrillicz {\uchar4{55}}
+\definecharacter cyrillici {\uchar4{56}}
+\definecharacter cyrillicishrt {\uchar4{57}}
+\definecharacter cyrillick {\uchar4{58}}
+\definecharacter cyrillicl {\uchar4{59}}
+\definecharacter cyrillicm {\uchar4{60}}
+\definecharacter cyrillicn {\uchar4{61}}
+\definecharacter cyrillico {\uchar4{62}}
+\definecharacter cyrillicp {\uchar4{63}}
+\definecharacter cyrillicr {\uchar4{64}}
+\definecharacter cyrillics {\uchar4{65}}
+\definecharacter cyrillict {\uchar4{66}}
+\definecharacter cyrillicu {\uchar4{67}}
+\definecharacter cyrillicf {\uchar4{68}}
+\definecharacter cyrillich {\uchar4{69}}
+\definecharacter cyrillicc {\uchar4{70}}
+\definecharacter cyrillicch {\uchar4{71}}
+\definecharacter cyrillicsh {\uchar4{72}}
+\definecharacter cyrillicshch {\uchar4{73}}
+\definecharacter cyrillichrdsn {\uchar4{74}}
+\definecharacter cyrillicery {\uchar4{75}}
+\definecharacter cyrillicsftsn {\uchar4{76}}
+\definecharacter cyrillicerev {\uchar4{77}}
+\definecharacter cyrillicyu {\uchar4{78}}
+\definecharacter cyrillicya {\uchar4{79}}
+
+%D I tried to figure out what these were, but the unicode
+%D tables suggested they were the same as cyrillici, which was
+%D already defined! So, a temporary definition:
+
+% \def\cyrillicII{\cyrillicI}
+% \def\cyrillicii{\cyrillici}
+
+%D a guess derived from looking at enco-cyr suggests that this is
+%D identical to the Roman I/i pair. To me, that sounds like
+%D CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I in the UC tables!
+
+\definecharacter cyrillicII {\uchar4{6}}
+\definecharacter cyrillicii {\uchar4{86}}
+
+%D Guessing that tlir6a corresponds with t2a encoding as advertised,
+%D here are some more, cos I had some spare time: (AL)
+
+\definecharacter cyrillicDJE {\uchar4{2}}
+\definecharacter cyrillicTSHE {\uchar4{11}}
+%definecharacter cyrillicSHHA 132
+%definecharacter cyrillicZHDSC 133
+\definecharacter cyrillicZDSC {\uchar4{152}}
+\definecharacter cyrillicLJE {\uchar4{9}}
+\definecharacter cyrillicYI {\uchar4{7}}
+\definecharacter cyrillicAE {\uchar4{212}}
+%definecharacter cyrillicNDSC 141
+%definecharacter cyrillicNG 142
+\definecharacter cyrillicDZE {\uchar4{5}}
+%definecharacter cyrillicOTLD 144
+\definecharacter cyrillicSDSC {\uchar4{170}}
+\definecharacter cyrillicUSHRT {\uchar4{14}}
+%definecharacter cyrillicY 147
+%definecharacter cyrillicYHCRS 148
+%definecharacter cyrillicHDSC 149
+\definecharacter cyrillicDZHE {\uchar4{15}}
+\definecharacter cyrillicIE {\uchar4{4}}
+\definecharacter cyrillicNJE {\uchar4{10}}
+\definecharacter cyrillicYO {\uchar4{1}}
+
+\definecharacter cyrillicdje {\uchar4{82}}
+\definecharacter cyrillictshe {\uchar4{91}}
+%definecharacter cyrillicshha 164
+%definecharacter cyrilliczhdsc 165
+\definecharacter cyrilliczdsc {\uchar4{153}}
+\definecharacter cyrilliclje {\uchar4{89}}
+\definecharacter cyrillicyi {\uchar4{87}}
+\definecharacter cyrillicae {\uchar4{213}}
+%definecharacter cyrillicndsc 173
+%definecharacter cyrillicng 174
+\definecharacter cyrillicdze {\uchar4{85}}
+%definecharacter cyrillicotld 176
+\definecharacter cyrillicsdsc {\uchar4{171}}
+\definecharacter cyrillicushrt {\uchar4{94}}
+%definecharacter cyrillicy 179
+%definecharacter cyrillicyhcrs 180
+%definecharacter cyrillichdsc 181
+\definecharacter cyrillicdzhe {\uchar4{95}}
+\definecharacter cyrillicie {\uchar4{84}}
+\definecharacter cyrillicnje {\uchar4{90}}
+\definecharacter cyrillicyo {\uchar4{81}}
+
+% is there overlap with the above definitions
+
+\definecharacter cyrillicEgrave {\uchar4{0}}
+\definecharacter cyrillicGJE {\uchar4{3}}
+\definecharacter cyrillicJE {\uchar4{8}}
+\definecharacter cyrillicKJE {\uchar4{12}}
+\definecharacter cyrillicIgrave {\uchar4{13}}
+\definecharacter cyrillicegrave {\uchar4{80}}
+\definecharacter cyrillicgje {\uchar4{83}}
+\definecharacter cyrillicje {\uchar4{88}}
+\definecharacter cyrillickje {\uchar4{92}}
+\definecharacter cyrillicigrave {\uchar4{93}}
+\definecharacter cyrillicOMEGA {\uchar4{96}}
+\definecharacter cyrillicomega {\uchar4{97}}
+\definecharacter cyrillicYAT {\uchar4{98}}
+\definecharacter cyrillicyat {\uchar4{99}}
+\definecharacter cyrillicEiotified {\uchar4{100}}
+\definecharacter cyrilliceiotified {\uchar4{101}}
+\definecharacter cyrillicLITTLEYUS {\uchar4{102}}
+\definecharacter cyrilliclittleyus {\uchar4{103}}
+\definecharacter cyrillicLITTLEYUSiotified {\uchar4{104}}
+\definecharacter cyrilliclittleyusiotified {\uchar4{105}}
+\definecharacter cyrillicBIGYUS {\uchar4{106}}
+\definecharacter cyrillicbigyus {\uchar4{107}}
+\definecharacter cyrillicBIGYUSiotified {\uchar4{108}}
+\definecharacter cyrillicbigyusiotified {\uchar4{109}}
+\definecharacter cyrillicKSI {\uchar4{110}}
+\definecharacter cyrillicksi {\uchar4{111}}
+\definecharacter cyrillicPSI {\uchar4{112}}
+\definecharacter cyrillicpsi {\uchar4{113}}
+\definecharacter cyrillicFITA {\uchar4{114}}
+\definecharacter cyrillicfita {\uchar4{115}}
+\definecharacter cyrillicIZHITSA {\uchar4{116}}
+\definecharacter cyrillicizhitsa {\uchar4{117}}
+\definecharacter cyrillicIZHITSAdoublegrave {\uchar4{118}}
+\definecharacter cyrillicizhitsadoublegrave {\uchar4{119}}
+\definecharacter cyrillicUK {\uchar4{120}}
+\definecharacter cyrillicuk {\uchar4{121}}
+\definecharacter cyrillicOMEGAround {\uchar4{122}}
+\definecharacter cyrillicomegaround {\uchar4{123}}
+\definecharacter cyrillicOMEGAtitlo {\uchar4{124}}
+\definecharacter cyrillicomegatitlo {\uchar4{125}}
+\definecharacter cyrillicOT {\uchar4{126}}
+\definecharacter cyrillicot {\uchar4{127}}
+\definecharacter cyrillicKOPPA {\uchar4{128}}
+\definecharacter cyrillickoppa {\uchar4{129}}
+\definecharacter cyrillicTITLO {\uchar4{131}}
+\definecharacter cyrillicPALATALIZATION {\uchar4{132}}
+\definecharacter cyrillicDASIAPNEUMATA {\uchar4{133}}
+\definecharacter cyrillicPSILIPNEUMATA {\uchar4{134}}
+\definecharacter cyrillicISHRTtail {\uchar4{138}}
+\definecharacter cyrillicishrttail {\uchar4{139}}
+\definecharacter cyrillicSEMISOFT {\uchar4{140}}
+\definecharacter cyrillicsemisoft {\uchar4{141}}
+\definecharacter cyrillicERtick {\uchar4{142}}
+\definecharacter cyrillicertick {\uchar4{143}}
+\definecharacter cyrillicGHEupturn {\uchar4{144}}
+\definecharacter cyrillicgheupturn {\uchar4{145}}
+\definecharacter cyrillicGHEstroke {\uchar4{146}}
+\definecharacter cyrillicghestroke {\uchar4{147}}
+\definecharacter cyrillicGHEmidhook {\uchar4{148}}
+\definecharacter cyrillicghemidhook {\uchar4{149}}
+\definecharacter cyrillicZHEdescender {\uchar4{150}}
+\definecharacter cyrilliczhedescender {\uchar4{151}}
+\definecharacter cyrillicZDSC {\uchar4{152}}
+\definecharacter cyrilliczdsc {\uchar4{153}}
+\definecharacter cyrillicKADC {\uchar4{154}}
+\definecharacter cyrillickadc {\uchar4{155}}
+\definecharacter cyrillicKAvertstroke {\uchar4{156}}
+\definecharacter cyrillickavertstroke {\uchar4{157}}
+\definecharacter cyrillicKAstroke {\uchar4{158}}
+\definecharacter cyrillickastroke {\uchar4{159}}
+\definecharacter cyrillicKAbashkir {\uchar4{160}}
+\definecharacter cyrillickabashkir {\uchar4{161}}
+\definecharacter cyrillicENDC {\uchar4{162}}
+\definecharacter cyrillicendc {\uchar4{163}}
+\definecharacter cyrillicENGHE {\uchar4{164}}
+\definecharacter cyrillicenghe {\uchar4{165}}
+\definecharacter cyrillicPEmidhook {\uchar4{166}}
+\definecharacter cyrillicpemidhook {\uchar4{167}}
+\definecharacter cyrillicHA {\uchar4{168}}
+\definecharacter cyrillicha {\uchar4{169}}
+%definecharacter cyrillicSDSC {\uchar4{170}} % already defined
+%definecharacter cyrilliccdsc {\uchar4{171}} % already defined
+\definecharacter cyrillicTEDC {\uchar4{172}}
+\definecharacter cyrillictedc {\uchar4{173}}
+\definecharacter cyrillicYstr {\uchar4{174}}
+\definecharacter cyrillicystr {\uchar4{175}}
+\definecharacter cyrillicYstrstroke {\uchar4{176}}
+\definecharacter cyrillicystrstroke {\uchar4{177}}
+\definecharacter cyrillicHADC {\uchar4{178}}
+\definecharacter cyrillichadc {\uchar4{179}}
+\definecharacter cyrillicTETSE {\uchar4{180}}
+\definecharacter cyrillictetse {\uchar4{181}}
+\definecharacter cyrillicCHEDC {\uchar4{182}}
+\definecharacter cyrillicchedc {\uchar4{183}}
+\definecharacter cyrillicCHEvertstroke {\uchar4{184}}
+\definecharacter cyrillicchevertstroke {\uchar4{185}}
+\definecharacter cyrillicSHHA {\uchar4{186}}
+\definecharacter cyrillicshha {\uchar4{187}}
+\definecharacter cyrillicCHEabkhasian {\uchar4{188}}
+\definecharacter cyrilliccheabkhasian {\uchar4{189}}
+\definecharacter cyrillicCHEDCabkhasian {\uchar4{190}}
+\definecharacter cyrillicchedcabkhasian {\uchar4{191}}
+\definecharacter cyrillicPALOCHKA {\uchar4{192}}
+\definecharacter cyrillicZHEbreve {\uchar4{193}}
+\definecharacter cyrilliczhebreve {\uchar4{194}}
+\definecharacter cyrillicKAhook {\uchar4{195}}
+\definecharacter cyrillickahook {\uchar4{196}}
+\definecharacter cyrillicELtail {\uchar4{197}}
+\definecharacter cyrilliceltail {\uchar4{198}}
+\definecharacter cyrillicENhook {\uchar4{199}}
+\definecharacter cyrillicenhook {\uchar4{200}}
+\definecharacter cyrillicENtail {\uchar4{201}}
+\definecharacter cyrillicentail {\uchar4{202}}
+\definecharacter cyrillicCHEkhakassian {\uchar4{203}}
+\definecharacter cyrillicchekhakassian {\uchar4{204}}
+\definecharacter cyrillicEMtail {\uchar4{205}}
+\definecharacter cyrillicemtail {\uchar4{206}}
+\definecharacter cyrillicAbreve {\uchar4{208}}
+\definecharacter cyrillicabreve {\uchar4{209}}
+\definecharacter cyrillicAdiaeresis {\uchar4{210}}
+\definecharacter cyrillicadiaeresis {\uchar4{211}}
+%definecharacter cyrillicAE {\uchar4{212}} % already defined
+%definecharacter cyrillicae {\uchar4{213}} % already defined
+\definecharacter cyrillicEbreve {\uchar4{214}}
+\definecharacter cyrillicebreve {\uchar4{215}}
+\definecharacter cyrillicSCHWA {\uchar4{216}}
+\definecharacter cyrillicschwa {\uchar4{217}}
+\definecharacter cyrillicSCHWAdiaeresis {\uchar4{218}}
+\definecharacter cyrillicschwadiaeresis {\uchar4{219}}
+\definecharacter cyrillicZHEdiaeresis {\uchar4{220}}
+\definecharacter cyrilliczhediaeresis {\uchar4{221}}
+\definecharacter cyrillicZEdiaeresis {\uchar4{222}}
+\definecharacter cyrilliczediaeresis {\uchar4{223}}
+\definecharacter cyrillicDZEabkhasian {\uchar4{224}}
+\definecharacter cyrillicdzeabkhasian {\uchar4{225}}
+\definecharacter cyrillicImacron {\uchar4{226}}
+\definecharacter cyrillicimacron {\uchar4{227}}
+\definecharacter cyrillicIdiaeresis {\uchar4{228}}
+\definecharacter cyrillicidiaeresis {\uchar4{229}}
+\definecharacter cyrillicOdiaeresis {\uchar4{230}}
+\definecharacter cyrillicodiaeresis {\uchar4{231}}
+\definecharacter cyrillicObarred {\uchar4{232}}
+\definecharacter cyrillicobarred {\uchar4{233}}
+\definecharacter cyrillicObarreddiaeresis {\uchar4{234}}
+\definecharacter cyrillicobarreddiaeresis {\uchar4{235}}
+\definecharacter cyrillicEdiaeresis {\uchar4{236}}
+\definecharacter cyrillicediaeresis {\uchar4{237}}
+\definecharacter cyrillicUmacron {\uchar4{238}}
+\definecharacter cyrillicumacron {\uchar4{239}}
+\definecharacter cyrillicUdiaeresis {\uchar4{240}}
+\definecharacter cyrillicudiaeresis {\uchar4{241}}
+\definecharacter cyrillicUdoubleacute {\uchar4{242}}
+\definecharacter cyrillicudoubleacute {\uchar4{243}}
+\definecharacter cyrillicCHEdiaeresis {\uchar4{244}}
+\definecharacter cyrillicchediaeresis {\uchar4{245}}
+\definecharacter cyrillicYERUdiaeresis {\uchar4{248}}
+\definecharacter cyrillicyerudiaeresis {\uchar4{249}}
+
+\stopencoding
+
+% Greek Extended
+
+\startencoding[uc]
+
+\definecharacter greekalphapsili {\uchar{31}{0}}
+\definecharacter greekalphadasia {\uchar{31}{1}}
+\definecharacter greekalphapsilivaria {\uchar{31}{2}}
+\definecharacter greekalphadasiavaria {\uchar{31}{3}}
+\definecharacter greekalphapsilitonos {\uchar{31}{4}}
+\definecharacter greekalphadasiatonos {\uchar{31}{5}}
+\definecharacter greekalphapsiliperispomeni {\uchar{31}{6}}
+\definecharacter greekalphadasiaperispomeni {\uchar{31}{7}}
+\definecharacter greekAlphapsili {\uchar{31}{8}}
+\definecharacter greekAlphadasia {\uchar{31}{9}}
+\definecharacter greekAlphapsilivaria {\uchar{31}{10}}
+\definecharacter greekAlphadasiavaria {\uchar{31}{11}}
+\definecharacter greekAlphapsilitonos {\uchar{31}{12}}
+\definecharacter greekAlphadasiatonos {\uchar{31}{13}}
+\definecharacter greekAlphapsiliperispomeni {\uchar{31}{14}}
+\definecharacter greekAlphadasiaperispomeni {\uchar{31}{15}}
+\definecharacter greekepsilonpsili {\uchar{31}{16}} % 1f10
+\definecharacter greekepsilondasia {\uchar{31}{17}}
+\definecharacter greekepsilonpsilivaria {\uchar{31}{18}}
+\definecharacter greekepsilondasiavaria {\uchar{31}{19}}
+\definecharacter greekepsilonpsilitonos {\uchar{31}{20}}
+\definecharacter greekepsilondasiatonos {\uchar{31}{21}}
+\definecharacter greekEpsilonpsili {\uchar{31}{24}}
+\definecharacter greekEpsilondasia {\uchar{31}{25}}
+\definecharacter greekEpsilonpsilivaria {\uchar{31}{26}}
+\definecharacter greekEpsilondasiavaria {\uchar{31}{27}}
+\definecharacter greekEpsilonpsilitonos {\uchar{31}{28}}
+\definecharacter greekEpsilondasiatonos {\uchar{31}{29}}
+\definecharacter greeketapsili {\uchar{31}{32}} % 1f20
+\definecharacter greeketadasia {\uchar{31}{33}}
+\definecharacter greeketapsilivaria {\uchar{31}{34}}
+\definecharacter greeketadasiavaria {\uchar{31}{35}}
+\definecharacter greeketapsilitonos {\uchar{31}{36}}
+\definecharacter greeketadasiatonos {\uchar{31}{37}}
+\definecharacter greeketapsiliperispomeni {\uchar{31}{38}}
+\definecharacter greeketadasiaperispomeni {\uchar{31}{39}}
+\definecharacter greekEtapsili {\uchar{31}{40}}
+\definecharacter greekEtadasia {\uchar{31}{41}}
+\definecharacter greekEtapsilivaria {\uchar{31}{42}}
+\definecharacter greekEtadasiavaria {\uchar{31}{43}}
+\definecharacter greekEtapsilitonos {\uchar{31}{44}}
+\definecharacter greekEtadasiatonos {\uchar{31}{45}}
+\definecharacter greekEtapsiliperispomeni {\uchar{31}{46}}
+\definecharacter greekEtadasiaperispomeni {\uchar{31}{47}}
+\definecharacter greekiotapsili {\uchar{31}{48}} % 1f30
+\definecharacter greekiotadasia {\uchar{31}{49}}
+\definecharacter greekiotapsilivaria {\uchar{31}{50}}
+\definecharacter greekiotadasiavaria {\uchar{31}{51}}
+\definecharacter greekiotapsilitonos {\uchar{31}{52}}
+\definecharacter greekiotadasiatonos {\uchar{31}{53}}
+\definecharacter greekiotapsiliperispomeni {\uchar{31}{54}}
+\definecharacter greekiotadasiaperispomeni {\uchar{31}{55}}
+\definecharacter greekIotapsili {\uchar{31}{56}}
+\definecharacter greekIotadasia {\uchar{31}{57}}
+\definecharacter greekIotapsilivaria {\uchar{31}{58}}
+\definecharacter greekIotadasiavaria {\uchar{31}{59}}
+\definecharacter greekIotapsilitonos {\uchar{31}{60}}
+\definecharacter greekIotadasiatonos {\uchar{31}{61}}
+\definecharacter greekIotapsiliperispomeni {\uchar{31}{62}}
+\definecharacter greekIotadasiaperispomeni {\uchar{31}{63}}
+\definecharacter greekomicronpsili {\uchar{31}{64}} % 1f40
+\definecharacter greekomicrondasia {\uchar{31}{65}}
+\definecharacter greekomicronpsilivaria {\uchar{31}{66}}
+\definecharacter greekomicrondasiavaria {\uchar{31}{67}}
+\definecharacter greekomicronpsilitonos {\uchar{31}{68}}
+\definecharacter greekomicrondasiatonos {\uchar{31}{69}}
+\definecharacter greekOmicronpsili {\uchar{31}{72}}
+\definecharacter greekOmicrondasia {\uchar{31}{73}}
+\definecharacter greekOmicronpsilivaria {\uchar{31}{74}}
+\definecharacter greekOmicrondasiavaria {\uchar{31}{75}}
+\definecharacter greekOmicronpsilitonos {\uchar{31}{76}}
+\definecharacter greekOmicrondasiatonos {\uchar{31}{77}}
+\definecharacter greekupsilonpsili {\uchar{31}{80}} % 1f50
+\definecharacter greekupsilondasia {\uchar{31}{81}}
+\definecharacter greekupsilonpsilivaria {\uchar{31}{82}}
+\definecharacter greekupsilondasiavaria {\uchar{31}{83}}
+\definecharacter greekupsilonpsilitonos {\uchar{31}{84}}
+\definecharacter greekupsilondasiatonos {\uchar{31}{85}}
+\definecharacter greekupsilonpsiliperispomeni {\uchar{31}{86}}
+\definecharacter greekupsilondasiaperispomeni {\uchar{31}{87}}
+\definecharacter greekUpsilondasia {\uchar{31}{89}}
+\definecharacter greekUpsilondasiavaria {\uchar{31}{91}}
+\definecharacter greekUpsilondasiatonos {\uchar{31}{93}}
+\definecharacter greekUpsilondasiaperispomeni {\uchar{31}{95}}
+\definecharacter greekomegapsili {\uchar{31}{96}} % 1f60
+\definecharacter greekomegadasia {\uchar{31}{97}}
+\definecharacter greekomegapsilivaria {\uchar{31}{98}}
+\definecharacter greekomegadasiavaria {\uchar{31}{99}}
+\definecharacter greekomegapsilitonos {\uchar{31}{100}}
+\definecharacter greekomegadasiatonos {\uchar{31}{101}}
+\definecharacter greekomegapsiliperispomeni {\uchar{31}{102}}
+\definecharacter greekomegadasiaperispomeni {\uchar{31}{103}}
+\definecharacter greekOmegapsili {\uchar{31}{104}}
+\definecharacter greekOmegadasia {\uchar{31}{105}}
+\definecharacter greekOmegapsilivaria {\uchar{31}{106}}
+\definecharacter greekOmegadasiavaria {\uchar{31}{107}}
+\definecharacter greekOmegapsilitonos {\uchar{31}{108}}
+\definecharacter greekOmegadasiatonos {\uchar{31}{109}}
+\definecharacter greekOmegapsiliperispomeni {\uchar{31}{110}}
+\definecharacter greekOmegadasiaperispomeni {\uchar{31}{111}}
+\definecharacter greekalphavaria {\uchar{31}{112}} % 1f70
+\definecharacter greekalphaoxia {\uchar{31}{113}}
+\definecharacter greekepsilonvaria {\uchar{31}{114}}
+\definecharacter greekepsilonoxia {\uchar{31}{115}}
+\definecharacter greeketavaria {\uchar{31}{116}}
+\definecharacter greeketaoxia {\uchar{31}{117}}
+\definecharacter greekiotavaria {\uchar{31}{118}}
+\definecharacter greekiotaoxia {\uchar{31}{119}}
+\definecharacter greekomicronvaria {\uchar{31}{120}}
+\definecharacter greekomicronoxia {\uchar{31}{121}}
+\definecharacter greekupsilonvaria {\uchar{31}{122}}
+\definecharacter greekupsilonoxia {\uchar{31}{123}}
+\definecharacter greekomegavaria {\uchar{31}{124}}
+\definecharacter greekomegaoxia {\uchar{31}{125}}
+\definecharacter greekalphaiotasubpsili {\uchar{31}{128}} % 1f80
+\definecharacter greekalphaiotasubdasia {\uchar{31}{129}}
+\definecharacter greekalphaiotasubpsilivaria {\uchar{31}{130}}
+\definecharacter greekalphaiotasubdasiavaria {\uchar{31}{131}}
+\definecharacter greekalphaiotasubpsilitonos {\uchar{31}{132}}
+\definecharacter greekalphaiotasubdasiatonos {\uchar{31}{133}}
+\definecharacter greekalphaiotasubpsiliperispomeni {\uchar{31}{134}}
+\definecharacter greekalphaiotasubdasiaperispomeni {\uchar{31}{135}}
+\definecharacter greekAlphaiotasubpsili {\uchar{31}{136}}
+\definecharacter greekAlphaiotasubdasia {\uchar{31}{137}}
+\definecharacter greekAlphaiotasubpsilivaria {\uchar{31}{138}}
+\definecharacter greekAlphaiotasubdasiavaria {\uchar{31}{139}}
+\definecharacter greekAlphaiotasubpsilitonos {\uchar{31}{140}}
+\definecharacter greekAlphaiotasubdasiatonos {\uchar{31}{141}}
+\definecharacter greekAlphaiotasubpsiliperispomeni {\uchar{31}{142}}
+\definecharacter greekAlphaiotasubdasiaperispomeni {\uchar{31}{143}}
+\definecharacter greeketaiotasubpsili {\uchar{31}{144}} % 1f90
+\definecharacter greeketaiotasubdasia {\uchar{31}{145}}
+\definecharacter greeketaiotasubpsilivaria {\uchar{31}{146}}
+\definecharacter greeketaiotasubdasiavaria {\uchar{31}{147}}
+\definecharacter greeketaiotasubpsilitonos {\uchar{31}{148}}
+\definecharacter greeketaiotasubdasiatonos {\uchar{31}{149}}
+\definecharacter greeketaiotasubpsiliperispomeni {\uchar{31}{150}}
+\definecharacter greeketaiotasubdasiaperispomeni {\uchar{31}{151}}
+\definecharacter greekEtaiotasubpsili {\uchar{31}{152}}
+\definecharacter greekEtaiotasubdasia {\uchar{31}{153}}
+\definecharacter greekEtaiotasubpsilivaria {\uchar{31}{154}}
+\definecharacter greekEtaiotasubdasiavaria {\uchar{31}{155}}
+\definecharacter greekEtaiotasubpsilitonos {\uchar{31}{156}}
+\definecharacter greekEtaiotasubdasiatonos {\uchar{31}{157}}
+\definecharacter greekEtaiotasubpsiliperispomeni {\uchar{31}{158}}
+\definecharacter greekEtaiotasubdasiaperispomeni {\uchar{31}{159}}
+\definecharacter greekomegaiotasubpsili {\uchar{31}{160}} % 1fa0
+\definecharacter greekomegaiotasubdasia {\uchar{31}{161}}
+\definecharacter greekomegaiotasubpsilivaria {\uchar{31}{162}}
+\definecharacter greekomegaiotasubdasiavaria {\uchar{31}{163}}
+\definecharacter greekomegaiotasubpsilitonos {\uchar{31}{164}}
+\definecharacter greekomegaiotasubdasiatonos {\uchar{31}{165}}
+\definecharacter greekomegaiotasubpsiliperispomeni {\uchar{31}{166}}
+\definecharacter greekomegaiotasubdasiaperispomeni {\uchar{31}{167}}
+\definecharacter greekOmegaiotasubpsili {\uchar{31}{168}}
+\definecharacter greekOmegaiotasubdasia {\uchar{31}{169}}
+\definecharacter greekOmegaiotasubpsilivaria {\uchar{31}{170}}
+\definecharacter greekOmegaiotasubdasiavaria {\uchar{31}{171}}
+\definecharacter greekOmegaiotasubpsilitonos {\uchar{31}{172}}
+\definecharacter greekOmegaiotasubdasiatonos {\uchar{31}{173}}
+\definecharacter greekOmegaiotasubpsiliperispomeni {\uchar{31}{174}}
+\definecharacter greekOmegaiotasubdasiaperispomeni {\uchar{31}{175}}
+\definecharacter greekalphavrachy {\uchar{31}{176}} % 1fb0
+\definecharacter greekalphamacron {\uchar{31}{177}}
+\definecharacter greekalphaiotasubvaria {\uchar{31}{178}}
+\definecharacter greekalphaiotasub {\uchar{31}{179}}
+\definecharacter greekalphaiotasubtonos {\uchar{31}{180}}
+\definecharacter greekalphaperispomeni {\uchar{31}{182}}
+\definecharacter greekalphaiotasubperispomeni {\uchar{31}{183}}
+\definecharacter greekAlphavrachy {\uchar{31}{184}}
+\definecharacter greekAlphamacron {\uchar{31}{185}}
+\definecharacter greekAlphavaria {\uchar{31}{186}}
+\definecharacter greekAlphatonos {\uchar{31}{187}}
+\definecharacter greekAlphaiotasub {\uchar{31}{188}}
+\definecharacter greekCoronis {\uchar{31}{189}}
+\definecharacter greekprosgegrammeni {\uchar{31}{190}}
+\definecharacter greekpsili {\uchar{31}{191}}
+\definecharacter greekperispomeni {\uchar{31}{192}} % 1fc0
+\definecharacter greekdialytikaperispomeni {\uchar{31}{193}}
+\definecharacter greeketaiotasubvaria {\uchar{31}{194}}
+\definecharacter greeketaiotasub {\uchar{31}{195}}
+\definecharacter greeketaiotasubtonos {\uchar{31}{196}}
+\definecharacter greeketaperispomeni {\uchar{31}{198}}
+\definecharacter greeketaiotasubperispomeni {\uchar{31}{199}}
+\definecharacter greekEpsilonvaria {\uchar{31}{200}}
+\definecharacter greekEpsilontonos {\uchar{31}{201}}
+\definecharacter greekEtavaria {\uchar{31}{202}}
+\definecharacter greekEtatonos {\uchar{31}{203}}
+\definecharacter greekEtaiotasub {\uchar{31}{204}}
+\definecharacter greekpsilivaria {\uchar{31}{205}}
+\definecharacter greekpsilitonos {\uchar{31}{206}}
+\definecharacter greekpsiliperispomeni {\uchar{31}{207}}
+\definecharacter greekiotavrachy {\uchar{31}{208}} % 1fd0
+\definecharacter greekiotamacron {\uchar{31}{209}}
+\definecharacter greekiotadialytikavaria {\uchar{31}{210}}
+\definecharacter greekiotadialytikatonos {\uchar{31}{211}}
+\definecharacter greekiotaperispomeni {\uchar{31}{214}}
+\definecharacter greekiotadialytikaperispomeni {\uchar{31}{215}}
+\definecharacter greekIotavrachy {\uchar{31}{216}}
+\definecharacter greekIotamacron {\uchar{31}{217}}
+\definecharacter greekIotavaria {\uchar{31}{218}}
+\definecharacter greekIotatonos {\uchar{31}{219}}
+\definecharacter greekdasiavaria {\uchar{31}{221}}
+\definecharacter greekdasiatonos {\uchar{31}{222}}
+\definecharacter greekdasiaperispomeni {\uchar{31}{223}}
+\definecharacter greekupsilonvrachy {\uchar{31}{224}} % 1fe0
+\definecharacter greekupsilonmacron {\uchar{31}{225}}
+\definecharacter greekupsilondialytikavaria {\uchar{31}{226}}
+\definecharacter greekupsilondialytikatonos {\uchar{31}{227}}
+\definecharacter greekrhopsili {\uchar{31}{228}}
+\definecharacter greekrhodasia {\uchar{31}{229}}
+\definecharacter greekupsilonperispomeni {\uchar{31}{230}}
+\definecharacter greekupsilondialytikaperispomeni {\uchar{31}{231}}
+\definecharacter greekUpsilonvrachy {\uchar{31}{232}}
+\definecharacter greekUpsilonmacron {\uchar{31}{233}}
+\definecharacter greekUpsilonvaria {\uchar{31}{234}}
+\definecharacter greekUpsilontonos {\uchar{31}{235}}
+\definecharacter greekRhodasia {\uchar{31}{236}}
+\definecharacter greekdialytikavaria {\uchar{31}{237}}
+\definecharacter greekdialytikatonos {\uchar{31}{238}}
+\definecharacter greekvaria {\uchar{31}{239}}
+\definecharacter greekomegaiotasubvaria {\uchar{31}{242}}
+\definecharacter greekomegaiotasub {\uchar{31}{243}}
+\definecharacter greekomegaiotasubtonos {\uchar{31}{244}}
+\definecharacter greekomegaperispomeni {\uchar{31}{246}}
+\definecharacter greekomegaiotasubperispomeni {\uchar{31}{247}}
+\definecharacter greekOmicronvaria {\uchar{31}{248}}
+\definecharacter greekOmicrontonos {\uchar{31}{249}}
+\definecharacter greekOmegavaria {\uchar{31}{250}}
+\definecharacter greekOmegatonos {\uchar{31}{251}}
+\definecharacter greekOmegaiotasub {\uchar{31}{252}}
+\definecharacter greekoxia {\uchar{31}{253}}
+\definecharacter greekdasia {\uchar{31}{254}}
+\definecharacter greeksigmalunate {\uchar3{242}}
+\definecharacter greekSigmalunate {\uchar3{249}}
+\definecharacter greeksampi {\uchar3{225}}
+\definecharacter greekdigamma {\uchar3{221}}
+\definecharacter greekstigma {\uchar3{219}}
+\definecharacter greeknumkoppa {\uchar3{223}}
+\definecharacter greekkoppa {\uchar3{217}}
+\definecharacter greekupsilondiaeresis {\uchar3{203}}
+
+\stopencoding
+
+% Hebrew:
+
+\startencoding[uc]
+
+\definecharacter hebrewAlef {\uchar5{208}} % 05D0
+\definecharacter hebrewBet {\uchar5{209}}
+\definecharacter hebrewGimel {\uchar5{210}}
+\definecharacter hebrewDalet {\uchar5{211}}
+\definecharacter hebrewHe {\uchar5{212}}
+\definecharacter hebrewVav {\uchar5{213}}
+\definecharacter hebrewZayin {\uchar5{214}}
+\definecharacter hebrewHet {\uchar5{215}}
+\definecharacter hebrewTet {\uchar5{216}}
+\definecharacter hebrewYod {\uchar5{217}}
+\definecharacter hebrewKaffinal {\uchar5{218}}
+\definecharacter hebrewKaf {\uchar5{219}}
+\definecharacter hebrewLamed {\uchar5{220}}
+\definecharacter hebrewMemfinal {\uchar5{221}}
+\definecharacter hebrewMem {\uchar5{222}}
+\definecharacter hebrewNunfinal {\uchar5{223}}
+\definecharacter hebrewNun {\uchar5{224}}
+\definecharacter hebrewSamekh {\uchar5{225}}
+\definecharacter hebrewAyin {\uchar5{226}}
+\definecharacter hebrewPefinal {\uchar5{227}}
+\definecharacter hebrewPe {\uchar5{228}}
+\definecharacter hebrewTsadifinal {\uchar5{229}}
+\definecharacter hebrewTsadi {\uchar5{230}}
+\definecharacter hebrewQof {\uchar5{231}}
+\definecharacter hebrewResh {\uchar5{232}}
+\definecharacter hebrewShin {\uchar5{233}}
+\definecharacter hebrewTav {\uchar5{234}} % 05EA
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-vis.mkii b/tex/context/base/enco-vis.mkii
new file mode 100644
index 000000000..3c1fd7765
--- /dev/null
+++ b/tex/context/base/enco-vis.mkii
@@ -0,0 +1,3 @@
+% temporary module, needed for downward compatibility
+
+\input regi-vis.tex \enableregime[viscii] \endinput
diff --git a/tex/context/base/enco-vna.mkii b/tex/context/base/enco-vna.mkii
new file mode 100644
index 000000000..05753f37b
--- /dev/null
+++ b/tex/context/base/enco-vna.mkii
@@ -0,0 +1,145 @@
+%D \module
+%D [ file=enco-vna,
+%D version=1999.12.12,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Vietnamese Accents,
+%D author=Han The Thanh & Adam Lindsay & Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module is originally derived from the some files Han The Thanh
+%D prepared for \LATEX. The dual accent support is still preliminary,
+%D but works ok. It's now adapted to named glyphs, and is activated by
+%D \type {\useencoding[thisfile]}.
+
+%D This was apparently buggy from the start: there is nothing to
+%D disambiguate \type {\ohorn} from \type {\ohook}. Both are entered
+%D with \type {\h{o}} (AL)!
+
+%D Once stable, this code will move to \type {enco-acc.tex}.
+
+\startencoding[default]
+
+\defineaccent h A {\Ahook}
+\defineaccent d A {\Adotbelow}
+\defineaccent ` ^A {\Acircumflexgrave}
+\defineaccent ' ^A {\Acircumflexacute}
+\defineaccent ~ ^A {\Acircumflextilde}
+\defineaccent h ^A {\Acircumflexhook}
+\defineaccent d ^A {\Acircumflexdotbelow}
+\defineaccent ` uA {\Abrevegrave}
+\defineaccent ' uA {\Abreveacute}
+\defineaccent ~ uA {\Abrevetilde}
+\defineaccent h uA {\Abrevehook}
+\defineaccent d uA {\Abrevedotbelow}
+\defineaccent h E {\Ehook}
+\defineaccent d E {\Edotbelow}
+\defineaccent ` ^E {\Ecircumflexgrave}
+\defineaccent ' ^E {\Ecircumflexacute}
+\defineaccent ~ ^E {\Ecircumflextilde}
+\defineaccent h ^E {\Ecircumflexhook}
+\defineaccent d ^E {\Ecircumflexdotbelow}
+\defineaccent h I {\Ihook}
+\defineaccent d I {\Idotbelow}
+\defineaccent h O {\Ohook}
+\defineaccent d O {\Odotbelow}
+\defineaccent ` ^O {\Ocircumflexgrave}
+\defineaccent ' ^O {\Ocircumflexacute}
+\defineaccent ~ ^O {\Ocircumflextilde}
+\defineaccent h ^O {\Ocircumflexhook}
+\defineaccent d ^O {\Ocircumflexdotbelow}
+%defineaccent h O {\Ohorn} % !!! conflict with \Ohook!
+\defineaccent ` hO {\Ohorngrave}
+\defineaccent ` {\Ohorn} {\Ohorngrave}
+\defineaccent ' hO {\Ohornacute}
+\defineaccent ' {\Ohorn} {\Ohornacute}
+\defineaccent ~ hO {\Ohorntilde}
+\defineaccent ~ {\Ohorn} {\Ohorntilde}
+\defineaccent h hO {\Ohornhook}
+\defineaccent h {\Ohorn} {\Ohornhook}
+\defineaccent d hO {\Ohorndotbelow}
+\defineaccent d {\Ohorn} {\Ohorndotbelow}
+\defineaccent h U {\Uhook}
+\defineaccent d U {\Udotbelow}
+%defineaccent h U {\Uhorn} % !!! conflict with \Uhook! honestly, people!
+\defineaccent ` hU {\Uhorngrave}
+\defineaccent ` {\Uhorn} {\Uhorngrave}
+\defineaccent ' hU {\Uhornacute}
+\defineaccent ' {\Uhorn} {\Uhornacute}
+\defineaccent ~ hU {\Uhorntilde}
+\defineaccent ~ {\Uhorn} {\Uhorntilde}
+\defineaccent h hU {\Uhornhook}
+\defineaccent h {\Uhorn} {\Uhornhook}
+\defineaccent d hU {\Uhorndotbelow}
+\defineaccent d {\Uhorn} {\Uhorndotbelow}
+\defineaccent ` Y {\Ygrave}
+\defineaccent ' Y {\Yacute}
+\defineaccent ~ Y {\Ytilde}
+\defineaccent h Y {\Yhook}
+\defineaccent d Y {\Ydotbelow}
+\defineaccent h a {\ahook}
+\defineaccent d a {\adotbelow}
+\defineaccent ` ^a {\acircumflexgrave}
+\defineaccent ' ^a {\acircumflexacute}
+\defineaccent ~ ^a {\acircumflextilde}
+\defineaccent h ^a {\acircumflexhook}
+\defineaccent d ^a {\acircumflexdotbelow}
+\defineaccent ` ua {\abrevegrave}
+\defineaccent ' ua {\abreveacute}
+\defineaccent ~ ua {\abrevetilde}
+\defineaccent h ua {\abrevehook}
+\defineaccent d ua {\abrevedotbelow}
+\defineaccent h e {\ehook}
+\defineaccent d e {\edotbelow}
+\defineaccent ` ^e {\ecircumflexgrave}
+\defineaccent ' ^e {\ecircumflexacute}
+\defineaccent ~ ^e {\ecircumflextilde}
+\defineaccent h ^e {\ecircumflexhook}
+\defineaccent d ^e {\ecircumflexdotbelow}
+\defineaccent h i {\ihook}
+\defineaccent d i {\idotbelow}
+\defineaccent h o {\ohook}
+\defineaccent d o {\odotbelow}
+\defineaccent ^ o {\ocircumflex}
+\defineaccent ` ^o {\ocircumflexgrave}
+\defineaccent ' ^o {\ocircumflexacute}
+\defineaccent ~ ^o {\ocircumflextilde}
+\defineaccent h ^o {\ocircumflexhook}
+\defineaccent d ^o {\ocircumflexdotbelow}
+%defineaccent h o {\ohorn} % !!!
+\defineaccent ` ho {\ohorngrave}
+\defineaccent ' ho {\ohornacute}
+\defineaccent ~ ho {\ohorntilde}
+\defineaccent h ho {\ohornhook}
+\defineaccent d ho {\ohorndotbelow}
+\defineaccent ` {\ohorn} {\ohorngrave}
+\defineaccent ' {\ohorn} {\ohornacute}
+\defineaccent ~ {\ohorn} {\ohorntilde}
+\defineaccent h {\ohorn} {\ohornhook}
+\defineaccent d {\ohorn} {\ohorndotbelow}
+\defineaccent h u {\uhook}
+\defineaccent d u {\udotbelow}
+%defineaccent h u {\uhorn} % !!!
+\defineaccent ` hu {\uhorngrave}
+\defineaccent ' hu {\uhornacute}
+\defineaccent ~ hu {\uhorntilde}
+\defineaccent h hu {\uhornhook}
+\defineaccent d hu {\uhorndotbelow}
+\defineaccent ` {\uhorn} {\uhorngrave}
+\defineaccent ' {\uhorn} {\uhornacute}
+\defineaccent ~ {\uhorn} {\uhorntilde}
+\defineaccent h {\uhorn} {\uhornhook}
+\defineaccent d {\uhorn} {\uhorndotbelow}
+\defineaccent ` y {\ygrave}
+\defineaccent ' y {\yacute}
+\defineaccent ~ y {\ytilde}
+\defineaccent h y {\yhook}
+\defineaccent d y {\ydotbelow}
+
+\stopencoding
+
+\endinput
diff --git a/tex/context/base/enco-win.mkii b/tex/context/base/enco-win.mkii
new file mode 100644
index 000000000..826371d8a
--- /dev/null
+++ b/tex/context/base/enco-win.mkii
@@ -0,0 +1,7 @@
+% temporary module, needed for downward compatibility
+
+%\input regi-win.tex
+
+\enableregime[windows]
+
+\endinput
diff --git a/tex/context/base/enco-x5.mkii b/tex/context/base/enco-x5.mkii
new file mode 100644
index 000000000..f82ec6c5c
--- /dev/null
+++ b/tex/context/base/enco-x5.mkii
@@ -0,0 +1,218 @@
+%D \module
+%D [ file=enco-x5,
+%D version=1999.12.12,
+%D title=\CONTEXT\ Encoding Macros,
+%D subtitle=Vietnamese Encoding,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module is derived from the some files Han The Thanh
+%D prepared for \LATEX. The dual accent support is still
+%D preliminary, but works ok.
+
+\startencoding[x5]
+
+\definecharacter textgrave 0
+\definecharacter textacute 1
+\definecharacter textcircumflex 2
+\definecharacter texttilde 3
+\definecharacter textdiaeresis 4
+\definecharacter texthungarumlaut 5
+\definecharacter textring 6
+\definecharacter textcaron 7
+\definecharacter textbreve 8
+\definecharacter textmacron 9
+\definecharacter textdotaccent 10
+\definecharacter textcedilla 11
+\definecharacter textogonek 12
+
+\definecharacter dotlessi 25
+\definecharacter DJ 30
+\definecharacter dj 31
+
+\defineaccent ` A 128
+\defineaccent ' A 129
+\defineaccent ~ A 130
+\defineaccent h A 131
+\defineaccent d A 132
+\defineaccent ^ A 133
+\defineaccent ` ^A 134
+\defineaccent ' ^A 135
+\defineaccent ~ ^A 136
+\defineaccent h ^A 137
+\defineaccent d ^A 138
+\defineaccent u A 139
+\defineaccent ` uA 140
+\defineaccent ' uA 141
+\defineaccent ~ uA 142
+\defineaccent h uA 143
+\defineaccent d uA 144
+\defineaccent ` E 145
+\defineaccent ' E 146
+\defineaccent ~ E 147
+\defineaccent h E 148
+\defineaccent d E 149
+\defineaccent ^ E 150
+\defineaccent ` ^E 151
+\defineaccent ' ^E 152
+\defineaccent ~ ^E 153
+\defineaccent h ^E 154
+\defineaccent d ^E 155
+\defineaccent ` I 156
+\defineaccent ' I 157
+\defineaccent ~ I 158
+\defineaccent h I 159
+\defineaccent d I 192
+\defineaccent ` O 193
+\defineaccent ' O 194
+\defineaccent ~ O 195
+\defineaccent h O 196
+\defineaccent d O 197
+\defineaccent ^ O 198
+\defineaccent ` ^O 199
+\defineaccent ' ^O 200
+\defineaccent ~ ^O 201
+\defineaccent h ^O 202
+\defineaccent d ^O 203
+\defineaccent h O 204
+\defineaccent ` hO 205
+\defineaccent ' hO 206
+\defineaccent ~ hO 207
+\defineaccent h hO 208
+\defineaccent d hO 209
+\defineaccent ` U 210
+\defineaccent ' U 211
+\defineaccent ~ U 212
+\defineaccent h U 213
+\defineaccent d U 214
+\defineaccent h U 215
+\defineaccent ` hU 216
+\defineaccent ' hU 217
+\defineaccent ~ hU 218
+\defineaccent h hU 219
+\defineaccent d hU 220
+\defineaccent ` Y 221
+\defineaccent ' Y 222
+\defineaccent ~ Y 223
+\defineaccent h Y 26
+\defineaccent d Y 28
+\defineaccent ` a 160
+\defineaccent ' a 161
+\defineaccent ~ a 162
+\defineaccent h a 163
+\defineaccent d a 164
+\defineaccent ^ a 165
+\defineaccent ` ^a 166
+\defineaccent ' ^a 167
+\defineaccent ~ ^a 168
+\defineaccent h ^a 169
+\defineaccent d ^a 170
+\defineaccent u a 171
+\defineaccent ` ua 172
+\defineaccent ' ua 173
+\defineaccent ~ ua 174
+\defineaccent h ua 175
+\defineaccent d ua 176
+\defineaccent ` e 177
+\defineaccent ' e 178
+\defineaccent ~ e 179
+\defineaccent h e 180
+\defineaccent d e 181
+\defineaccent ^ e 182
+\defineaccent ` ^e 183
+\defineaccent ' ^e 184
+\defineaccent ~ ^e 185
+\defineaccent h ^e 186
+\defineaccent d ^e 187
+\defineaccent ` i 188
+\defineaccent ' i 189
+\defineaccent ~ i 190
+\defineaccent h i 191
+\defineaccent d i 224
+\defineaccent ` o 225
+\defineaccent ' o 226
+\defineaccent ~ o 227
+\defineaccent h o 228
+\defineaccent d o 229
+\defineaccent ^ o 230
+\defineaccent ` ^o 231
+\defineaccent ' ^o 232
+\defineaccent ~ ^o 233
+\defineaccent h ^o 234
+\defineaccent d ^o 235
+\defineaccent h o 236
+\defineaccent ` ho 237
+\defineaccent ' ho 238
+\defineaccent ~ ho 239
+\defineaccent h ho 240
+\defineaccent d ho 241
+\defineaccent ` u 242
+\defineaccent ' u 243
+\defineaccent ~ u 244
+\defineaccent h u 245
+\defineaccent d u 246
+\defineaccent h u 247
+\defineaccent ` hu 248
+\defineaccent ' hu 249
+\defineaccent ~ hu 250
+\defineaccent h hu 251
+\defineaccent d hu 252
+\defineaccent ` y 253
+\defineaccent ' y 254
+\defineaccent ~ y 255
+\defineaccent h y 27
+\defineaccent d y 29
+
+\stopencoding
+
+\endinput
+
+% \startencoding [x5]
+%
+% \definecharacter aa {\xfiveencodedaa}
+% \definecharacter AA {\xfiveencodedAA}
+%
+% \stopencoding
+%
+% \def\xfiveencodedaa%
+% {\accent23a}
+%
+% \def\xfiveencodedAA%
+% {\leavevmode
+% \setbox\zerocount\hbox{h}%
+% \dimen@\ht\zerocount
+% \advance\dimen@ -1ex
+% \rlap{\raise.67\dimen@\hbox{\char23}}A}
+
+% \quotesinglbase 13
+% \guilsinglleft 14
+% \guilsinglright 15
+% \textquotedblleft 16
+% \textquotedblright 17
+% \quotedblbase 18
+% \guillemotleft 19
+% \guillemotright 20
+% \textendash 21
+% \textemdash 22
+% \textcompwordmark 23
+% \textperthousand \% \char 24
+% \textpertenthousand \%\char 24\char 24
+% \textvisiblespace 32
+% \textquotedbl `\"
+% \textdollar `\$
+% \textquoteright `\'
+% \textless `\<
+% \textgreater `\>
+% \textbackslash `\
+% \textasciicircum `\^
+% \textunderscore 95
+% \textquoteleft `\`
+% \textbraceleft `\{
+% \textbar `\|
+% \textbraceright `\}
+% \textasciitilde `\~
diff --git a/tex/context/base/filt-bas.mkii b/tex/context/base/filt-bas.mkii
new file mode 100644
index 000000000..ca3bc3d70
--- /dev/null
+++ b/tex/context/base/filt-bas.mkii
@@ -0,0 +1,63 @@
+%D \module
+%D [ file=filt-bas,
+%D version=2000.09.19,
+%D title=\CONTEXT\ Filter Macros,
+%D subtitle=A Base Collection,
+%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.
+
+% BEWARE: THIS IS A TEST MODULE, NAMES MAY CHANGE!
+
+\definefiltersynonym [utf8 to unicode16] [inutf8]
+
+\definefiltersynonym [persian fix] [FarsiToArabic]
+\definefiltersynonym [arabic analysis] [uni2cuni]
+\definefiltersynonym [arabic glyphs] [cuni2oar]
+
+\definefiltersequence
+ [farsi]
+ [utf8 to unicode16,
+ persian fix,
+ arabic analysis,
+ arabic glyphs]
+
+\definefiltersynonym [basic context analysis step1] [bcaa-1]
+\definefiltersynonym [basic context analysis step2] [bcaa-2]
+\definefiltersynonym [basic context analysis step3] [bcaa-3]
+\definefiltersynonym [farsi processing for uomarab] [uomarab-farsi]
+
+\definefiltersynonym [basic presentation forms to sf] [bpftosf]
+
+\definefiltersynonym [omega persian fix] [FarsiToArabic]
+\definefiltersynonym [omega arabic analysis] [uni2cuni]
+\definefiltersynonym [omega arabic glyphs] [cuni2oar]
+
+\definefiltersequence
+ [farsi-1]
+ [utf8 to unicode16,
+ omega persian fix,
+ omega arabic analysis,
+ omega arabic glyphs]
+
+\definefiltersequence
+ [farsi-2]
+ [utf8 to unicode16,
+ basic context analysis step1,
+ basic context analysis step2,
+ basic context analysis step3,
+ farsi processing for uomarab]
+
+\definefiltersequence
+ [farsi-3]
+ [utf8 to unicode16,
+ basic context analysis step1,
+ basic context analysis step2,
+ basic context analysis step3,
+ basic presentation forms to sf]
+
+\endinput
diff --git a/tex/context/base/filt-ini.mkii b/tex/context/base/filt-ini.mkii
new file mode 100644
index 000000000..6e1a16e9a
--- /dev/null
+++ b/tex/context/base/filt-ini.mkii
@@ -0,0 +1,121 @@
+%D \module
+%D [ file=filt-ini,
+%D version=2000.09.19,
+%D title=\CONTEXT\ Filter Macros,
+%D subtitle=Initialization,
+%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 Filter Macros / Initialization}
+
+% \ifx\OmegaVersion\undefined
+
+% \let\definefiltersynonym \gobbledoubleempty
+% \let\definefiltersequence \gobbledoubleempty
+% \unexpanded\def\usefiltersequence {\gobblesingleempty}
+% \let\usefilter \gobblesingleempty
+% \let\truefiltername \gobbleoneargument
+
+% \expandafter \endinput
+% \fi
+
+\unprotect
+
+%D The real work starts here.
+
+% We need the {\??ot::#1} check because otherwise aleph will crash. Taco's
+% torture test:
+%
+% \ocp\ArabicContext = contextual
+%
+% \dorecurse {5000} {
+% \message{[\recurselevel]}
+% \ocplist\Arabic=\addbeforeocplist 1 \ArabicContext \nullocplist
+% }
+
+%D \macros
+%D {definefiltersynonym}
+
+\def\definefiltersynonym
+ {\dodoubleargument\dodefinefiltersynonym}
+
+\def\dodefinefiltersynonym[#1][#2]%
+ {\setvalue{\??or#1}{#2}}
+
+%D \macros
+%D {truefiltername}
+
+\def\truefiltername#1%
+ {\ifundefined{\??or#1}#1\else\truefiltername{\getvalue{\??or#1}}\fi}
+
+%D \macros
+%D {definefiltersequence}
+
+\def\definefiltersequence
+ {\dodoubleargument\dodefinefiltersequence}
+
+% \def\dodefinefiltersequence[#1][#2]%
+% {\setvalue{\??ot#1}{#2}}
+
+\def\dodefinefiltersequence[#1][#2]%
+ {\setxvalue{\??ot#1}{#2}%
+ \letgvalue{\??ot::#1}\v!stop}
+
+%D \macros
+%D {usefiltersequence}
+%D
+
+\def\magicocpnumber{1}
+
+% one can do:
+%
+% \definefiltersequence
+% [farsi]
+% [utf8 to unicode16=>5,
+% persian fix,
+% arabic analysis=>3,
+% arabic glyphs]
+%
+% so, => is used to signal a priority
+
+\def\dodousefiltersequence#1%
+ {\expandafter\ocp\csname\??or:#1\endcsname=\truefiltername{#1}\relax
+ \splitstring#1\at=>\to\!!stringa\and\!!stringb
+ \edef\!!stringb{\number\ifx\!!stringb\empty\magicocpnumber\else\!!stringb\fi}%
+ \appendetoks
+ \noexpand\addbeforeocplist
+ \!!stringb\space
+ \expandafter\noexpand\csname\??or:\!!stringa\endcsname
+ \to \scratchtoks}
+
+\unexpanded\def\usefiltersequence[#1]%
+ {\doifdefined{\??ot::#1}%
+ {\doifvalue{\??ot::#1}\v!stop
+ {\scratchtoks\emptytoks
+ \expanded{\processcommalist[\getvalue{\??ot#1}]}\dodousefiltersequence
+ \expanded{\global\ocplist\csname\??ot:#1\endcsname=\the\scratchtoks}\nullocplist
+ \letgvalue{\??ot::#1}\v!start}%
+ \expanded{\pushocplist\csname\??ot:#1\endcsname}\relax}}
+
+%D \macros
+%D {usefilter}
+
+\def\dousefilter#1%
+ {\doifundefined{\c!file\f!filterprefix#1}%
+ {\letvalue{\c!file\f!filterprefix#1}\empty
+ \makeshortfilename[\truefilename{\f!filterprefix#1}]%
+ \startreadingfile
+ \readsysfile{\shortfilename.mkii}
+ {\showmessage\m!filters1{#1}}
+ {\showmessage\m!filters2{#1}}%
+ \stopreadingfile}}
+
+\def\usefilter[#1]%
+ {\processcommalist[#1]\dousefilter}
+
+\protect \endinput
diff --git a/tex/context/base/font-afm.lua b/tex/context/base/font-afm.lua
new file mode 100644
index 000000000..87dec59c6
--- /dev/null
+++ b/tex/context/base/font-afm.lua
@@ -0,0 +1,855 @@
+if not modules then modules = { } end modules ['font-afm'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+
Some code may look a bit obscure but this has to do with the
+fact that we also use this code for testing and much code evolved
+in the transition from to to .
+
+
The following code still has traces of intermediate font support
+where we handles font encodings. Eventually font encoding goes
+away.
+--ldx]]--
+
+local trace_features = false trackers.register("afm.features", function(v) trace_features = v end)
+local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end)
+local trace_loading = false trackers.register("afm.loading", function(v) trace_loading = v end)
+
+local format, match, gmatch, lower, gsub = string.format, string.match, string.gmatch, string.lower, string.gsub
+local lpegmatch = lpeg.match
+local abs = math.abs
+
+fonts = fonts or { }
+fonts.afm = fonts.afm or { }
+
+local afm = fonts.afm
+local tfm = fonts.tfm
+
+afm.version = 1.402 -- incrementing this number one up will force a re-cache
+afm.syncspace = true -- when true, nicer stretch values
+afm.enhance_data = true -- best leave this set to true
+afm.features = { }
+afm.features.aux = { }
+afm.features.data = { }
+afm.features.list = { }
+afm.features.default = { }
+afm.cache = containers.define("fonts", "afm", afm.version, true)
+
+--[[ldx--
+
We start with the basic reader which we give a name similar to the
+built in and reader.
+--ldx]]--
+
+--~ Comment FONTIDENTIFIER LMMATHSYMBOLS10
+--~ Comment CODINGSCHEME TEX MATH SYMBOLS
+--~ Comment DESIGNSIZE 10.0 pt
+--~ Comment CHECKSUM O 4261307036
+--~ Comment SPACE 0 plus 0 minus 0
+--~ Comment QUAD 1000
+--~ Comment EXTRASPACE 0
+--~ Comment NUM 676.508 393.732 443.731
+--~ Comment DENOM 685.951 344.841
+--~ Comment SUP 412.892 362.892 288.889
+--~ Comment SUB 150 247.217
+--~ Comment SUPDROP 386.108
+--~ Comment SUBDROP 50
+--~ Comment DELIM 2390 1010
+--~ Comment AXISHEIGHT 250
+
+local c = lpeg.P("Comment")
+local s = lpeg.S(" \t")
+local l = lpeg.S("\n\r")
+local w = lpeg.C((1 - l)^1)
+local n = lpeg.C((lpeg.R("09") + lpeg.S("."))^1) / tonumber * s^0
+
+local fd = { }
+
+local pattern = ( c * s^1 * (
+ ("CODINGSCHEME" * s^1 * w ) / function(a) end +
+ ("DESIGNSIZE" * s^1 * n * w ) / function(a) fd[ 1] = a end +
+ ("CHECKSUM" * s^1 * n * w ) / function(a) fd[ 2] = a end +
+ ("SPACE" * s^1 * n * "plus" * n * "minus" * n) / function(a,b,c) fd[ 3], fd[ 4], fd[ 5] = a, b, c end +
+ ("QUAD" * s^1 * n ) / function(a) fd[ 6] = a end +
+ ("EXTRASPACE" * s^1 * n ) / function(a) fd[ 7] = a end +
+ ("NUM" * s^1 * n * n * n ) / function(a,b,c) fd[ 8], fd[ 9], fd[10] = a, b, c end +
+ ("DENOM" * s^1 * n * n ) / function(a,b ) fd[11], fd[12] = a, b end +
+ ("SUP" * s^1 * n * n * n ) / function(a,b,c) fd[13], fd[14], fd[15] = a, b, c end +
+ ("SUB" * s^1 * n * n ) / function(a,b) fd[16], fd[17] = a, b end +
+ ("SUPDROP" * s^1 * n ) / function(a) fd[18] = a end +
+ ("SUBDROP" * s^1 * n ) / function(a) fd[19] = a end +
+ ("DELIM" * s^1 * n * n ) / function(a,b) fd[20], fd[21] = a, b end +
+ ("AXISHEIGHT" * s^1 * n ) / function(a) fd[22] = a end +
+ (1-l)^0
+) + (1-c)^1)^0
+
+local function scan_comment(str)
+ fd = { }
+ lpegmatch(pattern,str)
+ return fd
+end
+
+-- On a rainy day I will rewrite this in lpeg ...
+
+local keys = { }
+
+function keys.FontName (data,line) data.metadata.fullname = line:strip() end
+function keys.ItalicAngle (data,line) data.metadata.italicangle = tonumber (line) end
+function keys.IsFixedPitch(data,line) data.metadata.isfixedpitch = toboolean(line,true) end
+function keys.CharWidth (data,line) data.metadata.charwidth = tonumber (line) end
+function keys.XHeight (data,line) data.metadata.xheight = tonumber (line) end
+function keys.Descender (data,line) data.metadata.descender = tonumber (line) end
+function keys.Ascender (data,line) data.metadata.ascender = tonumber (line) end
+function keys.Comment (data,line)
+ -- Comment DesignSize 12 (pts)
+ -- Comment TFM designsize: 12 (in points)
+ line = lower(line)
+ local designsize = match(line,"designsize[^%d]*(%d+)")
+ if designsize then data.metadata.designsize = tonumber(designsize) end
+end
+
+local function get_charmetrics(data,charmetrics,vector)
+ local characters = data.characters
+ local chr, str, ind = { }, "", 0
+ for k,v in gmatch(charmetrics,"([%a]+) +(.-) *;") do
+ if k == 'C' then
+ if str ~= "" then characters[str] = chr end
+ chr = { }
+ str = ""
+ v = tonumber(v)
+ if v < 0 then
+ ind = ind + 1
+ else
+ ind = v
+ end
+ chr.index = ind
+ elseif k == 'WX' then
+ chr.width = v
+ elseif k == 'N' then
+ str = v
+ elseif k == 'B' then
+ local llx, lly, urx, ury = match(v,"^ *(.-) +(.-) +(.-) +(.-)$")
+ chr.boundingbox = { tonumber(llx), tonumber(lly), tonumber(urx), tonumber(ury) }
+ elseif k == 'L' then
+ local plus, becomes = match(v,"^(.-) +(.-)$")
+ if not chr.ligatures then chr.ligatures = { } end
+ chr.ligatures[plus] = becomes
+ end
+ end
+ if str ~= "" then
+ characters[str] = chr
+ end
+end
+
+local function get_kernpairs(data,kernpairs)
+ local characters = data.characters
+ for one, two, value in gmatch(kernpairs,"KPX +(.-) +(.-) +(.-)\n") do
+ local chr = characters[one]
+ if chr then
+ if not chr.kerns then chr.kerns = { } end
+ chr.kerns[two] = tonumber(value)
+ end
+ end
+end
+
+local function get_variables(data,fontmetrics)
+ for key, rest in gmatch(fontmetrics,"(%a+) *(.-)[\n\r]") do
+ if keys[key] then keys[key](data,rest) end
+ end
+end
+
+local function get_indexes(data,filename)
+ local pfbfile = file.replacesuffix(filename,"pfb")
+ local pfbname = resolvers.find_file(pfbfile,"pfb") or ""
+ if pfbname == "" then
+ pfbname = resolvers.find_file(file.basename(pfbfile),"pfb") or ""
+ end
+ if pfbname ~= "" then
+ data.luatex.filename = pfbname
+ local pfbblob = fontloader.open(pfbname)
+ if pfbblob then
+ local characters = data.characters
+ local pfbdata = fontloader.to_table(pfbblob)
+ --~ print(table.serialize(pfbdata))
+ if pfbdata then
+ local glyphs = pfbdata.glyphs
+ if glyphs then
+ if trace_loading then
+ logs.report("load afm","getting index data from %s",pfbname)
+ end
+ -- local offset = (glyphs[0] and glyphs[0] != .notdef) or 0
+ for index, glyph in next, glyphs do
+ local name = glyph.name
+ if name then
+ local char = characters[name]
+ if char then
+ if trace_indexing then
+ logs.report("load afm","glyph %s has index %s",name,index)
+ end
+ char.index = index
+ end
+ end
+ end
+ elseif trace_loading then
+ logs.report("load afm","no glyph data in pfb file %s",pfbname)
+ end
+ elseif trace_loading then
+ logs.report("load afm","no data in pfb file %s",pfbname)
+ end
+ fontloader.close(pfbblob)
+ elseif trace_loading then
+ logs.report("load afm","invalid pfb file %s",pfbname)
+ end
+ elseif trace_loading then
+ logs.report("load afm","no pfb file for %s",filename)
+ end
+end
+
+function afm.read_afm(filename)
+ local ok, afmblob, size = resolvers.loadbinfile(filename) -- has logging
+-- local ok, afmblob = true, file.readdata(filename)
+ if ok and afmblob then
+ local data = {
+ characters = { },
+ metadata = {
+ version = version or '0', -- hm
+ filename = file.removesuffix(file.basename(filename))
+ }
+ }
+ afmblob = gsub(afmblob,"StartCharMetrics(.-)EndCharMetrics", function(charmetrics)
+ if trace_loading then
+ logs.report("load afm","loading char metrics")
+ end
+ get_charmetrics(data,charmetrics,vector)
+ return ""
+ end)
+ afmblob = gsub(afmblob,"StartKernPairs(.-)EndKernPairs", function(kernpairs)
+ if trace_loading then
+ logs.report("load afm","loading kern pairs")
+ end
+ get_kernpairs(data,kernpairs)
+ return ""
+ end)
+ afmblob = gsub(afmblob,"StartFontMetrics%s+([%d%.]+)(.-)EndFontMetrics", function(version,fontmetrics)
+ if trace_loading then
+ logs.report("load afm","loading variables")
+ end
+ data.afmversion = version
+ get_variables(data,fontmetrics)
+ data.fontdimens = scan_comment(fontmetrics) -- todo: all lpeg, no time now
+ return ""
+ end)
+ data.luatex = { }
+ get_indexes(data,filename)
+ return data
+ else
+ if trace_loading then
+ logs.report("load afm","no valid afm file %s",filename)
+ end
+ return nil
+ end
+end
+
+--[[ldx--
+
We cache files. Caching is taken care of in the loader. We cheat a bit
+by adding ligatures and kern information to the afm derived data. That
+way we can set them faster when defining a font.
+--ldx]]--
+
+function afm.load(filename)
+ -- hm, for some reasons not resolved yet
+ filename = resolvers.find_file(filename,'afm') or ""
+ if filename ~= "" then
+ local name = file.removesuffix(file.basename(filename))
+ local data = containers.read(afm.cache(),name)
+ local size = lfs.attributes(filename,"size") or 0
+ if not data or data.verbose ~= fonts.verbose or data.size ~= size then
+ logs.report("load afm", "reading %s",filename)
+ data = afm.read_afm(filename)
+ if data then
+ -- data.luatex = data.luatex or { }
+ logs.report("load afm", "unifying %s",filename)
+ afm.unify(data,filename)
+ if afm.enhance_data then
+ logs.report("load afm", "add ligatures")
+ afm.add_ligatures(data,'ligatures') -- easier this way
+ logs.report("load afm", "add tex-ligatures")
+ afm.add_ligatures(data,'texligatures') -- easier this way
+ logs.report("load afm", "add extra kerns")
+ afm.add_kerns(data) -- faster this way
+ end
+ logs.report("load afm", "add tounicode data")
+ fonts.map.add_to_unicode(data,filename)
+ data.size = size
+ data.verbose = fonts.verbose
+ logs.report("load afm","saving: %s in cache",name)
+ data = containers.write(afm.cache(), name, data)
+ data = containers.read(afm.cache(),name)
+ end
+ end
+ return data
+ else
+ return nil
+ end
+end
+
+function afm.unify(data, filename)
+ local unicodevector = fonts.enc.load('unicode').hash
+ local glyphs, indices, unicodes, names = { }, { }, { }, { }
+ local verbose, private = fonts.verbose, fonts.private
+ for name, blob in next, data.characters do
+ local code = unicodevector[name] -- or characters.name_to_unicode[name]
+ if not code then
+ local u = match(name,"^uni(%x+)$")
+ code = u and tonumber(u,16)
+ if not code then
+ code = private
+ private = private + 1
+ logs.report("afm glyph", "assigning private slot U+%04X for unknown glyph name %s", code, name)
+ end
+ end
+ local index = blob.index
+ unicodes[name] = code
+ indices[code] = index
+ glyphs[index] = blob
+ names[name] = index
+ blob.name = name
+ if verbose then
+ local bu = blob.unicode
+ if not bu then
+ blob.unicode = code
+ elseif type(bu) == "table" then
+ bu[#bu+1] = code
+ else
+ blob.unicode = { bu, code }
+ end
+ else
+ blob.index = nil
+ end
+ end
+ data.glyphs = glyphs
+ data.characters = nil
+ local luatex = data.luatex
+ luatex.filename = luatex.filename or file.removesuffix(file.basename(filename))
+ luatex.unicodes = unicodes -- name to unicode
+ luatex.indices = indices -- unicode to index
+ luatex.marks = { } -- todo
+ luatex.names = names -- name to index
+ luatex.private = private
+end
+
+--[[ldx--
+
These helpers extend the basic table with extra ligatures, texligatures
+and extra kerns. This saves quite some lookups later.
+--ldx]]--
+
+function afm.add_ligatures(afmdata,ligatures)
+ local glyphs, luatex = afmdata.glyphs, afmdata.luatex
+ local indices, unicodes, names = luatex.indices, luatex.unicodes, luatex.names
+ for k,v in next, characters[ligatures] do -- main characters table
+ local one = glyphs[names[k]]
+ if one then
+ for _, b in next, v do
+ two, three = b[1], b[2]
+ if two and three and names[two] and names[three] then
+ local ol = one[ligatures]
+ if ol then
+ if not ol[two] then -- was one.ligatures ... bug
+ ol[two] = three
+ end
+ else
+ one[ligatures] = { [two] = three }
+ end
+ end
+ end
+ end
+ end
+end
+
+--[[ldx--
+
We keep the extra kerns in separate kerning tables so that we can use
+them selectively.
+--ldx]]--
+
+function afm.add_kerns(afmdata)
+ local glyphs = afmdata.glyphs
+ local names = afmdata.luatex.names
+ local uncomposed = characters.uncomposed
+ local function do_it_left(what)
+ for index, glyph in next, glyphs do
+ local kerns = glyph.kerns
+ if kerns then
+ local extrakerns = glyph.extrakerns or { }
+ for complex, simple in next, uncomposed[what] do
+ if names[compex] then
+ local ks = kerns[simple]
+ if ks and not kerns[complex] then
+ extrakerns[complex] = ks
+ end
+ end
+ end
+ if next(extrakerns) then
+ glyph.extrakerns = extrakerns
+ end
+ end
+ end
+ end
+ local function do_it_copy(what)
+ for complex, simple in next, uncomposed[what] do
+ local c = glyphs[names[complex]]
+ if c then -- optional
+ local s = glyphs[names[simple]]
+ if s then
+ if not c.kerns then
+ c.extrakerns = s.kerns or { }
+ end
+ if s.extrakerns then
+ local extrakerns = c.extrakerns or { }
+ for k, v in next, s.extrakerns do
+ extrakerns[k] = v
+ end
+ if next(extrakerns) then
+ s.extrakerns = extrakerns
+ end
+ end
+ end
+ end
+ end
+ end
+ -- add complex with values of simplified when present
+ do_it_left("left")
+ do_it_left("both")
+ -- copy kerns from simple char to complex char unless set
+ do_it_copy("both")
+ do_it_copy("right")
+end
+
+--[[ldx--
+
The copying routine looks messy (and is indeed a bit messy).
+--ldx]]--
+
+-- once we have otf sorted out (new format) we can try to make the afm
+-- cache similar to it (similar tables)
+
+function afm.add_dimensions(data) -- we need to normalize afm to otf i.e. indexed table instead of name
+ if data then
+ for index, glyph in next, data.glyphs do
+ local bb = glyph.boundingbox
+ if bb then
+ local ht, dp = bb[4], -bb[2]
+ if ht == 0 or ht < 0 then
+ -- no need to set it and no negative heights, nil == 0
+ else
+ glyph.height = ht
+ end
+ if dp == 0 or dp < 0 then
+ -- no negative depths and no negative depths, nil == 0
+ else
+ glyph.depth = dp
+ end
+ end
+ end
+ end
+end
+
+fonts.formats.afm = "type1"
+fonts.formats.pfb = "type1"
+
+function afm.copy_to_tfm(data)
+ if data then
+ local glyphs = data.glyphs
+ if glyphs then
+ local metadata, luatex = data.metadata, data.luatex
+ local unicodes, indices = luatex.unicodes, luatex.indices
+ local characters, parameters, descriptions = { }, { }, { }
+ -- todo : merge into tfm
+ for u, i in next, indices do
+ local d = glyphs[i]
+ characters[u] = { }
+ descriptions[u] = d
+ end
+ local filename = fonts.tfm.checked_filename(luatex) -- was metadata.filename
+ local fontname = metadata.fontname or metadata.fullname
+ local fullname = metadata.fullname or metadata.fontname
+ local endash, emdash, space, spaceunits = unicodes['space'], unicodes['emdash'], "space", 500
+ -- same as otf
+ if metadata.isfixedpitch then
+ if descriptions[endash] then
+ spaceunits, spacer = descriptions[endash].width, "space"
+ end
+ if not spaceunits and descriptions[emdash] then
+ spaceunits, spacer = descriptions[emdash].width, "emdash"
+ end
+ if not spaceunits and metadata.charwidth then
+ spaceunits, spacer = metadata.charwidth, "charwidth"
+ end
+ else
+ if descriptions[endash] then
+ spaceunits, spacer = descriptions[endash].width, "space"
+ end
+ if not spaceunits and metadata.charwidth then
+ spaceunits, spacer = metadata.charwidth, "charwidth"
+ end
+ end
+ spaceunits = tonumber(spaceunits)
+ if spaceunits < 200 then
+ -- todo: warning
+ end
+ --
+ parameters.slant = 0
+ parameters.space = spaceunits
+ parameters.space_stretch = 500
+ parameters.space_shrink = 333
+ parameters.x_height = 400
+ parameters.quad = 1000
+ local italicangle = data.metadata.italicangle
+ if italicangle then
+ parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
+ end
+ if metadata.isfixedpitch then
+ parameters.space_stretch = 0
+ parameters.space_shrink = 0
+ elseif afm.syncspace then
+ parameters.space_stretch = spaceunits/2
+ parameters.space_shrink = spaceunits/3
+ end
+ parameters.extra_space = parameters.space_shrink
+ if metadata.xheight and metadata.xheight > 0 then
+ parameters.x_height = metadata.xheight
+ else
+ -- same as otf
+ local x = unicodes['x']
+ if x then
+ local x = descriptions[x]
+ if x then
+ parameters.x_height = x.height
+ end
+ end
+ --
+ end
+ local fd = data.fontdimens
+ if fd and fd[8] and fd[9] and fd[10] then -- math
+ for k,v in next, fd do
+ parameters[k] = v
+ end
+ end
+ --
+ if next(characters) then
+ return {
+ characters = characters,
+ parameters = parameters,
+ descriptions = descriptions,
+ indices = indices,
+ unicodes = unicodes,
+ luatex = luatex,
+ encodingbytes = 2,
+ filename = filename,
+ fontname = fontname,
+ fullname = fullname,
+ psname = fullname, -- in otf: tfm.fontname or tfm.fullname
+ name = filename or fullname or fontname,
+ format = fonts.fontformat(filename,"type1"),
+ type = 'real',
+ units = 1000,
+ direction = 0,
+ boundarychar_label = 0,
+ boundarychar = 65536,
+ --~ false_boundarychar = 65536, -- produces invalid tfm in luatex
+ designsize = (metadata.designsize or 10)*65536,
+ spacer = spacer,
+ ascender = abs(metadata.ascender or 0),
+ descender = abs(metadata.descender or 0),
+ italicangle = italicangle,
+ }
+ end
+ end
+ end
+ return nil
+end
+
+--[[ldx--
+
Originally we had features kind of hard coded for
+files but since I expect to support more font formats, I decided
+to treat this fontformat like any other and handle features in a
+more configurable way.
+--ldx]]--
+
+function afm.features.register(name,default)
+ afm.features.list[#afm.features.list+1] = name
+ afm.features.default[name] = default
+end
+
+function afm.set_features(tfmdata)
+ local shared = tfmdata.shared
+ local afmdata = shared.afmdata
+ local features = shared.features
+ if features and next(features) then
+ local mode = tfmdata.mode or fonts.mode
+ local initializers = fonts.initializers
+ local fi = initializers[mode]
+ local fiafm = fi and fi.afm
+ if fiafm then
+ local lists = {
+ fonts.triggers,
+ afm.features.list,
+ fonts.manipulators,
+ }
+ for l=1,3 do
+ local list = lists[l]
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ local value = features[f]
+ if value and fiafm[f] then -- brr
+ if trace_features then
+ logs.report("define afm","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown')
+ end
+ fiafm[f](tfmdata,value)
+ mode = tfmdata.mode or fonts.mode
+ fiafm = initializers[mode].afm
+ end
+ end
+ end
+ end
+ end
+ local fm = fonts.methods[mode]
+ local fmafm = fm and fm.afm
+ if fmfm then
+ local lists = {
+ afm.features.list,
+ }
+ local sp = shared.processors
+ for l=1,1 do
+ local list = lists[l]
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ if features[f] and fmafm[f] then -- brr
+ if not sp then
+ sp = { fmafm[f] }
+ shared.processors = sp
+ else
+ sp[#sp+1] = fmafm[f]
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function afm.check_features(specification)
+ local features, done = fonts.define.check(specification.features.normal,afm.features.default)
+ if done then
+ specification.features.normal = features
+ tfm.hash_instance(specification,true)
+ end
+end
+
+function afm.afm_to_tfm(specification)
+ local afmname = specification.filename or specification.name
+ if specification.forced == "afm" or specification.format == "afm" then -- move this one up
+ if trace_loading then
+ logs.report("load afm","forcing afm format for %s",afmname)
+ end
+ else
+ local tfmname = resolvers.findbinfile(afmname,"ofm") or ""
+ if tfmname ~= "" then
+ if trace_loading then
+ logs.report("load afm","fallback from afm to tfm for %s",afmname)
+ end
+ afmname = ""
+ end
+ end
+ if afmname == "" then
+ return nil
+ else
+ afm.check_features(specification)
+ specification = fonts.define.resolve(specification) -- new, was forgotten
+ local features = specification.features.normal
+ local cache_id = specification.hash
+ local tfmdata = containers.read(tfm.cache(), cache_id) -- cache with features applied
+ if not tfmdata then
+ local afmdata = afm.load(afmname)
+ if afmdata and next(afmdata) then
+ afm.add_dimensions(afmdata)
+ tfmdata = afm.copy_to_tfm(afmdata)
+ if tfmdata and next(tfmdata) then
+ tfmdata.shared = tfmdata.shared or { }
+ tfmdata.unique = tfmdata.unique or { }
+ tfmdata.shared.afmdata = afmdata
+ tfmdata.shared.features = features
+ afm.set_features(tfmdata)
+ end
+ elseif trace_loading then
+ logs.report("load afm","no (valid) afm file found with name %s",afmname)
+ end
+ tfmdata = containers.write(tfm.cache(),cache_id,tfmdata)
+ end
+ return tfmdata
+ end
+end
+
+--[[ldx--
+
As soon as we could intercept the reader, I implemented an
+ reader. Since traditional could use
+fonts with companions, the following method also could handle
+those cases, but now that we can handle directly we no longer
+need this features.
+--ldx]]--
+
+tfm.default_encoding = 'unicode'
+
+function tfm.set_normal_feature(specification,name,value)
+ if specification and name then
+ specification.features = specification.features or { }
+ specification.features.normal = specification.features.normal or { }
+ specification.features.normal[name] = value
+ end
+end
+
+function tfm.read_from_afm(specification)
+ local tfmtable = afm.afm_to_tfm(specification)
+ if tfmtable then
+ tfmtable.name = specification.name
+ tfmtable = tfm.scale(tfmtable, specification.size, specification.relativeid)
+ local afmdata = tfmtable.shared.afmdata
+--~ local filename = afmdata and afmdata.luatex and afmdata.luatex.filename
+--~ if filename then
+--~ tfmtable.encodingbytes = 2
+--~ tfmtable.filename = resolvers.findbinfile(filename,"") or filename
+--~ tfmtable.fontname = afmdata.metadata.fontname or afmdata.metadata.fullname
+--~ tfmtable.fullname = afmdata.metadata.fullname or afmdata.metadata.fontname
+--~ tfmtable.format = 'type1'
+--~ tfmtable.name = afmdata.luatex.filename or tfmtable.fullname
+--~ end
+ if fonts.dontembed[filename] then
+ tfmtable.file = nil -- or filename ?
+ end
+ fonts.logger.save(tfmtable,'afm',specification)
+ end
+ return tfmtable
+end
+
+--[[ldx--
+
Here comes the implementation of a few features. We only implement
+those that make sense for this format.
So far we haven't really dealt with features (or whatever we want
+to pass along with the font definition. We distinguish the following
+situations:
+situations:
+
+
+name:xetex like specs
+name@virtual font spec
+name*context specification
+
+--ldx]]--
+
+function specify.predefined(specification)
+ local detail = specification.detail
+ if detail ~= "" then
+ -- detail = gsub(detail,"["..define.splitsymbols.."].*$","") -- get rid of *whatever specs and such
+ if define.methods[detail] then -- since these may be appended at the
+ specification.features.vtf = { preset = detail } -- tex end by default
+ end
+ end
+ return specification
+end
+
+define.register_split("@", specify.predefined)
+
+storage.register("fonts/setups" , define.specify.context_setups , "fonts.define.specify.context_setups" )
+storage.register("fonts/numbers", define.specify.context_numbers, "fonts.define.specify.context_numbers")
+storage.register("fonts/merged", define.specify.context_merged, "fonts.define.specify.context_merged")
+storage.register("fonts/synonyms", define.specify.synonyms, "fonts.define.specify.synonyms")
+
+local normalize_meanings = fonts.otf.meanings.normalize
+local settings_to_hash = aux.settings_to_hash
+local default_features = fonts.otf.features.default
+
+local function preset_context(name,parent,features) -- currently otf only
+ if features == "" and find(parent,"=") then
+ features = parent
+ parent = ""
+ end
+ if features == "" then
+ features = { }
+ elseif type(features) == "string" then
+ features = normalize_meanings(settings_to_hash(features))
+ else
+ features = normalize_meanings(features)
+ end
+ -- todo: synonyms, and not otf bound
+ if parent ~= "" then
+ for p in gmatch(parent,"[^, ]+") do
+ local s = setups[p]
+ if s then
+ for k,v in next, s do
+ if features[k] == nil then
+ features[k] = v
+ end
+ end
+ end
+ end
+ end
+ -- these are auto set so in order to prevent redundant definitions
+ -- we need to preset them (we hash the features and adding a default
+ -- setting during initialization may result in a different hash)
+ for k,v in next, triggers do
+ if features[v] == nil then -- not false !
+ local vv = default_features[v]
+ if vv then features[v] = vv end
+ end
+ end
+ -- sparse 'm so that we get a better hash and less test (experimental
+ -- optimization)
+ local t = { } -- can we avoid t ?
+ for k,v in next, features do
+ if v then t[k] = v end
+ end
+ -- needed for dynamic features
+ local number = (setups[name] and setups[name].number) or 0
+ if number == 0 then
+ number = #numbers + 1
+ numbers[number] = name
+ end
+ t.number = number
+ setups[name] = t
+ return number, t
+end
+
+local function context_number(name) -- will be replaced
+ local t = setups[name]
+ if not t then
+ return 0
+ elseif t.auto then
+ local lng = tonumber(tex.language)
+ local tag = name .. ":" .. lng
+ local s = setups[tag]
+ if s then
+ return s.number or 0
+ else
+ local script, language = languages.association(lng)
+ if t.script ~= script or t.language ~= language then
+ local s = table.fastcopy(t)
+ local n = #numbers + 1
+ setups[tag] = s
+ numbers[n] = tag
+ s.number = n
+ s.script = script
+ s.language = language
+ return n
+ else
+ setups[tag] = t
+ return t.number or 0
+ end
+ end
+ else
+ return t.number or 0
+ end
+end
+
+local function merge_context(currentnumber,extraname,option)
+ local current = setups[numbers[currentnumber]]
+ local extra = setups[extraname]
+ if extra then
+ local mergedfeatures, mergedname = { }, nil
+ if option < 0 then
+ if current then
+ for k, v in next, current do
+ if not extra[k] then
+ mergedfeatures[k] = v
+ end
+ end
+ end
+ mergedname = currentnumber .. "-" .. extraname
+ else
+ if current then
+ for k, v in next, current do
+ mergedfeatures[k] = v
+ end
+ end
+ for k, v in next, extra do
+ mergedfeatures[k] = v
+ end
+ mergedname = currentnumber .. "+" .. extraname
+ end
+ local number = #numbers + 1
+ mergedfeatures.number = number
+ numbers[number] = mergedname
+ merged[number] = option
+ setups[mergedname] = mergedfeatures
+ return number -- context_number(mergedname)
+ else
+ return currentnumber
+ end
+end
+
+local function register_context(fontnumber,extraname,option)
+ local extra = setups[extraname]
+ if extra then
+ local mergedfeatures, mergedname = { }, nil
+ if option < 0 then
+ mergedname = fontnumber .. "-" .. extraname
+ else
+ mergedname = fontnumber .. "+" .. extraname
+ end
+ for k, v in next, extra do
+ mergedfeatures[k] = v
+ end
+ local number = #numbers + 1
+ mergedfeatures.number = number
+ numbers[number] = mergedname
+ merged[number] = option
+ setups[mergedname] = mergedfeatures
+ return number -- context_number(mergedname)
+ else
+ return 0
+ end
+end
+
+specify.preset_context = preset_context
+specify.context_number = context_number
+specify.merge_context = merge_context
+specify.register_context = register_context
+
+local current_font = font.current
+local tex_attribute = tex.attribute
+
+local cache = { } -- concat might be less efficient than nested tables
+
+function fonts.withset(name,what)
+ local zero = tex_attribute[0]
+ local hash = zero .. "+" .. name .. "*" .. what
+ local done = cache[hash]
+ if not done then
+ done = merge_context(zero,name,what)
+ cache[hash] = done
+ end
+ tex_attribute[0] = done
+end
+function fonts.withfnt(name,what)
+ local font = current_font()
+ local hash = font .. "*" .. name .. "*" .. what
+ local done = cache[hash]
+ if not done then
+ done = register_context(font,name,what)
+ cache[hash] = done
+ end
+ tex_attribute[0] = done
+end
+
+function specify.show_context(name)
+ return setups[name] or setups[numbers[name]] or setups[numbers[tonumber(name)]] or { }
+end
+
+local function split_context(features)
+ return setups[features] or (preset_context(features,"","") and setups[features])
+end
+
+specify.split_context = split_context
+
+function specify.context_tostring(name,kind,separator,yes,no,strict,omit) -- not used
+ return aux.hash_to_string(table.merged(fonts[kind].features.default or {},setups[name] or {}),separator,yes,no,strict,omit)
+end
+
+local splitter = lpeg.splitat(",")
+
+function specify.starred(features) -- no longer fallbacks here
+ local detail = features.detail
+ if detail and detail ~= "" then
+ features.features.normal = split_context(detail)
+ else
+ features.features.normal = { }
+ end
+ return features
+end
+
+define.register_split('*',specify.starred)
+
+-- define (two steps)
+
+local P, C, Cc = lpeg.P, lpeg.C, lpeg.Cc
+
+local space = P(" ")
+local spaces = space^0
+local leftparent = (P"(")
+local rightparent = (P")")
+local value = C((leftparent * (1-rightparent)^0 * rightparent + (1-space))^1)
+local dimension = C((space/"" + P(1))^1)
+local rest = C(P(1)^0)
+local scale_none = Cc(0)
+local scale_at = P("at") * Cc(1) * spaces * dimension -- value
+local scale_sa = P("sa") * Cc(2) * spaces * dimension -- value
+local scale_mo = P("mo") * Cc(3) * spaces * dimension -- value
+local scale_scaled = P("scaled") * Cc(4) * spaces * dimension -- value
+
+local sizepattern = spaces * (scale_at + scale_sa + scale_mo + scale_scaled + scale_none)
+local splitpattern = spaces * value * spaces * rest
+
+local specification --
+
+local get_specification = define.get_specification
+
+-- we can make helper macros which saves parsing (but normaly not
+-- that many calls, e.g. in mk a couple of 100 and in metafun 3500)
+
+function define.command_1(str)
+ statistics.starttiming(fonts)
+ local fullname, size = lpegmatch(splitpattern,str)
+ local lookup, name, sub, method, detail = get_specification(fullname)
+ if not name then
+ logs.report("define font","strange definition '%s'",str)
+ texsprint(ctxcatcodes,"\\fcglet\\somefontname\\defaultfontfile")
+ elseif name == "unknown" then
+ texsprint(ctxcatcodes,"\\fcglet\\somefontname\\defaultfontfile")
+ else
+ texsprint(ctxcatcodes,"\\fcxdef\\somefontname{",name,"}")
+ end
+ -- we can also use a count for the size
+ if size and size ~= "" then
+ local mode, size = lpegmatch(sizepattern,size)
+ if size and mode then
+ count.scaledfontmode = mode
+ texsprint(ctxcatcodes,"\\def\\somefontsize{",size,"}")
+ else
+ count.scaledfontmode = 0
+ texsprint(ctxcatcodes,"\\let\\somefontsize\\empty")
+ end
+ elseif true then
+ -- so we don't need to check in tex
+ count.scaledfontmode = 2
+ texsprint(ctxcatcodes,"\\let\\somefontsize\\empty")
+ else
+ count.scaledfontmode = 0
+ texsprint(ctxcatcodes,"\\let\\somefontsize\\empty")
+ end
+ specification = define.makespecification(str,lookup,name,sub,method,detail,size)
+end
+
+local n = 0
+
+-- we can also move rscale to here (more consistent)
+
+function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfallbacks,fontfallbacks,mathsize,textsize,relativeid)
+ if trace_defining then
+ logs.report("define font","memory usage before: %s",statistics.memused())
+ end
+ -- name is now resolved and size is scaled cf sa/mo
+ local lookup, name, sub, method, detail = get_specification(str or "")
+ -- asome settings can be overloaded
+ if lookup and lookup ~= "" then
+ specification.lookup = lookup
+ end
+ if relativeid and relativeid ~= "" then -- experimental hook
+ local id = tonumber(relativeid) or 0
+ specification.relativeid = id > 0 and id
+ end
+ specification.name = name
+ specification.size = size
+ specification.sub = (sub and sub ~= "" and sub) or specification.sub
+ specification.mathsize = mathsize
+ specification.textsize = textsize
+ if detail and detail ~= "" then
+ specification.method, specification.detail = method or "*", detail
+ elseif specification.detail and specification.detail ~= "" then
+ -- already set
+ elseif fontfeatures and fontfeatures ~= "" then
+ specification.method, specification.detail = "*", fontfeatures
+ elseif classfeatures and classfeatures ~= "" then
+ specification.method, specification.detail = "*", classfeatures
+ end
+ if fontfallbacks and fontfallbacks ~= "" then
+ specification.fallbacks = fontfallbacks
+ elseif classfallbacks and classfallbacks ~= "" then
+ specification.fallbacks = classfallbacks
+ end
+ local tfmdata = define.read(specification,size) -- id not yet known
+ if not tfmdata then
+ logs.report("define font","unable to define %s as \\%s",name,cs)
+ texsetcount("global","lastfontid",-1)
+ elseif type(tfmdata) == "number" then
+ if trace_defining then
+ logs.report("define font","reusing %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,tfmdata,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks)
+ end
+ tex.definefont(global,cs,tfmdata)
+ -- resolved (when designsize is used):
+ texsprint(ctxcatcodes,format("\\def\\somefontsize{%isp}",fontdata[tfmdata].size))
+ texsetcount("global","lastfontid",tfmdata)
+ else
+ -- local t = os.clock(t)
+ local id = font.define(tfmdata)
+ -- print(name,os.clock()-t)
+ tfmdata.id = id
+ define.register(tfmdata,id)
+ tex.definefont(global,cs,id)
+ tfm.cleanup_table(tfmdata)
+ if trace_defining then
+ logs.report("define font","defining %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,id,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks)
+ end
+ -- resolved (when designsize is used):
+ texsprint(ctxcatcodes,format("\\def\\somefontsize{%isp}",tfmdata.size))
+ --~ if specification.fallbacks then
+ --~ fonts.collections.prepare(specification.fallbacks)
+ --~ end
+ texsetcount("global","lastfontid",id)
+ end
+ if trace_defining then
+ logs.report("define font","memory usage after: %s",statistics.memused())
+ end
+ statistics.stoptiming(fonts)
+end
+
+local enable_auto_r_scale = false
+
+experiments.register("fonts.autorscale", function(v)
+ enable_auto_r_scale = v
+end)
+
+local calculate_scale = fonts.tfm.calculate_scale
+
+function fonts.tfm.calculate_scale(tfmtable, scaledpoints, relativeid)
+ local scaledpoints, delta, units = calculate_scale(tfmtable, scaledpoints, relativeid)
+ if enable_auto_r_scale and relativeid then -- for the moment this is rather context specific
+ local relativedata = fontdata[relativeid]
+ local id_x_height = relativedata and relativedata.parameters and relativedata.parameters.x_height
+ local tf_x_height = id_x_height and tfmtable.parameters and tfmtable.parameters.x_height * delta
+ if tf_x_height then
+ scaledpoints = (id_x_height/tf_x_height) * scaledpoints
+ delta = scaledpoints/units
+ end
+ end
+ return scaledpoints, delta, units
+end
+
+--~ table.insert(readers.sequence,1,'vtf')
+
+--~ function readers.vtf(specification)
+--~ if specification.features.vtf and specification.features.vtf.preset then
+--~ return tfm.make(specification)
+--~ else
+--~ return nil
+--~ end
+--~ end
+
+-- we need a place for this .. outside the generic scope
+
+local dimenfactors = number.dimenfactors
+
+function fonts.dimenfactor(unit,tfmdata)
+ if unit == "ex" then
+ return (tfmdata and tfmdata.parameters.x_height) or 655360
+ elseif unit == "em" then
+ return (tfmdata and tfmdata.parameters.em_height) or 655360
+ else
+ return dimenfactors[unit] or unit
+ end
+end
+
+function fonts.cleanname(name)
+ texsprint(ctxcatcodes,fonts.names.cleanname(name))
+end
+
+local p, f = 1, "%0.1fpt" -- normally this value is changed only once
+
+local stripper = lpeg.patterns.strip_zeros
+
+function fonts.nbfs(amount,precision)
+ if precision ~= p then
+ p = precision
+ f = "%0." .. p .. "fpt"
+ end
+ texsprint(ctxcatcodes,lpegmatch(stripper,format(f,amount/65536)))
+end
+
+-- for the moment here, this will become a chain of extras that is
+-- hooked into the ctx registration (or scaler or ...)
+
+function fonts.set_digit_width(font)
+ local tfmtable = fontdata[font]
+ local parameters = tfmtable.parameters
+ local width = parameters.digitwidth
+ if not width then
+ width = round(parameters.quad/2) -- maybe tex.scale
+ local characters = tfmtable.characters
+ for i=48,57 do
+ local wd = round(characters[i].width)
+ if wd > width then
+ width = wd
+ end
+ end
+ parameters.digitwidth = width
+ end
+ return width
+end
+
+fonts.get_digit_width = fonts.set_digit_width
+
+-- soon to be obsolete:
+
+local loaded = { -- prevent loading (happens in cont-sys files)
+ ["original-base.map" ] = true,
+ ["original-ams-base.map" ] = true,
+ ["original-ams-euler.map"] = true,
+ ["original-public-lm.map"] = true,
+}
+
+function fonts.map.loadfile(name)
+ name = file.addsuffix(name,"map")
+ if not loaded[name] then
+ pdf.mapfile(name)
+ loaded[name] = true
+ end
+end
+
+local loaded = { -- prevent double loading
+}
+
+function fonts.map.loadline(how,line)
+ if line then
+ how = how .. " " .. line
+ elseif how == "" then
+ how = "= " .. line
+ end
+ if not loaded[how] then
+ pdf.mapline(how)
+ loaded[how] = true
+ end
+end
+
+function fonts.map.reset()
+ pdf.mapfile("")
+end
+
+fonts.map.reset() -- resets the default file
+
+-- we need an 'do after the banner hook'
+
+-- pdf.mapfile("mkiv-base.map") -- loads the default file
+
+local nounicode = byte("?")
+
+local function name_to_slot(name) -- maybe some day rawdata
+ local tfmdata = fonts.ids[font.current()]
+ local shared = tfmdata and tfmdata.shared
+ local fntdata = shared and shared.otfdata or shared.afmdata
+ if fntdata then
+ local unicode = fntdata.luatex.unicodes[name]
+ if not unicode then
+ return nounicode
+ elseif type(unicode) == "number" then
+ return unicode
+ else -- multiple unicodes
+ return unicode[1]
+ end
+ end
+ return nounicode
+end
+
+fonts.name_to_slot = name_to_slot
+
+function fonts.char(n) -- todo: afm en tfm
+ if type(n) == "string" then
+ n = name_to_slot(n)
+ end
+ if type(n) == "number" then
+ texsprint(ctxcatcodes,format("\\char%s ",n))
+ end
+end
+
+-- moved from ini:
+
+fonts.color = { } -- dummy in ini
+
+local attribute = attributes.private('color')
+local mapping = (attributes and attributes.list[attribute]) or { }
+
+local set_attribute = node.set_attribute
+local unset_attribute = node.unset_attribute
+
+function fonts.color.set(n,c)
+ local mc = mapping[c]
+ if not mc then
+ unset_attribute(n,attribute)
+ else
+ set_attribute(n,attribute,mc)
+ end
+end
+
+function fonts.color.reset(n)
+ unset_attribute(n,attribute)
+end
+
+-- this will become obsolete:
+
+fonts.otf.name_to_slot = name_to_slot
+fonts.afm.name_to_slot = name_to_slot
+
+fonts.otf.char = fonts.char
+fonts.afm.char = fonts.char
+
+-- this will change ...
+
+function fonts.show_char_data(n)
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata then
+ if type(n) == "string" then
+ n = utf.byte(n)
+ end
+ local chr = tfmdata.characters[n]
+ if chr then
+ write_nl(format("%s @ %s => U%04X => %s => ",tfmdata.fullname,tfmdata.size,n,utf.char(n)) .. serialize(chr,false))
+ end
+ end
+end
+
+function fonts.show_font_parameters()
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata then
+ local parameters, mathconstants = tfmdata.parameters, tfmdata.MathConstants
+ local hasparameters, hasmathconstants = parameters and next(parameters), mathconstants and next(mathconstants)
+ if hasparameters then
+ write_nl(format("%s @ %s => parameters => ",tfmdata.fullname,tfmdata.size) .. serialize(parameters,false))
+ end
+ if hasmathconstants then
+ write_nl(format("%s @ %s => math constants => ",tfmdata.fullname,tfmdata.size) .. serialize(mathconstants,false))
+ end
+ if not hasparameters and not hasmathconstants then
+ write_nl(format("%s @ %s => no parameters and/or mathconstants",tfmdata.fullname,tfmdata.size))
+ end
+ end
+end
diff --git a/tex/context/base/font-def.lua b/tex/context/base/font-def.lua
new file mode 100644
index 000000000..c3b10162c
--- /dev/null
+++ b/tex/context/base/font-def.lua
@@ -0,0 +1,651 @@
+if not modules then modules = { } end modules ['font-def'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
+local tostring, next = tostring, next
+local lpegmatch = lpeg.match
+
+local trace_defining = false trackers .register("fonts.defining", function(v) trace_defining = v end)
+local directive_embedall = false directives.register("fonts.embedall", function(v) directive_embedall = v end)
+
+trackers.register("fonts.loading", "fonts.defining", "otf.loading", "afm.loading", "tfm.loading")
+trackers.register("fonts.all", "fonts.*", "otf.*", "afm.*", "tfm.*")
+
+--[[ldx--
+
Here we deal with defining fonts. We do so by intercepting the
+default loader that only handles .
+--ldx]]--
+
+fonts = fonts or { }
+fonts.define = fonts.define or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+fonts.vf = fonts.vf or { }
+fonts.used = fonts.used or { }
+
+local tfm = fonts.tfm
+local vf = fonts.vf
+local define = fonts.define
+
+tfm.version = 1.01
+tfm.cache = containers.define("fonts", "tfm", tfm.version, false) -- better in font-tfm
+
+define.method = "afm or tfm" -- afm, tfm, afm or tfm, tfm or afm
+define.specify = fonts.define.specify or { }
+define.methods = fonts.define.methods or { }
+
+tfm.fonts = tfm.fonts or { }
+tfm.readers = tfm.readers or { }
+tfm.internalized = tfm.internalized or { } -- internal tex numbers
+
+tfm.readers.sequence = { 'otf', 'ttf', 'afm', 'tfm' }
+
+tfm.auto_afm = true
+
+local readers = tfm.readers
+local sequence = readers.sequence
+
+--[[ldx--
+
We hardly gain anything when we cache the final (pre scaled)
+ table. But it can be handy for debugging.
The following function split the font specification into components
+and prepares a table that will move along as we proceed.
+--ldx]]--
+
+-- beware, we discard additional specs
+--
+-- method:name method:name(sub) method:name(sub)*spec method:name*spec
+-- name name(sub) name(sub)*spec name*spec
+-- name@spec*oeps
+
+local splitter, specifiers = nil, ""
+
+local P, C, S, Cc = lpeg.P, lpeg.C, lpeg.S, lpeg.Cc
+
+local left = P("(")
+local right = P(")")
+local colon = P(":")
+local space = P(" ")
+
+define.defaultlookup = "file"
+
+local prefixpattern = P(false)
+
+function define.add_specifier(symbol)
+ specifiers = specifiers .. symbol
+ local method = S(specifiers)
+ local lookup = C(prefixpattern) * colon
+ local sub = left * C(P(1-left-right-method)^1) * right
+ local specification = C(method) * C(P(1)^1)
+ local name = C((1-sub-specification)^1)
+ splitter = P((lookup + Cc("")) * name * (sub + Cc("")) * (specification + Cc("")))
+end
+
+function define.add_lookup(str,default)
+ prefixpattern = prefixpattern + P(str)
+end
+
+define.add_lookup("file")
+define.add_lookup("name")
+define.add_lookup("spec")
+
+function define.get_specification(str)
+ return lpegmatch(splitter,str)
+end
+
+function define.register_split(symbol,action)
+ define.add_specifier(symbol)
+ define.specify[symbol] = action
+end
+
+function define.makespecification(specification, lookup, name, sub, method, detail, size)
+ size = size or 655360
+ if trace_defining then
+ logs.report("define font","%s -> lookup: %s, name: %s, sub: %s, method: %s, detail: %s",
+ specification, (lookup ~= "" and lookup) or "[file]", (name ~= "" and name) or "-",
+ (sub ~= "" and sub) or "-", (method ~= "" and method) or "-", (detail ~= "" and detail) or "-")
+ end
+--~ if specification.lookup then
+--~ lookup = specification.lookup -- can come from xetex [] syntax
+--~ specification.lookup = nil
+--~ end
+ if not lookup or lookup == "" then
+ lookup = define.defaultlookup
+ end
+ local t = {
+ lookup = lookup, -- forced type
+ specification = specification, -- full specification
+ size = size, -- size in scaled points or -1000*n
+ name = name, -- font or filename
+ sub = sub, -- subfont (eg in ttc)
+ method = method, -- specification method
+ detail = detail, -- specification
+ resolved = "", -- resolved font name
+ forced = "", -- forced loader
+ features = { }, -- preprocessed features
+ }
+ return t
+end
+
+function define.analyze(specification, size)
+ -- can be optimized with locals
+ local lookup, name, sub, method, detail = define.get_specification(specification or "")
+ return define.makespecification(specification, lookup, name, sub, method, detail, size)
+end
+
+--[[ldx--
+
A unique hash value is generated by:
+--ldx]]--
+
+local sortedhashkeys = table.sortedhashkeys
+
+function tfm.hash_features(specification)
+ local features = specification.features
+ if features then
+ local t = { }
+ local normal = features.normal
+ if normal and next(normal) then
+ local f = sortedhashkeys(normal)
+ for i=1,#f do
+ local v = f[i]
+ if v ~= "number" and v ~= "features" then -- i need to figure this out, features
+ t[#t+1] = v .. '=' .. tostring(normal[v])
+ end
+ end
+ end
+ local vtf = features.vtf
+ if vtf and next(vtf) then
+ local f = sortedhashkeys(vtf)
+ for i=1,#f do
+ local v = f[i]
+ t[#t+1] = v .. '=' .. tostring(vtf[v])
+ end
+ end
+--~ if specification.mathsize then
+--~ t[#t+1] = "mathsize=" .. specification.mathsize
+--~ end
+ if #t > 0 then
+ return concat(t,"+")
+ end
+ end
+ return "unknown"
+end
+
+fonts.designsizes = { }
+
+--[[ldx--
+
In principle we can share tfm tables when we are in node for a font, but then
+we need to define a font switch as an id/attr switch which is no fun, so in that
+case users can best use dynamic features ... so, we will not use that speedup. Okay,
+when we get rid of base mode we can optimize even further by sharing, but then we
+loose our testcases for .
+--ldx]]--
+
+function tfm.hash_instance(specification,force)
+ local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks
+ if force or not hash then
+ hash = tfm.hash_features(specification)
+ specification.hash = hash
+ end
+ if size < 1000 and fonts.designsizes[hash] then
+ size = math.round(tfm.scaled(size, fonts.designsizes[hash]))
+ specification.size = size
+ end
+--~ local mathsize = specification.mathsize or 0
+--~ if mathsize > 0 then
+--~ local textsize = specification.textsize
+--~ if fallbacks then
+--~ return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ] @ ' .. fallbacks
+--~ else
+--~ return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ]'
+--~ end
+--~ else
+ if fallbacks then
+ return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
+ else
+ return hash .. ' @ ' .. tostring(size)
+ end
+--~ end
+end
+
+--[[ldx--
+
We can resolve the filename using the next function:
+--ldx]]--
+
+define.resolvers = resolvers
+
+function define.resolvers.file(specification)
+ specification.forced = file.extname(specification.name)
+ specification.name = file.removesuffix(specification.name)
+end
+
+function define.resolvers.name(specification)
+ local resolve = fonts.names.resolve
+ if resolve then
+ specification.resolved, specification.sub = fonts.names.resolve(specification.name,specification.sub)
+ if specification.resolved then
+ specification.forced = file.extname(specification.resolved)
+ specification.name = file.removesuffix(specification.resolved)
+ end
+ else
+ define.resolvers.file(specification)
+ end
+end
+
+function define.resolvers.spec(specification)
+ local resolvespec = fonts.names.resolvespec
+ if resolvespec then
+ specification.resolved, specification.sub = fonts.names.resolvespec(specification.name,specification.sub)
+ if specification.resolved then
+ specification.forced = file.extname(specification.resolved)
+ specification.name = file.removesuffix(specification.resolved)
+ end
+ else
+ define.resolvers.name(specification)
+ end
+end
+
+function define.resolve(specification)
+ if not specification.resolved or specification.resolved == "" then -- resolved itself not per se in mapping hash
+ local r = define.resolvers[specification.lookup]
+ if r then
+ r(specification)
+ end
+ end
+ if specification.forced == "" then
+ specification.forced = nil
+ else
+ specification.forced = specification.forced
+ end
+ specification.hash = lower(specification.name .. ' @ ' .. tfm.hash_features(specification))
+ if specification.sub and specification.sub ~= "" then
+ specification.hash = specification.sub .. ' @ ' .. specification.hash
+ end
+ return specification
+end
+
+--[[ldx--
+
The main read function either uses a forced reader (as determined by
+a lookup) or tries to resolve the name using the list of readers.
+
+
We need to cache when possible. We do cache raw tfm data (from , or ). After that we can cache based
+on specificstion (name) and size, that is, only needs a number
+for an already loaded fonts. However, it may make sense to cache fonts
+before they're scaled as well (store 's with applied methods
+and features). However, there may be a relation between the size and
+features (esp in virtual fonts) so let's not do that now.
+
+
Watch out, here we do load a font, but we don't prepare the
+specification yet.
+--ldx]]--
+
+function tfm.read(specification)
+ local hash = tfm.hash_instance(specification)
+ local tfmtable = tfm.fonts[hash] -- hashes by size !
+ if not tfmtable then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = readers[lower(forced)](specification)
+ if not tfmtable then
+ logs.report("define font","forced type %s of %s not found",forced,specification.name)
+ end
+ else
+ for s=1,#sequence do -- reader sequence
+ local reader = sequence[s]
+ if readers[reader] then -- not really needed
+ if trace_defining then
+ logs.report("define font","trying (reader sequence driven) type %s for %s with file %s",reader,specification.name,specification.filename or "unknown")
+ end
+ tfmtable = readers[reader](specification)
+ if tfmtable then
+ break
+ else
+ specification.filename = nil
+ end
+ end
+ end
+ end
+ if tfmtable then
+ if directive_embedall then
+ tfmtable.embedding = "full"
+ elseif tfmtable.filename and fonts.dontembed[tfmtable.filename] then
+ tfmtable.embedding = "no"
+ else
+ tfmtable.embedding = "subset"
+ end
+ tfm.fonts[hash] = tfmtable
+ fonts.designsizes[specification.hash] = tfmtable.designsize -- we only know this for sure after loading once
+ --~ tfmtable.mode = specification.features.normal.mode or "base"
+ end
+ end
+ if not tfmtable then
+ logs.report("define font","font with name %s is not found",specification.name)
+ end
+ return tfmtable
+end
+
+--[[ldx--
+
For virtual fonts we need a slightly different approach:
+--ldx]]--
+
+function tfm.read_and_define(name,size) -- no id
+ local specification = define.analyze(name,size)
+ local method = specification.method
+ if method and define.specify[method] then
+ specification = define.specify[method](specification)
+ end
+ specification = define.resolve(specification)
+ local hash = tfm.hash_instance(specification)
+ local id = define.registered(hash)
+ if not id then
+ local fontdata = tfm.read(specification)
+ if fontdata then
+ fontdata.hash = hash
+ id = font.define(fontdata)
+ define.register(fontdata,id)
+ tfm.cleanup_table(fontdata)
+ else
+ id = 0 -- signal
+ end
+ end
+ return fonts.ids[id], id
+end
+
+--[[ldx--
+
Next follow the readers. This code was written while
+evolved. Each one has its own way of dealing with its format.
+--ldx]]--
+
+local function check_tfm(specification,fullname)
+ -- ofm directive blocks local path search unless set; btw, in context we
+ -- don't support ofm files anyway as this format is obsolete
+ local foundname = resolvers.findbinfile(fullname, 'tfm') or "" -- just to be sure
+ if foundname == "" then
+ foundname = resolvers.findbinfile(fullname, 'ofm') or "" -- bonus for usage outside context
+ end
+ if foundname ~= "" then
+ specification.filename, specification.format = foundname, "ofm"
+ return tfm.read_from_tfm(specification)
+ end
+end
+
+local function check_afm(specification,fullname)
+ local foundname = resolvers.findbinfile(fullname, 'afm') or "" -- just to be sure
+ if foundname == "" and tfm.auto_afm then
+ local encoding, shortname = match(fullname,"^(.-)%-(.*)$") -- context: encoding-name.*
+ if encoding and shortname and fonts.enc.known[encoding] then
+ shortname = resolvers.findbinfile(shortname,'afm') or "" -- just to be sure
+ if shortname ~= "" then
+ foundname = shortname
+ -- tfm.set_normal_feature(specification,'encoding',encoding) -- will go away
+ if trace_loading then
+ logs.report("load afm","stripping encoding prefix from filename %s",afmname)
+ end
+ end
+ end
+ end
+ if foundname ~= "" then
+ specification.filename, specification.format = foundname, "afm"
+ return tfm.read_from_afm(specification)
+ end
+end
+
+function readers.tfm(specification)
+ local fullname, tfmtable = specification.filename or "", nil
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = check_tfm(specification,specification.name .. "." .. forced)
+ end
+ if not tfmtable then
+ tfmtable = check_tfm(specification,specification.name)
+ end
+ else
+ tfmtable = check_tfm(specification,fullname)
+ end
+ return tfmtable
+end
+
+function readers.afm(specification,method)
+ local fullname, tfmtable = specification.filename or "", nil
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = check_afm(specification,specification.name .. "." .. forced)
+ end
+ if not tfmtable then
+ method = method or define.method or "afm or tfm"
+ if method == "tfm" then
+ tfmtable = check_tfm(specification,specification.name)
+ elseif method == "afm" then
+ tfmtable = check_afm(specification,specification.name)
+ elseif method == "tfm or afm" then
+ tfmtable = check_tfm(specification,specification.name) or check_afm(specification,specification.name)
+ else -- method == "afm or tfm" or method == "" then
+ tfmtable = check_afm(specification,specification.name) or check_tfm(specification,specification.name)
+ end
+ end
+ else
+ tfmtable = check_afm(specification,fullname)
+ end
+ return tfmtable
+end
+
+-- maybe some day a set of names
+
+local function check_otf(forced,specification,suffix,what)
+ local name = specification.name
+ if forced then
+ name = file.addsuffix(name,suffix)
+ end
+ local fullname, tfmtable = resolvers.findbinfile(name,suffix) or "", nil -- one shot
+ if fullname == "" then
+ local fb = fonts.names.old_to_new[name]
+ if fb then
+ fullname = resolvers.findbinfile(fb,suffix) or ""
+ end
+ end
+ if fullname == "" then
+ local fb = fonts.names.new_to_old[name]
+ if fb then
+ fullname = resolvers.findbinfile(fb,suffix) or ""
+ end
+ end
+ if fullname ~= "" then
+ specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then
+ tfmtable = tfm.read_from_open_type(specification) -- we need to do it for all matches / todo
+ end
+ return tfmtable
+end
+
+function readers.opentype(specification,suffix,what)
+ local forced = specification.forced or ""
+ if forced == "otf" then
+ return check_otf(true,specification,forced,"opentype")
+ elseif forced == "ttf" or forced == "ttc" or forced == "dfont" then
+ return check_otf(true,specification,forced,"truetype")
+ else
+ return check_otf(false,specification,suffix,what)
+ end
+end
+
+function readers.otf (specification) return readers.opentype(specification,"otf","opentype") end
+function readers.ttf (specification) return readers.opentype(specification,"ttf","truetype") end
+function readers.ttc (specification) return readers.opentype(specification,"ttf","truetype") end -- !!
+function readers.dfont(specification) return readers.opentype(specification,"ttf","truetype") end -- !!
+
+--[[ldx--
+
We need to check for default features. For this we provide
+a helper function.
+--ldx]]--
+
+function define.check(features,defaults) -- nb adapts features !
+ local done = false
+ if features and next(features) then
+ for k,v in next, defaults do
+ if features[k] == nil then
+ features[k], done = v, true
+ end
+ end
+ else
+ features, done = table.fastcopy(defaults), true
+ end
+ return features, done -- done signals a change
+end
+
+--[[ldx--
+
So far the specifyers. Now comes the real definer. Here we cache
+based on id's. Here we also intercept the virtual font handler. Since
+it evolved stepwise I may rewrite this bit (combine code).
+
+In the previously defined reader (the one resulting in a
+table) we cached the (scaled) instances. Here we cache them again, but
+this time based on id. We could combine this in one cache but this does
+not gain much. By the way, passing id's back to in the callback was
+introduced later in the development.
+--ldx]]--
+
+define.last = nil
+
+function define.register(fontdata,id)
+ if fontdata and id then
+ local hash = fontdata.hash
+ if not tfm.internalized[hash] then
+ if trace_defining then
+ logs.report("define font","loading at 2 id %s, hash: %s",id or "?",hash or "?")
+ end
+ fonts.identifiers[id] = fontdata
+ fonts.characters [id] = fontdata.characters
+ fonts.quads [id] = fontdata.parameters.quad
+ -- todo: extra functions, e.g. setdigitwidth etc in list
+ tfm.internalized[hash] = id
+ end
+ end
+end
+
+function define.registered(hash)
+ local id = tfm.internalized[hash]
+ return id, id and fonts.ids[id]
+end
+
+local cache_them = false
+
+function tfm.make(specification)
+ -- currently fonts are scaled while constructing the font, so we
+ -- have to do scaling of commands in the vf at that point using
+ -- e.g. "local scale = g.factor or 1" after all, we need to work
+ -- with copies anyway and scaling needs to be done at some point;
+ -- however, when virtual tricks are used as feature (makes more
+ -- sense) we scale the commands in fonts.tfm.scale (and set the
+ -- factor there)
+ local fvm = define.methods[specification.features.vtf.preset]
+ if fvm then
+ return fvm(specification)
+ else
+ return nil
+ end
+end
+
+function define.read(specification,size,id) -- id can be optional, name can already be table
+ statistics.starttiming(fonts)
+ if type(specification) == "string" then
+ specification = define.analyze(specification,size)
+ end
+ local method = specification.method
+ if method and define.specify[method] then
+ specification = define.specify[method](specification)
+ end
+ specification = define.resolve(specification)
+ local hash = tfm.hash_instance(specification)
+ if cache_them then
+ local fontdata = containers.read(fonts.cache(),hash) -- for tracing purposes
+ end
+ local fontdata = define.registered(hash) -- id
+ if not fontdata then
+ if specification.features.vtf and specification.features.vtf.preset then
+ fontdata = tfm.make(specification)
+ else
+ fontdata = tfm.read(specification)
+ if fontdata then
+ tfm.check_virtual_id(fontdata)
+ end
+ end
+ if cache_them then
+ fontdata = containers.write(fonts.cache(),hash,fontdata) -- for tracing purposes
+ end
+ if fontdata then
+ fontdata.hash = hash
+ fontdata.cache = "no"
+ if id then
+ define.register(fontdata,id)
+ end
+ end
+ end
+ define.last = fontdata or id -- todo ! ! ! ! !
+ if not fontdata then
+ logs.report("define font", "unknown font %s, loading aborted",specification.name)
+ elseif trace_defining and type(fontdata) == "table" then
+ logs.report("define font","using %s font with id %s, name:%s size:%s bytes:%s encoding:%s fullname:%s filename:%s",
+ fontdata.type or "unknown",
+ id or "?",
+ fontdata.name or "?",
+ fontdata.size or "default",
+ fontdata.encodingbytes or "?",
+ fontdata.encodingname or "unicode",
+ fontdata.fullname or "?",
+ file.basename(fontdata.filename or "?"))
+
+ end
+ statistics.stoptiming(fonts)
+ return fontdata
+end
+
+function vf.find(name)
+ name = file.removesuffix(file.basename(name))
+ if tfm.resolve_vf then
+ local format = fonts.logger.format(name)
+ if format == 'tfm' or format == 'ofm' then
+ if trace_defining then
+ logs.report("define font","locating vf for %s",name)
+ end
+ return resolvers.findbinfile(name,"ovf")
+ else
+ if trace_defining then
+ logs.report("define font","vf for %s is already taken care of",name)
+ end
+ return nil -- ""
+ end
+ else
+ if trace_defining then
+ logs.report("define font","locating vf for %s",name)
+ end
+ return resolvers.findbinfile(name,"ovf")
+ end
+end
+
+--[[ldx--
+
We overload both the and readers.
+--ldx]]--
+
+callbacks.register('define_font' , define.read, "definition of fonts (tfmtable preparation)")
+callbacks.register('find_vf_file', vf.find , "locating virtual fonts, insofar needed") -- not that relevant any more
diff --git a/tex/context/base/font-dum.lua b/tex/context/base/font-dum.lua
new file mode 100644
index 000000000..0a9bcd301
--- /dev/null
+++ b/tex/context/base/font-dum.lua
@@ -0,0 +1,301 @@
+if not modules then modules = { } end modules ['font-dum'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+fonts = fonts or { }
+
+-- general
+
+fonts.otf.pack = false -- only makes sense in context
+fonts.tfm.resolve_vf = false -- no sure about this
+fonts.tfm.fontname_mode = "specification" -- somehow latex needs this
+
+-- readers
+
+fonts.tfm.readers = fonts.tfm.readers or { }
+fonts.tfm.readers.sequence = { 'otf', 'ttf', 'tfm' }
+fonts.tfm.readers.afm = nil
+
+-- define
+
+fonts.define = fonts.define or { }
+
+--~ fonts.define.method = "tfm"
+
+fonts.define.specify.colonized_default_lookup = "name"
+
+function fonts.define.get_specification(str)
+ return "", str, "", ":", str
+end
+
+-- logger
+
+fonts.logger = fonts.logger or { }
+
+function fonts.logger.save()
+end
+
+-- names
+--
+-- Watch out, the version number is the same as the one used in
+-- the mtx-fonts.lua function scripts.fonts.names as we use a
+-- simplified font database in the plain solution and by using
+-- a different number we're less dependent on context.
+
+fonts.names = fonts.names or { }
+
+fonts.names.version = 1.001 -- not the same as in context
+fonts.names.basename = "luatex-fonts-names.lua"
+fonts.names.new_to_old = { }
+fonts.names.old_to_new = { }
+
+local data, loaded = nil, false
+
+local fileformats = { "lua", "tex", "other text files" }
+
+function fonts.names.resolve(name,sub)
+ if not loaded then
+ local basename = fonts.names.basename
+ if basename and basename ~= "" then
+ for i=1,#fileformats do
+ local format = fileformats[i]
+ local foundname = resolvers.find_file(basename,format) or ""
+ if foundname ~= "" then
+ data = dofile(foundname)
+ break
+ end
+ end
+ end
+ loaded = true
+ end
+ if type(data) == "table" and data.version == fonts.names.version then
+ local condensed = string.gsub(string.lower(name),"[^%a%d]","")
+ local found = data.mappings and data.mappings[condensed]
+ if found then
+ local fontname, filename, subfont = found[1], found[2], found[3]
+ if subfont then
+ return filename, fontname
+ else
+ return filename, false
+ end
+ else
+ return name, false -- fallback to filename
+ end
+ end
+end
+
+fonts.names.resolvespec = fonts.names.resolve -- only supported in mkiv
+
+-- For the moment we put this (adapted) pseudo feature here.
+
+table.insert(fonts.triggers,"itlc")
+
+local function itlc(tfmdata,value)
+ if value then
+ -- the magic 40 and it formula come from Dohyun Kim
+ local metadata = tfmdata.shared.otfdata.metadata
+ if metadata then
+ local italicangle = metadata.italicangle
+ if italicangle and italicangle ~= 0 then
+ local uwidth = (metadata.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
+ end
+ end
+ tfmdata.has_italic = true
+ end
+ end
+ end
+end
+
+fonts.initializers.base.otf.itlc = itlc
+fonts.initializers.node.otf.itlc = itlc
+
+-- slant and extend
+
+function fonts.initializers.common.slant(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ elseif value > 1 then
+ value = 1
+ elseif value < -1 then
+ value = -1
+ end
+ tfmdata.slant_factor = value
+end
+
+function fonts.initializers.common.extend(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ elseif value > 10 then
+ value = 10
+ elseif value < -10 then
+ value = -10
+ end
+ tfmdata.extend_factor = value
+end
+
+table.insert(fonts.triggers,"slant")
+table.insert(fonts.triggers,"extend")
+
+fonts.initializers.base.otf.slant = fonts.initializers.common.slant
+fonts.initializers.node.otf.slant = fonts.initializers.common.slant
+fonts.initializers.base.otf.extend = fonts.initializers.common.extend
+fonts.initializers.node.otf.extend = fonts.initializers.common.extend
+
+-- expansion and protrusion
+
+fonts.protrusions = fonts.protrusions or { }
+fonts.protrusions.setups = fonts.protrusions.setups or { }
+
+local setups = fonts.protrusions.setups
+
+function fonts.initializers.common.protrusion(tfmdata,value)
+ if value then
+ local setup = setups[value]
+ if setup then
+ local factor, left, right = setup.factor or 1, setup.left or 1, setup.right or 1
+ local emwidth = tfmdata.parameters.quad
+ tfmdata.auto_protrude = true
+ for i, chr in next, tfmdata.characters do
+ local v, pl, pr = setup[i], nil, nil
+ if v then
+ pl, pr = v[1], v[2]
+ end
+ if pl and pl ~= 0 then chr.left_protruding = left *pl*factor end
+ if pr and pr ~= 0 then chr.right_protruding = right*pr*factor end
+ end
+ end
+ end
+end
+
+fonts.expansions = fonts.expansions or { }
+fonts.expansions.setups = fonts.expansions.setups or { }
+
+local setups = fonts.expansions.setups
+
+function fonts.initializers.common.expansion(tfmdata,value)
+ if value then
+ local setup = setups[value]
+ if setup then
+ local stretch, shrink, step, factor = setup.stretch or 0, setup.shrink or 0, setup.step or 0, setup.factor or 1
+ tfmdata.stretch, tfmdata.shrink, tfmdata.step, tfmdata.auto_expand = stretch * 10, shrink * 10, step * 10, true
+ for i, chr in next, tfmdata.characters do
+ local v = setup[i]
+ if v and v ~= 0 then
+ chr.expansion_factor = v*factor
+ else -- can be option
+ chr.expansion_factor = factor
+ end
+ end
+ end
+ end
+end
+
+table.insert(fonts.manipulators,"protrusion")
+table.insert(fonts.manipulators,"expansion")
+
+fonts.initializers.base.otf.protrusion = fonts.initializers.common.protrusion
+fonts.initializers.node.otf.protrusion = fonts.initializers.common.protrusion
+fonts.initializers.base.otf.expansion = fonts.initializers.common.expansion
+fonts.initializers.node.otf.expansion = fonts.initializers.common.expansion
+
+-- left over
+
+function fonts.register_message()
+end
+
+-- example vectors
+
+local byte = string.byte
+
+fonts.expansions.setups['default'] = {
+
+ stretch = 2, shrink = 2, step = .5, factor = 1,
+
+ [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7,
+ [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7,
+ [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7,
+ [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7,
+ [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7,
+ [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7,
+ [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7,
+ [byte('w')] = 0.7, [byte('z')] = 0.7,
+ [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7,
+}
+
+fonts.protrusions.setups['default'] = {
+
+ factor = 1, left = 1, right = 1,
+
+ [0x002C] = { 0, 1 }, -- comma
+ [0x002E] = { 0, 1 }, -- period
+ [0x003A] = { 0, 1 }, -- colon
+ [0x003B] = { 0, 1 }, -- semicolon
+ [0x002D] = { 0, 1 }, -- hyphen
+ [0x2013] = { 0, 0.50 }, -- endash
+ [0x2014] = { 0, 0.33 }, -- emdash
+ [0x3001] = { 0, 1 }, -- ideographic comma 、
+ [0x3002] = { 0, 1 }, -- ideographic full stop 。
+ [0x060C] = { 0, 1 }, -- arabic comma ،
+ [0x061B] = { 0, 1 }, -- arabic semicolon ؛
+ [0x06D4] = { 0, 1 }, -- arabic full stop ۔
+
+}
+
+-- normalizer
+
+fonts.otf.meanings = fonts.otf.meanings or { }
+
+fonts.otf.meanings.normalize = fonts.otf.meanings.normalize or function(t)
+ if t.rand then
+ t.rand = "random"
+ end
+end
+
+-- bonus
+
+function fonts.otf.name_to_slot(name)
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata and tfmdata.shared then
+ local otfdata = tfmdata.shared.otfdata
+ local unicode = otfdata.luatex.unicodes[name]
+ return unicode and (type(unicode) == "number" and unicode or unicode[1])
+ end
+end
+
+function fonts.otf.char(n)
+ if type(n) == "string" then
+ n = fonts.otf.name_to_slot(n)
+ end
+ if type(n) == "number" then
+ tex.sprint("\\char" .. n)
+ end
+end
+
+-- another one:
+
+fonts.strippables = table.tohash {
+ 0x000AD, 0x017B4, 0x017B5, 0x0200B, 0x0200C, 0x0200D, 0x0200E, 0x0200F, 0x0202A, 0x0202B,
+ 0x0202C, 0x0202D, 0x0202E, 0x02060, 0x02061, 0x02062, 0x02063, 0x0206A, 0x0206B, 0x0206C,
+ 0x0206D, 0x0206E, 0x0206F, 0x0FEFF, 0x1D173, 0x1D174, 0x1D175, 0x1D176, 0x1D177, 0x1D178,
+ 0x1D179, 0x1D17A, 0xE0001, 0xE0020, 0xE0021, 0xE0022, 0xE0023, 0xE0024, 0xE0025, 0xE0026,
+ 0xE0027, 0xE0028, 0xE0029, 0xE002A, 0xE002B, 0xE002C, 0xE002D, 0xE002E, 0xE002F, 0xE0030,
+ 0xE0031, 0xE0032, 0xE0033, 0xE0034, 0xE0035, 0xE0036, 0xE0037, 0xE0038, 0xE0039, 0xE003A,
+ 0xE003B, 0xE003C, 0xE003D, 0xE003E, 0xE003F, 0xE0040, 0xE0041, 0xE0042, 0xE0043, 0xE0044,
+ 0xE0045, 0xE0046, 0xE0047, 0xE0048, 0xE0049, 0xE004A, 0xE004B, 0xE004C, 0xE004D, 0xE004E,
+ 0xE004F, 0xE0050, 0xE0051, 0xE0052, 0xE0053, 0xE0054, 0xE0055, 0xE0056, 0xE0057, 0xE0058,
+ 0xE0059, 0xE005A, 0xE005B, 0xE005C, 0xE005D, 0xE005E, 0xE005F, 0xE0060, 0xE0061, 0xE0062,
+ 0xE0063, 0xE0064, 0xE0065, 0xE0066, 0xE0067, 0xE0068, 0xE0069, 0xE006A, 0xE006B, 0xE006C,
+ 0xE006D, 0xE006E, 0xE006F, 0xE0070, 0xE0071, 0xE0072, 0xE0073, 0xE0074, 0xE0075, 0xE0076,
+ 0xE0077, 0xE0078, 0xE0079, 0xE007A, 0xE007B, 0xE007C, 0xE007D, 0xE007E, 0xE007F,
+}
+
diff --git a/tex/context/base/font-enc.lua b/tex/context/base/font-enc.lua
new file mode 100644
index 000000000..874f7c3f4
--- /dev/null
+++ b/tex/context/base/font-enc.lua
@@ -0,0 +1,122 @@
+if not modules then modules = { } end modules ['font-enc'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local match, gmatch, gsub = string.match, string.gmatch, string.gsub
+
+--[[ldx--
+
Because encodings are going to disappear, we don't bother defining
+them in tables. But we may do so some day, for consistency.
Beware! The generic encoding files don't always apply to the ones that
+ship with fonts. This has to do with the fact that names follow (slightly)
+different standards. However, the fonts where this applies to (for instance
+Latin Modern or Gyre) come in OpenType variants too, so these
+will be used.
+--ldx]]--
+
+function fonts.enc.load(filename)
+ local name = file.removesuffix(filename)
+ local data = containers.read(fonts.enc.cache(),name)
+ if data then
+ return data
+ end
+ if name == "unicode" then
+ data = fonts.enc.make_unicode_vector() -- special case, no tex file for this
+ end
+ if data then
+ return data
+ end
+ local vector, tag, hash, unicodes = { }, "", { }, { }
+ local foundname = resolvers.find_file(filename,'enc')
+ if foundname and foundname ~= "" then
+ local ok, encoding, size = resolvers.loadbinfile(foundname)
+ if ok and encoding then
+ local enccodes = characters.enccodes
+ encoding = gsub(encoding,"%%(.-)\n","")
+ local tag, vec = match(encoding,"/(%w+)%s*%[(.*)%]%s*def")
+ local i = 0
+ for ch in gmatch(vec,"/([%a%d%.]+)") do
+ if ch ~= ".notdef" then
+ vector[i] = ch
+ if not hash[ch] then
+ hash[ch] = i
+ else
+ -- duplicate, play safe for tex ligs and take first
+ end
+ if enccodes[ch] then
+ unicodes[enccodes[ch]] = i
+ end
+ end
+ i = i + 1
+ end
+ end
+ end
+ local data = {
+ name=name,
+ tag=tag,
+ vector=vector,
+ hash=hash,
+ unicodes=unicodes
+ }
+ return containers.write(fonts.enc.cache(), name, data)
+end
+
+--[[ldx--
+
There is no unicode encoding but for practical purposed we define
+one.
+--ldx]]--
+
+-- maybe make this a function:
+
+function fonts.enc.make_unicode_vector()
+ local vector, hash = { }, { }
+ for code, v in next, characters.data do
+ local name = v.adobename
+ if name then
+ vector[code], hash[name] = name, code
+ else
+ vector[code] = '.notdef'
+ end
+ end
+ for name, code in next, characters.synonyms do
+ vector[code], hash[name] = name, code
+ end
+ return containers.write(fonts.enc.cache(), 'unicode', { name='unicode', tag='unicode', vector=vector, hash=hash })
+end
diff --git a/tex/context/base/font-enh.lua b/tex/context/base/font-enh.lua
new file mode 100644
index 000000000..fc70c04c5
--- /dev/null
+++ b/tex/context/base/font-enh.lua
@@ -0,0 +1,201 @@
+if not modules then modules = { } end modules ['font-enh'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, match = next, string.match
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+-- tfmdata has also fast access to indices and unicodes
+-- to be checked: otf -> tfm -> tfmscaled
+--
+-- watch out: no negative depths and negative eights permitted in regular fonts
+
+--[[ldx--
+
The next function encapsulates the standard loader as
+supplied by .
+--ldx]]--
+
+-- auto complete font with missing composed characters
+
+table.insert(fonts.manipulators,"compose")
+
+function fonts.initializers.common.compose(tfmdata,value)
+ if value then
+ fonts.vf.aux.compose_characters(tfmdata)
+ end
+end
+
+-- tfm features, experimental
+
+tfm.features = tfm.features or { }
+tfm.features.list = tfm.features.list or { }
+tfm.features.default = tfm.features.default or { }
+
+function tfm.enhance(tfmdata,specification)
+ -- we don't really share tfm data because we always reload
+ -- but this is more in sycn with afm and such
+ local features = (specification.features and specification.features.normal ) or { }
+ tfmdata.shared = tfmdata.shared or { }
+ tfmdata.shared.features = features
+ -- tfmdata.shared.tfmdata = tfmdata -- circular
+ tfmdata.filename = specification.name
+ if not features.encoding then
+ local name, size = specification.name, specification.size
+ local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
+ if filename and encoding and fonts.enc.known[encoding] then
+ features.encoding = encoding
+ end
+ end
+ tfm.set_features(tfmdata)
+end
+
+function tfm.set_features(tfmdata)
+ -- todo: no local functions
+ local shared = tfmdata.shared
+-- local tfmdata = shared.tfmdata
+ local features = shared.features
+ if features and next(features) then
+ local mode = tfmdata.mode or fonts.mode
+ local fi = fonts.initializers[mode]
+ if fi and fi.tfm then
+ local function initialize(list) -- using tex lig and kerning
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ local value = features[f]
+ if value and fi.tfm[f] then -- brr
+ if tfm.trace_features then
+ logs.report("define font","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown')
+ end
+ fi.tfm[f](tfmdata,value)
+ mode = tfmdata.mode or fonts.mode
+ fi = fonts.initializers[mode]
+ end
+ end
+ end
+ end
+ initialize(fonts.triggers)
+ initialize(tfm.features.list)
+ initialize(fonts.manipulators)
+ end
+ local fm = fonts.methods[mode]
+ if fm and fm.tfm then
+ local function register(list) -- node manipulations
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ if features[f] and fm.tfm[f] then -- brr
+ if not shared.processors then -- maybe also predefine
+ shared.processors = { fm.tfm[f] }
+ else
+ shared.processors[#shared.processors+1] = fm.tfm[f]
+ end
+ end
+ end
+ end
+ end
+ register(tfm.features.list)
+ end
+ end
+end
+
+function tfm.features.register(name,default)
+ tfm.features.list[#tfm.features.list+1] = name
+ tfm.features.default[name] = default
+end
+
+function tfm.reencode(tfmdata,encoding)
+ if encoding and fonts.enc.known[encoding] then
+ local data = fonts.enc.load(encoding)
+ if data then
+ local characters, original, vector = tfmdata.characters, { }, data.vector
+ tfmdata.encoding = encoding -- not needed
+ for k, v in next, characters do
+ v.name, v.index, original[k] = vector[k], k, v
+ end
+ for k,v in next, data.unicodes do
+ if k ~= v then
+ if trace_defining then
+ logs.report("define font","reencoding U+%04X to U+%04X",k,v)
+ end
+ characters[k] = original[v]
+ end
+ end
+ end
+ end
+end
+
+tfm.features.register('reencode')
+
+fonts.initializers.base.tfm.reencode = tfm.reencode
+fonts.initializers.node.tfm.reencode = tfm.reencode
+
+fonts.enc = fonts.enc or { }
+fonts.enc.remappings = fonts.enc.remappings or { }
+
+function tfm.remap(tfmdata,remapping)
+ local vector = remapping and fonts.enc.remappings[remapping]
+ if vector then
+ local characters, original = tfmdata.characters, { }
+ for k, v in next, characters do
+ original[k], characters[k] = v, nil
+ end
+ for k,v in next, vector do
+ if k ~= v then
+ if trace_defining then
+ logs.report("define font","remapping U+%04X to U+%04X",k,v)
+ end
+ local c = original[k]
+ characters[v] = c
+ c.index = k
+ end
+ end
+ tfmdata.encodingbytes = 2
+ tfmdata.format = 'type1'
+ end
+end
+
+tfm.features.register('remap')
+
+fonts.initializers.base.tfm.remap = tfm.remap
+fonts.initializers.node.tfm.remap = tfm.remap
+
+--~ obsolete
+--~
+--~ function tfm.enhance(tfmdata,specification)
+--~ local name, size = specification.name, specification.size
+--~ local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
+--~ if filename and encoding and fonts.enc.known[encoding] then
+--~ local data = fonts.enc.load(encoding)
+--~ if data then
+--~ local characters = tfmdata.characters
+--~ tfmdata.encoding = encoding
+--~ local vector = data.vector
+--~ local original = { }
+--~ for k, v in next, characters do
+--~ v.name = vector[k]
+--~ v.index = k
+--~ original[k] = v
+--~ end
+--~ for k,v in next, data.unicodes do
+--~ if k ~= v then
+--~ if trace_defining then
+--~ logs.report("define font","mapping %s onto %s",k,v)
+--~ end
+--~ characters[k] = original[v]
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
diff --git a/tex/context/base/font-ext.lua b/tex/context/base/font-ext.lua
new file mode 100644
index 000000000..05bdaf2fc
--- /dev/null
+++ b/tex/context/base/font-ext.lua
@@ -0,0 +1,623 @@
+if not modules then modules = { } end modules ['font-ext'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv and hand-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+local next, type, byte = next, type, string.byte
+local gmatch, concat = string.gmatch, table.concat
+local utfchar = utf.char
+
+local trace_protrusion = false trackers.register("fonts.protrusion", function(v) trace_protrusion = v end)
+local trace_expansion = false trackers.register("fonts.expansion", function(v) trace_expansion = v end)
+
+commands = commands or { }
+
+--[[ldx--
+
When we implement functions that deal with features, most of them
+will depend of the font format. Here we define the few that are kind
+of neutral.
+--ldx]]--
+
+fonts.triggers = fonts.triggers or { }
+fonts.initializers = fonts.initializers or { }
+fonts.methods = fonts.methods or { }
+fonts.initializers.common = fonts.initializers.common or { }
+
+local initializers = fonts.initializers
+local methods = fonts.methods
+
+--[[ldx--
+
This feature will remove inter-digit kerns.
+--ldx]]--
+
+table.insert(fonts.triggers,"equaldigits")
+
+function initializers.common.equaldigits(tfmdata,value)
+ if value then
+ local chr = tfmdata.characters
+ for i = utfbyte('0'), utfbyte('9') do
+ local c = chr[i]
+ if c then
+ c.kerns = nil
+ end
+ end
+ end
+end
+
+--[[ldx--
+
This feature will give all glyphs an equal height and/or depth. Valid
+values are none, height, depth and
+both.
+--ldx]]--
+
+table.insert(fonts.triggers,"lineheight")
+
+function initializers.common.lineheight(tfmdata,value)
+ if value and type(value) == "string" then
+ if value == "none" then
+ for _,v in next, tfmdata.characters do
+ v.height, v.depth = 0, 0
+ end
+ else
+ local ascender, descender = tfmdata.ascender, tfmdata.descender
+ if ascender and descender then
+ local ht, dp = ascender or 0, descender or 0
+ if value == "height" then
+ dp = 0
+ elseif value == "depth" then
+ ht = 0
+ end
+ if ht > 0 then
+ if dp > 0 then
+ for _,v in next, tfmdata.characters do
+ v.height, v.depth = ht, dp
+ end
+ else
+ for _,v in next, tfmdata.characters do
+ v.height = ht
+ end
+ end
+ elseif dp > 0 then
+ for _,v in next, tfmdata.characters do
+ v.depth = dp
+ end
+ end
+ end
+ end
+ end
+end
+
+-- -- -- -- -- --
+-- shared
+-- -- -- -- -- --
+
+local function get_class_and_vector(tfmdata,value,where) -- "expansions"
+ local g_where = tfmdata.goodies and tfmdata.goodies[where]
+ local f_where = fonts[where]
+ local g_classes = g_where and g_where.classes
+ local class = g_where and g_where[value] or f_where.classes[value]
+ if class then
+ local class_vector = class.vector
+ local g_vectors = g_where and g_where.vectors
+ local vector = g_vectors and g_vectors[class_vector] or f_where.vectors[class_vector]
+ return class, vector
+ end
+end
+
+-- -- -- -- -- --
+-- expansion (hz)
+-- -- -- -- -- --
+
+fonts.expansions = fonts.expansions or { }
+fonts.expansions.classes = fonts.expansions.classes or { }
+fonts.expansions.vectors = fonts.expansions.vectors or { }
+
+local expansions = fonts.expansions
+local classes = fonts.expansions.classes
+local vectors = fonts.expansions.vectors
+
+-- beware, pdftex itself uses percentages * 10
+
+classes.preset = { stretch = 2, shrink = 2, step = .5, factor = 1 }
+
+function commands.setupfontexpansion(class,settings)
+ aux.getparameters(classes,class,'preset',settings)
+end
+
+classes['quality'] = {
+ stretch = 2, shrink = 2, step = .5, vector = 'default', factor = 1
+}
+
+vectors['default'] = {
+ [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7,
+ [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7,
+ [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7,
+ [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7,
+ [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7,
+ [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7,
+ [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7,
+ [byte('w')] = 0.7, [byte('z')] = 0.7,
+ [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7,
+}
+
+vectors['quality'] = vectors['default'] -- metatable ?
+
+--~ function table.locator(...)
+--~ local k = { ... }
+--~ return function(t)
+--~ for i=1,#k do
+--~ t = t[k[i]]
+--~ if not k then
+--~ return false
+--~ end
+--~ end
+--~ return t
+--~ end
+--~ end
+
+--~ local locate = table.locator { "goodies", "expansions" }
+
+function initializers.common.expansion(tfmdata,value)
+ if value then
+ local class, vector = get_class_and_vector(tfmdata,value,"expansions")
+ if class then
+ if vector then
+ local stretch, shrink, step, factor = class.stretch or 0, class.shrink or 0, class.step or 0, class.factor or 1
+ if trace_expansion then
+ logs.report("fonts","set expansion class %s, vector: %s, factor: %s, stretch: %s, shrink: %s, step: %s",value,class_vector,factor,stretch,shrink,step)
+ end
+ tfmdata.stretch, tfmdata.shrink, tfmdata.step, tfmdata.auto_expand = stretch * 10, shrink * 10, step * 10, true
+ local data = characters and characters.data
+ for i, chr in next, tfmdata.characters do
+ local v = vector[i]
+ if data and not v then -- we could move the data test outside (needed for plain)
+ local d = data[i]
+ if d then
+ local s = d.shcode
+ if not s then
+ -- sorry
+ elseif type(s) == "table" then
+ v = ((vector[s[1]] or 0) + (vector[s[#s]] or 0)) / 2
+ else
+ v = vector[s] or 0
+ end
+ end
+ end
+ if v and v ~= 0 then
+ chr.expansion_factor = v*factor
+ else -- can be option
+ chr.expansion_factor = factor
+ end
+ end
+ elseif trace_expansion then
+ logs.report("fonts","unknown expansion vector '%s' in class '%s",class_vector,value)
+ end
+ elseif trace_expansion then
+ logs.report("fonts","unknown expansion class '%s'",value)
+ end
+ end
+end
+
+table.insert(fonts.manipulators,"expansion")
+
+initializers.base.otf.expansion = initializers.common.expansion
+initializers.node.otf.expansion = initializers.common.expansion
+
+initializers.base.afm.expansion = initializers.common.expansion
+initializers.node.afm.expansion = initializers.common.expansion
+
+fonts.goodies.register("expansions", function(...) return fonts.goodies.report("expansions", trace_expansion, ...) end)
+
+-- -- -- -- -- --
+-- protrusion
+-- -- -- -- -- --
+
+fonts.protrusions = fonts.protrusions or { }
+fonts.protrusions.classes = fonts.protrusions.classes or { }
+fonts.protrusions.vectors = fonts.protrusions.vectors or { }
+
+local protrusions = fonts.protrusions
+local classes = fonts.protrusions.classes
+local vectors = fonts.protrusions.vectors
+
+-- the values need to be revisioned
+
+classes.preset = { factor = 1, left = 1, right = 1 }
+
+function commands.setupfontprotrusion(class,settings)
+ aux.getparameters(classes,class,'preset',settings)
+end
+
+classes['pure'] = {
+ vector = 'pure', factor = 1
+}
+classes['punctuation'] = {
+ vector = 'punctuation', factor = 1
+}
+classes['alpha'] = {
+ vector = 'alpha', factor = 1
+}
+classes['quality'] = {
+ vector = 'quality', factor = 1
+}
+
+vectors['pure'] = {
+
+ [0x002C] = { 0, 1 }, -- comma
+ [0x002E] = { 0, 1 }, -- period
+ [0x003A] = { 0, 1 }, -- colon
+ [0x003B] = { 0, 1 }, -- semicolon
+ [0x002D] = { 0, 1 }, -- hyphen
+ [0x2013] = { 0, 0.50 }, -- endash
+ [0x2014] = { 0, 0.33 }, -- emdash
+ [0x3001] = { 0, 1 }, -- ideographic comma 、
+ [0x3002] = { 0, 1 }, -- ideographic full stop 。
+ [0x060C] = { 0, 1 }, -- arabic comma ،
+ [0x061B] = { 0, 1 }, -- arabic semicolon ؛
+ [0x06D4] = { 0, 1 }, -- arabic full stop ۔
+
+}
+
+vectors['punctuation'] = {
+
+ [0x003F] = { 0, 0.20 }, -- ?
+ [0x00BF] = { 0, 0.20 }, -- ¿
+ [0x0021] = { 0, 0.20 }, -- !
+ [0x00A1] = { 0, 0.20 }, -- ¡
+ [0x0028] = { 0.05, 0 }, -- (
+ [0x0029] = { 0, 0.05 }, -- )
+ [0x005B] = { 0.05, 0 }, -- [
+ [0x005D] = { 0, 0.05 }, -- ]
+ [0x002C] = { 0, 0.70 }, -- comma
+ [0x002E] = { 0, 0.70 }, -- period
+ [0x003A] = { 0, 0.50 }, -- colon
+ [0x003B] = { 0, 0.50 }, -- semicolon
+ [0x002D] = { 0, 0.70 }, -- hyphen
+ [0x2013] = { 0, 0.30 }, -- endash
+ [0x2014] = { 0, 0.20 }, -- emdash
+ [0x060C] = { 0, 0.70 }, -- arabic comma
+ [0x061B] = { 0, 0.50 }, -- arabic semicolon
+ [0x06D4] = { 0, 0.70 }, -- arabic full stop
+ [0x061F] = { 0, 0.20 }, -- ؟
+
+ -- todo: left and right quotes: .5 double, .7 single
+
+ [0x2039] = { 0.70, 0.70 }, -- left single guillemet ‹
+ [0x203A] = { 0.70, 0.70 }, -- right single guillemet ›
+ [0x00AB] = { 0.50, 0.50 }, -- left guillemet «
+ [0x00BB] = { 0.50, 0.50 }, -- right guillemet »
+
+ [0x2018] = { 0.70, 0.70 }, -- left single quotation mark ‘
+ [0x2019] = { 0, 0.70 }, -- right single quotation mark ’
+ [0x201A] = { 0.70, 0 }, -- single low-9 quotation mark ,
+ [0x201B] = { 0.70, 0 }, -- single high-reversed-9 quotation mark ‛
+ [0x201C] = { 0.50, 0.50 }, -- left double quotation mark “
+ [0x201D] = { 0, 0.50 }, -- right double quotation mark ”
+ [0x201E] = { 0.50, 0 }, -- double low-9 quotation mark „
+ [0x201F] = { 0.50, 0 }, -- double high-reversed-9 quotation mark ‟
+
+}
+
+vectors['alpha'] = {
+
+ [byte("A")] = { .05, .05 },
+ [byte("F")] = { 0, .05 },
+ [byte("J")] = { .05, 0 },
+ [byte("K")] = { 0, .05 },
+ [byte("L")] = { 0, .05 },
+ [byte("T")] = { .05, .05 },
+ [byte("V")] = { .05, .05 },
+ [byte("W")] = { .05, .05 },
+ [byte("X")] = { .05, .05 },
+ [byte("Y")] = { .05, .05 },
+
+ [byte("k")] = { 0, .05 },
+ [byte("r")] = { 0, .05 },
+ [byte("t")] = { 0, .05 },
+ [byte("v")] = { .05, .05 },
+ [byte("w")] = { .05, .05 },
+ [byte("x")] = { .05, .05 },
+ [byte("y")] = { .05, .05 },
+
+}
+
+vectors['quality'] = table.merge( {},
+ vectors['punctuation'],
+ vectors['alpha']
+)
+
+-- As this is experimental code, users should not depend on it. The
+-- implications are still discussed on the ConTeXt Dev List and we're
+-- not sure yet what exactly the spec is (the next code is tested with
+-- a gyre font patched by / fea file made by Khaled Hosny). The double
+-- trick should not be needed it proper hanging punctuation is used in
+-- which case values < 1 can be used.
+--
+-- preferred (in context, usine vectors):
+--
+-- \definefontfeature[whatever][default][mode=node,protrusion=quality]
+--
+-- using lfbd and rtbd, with possibibility to enable only one side :
+--
+-- \definefontfeature[whocares][default][mode=node,protrusion=yes, opbd=yes,script=latn]
+-- \definefontfeature[whocares][default][mode=node,protrusion=right,opbd=yes,script=latn]
+--
+-- idem, using multiplier
+--
+-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn]
+-- \definefontfeature[whocares][default][mode=node,protrusion=double,opbd=yes,script=latn]
+--
+-- idem, using named feature file (less frozen):
+--
+-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn,featurefile=texgyrepagella-regularxx.fea]
+
+classes['double'] = { -- for testing opbd
+ factor = 2, left = 1, right = 1,
+}
+
+local function map_opbd_onto_protrusion(tfmdata,value,opbd)
+ local characters, descriptions = tfmdata.characters, tfmdata.descriptions
+ local otfdata = tfmdata.shared.otfdata
+ local singles = otfdata.shared.featuredata.gpos_single
+ local script, language = tfmdata.script, tfmdata.language
+ local done, factor, left, right = false, 1, 1, 1
+ local class = classes[value]
+ if class then
+ factor = class.factor or 1
+ left = class.left or 1
+ right = class.right or 1
+ else
+ factor = tonumber(value) or 1
+ end
+ if opbd ~= "right" then
+ local validlookups, lookuplist = fonts.otf.collect_lookups(otfdata,"lfbd",script,language)
+ if validlookups then
+ for i=1,#lookuplist do
+ local lookup = lookuplist[i]
+ local data = singles[lookup]
+ if data then
+ if trace_protrusion then
+ logs.report("fonts","set left protrusion using lfbd lookup '%s'",lookup)
+ end
+ for k, v in next, data do
+ -- local p = - v[3] / descriptions[k].width-- or 1 ~= 0 too but the same
+ local p = - (v[1] / 1000) * factor * left
+ characters[k].left_protruding = p
+ if trace_protrusion then
+ logs.report("opbd","lfbd -> %s -> 0x%05X (%s) -> %0.03f (%s)",lookup,k,utfchar(k),p,concat(v," "))
+ end
+ end
+ done = true
+ end
+ end
+ end
+ end
+ if opbd ~= "left" then
+ local validlookups, lookuplist = fonts.otf.collect_lookups(otfdata,"rtbd",script,language)
+ if validlookups then
+ for i=1,#lookuplist do
+ local lookup = lookuplist[i]
+ local data = singles[lookup]
+ if data then
+ if trace_protrusion then
+ logs.report("fonts","set right protrusion using rtbd lookup '%s'",lookup)
+ end
+ for k, v in next, data do
+ -- local p = v[3] / descriptions[k].width -- or 3
+ local p = (v[1] / 1000) * factor * right
+ characters[k].right_protruding = p
+ if trace_protrusion then
+ logs.report("opbd","rtbd -> %s -> 0x%05X (%s) -> %0.03f (%s)",lookup,k,utfchar(k),p,concat(v," "))
+ end
+ end
+ end
+ done = true
+ end
+ end
+ end
+ tfmdata.auto_protrude = done
+end
+
+-- The opbd test is just there because it was discussed on the
+-- context development list. However, the mentioned fxlbi.otf font
+-- only has some kerns for digits. So, consider this feature not
+-- supported till we have a proper test font.
+
+function initializers.common.protrusion(tfmdata,value)
+ if value then
+ local opbd = tfmdata.shared.features.opbd
+ if opbd then
+ -- possible values: left right both yes no (experimental)
+ map_opbd_onto_protrusion(tfmdata,value,opbd)
+ else
+ local class, vector = get_class_and_vector(tfmdata,value,"protrusions")
+ if class then
+ if vector then
+ local factor = class.factor or 1
+ local left = class.left or 1
+ local right = class.right or 1
+ if trace_protrusion then
+ logs.report("fonts","set protrusion class %s, vector: %s, factor: %s, left: %s, right: %s",value,class_vector,factor,left,right)
+ end
+ local data = characters.data
+ local emwidth = tfmdata.parameters.quad
+ tfmdata.auto_protrude = true
+ for i, chr in next, tfmdata.characters do
+ local v, pl, pr = vector[i], nil, nil
+ if v then
+ pl, pr = v[1], v[2]
+ else
+ local d = data[i]
+ if d then
+ local s = d.shcode
+ if not s then
+ -- sorry
+ elseif type(s) == "table" then
+ local vl, vr = vector[s[1]], vector[s[#s]]
+ if vl then pl = vl[1] end
+ if vr then pr = vr[2] end
+ else
+ v = vector[s]
+ if v then
+ pl, pr = v[1], v[2]
+ end
+ end
+ end
+ end
+ if pl and pl ~= 0 then
+ chr.left_protruding = left *pl*factor
+ end
+ if pr and pr ~= 0 then
+ chr.right_protruding = right*pr*factor
+ end
+ end
+ elseif trace_protrusion then
+ logs.report("fonts","unknown protrusion vector '%s' in class '%s",class_vector,value)
+ end
+ elseif trace_protrusion then
+ logs.report("fonts","unknown protrusion class '%s'",value)
+ end
+ end
+ end
+end
+
+table.insert(fonts.manipulators,"protrusion")
+
+initializers.base.otf.protrusion = initializers.common.protrusion
+initializers.node.otf.protrusion = initializers.common.protrusion
+
+initializers.base.afm.protrusion = initializers.common.protrusion
+initializers.node.afm.protrusion = initializers.common.protrusion
+
+fonts.goodies.register("protrusions", function(...) return fonts.goodies.report("protrusions", trace_protrusion, ...) end)
+
+-- -- --
+
+function initializers.common.nostackmath(tfmdata,value)
+ tfmdata.ignore_stack_math = value
+end
+
+table.insert(fonts.manipulators,"nostackmath")
+
+initializers.base.otf.nostackmath = initializers.common.nostackmath
+initializers.node.otf.nostackmath = initializers.common.nostackmath
+
+table.insert(fonts.triggers,"itlc")
+
+function initializers.common.itlc(tfmdata,value)
+ if value then
+ -- the magic 40 and it formula come from Dohyun Kim
+ local fontdata = tfmdata.shared.otfdata or tfmdata.shared.afmdata
+ local metadata = fontdata and fontdata.metadata
+ if metadata then
+ local italicangle = metadata.italicangle
+ if italicangle and italicangle ~= 0 then
+ local uwidth = (metadata.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
+ end
+ end
+ tfmdata.has_italic = true
+ end
+ end
+ end
+end
+
+initializers.base.otf.itlc = initializers.common.itlc
+initializers.node.otf.itlc = initializers.common.itlc
+
+initializers.base.afm.itlc = initializers.common.itlc
+initializers.node.afm.itlc = initializers.common.itlc
+
+-- slanting
+
+table.insert(fonts.triggers,"slant")
+
+function initializers.common.slant(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ elseif value > 1 then
+ value = 1
+ elseif value < -1 then
+ value = -1
+ end
+ tfmdata.slant_factor = value
+end
+
+initializers.base.otf.slant = initializers.common.slant
+initializers.node.otf.slant = initializers.common.slant
+
+initializers.base.afm.slant = initializers.common.slant
+initializers.node.afm.slant = initializers.common.slant
+
+table.insert(fonts.triggers,"extend")
+
+function initializers.common.extend(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ elseif value > 10 then
+ value = 10
+ elseif value < -10 then
+ value = -10
+ end
+ tfmdata.extend_factor = value
+end
+
+initializers.base.otf.extend = initializers.common.extend
+initializers.node.otf.extend = initializers.common.extend
+
+initializers.base.afm.extend = initializers.common.extend
+initializers.node.afm.extend = initializers.common.extend
+
+-- historic stuff, move from font-ota
+
+local delete_node = nodes.delete
+local glyph = node.id("glyph")
+local fontdata = fonts.ids
+
+fonts.strippables = fonts.strippables or { -- just a placeholder
+ [0x200C] = true, -- zwnj
+ [0x200D] = true, -- zwj
+}
+
+local strippables = fonts.strippables
+
+local function processformatters(head,font)
+ local how = fontdata[font].shared.features.formatters
+ if how == nil or how == "strip" then -- nil when forced
+ local current, done = head, false
+ while current do
+ if current.id == glyph and current.subtype<256 and current.font == font then
+ local char = current.char
+ if strippables[char] then
+ head, current = delete_node(head,current)
+ done = true
+ else
+ current = current.next
+ end
+ else
+ current = current.next
+ end
+ end
+ return head, done
+ else
+ return head, false
+ end
+end
+
+methods.node.otf.formatters = processformatters
+methods.base.otf.formatters = processformatters
+
+fonts.otf.tables.features['formatters'] = 'Hide Formatting Characters'
+
+fonts.otf.features.register("formatters")
+
+table.insert(fonts.manipulators,"formatters") -- at end
diff --git a/tex/context/base/font-fbk.lua b/tex/context/base/font-fbk.lua
new file mode 100644
index 000000000..1ad1cc781
--- /dev/null
+++ b/tex/context/base/font-fbk.lua
@@ -0,0 +1,316 @@
+if not modules then modules = { } end modules ['font-fbk'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local cos, tan, rad, format = math.cos, math.tan, math.rad, string.format
+
+local trace_combining = false trackers.register("fonts.combining", function(v) trace_combining = v end)
+
+--[[ldx--
+
This is very experimental code!
+--ldx]]--
+
+fonts.fallbacks = fonts.fallbacks or { }
+
+local vf = fonts.vf
+local tfm = fonts.tfm
+
+vf.aux.combine.commands["enable-tracing"] = function(g,v)
+ trace_combining = true
+end
+
+vf.aux.combine.commands["disable-tracing"] = function(g,v)
+ trace_combining = false
+end
+
+vf.aux.combine.commands["set-tracing"] = function(g,v)
+ if v[2] == nil then
+ trace_combining = true
+ else
+ trace_combining = v[2]
+ end
+end
+
+function vf.aux.combine.initialize_trace()
+ if trace_combining then
+ return "special", "pdf: .8 0 0 rg .8 0 0 RG", "pdf: 0 .8 0 rg 0 .8 0 RG", "pdf: 0 0 .8 rg 0 0 .8 RG", "pdf: 0 g 0 G"
+ else
+ return "comment", "", "", "", ""
+ end
+end
+
+vf.aux.combine.force_fallback = false
+
+vf.aux.combine.commands["fake-character"] = function(g,v) -- g, nr, fallback_id
+ local index, fallback = v[2], v[3]
+ if vf.aux.combine.force_fallback or not g.characters[index] then
+ if fonts.fallbacks[fallback] then
+ g.characters[index], g.descriptions[index] = fonts.fallbacks[fallback](g)
+ end
+ end
+end
+
+fonts.fallbacks['textcent'] = function (g)
+ local c = ("c"):byte()
+ local t = table.fastcopy(g.characters[c])
+ local a = - tan(rad(g.italicangle or 0))
+ local special, red, green, blue, black = vf.aux.combine.initialize_trace()
+ local quad = g.parameters.quad
+ if a == 0 then
+ t.commands = {
+ {"push"}, {"slot", 1, c}, {"pop"},
+ {"right", .5*t.width},
+ {"down", .2*t.height},
+ {special, green},
+ {"rule", 1.4*t.height, .02*quad},
+ {special, black},
+ }
+ else
+ t.commands = {
+ {"push"},
+ {"right", .5*t.width-.025*quad},
+ {"down", .2*t.height},
+ {"special",format("pdf: q 1 0 %s 1 0 0 cm",a)},
+ {special, green},
+ {"rule", 1.4*t.height, .025*quad},
+ {special, black},
+ {"special","pdf: Q"},
+ {"pop"},
+ {"slot", 1, c} -- last else problems with cm
+ }
+ end
+ -- somehow the width is messed up now
+ -- todo: set height
+ t.height = 1.2*t.height
+ t.depth = 0.2*t.height
+ g.virtualized = true
+ local d = g.descriptions
+ return t, d and d[c]
+end
+
+fonts.fallbacks['texteuro'] = function (g)
+ local c = ("C"):byte()
+ local t = table.fastcopy(g.characters[c])
+ local d = cos(rad(90+(g.italicangle)))
+ local special, red, green, blue, black = vf.aux.combine.initialize_trace()
+ local quad = g.parameters.quad
+ t.width = 1.05*t.width
+ t.commands = {
+ {"right", .05*t.width},
+ {"push"}, {"slot", 1, c}, {"pop"},
+ {"right", .5*t.width*d},
+ {"down", -.5*t.height},
+ {special, green},
+ {"rule", .05*quad, .4*quad},
+ {special, black},
+ }
+ g.virtualized = true
+ return t, g.descriptions[c]
+end
+
+-- maybe store llx etc instead of bbox in tfm blob / more efficient
+
+vf.aux.combine.force_composed = false
+
+local push, pop = { "push" }, { "pop" }
+
+local cache = { } -- we could make these weak
+
+function vf.aux.compose_characters(g) -- todo: scaling depends on call location
+ -- this assumes that slot 1 is self, there will be a proper self some day
+ local chars, descs = g.characters, g.descriptions
+ local X = ("X"):byte()
+ local xchar = chars[X]
+ local xdesc = descs[X]
+ if xchar and xdesc then
+ local scale = g.factor or 1
+ local cap_lly = scale*xdesc.boundingbox[4]
+ local ita_cor = cos(rad(90+(g.italicangle or 0)))
+ local force = vf.aux.combine.force_composed
+ local fallbacks = characters.fallbacks
+ local special, red, green, blue, black
+ if trace_combining then
+ special, red, green, blue, black = vf.aux.combine.initialize_trace()
+ red, green, blue, black = { special, red }, { special, green }, { special, blue }, { special, black }
+ end
+ local done = false
+ for i,c in next, characters.data do
+ if force or not chars[i] then
+ local s = c.specials
+ if s and s[1] == 'char' then
+ local chr = s[2]
+ local charschr = chars[chr]
+ if charschr then
+ local cc = c.category
+ if cc == 'll' or cc == 'lu' or cc == 'lt' then
+ local acc = s[3]
+ local t = { }
+ for k, v in next, charschr do
+ if k ~= "commands" then
+ t[k] = v
+ end
+ end
+ local charsacc = chars[acc]
+--~ local ca = charsacc.category
+--~ if ca == "mn" then
+--~ -- mark nonspacing
+--~ elseif ca == "ms" then
+--~ -- mark spacing combining
+--~ elseif ca == "me" then
+--~ -- mark enclosing
+--~ else
+ if not charsacc then
+ acc = fallbacks[acc]
+ charsacc = acc and chars[acc]
+ end
+ if charsacc then
+ local chr_t = cache[chr]
+ if not cht_t then
+ chr_t = {"slot", 1, chr}
+ cache[chr] = chr_t
+ end
+ local acc_t = cache[acc]
+ if not acc_t then
+ acc_t = {"slot", 1, acc}
+ cache[acc] = acc_t
+ end
+ local cb = descs[chr].boundingbox
+ local ab = descs[acc].boundingbox
+ if cb and ab then
+ -- can be sped up for scale == 1
+ local c_llx, c_lly, c_urx, c_ury = scale*cb[1], scale*cb[2], scale*cb[3], scale*cb[4]
+ local a_llx, a_lly, a_urx, a_ury = scale*ab[1], scale*ab[2], scale*ab[3], scale*ab[4]
+ local dx = (c_urx - a_urx - a_llx + c_llx)/2
+ local dd = (c_urx - c_llx)*ita_cor
+ if a_ury < 0 then
+ if trace_combining then
+ t.commands = {
+ push,
+ {"right", dx-dd},
+ red,
+ acc_t,
+ black,
+ pop,
+ chr_t,
+ }
+ else
+ t.commands = {
+ push,
+ {"right", dx-dd},
+ acc_t,
+ pop,
+ chr_t,
+ }
+ end
+ elseif c_ury > a_lly then
+ local dy = cap_lly-a_lly
+ if trace_combining then
+ t.commands = {
+ push,
+ {"right", dx+dd},
+ {"down", -dy},
+ green,
+ acc_t,
+ black,
+ pop,
+ chr_t,
+ }
+ else
+ t.commands = {
+ push,
+ {"right", dx+dd},
+ {"down", -dy},
+ acc_t,
+ pop,
+ chr_t,
+ }
+ end
+ else
+ if trace_combining then
+ t.commands = {
+ {"push"},
+ {"right", dx+dd},
+ blue,
+ acc_t,
+ black,
+ {"pop"},
+ chr_t,
+ }
+ else
+ t.commands = {
+ {"push"},
+ {"right", dx+dd},
+ acc_t,
+ {"pop"},
+ chr_t,
+ }
+ end
+ end
+ done = true
+ end
+ end
+ chars[i] = t
+ local d = { }
+ for k, v in next, descs[chr] do
+ d[k] = v
+ end
+ d.name = c.adobename or "unknown"
+ -- d.unicode = i
+ descs[i] = d
+ end
+ end
+ end
+ end
+ end
+ if done then
+ g.virtualized = true
+ end
+ end
+end
+
+vf.aux.combine.commands["complete-composed-characters"] = function(g,v)
+ vf.aux.compose_characters(g)
+end
+
+--~ {'special', 'pdf: q ' .. s .. ' 0 0 '.. s .. ' 0 0 cm'},
+--~ {'special', 'pdf: q 1 0 0 1 ' .. -w .. ' ' .. -h .. ' cm'},
+--~ -- {'special', 'pdf: /Fm\XX\space Do'},
+--~ {'special', 'pdf: Q'},
+--~ {'special', 'pdf: Q'},
+
+-- for documentation purposes we provide:
+
+fonts.define.methods.install("fallback", { -- todo: auto-fallback with loop over data.characters
+ { "fake-character", 0x00A2, 'textcent' },
+ { "fake-character", 0x20AC, 'texteuro' }
+})
+
+vf.aux.combine.commands["enable-force"] = function(g,v)
+ vf.aux.combine.force_composed = true
+ vf.aux.combine.force_fallback = true
+end
+vf.aux.combine.commands["disable-force"] = function(g,v)
+ vf.aux.combine.force_composed = false
+ vf.aux.combine.force_fallback = false
+end
+
+fonts.define.methods.install("demo-2", {
+ { "enable-tracing" },
+ { "enable-force" },
+ { "initialize" },
+ { "include-method", "fallback" },
+ { "complete-composed-characters" },
+ { "disable-tracing" },
+ { "disable-force" },
+})
+
+fonts.define.methods.install("demo-3", {
+ { "enable-tracing" },
+ { "initialize" },
+ { "complete-composed-characters" },
+ { "disable-tracing" },
+})
diff --git a/tex/context/base/font-gds.lua b/tex/context/base/font-gds.lua
new file mode 100644
index 000000000..e3db8c816
--- /dev/null
+++ b/tex/context/base/font-gds.lua
@@ -0,0 +1,294 @@
+if not modules then modules = { } end modules ['font-gds'] = {
+ version = 1.000,
+ comment = "companion to font-gds.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, next = type, next
+local gmatch = string.gmatch
+
+local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end)
+
+-- goodies=name,colorscheme=,featureset=
+--
+-- goodies=auto
+
+-- goodies
+
+fonts.goodies = fonts.goodies or { }
+fonts.goodies.data = fonts.goodies.data or { }
+fonts.goodies.list = fonts.goodies.list or { }
+
+local data = fonts.goodies.data
+local list = fonts.goodies.list
+
+function fonts.goodies.report(what,trace,goodies)
+ if trace_goodies or trace then
+ local whatever = goodies[what]
+ if whatever then
+ logs.report("fonts", "goodie '%s' found in '%s'",what,goodies.name)
+ end
+ end
+end
+
+local function getgoodies(filename) -- maybe a merge is better
+ local goodies = data[filename] -- we assume no suffix is given
+ if goodies ~= nil then
+ -- found or tagged unfound
+ elseif type(filename) == "string" then
+ local fullname = resolvers.find_file(file.addsuffix(filename,"lfg")) or "" -- prefered suffix
+ if fullname == "" then
+ fullname = resolvers.find_file(file.addsuffix(filename,"lua")) or "" -- fallback suffix
+ end
+ if fullname == "" then
+ logs.report("fonts", "goodie file '%s.lfg' is not found",filename)
+ data[filename] = false -- signal for not found
+ else
+ goodies = dofile(fullname) or false
+ if not goodies then
+ logs.report("fonts", "goodie file '%s' is invalid",fullname)
+ return nil
+ elseif trace_goodies then
+ logs.report("fonts", "goodie file '%s' is loaded",fullname)
+ end
+ goodies.name = goodies.name or "no name"
+ for name, fnc in next, list do
+ fnc(goodies)
+ end
+ goodies.initialized = true
+ data[filename] = goodies
+ end
+ end
+ return goodies
+end
+
+function fonts.goodies.register(name,fnc)
+ list[name] = fnc
+end
+
+fonts.goodies.get = getgoodies
+
+-- register goodies file
+
+local preset_context = fonts.define.specify.preset_context
+
+function fonts.initializers.common.goodies(tfmdata,value)
+ local goodies = tfmdata.goodies or { } -- future versions might store goodies in the cached instance
+ for filename in gmatch(value,"[^, ]+") do
+ -- we need to check for duplicates
+ local ok = getgoodies(filename)
+ if ok then
+ goodies[#goodies+1] = ok
+ end
+ end
+ tfmdata.goodies = goodies -- shared ?
+end
+
+-- featuresets
+
+local function flattened(t,tt)
+ -- first set value dominates
+ local tt = tt or { }
+ for i=1,#t do
+ local ti = t[i]
+ if type(ti) == "table" then
+ flattened(ti,tt)
+ elseif tt[ti] == nil then
+ tt[ti] = true
+ end
+ end
+ for k, v in next, t do
+ if type(k) ~= "number" then
+ if type(v) == "table" then
+ flattened(v,tt)
+ elseif tt[k] == nil then
+ tt[k] = v
+ end
+ end
+ end
+ return tt
+end
+
+fonts.flattened_features = flattened
+
+function fonts.goodies.prepare_features(goodies,name,set)
+ if set then
+ local ff = fonts.flattened_features(set)
+ local fullname = goodies.name .. "::" .. name
+ local n, s = preset_context(fullname,"",ff)
+ goodies.featuresets[name] = s -- set
+ if trace_goodies then
+ logs.report("fonts", "feature set '%s' gets number %s and name '%s'",name,n,fullname)
+ end
+ return n
+ end
+end
+
+local function initialize(goodies,tfmdata)
+ local featuresets = goodies.featuresets
+ local goodiesname = goodies.name
+ if featuresets then
+ if trace_goodies then
+ logs.report("fonts", "checking featuresets in '%s'",goodies.name)
+ end
+ for name, set in next, featuresets do
+ fonts.goodies.prepare_features(goodies,name,set)
+ end
+ end
+end
+
+fonts.goodies.register("featureset",initialize)
+
+function fonts.initializers.common.featureset(tfmdata,set)
+ local goodies = tfmdata.goodies -- shared ?
+ if goodies then
+ local features = tfmdata.shared.features
+ local what
+ for i=1,#goodies do
+ -- last one counts
+ local g = goodies[i]
+ what = (g.featuresets and g.featuresets[set]) or what
+ end
+ if what then
+ for feature, value in next, what do
+ if features[feature] == nil then
+ features[feature] = value
+ end
+ end
+ tfmdata.mode = features.mode or tfmdata.mode
+ end
+ end
+end
+
+-- colorschemes
+
+fonts.goodies.colorschemes = fonts.goodies.colorschemes or { }
+fonts.goodies.colorschemes.data = fonts.goodies.colorschemes.data or { }
+
+local colorschemes = fonts.goodies.colorschemes
+
+function fonts.initializers.common.colorscheme(tfmdata,scheme)
+ if type(scheme) == "string" then
+ local goodies = tfmdata.goodies
+ -- todo : check for already defined in shared
+ if goodies then
+ local what
+ for i=1,#goodies do
+ -- last one counts
+ local g = goodies[i]
+ what = (g.colorschemes and g.colorschemes[scheme]) or what
+ end
+ if what then
+ -- this is font bound but we can share them if needed
+ -- just as we could hash the conversions (per font)
+ local hash, reverse = tfmdata.luatex.unicodes, { }
+ for i=1,#what do
+ local w = what[i]
+ for j=1,#w do
+ local name = w[j]
+ local unicode = hash[name]
+ if unicode then
+ reverse[unicode] = i
+ end
+ end
+ end
+ tfmdata.colorscheme = reverse
+ return
+ end
+ end
+ end
+ tfmdata.colorscheme = false
+end
+
+local fontdata = fonts.ids
+local fcs = fonts.color.set
+local has_attribute = node.has_attribute
+local traverse_id = node.traverse_id
+local a_colorscheme = attributes.private('colorscheme')
+local glyph = node.id("glyph")
+
+function fonts.goodies.colorschemes.coloring(head)
+ local lastfont, lastscheme
+ for n in traverse_id(glyph,head) do
+ local a = has_attribute(n,a_colorscheme)
+ if a then
+ local f = n.font
+ if f ~= lastfont then
+ lastscheme, lastfont = fontdata[f].colorscheme, f
+ end
+ if lastscheme then
+ local sc = lastscheme[n.char]
+ if sc then
+ fcs(n,"colorscheme:"..a..":"..sc) -- slow
+ end
+ end
+ end
+ end
+end
+
+function fonts.goodies.colorschemes.enable()
+ tasks.appendaction("processors","fonts","fonts.goodies.colorschemes.coloring")
+ function fonts.goodies.colorschemes.enable() end
+end
+
+-- installation (collected to keep the overview)
+
+fonts.otf.tables.features['goodies'] = 'Goodies on top of built in features'
+fonts.otf.tables.features['featurset'] = 'Goodie Feature Set'
+fonts.otf.tables.features['colorscheme'] = 'Goodie Color Scheme'
+
+fonts.otf.features.register('goodies')
+fonts.otf.features.register('featureset')
+fonts.otf.features.register('colorscheme')
+
+table.insert(fonts.triggers, 1, "goodies")
+table.insert(fonts.triggers, 2, "featureset") -- insert after
+table.insert(fonts.triggers, "colorscheme")
+
+fonts.initializers.base.otf.goodies = fonts.initializers.common.goodies
+fonts.initializers.node.otf.goodies = fonts.initializers.common.goodies
+
+fonts.initializers.base.otf.featureset = fonts.initializers.common.featureset
+fonts.initializers.node.otf.featureset = fonts.initializers.common.featureset
+
+fonts.initializers.base.otf.colorscheme = fonts.initializers.common.colorscheme
+fonts.initializers.node.otf.colorscheme = fonts.initializers.common.colorscheme
+
+-- experiment, we have to load the definitions immediately as they precede
+-- the definition so they need to be initialized in the typescript
+
+local function initialize(goodies)
+ local mathgoodies = goodies.mathematics
+ local virtuals = mathgoodies and mathgoodies.virtuals
+ local mapfiles = mathgoodies and mathgoodies.mapfiles
+ local maplines = mathgoodies and mathgoodies.maplines
+ if virtuals then
+ for name, specification in next, virtuals do
+ mathematics.make_font(name,specification)
+ end
+ end
+ if mapfiles then
+ for i=1,#mapfiles do
+ fonts.map.loadfile(mapfiles[i]) -- todo: backend function
+ end
+ end
+ if maplines then
+ for i=1,#maplines do
+ fonts.map.loadline(maplines[i]) -- todo: backend function
+ end
+ end
+end
+
+fonts.goodies.register("mathematics", initialize)
+
+-- The following file (husayni.lfg) is the experimental setup that we used
+-- for Idris font. For the moment we don't store this in the cache and quite
+-- probably these files sit in one of the paths:
+--
+-- tex/context/fonts/goodies
+-- tex/fonts/goodies/context
+-- tex/fonts/data/foundry/collection
+--
+-- see lfg files in distribution
diff --git a/tex/context/base/font-gds.mkiv b/tex/context/base/font-gds.mkiv
new file mode 100644
index 000000000..e36116283
--- /dev/null
+++ b/tex/context/base/font-gds.mkiv
@@ -0,0 +1,83 @@
+%D \module
+%D [ file=font-gds,
+%D version=2009.10.14,
+%D title=\CONTEXT\ Font Support,
+%D subtitle=Colorschemes,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 Font Support / Colorschemes}
+
+% \registerctxluafile{font-gds}{1.001}
+
+\unprotect
+
+\def\loadfontgoodies[#1]%
+ {\ctxlua{fonts.goodies.get("#1")}}
+
+
+% this will become colorgroups and move to font-col or so
+
+\definecolor[colorscheme:1:1][s=.75]
+\definecolor[colorscheme:1:2][r=.75]
+\definecolor[colorscheme:1:3][g=.75]
+\definecolor[colorscheme:1:4][b=.75]
+\definecolor[colorscheme:1:5][c=.75]
+\definecolor[colorscheme:1:6][m=.75]
+\definecolor[colorscheme:1:7][y=.75]
+
+\definecolor[colorscheme:2:7][s=.75]
+\definecolor[colorscheme:2:6][r=.75]
+\definecolor[colorscheme:2:5][g=.75]
+\definecolor[colorscheme:2:4][b=.75]
+\definecolor[colorscheme:2:3][c=.75]
+\definecolor[colorscheme:2:2][m=.75]
+\definecolor[colorscheme:2:1][y=.75]
+
+\definesystemattribute[colorscheme] \chardef\colorschemeattribute \dogetattributeid{colorscheme}
+
+\def\setfontcolorscheme
+ {\ctxlua{fonts.goodies.colorschemes.enable()}%
+ \xdef\setfontcolorscheme[##1]{\attribute\colorschemeattribute##1\relax}%
+ \setfontcolorscheme}
+
+\edef\resetfontcolorscheme{\attribute\colorschemeattribute\attributeunsetvalue}
+
+\protect \endinput
+
+% \definefontfeature[husayni-colored][goodies=husayni,colorscheme=default,featureset=default]
+%
+% \definedfont[husayni*husayni-colored at 36pt]
+%
+% \starttext \pardir TRT \textdir TRT
+%
+% \setfontcolorscheme[1]
+%
+% اَلْحَمْدُ لِلّٰهِ حَمْدَ مُعْتَرِفٍ بِحَمْدِهٖ، مُغْتَرِفٌ مِنْ بِحَارِ
+% مَجْدِهٖ، بِلِسَانِ ٱلثَّنَاۤءِ شَاكِرًا، وَلِحُسْنِ اٰلاۤئِهٖ نَاشِرًا؛
+% اَلَّذِيْ خَلَقَ ٱلْمَوْتَ وَٱلْحَيٰوةَ، وَٱلْخَيْرَ وَٱلشَّرَّ،
+% وَٱلنَّفْعَ وَٱلضَّرَّ، وَٱلسُّكُوْنَ وَٱلْحَرَكَةَ، وَٱلْأَرْوَاحَ
+% وَٱلْأَجْسَامَ، وَٱلذِّكْرَ وَٱلنِّسْيَانَ.
+%
+% \setfontcolorscheme[2]
+%
+% اَلْحَمْدُ لِلّٰهِ حَمْدَ مُعْتَرِفٍ بِحَمْدِهٖ، مُغْتَرِفٌ مِنْ بِحَارِ
+% مَجْدِهٖ، بِلِسَانِ ٱلثَّنَاۤءِ شَاكِرًا، وَلِحُسْنِ اٰلاۤئِهٖ نَاشِرًا؛
+% اَلَّذِيْ خَلَقَ ٱلْمَوْتَ وَٱلْحَيٰوةَ، وَٱلْخَيْرَ وَٱلشَّرَّ،
+% وَٱلنَّفْعَ وَٱلضَّرَّ، وَٱلسُّكُوْنَ وَٱلْحَرَكَةَ، وَٱلْأَرْوَاحَ
+% وَٱلْأَجْسَامَ، وَٱلذِّكْرَ وَٱلنِّسْيَانَ.
+%
+% \resetfontcolorscheme
+%
+% اَلْحَمْدُ لِلّٰهِ حَمْدَ مُعْتَرِفٍ بِحَمْدِهٖ، مُغْتَرِفٌ مِنْ بِحَارِ
+% مَجْدِهٖ، بِلِسَانِ ٱلثَّنَاۤءِ شَاكِرًا، وَلِحُسْنِ اٰلاۤئِهٖ نَاشِرًا؛
+% اَلَّذِيْ خَلَقَ ٱلْمَوْتَ وَٱلْحَيٰوةَ، وَٱلْخَيْرَ وَٱلشَّرَّ،
+% وَٱلنَّفْعَ وَٱلضَّرَّ، وَٱلسُّكُوْنَ وَٱلْحَرَكَةَ، وَٱلْأَرْوَاحَ
+% وَٱلْأَجْسَامَ، وَٱلذِّكْرَ وَٱلنِّسْيَانَ.
+%
+% \stoptext
diff --git a/tex/context/base/font-heb.mkii b/tex/context/base/font-heb.mkii
new file mode 100644
index 000000000..3ec0395f3
--- /dev/null
+++ b/tex/context/base/font-heb.mkii
@@ -0,0 +1,5 @@
+\unprotected \writestatus\m!systems{load ARABTEX as a module instead}
+
+\usemodule[arabtex]
+
+\endinput
diff --git a/tex/context/base/font-ini.lua b/tex/context/base/font-ini.lua
new file mode 100644
index 000000000..e45149781
--- /dev/null
+++ b/tex/context/base/font-ini.lua
@@ -0,0 +1,95 @@
+if not modules then modules = { } end modules ['font-ini'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+
Not much is happening here.
+--ldx]]--
+
+local utf = unicode.utf8
+local format, serialize = string.format, table.serialize
+local write_nl = texio.write_nl
+
+if not fontloader then fontloader = fontforge end
+
+fontloader.totable = fontloader.to_table
+
+-- vtf comes first
+-- fix comes last
+
+fonts = fonts or { }
+
+fonts.ids = fonts.ids or { } fonts.identifiers = fonts.ids -- aka fontdata
+fonts.chr = fonts.chr or { } fonts.characters = fonts.chr -- aka chardata
+fonts.qua = fonts.qua or { } fonts.quads = fonts.qua -- aka quaddata
+
+fonts.tfm = fonts.tfm or { }
+
+fonts.mode = 'base'
+fonts.private = 0xF0000 -- 0x10FFFF
+fonts.verbose = false -- more verbose cache tables
+
+fonts.ids[0] = { -- nullfont
+ characters = { },
+ descriptions = { },
+ name = "nullfont",
+}
+
+fonts.chr[0] = { }
+
+fonts.methods = fonts.methods or {
+ base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
+ node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
+}
+
+fonts.initializers = fonts.initializers or {
+ base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
+ node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } }
+}
+
+fonts.triggers = fonts.triggers or {
+ 'mode',
+ 'language',
+ 'script',
+ 'strategy',
+}
+
+fonts.processors = fonts.processors or {
+}
+
+fonts.manipulators = fonts.manipulators or {
+}
+
+fonts.define = fonts.define or { }
+fonts.define.specify = fonts.define.specify or { }
+fonts.define.specify.synonyms = fonts.define.specify.synonyms or { }
+
+-- tracing
+
+if not fonts.color then
+
+ fonts.color = {
+ set = function() end,
+ reset = function() end,
+ }
+
+end
+
+-- format identification
+
+fonts.formats = { }
+
+function fonts.fontformat(filename,default)
+ local extname = file.extname(filename)
+ local format = fonts.formats[extname]
+ if format then
+ return format
+ else
+ logs.report("fonts define","unable to detemine font format for '%s'",filename)
+ return default
+ end
+end
diff --git a/tex/context/base/font-ini.mkii b/tex/context/base/font-ini.mkii
new file mode 100644
index 000000000..89fbb5d07
--- /dev/null
+++ b/tex/context/base/font-ini.mkii
@@ -0,0 +1,4573 @@
+%D \module
+%D [ file=font-ini,
+%D version=1998.09.11, % (second)
+%D version=2001.02.20, % (third)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Initialization,
+%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 Font Macros / Initialization}
+
+\unprotect
+
+% \def\fontrange#1%
+% {\dofontrange{#1 =\bodyfontsize}}
+%
+% \def\dofontrange#1%
+% {\dodofontrange#1 \relax}% \fontstringA
+%
+% \def\dodofontrange#1 #2 %
+% {\ifdim\bodyfontsize#2%
+% #1\expandafter\gobbleuntilrelax
+% \else
+% \expandafter\dodofontrange
+% \fi}
+%
+% \definefont
+% [crap]
+% [\fontrange
+% {Regular <10pt
+% RegularBold <12pt
+% RegularSlanted <15pt
+% Regular} sa 1]
+%
+% may be better:
+%
+% \definefontrange
+% [crap]
+% [Regular <10pt
+% RegularBold <12pt
+% RegularSlanted <15pt]
+% [Regular sa 1]
+%
+%
+% \dostepwiserecurse{2}{15}{1}
+% {{\switchtobodyfont[\recurselevel pt]\crap test}\endgraf}
+
+% adapted, else wrong interlinespace
+
+\def\setfontparameters
+ {\synchronizefontsfalse
+ \the\everybodyfont
+ \synchronizefontstrue}
+
+% handy
+
+\newcounter\pushedfont
+
+\def\savefont
+ {\edef\savedfont{\the\font}%
+ \pushmacro\savedfont
+ \pushmacro\currentregime
+ \pushmacro\charactermapping
+ \pushmacro\characterencoding}
+
+\def\restorefont
+ {\popmacro\characterencoding
+ \popmacro\charactermapping
+ \popmacro\currentregime
+ \popmacro\savedfont
+ \savedfont}
+
+\def\pushcurrentfont
+ {\edef\popcurrentfont
+ {\noexpand\def\noexpand\fontbody{\fontbody}%
+ \noexpand\def\noexpand\fontstyle{\fontstyle}%
+ \noexpand\dosetcurrentfontalternative{\fontalternative}%
+ \noexpand\dosetcurrentfontsize{\fontsize}%
+ \noexpand\synchronizefont}}
+
+% \definetypeface[one][rm][serif][computer-roman][default]
+% \definetypeface[two][rm][serif][computer-roman][default][rscale=.9]
+%
+% {\one \bf test \two test}
+% {\one \bf test \pushcurrentfont \two \popcurrentfont test}
+
+%D \macros
+%D {definedfont,startfont,doiffontcharelse}
+%D
+%D A couple of relatively new macros:
+
+\newevery \everydefinedfont \relax
+
+\def\dodefinedfont[#1]%
+ {\iffirstargument\definefont[\string\thedefinedfont][#1]\fi
+ \csname\string\thedefinedfont\endcsname % can be \relax
+ \the\everydefinedfont} % hm, redundant
+
+\unexpanded\def\definedfont
+ {\dosingleempty\dodefinedfont}
+
+\unexpanded\def\startfont
+ {\bgroup\definedfont}
+
+\def\stopfont
+ {\egroup}
+
+\def\doiffontcharelse#1#2%
+ {\bgroup
+ \definedfont[#1]%
+ \iffontchar\font#2\relax
+ \egroup\expandafter\firstoftwoarguments
+ \else
+ \egroup\expandafter\secondoftwoarguments
+ \fi}
+
+%%% message 14 added
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+%D This module is one of the oldest modules of \CONTEXT. The
+%D macros below evolved out of the \PLAIN\ \TEX\ macros and
+%D therefore use a similar naming scheme (\type{\rm},
+%D \type{\bf}, etc). This module grew out of our needs. We
+%D started with the \PLAIN\ \TEX\ definitions, generalized the
+%D underlaying macros, and extended those to a level at which
+%D probably no one will ever recognize them.
+%D
+%D In 2001 we ran into a couple of projects where more than
+%D one combined set of fonts was involved in a document. To
+%D make definitions more readable, as well as to overcome the
+%D problem of ever growing file name lists, and also because
+%D we needed to scale fonts relative to each other, the low
+%D level implementation was partly rewritten. Global
+%D font assignments, relative scaling, font classes and alike
+%D were added then. At the same time some macros were made a
+%D bit more readable, and math support was extended to the
+%D larger sizes.
+%D
+%D One important characteristic of the font mechanism presented
+%D here is the postponing of font loading. This makes it
+%D possible to distribute \type{fmt} files without bothering
+%D about the specific breed of \type{tfm} files.
+%D
+%D Another feature implemented here is the massive switching
+%D from roman to {\ss sans serif}, {\tt teletype} or else. This
+%D means one doesn't have to take care of all kind of relations
+%D between fonts.
+%D
+%D \page[bigpreference]
+
+%D \macros
+%D {rm,ss,tt,hw,cg}
+%D
+%D Fonts are defined in separate files. When we define a font,
+%D we distinguish between several styles. In most cases we will
+%D use:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC roman regular serif \NC \type{\rm} \NC\FR
+%D \NC sansserif sans support \NC \type{\ss} \NC\MR
+%D \NC type teletype mono \NC \type{\tt} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D The number of styles is not limited to these three. When
+%D using Lucida Bright we can for instance also define:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC handwritten \NC \type{\hw} \NC\FR
+%D \NC calligraphic \NC \type{\cg} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D Anyone who feels the need, can define additional ones, like
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC faxfont \NC \type{\ff} \NC\FR
+%D \NC blackboard \NC \type{\bb} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D Or even
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC hebrew \NC \type{\hb} \NC\SR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D Styles are grouped in font sets. At the moment there are
+%D three main sets defined:
+%D
+%D \startlinecorrection
+%D \starttable[|l|l||]
+%D \HL
+%D \NC Computer Modern Roman \NC Knuth \NC \type{cmr} \NC\FR
+%D \NC Lucida Bright \NC Bigelow \& Holmes \NC \type{lbr} \NC\MR
+%D \NC Standard Postscript Fonts \NC Adobe \NC \type{pos} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D There are also some Computer Modern Roman alternatives:
+%D
+%D \startlinecorrection
+%D \starttable[|l|l||]
+%D \HL
+%D \NC Computer Modern Roman \NC Knuth \& Sauter \NC \type{sau} \NC\FR
+%D \NC Euler fonts \NC Zapf \NC \type{eul} \NC\MR
+%D \NC Computer Modern Concrete \NC Knuth \& Zapf \NC \type{con} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D All these definitions are ordered in files with names like
+%D \type{font-cmr} and \type{font-pos}, where the last three
+%D characters specify the name as known to \CONTEXT.
+%D
+%D Within such a font set (\type{cmr}) and style (\type{\rm})
+%D we can define a number of text font alternatives:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC typeface \NC \type{\tf} \NC\FR
+%D \NC boldface \NC \type{\bf} \NC\MR
+%D \NC slanted \NC \type{\sl} \NC\MR
+%D \NC italic \NC \type{\it} \NC\MR
+%D \NC boldslanted \NC \type{\bs} \NC\MR
+%D \NC bolditalic \NC \type{\bi} \NC\MR
+%D \NC smallcaps \NC \type{\sc} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+
+%D For old stylish Frans Goddijn we have:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC oldstyle \NC \type{\os} \NC\SR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D The availability of these alternatives depends on the
+%D completeness of a font family and of course the definitions
+%D in the font files.
+%D
+%D But let's not forget math. In addition to the previous \TEX\
+%D families (the mysterious \type{\fam}'s) we've got some more:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC Math Roman \NC \type{\mr} \NC\FR
+%D \NC Math Italic \NC \type{\mi} \NC\MR
+%D \NC Math Symbol \NC \type{\sy} \NC\MR
+%D \NC Math Extra \NC \type{\ex} \NC\MR
+%D \NC Math A \NC \type{\ma} \NC\MR
+%D \NC Math B \NC \type{\mb} \NC\MR
+%D \NC Math C \NC \type{\mc} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D Users can call for specific fonts in many ways. Switches to
+%D other typefaces, like the switch from normal to bold, are as
+%D intuitive as possible, which means that all dependant fonts
+%D also switch. One can imagine that this takes quite some
+%D processing time.
+%D
+%D Internally fonts are stored as combination of size, style
+%D and alternative, e.g. \type{12pt}+\type{\ss}+\type{\bf}.
+%D Users are not confronted with sizes, but use the style or
+%D style+alternative to activate them.
+%D
+%D During the definition of a bodyfont one can also declare the
+%D available larger alternatives:
+%D
+%D \starttyping
+%D \tf \tfa \tfb \tfc ...
+%D \bf \bfa \bfb \bfc ...
+%D \sl \sla \slb \slc ...
+%D \stoptyping
+%D
+%D The smaller ones are automatically supplied and derived from
+%D the the bodyfont environment.
+%D
+%D \starttyping
+%D \tfx \tfxx
+%D \bfx \bfxx
+%D \slx \slxx
+%D \stoptyping
+%D
+%D There are only two smaller alternatives per style. The
+%D larger alternatives on the other hand have no limitations.
+%D
+%D These larger alternatives are mostly used in chapter and
+%D section titles or on title pages. When one switches to a
+%D larger alternative, the bold an other ones automatically
+%D adapt themselves:
+%D
+%D \startbuffer
+%D \tfd Hi \bf there\sl, here \tfb I \bf am
+%D \stopbuffer
+%D
+%S \startnarrower
+%D \typebuffer
+%S \stopnarrower
+%D
+%D therefore becomes:
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D Maybe this mechanism isn't always as logic, but as said
+%D before, we tried to make it as intuitive as possible.
+%D
+%D So a specific kind of glyph can be characterized by:
+%D
+%D \startnarrower
+%D family (cmr) + bodyfont (12pt) + style (rm) + alternative (bf) + size (a)
+%D \stopnarrower
+%D
+%D The last component (the size) is optional.
+%D
+%D We introduced \type{\tf} as command to call for the current
+%D normally sized typeface. This commands results in roman,
+%D sans serif, teletype or whatever style is in charge. Such
+%D rather massive switches of style sometimes take more
+%D processing time than comfortable. Of course there is a
+%D workaround for this: we can call fonts directly by means of
+%D commands like:
+%D
+%D \starttyping
+%D \rmtf \sssl \tttf \rmbsa
+%D \stoptyping
+%D
+%D One should realize that this fast calls have limitations,
+%D they lack for instance automatic super- and subscript
+%D support.
+%D
+%D This leaves us two more commands: \type{\tx} and
+%D \type{\txx}. These activate a smaller and even more smaller
+%D font than the current one and adapt themselves to the
+%D current alternative, so when \type{\bf} is active,
+%D \type{\tx} gives a smaller boldface, which in turn can be
+%D called directly by \type{\bfx}.
+%D
+%D These two smaller alternatives are specified by the bodyfont
+%D environment and therefore not necessarily have similar sizes
+%D as \type{\scriptsize} and \type{\scriptscriptsize}. The main
+%D reason for this incompatibility (which can easily be undone)
+%D lays in the fact that we often want a bit bigger characters
+%D than in math mode. In \CONTEXT\ for instance the \type{\tx}
+%D and \type{\txx} commands are used for surrogate
+%D \cap{smallcaps} which support both nesting and alternatives,
+%D like in {\bf\cap{a \cap{small} world}}, which was typeset by
+%D
+%D \starttyping
+%D \bf\cap{a \cap{small} world}
+%D \stoptyping
+%D
+%D And compare $\rm \scriptstyle THIS$ with the slightly larger
+%D \cap{THIS}: \ruledhbox{$\rm \scriptstyle scriptstyle: THIS$}
+%D or \ruledhbox{\cap{x style: THIS}} makes a big difference.
+
+%D The \type{x..d} sizes should be used grouped. If you
+%D don't group them, i.e. call them in a row, \CONTEXT\ will
+%D not be able to sort out your intention (\type {x} inside
+%D \type {d} inside \type {x}. etc.). The following table
+%D demonstrates this:
+%D
+%D \def\FontState{\setstrut\ruledhbox{\strut Hello}}
+%D
+%D \starttabulate[|||||]
+%D \HL
+%D \NC \rlap{\quad\bf grouped} \NC \NC \type {\tx} \NC \type {\txx} \NC \NR
+%D \HL
+%D \NC \type{\tfx} \NC \tfx \FontState \NC \tfx \tx \FontState \NC \tfx \txx \FontState \NC \NR
+%D \NC \type{\tfxx} \NC \tfxx \FontState \NC \tfxx\tx \FontState \NC \tfxx\txx \FontState \NC \NR
+%D \NC \type{\tf} \NC \tf \FontState \NC \tf \tx \FontState \NC \tf \txx \FontState \NC \NR
+%D \NC \type{\tfa} \NC \tfa \FontState \NC \tfa \tx \FontState \NC \tfa \txx \FontState \NC \NR
+%D \NC \type{\tfb} \NC \tfb \FontState \NC \tfb \tx \FontState \NC \tfb \txx \FontState \NC \NR
+%D \NC \type{\tfc} \NC \tfc \FontState \NC \tfc \tx \FontState \NC \tfc \txx \FontState \NC \NR
+%D \NC \type{\tfd} \NC \tfd \FontState \NC \tfd \tx \FontState \NC \tfd \txx \FontState \NC \NR
+%D \NC \type{\tfx} \NC \tfx \FontState \NC \tfx \tx \FontState \NC \tfx \txx \FontState \NC \NR
+%D \NC \type{\tfxx} \NC \tfxx \FontState \NC \tfxx\tx \FontState \NC \tfxx\txx \FontState \NC \NR
+%D \HL
+%D \stoptabulate
+%D
+%D \blank
+%D
+%D \starttabulate[|||||]
+%D \HL
+%D \NC \rlap{\quad\bf stacked} \NC \NC \type {\tx} \NC \type {\txx} \NC \NR
+%D \HL
+%D \NC \type{\tfx}
+%D \NC \tfx \FontState
+%D \NC \tfx \tx \FontState
+%D \NC \tfx \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfxx}
+%D \NC \tfx\tfxx \FontState
+%D \NC \tfx\tfxx \tx \FontState
+%D \NC \tfx\tfxx \txx \FontState
+%D \NC \NR
+%D \NC \type{\tf}
+%D \NC \tfx\tfxx\tf \FontState
+%D \NC \tfx\tfxx\tf \tx \FontState
+%D \NC \tfx\tfxx\tf \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfa}
+%D \NC \tfx\tfxx\tf\tfa \FontState
+%D \NC \tfx\tfxx\tf\tfa \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfb}
+%D \NC \tfx\tfxx\tf\tfa\tfb \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfc}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfd}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfx}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfxx}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \txx \FontState
+%D \NC \NR
+%D \HL
+%D \stoptabulate
+
+%D \macros
+%D {mf}
+%D
+%D Math fonts are a species in their own. They are tightly
+%D hooked into smaller and even smaller ones of similar breed
+%D to form a tight family. Let's first see how these are
+%D related:
+%D
+%D \startbuffer
+%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+ \bi x^2 =\rm 6x^2$
+%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+{\bi x^2}=\rm 6x^2$
+%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+ \bi x^2 =\tf 6x^2$
+%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+{\bi x^2}=\tf 6x^2$
+%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+ \bi x^2 =\bf 6x^2$
+%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+{\bi x^2}=\bf 6x^2$
+%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+ \bi x^2 =\sl 6x^2$
+%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+{\bi x^2}=\sl 6x^2$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Gives both an expected and unexpected result:
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D We see here that the character shapes change accordingly to
+%D the current family, but that the symbols are always typeset
+%D in the font assigned to \type{\fam0}.
+%D
+%D \startbuffer
+%D $\tf\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
+%D $\bf\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
+%D $\sl\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
+%D $\bs\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
+%D $\it\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
+%D $\bi\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
+%D \stopbuffer
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D In this example we see a new command \type{\mf} surface
+%D which means as much as {\em math font}. This commands
+%D reactivates the last font alternative and therefore equals
+%D \type{\bf}, \type{\sl} etc. but by default it equals
+%D \type{\tf}:
+
+\unexpanded\def\mf
+ {\dodosetmathfont\fontalternative
+ \csname\fontalternative\endcsname}
+
+%D The previous example was typeset saying:
+%D
+%D \typebuffer
+%D
+%D Beware: the exact location of \type{\mf} is not that
+%D important, we could as well has said
+%D
+%D \startbuffer
+%D $\bf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = \mf 6x^2$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D This is due to the way \TEX\ handles fonts in math mode.
+%D
+%D Of course we'll have to redefine \type{\mf} every time we
+%D change the current \type{\fam}.
+
+%D \macros
+%D {mbox,enablembox,mathop}
+%D
+%D Now how can we put this to use? Will the next sequence
+%D give the desired result?
+%D
+%D \startbuffer
+%D $\bf x^2 + \hbox{\mf whatever} + \sin(2x)$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D It won't!
+%D
+%D \startvoorbeeld
+%D \let\mathop=\normalmathop \getbuffer
+%D \stopvoorbeeld
+%D
+%D The reason for this is that \type{\sin} is defined as:
+%D
+%D \starttyping
+%D \def\sin{\mathop{\rm sin}\nolimits}
+%D \stoptyping
+%D
+%D We can fix this by defining
+
+\unexpanded\def\mathop
+ {\normalmathop
+ \bgroup
+ \let\rm\mf
+ \let\next=}
+
+%D We can fix arbitrary horizontal boxes by redefining the
+%D \TEX\ primitive \type{\hbox}:
+%D
+%D \starttyping
+%D \def\hbox{\ifmmode\mbox\else\normalhbox\fi}
+%D \stoptyping
+%D
+%D with
+%D
+%D \starttyping
+%D \def\mbox#1#%
+%D {\normalhbox#1\bgroup\mf\let\next=}
+%D \stoptyping
+%D
+%D or more robust, that is, also accepting \type{\hbox\bgroup}:
+%D
+%D \starttyping
+%D \def\mbox%
+%D {\normalhbox\bgroup\mf
+%D \dowithnextbox{\flushnextbox\egroup}%
+%D \normalhbox}
+%D \stoptyping
+%D
+%D And now:
+%D
+%D \startbuffer
+%D $\bf x^2 + \hbox{whatever} + \sin(2x)$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Indeed gives:
+%D
+%D \startvoorbeeld
+%D \enablembox\getbuffer
+%D \stopvoorbeeld
+%D
+%D But, do we want this kind of trickery to be activated? No,
+%D simply because we cannot be sure of incompatibilities,
+%D although for instance unboxing goes ok. Therefore we
+%D introduce:
+
+% best can go to math-ini and make \mf a hook then
+
+% better use \dowithnextboxcontent
+
+\def\normalmbox
+ {\normalhbox\bgroup\mf
+ \dowithnextbox{\flushnextbox\egroup}\normalhbox}
+
+% to test:
+%
+% \def\normalmbox
+% {\dowithnextboxcontent\mf\flushnextbox\normalhbox}
+
+\def\mbox
+ {\ifmmode\normalmbox\else\normalhbox\fi}
+
+\def\enablembox
+ {\appendtoks
+ \ifx\normalhbox\undefined\let\normalhbox\hbox\fi
+ \let\hbox\mbox
+ \to\everymathematics}
+
+%D So in fact one can enable this feature if needed. I would say:
+%D go along, but use grouping if needed!
+
+%D \macros
+%D {mrfam,mifam,syfam,exfam,
+%D bsfam,bifam,scfam,tffam,
+%D mafam,mbfam,msfam}
+%D
+%D After this short mathematical excursion, we enter the world
+%D of fonts and fontswitching. We start with something very
+%D \TEX: \type{\fam} specified font families. \TEX\ uses
+%D families for managing fonts in math mode. Such a family has
+%D three members: text, script and scriptscript: $x^{y^z}$. In
+%D \CONTEXT\ we take a bit different approach than \PLAIN\
+%D \TEX\ does. \PLAIN\ \TEX\ needs at least four families for
+%D typesetting math. We use those but give them symbolic names.
+
+\chardef\mrfam = 0 % (Plain TeX) Math Roman
+\chardef\mifam = 1 % (Plain TeX) Math Italic
+\chardef\syfam = 2 % (Plain TeX) Math Symbol
+\chardef\exfam = 3 % (Plain TeX) Math Extra
+
+%D \PLAIN\ \TEX\ also defines families for {\it italic}, {\sl
+%D slanted} and {\bf bold} typefaces, so we don't have to
+%D define them here.
+
+\ifx\itfam\undefined
+
+\chardef\itfam = 4 % (Plain TeX) Italic
+\chardef\slfam = 5 % (Plain TeX) Slanted
+\chardef\bffam = 6 % (Plain TeX) Boldface
+
+\fi
+
+%D Family~7 in \PLAIN\ \TEX\ is not used in \CONTEXT, because
+%D we do massive switches from roman to sans serif, teletype or
+%D other faces.
+
+\ifx\ttfam\undefined
+
+\chardef\ttfam = 7 % (Plain TeX) can be reused!
+
+\fi
+
+%D We define ourselves some more families for {\bs bold
+%D slanted}, {\bi bold italic} and {\sc Small Caps}, so
+%D we can use them in math mode too. Instead of separate
+%D families for {\ss sans serif} and \type{teletype} we use the
+%D more general \type{\tffam}, which stands for typeface.
+
+\chardef\bsfam = 8 % (ConTeXt) BoldSlanted
+\chardef\bifam = 9 % (ConTeXt) BoldItalic
+\chardef\scfam = 10 % (ConTeXt) SmallCaps
+\chardef\tffam = 11 % (ConTeXt) TypeFace
+
+%D Because Taco needs a few more math families, we reuse
+%D family~7 for all those typefaces that have no related
+%D family, and therefore are grouped into one.
+
+\chardef\nnfam = 7 % (ReUsed) NoName
+
+%D Normally \type{\mrfam} equals \type{\tffam}, but a more
+%D distinctive alternatives are possible, for instance the
+%D Euler and Concrete Typefaces.
+%D
+%D After having defined all those in nature non||mathematical
+%D families, we define ourselves some real math ones. These are
+%D needed for the \AMS\ Symbol Fonts and Extended Lucida
+%D Bright.
+
+\chardef\mafam = 12 % (ConTeXt) Math A Fam (AmsTeX A)
+\chardef\mbfam = 13 % (ConTeXt) Math B Fam (AmsTeX B)
+\chardef\mcfam = 14 % (ConTeXt) Math C Fam (MathTime)
+\chardef\mdfam = 15 % (ConTeXt) Math D Fam (MathTime)
+
+%D Because there are 16~families and because \type{\ttfam}
+%D is reused, at the moment we have no so many families
+%D left. By default, we map any newly defined family on the
+%D last one (F).
+
+\def\newfam#1{\chardef#1=15 }
+
+%D This hack is also needed because in \ETEX\ we are going
+%D to reuse the \type {\newfam} allocation counter.
+
+%D To ease the support of font packages, we als define
+%D shortcuts to these familynames. This is necessary because
+%D the family names are in fact \type{\chardef}'s, which means
+%D that we're dealing with numbers (one can check this by
+%D applying \type{\showthe} and \type{\show}). In the
+%D specification of math symbols however we need hexadecimal
+%D numbers, so we have to convert the \type{\fam}'s value.
+
+\edef\hexmrfam {\hexnumber\mrfam} \edef\hexbsfam {\hexnumber\bsfam}
+\edef\hexmifam {\hexnumber\mifam} \edef\hexbifam {\hexnumber\bifam}
+\edef\hexsyfam {\hexnumber\syfam} \edef\hexscfam {\hexnumber\scfam}
+\edef\hexexfam {\hexnumber\exfam} \edef\hextffam {\hexnumber\tffam}
+\edef\hexitfam {\hexnumber\itfam} \edef\hexmafam {\hexnumber\mafam}
+\edef\hexslfam {\hexnumber\slfam} \edef\hexmbfam {\hexnumber\mbfam}
+\edef\hexbffam {\hexnumber\bffam} \edef\hexmcfam {\hexnumber\mcfam}
+\edef\hexnnfam {\hexnumber\nnfam} \edef\hexmdfam {\hexnumber\mdfam}
+
+%D \macros
+%D {uchar}
+%D
+%D This macro prepares \CONTEXT\ for \UNICODE\ support. By
+%D defining it here, we have at least an safeguard for utility
+%D file reading.
+
+\ifx\uchar\undefined \unexpanded\def\uchar#1#2{[#1,#2]} \fi
+
+%D We define some (very private) constants to improve speed,
+%D memory usage and consistency.
+
+\def\@size@ {@f@si@} % bodyfont size prefix (12pt etc)
+\def\@style@ {@f@st@} % full style prefix (roman etc)
+\def\@shortstyle@ {@f@sh@} % short style prefix (rm etc)
+\def\@letter@ {@f@le@} % first alternative typeface
+\def\@noletter@ {@f@no@} % second alternative typeface
+\def\@fontclass@ {@f@cl@} % fontclass
+
+%D The families can be grouped into math specific ones and
+%D more text related families, although text ones can be
+%D mapped onto the math ones to get for instance bold math.
+%D
+%D Both groups of families are handles by a couple of token
+%D list tagged as strategies. This implementation makes
+%D implementing extensions more comfortable.
+
+\newtoks \textstrategies
+\newtoks \mathstrategies
+\newtoks \symbstrategies
+
+\newif\ifsynchronizemathfonts \synchronizemathfontstrue
+
+\def\synchronizetext % stylish text in mmode
+ {\ifsynchronizemathfonts\the\textstrategies\fi} % \if...\fam\minusone\fi}
+
+\def\synchronizemath % math stuff in mmode
+ {\ifsynchronizemathfonts\the\mathstrategies\fi} % \if...\fam\minusone\fi}
+
+\def\synchronizesymb % stylish math stuff in mmode
+ {\ifsynchronizemathfonts\the\symbstrategies\fi} % \if...\fam\minusone\fi}
+
+%D By not setting the family we can append a font switch to \type
+%D {\everymath}. On the other hand, one never knows in what family
+%D state the strategies brought us.
+%D
+%D \starttyping
+%D {\bfa $\the\fam$} {\bfa \everymath{} $\the\fam$}
+%D \stoptyping
+
+%D \macros
+%D {textonly}
+%D
+%D We can inhibit this slow||downer with:
+
+\def\textonly{\synchronizemathfontsfalse} % document this
+
+\appendtoks
+ \dosettextfamily\c!tf
+ \dosettextfamily\c!bf
+ \dosettextfamily\c!sl
+ \dosettextfamily\c!it
+ \dosettextfamily\c!bs
+ \dosettextfamily\c!bi
+ \dosettextfamily\c!sc
+\to \textstrategies
+
+\def\dosettextfamily#1% better pass fontbody to dodoset
+ {\let\savedfontbody\fontbody
+ \let\fontfamily#1%
+ \let\fontbody\scriptscriptface\dodosettextfamily\scriptscriptfont
+ \let\fontbody\scriptface \dodosettextfamily \scriptfont
+ \let\fontbody\textface \dodosettextfamily \textfont
+ \let\fontbody\savedfontbody}
+
+% \def\s!nullfont{nullfont}
+
+\def\dodosettextfamily
+ {\ifx\fontclass\empty
+ \@EA\dodosettextfamilyA
+ \else
+ \@EA\dodosettextfamilyB
+ \fi}
+
+\def\dodosettextfamilyA#1%
+ {\ifcsname \fontbody\c!mm\fontfamily\fontsize\endcsname \autofontsizefalse
+ \csname \fontbody\c!mm\fontfamily\fontsize\endcsname \else
+ \ifcsname \fontbody\c!mm\fontfamily\endcsname \autofontsizetrue
+ \csname \fontbody\c!mm\fontfamily\endcsname \else
+ \ifcsname \fontbody\c!rm\fontfamily\fontsize\endcsname \autofontsizefalse
+ \csname \fontbody\c!rm\fontfamily\fontsize\endcsname \else
+ \ifcsname \fontbody\c!rm\fontfamily\endcsname \autofontsizetrue
+ \csname \fontbody\c!rm\fontfamily\endcsname \else
+ \nullfont \autofontsizetrue
+ \fi\fi\fi\fi
+ #1\csname\fontfamily\s!fam\endcsname\font}
+
+\def\dodosettextfamilyB#1%
+ {\ifcsname\fontclass\fontbody\c!mm\fontfamily\fontsize\endcsname \autofontsizefalse
+ \csname\fontclass\fontbody\c!mm\fontfamily\fontsize\endcsname \else
+ \ifcsname\fontclass\fontbody\c!mm\fontfamily\endcsname \autofontsizetrue
+ \csname\fontclass\fontbody\c!mm\fontfamily\endcsname \else
+ \ifcsname\fontclass\fontbody\c!rm\fontfamily\fontsize\endcsname \autofontsizefalse
+ \csname\fontclass\fontbody\c!rm\fontfamily\fontsize\endcsname \else
+ \ifcsname\fontclass\fontbody\c!rm\fontfamily\endcsname \autofontsizetrue
+ \csname\fontclass\fontbody\c!rm\fontfamily\endcsname \else
+ \dodosettextfamilyA#1%
+ \fi\fi\fi\fi
+ #1\csname\fontfamily\s!fam\endcsname\font}
+
+\def\mrfallback{\c!rm\c!tf}
+
+\appendtoks
+ \dosetmathfamily\mrfam\textface\scriptface\scriptscriptface\c!mr\mrfallback
+ \dosetmathfamily\mifam\textface\scriptface\scriptscriptface\c!mi\empty
+ \dosetmathfamily\syfam\textface\scriptface\scriptscriptface\c!sy\empty
+ \dosetmathfamily\exfam\textface\textface \textface \c!ex\empty
+ \dosetmathfamily\mafam\textface\scriptface\scriptscriptface\c!ma\empty
+ \dosetmathfamily\mbfam\textface\scriptface\scriptscriptface\c!mb\empty
+ \dosetmathfamily\mcfam\textface\scriptface\scriptscriptface\c!mc\empty
+% \dosetmathfamily\mdfam\textface\scriptface\scriptscriptface\c!md\empty
+ \dosetmathfamily\nnfam\textface\scriptface\scriptscriptface\c!nn\empty
+\to \mathstrategies
+
+\appendtoks
+ \dosetskewchar\mifam\defaultskewcharmi % implemented later on
+ \dosetskewchar\syfam\defaultskewcharsy % implemented later on
+\to \mathstrategies
+
+\def\dosetmathfamily#1#2#3#4#5#6%
+ {\let\savedfontbody\fontbody % op hoger plan
+ \let\fontfamily#5%
+ \let\backfamily#6%
+ \let\fontbody #4\dodosetmathfamily\scriptscriptfont#1%
+ \let\fontbody #3\dodosetmathfamily \scriptfont#1%
+ \let\fontbody #2\dodosetmathfamily \textfont#1%
+ \let\fontbody\savedfontbody}
+
+\def\dodosetmathfamily
+ {\ifx\fontclass\empty
+ \@EA\dodosetmathfamilyA
+ \else
+ \@EA\dodosetmathfamilyB
+ \fi}
+
+\def\dodosetmathfamilyA#1#2%
+ {\ifcsname \fontbody\c!mm\fontfamily\fontsize\endcsname \autofontsizefalse
+ \csname \fontbody\c!mm\fontfamily\fontsize\endcsname \else
+ \ifcsname \fontbody\c!mm\fontfamily \endcsname \autofontsizetrue
+ \csname \fontbody\c!mm\fontfamily \endcsname \else
+ \ifcsname \fontbody \backfamily\fontsize\endcsname \autofontsizefalse
+ \csname \fontbody \backfamily\fontsize\endcsname \else
+ \ifcsname \fontbody \backfamily \endcsname \autofontsizetrue
+ \csname \fontbody \backfamily \endcsname \else
+ \nullfont \autofontsizetrue
+ \fi\fi\fi\fi
+ #1#2\font}
+
+\def\dodosetmathfamilyB#1#2%
+ {\ifcsname\fontclass\fontbody\c!mm\fontfamily\fontsize\endcsname \autofontsizefalse
+ \csname\fontclass\fontbody\c!mm\fontfamily\fontsize\endcsname \else
+ \ifcsname\fontclass\fontbody\c!mm\fontfamily \endcsname \autofontsizetrue
+ \csname\fontclass\fontbody\c!mm\fontfamily \endcsname \else
+ \ifcsname\fontclass\fontbody \backfamily\fontsize\endcsname \autofontsizefalse
+ \csname\fontclass\fontbody \backfamily\fontsize\endcsname \else
+ \ifcsname\fontclass\fontbody \backfamily \endcsname \autofontsizetrue
+ \csname\fontclass\fontbody \backfamily \endcsname \else
+ \dodosetmathfamilyA#1#2%
+ \fi\fi\fi\fi
+ #1#2\font}
+
+\appendtoks
+ \dosetsymbfamily\mrfam\textface\scriptface\scriptscriptface\c!mr
+ \dosetsymbfamily\mifam\textface\scriptface\scriptscriptface\c!mi
+ \dosetsymbfamily\syfam\textface\scriptface\scriptscriptface\c!sy
+ \dosetsymbfamily\exfam\textface\textface \textface \c!ex
+ \dosetsymbfamily\mafam\textface\scriptface\scriptscriptface\c!ma
+ \dosetsymbfamily\mbfam\textface\scriptface\scriptscriptface\c!mb
+ \dosetsymbfamily\mcfam\textface\scriptface\scriptscriptface\c!mc
+% \dosetsymbfamily\mdfam\textface\scriptface\scriptscriptface\c!md % also ?
+\to \symbstrategies
+
+\def\dosetsymbfamily#1#2#3#4#5%
+ {\let\savedfontbody\fontbody
+ \let\fontfamily#5%
+ \let\fontbody #4\dodosetsymbfamily\scriptscriptfont#1%
+ \let\fontbody #3\dodosetsymbfamily \scriptfont#1%
+ \let\fontbody #2\dodosetsymbfamily \textfont#1%
+ \let\fontbody\savedfontbody}
+
+\def\dodosetsymbfamily#1#2%
+ {\ifcsname\fontclass\fontbody\c!mm\fontfamily\fontalternative\fontsize\endcsname
+ \csname\fontclass\fontbody\c!mm\fontfamily\fontalternative\fontsize\endcsname
+ #1#2\font
+ \else\ifcsname\fontbody\c!mm\fontfamily\fontalternative\fontsize\endcsname
+ \csname\fontbody\c!mm\fontfamily\fontalternative\fontsize\endcsname
+ #1#2\font
+ \fi\fi}
+
+%D All used styles, like rm, ss and tt, are saved in a comma
+%D separated list. Appart from practical limitations one can
+%D define as many styles as needed.
+
+\def\fontrelativesizelist{\s!text,\s!script,\s!scriptscript,\c!x,\c!xx,\c!big,\c!small}
+
+%D \macros
+%D {magfactor,magfactorhalf}
+%D
+%D There are several ways to specify a font. Three of them are
+%D pure \TeX\ ones, the fourth one is new:
+%D
+%D \starttyping
+%D \font\name=cmr12
+%D \font\name=cmr12 at 10pt
+%D \font\name=cmr12 scaled \magstep2
+%D \font\name=cmr12 sa 1.440
+%D \stoptyping
+%D
+%D The non||\TEX\ alternative \type{sa} stands for {\em scaled
+%D at}. This means as much as: scale the bodyfontsize with this
+%D factor. The value 1.440 in this example is derived
+%D from the \type{\magstep}'s as mentioned in
+%D \in{table}[tab:magstep]. We therefore introduce
+%D \type{\magfactor} as an alternative for \type{\magstep}.
+%D
+%D \placetable[here][tab:magstep]
+%D {Factors to be used with \type{sa.}}
+%D \starttable[|c|c|c|]
+%D \HL
+%D \NC \bf magstep \NC \bf equivalent \NC \bf factor \NC\SR
+%D \HL
+%D \NC 1 \NC \type{\magfactor1} \NC 1.200 \NC\FR
+%D \NC 2 \NC \type{\magfactor2} \NC 1.440 \NC\MR
+%D \NC 3 \NC \type{\magfactor3} \NC 1.728 \NC\MR
+%D \NC 4 \NC \type{\magfactor4} \NC 2.074 \NC\MR
+%D \NC 5 \NC \type{\magfactor5} \NC 2.488 \NC\LR
+%D \HL
+%D \stoptable
+
+\def\magstep#1% \relax removed, otherwise space after it sticks, else added
+ {\ifcase#1 1000\or1200\or1440\or1728\or2074\or2488\or1000\fi}
+
+\def\magstephalf
+ {1095}
+
+\def\magfactor#1%
+ {\ifcase#1 1.000\or1.200\or1.440\or1.728\or2.074\or2.488\or1\fi}
+
+\def\magfactorhalf
+ {1.095}
+
+%D These macros enable the use of definitions like \type{sa
+%D \magfactor3} which saves us both (mis|)|calculations and
+%D potential mistypings.
+%D
+%D Because \type {sa} (scaled at) and \type {mo} (mapped on)
+%D are not low level \TEX\ supported alternatives, we have to
+%D test for it ourselves. In doing so, we need an auxiliary
+%D \DIMENSION. We cannot use \type{\scratchdimen} because font
+%D loading can happen at any moment due to postponed loading.
+%D We could instead have used dirty grouping tricks, but this
+%D one works too.
+
+\let\defaultrelativefontsize \plusone
+\let\localrelativefontsize \plusone
+\def\localabsolutefontsize {\fontbody}
+
+\let\relativefontsize \defaultrelativefontsize
+
+\def\saverelativefontsize#1#2% #1=rm|ss|.. #2=waarde
+ {\setxvalue{\fontclass#1\s!rscale}{#2}}
+
+\def\checkrelativefontsize#1%
+ {\edef\relativefontsize
+ {\ifcsname\fontclass#1\s!rscale\endcsname
+ \csname\fontclass#1\s!rscale\endcsname
+ \else
+ \defaultrelativefontsize
+ \fi}}
+
+%D We also save:
+
+\def\savemathtextstyle#1% #1=rm|ss|..
+ {\doifsomething{#1}{\setxvalue{\fontclass\c!mm\s!text}{#1}}}
+
+\def\currentmathtextstyle % we default to empty !
+ {\executeifdefined{\fontclass\c!mm\s!text}\empty}
+
+%D Scaling macros:
+
+\newdimen\scaledfont
+
+\let\somefontspec\empty
+
+\def\@fs@{@fs@}
+
+% \def\parsefontspec#1%
+% {\xdef\somefontspec{#1\space\relax}%
+% \@EA\doparsefontspec\somefontspec]% =>#1 \relax]
+% \donoparsefontspec}
+%
+% but, better:
+
+\let\somefontname\empty
+
+\def\parsefontspec#1%
+ {\xdef\somefontspec{#1\space}%
+ \@EA\doparsefontspec\somefontspec\relax]% =>#1 \relax]
+ \donoparsefontspec}
+
+\def\doparsefontspec#1 #2%
+ {\def\somefontname{#1}%
+ \ifx\somefontname\empty % space before fontname
+ \@EA\doparsefontspec
+ \else\ifx#2\relax
+ \@EAEAEA\setnaturalfontspec
+ \else
+ \@EAEAEA\setforcedfontspec
+ \fi\fi
+ #2}
+
+\def\setnaturalfontspec#1]%
+ {\@fs@scaled\plusthousand\relax}
+
+\def\setforcedfontspec#1 #2\relax]%
+ {\csname\@fs@#1\endcsname#2\relax}
+
+\def\@fs@scaled
+ {\afterassignment\do@fs@scaled\scratchcounter}
+
+\def\do@fs@scaled#1\relax
+ {\scaledfont\number\scratchcounter\points
+ \scaledfont\localrelativefontsize\scaledfont
+ \ifautofontsize\scaledfont\currentfontbodyscale\scaledfont\fi
+ \scratchcounter\scaledfont % \scaledfont is now pretty large
+ \advance\scratchcounter \medcard
+ \divide\scratchcounter \maxcard
+ \xdef\somefontspec{ scaled \the\scratchcounter}}
+
+\def\@fs@at
+ {\afterassignment\do@fs@at\scaledfont}
+
+\def\do@fs@at#1\relax
+ {\scaledfont\localrelativefontsize\scaledfont
+ \ifautofontsize\scaledfont\currentfontbodyscale\scaledfont\fi
+ \xdef\somefontspec{ at \the\scaledfont}}
+
+\def\@fs@sa
+ {\scaledfont\localabsolutefontsize
+ \setsamofontspec}
+
+\def\@fs@mo
+ {\scaledfont\setmappedfontsize\localabsolutefontsize
+ \setsamofontspec}
+
+\def\setsamofontspec#1\relax
+ {\checkfontscale#1\end\scaledfont
+ \scaledfont\localrelativefontsize\scaledfont
+ \ifautofontsize\scaledfont\currentfontbodyscale\scaledfont\fi
+ \xdef\somefontspec{ at \the\scaledfont}}
+
+\def\getfontparameters
+ {\expandafter\dogetfontparameter\@@fontdata,]=,}
+
+\def\getglobalfontparameters
+ {\expandafter\dogetglobalfontparameter\@@fontdata,]=,}
+
+\def\dogetfontparameter#1=#2,%
+ {\if]#1\else
+ \expandafter\def\csname\??ff\@@fontfile#1\endcsname{#2}%
+ \expandafter\dogetfontparameter
+ \fi}
+
+\def\dogetglobalfontparameter#1=#2,%
+ {\if]#1\else
+ \expandafter\gdef\csname\??ff\@@fontfile#1\endcsname{#2}%
+ \expandafter\dogetglobalfontparameter
+ \fi}
+
+\let\@@fontencoding\empty
+\let\@@fontmapping \empty
+\let\@@fonthandling\empty
+\let\@@fontfeatures\empty
+\let\@@skewchar \empty
+\let\@@hyphenchar \empty % todo, will go to encoding
+
+%D This brings down maps processing from 466 to 309 seconds
+%D ($-33$\%) and mfonts from 42 to 34 seconds ($-15$\%).
+
+\newif\ifskipfontcharacteristics \skipfontcharacteristicstrue
+
+%D When fontclasses are used, we define the font global,
+%D since namespaces are used. Otherwise we parse the specs
+%D each time.
+
+% wrong: this way we cannot set encoding etc
+%
+% \def\donoparsefontspec#1%
+% {\edef\fontfile{\truefontname\somefontname}%
+% \ifx\fontfile\s!unknown \let\fontfile\defaultfontfile \fi
+% \edef\lastfontname{\fontfile\somefontspec}%
+% \ifx\fontclass\empty\else\global\fi
+% \expandafter\font\csname#1\endcsname\lastfontname\relax
+% \relax}
+
+\let\fontfile\s!unknown
+
+\ifx\checkfontfilename\undefined \let\checkfontfilename\relax \fi
+
+% \definefontsynonym
+% [blabla]
+% [name:Latin Modern Something]
+% \definefontsynonym
+% [blabla]
+% [file:texnansi-lmr10]
+% [encoding=texnansi]
+% \definedfont[blabla] test \currentencoding/\fontfile \par
+% \definefontsynonym
+% [blabla]
+% [texnansi-lmtt10]
+% [encoding=texnansi]
+% \definedfont[blabla] test \currentencoding/\fontfile \par
+% \definefontsynonym
+% [blabla]
+% [ec-lmtt10]
+% [encoding=ec]
+% \definedfont[blabla] test \currentencoding/\fontfile \par
+
+\def\checkfontfilename
+ {\expandafter\docheckfontfilename\fontfile:\empty:\empty\relax}
+
+\def\docheckfontfilename#1:#2:#3#4\relax
+ {\edef\!!stringa{#1}%
+ \edef\!!stringb{#2}%
+ \ifx\!!stringb\empty
+ \edef\checkedfontfile{\!!stringa}%
+ \else\ifx\!!stringa\v!file
+ \edef\checkedfontfile{"\!!stringb"}%
+ \else\ifx\!!stringa\v!name
+ \edef\checkedfontfile{"\!!stringb"}%
+ \else
+ \edef\checkedfontfile{\!!stringb}%
+ \fi\fi\fi}
+
+% \definefontfeature[default] [liga=yes,texligatures=yes,texquotes=yes]
+% \definefontfeature[default-caps][liga=yes,texligatures=yes,texquotes=yes,smcp=yes,script=latn]
+%
+% \starttypescript [serif] [palatino-nova-regular] [name]
+% \definefontsynonym[Serif] [palatinonova-regular][features=default]
+% \definefontsynonym[SerifCaps][palatinonova-regular][features=default-caps] % also sets Serif
+% \stoptypescript
+%
+% \starttypescript [serif] [palatino-nova-regular] [name]
+% \definefontsynonym[Serif] [palatinonova-regular*default]
+% \definefontsynonym[SerifCaps] [palatinonova-regular*default-caps]
+% \stoptypescript
+
+% \definetypeface[mainface][rm][serif][palatino-nova-regular][default] \setupbodyfont[mainface]
+%
+% \starttext
+% ``Test'' -- --- ff fi fl \sc ``Test'' -- --- ff fi fl
+% \stoptext
+
+% \starttext
+% \definefont
+% [blabla]
+% [name:Latin Modern Something]
+% \definefont
+% [blabla]
+% [file:texnansi-lmr10]
+% \blabla test
+% \definefont
+% [blabla]
+% [texnansi-lmtt10]
+% \blabla test
+% \stoptext
+
+% \starttext
+%
+% \setupcolors[state=start]
+%
+% \definefontfeature
+% [default-base]
+% [script=latn,language=dflt,liga=yes,kern=yes,tlig=yes,trep=yes]
+% \definefontfeature
+% [default-node]
+% [script=latn,language=dflt,liga=yes,kern=yes,tlig=yes,trep=yes,mode=node]
+% \definefontfeature
+% [default-none]
+% [script=latn,language=dflt,liga=yes,kern=no, tlig=yes,trep=yes]
+%
+% \startoverlay
+% {\vtop{\color[red] {\font\test=name:lmroman12regular*default-node \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[green]{\font\test=name:lmroman12regular*default-base \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[blue] {\font\test=name:lmroman12regular*default-none \test \input ward \input zapf \input linden }}}
+% \stopoverlay
+%
+% \blank
+%
+% \startoverlay
+% {\vtop{\color[red] {\font\test=name:texgyrepagella*default-node \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[green]{\font\test=name:texgyrepagella*default-base \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[blue] {\font\test=name:texgyrepagella*default-none \test \input ward \input zapf \input linden }}}
+% \stopoverlay
+%
+% \blank
+%
+% \startoverlay
+% {\vtop{\color[red] {\font\test=name:palatinonovaregular*default-node \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[green]{\font\test=name:palatinonovaregular*default-base \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[blue] {\font\test=name:palatinonovaregular*default-none \test \input ward \input zapf \input linden }}}
+% \stopoverlay
+%
+% \startoverlay
+% {\vtop{\color[red] {\font\test=name:OfficinaSerifBookITC*default-node \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[green]{\font\test=name:OfficinaSerifBookITC*default-base \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[blue] {\font\test=name:OfficinaSerifBookITC*default-none \test \input ward \input zapf \input linden }}}
+% \stopoverlay
+%
+% \definefontfeature[superdefault][default][compose=yes]
+%
+% {\font\oeps=name:lmroman10regular*default at 30pt \oeps test \char7683}
+% {\font\oeps=name:lmroman10regular*superdefault at 30pt \oeps test \char7683}
+%
+% \stoptext
+
+\let\doshowcheckedfontfeatures\relax
+
+\def\showcheckedfontfeatures
+ {\def\doshowcheckedfontfeatures{\writestatus\m!fonts{checked: \checkedfontfile}}}
+
+\def\checkedfontfile{\fontfile} % default
+
+\newtoks\everydefinefont
+
+\def\donoparsefontspec % #1 == \cs
+ {\edef\fontfile{\truefontname\somefontname}%
+ \ifx\fontfile\s!unknown \let\fontfile\defaultfontfile \fi % can for instance happen with MathGamma
+ \updatefontparameters
+ \checkfontfilename
+ \edef\lastfontname{\checkedfontfile\somefontspec}%
+ \ifx\fontclass\empty
+ \expandafter\definefontlocal
+ \else
+ \expandafter\definefontglobal
+ \fi} % #1 == \cs
+
+\def\definefontlocal#1%
+ {\expandafter\edef\csname#1\endcsname % ! ! ! ! not needed in luatex ! ! ! !
+ {\noexpand\csname#1:\endcsname
+ \noexpand\reactivatefont{\somefontname}{\fontfile}}%
+ \expandafter\font\csname#1:\endcsname\lastfontname\relax
+ \expandafter\let\expandafter\lastrawfontcall\csname#1:\endcsname
+ \the\everydefinefont}
+
+\def\definefontglobal#1% stores \somefontname=Mono and \fontfile=cmtt10
+ {\expandafter\xdef\csname#1\endcsname % ! ! ! ! not needed in luatex ! ! ! !
+ {\noexpand\csname#1:\endcsname
+ \noexpand\reactivatefont{\somefontname}{\fontfile}}%
+ \global\expandafter\font\csname#1:\endcsname\lastfontname\relax
+ \expandafter\let\expandafter\lastrawfontcall\csname#1:\endcsname
+ \the\everydefinefont}
+
+\def\reactivatefont#1#2%
+ {\def\somefontname{#1}%
+ \def\fontfile {#2}%
+ \updatefontparameters}
+
+% can be handy for tracing purposes
+%
+% \def\reportfontdefinition
+% {\bgroup
+% \expanded{\infofont
+% [\lastfontidentifier
+% ->\newfontidentifier
+% ->\fontname\csname\newfontidentifier\endcsname]}%
+% \endgraf
+% \egroup}
+
+%D An additional the second \type {\font} definition can
+%D prevent fuzzy font refs
+%D
+%D \starttyping
+%D \expandafter\font\csname\dummyfontname\endcsname\lastfontname
+%D \stoptyping
+%D
+%D but somehow they changed \TEX\ so that it does not matter
+%D any more.
+
+\def \defaultfontfile{\truefontname{Normal}} % was cmtt10, but that one is gone
+\edef\nullfontname {\fontname\nullfont}
+\edef\dummyfontname {font\strippedcsname\\}
+
+%D \macros
+%D {everyfont,everyfontswitch}
+%D
+%D For special purposes, we provide a hook.
+
+% \newevery \everyfont \relax
+% \newevery \everyfontswitch \relax
+
+% safer but sometimes introducing newlines in the log
+%
+% \batchmode
+% \font\lastloadedfont\fontfile\somefontspec\relax
+% \errorstopmode
+% \edef\lastfontname{\fontname\lastloadedfont}%
+% \ifx\lastfontname\nullfontname
+% \showmessage\m!fonts{10}{\fontfile}%
+% \expandafter\font\csname#1\endcsname=\defaultfontfile\somefontspec\relax
+% \else
+% \expandafter\let\csname#1\endcsname\lastloadedfont
+% \fi
+
+%D We also accept \type{sa a}||\type{sa d} as specification.
+
+\def\checkfontscale#1#2\end#3%
+ {#3\ifcsname\??ft\s!default\noexpand#1\endcsname
+ \csname\??ft\s!default\noexpand#1\endcsname\else#1#2%
+ \fi#3}
+
+%D The duplicate font definition, using the ever the same dummy
+%D font name, results in less fuzzy error messages. In the log
+%D file, for instance when overfull boxes are reported, the
+%D simple keyword `font' replaces the \TEX\ ordinated name. The
+%D latter can be too misleading, due to the fact that \TEX\ has
+%D a rather optimized font memory management. Thanks to Taco
+%D for helping me sort this out.
+
+%D \macros
+%D {definefontsynonym, doifelsefontsynonym,
+%D expandfontsynonym, truefontname, truefontdata}
+%D
+%D While looking for fonts, fontsynonyms are used for accessing
+%D the files!
+%D
+%D \starttyping
+%D \definefontsynonym[Serif][Lucida-Bright]
+%D \definefontsynonym[Lucida-Bright][lbr][encoding=texnansi]
+%D \stoptyping
+%D
+%D The definitions can be accessed by:
+%D
+%D \startlines
+%D name: \type {\truefontname{Lucida-Bright}}
+%D data: \type {\truefontdata{\truefontname{Lucida-Bright}}}
+%D \stoplines
+
+% \def\definefontsynonym
+% {\dotripleempty\dodefinefontsynonym}
+%
+% \def\dodefinefontsynonym[#1][#2][#3]%
+% {\@EA\edef\csname\??ff\fontclass#1\endcsname{#2}%
+% \ifthirdargument
+% \edef\@@fontdata{#3}%
+% \ifx\@@fontdata\empty \else
+% \edef\@@fontfile{#2}%
+% \ifx\fontclass\empty
+% \getfontparameters
+% \else
+% \getglobalfontparameters
+% \fi
+% \fi
+% \fi}
+%
+% slightly faster, noticable when loading many typefaces,
+%
+% \testfeatureonce{5000}{\definefontsynonym[somefont][somename]} \end
+
+\def\classfont#1#2{#1#2} % \definefont[whatever][\classfont{xx}{yy} at 10pt]
+
+\def\definefontsynonym[#1]#2[#3]%
+ {\edef\@@fontfile{#3}%
+ \@EA\let\csname\??ff\fontclass#1\endcsname\@@fontfile
+ \doifnextoptionalelse\dodefinefontsynonym\donothing}
+
+\def\dodefinefontsynonym[#1]%
+ {\edef\@@fontdata{#1}%
+ \ifx\@@fontdata\empty \else \ifx\fontclass\empty
+ \getfontparameters
+ \else
+ \getglobalfontparameters
+ \fi \fi}
+
+\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater
+
+\def\setupfontsynonym
+ {\dodoubleempty\dosetupfontsynonym}
+
+\def\dosetupfontsynonym[#1][#2]%
+ {\edef\@@fontdata{#2}%
+ \ifx\@@fontdata\empty \else
+ \edef\@@fontfile{#1}%
+ \ifx\fontclass\empty
+ \getfontparameters
+ \else
+ \getglobalfontparameters
+ \fi
+ \fi}
+
+\def\truefontdata#1#2%
+ {\ifcsname\??ff#1#2\endcsname
+ % raw(Regular) raw(key)
+ \csname\??ff#1#2\endcsname
+ \else\ifcsname\??ff\fontclass#1\endcsname
+ % exp(palatino Regular) raw(key)
+ \expandafter\truefontdata\csname\??ff\fontclass#1\endcsname#2%
+ \else\ifcsname\??ff#1\endcsname
+ % exp(Regular) raw(key)
+ \expandafter\truefontdata\csname\??ff#1\endcsname#2%
+ \else\ifcsname\??ff#2\endcsname
+ % raw(key)
+ \csname\??ff#2\endcsname
+ \fi\fi\fi\fi}
+
+\def\truefontname#1%
+ {\ifcsname\??ff\fontclass#1\endcsname
+ \@EA\truefontname\csname\??ff\fontclass#1\endcsname
+ \else\ifcsname\??ff#1\endcsname
+ \@EA\truefontname\csname\??ff#1\endcsname
+ \else
+ #1%
+ \fi\fi}
+
+\def\expandfontsynonym#1#2% #2 := onelevelexpansion(#1)
+ {\ifcsname\??ff\fontclass#2\endcsname
+ \expandafter\def\expandafter#1\expandafter{\csname\??ff\fontclass#2\endcsname}%
+ \fi}
+
+\def\doifelsefontsynonym#1%
+ {\ifcsname\??ff\fontclass#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+% \definetypeface[palatino][rm][serif][palatino,allbold][default]
+%
+% \startfontclass[palatino]
+% \definefontsynonym [Serif] [SerifBold]
+% \definefontsynonym [SerifItalic] [SerifBoldItalic]
+% \definefontsynonym [SerifSlanted] [SerifBoldSlanted]
+% \definefontsynonym [SerifCaps] [SerifBold]
+% \stopfontclass
+%
+% \setupbodyfont[palatino]
+
+\def\startfontclass
+ {\dosingleempty\dostartfontclass}
+
+\def\dostartfontclass[#1]%
+ {\pushmacro\fontclass
+ \doifelse{#1}{\v!each}
+ {\let\fontclass\empty}
+ {\doifsomething{#1}{\def\fontclass{#1}}}}
+
+\def\stopfontclass
+ {\popmacro\fontclass}
+
+%D \macros
+%D {tracedfontname}
+%D
+%D A goody:
+
+\def\tracedfontencoding#1%
+ {\ifcsname\??ff#1\s!encoding\endcsname
+ \space[\csname\??ff#1\s!encoding\endcsname]%
+ \fi}
+
+\def\tracedfontname#1%
+ {\ifcsname\??ff\fontclass#1\endcsname
+ #1\tracedfontencoding{\fontclass#1}\space->\space
+ \@EA\tracedfontname\csname\??ff\fontclass#1\endcsname
+ \else\ifcsname\??ff#1\endcsname
+ #1\tracedfontencoding{#1}\space->\space
+ \@EA\tracedfontname\csname\??ff#1\endcsname
+ \else
+ #1%
+ \fi\fi}
+
+%D \macros
+%D {getfontfileparameters}
+%D
+%D For special purposes, one can use the next macro to
+%D access font file characteristics, for instance:
+%D
+%D \starttyping
+%D \getfontfileparameters{Regular}
+%D \stoptyping
+%D
+%D can result in:
+%D
+%D \starttyping
+%D \def\currentfontfileencoding{texnansi}
+%D \stoptyping
+
+% \def\@@currentfontfile{currentfontfile}
+%
+% \def\getfontfileparameters#1%
+% {\edef\fontdata{\truefontdata{\truefontname{#1}}}%
+% \expanded{\getparameters[\@@currentfontfile][\fontdata]}}
+
+\def\getfontfileparameters#1% can be simpler for mkii
+ {\edef\@@truefontname{\truefontname{#1}}%
+ \edef\currentfontfileencoding{\truefontdata\@@truefontname\s!encoding}%
+ \edef\currentfontfilemapping {\truefontdata\@@truefontname\s!mapping }%
+ \edef\currentfontfilehandling{\truefontdata\@@truefontname\s!handling}%
+ \edef\currentfontfilefeatures{\truefontdata\@@truefontname\s!features}}
+
+%D \macros
+%D {definefont}
+%D
+%D Before we implement the main definition macro, we first show
+%D one for local use:
+%D
+%D \starttyping
+%D \definefont[Some][LucidaBright at 100pt] \Some some
+%D \definefont[More][LucidaBright scaled 3000] \More more
+%D \definefont[Nice][LucidaBright mp 2] \Nice nice
+%D \definefont[Text][LucidaBright sa 5.4] \Text last
+%D \stoptyping
+%D
+%D The implementation looks as follows:
+
+\def\definefont
+ {\dotripleempty\dodefinefont}
+
+\def\dodefinefont[#1][#2][#3]% [name][spec][1.6 | line=10pt | setup_id]
+ {\doifinstringelse{ }{#2}
+ {\ifthirdargument
+ \unexpanded\setvalue{#1}{\redodefinefont{#1}{#2}{#3}}%
+ \else
+ \unexpanded\setvalue{#1}{\dododefinefont{#1}{#2}}%
+ \fi}
+ {\definefont[#1][#2 sa *][#3]}}
+
+\def\redodefinefont#1#2#3%
+ {\dododefinefont{#1}{#2}%
+ \doifsetupselse{#3}
+ {\setups[#3]} % don't forget to document this !
+ {\setuplocalinterlinespace[#3]%
+ \setupspacing}} % needed ?
+
+\def\definefrozenfont
+ {\dotripleempty\dodefinefrozenfont}
+
+\def\dodefinefrozenfont[#1][#2][#3]%
+ {\dodefinefont[#1][#2][#3]%
+ \expandafter\let\csname\lastfontidentifier\expandafter\endcsname\csname\rawfontidentifier\endcsname}
+
+% \def\defineclassfont
+% {\doquadrupleempty\dodefineclassfont}
+%
+% \def\dodefineclassfont[#1][#2][#3][#4]% #2 = class
+% {\iffourthargument
+% \definefont[#1][#2#3][#4]%
+% %\else\ifthirdargument
+% % \definefont[#1][#2#3]%
+% \else
+% \definefont[#1][#2]%
+% \fi}
+
+%D The \type {*} makes the switch local, so that we can redefine a
+%D logical name and/or change the size in between.
+
+\newif\ifautofontsize \autofontsizetrue
+
+\let\lastfontidentifier\empty
+
+\def\rawfontidentifier{**\lastfontidentifier\fontsize**}
+\def\newfontidentifier{*\fontclass\lastfontidentifier\fontsize*}
+
+% best we can add the style as well because otherwise we get math encoding mixups
+%
+% \setupbodyfont [8pt] [\currentencoding/\ccaron\scaron\zcaron]
+% \blank
+% \switchtobodyfont[7pt] [\currentencoding/\ccaron\scaron\zcaron]
+
+\def\newfontidentifier{*\fontclass\lastfontidentifier\fontstyle\fontsize*}
+
+\def\dododefinefont#1#2%
+ {\edef\lastfontidentifier{#1}%
+ \let\localrelativefontsize\defaultrelativefontsize
+ \let\localabsolutefontsize\fontbody
+ \parsefontspec{#2}\rawfontidentifier
+ \let\localrelativefontsize\defaultrelativefontsize % not needed
+ \csname\rawfontidentifier\endcsname
+ \autofontsizefalse
+ \setfontcharacteristics
+ \the\everyfontswitch}
+
+\def\xxdododefinefont#1#2#3#4% \autofontsizetrue is set by calling routine
+ {\edef\lastfontidentifier{#3}%
+ \ifcsname\newfontidentifier\endcsname\else
+ \def\localrelativefontsize{#1}%
+ \def\localabsolutefontsize{#2}%
+ \parsefontspec{#4}\newfontidentifier
+ \let\localrelativefontsize\defaultrelativefontsize % not needed
+ \fi
+ \csname\newfontidentifier\endcsname
+ \autofontsizefalse
+ %\edef\lastfontidentifier{#3}%
+ \ifskipfontcharacteristics \else
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \fi}
+
+%D I considered checking for mistakenly use of \PLAIN's
+%D \type{\magstep}'s but although it would take only a few
+%D lines of code, this would not add to consistent use. I
+%D therefore removed this check.
+
+%D \macros
+%D {mapfontsize}
+%D
+%D For special purposes, like in math, you may want to use
+%D slightly different sizes than the ones given. This happens
+%D for instance with the Math Times fonts. Mapped font sizes
+%D can be specified by using the \type {mo} key instead of
+%D \type {sa} in font definitions.
+%D
+%D \startbuffer
+%D \mapfontsize[10pt][11pt]
+%D \mapfontsize[11pt][12pt]
+%D \mapfontsize[12pt][13pt]
+%D
+%D \definefont[test][Serif]\test TEST \par
+%D \definefont[test][Serif sa 5]\test TEST \par
+%D \definefont[test][Serif mo 5]\test TEST \par
+%D \definefont[test][Serif sa d]\test TEST \par
+%D \definefont[test][Serif at 60pt]\test TEST \par
+%D \definefont[test][Serif scaled 6000]\test TEST \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startpacked
+%D \getbuffer
+%D \stoppacked
+
+\def\mapfontsize
+ {\dodoubleargument\domapfontsize}
+
+\def\domapfontsize[#1][#2]%
+ {\scratchdimen#1\relax % \relax is really needed here
+ \setvalue{\??ft*\the\scratchdimen}{#2}}
+
+\def\setmappedfontsize#1%
+ {\ifcsname\??ft*#1\endcsname
+ \csname\??ft*#1\endcsname
+ \else
+ #1%
+ \fi}
+
+%D \macros
+%D {getfontname}
+%D
+%D The names of the fonts can be called with the rather simple
+%D macro \type{\getfontname}. When for instance we pass
+%D \type{12ptrmtf} as argument, we get \getfontname{12ptrmtf}.
+
+\def\getfontname#1%
+ {\csname\??ft#1\endcsname}
+
+%D To be documented.
+
+\let\fontsizelist\empty
+\let\fontstylelist\empty
+
+\def\definefontsize[#1]% sneller met toks
+ {\addtocommalist{#1}\fontsizelist
+ \def\docommand##1%
+ {\def\dodocommand####1%
+ {\def\dododocommand########1%
+ %{\checkbodyfont{}{########1}{####1}{##1}}%
+ {\checkbodyfont{########1}{####1}{##1}}%
+ \processcommacommand[\fontstylelist]\dododocommand}%
+ \processcommacommand[\fontalternativelist]\dodocommand}%
+ \processcommacommand[\fontsizelist]\docommand}
+
+\def\fontalternativetextlist{\c!tf,\c!bf,\c!it,\c!sl,\c!bs,\c!bi,\c!sc}
+\def\fontalternativemathlist{\c!mr,\c!mi,\c!sy,\c!ex,\c!ma,\c!mb}
+
+\let\fontalternativelist\fontalternativetextlist % upward compatible
+
+%D \macros
+%D {currentfontscale,currentfontbodyscale}
+%D
+%D Sometimes we need to have access to the font scale
+%D including the \type{a}||\type{d} sizes. The next macro
+%D returns the current scaling factor. Take a look at
+%D \type {cont-log.tex} for an example of its use.
+
+\def\currentfontscale
+ {\csname\??ft\s!default
+ \ifcsname\??ft\s!default\xfontsize\endcsname \xfontsize \else
+ \ifcsname\??ft\s!default\s!text \endcsname \s!text \fi\fi
+ \endcsname}
+
+\def\currentfontbodyscale
+ {\csname\??ft\s!default
+ \ifcsname\??ft\s!default\fontsize\endcsname \fontsize \else
+ \ifcsname\??ft\s!default\s!text \endcsname \s!text \fi\fi
+ \endcsname}
+
+\setvalue{\??ft\s!default}{1}
+
+%D Both alternatives use \type {\xfontsize}, a macro that
+%D expands to the current size in terms of \type {a} \unknown
+%D \type {d}, nothing, or \type {x} \unknown \type {xx}.
+
+\def\xfontsize{\ifcase\currentxfontsize\fontsize\or\c!x\else\c!xx\fi}
+
+%D A typical use of this command is in commands that switch
+%D to another font bypassing the font mechanism:
+%D
+%D \starttyping
+%D \font\myfont=\truefontname{MyFont} at \currentfontscale\bodyfontsize
+%D \stoptyping
+
+%D Now we enter the area of font switching. The switching
+%D mechanism has to take care of several situations, like:
+%D
+%D \startitemize[packed]
+%D \item changing the overal document fonts (including margins,
+%D headers and footers)
+%D \item changing local fonts (only the running text)
+%D \item smaller and even more smaller alternatives (super-
+%D and subscripts)
+%D \stopitemize
+%D
+%D \TEX\ offers a powerfull family mechanism for super- and
+%D subscripts in math mode. In text mode however, we don't use
+%D families for the smaller alternatives, and therefore have
+%D to take care of it otherwise.
+
+%D \macros
+%D {definebodyfontenvironment,setupbodyfontenvironment}
+%D
+%D The relationship between the several sizes of a font, is
+%D defined by:
+%D
+%D \showsetup{definebodyfontenvironment}
+%D
+%D Later on we will see how these parameters are used, so for
+%D the moment we stick with an example:
+%D
+%D \starttyping
+%D \definebodyfontenvironment
+%D [12pt]
+%D [ text=12pt,
+%D script=9pt,
+%D scriptscript=7pt,
+%D x=10pt,
+%D xx=8pt,
+%D big=12pt,
+%D small=10pt]
+%D \stoptyping
+%D
+%D The first argument specifies the bodyfont size to which the
+%D settings apply. All second parameters are specified in
+%D dimensions and tell us more about related sizes.
+%D
+%D Afterwards, one can change values with
+%D
+%D \showsetup{setupbodyfontenvironment}
+%D
+%D Due to the fact that \type{\c!text} and \type{\s!text} can
+%D have a similar meaning, and therefore can lead to an
+%D unwanted loop, we temporary redefine \type{\c!text}. For
+%D the moment this in only place that some trickery is needed
+%D to fool the multilingual interface.
+%D
+%D When instead of a size the keyword \type{unknown} is
+%D passed, fractions (relations) are used instead of fixed
+%D sizes.
+
+\let\bodyfontenvironmentlist\empty
+
+\newcount\@@fontdefhack
+
+\def\@@beginfontdef
+ {\ifcase\@@fontdefhack
+ \let\k!savedtext \k!text \let\k!text \s!text
+ \let\k!k!savedtext \k!k!text \let\k!k!text \!!plusone
+ \let\k!saveddefault \k!default \let\k!default \s!default
+ \let\k!k!saveddefault\k!k!default \let\k!k!default \!!plusone
+ \fi
+ \advance\@@fontdefhack \plusone }
+
+\def\@@endfontdef
+ {\advance\@@fontdefhack \minusone
+ \ifcase\@@fontdefhack
+ \let\k!k!default\k!k!saveddefault
+ \let\k!default \k!saveddefault
+ \let\k!k!text \k!k!savedtext
+ \let\k!text \k!savedtext
+ \fi}
+
+\def\definebodyfontenvironment
+ {\dotripleempty\dodefinebodyfontenvironment}
+
+\def\dodefinebodyfontenvironment[#1][#2][#3]% class size settings
+ {\ifthirdargument
+ \@@beginfontdef
+ \doifelse{#2}\s!default
+ {\getparameters[\??ft\s!default][#3]}
+ {\normalizebodyfontsize#2\to\tempbodyfontsize
+ \addtocommalist\tempbodyfontsize\bodyfontenvironmentlist
+ \@EA\dododefinebodyfontenvironment\@EA[\tempbodyfontsize][#1][#3]}%
+ \@@endfontdef
+ \else
+ \definebodyfontenvironment[\fontclass][#1][#2]% change */*
+ \fi}
+
+\def\dododefinebodyfontenvironment[#1][#2][#3]% size class settings
+ {\@@beginfontdef
+ \doifundefined{\??ft#2#1\c!em} % \s!text goes wrong in testing because
+ {\def\docommand##1% % the 12pt alternative will called when
+ {\scratchdimen#1\relax % typesetting the test (or so)
+ \scratchdimen\csname\??ft\s!default##1\endcsname\scratchdimen
+ \normalizebodyfontsize\scratchdimen\to\tempbodyfontsize
+ \setevalue{\??ft#2#1##1}{\tempbodyfontsize}}%
+ \processcommacommand[\fontrelativesizelist]\docommand
+ \copyparameters
+ [\??ft#2#1][\??ft\s!default]
+ [\c!interlinespace,\c!em]}%
+ \getparameters[\??ft#2#1][#3]%
+ \@@endfontdef
+ % new code, see remark
+ \ifloadingfonts \else % only runtime
+ \doifundefined{\@size@#1} % only once
+ {\letvalue{\@size@#1}\empty % prevent loop
+ \defineunknownfont{#1}}% % safeguard
+ \fi
+ % so far
+ \setvalue{\@size@#1}{\docompletefontswitch[#1]}}
+
+%D {\bf Remark:} We need to cover the following cases,
+%D otherwise users can get confused:
+%D
+%D \starttyping
+%D \setupbodyfont[23pt]
+%D
+%D \definebodyfontenvironment[23pt]
+%D \setupbodyfont[23pt]
+%D
+%D \definebodyfontenvironment[23pt]
+%D \definebodyfont[23pt][rm,ss,tt][default]
+%D \setupbodyfont[23pt]
+%D \stoptyping
+
+%D Beware: while some font defs can be global, the bodyfont
+%D environment checks local. This means that multiple local
+%D checks resulting in definitions are not that efficient.
+%D So, apart from an occasional switch, one should define an
+%D environment at the outer level.
+
+\def\checkbodyfontenvironment[#1]%
+ {\definebodyfontenvironment[\fontclass][#1][]}
+
+% original
+%
+% \def\setupbodyfontenvironment
+% {\dotripleempty\dosetupbodyfontenvironment}
+%
+% \def\dosetupbodyfontenvironment[#1][#2][#3]% class size settings
+% {\@@beginfontdef
+% \ifthirdargument
+% \getparameters[\??ft#1#2][#3]%
+% \else
+% \getparameters[\??ft#1][#2]%
+% \fi
+% \@@endfontdef}
+%
+% this one already catches both define/setup
+
+\def\setupbodyfontenvironment{\definebodyfontenvironment}
+
+% officially, but not needed (yet):
+%
+% \def\dosetupbodyfontenvironment[#1][#2][#3]% class size settings
+% {\ifthirdargument
+% \localbodyfontsize#2\relax
+% \normalizebodyfontsize\localbodyfontsize\to\normalizedbodyfontsize
+% \doifundefinedelse{\??ft#1\normalizedbodyfontsize\c!em}
+% {\definebodyfontenvironment[#1][#2][#3]}%
+% {\getparameters[\??ft#1\normalizedbodyfontsize][#3]}%
+% \else
+% \localbodyfontsize#1\relax
+% \normalizebodyfontsize\localbodyfontsize\to\normalizedbodyfontsize
+% \doifundefinedelse{\??ft\normalizedbodyfontsize\c!em}
+% {\definebodyfontenvironment[#1][#2]}%
+% {\getparameters[\??ft\normalizedbodyfontsize][#2]}%
+% \fi}
+
+%D Just a couple of interface macros:
+
+\def\bodyfontvariable#1%
+ {\??ft\ifcsname\??ft\fontclass#1\endcsname\fontclass\fi#1}
+
+\def\bodyfontcsname
+ {\csname\bodyfontvariable}
+
+\def\bodyfontinterlinespecs
+ {\bodyfontvariable{\normalizedbodyfontsize\c!interlinespace}}
+
+\def\bodyfontinterlinespace
+ {\csname\bodyfontinterlinespecs\endcsname}
+
+%D We default all parameters to the main bodyfont size (begin
+%D \type{#1}), so the next setup is valid too:
+%D
+%D \starttyping
+%D \definebodyfontenvironment[24pt]
+%D \stoptyping
+%D
+%D All parameters can be redefined when needed, so one does
+%D not have to stick to the default ones.
+
+%D \macros
+%D {definebodyfont}
+%D
+%D The next step in defining a bodyfont involves the actual font
+%D files, which can be recognized by their extension
+%D \type{tfm}. Installing those file is often beyond the
+%D scope of the user and up to the system administrator.
+%D
+%D \showsetup{definebodyfont}
+%D
+%D This commands takes three arguments: a (series of) bodyfont
+%D size(s), the style group to which the definitions belong,
+%D and an alternative, as specified by the \TEX\ (math) families,
+%D extended with~a, b~\unknown.
+%D
+%D We show two examples, that show all the alternative
+%D scaling options. The \type{\tfa} alternatives can be
+%D extended with \type{\bfa}, \type{\slb}, etc. or even
+%D \type{e} and higher alternatives.
+%D
+%D \starttyping
+%D \definebodyfont [12pt] [rm]
+%D [tf=cmr12,
+%D bf=cmbx12,
+%D it=cmti12,
+%D sl=cmsl12,
+%D bi=cmbxti10 at 12pt,
+%D bs=cmbxsl10 at 12pt,
+%D tfa=cmr12 scaled \magstep1,
+%D tfb=cmr12 scaled \magstep2,
+%D tfc=cmr12 scaled \magstep3,
+%D tfd=cmr12 scaled \magstep4,
+%D sc=cmcsc10 at 12pt]
+%D
+%D \definebodyfont [12pt,11pt,10pt,9pt,8pt] [rm]
+%D [tf=lbr sa 1,
+%D bf=lbd sa 1,
+%D it=lbi sa 1,
+%D sl=lbsl sa 1,
+%D bi=lbdi sa 1,
+%D bs=lbdi sa 1,
+%D tfa=lbr sa 1.200,
+%D tfb=lbr sa 1.440,
+%D tfc=lbr sa 1.728,
+%D tfd=lbr sa 2.074,
+%D sc=lbr sa 0.833]
+%D \stoptyping
+%D
+%D The second example shows that we can define more sizes at
+%D once. The main difference between these examples is that the
+%D Computer Modern Roman come in many design sizes. This means
+%D that there we cannot define them in bulk using \type{sa}.
+%D Instead of \type{rm} (roman) one can define \type{ss} (sans
+%D serif), \type{tt} (teletype), \type{hw} (hand written),
+%D \type{cg} (calygraphic) and whatever styles.
+%D
+%D The first argument may be a comma separated list. This,
+%D combined with specifications using \type{sa} can save a lot
+%D of typing. Although all arguments should be specified, we
+%D treat the second argument as optional.
+%D
+%D Defining a bodyfont involves two actions: defining the
+%D specific style related alternatives, like \type{\rma},
+%D \type{\bfa} and \type{\rmsla}, and storing the definitions
+%D of their bodyfont size related fonts. The first step is
+%D bodyfont independant but executed every time. This permits
+%D user definitions like \type{\tfw} or \type{\bfq} for real
+%D large alternatives.
+
+\def\definebodyfont
+ {\doquadrupleempty\redefinebodyfont}
+
+\def\redefinebodyfont[#1][#2][#3][#4]%
+ {\iffourthargument
+ \processcommacommand[#1]{\reredefinebodyfont[#2][#3][#4]}%
+ \else
+ \dodefinebodyfont[#1][#2][#3]%
+ \fi}
+
+\def\reredefinebodyfont[#1][#2][#3]#4%
+ {\pushmacro\fontclass
+ \doifelse{#4}\s!default
+ {\let\fontclass\empty}
+ {\def\fontclass{#4}}%
+ \definebodyfont[#1][#2][#3]%
+ \popmacro\fontclass}
+
+\def\dodefinebodyfont[#1][#2][#3]% body|identifier style defs|identifier
+ {\ifthirdargument
+ \doifnumberelse{#1}
+ {\doifassignmentelse{#3}
+ {% [12pt] [style] [settings]
+ \doifundefined{#2}{\expanded{\definefontstyle[#2][#2]}}% new
+ \processcommalist[#1]{\dododefinebodyfont{#2}{#3}}}
+ {% [12pt] [style] [identifier]
+ \dodefinedefaultbodyfont[#1][#2][#3]}} % body style identifier
+ {% [identifier] [style] [settings] % see ***
+ \setvalue{\s!default#1#2}##1##2{\expanded{\xdodefinebodyfont[##1][##2][#3]}}}%
+ \else\ifsecondargument
+ \definebodyfont[#1][\c!rm][#2]%
+ \else
+ \doifundefined{\@size@#1} % Maybe there are default dependancies
+ {\defineunknownfont{#1}}% defined which we can use ([unknown])
+ \doifundefined{\@size@#1} % and if not, then we have at least to
+ {\definebodyfont[#1][\c!rm][]}% make sure some basics are set up.
+ \fi\fi}
+
+\def\xdodefinebodyfont[#1][#2][#3]% body|identifier style defs|identifier
+ {%\writestatus{[#1]}{[#2][#3]}%
+ \checkrelativefontsize{#2}% rather new, inherit from other defs
+ \ifundefined{#2}\expanded{\definefontstyle[#2][#2]}\fi % new
+ \processcommalist[#1]{\dododefinebodyfont{#2}{#3}}%
+ \let\relativefontsize\defaultrelativefontsize}
+
+\def\dododefinebodyfont#1#2#3% style defs body
+ {\checkbodyfontenvironment[#3]% just to be sure.
+ \processcommalist[#2]{\dodododefinebodyfont{#1}{#3}}}
+
+\def\dodododefinebodyfont#1#2#3% style body def
+ {\dododododefinebodyfont{#1}{#2}[#3]}
+
+\newif \ifresolvefontfile % protected by fontclass anyway
+
+\def\resolvefontname#1 {\truefontname{#1} }
+
+\def\iflocalclassfonts{\ifx\fontclass\empty}
+
+\def\dododododefinebodyfont#1#2[#3#4#5=#6]% style body def
+ {\ifundefined{#1#3#4#5}%
+ %\checkbodyfont{#2}{#1}{#3#4}{#5}% not \definefontsize[#5]
+ \checkbodyfont{#1}{#3#4}{#5}% not \definefontsize[#5]
+ \fi
+ \iflocalclassfonts
+ \letbeundefined{*\fontclass#2#1#3#4#5*}%
+ \scratchtoks{#6}%
+ \expanded{\unexpanded\noexpand\setvalue{#2#1#3#4#5}%
+ {\noexpand\xxdododefinefont{\relativefontsize}{#2}%
+ {#2#1#3#4#5}{\the\scratchtoks}}}%
+ \else
+ %\expanded{\writestatus{defining}{[\fontclass][#2#1#3#4#5] \resolvefontname#6 }}%
+ \global\letbeundefined{*\fontclass#2#1#3#4#5*}%
+ \ifresolvefontfile
+ \unexpanded\setxvalue{\fontclass#2#1#3#4#5}%
+ {\noexpand\xxdododefinefont{\relativefontsize}{#2}%
+ {#2#1#3#4#5}{\resolvefontname#6 }}%
+ \else
+ \scratchtoks{#6}%
+ \expanded{\unexpanded\noexpand\setgvalue{\fontclass#2#1#3#4#5}%
+ {\noexpand\xxdododefinefont{\relativefontsize}{#2}%
+ {#2#1#3#4#5}{\the\scratchtoks}}}%
+ \fi
+ \fi}
+
+% \def\checkbodyfont#1#2#3#4% body style alt size / gdef % #4 can be empty
+% {\def\c!!mm{#2}%
+% \ifx\c!!mm\c!mm % prevents \max and alike (re)defs
+% \unexpanded\setgvalue {#2}{\setcurrentfontstyle {#2}}% \rm
+% \unexpanded\setgvalue {#3}{\setcurrentfontalternative {#3}}% \sl
+% \else
+% \unexpanded\setgvalue {#2#4}{\setcurrentfontstylesize {#2}{#4}}% \rma
+% \unexpanded\setgvalue {#3#4}{\setcurrentfontalternativesize {#3}{#4}}% \sla
+% \unexpanded\setgvalue {#2#3#4}{\setcurrentfontstylealternativesize{#2}{#3}{#4}}% \rmsla
+% \unexpanded\setgvalue {#2}{\setcurrentfontstyle {#2}}% \rm
+% \unexpanded\setgvalue {#3}{\setcurrentfontalternative {#3}}% \sl
+% \unexpanded\setgvalue {#2\c!x}{\setcurrentfontxstylealternative {#2}}% \rmx
+% \unexpanded\setgvalue{#2\c!xx}{\setcurrentfontxxstylealternative {#2}}% \rmxx
+% \unexpanded\setgvalue {#3\c!x}{\setcurrentfontxalternative {#3}}% \slx
+% \unexpanded\setgvalue{#3\c!xx}{\setcurrentfontxxalternative {#3}}% \slxx
+% \unexpanded\setgvalue {#2#3}{\setcurrentfontstylealternative {#2}{#3}}% \rmsl
+% \fi}
+%
+% leaner
+
+\def\checkbodyfont#1% tests for ttsl mmbf
+ {\def\c!!mm{#1}%
+ \ifx\c!!mm\c!mm % prevents \max and alike (re)defs
+ \expandafter\checkmathbodyfont
+ \else
+ \expandafter\checktextbodyfont
+ \fi{#1}} % no \c!!mm, not expanded later on
+
+\def\checkmathbodyfont#1#2#3% style alt size / gdef % #3 can be empty
+ {%\message{!m #1 #2 #3!}%
+ % #1 #2 #3 = signal
+ \unexpanded\setgvalue {#1#2#3}{\setcurrentfontstylealternativesize{#1}{#2}{#3}}% \mmsla
+ \unexpanded\setgvalue {#1}{\setcurrentfontstyle {#1}}% \mm
+ \unexpanded\setgvalue {#2}{\setcurrentfontalternative {#2}}}% \sl
+
+\def\checktextbodyfont#1#2#3% style alt size / gdef % #3 can be empty
+ {%\message{!t #1 #2 #3!}%
+ \unexpanded\setgvalue {#1#3}{\setcurrentfontstylesize {#1}{#3}}% \rma
+ \unexpanded\setgvalue {#2#3}{\setcurrentfontalternativesize {#2}{#3}}% \sla
+ \unexpanded\setgvalue {#1#2#3}{\setcurrentfontstylealternativesize{#1}{#2}{#3}}% \rmsla
+ \unexpanded\setgvalue {#1}{\setcurrentfontstyle {#1}}% \rm
+ \unexpanded\setgvalue {#2}{\setcurrentfontalternative {#2}}% \sl
+ \unexpanded\setgvalue {#1\c!x}{\setcurrentfontxstylealternative {#1}}% \rmx
+ \unexpanded\setgvalue{#1\c!xx}{\setcurrentfontxxstylealternative {#1}}% \rmxx
+ \unexpanded\setgvalue {#2\c!x}{\setcurrentfontxalternative {#2}}% \slx
+ \unexpanded\setgvalue{#2\c!xx}{\setcurrentfontxxalternative {#2}}% \slxx
+ \unexpanded\setgvalue {#1#2}{\setcurrentfontstylealternative {#1}{#2}}}% \rmsl
+
+\def\dodefinedefaultbodyfont[#1][#2][#3]% sizes styles identifier
+ {\def\dododefinedefaultbodyfont##1%
+ {\def\dodododefinedefaultbodyfont####1%
+ {\def\dododododefinedefaultbodyfont########1%
+ {\doifdefined{\s!default########1####1}
+ {% [12pt] [style] [identifier]
+ \getvalue{\s!default########1####1}{##1}{####1}}}%
+ \processcommalist[#3]\dododododefinedefaultbodyfont}%
+ \processcommalist[#2]\dodododefinedefaultbodyfont}%
+ \processcommalist[#1]\dododefinedefaultbodyfont}
+
+%D Unknown families are added to the family list! For the
+%D moment we also set the direct calls here. Some day a better
+%D solution will be implemented. The good news is that unknown
+%D fonts are defined automatically.
+
+\newif\ifdefiningunknownfont
+
+% \def\defineunknownfont#1%
+% {\let\c!savedtext\c!text
+% \let\c!text\s!text
+% \donefalse
+% \def\docommand##1%
+% {\doifdefined{\??ft\s!default##1}
+% {\donetrue
+% \scratchdimen#1\relax
+% \scratchdimen\csname\??ft\s!default##1\endcsname\scratchdimen
+% \normalizebodyfontsize\scratchdimen\to\!!stringa
+% \letvalue{\??ft#1##1}\!!stringa}}%
+% \processcommacommand[\fontrelativesizelist]\docommand
+% \let\c!text\c!savedtext
+% \ifdone
+% \donefalse
+% \def\defineunknownbodyfont##1% see ***
+% %{\doifdefined{\s!default##1}
+% % {\donetrue\getvalue{\s!default##1}{#1}}}%
+% {\doifdefined{\s!default\s!default##1}
+% {\donetrue\getvalue{\s!default\s!default##1}{#1}{##1}}}%
+% \processcommacommand
+% [\fontstylelist]
+% \defineunknownbodyfont
+% \ifdone
+% \setvalue{\@size@#1}{\docompletefontswitch[#1]}%
+% \ifdefiningunknownfont \else
+% \definingunknownfonttrue
+% \def\defineunknownsubfont##1%
+% {\doifundefined{\@size@\getvalue{\??ft#1##1}}
+% {\defineunknownfont{\getvalue{\??ft#1##1}}}}%
+% \processcommacommand[\fontrelativesizelist]\defineunknownsubfont
+% \definingunknownfontfalse
+% \fi
+% \fi
+% \ifdone
+% \showmessage\m!fonts{14}{#1}%
+% \fi
+% \fi}
+
+\def\dodefineunknownfont#1#2%
+ {\doifdefined{\??ft\s!default#2}
+ {\donetrue
+ \scratchdimen#1\relax
+ \scratchdimen\csname\??ft\s!default#2\endcsname\scratchdimen
+ \normalizebodyfontsize\scratchdimen\to\!!stringa
+ \letvalue{\??ft#1#2}\!!stringa}}
+
+% \def\dodefineunknownbodyfont#1#2% see ***
+% {\doifdefined{\s!default\s!default#2}
+% {\donetrue
+% \getvalue{\s!default\s!default#2}{#1}{#2}}}
+%
+% but ... it needs to be as follows:
+%
+% \def\dodefineunknownbodyfont#1#2% see ***
+% {\doifdefined{\s!default\fontclass#2}% was \s!default\s!default (related to change */*)
+% {\donetrue
+% \getvalue{\s!default\fontclass#2}{#1}{#2}}}
+%
+% eh ... this does not work so we revert back to:
+
+\def\dodefineunknownbodyfont#1#2% see ***
+ {\doifdefined{\s!default\s!default#2}% somehow related to */*
+ {\donetrue
+ \getvalue{\s!default\s!default#2}{#1}{#2}}}
+
+\def\dodefineunknownsubfont#1#2%
+ {\doifundefined{\@size@\getvalue{\??ft#1#2}}
+ {\donetrue
+ \defineunknownfont{\getvalue{\??ft#1#2}}}}
+
+\def\defineunknownfont#1%
+ {\let\c!savedtext\c!text
+ \let\c!text\s!text
+ \donefalse
+ \processcommacommand[\fontrelativesizelist]{\dodefineunknownfont{#1}}%
+ \let\c!text\c!savedtext
+ \ifdone
+ \donefalse
+ \processcommacommand
+ [\fontstylelist]
+ {\dodefineunknownbodyfont{#1}}%
+ \ifdone
+ \donefalse
+ \setvalue{\@size@#1}{\docompletefontswitch[#1]}%
+ \ifdefiningunknownfont \else
+ \definingunknownfonttrue
+ \processcommacommand[\fontrelativesizelist]{\dodefineunknownsubfont{#1}}%
+ \definingunknownfontfalse
+ \fi
+ \fi
+ \ifdone
+ \showmessage\m!fonts{14}{#1}%
+ \fi
+ \fi}
+
+% \def\defineunknownfontstyles#1%
+% {\def\defineunknownbodyfont##1% see ***
+% {\executeifdefined{\s!default\s!default##1}\gobbletwoarguments{#1}{##1}}%
+% \rawprocesscommacommand[\fontstylelist]\defineunknownbodyfont}
+
+%D These macros show that quite some definitions take place.
+%D Fonts are not loaded yet! This means that at format
+%D generation time, no font files are preloaded.
+
+%D A previous implementation used:
+%D
+%D \starttyping
+%D \type {\setvalue{name}{\donottest...}}
+%D \stoptyping
+%D
+%D instead of the more memory hungry:
+%D
+%D \starttyping
+%D \unexpanded\setvalue{name}{...}
+%D \stoptyping
+%D
+%D The first alternative saves about 500 hash entries (about
+%D 2.5\% of the total number of entries used. The second
+%D alternative is currently used, because that one can more
+%D easily be made \ETEX\ aware.
+
+%D \macros
+%D {everybodyfont,Everybodyfont,everyglobalbodyfont}
+%D
+%D Every change in bodyfont size has conseqences for the baseline
+%D distance and skips between paragraphs. These are initialized
+%D in other modules. Here we only provide the hooks that
+%D garantees their handling.
+
+% \ifx\everybodyfont\undefined % permits reloading
+% \newevery \everybodyfont \EveryBodyFont
+% \fi
+
+%D At the system level one can initialize thing like:
+%D
+%D \starttyping
+%D \appendtoks \setupspacing \to \everybodyfont
+%D \stoptyping
+%D
+%D While users can add their own non standard commands like:
+%D
+%D \starttyping
+%D \EveryBodyFont{\message{changing to bodyfont \the\bodyfontsize}}
+%D \stoptyping
+%D
+%D Personnaly I never felt the need for such extensions, but
+%D at least its possible.
+
+%D \macros
+%D {globalbodyfontsize,localbodyfontsize}
+%D
+%D Next we'll do the tough job of font switching. Here we
+%D have to distinguish between the global (overal) bodyfont
+%D size and the local (sometimes in the textflow) size. We
+%D store these dimensions in two \DIMENSION\ registers.
+
+\ifdefined\globalbodyfontsize\else \newdimen\globalbodyfontsize \fi \globalbodyfontsize=12pt
+\ifdefined\localbodyfontsize \else \newdimen\localbodyfontsize \fi \localbodyfontsize =\globalbodyfontsize
+
+%D \macros
+%D {bodyfontsize}
+%D
+%D These two registers are not to be misused in calculations.
+%D For this purpose we keep a copy:
+
+\newdimen\bodyfontsize \bodyfontsize=\globalbodyfontsize
+
+%D \macros
+%D {outputresolution}
+%D
+%D Sometimes (to be honest: not in this module) we need to
+%D take the system resolution into account. Therefore we also
+%D define a macro:
+
+\def\outputresolution {600}
+
+%D \macros
+%D {bodyfontfactor,bodyfontpoints}
+%D
+%D For multiplication purposes we keep an auxiliary counter
+%D and macro (here the expansion is not explicitly needed):
+
+\newcount\bodyfontpoints \dimensiontocount\bodyfontsize\bodyfontpoints
+
+\edef\bodyfontfactor{\withoutpt\the\bodyfontsize}
+
+%D When we assign for instance 12pt to a \DIMENSION\ register
+%D the \type{\the}'d value comes out as 12.0pt, which is
+%D often not the way users specify the bodyfont size. Therefore
+%D we also store the normalized value.
+
+\chardef\fontdigits=2 % was 1
+
+% \def\normalizebodyfontsize#1\to#2%
+% {\scratchdimen#1\relax
+% \ifcase\fontdigits\advance\scratchdimen.5\points\fi
+% \@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\scratchdimen00\to#2}
+%
+% \def\donormalizedbodyfontsize#1.#2#3#4\to#5% \points ?
+% {\edef#5%
+% {#1%
+% \ifcase\fontdigits\or
+% \ifcase#2 \else.#2\fi % and not: \ifcase#2\else ...
+% \else
+% \ifcase#2#3 \else.#2\ifcase#3 \else#3\fi\fi % not: \ifcase#2#3\else ...
+% \fi
+% \s!pt}}
+
+\def\normalizebodyfontsize#1\to#2%
+ {\scratchdimen\dimexpr#1+\ifcase\fontdigits.5\or.05\or.005\fi\points\relax
+ \@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\scratchdimen000\to#2}
+
+\def\donormalizedbodyfontsize#1.#2#3#4#5\to#6% \points ?
+ {\edef#6% not \ifcase#2\else due to \relax adding
+ {#1%
+ \ifcase\fontdigits
+ \or \ifcase#2 \else .#2\fi % 1
+ \or \ifcase#2#3 \else .#2\ifcase#3 \else #3\fi\fi % 2
+ \else \ifcase#2#3#4 \else .#2\ifcase#4 \ifcase#3 \else#3\fi \else#3#4\fi\fi % 3
+ \fi
+ \s!pt}}
+
+%D To be internationalized:
+
+\def\korpsgrootte {\bodyfontsize}
+\def\korpspunten {\bodyfontpoints}
+
+%D some day.
+
+%D \macros
+%D {fontstyle,fontalternative,fontsize}
+%D
+%D Within a bodyfont, fonts can come in different sizes. For
+%D instance \type{\tf} is accompanied by \type{\tfa},
+%D \type{\tfb} etc. The first two characters denote the
+%D alternative, while the third character in these sequences
+%D represents the size. The actual size is saved in a macro
+%D
+%D The style, being roman (\type{\rm}), sans serif (\type{\ss})
+%D etc. is also available in a macro in \type{rm}, \type{ss}
+%D etc. form:
+
+\let\defaultfontalternative = \c!tf
+\let\defaultfontstyle = \empty
+\let\defaultfontsize = \empty
+
+\let\fontalternative = \defaultfontalternative
+\let\fontstyle = \defaultfontstyle
+\let\fontsize = \defaultfontsize
+
+%D {\em The following approach is obsolete.}
+%D
+%D All things related to fonts are grouped into files with
+%D names like \type{font-cmr}. These files are loaded by:
+
+\def\resetfontdefinitionfile[#1]%
+ {\letbeundefined{\c!file\f!fontprefix#1}}
+
+\newif\ifloadfontfileonce
+
+\def\doreadfontdefinitionfile#1#2% #1 = set/switch state
+ {\doifundefined{\c!file\f!fontprefix#2}%
+ {\ifloadfontfileonce
+ \letvalue{\c!file\f!fontprefix#2}\empty
+ \fi
+ \makeshortfilename[\truefilename{\f!fontprefix#2}]%
+ \startreadingfile
+ \readsysfile{\shortfilename.mkii}
+ {\showmessage\m!fonts2{#2}}
+ {\showmessage\m!fonts3{#2}}%
+ \stopreadingfile}}
+
+%D When \type {\loadfontfileoncetrue}, such files are
+%D only loaded once! This permits redundant loading, but at
+%D the same time forced grouping when we want continuously mix
+%D all kind of font, which of course is a kind of
+%D typographically sin. The \type{"} is made inactive if
+%D needed to prevent problems with loading files that use this
+%D character in numbers.
+
+\def\doswitchpoints[#1]%
+ {\expanded{\dodoswitchpoints{#1}}}
+
+\def\dodoswitchpoints#1%
+ {\doifundefined{\@size@#1}
+ {\defineunknownfont{#1}}%
+ %\defineunknownfontstyles{#1}%
+ \doifdefinedelse{\@size@#1}
+ {\getvalue{\@size@#1}%
+ \localbodyfontsize#1\relax
+ \normalizebodyfontsize\localbodyfontsize\to\normalizedbodyfontsize
+ \checkbodyfontenvironment[\normalizedbodyfontsize]}
+ {\showmessage\m!fonts4{#1}}}
+
+\unprotected \def\doswitchstyle[#1]%
+ {\doifdefinedelse{\@style@#1}
+ {\getvalue{\@style@#1}%
+ \edef\fontstyle{#1}%
+ \ifmmode\mr\fi % in order to be compatible with \rm in math mode
+ }% \the\everybodyfont} % cleaner, in setting size as well as style
+ {\showmessage\m!fonts5{#1}}}
+
+%D \TEX\ loads font metric files like \type{cmr10.tfm} and
+%D \type{tir.tfm} only once. In \PLAIN\ \TEX\ some font files
+%D are {\em preloaded}. This means that the font files are
+%D loaded, but not accessible yet by name. This is accomplished
+%D by saying:
+%D
+%D \starttyping
+%D \font\preloaded=cmr10 at 11pt
+%D \stoptyping
+%D
+%D and using the name \type{\preloaded} again and again, so
+%D fonts are indeed loaded, but unnamed, and therefore
+%D unaccessible. In \CONTEXT\ we don't preload fonts, not even
+%D the \PLAIN\ \TEX\ ones, although users can access them. Now
+%D why is this done?
+
+%D Defining fonts using \type{\definebodyfont} takes time, so we
+%D prefer to predefine at least the Computer Modern Roman
+%D fonts. However, loading all those fonts at definition time
+%D would take both time and space. But even worse, once fonts
+%D are loaded into memory, their encoding vector is fixed,
+%D which is a handicap when we want to distribute the compact
+%D \type{fmt} files. So what we want to do is defining fonts in
+%D a way that postpones the loading. We accomplish this by only
+%D loading the fonts when we switch to another bodyfont size.
+%D Among the other alternatives, such as loading the font at
+%D the moment of activation and redefining the activation
+%D macro afterwards, this proved to be the most efficient
+%D alternative.
+%D
+%D The next few macros take care of the one exeption on this
+%D scheme. When at format generation time we load the default
+%D font file, the one that defines the Computer Modern Fonts,
+%D we don't want the fonts metrics to end up in the format
+%D file, so we temporary prohibit loading. This means that at
+%D runtime we have to load the default bodyfont size just before
+%D we start typesetting.
+%D
+%D Therefore we have to signal the font switching macros that
+%D we are preloading fonts. As long as the next boolean is,
+%D true, no loading is done.
+
+\newif\ifloadingfonts \loadingfontstrue
+
+%D \macros
+%D {preloadfonts}
+%D
+%D Preloading is only called for once, during the startup
+%D sequence of a session. After the loading job is done, the
+%D macro relaxes itself and reset the signal.
+
+\def\preloadfonts % never called, needs a clean up
+ {\showmessage\m!fonts6{\normalizedbodyfontsize\normalspace\fontstyle}%
+ \global\loadingfontsfalse
+ \doswitchpoints[\normalizedbodyfontsize]%
+ \doswitchstyle[\fontstyle]%
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace
+ \global\let\preloadfonts\relax}
+
+% \prependtoks \preloadfonts \to \everydump % saves .1 s on a DELL P60 - 2GHZ
+
+%D Here comes the main font switching macros. These macros
+%D handle changes in size as well as returning to the global
+%D bodyfont size.
+
+\def\dosetfont#1#2% #1 = set/switch state
+ {\doifelse{#2}\v!global
+ {\restoreglobalbodyfont}
+ {\processcommacommand[#2]{\dodosetfont{#1}}% ##1 get also passed
+ \ifloadingfonts\else
+ \doswitchpoints[\normalizedbodyfontsize]%
+ \doswitchstyle[\fontstyle]%
+ \fi}%
+ \chardef\currentxfontsize\zerocount}
+
+\def\dodosetfont#1#2% #1 = set/switch state | check fo rempty, else space
+ {\doifsomething{#2}{\dododosetfont{#1}{#2}{\showmessage\m!fonts4{#2}}}}
+
+\def\dododosetfont#1#2#3% #1 = set/switch state
+ {\doifnumberelse{#2}
+ {\dodododosetfont{#1}{#2}{#3}}
+ {\doifdefinedelse{\??ft\normalizedbodyfontsize\interfaced{#2}}
+ {\edef\fontstep{\bodyfontcsname\normalizedbodyfontsize\interfaced{#2}\endcsname}%
+ \expanded{\dodododosetfont{#1}{\fontstep}}{#3}}
+ {\doifelse{#2}\v!reset
+ {\let\fontstyle\empty % new 31/7/2006
+ \let\fontsize \empty}
+ {\doifdefinedelse{\@style@#2}
+ {\edef\fontstyle{#2}}
+ {\doreadfontdefinitionfile{#1}{#2}}}}}}
+
+\def\dodododosetfont#1#2#3% #1 = set/switch state
+ {\scratchdimen#2\relax
+ \normalizebodyfontsize\scratchdimen\to\normalizedsetfont
+ \doifundefined{\@size@\normalizedsetfont}
+ {\defineunknownfont{#2}}%
+ \doifdefinedelse{\@size@\normalizedsetfont}
+ {\localbodyfontsize\normalizedsetfont
+ \let\normalizedbodyfontsize\normalizedsetfont}
+ {#3\dosetsubstitutefont{#1}{#2}}}
+
+%D In the previous macros we use \type{\currentxfontsize} to
+%D hold the current x||size of the font. This enables us to
+%D support for instance \type{\sl} inside a \type{\tx} switch.
+
+\chardef\currentxfontsize=0
+
+%D When users specify for instance a 13 point bodyfont while no
+%D such bodyfont is defined, the system automatically tries to
+%D find a best fit, that is the nearest smaller defined
+%D bodyfontzize. A smaller one is definitely better than a larger
+%D one, simply because otherwise a lot of overfull box messages
+%D are more probable to occur. By taking a value slightly
+%D smaller than half a point, we can use the next method.
+
+\def\dosetsubstitutefont#1#2% #1 = set/switch state
+ {\scratchdimen#2\relax
+ \advance\scratchdimen .499\points
+ \dimensiontocount\scratchdimen\scratchcounter
+ \advance\scratchcounter \minusone
+ \ifnum\scratchcounter>\plusthree
+ \dododosetfont{#1}{\the\scratchcounter\s!pt}{}%
+ \fi}
+
+% The following bunch of macros deals with the (run time)
+% expansion of names onto the definitions made by \type
+% {\definebodyfont}.
+
+% \let\fontbody \empty % ... 10pt 11pt 12pt ...
+% \let\fontstyle \empty % rm ss tt mm hw cg ...
+% \let\fontalternative\empty % tf bf sl it bs bi sc ...
+% \let\fontsize \empty % xy-abcd ...
+
+\def\defaultfontbody{\normalizedbodyfontsize}
+
+\let\fontbody\defaultfontbody
+
+\let\fontclass\empty \let\globalfontclass\fontclass
+
+% \def\setcurrentfontclass#1%
+% {\edef\fontclass{#1}}
+
+\def\registerfontclass#1%
+ {\letgvalue{\@fontclass@#1}\v!yes} % global ?
+
+\def\setcurrentfontclass#1%
+ {\ifcsname\@fontclass@#1\endcsname
+ \edef\fontclass{#1}%
+ \fi}
+
+\let\defaultfontstyle \c!rm
+\let\defaultfontalternative \c!tf
+\let\defaultfontsize \empty
+
+%D \macros
+%D {bigmath,nobigmath}
+%D
+%D We can inhibit this slow||downer with:
+
+% these can best be combined
+
+% 0=never 1=everymath 2=always
+
+\chardef\synchronizebigmathflag=1
+
+\appendtoks
+ \ifcase\synchronizebigmathflag
+ % never
+ \or
+ \synchronizebigmath
+ \or
+ % always
+ \fi
+\to \everymathematics
+
+\def\nobigmath{\chardef\synchronizebigmathflag 0 }
+\def\bigmath {\chardef\synchronizebigmathflag 2 \synchronizebigmath}
+
+\let\bigmathfontsize\empty
+
+\def\synchronizebigmath
+ {\ifx\bigmathfontsize\fontsize
+ % already in sync
+ \else
+ \let\bigmathfontsize\fontsize
+ \synchronizemath \synchronizetext
+ \fi}
+
+\def\checkbigmathsynchronization
+ {\ifcase\synchronizebigmathflag
+ % never
+ \or
+ \ifmmode \synchronizebigmath \fi
+ \or
+ \synchronizebigmath
+ \fi}
+
+%D So far for synchronisation.
+
+\def\dosetcurrentfontsize#1%
+ {\edef\fontsize{#1}%
+ \checkbigmathsynchronization}
+
+\def\dosetcurrentfontalternative#1%
+ {\edef\fontalternative{#1}%
+ \ifmmode % maybe no test, or actually, an option
+ \fam\csname\fontalternative\s!fam\endcsname
+ \fi}
+
+\def\setcurrentfont#1#2#3#4%
+ {%\message{[1 #1 #2 #3 #4]}%
+ \edef\fontbody{#1}%
+ \edef\fontstyle{#2}%
+ \dosetcurrentfontalternative{#3}%
+ \dosetcurrentfontsize{#4}%
+ \synchronizefont}
+
+\def\setcurrentfontbody#1%
+ {%\message{[2 #1]}%
+ \edef\fontbody{#1}%
+ \synchronizefont}
+
+% \def\setcurrentfontstyle#1%
+% {%\message{[3 #1]}%
+% \edef\fontstyle{#1}%
+% \ifmmode\mr\fi % otherwise \rm not downward compatible
+% \synchronizefont}
+%
+% For Taco: optional fall backs:
+
+\ifx\checkfontclass\undefined \let\checkfontclass\gobbleoneargument \fi % implemented in type-ini
+
+\def\setcurrentfontstyle#1%
+ {%\message{[3 #1]}%
+ \checkfontclass{#1}%
+ \edef\fontstyle{#1}%
+ \ifmmode\mr\fi % otherwise \rm not downward compatible
+ \synchronizefont}
+
+\def\setcurrentfontbodyalternative#1#2%
+ {%\message{[4 #1 #2]}%
+ \edef\fontbody{#1}%
+ \dosetcurrentfontalternative{#2}%
+ \synchronizefont}
+
+\def\setcurrentfontalternative#1%
+ {%\message{[5 #1]}%
+ \dosetcurrentfontalternative{#1}%
+ \synchronizefont}
+
+\def\setcurrentfontsize#1%
+ {%\message{[6 #1]}%
+ \dosetcurrentfontsize{#1}%
+ \synchronizefont}
+
+\def\setcurrentfontstylealternative#1#2% \rmsl
+ {%\message{[7 #1 #2]}%
+ \edef\fontstyle{#1}%
+ \dosetcurrentfontalternative{#2}%
+ \synchronizefont}
+
+\def\setcurrentfontstylesize#1#2% \rmsla
+ {%\message{[8 #1 #2]}%
+ \edef\fontstyle{#1}%
+ \dosetcurrentfontsize{#2}%
+ \synchronizefont}
+
+\def\setcurrentfontalternativesize#1#2% \sla
+ {%\message{[9 #1 #2]}%
+ \dosetcurrentfontalternative{#1}%
+ \dosetcurrentfontsize{#2}%
+ \synchronizefont}
+
+\def\setcurrentfontstylealternativesize#1#2#3% \rmsla
+ {%\message{[10 #1 #2 #3]}%
+ \edef\fontstyle{#1}%
+ \dosetcurrentfontalternative{#2}%
+ \dosetcurrentfontsize{#3}%
+ \synchronizefont}
+
+%D In principle one can assign alternative fallback routines.
+%D Some day we will.
+
+\newtoks\fontstrategies
+\newif\iftryingfont
+
+\let\fontstrategy\relax
+
+\def\synchronizefont
+ {\tryingfonttrue
+ \ifx\fontclass\empty\else
+ \global\let\fontstrategy\dofontclassstrategy
+ \the\fontstrategies \relax % \relax still needed ?
+ \fi
+ \iftryingfont
+ \global\let\fontstrategy\dofontstrategy
+ \the\fontstrategies \relax % \relax still needed ?
+ \fi
+ \ifskipfontcharacteristics
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \fi}
+
+\def\dofontstrategy#1#2#3#4#5%
+ {\ifcsname#2#3#4#5\endcsname
+ #1\csname#2#3#4#5\endcsname \tryingfontfalse
+ \fi}
+
+\def\dofontclassstrategy#1#2#3#4#5%
+ {\ifcsname\fontclass#2#3#4#5\endcsname
+ #1\csname\fontclass#2#3#4#5\endcsname \tryingfontfalse
+ \fi}
+
+\appendtoks \iftryingfont \fontstrategy \autofontsizefalse % --- --- --- --- % pt tt bf a
+ \fontbody \fontstyle \fontalternative \fontsize
+\fi \to \fontstrategies
+
+\appendtoks \iftryingfont \fontstrategy \autofontsizetrue % --- --- --- def % pt tt bf
+ \fontbody \fontstyle \fontalternative \defaultfontsize
+\fi \to \fontstrategies
+
+\appendtoks \iftryingfont \fontstrategy \autofontsizetrue % --- --- def --- % pt tt tf a
+ \fontbody \fontstyle \defaultfontalternative \fontsize
+\fi \to \fontstrategies
+
+\appendtoks \iftryingfont \fontstrategy \autofontsizetrue % --- --- def def % pt tt tf
+ \fontbody \fontstyle \defaultfontalternative \defaultfontsize
+\fi \to \fontstrategies
+
+\appendtoks \iftryingfont \fontstrategy \autofontsizefalse % --- def def def % pt rm tf
+ \fontbody \defaultfontstyle \defaultfontalternative \defaultfontsize
+\fi \to \fontstrategies
+
+\appendtoks \iftryingfont \fontstrategy \autofontsizetrue % def def def def % rm tf
+ \defaultfontbody \defaultfontstyle \defaultfontalternative \defaultfontsize
+\fi \to \fontstrategies
+
+%D Let's synchronize:
+
+\newif\ifsynchronizefonts \synchronizefontstrue
+
+\prependtoks
+ \ifsynchronizefonts
+ \synchronizemath
+ \synchronizetext
+ \synchronizefont % problem: syncs last font
+ \fi
+\to \everybodyfont
+
+%D Setting the normal sized as well as the x and xx smaller
+%D sizes is accomplished by the next set of macros. When in
+%D math mode, the commands \type{\tx} and \type{\txx} are
+%D just a switch to the script and double script styles, but
+%D in text mode the values defined by the bodyfontenvironment are
+%D used. Here we also set \type{\currentxfontsize}.
+
+\def\dosetcurrentfontxxxalternative#1#2#3#4%
+ {\chardef\currentxfontsize#2\relax
+ \ifmmode
+ #4%
+ \else\ifcsname\bodyfontvariable{\normalizedbodyfontsize#3}\endcsname
+ \setcurrentfontbodyalternative{\bodyfontcsname\normalizedbodyfontsize#3\endcsname}{#1}%
+ \fi\fi}
+
+\def\setcurrentfontxalternative#1%
+ {\dosetcurrentfontxxxalternative{#1}1\c!x\scriptstyle
+ \let\tx\txx}
+
+\def\setcurrentfontxxalternative#1%
+ {\dosetcurrentfontxxxalternative{#1}2\c!xx\scriptscriptstyle
+ \let\tx\empty
+ \let\txx\empty}
+
+\def\checknestedxfontsize % option
+ {\ifcase\currentxfontsize\else\ifx\fontsize\empty\else
+ \chardef\currentxfontsize\zeropoint
+ \let\fontsize\empty
+ \let\tx\normaltx
+ \let\txx\normaltxx
+ \fi\fi}
+
+\def\setcurrentfontxalternative#1%
+ {\checknestedxfontsize
+ \dosetcurrentfontxxxalternative{#1}1\c!x\scriptstyle
+ \let\tx\txx}
+
+\def\setcurrentfontxxalternative#1%
+ {\checknestedxfontsize
+ \dosetcurrentfontxxxalternative{#1}2\c!xx\scriptscriptstyle
+ \let\tx\empty
+ \let\txx\empty}
+
+% This alterative is not really needed, but for old time's sake
+% we keep it there. We can speed it up when needed.
+
+% \def\setcurrentfontxstylealternative #1{\csname#1\endcsname\tfx}
+% \def\setcurrentfontxxstylealternative#1{\csname#1\endcsname\tfxx}
+
+\def\setcurrentfontxstylealternative #1{\csname#1\endcsname\tx}
+\def\setcurrentfontxxstylealternative#1{\csname#1\endcsname\txx}
+
+%D These macros also show us that when we call for \type{\tx},
+%D this macro is redefined to be \type{\txx}. Therefore calls
+%D like:
+%D
+%D \startbuffer
+%D {small \tx is \tx beautiful}
+%D {small \tx is \txx beautiful}
+%D {small \txx is \tx beautiful}
+%D {small \txx is \txx beautiful}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D result in:
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D Setting the main size involves the style list and therefore
+%D takes a bit more time. Keep in mind that the fontsize is
+%D represented by a character or empty.
+
+\unexpanded\def\tx {\setcurrentfontxalternative \fontalternative}
+\unexpanded\def\txx{\setcurrentfontxxalternative\fontalternative}
+
+\let\normaltx \tx
+\let\normaltxx\txx
+
+%D \macros
+%D {definefontstyle}
+%D
+%D When setting of switching the overall style we can use the
+%D short identifier like rm and ss, but when defined we can
+%D also use more verbose names like roman or sansserif. Such
+%D names are defined by:
+%D
+%D \starttyping
+%D \definefontstyle [serif,rm] [rm]
+%D \definefontstyle [sansserif,ss] [ss]
+%D \stoptyping
+
+\def\dodefinefontstyle[#1][#2]%
+ {\rawdoifinsetelse{#2}{\fontstylelist}
+ {}%\debuggerinfo\m!fonts{unknown style #2}}
+ {\addtocommalist{#2}\fontstylelist
+ \showmessage\m!fonts8{#2\space (#1)}}%
+ % check kan hier
+ \def\docommand##1%
+ {\setvalue{\@shortstyle@##1}{#2}%
+ \setvalue{\@style@##1}{\csname#2\endcsname}}%
+ \processcommalist[#1]\docommand}
+
+\def\definefontstyle
+ {\dodoubleargument\dodefinefontstyle}
+
+\def\setfontstyle#1#2% #1:name (roman, romaan) #2:style (rm)
+ {\edef\fontstyle{#1}%
+ \setcurrentfontstyle\normalizedbodyfontsize}
+
+\chardef\defaultskewcharmi=127 % '177
+\chardef\defaultskewcharsy= 48 % '60
+
+% \def\dosetskewchar#1%
+% {\skewchar\font\ifx\@@fontskewchar\empty#1\else\@@fontskewchar\fi}
+
+\def\dosetskewchar#1#2%
+ {\ifx\@@fontskewchar\empty
+ \skewchar\textfont #1#2%
+ \skewchar\scriptfont #1#2%
+ \skewchar\scriptscriptfont#1#2%
+ \else
+ \skewchar\textfont #1\@@fontskewchar
+ \skewchar\scriptfont #1\@@fontskewchar
+ \skewchar\scriptscriptfont#1\@@fontskewchar
+ \fi}
+
+%D The previous macros show that it's is not always
+%D neccessary to define the whole bunch of fonts, take for
+%D instance the sequence:
+%D
+%D \starttyping
+%D \setupbodyfont
+%D [ams]
+%D
+%D \definebodyfont [24pt] [mm]
+%D [ma=msam10 at 24pt,
+%D mb=msbm10 at 24pt]
+%D
+%D \switchtobodyfont
+%D [24pt]
+%D
+%D This is a 24pt $\blacktriangleleft$
+%D \stoptyping
+%D
+%D Here we didn't define the 24 point bodyfont environment, so
+%D it's defined automatically. Of course one can always use the
+%D \TEX\ primitive \type{\font} to switch to whatever font
+%D needed.
+
+%D When asking for a complete font switch, for instance from 10
+%D to 12~points, the next macro does the job. First we
+%D normalize the size, next we define the current range of
+%D text, script and scriptscript sizes, then we set the text
+%D fonts and the math families and finally we activate the
+%D default typeface and also set the font specific parameters
+%D assigned to \type{\everybodyfont}
+
+\def\dosetbodyfontface#1#2%
+ {\edef#1{\bodyfontcsname\normalizedbodyfontsize#2\endcsname}}
+
+\def\docompletefontswitch[#1]%
+ {\bodyfontsize#1\relax
+ \dimensiontocount\bodyfontsize\bodyfontpoints
+ \edef\bodyfontfactor{\withoutpt\the\bodyfontsize}%
+ \normalizebodyfontsize\bodyfontsize\to\normalizedbodyfontsize
+ \dosetbodyfontface \textface \s!text
+ \dosetbodyfontface \scriptface \s!script
+ \dosetbodyfontface \scriptscriptface \s!scriptscript}
+
+\docompletefontswitch[12pt] % init
+
+%D \macros
+%D {setupbodyfont,switchtobodyfont}
+%D
+%D The next two macros are user ones. With \type{\setupbodyfont}
+%D one can set the document bodyfont size, font family, style
+%D and/or options defined in files, for example:
+%D
+%D \starttyping
+%D \setupbodyfont[cmr,ams,12pt,roman]
+%D \stoptyping
+%D
+%D This command affects the document as a whole: text, headers
+%D and footers. The second macro however affects only the text:
+%D
+%D \starttyping
+%D \switchtobodyfont[10pt]
+%D \stoptyping
+%D
+%D So we've got:
+%D
+%D \showsetup{setupbodyfont}
+%D \showsetup{switchtobodyfont}
+%D
+%D Both macros look alike. The second one also has to take
+%D all kind of keywords into account.
+
+\ifx\saveinterlinespace \undefined \let\saveinterlinespace \relax \fi
+\ifx\restoreinterlinespace\undefined \let\restoreinterlinespace\relax \fi
+
+\chardef\bodyfontsetstate=0
+
+\definecomplexorsimple\setupbodyfont
+
+\def\simplesetupbodyfont
+ {\restoreglobalbodyfont
+ \saveinterlinespace}
+
+\def\complexsetupbodyfont[#1]%
+ {\doifsomething{#1}
+ {\dosetfont1{#1}%
+ \globalbodyfontsize\localbodyfontsize
+ \normalizebodyfontsize\globalbodyfontsize\to\normalizedglobalbodyfontsize
+ \let\globalfontstyle\fontstyle
+ \ifloadingfonts\else
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace
+ \fi}}
+
+\unexpanded\def\switchtobodyfont[#1]%
+ {\doifsomething{#1}
+ {\doifdefinedelse{\??ft\normalizedbodyfontsize\interfaced{#1}}
+ {\setbodyfontstep{#1}} % so we have a fast [small] switch
+ {\dosetfont0{#1}}%
+ \the\everybodyfont}} % indeed needed in case nothing is executed
+
+%D The following alternative is meant for math||to||text
+%D switching and will be optimized.
+
+\def\fastswitchtobodyfont#1%
+ {\ifcsname\??ft\normalizedbodyfontsize#1\endcsname
+ \edef\futurebodyfontsize
+ {\csname\??ft\normalizedbodyfontsize#1\endcsname}%
+ \ifcsname\@size@\futurebodyfontsize\endcsname
+ \csname\@size@\futurebodyfontsize\endcsname
+ \localbodyfontsize\futurebodyfontsize\relax
+ \fi
+ \fi
+ \csname\@style@\fontstyle\endcsname
+ \the\everybodyfont}
+
+%D Because the last macro can appear in arguments or be assigned
+%D to parameters, we protect this one for unwanted expansion.
+
+\def\dodosetmathfont#1%
+ {\setcurrentfontalternative{#1}%
+ % \doifdefinedelse{#1\s!fam} % adapted
+ % {\edef\mffam{\getvalue{#1\s!fam}}}
+ % {\edef\mffam{\getvalue{\c!nn\s!fam}}}%
+ \textfont \mrfam\textfont \mffam
+ \scriptfont \mrfam\scriptfont \mffam
+ \scriptscriptfont\mrfam\scriptscriptfont\mffam}
+
+\def\domffam#1%
+ {\csname\ifcsname#1\s!fam\endcsname#1\else\c!nn\fi\s!fam\endcsname}
+
+\def\mffam
+ {\domffam\fontalternative}
+
+\def\dosetmathfont
+ {\def\rm{\fam\mrfam}\dodosetmathfont}
+
+\def\enableencodinginmath
+ {\appendtoks
+ \everyhbox{\mr\everyhbox\emptytoks}%
+ \everyvbox{\mr\everyvbox\emptytoks}%
+ \to \everymathematics} % was \everymath
+
+% \enableencodinginmath % too untested to enable by default
+
+%D \starttyping
+%D $\cases{& \ccaron}$ $x=\hbox{\ccaron $x=\hbox{\ccaron}$}$
+%D \stoptyping
+
+%D The font specific features are bound to the filename.
+
+\def\updatefontparameters
+ {\edef\@@fontencoding{\truefontdata\fontfile \s!encoding}%
+ \edef\@@fontmapping {\truefontdata\fontfile \s!mapping }%
+ \edef\@@fonthandling{\truefontdata\somefontname\s!handling}%
+ \edef\@@fontfeatures{\truefontdata\fontfile \s!features}%
+ \edef\@@fontskewchar{\truefontdata\fontfile \s!skewchar}}
+
+\def\setfontcharacteristics
+ {\updatefontparameters % redundant, will go away, faster too
+ \fastenableencoding
+ {\ifx\@@fontencoding\empty
+ \s!default \else \@@fontencoding
+ \fi}%
+ \fastenablemapping
+ {\ifx\@@fontmapping\empty
+ \ifx\@@fontencoding\empty
+ \s!default \else \@@fontencoding
+ \fi
+ \else
+ \@@fontmapping
+ \fi}%
+ \fastenablehandling
+ {\ifx\@@fonthandling\empty
+ \s!default \else \@@fonthandling
+ \fi}%
+ {\lastfontidentifier}%
+ \the\everyfont
+ \synchronizepatternswithfont}
+
+\ifx\synchronizepatternswithfont\undefined
+ \def\synchronizepatternswithfont{\synchronizepatterns}
+\fi
+
+%D Experimental:
+
+\def\definefontfeature
+ {\dotripleargument\dodefinefontfeature}
+
+\def\dododefinefontfeature#1%
+ {\edef\!!stringa{\ifx\!!stringa\empty\else\!!stringa,\fi\executeifdefined{\??fa#1}\empty}}
+
+\def\dodefinefontfeature[#1][#2][#3]%
+ {\doifassignmentelse{#2}
+ {\setevalue{\??fa#1}{#2}}
+ {\let\!!stringa\empty
+ \processcommalist[#2]\dododefinefontfeature
+ \setevalue{\??fa#1}{\ifx\!!stringa\empty\else\!!stringa,\fi#3}}}
+
+\definefontfeature
+ [default]
+ [liga=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes
+
+\definefontfeature
+ [smallcaps]
+ [liga=yes,kern=yes,tlig=yes,trep=yes,smcp=yes] % texligatures=yes,texquotes=yes
+
+\definefontfeature
+ [oldstyle]
+ [liga=yes,kern=yes,tlig=yes,trep=yes,onum=yes] % texligatures=yes,texquotes=yes
+
+\definefontfeature % no calt
+ [arabic]
+ [language=dflt,script=arab,
+ init=yes,medi=yes,fina=yes,isol=yes,
+ liga=yes,dlig=yes,rlig=yes,clig=yes,
+ mark=yes,mkmk=yes,kern=yes,curs=yes]
+
+\definefontfeature
+ [none]
+ [features=no]
+
+%D The next auxilliary macro is an alternative to \type
+%D {\fontname}.
+
+% \def\purefontname#1{\expandafter\splitoffpurefontname\fontname#1 \\}
+%
+% extra level is needed:
+
+\def\purefontname#1{\@EA\splitoffpurefontname\@EA{\@EA{\@EA\unstringed\fontname#1}} \\}
+
+\def\splitoffpurefontname#1 #2\\{#1}
+
+%D \macros
+%D {switchstyleonly}
+%D
+%D For switching a style but keeping the alternative, there
+%D is:
+%D
+%D \starttyping
+%D {\bf text \switchstyleonly\ss text}
+%D {\bf text \switchstyleonly[ss]text}
+%D {\sl text \switchstyleonly[sansserif]text}
+%D \stoptyping
+
+\definecomplexorsimple\switchstyleonly
+
+\def\simpleswitchstyleonly#1% stupid version
+ {\complexswitchstyleonly[\strippedcsname#1]}
+
+\def\complexswitchstyleonly[#1]% todo : check
+ {\setcurrentfontstyle{\getvalue{\@shortstyle@#1}}%
+ \the\everybodyfont} % needed ?
+
+%D \macros
+%D {os,frak, goth, cal}
+%D
+%D Old style numerals can be typeset with \type{\os} and look
+%D like {\os 1234567890} instead of the more common looking
+%D 1234567890.
+%D
+%D On behalf of {\frac Tobias Burnus}, we define some more of
+%D these. Later we will link these names to real file names.
+
+% older
+%
+% \definefont [os] [OldStyle sa *]
+% \definefont [frak] [Fraktur sa *]
+% \definefont [goth] [Gothic sa *]
+% \definefont [cal] [Calligraphic sa *]
+% \definefont [bbd] [Blackboard sa *]
+%
+% newer
+
+\unexpanded\def\os {\mathortext{\fam\purefamily {oldstyle}}{\symbolicfont {OldStyle}}}
+\unexpanded\def\frak{\mathortext{\fam\purefamily {fraktur}}{\symbolicfont {Fraktur}}}
+\unexpanded\def\goth{\mathortext{\fam\purefamily {gothic}}{\symbolicfont {Gothic}}}
+\unexpanded\def\cal {\mathortext{\fam\purefamily{calligraphic}}{\symbolicfont{Calligraphic}}}
+\unexpanded\def\bbd {\mathortext{\fam\purefamily {blackboard}}{\symbolicfont {Blackboard}}}
+
+\definefontsynonym [OldStyle] [Serif]
+\definefontsynonym [Fraktur] [Serif]
+\definefontsynonym [Gothic] [Serif]
+\definefontsynonym [Calligraphic] [Serif]
+\definefontsynonym [Blackboard] [Serif]
+
+%D \macros
+%D {fraktur, gothic, calligraphic, blackboard}
+%D
+%D These macros assume that we use text fonts, and not math
+%D families.
+
+\ifx\mathtext\undefined \let\mathtext\hbox \fi
+
+\unexpanded\def\fraktur #1{\mathortext\domathtext\donothing{\frak#1}}
+\unexpanded\def\gothic #1{\mathortext\domathtext\donothing{\goth#1}}
+\unexpanded\def\calligraphic#1{\mathortext\domathtext\donothing{\cal #1}}
+\unexpanded\def\blackboard #1{\mathortext\domathtext\donothing{\bbd#1}}
+
+%D Torture test:
+%D
+%D \starttyping
+%D \usetypescript[modern] [texnansi]
+%D \usetypescript[lucida] [texnansi]
+%D \usetypescript[palatino][texnansi]
+%D \usetypescript[times] [texnansi]
+%D \usetypescript[fourier] [ec]
+%D
+%D \startbuffer
+%D \section{\blackboard{T\high{\blackboard{T}}} \blackboard{E}\high{\blackboard{E}} \blackboard{X}\high{\blackboard{X}}}
+%D
+%D {\fontclass: 123 \os123 \cal TEX $\os 123$}
+%D
+%D $\blackboard{T}^{\blackboard{T}} \blackboard{E}^{\blackboard{E}} \blackboard{X}^{\blackboard{X}}$
+%D \blackboard{T}\high{\blackboard{T}} \blackboard{E}\high{\blackboard{E}} \blackboard{X}\high{\blackboard{X}}
+%D \stopbuffer
+%D
+%D {\setupbodyfont[lucida] \getbuffer}
+%D {\setupbodyfont[modern] \getbuffer}
+%D {\setupbodyfont[palatino] \getbuffer}
+%D {\setupbodyfont[times] \getbuffer}
+%D {\setupbodyfont[fourier] \getbuffer}
+%D \stoptyping
+
+%D \macros
+%D {definebodyfontswitch}
+%D
+%D \PLAIN\ \TEX\ defines some macro's like \type{\tenpoint}
+%D to switch to a specific bodyfontsize. Just for the sake of
+%D compatibility we can define them like:
+%D
+%D \starttyping
+%D \definebodyfontswitch [twelvepoint] [12pt]
+%D \stoptyping
+%D
+%D We don't support language specific synonyms here, mainly
+%D because \PLAIN\ \TEX\ is english anyway.
+
+\def\dodefinebodyfontswitch[#1][#2]%
+ {\def\docommand##1{\setvalue{##1}{\switchtobodyfont[#2]}}%
+ \processcommalist[#1]\docommand}
+
+\def\definebodyfontswitch
+ {\dodoubleargument\dodefinebodyfontswitch}
+
+%D \macros
+%D {setsmallbodyfont,setmainbodyfont,setbigbodyfont}
+%D
+%D When we're typesetting at for instance 10pt, we can call for
+%D the \type{small} as well as the \type{big} alternative,
+%D related to this main size, using \type{\switchtobodyfont[small]}.
+%D The three alternatives can be activated by the next three
+%D system calls and are defined by the bodyfontenvironment.
+
+\let\fontstep\empty % we can use \fontstep for tracing purposes
+
+\def\setbodyfontstep#1%
+ {\edef\fontstep{\bodyfontcsname\normalizedbodyfontsize\interfaced{#1}\endcsname}%
+ \doswitchpoints[\fontstep]%
+ \doswitchstyle[\fontstyle]}
+
+\unexpanded\def\setsmallbodyfont{\setbodyfontstep\v!small\the\everybodyfont}
+\unexpanded\def\setbigbodyfont {\setbodyfontstep\v!big \the\everybodyfont}
+
+\unexpanded\def\setmainbodyfont
+ {\doswitchpoints[\normalizedbodyfontsize]%
+ \doswitchstyle[\fontstyle]%
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace}
+
+%D \macros
+%D {restoreglobalbodyfont}
+%D
+%D Users can set whatever font available while typesetting text.
+%D Pagenumbers, footers, headers etc. however must be typeset
+%D in the main bodyfont and style of the document. Returning to
+%D the global state can be done with the next macro:
+
+\let\mainfontclass\empty
+
+\def\fullrestoreglobalbodyfont
+ {\let\fontsize\defaultfontsize
+ \let\fontbody\defaultfontbody
+ \chardef\currentxfontsize\zerocount
+ \let\fontclass\globalfontclass
+ \doswitchpoints[\normalizedglobalbodyfontsize]%
+ \doswitchstyle[\globalfontstyle]%
+ \redoconvertfont % just in case a pagebreak occurs
+ \tf
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace}
+
+\def\partialrestoreglobalbodyfont
+ {\let\fontsize\defaultfontsize
+ \let\fontbody\defaultfontbody
+ \chardef\currentxfontsize\zerocount
+ \redoconvertfont
+ \tf
+ \saveinterlinespace}
+
+\def\restoreglobalbodyfont % ook style etc
+ {\ifx\fontclass\globalfontclass
+ \ifx\fontstyle\globalfontstyle
+ \ifx\normalizedbodyfontsize\normalizedglobalbodyfontsize
+ \partialrestoreglobalbodyfont
+ \else
+ \fullrestoreglobalbodyfont
+ \fi
+ \else
+ \fullrestoreglobalbodyfont
+ \fi
+ \else
+ \fullrestoreglobalbodyfont
+ \fi}
+
+% in case of troubles: \let\restorebodyfont\fullrestoreglobalbodyfont
+
+%D This macro has to be called when entering the pagebody
+%D handling routine as well as the footnote insert routine.
+%D Users can access this feature |<|for instance when one wants
+%D to typeset tables and alike in the main bodyfont and style
+%D while the running text is temporary set to a smaller one|>|
+%D by saying \type{\switchtobodyfont[global]}.
+
+%D \macros
+%D {rasterfont}
+%D
+%D There are (at the moment) two situations in which we want to
+%D have fast access to a particular font. When we are using
+%D \TEX\ to typeset rasters, we use small {\rasterfont.}'s
+%D (a rather small period indeed), the same as \PICTEX\ uses
+%D for drawing purposes.
+
+\definefont [rasterfont] [Serif at 5pt]
+
+%D \macros
+%D {infofont}
+%D
+%D The second situation occurs when we enable the info mode,
+%D and put all kind of status information in the margin. We
+%D don't want huge switches to the main bodyfont and style, so
+%D here too we use a direct method.
+
+% old mechanism
+%
+% \def\infofont{\getvalue{\!!sixpoint\c!tt\c!tf}\the\everybodyfont}
+
+\let\infofont\relax % satisfy dep checker
+
+\definefont [infofont] [Mono at 6pt] % todo \the\everybodyfont
+
+%D \macros
+%D {definealternativestyle}
+%D
+%D In the main modules we are going to implement lots of
+%D parameterized commands and one of these parameters will
+%D concern the font to use. To suit consistent use of fonts we
+%D here implement a mechanism for defining the keywords that
+%D present a particular style or alternative.
+%D
+%D \starttyping
+%D \definealternativestyle [keywords] [\style] [\nostyle]
+%D \stoptyping
+%D
+%D The first command is used in the normal textflow, while the
+%D second command takes care of headings and alike. Consider
+%D the next two definitions:
+%D
+%D \starttyping
+%D \definealternativestyle [bold] [\bf] []
+%D \definealternativestyle [cap] [\cap] [\cap]
+%D \stoptyping
+%D
+%D A change \type{\bf} in a heading which is to be set in
+%D \type{\tfd} does not look that well, so therefore we leave
+%D the second argument of \type{\definealternativestyle} empty.
+%D When we capatalize characters using the pseudo small cap
+%D command \type{\cap}, we want this to take effect in both
+%D text and headings, which is accomplished by assigning both
+%D arguments.
+
+\def\dodefinealternativestyle[#1][#2][#3]%
+ {\def\docommand##1%
+ {\doifundefined{##1}{\setvalue{##1}{\groupedcommand{#2}{}}}%
+ \setvalue{\@letter@ ##1}{#2}%
+ \setvalue{\@noletter@##1}{#3}}%
+ \processcommalist[#1]\docommand}
+
+\def\definealternativestyle
+ {\dotripleempty\dodefinealternativestyle}
+
+\def\definestyle{\definealternativestyle}
+
+%D Maybe too geneneric, but probably ok is the following. (Maybe one
+%D day we will use a dedicated grouped command for styles.)
+
+\appendtoks
+ \let\groupedcommand\thirdofthreearguments
+\to \simplifiedcommands
+
+%D This command also defines the keyword as command. This means
+%D that the example definition of \type{bold} we gave before,
+%D results in a command \type{\bold} which can be used as:
+%D
+%D \startbuffer
+%D He's a \bold{bold} man with a {\bold head}.
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or
+%D
+%D \startvoorbeeld
+%D \definealternativestyle[bold][\bf][]\getbuffer
+%D \stopvoorbeeld
+%D
+%D Such definitions are of course unwanted for \type{\cap}
+%D because this would result in an endless recursive call.
+%D Therefore we check on the existance of both the command and
+%D the substitution. The latter is needed because for instance
+%D \type{\type} is an entirely diferent command. That command
+%D handles verbatim, while the style command would just switch
+%D to teletype font. This is just an example of a tricky
+%D naming coincidence.
+
+%D \macros
+%D {doconvertfont,noconvertfont,
+%D dontconvertfont,redoconvertfont}
+%D
+%D After having defined such keywords, we can call for them by
+%D using
+%D
+%D \starttyping
+%D \doconvertfont{keyword}{text}
+%D \stoptyping
+%D
+%D We deliberately pass an argument. This enables us to
+%D assign converters that handle one agrument, like
+%D \type{\cap}.
+%D
+%D By default the first specification is used to set the style,
+%D exept when we say \type{\dontconvertfont}, after which the
+%D second specification is used. We can also directly call for
+%D \type{\noconvertfont}. In nested calls, we can restore the
+%D conversion by saying \type{\redoconvertfont}.
+
+\def\@@dodoconvertfont#1{\csname\@letter@ #1\endcsname}
+\def\@@donoconvertfont#1{\csname\@noletter@#1\endcsname}
+
+\unexpanded\def\dodoconvertfont#1% #2% we need the protection
+ {\doifdefinedelse{\@letter@#1} % in testing
+ {\doifelsenothing{#1}\gobbleoneargument\@@dodoconvertfont}
+ {\doifdefinedelse{#1}\getvalue \firstofoneargument}%
+ {#1}} % {#2}}
+
+\let\doconvertfont\dodoconvertfont
+
+\def\noconvertfont#1% #2%
+ {\doifdefinedelse{\@noletter@#1}
+ {\doifelsenothing{#1}\gobbleoneargument\@@donoconvertfont}\gobbleoneargument
+ {#1}} % {#2}}
+
+%D Extras:
+
+\unexpanded\def\dontconvertfont
+ {\let\doconvertfont\noconvertfont}
+
+\unexpanded\def\redoconvertfont
+ {\let\doconvertfont\dodoconvertfont}
+
+%D These commands are not grouped! Grouping is most probably
+%D done by the calling macro's and would lead to unnecessary
+%D overhead.
+
+%D \macros
+%D {em,emphasistypeface,emphasisboldface}
+%D
+%D The next macro started as a copy of Donald Arseneau's
+%D \type{\em} (\TUGNEWS\ Vol.~3, no.~1, 1994). His
+%D implementation was a bit more sophisticated version of the
+%D standard \LATEX\ one. We furter enhanced the macro, so now
+%D it also adapts itself to boldface mode. Because we favor
+%D {\sl slanted} type over {\it italic}, we made the emphasis
+%D adaptable, for instance:
+%D
+%D \starttyping
+%D \def\emphasistypeface {\it}
+%D \def\emphasisboldface {\bi}
+%D \stoptyping
+%D
+%D But we prefer:
+
+\def\emphasistypeface {\sl}
+\def\emphasisboldface {\bs}
+
+%D or even better:
+
+% \def\doemphasistypeface#1#2%
+% {\doifelsevalue{\??ft\fontclass\normalizedbodyfontsize\c!em}\v!slanted#1%
+% {\doifelsevalue{\??ft\fontclass\normalizedbodyfontsize\c!em}\v!italic #2%
+% {\doifelsevalue{\??ft \normalizedbodyfontsize\c!em}\v!slanted#1%
+% {\doifvalue {\??ft \normalizedbodyfontsize\c!em}\v!italic #2}}}}
+
+\def\doemphasistypeface#1#2%
+ {\doifelsevalue{\??ft\fontclass\normalizedbodyfontsize\c!em}\v!slanted
+ {#1}%
+ {\doifelsevalue{\??ft\fontclass\normalizedbodyfontsize\c!em}\v!italic
+ {#2}%
+ {\doifelsevaluenothing{\??ft\fontclass\normalizedbodyfontsize\c!em}
+ {\doifelsevalue{\??ft\normalizedbodyfontsize\c!em}\v!slanted
+ {#1}%
+ {\doifelsevalue{\??ft\normalizedbodyfontsize\c!em}\v!italic
+ {#2}%
+ {\getvalue{\??ft\normalizedbodyfontsize\c!em}}}}
+ {\getvalue{\??ft\fontclass\normalizedbodyfontsize\c!em}}}}}
+
+\def\emphasistypeface{\doemphasistypeface\sl\it}
+\def\emphasisboldface{\doemphasistypeface\bs\bi}
+
+%D To be set with the default body font environment: \type
+%D {em} being \type {slanted} or \type {italic}.
+
+\newconditional\emneeded
+
+\newtoks\everyemphasized
+
+\unexpanded\def\em
+ {\relax
+ \ifdim\slantperpoint>\zeropoint
+ \settrue\emneeded
+ \else
+ \setfalse\emneeded
+ \fi
+ \setemphasisboldface % new
+ \ifx\fontalternative\c!it % \ifnum\fam=\itfam
+ \def\emphasistypeface{\it}\tf
+ \else\ifx\fontalternative\c!sl % \ifnum\fam=\slfam
+ \def\emphasistypeface{\sl}\tf
+ \else\ifx\fontalternative\c!bf % \ifnum\fam=\bffam
+ \emphasisboldface
+ \else\ifx\fontalternative\c!bs % \ifnum\fam=\bsfam
+ \def\emphasisboldface{\bs}\bf
+ \else\ifx\fontalternative\c!bi % \ifnum\fam=\bifam
+ \def\emphasisboldface{\bi}\bf
+ \else
+ \emphasistypeface
+ \fi\fi\fi\fi\fi
+ \the\everyemphasized
+ \ifconditional\emneeded\relax
+ \else
+ \expandafter\aftergroup
+ \fi
+ \emphasiscorrection}
+
+% compare ...
+%
+% \appendtoks \red \to \everyemphasized
+% \setupbodyfontenvironment [default] [em={\italic\color[red]}]
+
+%D The next feature was not present in previous versions. It
+%D takes care of \type {\em \bf ...} sitiations.
+
+\def\setemphasisboldface
+ {\let\normalbf\bf
+ \let\setemphasisboldface\relax
+ \unexpanded\def\bf
+ {%\relax
+ \let\bf\relax % new
+ \ifx\fontalternative\c!it % \ifnum\fam=\itfam
+ \bi
+ \else\ifx\fontalternative\c!sl % \ifnum\fam=\slfam
+ \bs
+ \else
+ \normalbf
+ \fi\fi
+ \let\bf\normalbf}}
+
+%D Donald's (adapted) macros take the next character into
+%D account when placing italic correction. As a bonus we also
+%D look for something that looks like a dash, in which case we
+%D don't correct.
+
+\let\italiccorrection=\/
+
+\def\emphasiscorrection
+ {\ifhmode
+ \expandafter\emphasislook
+ \fi}
+
+\def\emphasislook
+ {\begingroup
+ \beginrobusttest
+ \futurelet\next\emphasistest}
+
+\def\emphasistest
+ {\normalifcat\noexpand\next,%
+ \endrobusttest\expandafter\doemphasiscorrection
+ \normalelse
+ \endrobusttest\expandafter\dododoemphasiscorrection
+ \normalfi}
+
+\def\doemphasiscorrection
+ {\futurelet\next\dodoemphasiscorrection}
+
+\def\dodoemphasiscorrection
+ {\setbox\scratchbox\hbox{\next}%
+ \ifdim\ht\scratchbox=\zeropoint % probably a space
+ \expandafter\dododoemphasiscorrection
+ \else\ifdim\ht\scratchbox<.3ex
+ \expandafter\expandafter\expandafter\endgroup
+ \else
+ \expandafter\expandafter\expandafter\dododoemphasiscorrection
+ \fi\fi}
+
+\def\dododoemphasiscorrection
+ {\scratchskip\lastskip
+ \ifdim\scratchskip=\zeropoint\relax % == \ifzeropt\scratchskip
+ \italiccorrection\relax
+ \else
+ \unskip\italiccorrection\hskip\scratchskip
+ \fi
+ \endgroup}
+
+%D We end with some examples which show the behavior when
+%D some punctuation is met. We also show how the mechanism
+%D adapts itself to bold, italic and slanted typing.
+%D
+%D \startbuffer
+%D test {test}test \par
+%D test {\sl test}test \par
+%D test {\em test}test \par
+%D test {\em test}--test \par
+%D
+%D test {test}, test \par
+%D test {\em test}, test \par
+%D
+%D test {\em test {\em test {\em test} test} test} test \par
+%D test {\bf test {\em test {\em test} test} test} test \par
+%D test {\sl test {\em test {\em test} test} test} test \par
+%D test {\it test {\em test {\em test} test} test} test \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D We get:
+%D
+%D \startvoorbeeld
+%D \startpacked
+%D \getbuffer
+%D \stoppacked
+%D \stopvoorbeeld
+
+%D \macros
+%D {emphbf,emphit,emphsl,emphtf}
+%D
+%D The next emphasis alternatives are for \THANH. They adapt
+%D their style as good as possible.
+
+\def\emphbf{\groupedcommand{\bf\def\emphit{\bi}\def\emphsl{\bs}}{}}
+\def\emphit{\groupedcommand{\it\def\emphbf{\bi}\def\emphsl{\sl}}{}}
+\def\emphsl{\groupedcommand{\sl\def\emphbf{\bs}\def\emphit{\it}}{}}
+\def\emphtf{\groupedcommand{\tf\def\emphbf{\bf}\def\emphit{\it}\def\emphsl{\sl}}{}}
+
+%D \startbuffer
+%D TEXT {\emphbf text \emphit text \emphtf text \emphsl text} TEXT
+%D TEXT \emphbf{text \emphit{text} \emphtf{text} \emphsl{text}} TEXT
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+%D \macros
+%D {setfont}
+%D
+%D Every now and then we want to define a font directly, for
+%D instance when we typeset title pages. The next macro saves
+%D some typing:
+
+\def\setfont% geen \dosetfont mogelijk
+ {\def\next{\nextfont\setupinterlinespace}%
+ \afterassignment\next\font\nextfont=}
+
+%D One can call this macro as:
+%D
+%D \starttyping
+%D \setfont cmr10 at 60pt
+%D \stoptyping
+%D
+%D After which the font is active and the baselines and
+%D struts are set.
+
+%D \macros
+%D {showbodyfont}
+%D
+%D One can call for a rather simple overview of a bodyfont and the
+%D relations between its alternative fonts.
+%D
+%D \showsetup{showbodyfont}
+%D
+%D The current bodyfont (here we omitted the argument) looks like:
+%D
+%D \showbodyfont
+%D
+%D The implementation is rather straightforward in using
+%D \type{\halign}.
+
+\fetchruntimecommand \showbodyfont {\f!fontprefix\s!run.mkii}
+
+%D \macros
+%D {showfontstrip, testminimalbaseline, showminimalbaseline}
+%D
+%D The next command can come in handy when combining
+%D different fonts into a collection (typeface) and
+%D determining optimal baseline distances.
+%D
+%D \showfontstrip \blank \showminimalbaseline
+
+\fetchruntimecommand \showfontstrip {\f!fontprefix\s!run.mkii}
+\fetchruntimecommand \testminimalbaseline {\f!fontprefix\s!run.mkii}
+\fetchruntimecommand \showminimalbaseline {\f!fontprefix\s!run.mkii}
+
+%D \macros
+%D {showkerning}
+%D
+%D A goody is:
+%D
+%D \showkerning{Can you guess what kerning is?}
+
+\fetchruntimecommand \showkerning {\f!fontprefix\s!run.mkii}
+
+%D \macros
+%D {showbodyfontenvironment}
+%D
+%D The current bodyfontenvironment is:
+%D
+%D \showbodyfontenvironment
+%D
+%D This overview is generated using:
+%D
+%D \showsetup{showbodyfontenvironment}
+
+\fetchruntimecommand \showbodyfontenvironment {\f!fontprefix\s!run.mkii}
+
+%D \macros
+%D {showfont,showfontstyle,showligatures}
+%D
+%D The following command generates a fontmap:
+%D
+%D \startbuffer
+%D \showfont[SansBold at 12pt]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Below the table the name, encoding, mapping and handling are
+%D shown. Special characters like the \type {\skewchar} and
+%D \type {\hyphenchar} als marked.
+%D
+%D \getbuffer
+
+% to be internationalized
+
+\fetchruntimecommand \showfont {\f!fontprefix\s!run.mkii}
+\fetchruntimecommand \showfontstyle {\f!fontprefix\s!run.mkii}
+\fetchruntimecommand \showligature {\f!fontprefix\s!run.mkii}
+\fetchruntimecommand \showligatures {\f!fontprefix\s!run.mkii}
+\fetchruntimecommand \showcharratio {\f!fontprefix\s!run.mkii}
+
+%D \macros
+%D {getglyph, symbolicfont}
+%D
+%D Individual glyphs can be accessed by using
+%D
+%D \starttyping
+%D \getglyph{fontname}{character}
+%D \stoptyping
+%D
+%D This macro is used in for instance the symbol modules and
+%D as one can see, it does obey the small and even smaller
+%D sizes. The \type {\symbolicfont} macro can be used to
+%D switch to a font named \type {fontname} (see \type
+%D {cont-log} and \type {symb-eur} for examples of symbolic
+%D definitions.
+
+\def\fontstringA
+ {\ifx\fontstyle\c!rm \s!Serif \else
+ \ifx\fontstyle\c!ss \s!Sans \else
+ \ifx\fontstyle\c!tt \s!Mono \else
+ \s!Serif \fi\fi\fi}
+
+\def\fontstringB
+ {\ifx\fontstyle\c!rm \s!Regular \else
+ \ifx\fontstyle\c!ss \s!Support \else
+ \ifx\fontstyle\c!tt \s!Type \else
+ \s!Serif \fi\fi\fi}
+
+\def\fontstringC
+ {\ifx\fontalternative\c!bf \s!Bold \else
+ \ifx\fontalternative\c!sl \s!Slanted \else
+ \ifx\fontalternative\c!it \s!Italic \else
+ \ifx\fontalternative\c!bs \s!BoldSlanted \else
+ \ifx\fontalternative\c!bi \s!BoldItalic \fi\fi\fi\fi\fi}
+
+\def\fontstringD % default fontstyle
+ {\expandafter\ifx\csname\??tf\fontclass\s!default\endcsname\c!rm \s!Serif \else
+ \expandafter\ifx\csname\??tf\fontclass\s!default\endcsname\c!ss \s!Sans \else
+ \expandafter\ifx\csname\??tf\fontclass\s!default\endcsname\c!tt \s!Mono \else
+ \s!Serif \fi\fi\fi}
+
+% potential generalization:
+
+% \letvalue{\??ff:t:\c!rm}\s!Serif
+% \letvalue{\??ff:t:\c!ss}\s!Sans
+% \letvalue{\??ff:t:\c!tt}\s!Mono
+%
+% \letvalue{\??ff:s:\c!bf}\s!Bold
+% \letvalue{\??ff:s:\c!sl}\s!Slanted
+% \letvalue{\??ff:s:\c!it}\s!Italic
+% \letvalue{\??ff:s:\c!bs}\s!BoldSlanted
+% \letvalue{\??ff:s:\c!bi}\s!BoldItalic
+%
+% \letvalue{\??ff:a:\c!rm}\s!Regular
+% \letvalue{\??ff:a:\c!ss}\s!Support
+% \letvalue{\??ff:a:\c!tt}\s!Type
+%
+% \def\fontstringA{\executeifdefined{\??ff:t:\fontstyle}\s!Serif}
+% \def\fontstringB{\executeifdefined{\??ff:a:\fontstyle}\s!Serif}
+% \def\fontstringC{\executeifdefined{\??ff:s:\fontstyle}\empty}
+% \def\fontstringD{\executeifdefined{\??ff:t:\csname\??tf\fontclass\s!default\endcsname}\s!Serif}
+
+\def\glyphfontfile#1%
+ {#1%
+ \ifcsname\??ff#1\fontstringA\fontstringC\endcsname
+ \fontstringA\fontstringC
+ \else\ifcsname\??ff#1\fontstringB\fontstringC\endcsname
+ \fontstringB\fontstringC
+ \else\ifcsname\??ff#1\fontstringA\endcsname
+ \fontstringA
+ \else\ifcsname\??ff#1\fontstringB\endcsname
+ \fontstringB
+ \else\ifcsname\??ff#1\fontstringC\endcsname
+ \fontstringC
+ \fi\fi\fi\fi\fi}
+
+%D The next macro can be used to make decisions based on the shape:
+
+\def\doifitalicelse#1#2%
+ {\ifx\fontalternative\c!sl#1\else
+ \ifx\fontalternative\c!it#1\else
+ \ifx\fontalternative\c!bs#1\else
+ \ifx\fontalternative\c!bi#1\else#2\fi\fi\fi\fi}
+
+%D For an example of usage of the following command,
+%D see \type {cont-log.tex}.
+%D
+%D \starttyping
+%D \def\symbolicfont#1%
+%D {\definedfont[\glyphfontfile{#1} sa *]}
+%D \stoptyping
+%D
+%D Since we know what scaling it to be applied, we can
+%D implement a much faster alternative:
+
+\let\thedefinedfont\relax
+
+% \def\symbolicscaledfont#1#2%
+% {\scaledfont\fontbody
+% \scaledfont#1\scaledfont
+% \font\thedefinedfont\truefontname{\glyphfontfile{#2}} at
+% \currentfontbodyscale\scaledfont
+% \thedefinedfont}
+%
+% \unexpanded\def\symbolicfont
+% {\symbolicscaledfont\plusone}
+%
+% even more control (needed for mthsqrt etc)
+
+\def\symbolicsizedfont#1#2#3%
+ {\scaledfont#1%
+ \scaledfont#2\scaledfont
+ \font\thedefinedfont\truefontname{\glyphfontfile{#3}} at
+ \currentfontbodyscale\scaledfont
+ \thedefinedfont}
+
+\def\symbolicscaledfont
+ {\symbolicsizedfont\fontbody}
+
+\unexpanded\def\symbolicfont
+ {\symbolicsizedfont\fontbody\plusone}
+
+\unexpanded\def\getglyph#1#2% slow, faster, much faster
+ %{{\definefont[\s!dummy][\glyphfontfile{#1} sa \currentfontscale]\dummy#2}}
+ %{{\definefont[\s!dummy][\glyphfontfile{#1} sa *]\dummy#2}}
+ %{{\symbolicfont{#1}#2}}
+ {{\symbolicfont{#1}\doifnumberelse{#2}\char\donothing#2}}
+
+\unexpanded\def\getscaledglyph#1#2#3%
+ {{\symbolicscaledfont{#1}{#2}\doifnumberelse{#3}\char\donothing#3}}
+
+\unexpanded\def\getrawglyph#1#2% for simple symbols
+ {{\scaledfont\fontbody
+ \font\thedefinedfont=#1 at \currentfontbodyscale\scaledfont
+ \thedefinedfont\doifnumberelse{#2}\char\donothing#2}}
+
+%D The last implementation of \type {\getglyph} permits
+%D definitions like:
+%D
+%D \starttyping
+%D \definefontsynonym [EuroSans] [eurose]
+%D \definefontsynonym [EuroSansBold] [euroseb]
+%D \definefontsynonym [EuroSansItalic] [eurosei]
+%D \definefontsynonym [EuroSansSlanted] [eurosei]
+%D \definefontsynonym [EuroSansBoldItalic] [eurosebi]
+%D \definefontsynonym [EuroSansBoldSlanted] [eurosebi]
+%D
+%D \definesymbol [euro] [\getglyph{Euro}{\char160}]
+%D
+%D \def\euro{\symbol[euro]}
+%D \stoptyping
+%D
+%D These definitions guarantee that the next calls work okay:
+%D
+%D \starttyping
+%D \ss \tf\euro \bf\euro \sla\euro \itd\euro \bs\euro \bic\euro
+%D \stoptyping
+%D
+%D The shape as well as the size is adapted to the current
+%D environment.
+
+%D Fonts can only be used when loaded. In \CONTEXT\ we
+%D postpone the loading of fonts, even when we load \PLAIN.
+%D This means that we have to redefine one of the \PLAIN\
+%D macros. Let's tell that to the user first:
+
+\writestatus{loading}{Postponed Plain TeX Font Definitions}
+
+%D \macros
+%D {bordermatrix}
+%D
+%D In \PLAIN\ \TEX\ the width of a parenthesis is stored in
+%D the \DIMENSION\ \type{\mathparentwd}. This value is derived from
+%D the width of \type{\tenrm B}, so let's take care of it now:
+
+\let\normalbordermatrix=\bordermatrix
+
+\def\bordermatrix%
+ {\bgroup
+ \setbox0\hbox{\getvalue{\textface\c!mm\c!ex}B}%
+ \global\mathparentwd\wd0\relax
+ \egroup
+ \normalbordermatrix}
+
+%D Because we want to be as \PLAIN\ compatible as possible, we
+%D make most of \PLAIN's font mechanisme available to the
+%D \CONTEXT\ user.
+
+\def\setplainfonts#1#2%
+ {\setvalue {ten#1}{\getvalue{\!!tenpoint #2}}%
+ \setvalue{seven#1}{\getvalue{\!!sevenpoint#2}}%
+ \setvalue {five#1}{\getvalue{\!!fivepoint #2}}}
+
+\setplainfonts {\c!rm} {\c!rm\c!tf}
+\setplainfonts {\c!bf} {\c!rm\c!bf}
+\setplainfonts {\c!sl} {\c!rm\c!sl}
+\setplainfonts {\c!it} {\c!rm\c!it}
+\setplainfonts {\c!tt} {\c!rm\c!tt}
+\setplainfonts {\c!sy} {\c!mm\c!sy}
+\setplainfonts {\c!ex} {\c!mm\c!ex}
+\setplainfonts {\c!i} {\c!mm\c!mi}
+
+\let\setplainfonts=\undefined
+
+%D \macros
+%D {ss, SS, sz}
+%D
+%D We are going to redefine \type{\ss} but for those wo still
+%D want to have access to the german \SS, we save it's value in
+%D \type{\SS}. Ok, I should have used \type{\sf} instead of
+%D \type{\ss} in the first place.
+
+\ifx\undefined\SS \let\SS=\ss \fi
+\ifx\undefined\sz \let\sz=\ss \fi
+
+%D \macros
+%D {xi}
+%D
+%D We are going to redefine \type{\xi}, but fortunately this
+%D is a math mode character, so we can just say:
+
+\let\normalxi=\xi
+
+%D \macros
+%D {smashaccent}
+%D
+%D When we let \TEX\ put an accent on top of a character, such
+%D composed characters can get more height that height of a
+%D standard \type{\strut}. The next macro takes care of such
+%D unwanted compositions.
+%D
+%D We need to reach over the number that specifies the accent,
+%D and in doing so we use \type{\scratchcounter} as a placeholder
+%D because it accepts 8 bit numbers in octal, decimal or
+%D hexadecimal format. Next we set the height of the accented
+%D character to the natural height of the character.
+
+\unexpanded\def\smashaccent#1%
+ {\dontleavehmode
+ \bgroup
+ \setbox\scratchbox\hbox{#1}%
+ \ifdim\ht\scratchbox>\strutheight\relax\ht\scratchbox\strutheight\fi
+ \ifdim\dp\scratchbox>\strutdepth \relax\dp\scratchbox\strutdepth \fi
+ \box\scratchbox
+ \egroup}
+
+%D For instance we can say:
+%D
+%D \starttyping
+%D \smashaccent{\"Uberhaupt}
+%D \stoptyping
+%D
+%D But normally one will use it as a prefix in definitions.
+%D The difference is in the height:
+%D
+%D \leavevmode\ruledhbox
+%D {\ruledhbox{\smashaccent{\"U}berhaupt}\quad
+%D oder\quad
+%D \ruledhbox{\"Uberhaupt}}
+
+%D \macros
+%D {moveaccent}
+%D
+%D Exact positioning of accents can be realized by saying:
+%D
+%D \starttyping
+%D \moveaccent{-.1ex}{\"u}berhaupt
+%D \stoptyping
+%D
+%D Again, this one will mostly used as a prefix in definitions.
+%D Here the difference is in the position:
+%D
+%D \leavevmode\ruledhbox
+%D {\ruledhbox{\moveaccent{-.1ex}{\"}Uberhaupt}\quad
+%D oder\quad
+%D \ruledhbox{\"Uberhaupt}}
+
+\unexpanded\def\moveaccent#1#2%
+ {\smashaccent
+ {\dimen0\exheight
+ \dimen2\dimen0
+ \advance\dimen2 -#1%
+ \exheight\dimen2
+ #2\relax
+ \exheight\dimen0}}
+
+%D Personally I think that using \TEX\ is complicated by the
+%D way fonts are handled. Apart from the many encodings, we
+%D also deal with different naming schemes. Confronted with
+%D this problem, I decided to change the definitions into:
+%D
+%D \starttyping
+%D \definebodyfont [12pt] [rm] [tf=Times-Roman at 12pt]
+%D \stoptyping
+%D
+%D combined with for instance:
+%D
+%D \starttyping
+%D \definefontsynonym [Times-Roman] [tir]
+%D \stoptyping
+
+%D Now we're up to some definitions.
+
+\definebodyfontenvironment
+ [\s!default]
+ [ \s!text=1.0,
+ \s!script=0.7,
+ \s!scriptscript=0.5,
+ \c!a=1.200,
+ \c!b=1.440,
+ \c!c=1.728,
+ \c!d=2.074,
+ *=\currentfontscale, % wildcard
+ \c!x=0.8,
+ \c!xx=0.6,
+ \c!big=1.2,
+ \c!small=0.8,
+ \c!interlinespace=,
+ \c!em=\v!slanted]
+
+\definebodyfontenvironment
+ [20.7pt]
+ [ \s!text=20.7pt,
+ \s!script=\!!fourteenpointfour,
+ \s!scriptscript=\!!twelvepoint,
+ \c!x=17.3pt,
+ \c!xx=\!!fourteenpointfour,
+ \c!big=20.7pt, % !!!!
+ \c!small=17.3pt]
+
+\definebodyfontenvironment
+ [17.3pt]
+ [ \s!text=17.3pt,
+ \s!script=\!!twelvepoint,
+ \s!scriptscript=\!!tenpoint,
+ \c!x=\!!fourteenpointfour,
+ \c!xx=\!!twelvepoint,
+ \c!big=20.7pt,
+ \c!small=\!!fourteenpointfour]
+
+\definebodyfontenvironment
+ [\!!fourteenpointfour]
+ [ \s!text=\!!fourteenpointfour,
+ \s!script=\!!elevenpoint,
+ \s!scriptscript=\!!ninepoint,
+ \c!x=\!!twelvepoint,
+ \c!xx=\!!tenpoint,
+ \c!big=17.3pt,
+ \c!small=\!!twelvepoint]
+
+\definebodyfontenvironment
+ [\!!twelvepoint]
+ [ \s!text=\!!twelvepoint,
+ \s!script=\!!ninepoint,
+ \s!scriptscript=\!!sevenpoint,
+ \c!x=\!!tenpoint,
+ \c!xx=\!!eightpoint,
+ \c!big=\!!fourteenpointfour,
+ \c!small=\!!tenpoint]
+
+\definebodyfontenvironment
+ [\!!elevenpoint]
+ [ \s!text=\!!elevenpoint,
+ \s!script=\!!eightpoint,
+ \s!scriptscript=\!!sixpoint,
+ \c!x=\!!ninepoint,
+ \c!xx=\!!sevenpoint,
+ \c!big=\!!twelvepoint,
+ \c!small=\!!ninepoint]
+
+\definebodyfontenvironment
+ [\!!tenpoint]
+ [ \s!text=\!!tenpoint,
+ \s!script=\!!sevenpoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!eightpoint,
+ \c!xx=\!!sixpoint,
+ \c!big=\!!twelvepoint,
+ \c!small=\!!eightpoint]
+
+\definebodyfontenvironment
+ [\!!ninepoint]
+ [ \s!text=\!!ninepoint,
+ \s!script=\!!sevenpoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!sevenpoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!elevenpoint,
+ \c!small=\!!sevenpoint]
+
+\definebodyfontenvironment
+ [\!!eightpoint]
+ [ \s!text=\!!eightpoint,
+ \s!script=\!!sixpoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!sixpoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!tenpoint,
+ \c!small=\!!sixpoint]
+
+\definebodyfontenvironment
+ [\!!sevenpoint]
+ [ \s!text=\!!sevenpoint,
+ \s!script=\!!sixpoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!sixpoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!ninepoint,
+ \c!small=\!!fivepoint]
+
+\definebodyfontenvironment
+ [\!!sixpoint]
+ [ \s!text=\!!sixpoint,
+ \s!script=\!!fivepoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!fivepoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!eightpoint,
+ \c!small=\!!fivepoint]
+
+\definebodyfontenvironment
+ [\!!fivepoint]
+ [ \s!text=\!!fivepoint,
+ \s!script=\!!fivepoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!fivepoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!sevenpoint,
+ \c!small=\!!fivepoint]
+
+\definebodyfontenvironment
+ [\!!fourpoint]
+ [ \s!text=\!!fourpoint,
+ \s!script=\!!fourpoint,
+ \s!scriptscript=\!!fourpoint,
+ \c!x=\!!fourpoint,
+ \c!xx=\!!fourpoint,
+ \c!big=\!!sixpoint,
+ \c!small=\!!fourpoint]
+
+\definebodyfontswitch [fourteenpointfour] [\!!fourteenpointfour]
+\definebodyfontswitch [twelvepoint] [\!!twelvepoint]
+\definebodyfontswitch [elevenpoint] [\!!elevenpoint]
+\definebodyfontswitch [tenpoint] [\!!tenpoint]
+\definebodyfontswitch [ninepoint] [\!!ninepoint]
+\definebodyfontswitch [eightpoint] [\!!eightpoint]
+\definebodyfontswitch [sevenpoint] [\!!sevenpoint]
+\definebodyfontswitch [sixpoint] [\!!sixpoint]
+\definebodyfontswitch [fivepoint] [\!!fivepoint]
+\definebodyfontswitch [fourpoint] [\!!fourpoint]
+
+\definebodyfontswitch [xii] [\!!twelvepoint]
+\definebodyfontswitch [xi] [\!!elevenpoint]
+\definebodyfontswitch [x] [\!!tenpoint]
+\definebodyfontswitch [ix] [\!!ninepoint]
+\definebodyfontswitch [viii] [\!!eightpoint]
+\definebodyfontswitch [vii] [\!!sevenpoint]
+\definebodyfontswitch [vi] [\!!sixpoint]
+
+%D So far.
+
+\definefontstyle [\c!mm] [\c!mm]
+\definefontstyle [\c!rm,\v!roman,\v!serif,\v!regular] [\c!rm]
+\definefontstyle [\c!ss,\v!sansserif,\v!sans,\v!support] [\c!ss]
+\definefontstyle [\c!tt,\v!teletype,\v!type,\v!mono] [\c!tt]
+\definefontstyle [\c!hw,\v!handwritten] [\c!hw]
+\definefontstyle [\c!cg,\v!calligraphic] [\c!cg]
+
+\definefontsize[\c!a] \definefontsize[\c!b]
+\definefontsize[\c!c] \definefontsize[\c!d]
+
+\definealternativestyle [\v!mediaeval] [\os] []
+\definealternativestyle [\v!normal] [\tf] []
+\definealternativestyle [\v!bold] [\bf] []
+\definealternativestyle [\v!type] [\tt] []
+\definealternativestyle [\v!mono] [\tt] []
+\definealternativestyle [\v!slanted] [\sl] []
+\definealternativestyle [\v!italic] [\it] []
+\definealternativestyle [\v!boldslanted,\v!slantedbold] [\bs] []
+\definealternativestyle [\v!bolditalic,\v!italicbold] [\bi] []
+\definealternativestyle [\v!small,\v!smallnormal] [\tfx] []
+\definealternativestyle [\v!smallbold] [\bfx] []
+\definealternativestyle [\v!smalltype] [\ttx] []
+\definealternativestyle [\v!smallslanted] [\slx] []
+\definealternativestyle [\v!smallboldslanted,\v!smallslantedbold] [\bsx] []
+\definealternativestyle [\v!smallbolditalic,\v!smallitalicbold] [\bix] []
+
+\definealternativestyle [\v!sans,\v!sansserif] [\ss] []
+\definealternativestyle [\v!sansbold] [\ss\bf] []
+
+%D Slow but handy:
+
+\definealternativestyle [\v!smallbodyfont] [\setsmallbodyfont] []
+\definealternativestyle [\v!bigbodyfont] [\setbigbodyfont] []
+
+%D We treat {\sc Small Caps} and \cap {Pseudo Caps} a bit
+%D different. We also provide an \WORD {uppercase} style.
+
+\definealternativestyle [\v!cap,\v!capital] [\smallcapped] [\smallcapped]
+\definealternativestyle [\v!smallcaps] [\sc] [\sc]
+\definealternativestyle [\v!WORD] [\WORD] [\WORD]
+
+%D \macros
+%D {...math}
+%D
+%D New or old?
+
+% tzt proper \define...
+%
+% watch out: \synchronizesymb resets the family so we need a second
+% \mf (or maybe \mr): messy and to be sorted out
+
+\def\tfmath{\tf\mf\synchronizesymb\mf}
+\def\bfmath{\bf\mf\synchronizesymb\mf}
+\def\slmath{\sl\mf\synchronizesymb\mf}
+\def\itmath{\it\mf\synchronizesymb\mf}
+\def\bsmath{\bs\mf\synchronizesymb\mf}
+\def\bimath{\bi\mf\synchronizesymb\mf}
+\def\scmath{\sc\mf\synchronizesymb\mf}
+\def\nnmath{\nn\mf\synchronizesymb\mf}
+
+\def\textmath {\synchronizesymb}
+
+%D \macros
+%D {fontstylesuffix}
+%D
+%D The next macro is used to map non latin fontnames on
+%D fonts. See \type {font-uni} for an example of its use.
+
+%\def\fontstylesuffix%
+% {\ifnum\fam=\tffam \s!Regular \else
+% \ifnum\fam=\bffam \s!Bold \else
+% \ifnum\fam=\slfam \s!Slanted \else
+% \ifnum\fam=\itfam \s!Italic \else
+% \ifnum\fam=\bsfam \s!BoldSlanted \else
+% \ifnum\fam=\bifam \s!BoldItalic \else
+% \s!Regular \fi\fi\fi\fi\fi\fi}%
+
+\def\fontstylesuffix% why the \s!Regular ? see \getglyph
+ {\ifx\fontalternative\c!tf \s!Regular \else
+ \ifx\fontalternative\c!bf \s!Bold \else
+ \ifx\fontalternative\c!sl \s!Slanted \else
+ \ifx\fontalternative\c!it \s!Italic \else
+ \ifx\fontalternative\c!bs \s!BoldSlanted \else
+ \ifx\fontalternative\c!bi \s!BoldItalic \else
+ \ifx\fontalternative\c!sc \s!Caps \else
+ \s!Regular \fi\fi\fi\fi\fi\fi\fi}%
+
+%D We still have to take care of \type{\xi}, so:
+
+\def\xi{\ifmmode\normalxi\else\elevenpoint\fi}
+
+%D \macros
+%D {definefontvariant,fontvariant,variant}
+%D
+%D A slightly adapted version of Adam Lindsays variant patches:
+%D
+%D \starttyping
+%D \usetypescriptfile[type-psc] \loadmapfile[texnansi-public-fpl]
+%D \usetypescript[palatino][texnansi] \setupbodyfont[palatino]
+%D
+%D \definefontvariant [Serif][osf] [OsF]
+%D
+%D \startlines
+%D {\sc abcdefgHIJKlmnop}
+%D 123{\Var[osf]456}789
+%D {\Var[osf] 123{\Var[reset]456}789}
+%D {\it 123{\Var[osf]456}789
+%D {\Var[osf]123{\Var[reset]456}789}}
+%D {\tfb\bf 123{\Var[osf]456}789
+%D {\Var[osf] 123{\Var[reset]456}789}}
+%D {\sc 123{\Var[osf]456}789
+%D {\Var[osf] 123{\Var[reset]456}789}}
+%D \stoplines
+%D \stoptyping
+
+\def\definefontvariant
+ {\dotripleargument\dodefinefontvariant}
+
+\def\dodefinefontvariant[#1][#2][#3]%
+ {\setvalue{\??fv#1#2}{#3}}
+
+\def\fontvariant#1#2{\executeifdefined{\??fv#1#2}\empty}
+
+\def\dosetscaledfont
+ {\checkrelativefontsize\fontstyle
+ \scaledfont\currentfontscale\bodyfontsize
+ \scaledfont\relativefontsize\scaledfont}
+
+\unexpanded\def\variant[#1]% slow
+ {\dosetscaledfont
+ \expanded{\definedfont
+ [\truefontname{\fontstringA\fontstylesuffix\fontvariant\fontstringA{#1}}
+ at \scaledfont]}%
+ \ignoreimplicitspaces}
+
+\ifx\Var\undefined \let\Var\variant \fi
+
+%D By default we load the Computer Modern Roman fonts (but
+%D not yet at this moment) and activate the 12pt roman
+%D bodyfont. Sans serif and teletype are also available and
+%D can be called for by \type{\ss} and \type{\tt}.
+
+% \setupbodyfont [unk, rm]
+
+%D Also needed is:
+
+\definefont[tinyfont][Mono at 1ex]
+
+%D \macros
+%D {doiffontpresentelse}
+%D
+%D Some unused left||overs:
+%D
+%D \starttyping
+%D \def\doiffontpresentelse#1#2#3%
+%D {\bgroup
+%D \batchmode\font\dummy=\truefontname{#1}\errorstopmode
+%D \edef\lastfontname{\fontname\dummy}%
+%D \ifx\lastfontname\nullfontname\egroup#3\else\egroup#2\fi}
+%D
+%D \def\abortiffontnotfound#1%
+%D {\doiffontpresentelse{#1}{}{\showmessage\m!fonts{10}{\truefontname{#1}}\endinput}}
+%D \stoptyping
+%D
+%D We now provide (slow, but sometimes handy):
+%D
+%D \starttyping
+%D \doiffontpresentelse{texnansi-lmr10}{YES}{NO}
+%D \doiffontpresentelse{adam-lindsay-modern-serif}{YES}{NO}
+%D \stoptyping
+
+\def\doiffontpresentelse#1%
+ {\bgroup
+ \scratchcounter\interactionmode
+ \batchmode
+ \font\dummy=\truefontname{#1}\relax
+ \interactionmode\scratchcounter
+ \edef\lastfontname{\fontname\dummy}%
+ \ifx\lastfontname\nullfontname
+ \egroup\expandafter\secondoftwoarguments
+ \else
+ \egroup\expandafter\firstoftwoarguments
+ \fi}
+
+%D New commands (not yet interfaced):
+
+\def\style[#1]% for inline usage, like \color
+ {\groupedcommand{\ifcsname#1\endcsname\csname#1\endcsname\else\definedfont[#1]\fi}{}}
+
+\def\startstyle[#1]%
+ {\begingroup
+ \ifcsname#1\endcsname\csname#1\endcsname\else\definedfont[#1]\fi}
+
+\def\stopstyle
+ {\endgroup}
+
+%D Still experimental (might even go away).
+
+% \definestylecollection[mine]
+
+% \definestyleinstance[mine][default][sorry]
+% \definestyleinstance[mine][tt][bs][ttbs:\rm\sl]
+% \definestyleinstance[mine][tt][bf][ttbf:\rm\sl]
+% \definestyleinstance[mine][bf][\sl]
+% \definestyleinstance[mine][sl][\tt]
+
+% {\bf test \mine test \sl test \mine test \bs oeps \mine oeps {\tt test \mine \bf test}}
+
+\definesystemvariable{sx}
+
+\def\definestylecollection
+ {\dosingleargument\dodefinestylecollection}
+
+\def\dodefinestylecollection[#1]%
+ {\iffirstargument
+ \unexpanded\setvalue{#1}{\styleinstance[#1]}%
+ \def\docommand##1%
+ {\def\dodocommand####1{\letbeundefined{\??sx##1:####1:\commalistelement}}%
+ \processcommacommand[\fontalternativelist,\s!default]\dodocommand}%
+ \processcommacommand[\fontstylelist,\s!default]\docommand
+ \fi}
+
+\def\definestyleinstance
+ {\doquadrupleargument\dodefinestyleinstance}
+
+\def\dodefinestyleinstance[#1][#2][#3][#4]% [name] [rm|ss|tt|..] [sl|bf|...] [whatever]
+ {\iffirstargument
+ \doifundefined{#1}{\definestylecollection[#1]}%
+ \fi
+ \iffourthargument
+ \setvalue{\??sx#1:#2:#3}{#4}%
+ \else\ifthirdargument
+ \setvalue{\??sx#1::#2}{#3}%
+ \else\ifsecondargument
+ \letvalue{\??sx#1::#2}\empty
+ \fi\fi\fi}
+
+\unexpanded\def\styleinstance[#1]% will be faster
+ {%\begingroup\expanded{\infofont[#1:\fontstyle:\fontalternative]}\endgroup
+ \executeifdefined{\??sx#1:\fontstyle:\fontalternative}%
+ {\executeifdefined{\??sx#1:\fontstyle:\s!default}%
+ {\executeifdefined{\??sx#1::\fontalternative}
+ {\getvalue {\??sx#1::\s!default}}}}}
+
+% \unexpanded\def\styleinstance[#1]%
+% {\csname\??sx#1%
+% \ifcsname:\fontstyle:\fontalternative\endcsname
+% :\fontstyle:\fontalternative
+% \else\ifcsname:\fontstyle:\s!default\endcsname
+% :\fontstyle:\s!default
+% \else\ifcsname::\fontalternative\endcsname
+% ::\fontalternative
+% \else\ifcsname::\s!default\endcsname
+% ::\s!default
+% \else
+% % nothing, \relax
+% \fi\fi\fi\fi
+% \endcsname}
+
+%D \Compatibility with \MKIV:
+
+\def\somefontsize{\scaledfont}
+
+\protect \endinput
diff --git a/tex/context/base/font-ini.mkiv b/tex/context/base/font-ini.mkiv
new file mode 100644
index 000000000..c7d515cca
--- /dev/null
+++ b/tex/context/base/font-ini.mkiv
@@ -0,0 +1,3896 @@
+%D \module
+%D [ file=font-ini,
+%D version=1998.09.11, % (second)
+%D version=2001.02.20, % (third)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Initialization,
+%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.
+
+% runtime commands will move to modules
+
+% simplification ... we no longer deal with specific mmtfa specifications
+
+% todo: always fontclass, then less testing
+
+% \definefontfeature[smallcaps][smcp=yes,script=latn]
+% \definefontfeature[smallcaps][SmallCapitals=yes,script=latn]
+% \definefontfeature[smallcaps][Small Capitals=yes,script=latn]
+% \definefontfeature[smallcaps][small capitals=yes,script=latn]
+% \definefontfeature[smallcaps][smallcapitals=yes,script=latn]
+%
+% \definedfont[cambria*smallcaps] test
+
+% \starttext
+% \definefontfeature[basekerned][default][mode=base]
+% \definefontfeature[nodekerned][default][mode=node]
+% \definefontfeature[nonekerned][default][mode=base,kern=no]
+% \setupcolors[state=start]
+% \startoverlay
+% {\vbox{\red \definedfont[Serif*nonekerned at 12pt]\input tufte }}
+% {\vbox{\blue \definedfont[Serif*basekerned at 12pt]\input tufte }}
+% {\vbox{\green\definedfont[Serif*nodekerned at 12pt]\input tufte }}
+% \stopoverlay
+% \stoptext
+
+% \enabletrackers[otf.kerns]
+%
+% \definefontfeature[withkern][default][mode=node]
+% \definefontfeature[nokern] [default][mode=node,kern=no]
+% \definefontfeature[single] [default][mode=node,cpsp=yes]
+% \definefontfeature[simple] [default][mode=node,cpsp=yes,kern=no]
+%
+% {\definedfont[Serif*default] [FGFGFGFGFGFGFGFGFGFGFGFGFG ABCDEFGHIJKLMNOPQRSTUVWXYZ] \par}
+% {\definedfont[Serif*nokern] [FGFGFGFGFGFGFGFGFGFGFGFGFG ABCDEFGHIJKLMNOPQRSTUVWXYZ] \par}
+% {\definedfont[Serif*single] [FGFGFGFGFGFGFGFGFGFGFGFGFG ABCDEFGHIJKLMNOPQRSTUVWXYZ] \par}
+% {\definedfont[Serif*simple] [FGFGFGFGFGFGFGFGFGFGFGFGFG ABCDEFGHIJKLMNOPQRSTUVWXYZ] \par}
+
+% figure out why \fontbody is not expanded
+
+\writestatus{loading}{ConTeXt Font Macros / Initialization}
+
+\registerctxluafile{font-ini}{1.001}
+\registerctxluafile{node-fnt}{1.001} % here
+\registerctxluafile{font-enc}{1.001}
+\registerctxluafile{font-map}{1.001}
+\registerctxluafile{font-syn}{1.001}
+\registerctxluafile{font-log}{1.001}
+\registerctxluafile{font-tfm}{1.001}
+\registerctxluafile{font-enh}{1.001}
+\registerctxluafile{font-afm}{1.001}
+\registerctxluafile{font-cid}{1.001} % cid maps
+\registerctxluafile{font-ott}{1.001} % otf tables
+\registerctxluafile{font-otf}{1.001} % otf main
+\registerctxluafile{font-otd}{1.001} % otf dynamics
+\registerctxluafile{font-oti}{1.001} % otf initialization
+\registerctxluafile{font-otb}{1.001} % otf main base
+\registerctxluafile{font-otn}{1.001} % otf main node
+\registerctxluafile{font-ota}{1.001} % otf analyzers
+\registerctxluafile{font-otp}{1.001} % otf pack
+\registerctxluafile{font-otc}{1.001} % otf context
+\registerctxluafile{font-vf} {1.001}
+\registerctxluafile{font-def}{1.001}
+\registerctxluafile{font-ctx}{1.001}
+\registerctxluafile{font-xtx}{1.001}
+\registerctxluafile{font-fbk}{1.001}
+\registerctxluafile{font-gds}{1.001}
+\registerctxluafile{font-ext}{1.001}
+\registerctxluafile{font-pat}{1.001}
+\registerctxluafile{font-chk}{1.001}
+\registerctxluafile{font-agl}{1.001}
+
+\unprotect
+
+% \def\fontrange#1%
+% {\dofontrange{#1 =\bodyfontsize}}
+%
+% \def\dofontrange#1%
+% {\dodofontrange#1 \relax}% \fontstringA
+%
+% \def\dodofontrange#1 #2 %
+% {\ifdim\bodyfontsize#2%
+% #1\expandafter\gobbleuntilrelax
+% \else
+% \expandafter\dodofontrange
+% \fi}
+%
+% \definefont
+% [crap]
+% [\fontrange
+% {Regular <10pt
+% RegularBold <12pt
+% RegularSlanted <15pt
+% Regular} sa 1]
+%
+% may be better:
+%
+% \definefontrange
+% [crap]
+% [Regular <10pt
+% RegularBold <12pt
+% RegularSlanted <15pt]
+% [Regular sa 1]
+%
+%
+% \dostepwiserecurse{2}{15}{1}
+% {{\switchtobodyfont[\recurselevel pt]\crap test}\endgraf}
+
+% adapted, else wrong interlinespace
+
+\def\setfontparameters
+ {\synchronizefontsfalse
+ \the\everybodyfont
+ \synchronizefontstrue}
+
+% handy
+
+\newcounter\pushedfont
+
+\def\savefont
+ {\edef\savedfont{\the\font}%
+ \pushmacro\savedfont}
+
+\def\restorefont
+ {\popmacro\savedfont
+ \savedfont}
+
+\def\pushcurrentfont
+ {\edef\popcurrentfont
+ {\noexpand\def\noexpand\fontbody{\fontbody}%
+ \noexpand\def\noexpand\fontstyle{\fontstyle}%
+ \noexpand\dosetcurrentfontalternative{\fontalternative}%
+ \noexpand\dosetcurrentfontsize{\fontsize}%
+ \noexpand\synchronizefont}}
+
+% \definetypeface[one][rm][serif][computer-roman][default]
+% \definetypeface[two][rm][serif][computer-roman][default][rscale=.9]
+%
+% {\one \bf test \two test}
+% {\one \bf test \pushcurrentfont \two \popcurrentfont test}
+
+%D \macros
+%D {definedfont,startfont,doiffontcharelse}
+%D
+%D A couple of relatively new macros:
+
+% \newtoks \everydefinedfont % not ot be confused with \everydefinefont
+
+\def\dodefinedfont[#1]%
+ {\iffirstargument\definefont[thedefinedfont][#1]\fi % we can speed this one up
+ \csname thedefinedfont\endcsname
+ \the\everydefinedfont}
+
+\unexpanded\def\definedfont
+ {\dosingleempty\dodefinedfont}
+
+\unexpanded\def\startfont
+ {\bgroup\definedfont}
+
+\unexpanded\def\stopfont
+ {\egroup}
+
+\def\doiffontcharelse#1#2%
+ {\bgroup
+ \definedfont[#1]%
+ \iffontchar\font#2\relax
+ \egroup\expandafter\firstoftwoarguments
+ \else
+ \egroup\expandafter\secondoftwoarguments
+ \fi}
+
+%D For more detailed (and historic information) we refer to the file
+%D \type {font-ini.mkii}. Here we have a much simplified lower level
+%D implementation due to a different approach to math. Also the chapter
+%D on fonts in the reference manual explains a lot.
+
+%D \macros
+%D {rm,ss,tt,hw,cg}
+%D
+%D Fonts are defined in separate files. When we define a font,
+%D we distinguish between several styles. In most cases we will
+%D use:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC roman regular serif \NC \type{\rm} \NC\FR
+%D \NC sansserif sans support \NC \type{\ss} \NC\MR
+%D \NC type teletype mono \NC \type{\tt} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D The number of styles is not limited to these three. When
+%D using Lucida Bright we can for instance also define:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC handwritten \NC \type{\hw} \NC\FR
+%D \NC calligraphic \NC \type{\cg} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D Within such a font set (\type{cmr}) and style (\type{\rm})
+%D we can define a number of text font alternatives:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC typeface \NC \type{\tf} \NC\FR
+%D \NC boldface \NC \type{\bf} \NC\MR
+%D \NC slanted \NC \type{\sl} \NC\MR
+%D \NC italic \NC \type{\it} \NC\MR
+%D \NC boldslanted \NC \type{\bs} \NC\MR
+%D \NC bolditalic \NC \type{\bi} \NC\MR
+%D \NC smallcaps \NC \type{\sc} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D Internally fonts are stored as combination of size, style
+%D and alternative, e.g. \type{12pt}+\type{\ss}+\type{\bf}.
+%D Users are not confronted with sizes, but use the style or
+%D style+alternative to activate them.
+%D
+%D During the definition of a bodyfont one can also declare the
+%D available larger alternatives:
+%D
+%D \starttyping
+%D \tf \tfa \tfb \tfc ...
+%D \bf \bfa \bfb \bfc ...
+%D \sl \sla \slb \slc ...
+%D \stoptyping
+%D
+%D The smaller ones are automatically supplied and derived from
+%D the the bodyfont environment.
+%D
+%D \starttyping
+%D \tfx \tfxx
+%D \bfx \bfxx
+%D \slx \slxx
+%D \stoptyping
+%D
+%D There are only two smaller alternatives per style. The
+%D larger alternatives on the other hand have no limitations.
+%D
+%D These larger alternatives are mostly used in chapter and
+%D section titles or on title pages. When one switches to a
+%D larger alternative, the bold an other ones automatically
+%D adapt themselves:
+%D
+%D \startbuffer
+%D \tfd Hi \bf there\sl, here \tfb I \bf am
+%D \stopbuffer
+%D
+%S \startnarrower
+%D \typebuffer
+%S \stopnarrower
+%D
+%D therefore becomes:
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D Maybe this mechanism isn't always as logic, but as said
+%D before, we tried to make it as intuitive as possible.
+%D
+%D So a specific kind of glyph can be characterized by:
+%D
+%D \startnarrower
+%D family (cmr) + bodyfont (12pt) + style (rm) + alternative (bf) + size (a)
+%D \stopnarrower
+%D
+%D The last component (the size) is optional.
+%D
+%D We introduced \type{\tf} as command to call for the current
+%D normally sized typeface. This commands results in roman,
+%D sans serif, teletype or whatever style is in charge. Such
+%D rather massive switches of style sometimes take more
+%D processing time than comfortable. Of course there is a
+%D workaround for this: we can call fonts directly by means of
+%D commands like:
+%D
+%D \starttyping
+%D \rmtf \sssl \tttf \rmbsa
+%D \stoptyping
+%D
+%D One should realize that this fast calls have limitations,
+%D they lack for instance automatic super- and subscript
+%D support.
+%D
+%D This leaves us two more commands: \type{\tx} and
+%D \type{\txx}. These activate a smaller and even more smaller
+%D font than the current one and adapt themselves to the
+%D current alternative, so when \type{\bf} is active,
+%D \type{\tx} gives a smaller boldface, which in turn can be
+%D called directly by \type{\bfx}.
+%D
+%D These two smaller alternatives are specified by the bodyfont
+%D environment and therefore not necessarily have similar sizes
+%D as \type{\scriptsize} and \type{\scriptscriptsize}. The main
+%D reason for this incompatibility (which can easily be undone)
+%D lays in the fact that we often want a bit bigger characters
+%D than in math mode. In \CONTEXT\ for instance the \type{\tx}
+%D and \type{\txx} commands are used for surrogate
+%D \cap{smallcaps} which support both nesting and alternatives,
+%D like in {\bf\cap{a \cap{small} world}}, which was typeset by
+%D
+%D \starttyping
+%D \bf\cap{a \cap{small} world}
+%D \stoptyping
+%D
+%D And compare $\rm \scriptstyle THIS$ with the slightly larger
+%D \cap{THIS}: \ruledhbox{$\rm \scriptstyle scriptstyle: THIS$}
+%D or \ruledhbox{\cap{x style: THIS}} makes a big difference.
+%D
+%D The \type{x..d} sizes should be used grouped. If you
+%D don't group them, i.e. call them in a row, \CONTEXT\ will
+%D not be able to sort out your intention (\type {x} inside
+%D \type {d} inside \type {x}. etc.). The following table
+%D demonstrates this:
+%D
+%D \def\FontState{\setstrut\ruledhbox{\strut Hello}}
+%D
+%D \starttabulate[|||||]
+%D \HL
+%D \NC \rlap{\quad\bf grouped} \NC \NC \type {\tx} \NC \type {\txx} \NC \NR
+%D \HL
+%D \NC \type{\tfx} \NC \tfx \FontState \NC \tfx \tx \FontState \NC \tfx \txx \FontState \NC \NR
+%D \NC \type{\tfxx} \NC \tfxx \FontState \NC \tfxx\tx \FontState \NC \tfxx\txx \FontState \NC \NR
+%D \NC \type{\tf} \NC \tf \FontState \NC \tf \tx \FontState \NC \tf \txx \FontState \NC \NR
+%D \NC \type{\tfa} \NC \tfa \FontState \NC \tfa \tx \FontState \NC \tfa \txx \FontState \NC \NR
+%D \NC \type{\tfb} \NC \tfb \FontState \NC \tfb \tx \FontState \NC \tfb \txx \FontState \NC \NR
+%D \NC \type{\tfc} \NC \tfc \FontState \NC \tfc \tx \FontState \NC \tfc \txx \FontState \NC \NR
+%D \NC \type{\tfd} \NC \tfd \FontState \NC \tfd \tx \FontState \NC \tfd \txx \FontState \NC \NR
+%D \NC \type{\tfx} \NC \tfx \FontState \NC \tfx \tx \FontState \NC \tfx \txx \FontState \NC \NR
+%D \NC \type{\tfxx} \NC \tfxx \FontState \NC \tfxx\tx \FontState \NC \tfxx\txx \FontState \NC \NR
+%D \HL
+%D \stoptabulate
+%D
+%D \blank
+%D
+%D \starttabulate[|||||]
+%D \HL
+%D \NC \rlap{\quad\bf stacked} \NC \NC \type {\tx} \NC \type {\txx} \NC \NR
+%D \HL
+%D \NC \type{\tfx}
+%D \NC \tfx \FontState
+%D \NC \tfx \tx \FontState
+%D \NC \tfx \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfxx}
+%D \NC \tfx\tfxx \FontState
+%D \NC \tfx\tfxx \tx \FontState
+%D \NC \tfx\tfxx \txx \FontState
+%D \NC \NR
+%D \NC \type{\tf}
+%D \NC \tfx\tfxx\tf \FontState
+%D \NC \tfx\tfxx\tf \tx \FontState
+%D \NC \tfx\tfxx\tf \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfa}
+%D \NC \tfx\tfxx\tf\tfa \FontState
+%D \NC \tfx\tfxx\tf\tfa \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfb}
+%D \NC \tfx\tfxx\tf\tfa\tfb \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfc}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfd}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfx}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfxx}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \txx \FontState
+%D \NC \NR
+%D \HL
+%D \stoptabulate
+%D
+%D Remark: math support has changed a bit.
+
+%D \macros
+%D {uchar}
+%D
+%D This macro prepares \CONTEXT\ for \UNICODE\ support. By
+%D defining it here, we have at least an safeguard for utility
+%D file reading.
+
+\ifdefined\uchar\else \unexpanded\def\uchar#1#2{[#1,#2]} \fi
+
+%D We define some (very private) constants to improve speed,
+%D memory usage and consistency.
+
+\def\@size@ {@f@si@} % bodyfont size prefix (12pt etc)
+\def\@style@ {@f@st@} % full style prefix (roman etc)
+\def\@shortstyle@ {@f@sh@} % short style prefix (rm etc)
+\def\@letter@ {@f@le@} % first alternative typeface
+\def\@noletter@ {@f@no@} % second alternative typeface
+\def\@fontclass@ {@f@cl@} % fontclass
+
+%D \macros
+%D {fontclass, defaultfontclass}
+%D
+%D The fontclass model was introduced a while after we implement
+%D the basic font model and at that time we still defaulted to
+%D no model at all. Nowadays we default to the \type {modern}
+%D fontclass.
+
+\let\fontclass \empty
+\let\defaultfontclass\empty
+
+%D \macros
+%D {textonly}
+%D
+%D Traditionally math has a big impact on font definitions, mainly
+%D because we need to define alphabet variants using families and
+%D fonts. This means that one can easily get 10 fonts loaded per
+%D math size. In \MKIV\ we use a different approach: one family
+%D which has either a virtual font made of traditional fonts, or
+%D an \OPENTYPE\ font that has it all.
+%D
+%D We currently use only one math family but in the future we
+%D might consider using a second one for bold math. For the
+%D moment we keep the \MKII\ method of using a token register
+%D for definitions but we already dropped the text and symbols
+%D ones since they now live in the same family.
+
+\newtoks \mathstrategies
+
+\newif\ifsynchronizemathfonts \synchronizemathfontstrue
+
+\def\synchronizemath % math stuff in mmode
+ {\ifsynchronizemathfonts\the\mathstrategies\fi}
+
+\def\textonly{\synchronizemathfontsfalse} % document this
+
+%D The main math font definer. We have removed some optimized
+%D code simply because we now always have a fontclass. We could
+%D check for fontclass being default or empty and save a few
+%D tests but it does not help us when no math is defined.
+
+\chardef\mrfam\zerocount % math regular
+\chardef\mbfam\plusone % math bold
+
+\unexpanded\def\mr{\ifmmode\fam\zerocount\else\setcurrentfontalternative\c!mr\fi} % \fam\csname\c!mr fam\endcsname
+\unexpanded\def\mb{\ifmmode\fam\plusone \else\setcurrentfontalternative\c!mb\fi} % \fam\csname\c!mb fam\endcsname
+
+\def\mathtextsuffix {-text}
+\def\mathscriptsuffix {-script}
+\def\mathscriptscriptsuffix{-scriptscript}
+
+% \let\mathsizesuffix\empty
+
+\let\currentmathsize\empty
+
+\def\mathsizesuffix{\ifcase0\currentmathsize\or\mathtextsuffix\or\mathscriptsuffix\or\mathscriptscriptsuffix\fi}
+
+\def\dodosetmathfamily#1#2%
+ {\ifcsname\fontclass \fontbody\c!mm\fontfamily\fontsize\currentmathsize\endcsname \autofontsizefalse
+ \csname\fontclass \fontbody\c!mm\fontfamily\fontsize\currentmathsize\endcsname \else
+ \ifcsname\fontclass \fontbody\c!mm\fontfamily \currentmathsize\endcsname \autofontsizetrue
+ \csname\fontclass \fontbody\c!mm\fontfamily \currentmathsize\endcsname \else
+ \dodosetmathfamilyx#1#2%
+ \fi\fi
+ #1#2\font}
+
+\def\dodosetmathfamilyx#1#2%
+ {\ifcsname\defaultfontclass\fontbody\c!mm\fontfamily\fontsize\currentmathsize\endcsname \autofontsizefalse
+ \csname\defaultfontclass\fontbody\c!mm\fontfamily\fontsize\currentmathsize\endcsname \else
+ \ifcsname\defaultfontclass\fontbody\c!mm\fontfamily \currentmathsize\endcsname \autofontsizetrue
+ \csname\defaultfontclass\fontbody\c!mm\fontfamily \currentmathsize\endcsname \else
+ \dodosetmathfamilyxx#1#2%
+ \fi\fi}
+
+\def\dodosetmathfamilyxx#1#2%
+ {\ifcsname \fontbody\c!mm\fontfamily\fontsize\currentmathsize\endcsname \autofontsizefalse
+ \csname \fontbody\c!mm\fontfamily\fontsize\currentmathsize\endcsname \else
+ \ifcsname \fontbody\c!mm\fontfamily \currentmathsize\endcsname \autofontsizetrue
+ \csname \fontbody\c!mm\fontfamily \currentmathsize\endcsname \else
+ \nullfont \autofontsizetrue
+ \fi\fi}
+
+\def\dosetmathfamily#1#2%
+ {\let\savedfontbody\fontbody % op hoger plan
+ \let\fontfamily#2%
+ \let\currentmathsize\!!plusthree\let\fontbody\scriptscriptface\dodosetmathfamily\scriptscriptfont#1%
+ \let\currentmathsize\!!plustwo \let\fontbody\scriptface \dodosetmathfamily\scriptfont #1%
+ \let\currentmathsize\!!plusone \let\fontbody\textface \dodosetmathfamily\textfont #1%
+ \let\currentmathsize\empty
+ \let\fontbody\savedfontbody
+ \autofontsizefalse}
+
+\appendtoks
+ \dosetmathfamily\mrfam\c!mr
+\to \mathstrategies
+
+% not official !
+
+\chardef\boldmathmode\zerocount % might change ... maybe \mathfontsupport 1 (normal) 2 (bold too)
+
+\def\enableboldmath {\chardef\boldmathmode\plusone } % todo: \setupbodyfont[boldmath,...]
+\def\disableboldmath{\chardef\boldmathmode\zerocount}
+
+\appendtoks
+ \ifcase\boldmathmode\or\dosetmathfamily\mbfam\c!mb\fi
+\to \mathstrategies
+
+% \chardef\msfam\plustwo % math symbol
+%
+% \def\c!ms{ms}
+%
+% \unexpanded\def\ms{\ifmmode\fam\plustwo\else\setcurrentfontalternative\c!ms\fi}
+%
+% \chardef\symbolmathmode\zerocount
+%
+% \def\enablesymbolmath {\chardef\symbolmathmode\plusone }
+% \def\disablesymbolmath{\chardef\symbolmathmode\zerocount}
+%
+% \appendtoks
+% \ifcase\symbolmathmode\or\dosetmathfamily\msfam\c!ms\fi
+% \to \mathstrategies
+
+%D All used styles, like rm, ss and tt, are saved in a comma
+%D separated list. Appart from practical limitations one can
+%D define as many styles as needed.
+
+\def\fontrelativesizelist{\s!text,\s!script,\s!scriptscript,\c!x,\c!xx,\c!big,\c!small}
+
+%D There are several ways to specify a font. Three of them are
+%D pure \TeX\ ones, the fourth one is new:
+%D
+%D \starttyping
+%D \font\name=cmr12
+%D \font\name=cmr12 at 10pt
+%D \font\name=cmr12 scaled 2
+%D \font\name=cmr12 sa 1.440
+%D \stoptyping
+%D
+%D The non||\TEX\ alternative \type{sa} stands for {\em scaled
+%D at}. This means as much as: scale the bodyfontsize with this
+%D factor. The scaled option is not that useful as one needs to
+%D know the design size.
+%D
+%D Because \type {sa} (scaled at) and \type {mo} (mapped on)
+%D are not low level \TEX\ supported alternatives, we have to
+%D test for it ourselves. In doing so, we need an auxiliary
+%D \DIMENSION. We cannot use \type{\scratchdimen} because font
+%D loading can happen at any moment due to postponed loading.
+%D We could instead have used dirty grouping tricks, but this
+%D one works too.
+
+% \enableexperiments[fonts.autorscale]
+%
+% \starttypescript[mscore]
+% \definetypeface [mscore] [rm] [serif] [mscoretimes] [default]
+% \definetypeface [mscore] [ss] [sans] [mscorearial] [default] [rscale=auto] % 0.860]
+% \definetypeface [mscore] [tt] [mono] [mscorecourier] [default] [rscale=auto] % 1.065]
+% \definetypeface [mscore] [mm] [math] [times] [default] [rscale=auto] % 1.020]
+% \stoptypescript
+%
+% \starttext
+% \setupbodyfont[mscore,12pt]
+% \startTEXpage
+% test \ss test \tt test
+% \stopTEXpage
+% \stoptext
+
+\let\defaultrelativefontsize \plusone
+\let\localrelativefontsize \plusone
+\def\localabsolutefontsize {\fontbody}
+
+\let\relativefontsize \defaultrelativefontsize
+
+% \def\saverelativefontsize#1#2% #1=rm|ss|.. #2=waarde
+% {\setxvalue{\fontclass#1\s!rscale}{#2}}
+
+\def\checkrelativefontid
+ {\ifcsname\??tf\fontclass\s!rname\endcsname
+ \@EA\let\@EA\relativefontid\csname\??tf\fontclass\s!rname\endcsname
+ \else
+ \@EA\xdef\csname\??tf\fontclass\s!rname\endcsname{\the\lastfontid}%
+ \let\relativefontid\empty
+ \fi}
+
+\def\checkrelativefontsize#1%
+ {\edef\relativefontsize
+ {\ifcsname\fontclass#1\s!rscale\endcsname
+ \csname\fontclass#1\s!rscale\endcsname
+ \else\ifcsname\defaultfontclass#1\s!rscale\endcsname
+ \csname\defaultfontclass#1\s!rscale\endcsname
+ \else
+ \defaultrelativefontsize
+ \fi\fi}%
+ \ifx\relativefontsize\v!auto
+ \let\relativefontsize\plusone
+ \checkrelativefontid
+ \else
+ \let\relativefontid\minusone
+ \fi}
+
+%D Scaling macros:
+%D
+%D This system is somewhat complicated by two (possible conflicting)
+%D demands:
+%D
+%D \startitemize
+%D \item We support wildcards like \type {sa *} which will adapt
+%D to the current size. This is also the default specification.
+%D \item We support named scales like \type {sa d}; beware: \type
+%D {x} and \type {xx} are valid scales but they are not alway
+%D the same as the ones used in for instance \type {\bfx} because
+%D there the sized come from the bodyfont environment. In the
+%D future there maybe a switch that also honors the environment
+%D in named scales.
+%D \stopitemize
+
+%D Keep in mind that the smaller sizes are just for text super and
+%D subscripts while larger sizes can be used in titles where for
+%D instance math follows the size.
+
+% b:x{\definedfont[SerifBold sa b]x}{\bfb x $x^x$}\par
+% 1:x{\definedfont[SerifBold sa 1]x}{\bf x $x^x$}\par
+% x:x{\definedfont[SerifBold sa x]x}{\bfx x $x^x$}\par
+% xx:x{\definedfont[SerifBold sa xx]x}{\bfxx x $x^x$}\par
+%
+% *:x{\definedfont[Serif sa *]x}\par
+% 1:x{\definedfont[Serif sa 1]x}\par
+% 2:x{\definedfont[Serif sa 2]x}\par
+% 3:x{\definedfont[Serif sa 3]x}\par
+% 4:x{\definedfont[Serif sa 4]x}\par
+% 5:x{\definedfont[Serif sa 5]x}\par
+%
+% {\definedfont[cmbx10 at 10pt]x\definedfont[cmbx8 at 10pt]x}
+
+\def\safontscale{\number\dimexpr\localabsolutefontsize\relax}
+\def\mofontscale{\number\dimexpr\setmappedfontsize\localabsolutefontsize\relax}
+
+\let\somefontname\s!unknown
+\let\somefontspec\s!unknown
+\let\somefontsize\zerocount
+
+\newcount\scaledfontmode
+\newdimen\scaledfontsize
+\newtoks \everydefinefont
+\newcount\lastfontid
+
+\def\currentfontbodysize
+ {\ifcsname\??ft\s!default\somefontsize\endcsname
+ \csname\??ft\s!default\somefontsize\endcsname
+ \else
+ \somefontsize
+ \fi}
+
+\let\relativefontid\empty
+
+\def\lowleveldefinefont#1#2% #2 = cs
+ {%
+ \ctxlua{fonts.define.command_1("\luaescapestring{#1}")}% the escapestring catches at \somedimen
+ % sets \scaledfontmode and \somefontname and \somefontsize
+ \ifcase\scaledfontmode\relax
+ % none, avoid the designsize if possible
+ \scaledfontsize-1000\scaledpoint
+ \or
+ % at
+ \scaledfontsize\somefontsize
+ \or
+ % sa
+ \scaledfontsize\localabsolutefontsize\relax
+ \scaledfontsize\currentfontbodysize\scaledfontsize
+ \or
+ % mo
+ \scaledfontsize\setmappedfontsize\localabsolutefontsize
+ \scaledfontsize\currentfontbodysize\scaledfontsize
+ \or
+ % scaled, don't use this one as it's unpredictable
+ \scaledfontsize-\somefontsize\scaledpoint
+ \fi
+ \scaledfontsize\localrelativefontsize\scaledfontsize
+ \ifautofontsize
+ \scaledfontsize\currentfontbodyscale\scaledfontsize
+ \fi
+ \edef\somefontspec{at \number\scaledfontsize sp}%
+ \edef\somefontfile{\truefontname\somefontname}%
+ \ifx\somefontfile\s!unknown
+ \edef\somefontfile{\defaultfontfile}%
+ \fi
+ \updatefontparameters
+ \updatefontclassparameters
+ \ctxlua{fonts.define.command_2(
+ \ifx\fontclass\empty false\else true\fi,
+ "#2", % cs, trailing % is gone
+ "\somefontfile",
+ \number\scaledfontsize,
+ "\@@fontclassfeatures",
+ "\@@fontfeatures",
+ "\@@fontclassfallbacks",
+ "\@@fontfallbacks",
+ 0\currentmathsize,
+ \number\dimexpr\textface\relax,
+ "\relativefontid" % experiment
+ )}%
+ \edef\somefontspec{at \somefontsize}% we need the resolved designsize (for fallbacks)
+ \expandafter\let\expandafter\lastrawfontcall\csname#2\endcsname
+ \the\everydefinefont}
+
+\def\updatefontclassparameters
+ {\edef\@@fontclassfeatures {\ifcsname\fontclass\fontstyle\s!features \endcsname\csname\fontclass\fontstyle\s!features \endcsname\fi}%
+ \edef\@@fontclassfallbacks{\ifcsname\fontclass\fontstyle\s!fallbacks\endcsname\csname\fontclass\fontstyle\s!fallbacks\endcsname\fi}}
+
+% resolve
+
+\def\@@thefeaturesyes#1%
+ {\ifcsname\??ff\fontclass#1\s!features \endcsname\@EA\let\@EA\@@fontfeatures \csname\??ff\fontclass#1\s!features \endcsname\else
+ \ifcsname\??ff #1\s!features \endcsname\@EA\let\@EA\@@fontfeatures \csname\??ff #1\s!features \endcsname\else
+ \ifcsname\??ff\fontclass #1\endcsname\@EA \@@thefeaturesyes \csname\??ff\fontclass #1\endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thefeaturesyes \csname\??ff #1\endcsname\else
+ \let \@@fontfeatures \empty \fi\fi\fi\fi}
+
+\def\@@thefallbacksyes#1%
+ {\ifcsname\??ff\fontclass#1\s!fallbacks\endcsname\@EA\let\@EA\@@fontfallbacks \csname\??ff\fontclass#1\s!fallbacks\endcsname\else
+ \ifcsname\??ff #1\s!fallbacks\endcsname\@EA\let\@EA\@@fontfallbacks \csname\??ff #1\s!fallbacks\endcsname\else
+ \ifcsname\??ff\fontclass #1\endcsname\@EA \@@thefallbacksyes\csname\??ff\fontclass #1\endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thefallbacksyes\csname\??ff #1\endcsname\else
+ \let \@@fontfallbacks \empty \fi\fi\fi\fi}
+
+\def\@@thefeaturesnop#1%
+ {\ifcsname\??ff#1\s!features \endcsname\@EA\let\@EA\@@fontfeatures \csname\??ff#1\s!features \endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thefeaturesnop \csname\??ff #1\endcsname\else
+ \let \@@fontfeatures \empty \fi\fi}
+
+\def\@@thefallbacksnop#1%
+ {\ifcsname\??ff#1\s!fallbacks\endcsname\@EA\let\@EA\@@fontfallbacks \csname\??ff#1\s!fallbacks\endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thefallbacksnop\csname\??ff #1\endcsname\else
+ \let \@@fontfallbacks \empty \fi\fi}
+
+\def\updatefontparametersyes
+ {\@@thefeaturesyes \somefontname
+ \@@thefallbacksyes\somefontname}
+
+\def\updatefontparametersnop
+ {\@@thefeaturesnop \somefontname
+ \@@thefallbacksnop\somefontname}
+
+\def\updatefontparameters
+ {\ifx\fontclass\empty\updatefontparametersnop\else\updatefontparametersyes\fi}
+
+\let\@@fontclassfeatures \empty
+\let\@@fontclassfallbacks\empty
+
+\let\@@fontfallbacks\empty
+\let\@@fontfeatures \empty
+\let\@@hyphenchar \empty % todo, will go to encoding
+
+%D This brings down maps processing from 466 to 309 seconds
+%D ($-33$\%) and mfonts from 42 to 34 seconds ($-15$\%).
+
+\newif\ifskipfontcharacteristics \skipfontcharacteristicstrue
+
+%D When fontclasses are used, we define the font global,
+%D since namespaces are used. Otherwise we parse the specs
+%D each time.
+
+\let\fontfile\s!unknown
+
+% \definefontfeature[slanted] [default][slant=.25]
+% \definefontfeature[stretched][default][stretch=2]
+%
+% \start \definedfont[SerifBold*slanted at 20pt] \ruledhbox{Test!} \stop
+% \start \definedfont[SerifBold*stretched at 20pt] \ruledhbox{Test!} \stop
+
+% \definefontfeature[default] [liga=yes,texligatures=yes,texquotes=yes]
+% \definefontfeature[default-caps][liga=yes,texligatures=yes,texquotes=yes,smcp=yes,script=latn]
+%
+% \starttypescript [serif] [palatino-nova-regular] [name]
+% \definefontsynonym[Serif] [palatinonova-regular][features=default]
+% \definefontsynonym[SerifCaps][palatinonova-regular][features=default-caps] % also sets Serif
+% \stoptypescript
+%
+% \starttypescript [serif] [palatino-nova-regular] [name]
+% \definefontsynonym[Serif] [palatinonova-regular*default]
+% \definefontsynonym[SerifCaps] [palatinonova-regular*default-caps]
+% \stoptypescript
+
+% \definetypeface[mainface][rm][serif][palatino-nova-regular][default] \setupbodyfont[mainface]
+%
+% \starttext
+% ``Test'' -- --- ff fi fl \sc ``Test'' -- --- ff fi fl
+% \stoptext
+
+% \starttext
+% \definefont
+% [blabla]
+% [name:Latin Modern Something]
+% \definefont
+% [blabla]
+% [file:texnansi-lmr10]
+% \blabla test
+% \definefont
+% [blabla]
+% [texnansi-lmtt10]
+% \blabla test
+% \stoptext
+
+% \starttext
+%
+% \setupcolors[state=start]
+%
+% \definefontfeature
+% [default-base]
+% [script=latn,language=dflt,liga=yes,kern=yes,tlig=yes,trep=yes]
+% \definefontfeature
+% [default-node]
+% [script=latn,language=dflt,liga=yes,kern=yes,tlig=yes,trep=yes,mode=node]
+% \definefontfeature
+% [default-none]
+% [script=latn,language=dflt,liga=yes,kern=no, tlig=yes,trep=yes]
+%
+% \startoverlay
+% {\vtop{\color[red] {\font\test=name:lmroman12regular*default-node \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[green]{\font\test=name:lmroman12regular*default-base \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[blue] {\font\test=name:lmroman12regular*default-none \test \input ward \input zapf \input linden }}}
+% \stopoverlay
+%
+% \blank
+%
+% \startoverlay
+% {\vtop{\color[red] {\font\test=name:texgyrepagella*default-node \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[green]{\font\test=name:texgyrepagella*default-base \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[blue] {\font\test=name:texgyrepagella*default-none \test \input ward \input zapf \input linden }}}
+% \stopoverlay
+%
+% \blank
+%
+% \startoverlay
+% {\vtop{\color[red] {\font\test=name:palatinonovaregular*default-node \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[green]{\font\test=name:palatinonovaregular*default-base \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[blue] {\font\test=name:palatinonovaregular*default-none \test \input ward \input zapf \input linden }}}
+% \stopoverlay
+%
+% \startoverlay
+% {\vtop{\color[red] {\font\test=name:OfficinaSerifBookITC*default-node \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[green]{\font\test=name:OfficinaSerifBookITC*default-base \test \input ward \input zapf \input linden }}}
+% {\vtop{\color[blue] {\font\test=name:OfficinaSerifBookITC*default-none \test \input ward \input zapf \input linden }}}
+% \stopoverlay
+%
+% \definefontfeature[superdefault][default][compose=yes]
+%
+% {\font\oeps=name:lmroman10regular*default at 30pt \oeps test \char7683}
+% {\font\oeps=name:lmroman10regular*superdefault at 30pt \oeps test \char7683}
+%
+% \stoptext
+
+\def \defaultfontfile{\truefontname{Normal}} % was cmtt10, but that one is gone
+\edef\nullfontname {\fontname\nullfont}
+
+%D \macros
+%D {everyfont,everyfontswitch}
+%D
+%D For special purposes, we provide a hook.
+
+% \newevery \everyfont \relax
+% \newevery \everyfontswitch \relax
+
+%D We also accept \type{sa a}||\type{sa d} as specification.
+
+%D \macros
+%D {definefontsynonym, doifelsefontsynonym,
+%D expandfontsynonym, truefontname, truefontdata}
+%D
+%D While looking for fonts, fontsynonyms are used for accessing
+%D the files!
+%D
+%D \starttyping
+%D \definefontsynonym[Serif][Lucida-Bright]
+%D \definefontsynonym[Lucida-Bright][lbr][encoding=texnansi]
+%D \stoptyping
+
+\def\classfont#1#2{#1#2} % \definefont[whatever][\classfont{xx}{yy} at 10pt]
+
+% We need to move the feature into the filename else it may be
+% overloaded by another reference. For instance the definition of
+% a regular and caps variant can use the same font.
+
+% We could use an indirect method ... store in 'array' and refer to
+% slot.
+
+\unexpanded\def\definefontsynonym[#1]#2[#3]%
+ {\edef\@@fontname{#1}%
+ \edef\@@fontfile{#3}%
+ \ifx\fontclass\empty
+ \expandafter\dodefinefontsynonymnop
+ \else
+ \expandafter\dodefinefontsynonymyes
+ \fi}
+
+\def\dodefinefontsynonymnop
+ {\@EA\let\csname\??ff\@@fontname\endcsname\@@fontfile % maybe just #1 #3, saves expansion
+ \doifnextoptionalelse\dododefinefontsynonymnop\nonodefinefontsynonymnop}
+
+\def\dodefinefontsynonymyes
+ {\@EA\let\csname\??ff\fontclass\@@fontname\endcsname\@@fontfile % maybe just #1 #3, saves expansion
+ \doifnextoptionalelse\dododefinefontsynonymyes\nonodefinefontsynonymyes}
+
+\def\dododefinefontsynonymnop[#1]%
+ {\let\@@ff@@features \undefined
+ \let\@@ff@@fallbacks\undefined
+ \expandafter\dogetfontparameternop#1,]=,}
+
+\def\dododefinefontsynonymyes[#1]%
+ {\let\@@ff@@features \undefined
+ \let\@@ff@@fallbacks\undefined
+ \expandafter\dogetfontparameteryes#1,]=,}
+
+\def\dogetfontparameternop#1=#2,%
+ {\if]#1%
+ \dodododefinefontsynonymnop
+ \else
+ \expandafter\def\csname @@ff@@#1\endcsname{#2}%
+ \expandafter\dogetfontparameternop
+ \fi}
+
+\def\dogetfontparameteryes#1=#2,%
+ {\if]#1%
+ \dodododefinefontsynonymyes
+ \else
+ \expandafter\def\csname @@ff@@#1\endcsname{#2}%
+ \expandafter\dogetfontparameteryes
+ \fi}
+
+% hm, was wrong, class/global reversed
+
+\let\fcglobal\global
+\let\fcxdef \xdef
+\let\fcglet \glet
+
+\def\nonodefinefontsynonymnop
+ {\@EA\let\csname\??ff\@@fontname\s!features \endcsname\undefined
+ \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\undefined}
+
+\def\nonodefinefontsynonymyes
+ {\fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\undefined
+ \fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\undefined}
+
+\def\dodododefinefontsynonymnop
+ {\@EA\let\csname\??ff\@@fontname\s!features \endcsname\@@ff@@features
+ \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks}
+
+\def\dodododefinefontsynonymyes
+ {\fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\@@ff@@features
+ \fcglobal\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks}
+
+\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater
+
+\unexpanded\def\setupfontsynonym
+ {\dodoubleempty\dosetupfontsynonym}
+
+\def\dosetupfontsynonym[#1][#2]% not yet supported, will do when needed
+ {}
+
+\def\truefontname#1%
+ {\@EA\dotruefontname#1*\empty*\relax}
+
+\def\dotruefontname#1*#2#3*#4\relax
+ {\ifcsname\??ff\fontclass#1\endcsname
+ \ifx#2\empty
+ \@EA\truefontname\csname\??ff\fontclass#1\endcsname
+ \else
+ \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname*#2#3%
+ \fi
+ \else\ifcsname\??ff\defaultfontclass#1\endcsname
+ \ifx#2\empty
+ \@EA\truefontname\csname\??ff\defaultfontclass#1\endcsname
+ \else
+ \@EA\redotruefontname\csname\??ff\defaultfontclass#1\endcsname*#2#3%
+ \fi
+ \else\ifcsname\??ff#1\endcsname
+ \ifx#2\empty
+ \@EA\truefontname\csname\??ff#1\endcsname
+ \else
+ \@EA\redotruefontname\csname\??ff#1\endcsname*#2#3%
+ \fi
+ \else
+ #1\ifx#2\empty\else*#2#3\fi
+ \fi\fi\fi}
+
+\def\redotruefontname#1%
+ {\@EA\dodotruefontname#1*\relax}
+
+\def\dodotruefontname#1*#2\relax
+ {\ifcsname\??ff\fontclass#1\endcsname
+ \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname
+ \else\ifcsname\??ff\defaultfontclass#1\endcsname
+ \@EA\redotruefontname\csname\??ff\defaultfontclass#1\endcsname
+ \else\ifcsname\??ff#1\endcsname
+ \@EA\redotruefontname\csname\??ff#1\endcsname
+ \else
+ #1%
+ \fi\fi\fi}
+
+\def\expandfontsynonym#1#2% #2 := onelevelexpansion(#1)
+ {\ifcsname\??ff\fontclass#2\endcsname
+ \expandafter\def\expandafter#1\expandafter{\csname\??ff\fontclass#2\endcsname}%
+ \else\ifcsname\??ff\defaultfontclass#2\endcsname
+ \expandafter\def\expandafter#1\expandafter{\csname\??ff\defaultfontclass#2\endcsname}%
+ \fi\fi}
+
+\def\doifelsefontsynonym#1%
+ {\ifcsname\??ff\fontclass#1\endcsname
+ \@EA\firstoftwoarguments
+ \else\ifcsname\??ff\defaultfontclass#1\endcsname
+ \@EAEAEA\firstoftwoarguments
+ \else
+ \@EAEAEA\secondoftwoarguments
+ \fi\fi}
+
+% \definetypeface[palatino][rm][serif][palatino,allbold][default]
+%
+% \startfontclass[palatino]
+% \definefontsynonym [Serif] [SerifBold]
+% \definefontsynonym [SerifItalic] [SerifBoldItalic]
+% \definefontsynonym [SerifSlanted] [SerifBoldSlanted]
+% \definefontsynonym [SerifCaps] [SerifBold]
+% \stopfontclass
+%
+% \setupbodyfont[palatino]
+
+\unexpanded\def\startfontclass
+ {\dosingleempty\dostartfontclass}
+
+\def\dostartfontclass[#1]%
+ {\pushmacro\fontclass
+ \doifelse{#1}\v!each
+ {\let\fontclass\empty}
+ {\doifsomething{#1}{\def\fontclass{#1}}}}
+
+\unexpanded\def\stopfontclass
+ {\popmacro\fontclass}
+
+%D \macros
+%D {tracedfontname}
+%D
+%D A goody:
+
+\def\tracedfontname#1%
+ {#1\ifcsname\??ff\fontclass#1\endcsname
+ \@EA\tracedfontname\csname\??ff\fontclass#1\endcsname
+ \else\ifcsname\??ff#1\endcsname
+ \@EA\tracedfontname\csname\??ff#1\endcsname
+ \fi\fi}
+
+%D \macros
+%D {definefont}
+%D
+%D Before we implement the main definition macro, we first show
+%D one for local use:
+%D
+%D \starttyping
+%D \definefont[Some][LucidaBright at 100pt] \Some some
+%D \definefont[More][LucidaBright scaled 3000] \More more
+%D \definefont[Nice][LucidaBright mo 2] \Nice nice
+%D \definefont[Text][LucidaBright sa 5.4] \Text last
+%D \stoptyping
+%D
+%D The implementation looks as follows:
+
+\unexpanded\def\definefont
+ {\dotripleempty\dodefinefont}
+
+\def\dodefinefont[#1][#2][#3]% [name][spec][1.6 | line=10pt | setup_id]
+ {\ifthirdargument
+ \setuvalue{#1}{\redodefinefont{#1}{#2}{#3}}%
+ \else
+ \setuvalue{#1}{\dododefinefont{#1}{#2}}%
+ \fi}
+
+\def\redodefinefont#1#2#3%
+ {\dododefinefont{#1}{#2}%
+ \doifsetupselse{#3}
+ {\setups[#3]} % don't forget to document this !
+ {\setuplocalinterlinespace[#3]%
+ \setupspacing}} % needed ?
+
+\unexpanded\def\definefrozenfont
+ {\dotripleempty\dodefinefrozenfont}
+
+\def\dodefinefrozenfont[#1][#2][#3]%
+ {\dodefinefont[#1][#2][#3]%
+ \expandafter\let\csname\lastfontidentifier\expandafter\endcsname\csname\rawfontidentifier\endcsname}
+
+%D The \type {*} makes the switch local, so that we can redefine a
+%D logical name and/or change the size in between.
+
+\newif\ifautofontsize \autofontsizetrue
+
+\let\lastfontidentifier\empty
+
+\def\rawfontidentifier{**\lastfontidentifier\fontsize\currentmathsize**}
+\def\newfontidentifier{*\fontclass\lastfontidentifier\fontsize\currentmathsize*}
+
+\let\oldrawfontidentifier\rawfontidentifier
+\let\oldnewfontidentifier\newfontidentifier
+
+\def\newfontidentifier{*\fontclass\lastfontidentifier\fontstyle\fontsize*}
+
+\def\dododefinefont#1#2%
+ {\edef\lastfontidentifier{#1}%
+ \let\localrelativefontsize\defaultrelativefontsize
+ \let\localabsolutefontsize\fontbody
+ \lowleveldefinefont{#2}\rawfontidentifier
+ \csname\rawfontidentifier\endcsname
+ \autofontsizefalse
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \let\rawfontidentifier\oldrawfontidentifier}
+
+\def\xxdododefinefont#1#2#3#4% \autofontsizetrue is set by calling routine
+ {\edef\lastfontidentifier{#3}%
+ \ifcsname\newfontidentifier\endcsname\else
+ \def\localrelativefontsize{#1}%
+ \def\localabsolutefontsize{#2}%
+ \lowleveldefinefont{#4}\newfontidentifier
+ \fi
+ \csname\newfontidentifier\endcsname
+ \autofontsizefalse
+ %\edef\lastfontidentifier{#3}%
+ \ifskipfontcharacteristics \else
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \fi
+ \let\newfontidentifier\oldnewfontidentifier}
+
+%D \macros
+%D {mapfontsize}
+%D
+%D For special purposes, like in math, you may want to use
+%D slightly different sizes than the ones given. This happens
+%D for instance with the Math Times fonts. Mapped font sizes
+%D can be specified by using the \type {mo} key instead of
+%D \type {sa} in font definitions.
+%D
+%D \startbuffer
+%D \mapfontsize[10pt][11pt]
+%D \mapfontsize[11pt][12pt]
+%D \mapfontsize[12pt][13pt]
+%D
+%D \definefont[test][Serif]\test TEST \par
+%D \definefont[test][Serif sa 5]\test TEST \par
+%D \definefont[test][Serif mo 5]\test TEST \par
+%D \definefont[test][Serif sa d]\test TEST \par
+%D \definefont[test][Serif at 60pt]\test TEST \par
+%D \definefont[test][Serif scaled 6000]\test TEST \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startpacked
+%D \getbuffer
+%D \stoppacked
+
+\def\mapfontsize
+ {\dodoubleargument\domapfontsize}
+
+\def\domapfontsize[#1][#2]%
+ {\setvalue{\??ft*\the\dimexpr#1\relax}{#2}}
+
+\def\setmappedfontsize#1%
+ {\ifcsname\??ft*#1\endcsname
+ \csname\??ft*#1\endcsname
+ \else
+ #1%
+ \fi}
+
+%D \macros
+%D {getfontname}
+%D
+%D The names of the fonts can be called with the rather simple
+%D macro \type{\getfontname}. When for instance we pass
+%D \type{12ptrmtf} as argument, we get \getfontname{12ptrmtf}.
+
+\def\getfontname#1%
+ {\csname\??ft#1\endcsname}
+
+%D To be documented.
+
+\let\fontsizelist \empty
+\let\fontalternativelist\empty
+\let\fontstylelist \empty
+
+\def\checkfontnamecombinations % we need to split math and text here ... todo (math only has mr and mb)
+ {\def\docommand##1%
+ {\def\dodocommand####1%
+ {\def\dododocommand########1{\checkbodyfont{########1}{####1}{##1}}%
+ \processcommacommand[\fontstylelist]\dododocommand}%
+ \processcommacommand[\fontalternativelist]\dodocommand}%
+ \processcommacommand[\fontsizelist]\docommand}
+
+\unexpanded\def\definefontsize[#1]% sneller met toks
+ {\addtocommalist{#1}\fontsizelist
+ \checkfontnamecombinations}
+
+\unexpanded\def\definefontalternative[#1]%
+ {\addtocommalist{#1}\fontalternativelist
+ \checkfontnamecombinations}
+
+%D \macros
+%D {currentfontscale,currentfontbodyscale}
+%D
+%D Sometimes we need to have access to the font scale
+%D including the \type{a}||\type{d} sizes. The next macro
+%D returns the current scaling factor. Take a look at
+%D \type {cont-log.tex} for an example of its use.
+
+\def\currentfontscale
+ {\csname\??ft\s!default
+ \ifcsname\??ft\s!default\xfontsize\endcsname \xfontsize \else
+ \ifcsname\??ft\s!default\s!text \endcsname \s!text \fi\fi
+ \endcsname}
+
+\def\currentfontbodyscale
+ {\csname\??ft\s!default
+ \ifcsname\??ft\s!default\fontsize\endcsname \fontsize \else
+ \ifcsname\??ft\s!default\s!text \endcsname \s!text \fi\fi
+ \endcsname}
+
+\setvalue{\??ft\s!default}{1}
+
+%D Both alternatives use \type {\xfontsize}, a macro that
+%D expands to the current size in terms of \type {a} \unknown
+%D \type {d}, nothing, or \type {x} \unknown \type {xx}.
+
+\def\xfontsize{\ifcase\currentxfontsize\fontsize\or\c!x\else\c!xx\fi}
+
+%D A typical use of this command is in commands that switch
+%D to another font bypassing the font mechanism:
+%D
+%D \starttyping
+%D \font\myfont=\truefontname{MyFont} at \the\dimexpr\currentfontscale\bodyfontsize\relax
+%D \stoptyping
+
+%D Now we enter the area of font switching. The switching
+%D mechanism has to take care of several situations, like:
+%D
+%D \startitemize[packed]
+%D \item changing the overal document fonts (including margins,
+%D headers and footers)
+%D \item changing local fonts (only the running text)
+%D \item smaller and even more smaller alternatives (super-
+%D and subscripts)
+%D \stopitemize
+%D
+%D \TEX\ offers a powerfull family mechanism for super- and
+%D subscripts in math mode. In text mode however, we don't use
+%D families for the smaller alternatives, and therefore have
+%D to take care of it otherwise.
+
+%D \macros
+%D {definebodyfontenvironment,setupbodyfontenvironment}
+%D
+%D The relationship between the several sizes of a font, is
+%D defined by:
+%D
+%D \showsetup{definebodyfontenvironment}
+%D
+%D Later on we will see how these parameters are used, so for
+%D the moment we stick with an example:
+%D
+%D \starttyping
+%D \definebodyfontenvironment
+%D [12pt]
+%D [ text=12pt,
+%D script=9pt,
+%D scriptscript=7pt,
+%D x=10pt,
+%D xx=8pt,
+%D big=12pt,
+%D small=10pt]
+%D \stoptyping
+%D
+%D The first argument specifies the bodyfont size to which the
+%D settings apply. All second parameters are specified in
+%D dimensions and tell us more about related sizes.
+%D
+%D Afterwards, one can change values with
+%D
+%D \showsetup{setupbodyfontenvironment}
+%D
+%D Due to the fact that \type{\c!text} and \type{\s!text} can
+%D have a similar meaning, and therefore can lead to an
+%D unwanted loop, we temporary redefine \type{\c!text}. For
+%D the moment this in only place that some trickery is needed
+%D to fool the multilingual interface. However, long ago
+%D we decided to stick to \s!text in definitions as it closely
+%D relates to the math model where text, script and scriptscript
+%D are used untranslated. Also, we are now english at the low
+%D level so it cannot go wrong anymore.
+%D
+%D When instead of a size the keyword \type{unknown} is
+%D passed, fractions (relations) are used instead of fixed
+%D sizes.
+
+\let\bodyfontenvironmentlist\empty
+
+\newcount\@@fontdefhack % check if this is still needed
+
+\def\@@beginfontdef
+ {\ifcase\@@fontdefhack
+ \let\k!savedtext \k!text \let\k!text \s!text
+ \let\k!k!savedtext \k!k!text \let\k!k!text \!!plusone
+ \let\k!saveddefault \k!default \let\k!default \s!default
+ \let\k!k!saveddefault\k!k!default \let\k!k!default \!!plusone
+ \fi
+ \advance\@@fontdefhack \plusone }
+
+\def\@@endfontdef
+ {\advance\@@fontdefhack \minusone
+ \ifcase\@@fontdefhack
+ \let\k!k!default\k!k!saveddefault
+ \let\k!default \k!saveddefault
+ \let\k!k!text \k!k!savedtext
+ \let\k!text \k!savedtext
+ \fi}
+
+\unexpanded\def\definebodyfontenvironment
+ {\dotripleempty\dodefinebodyfontenvironment}
+
+\def\dodefinebodyfontenvironment[#1][#2][#3]% class size settings
+ {\ifthirdargument
+ \@@beginfontdef
+ \doifelse{#2}\s!default
+ {\getparameters[\??ft\s!default][#3]}
+ {\normalizebodyfontsize#2\to\tempbodyfontsize
+ \addtocommalist\tempbodyfontsize\bodyfontenvironmentlist
+ \@EA\dododefinebodyfontenvironment\@EA[\tempbodyfontsize][#1][#3]}%
+ \@@endfontdef
+ \else
+ \ifx\fontclass\empty\else
+ \writestatus\m!fonts{beware: fontclass ignored (if needed use: [fontclass][size][settings])}%
+ \fi
+ \pushmacro\fontclass
+ \let\fontclass\empty
+ \definebodyfontenvironment[\fontclass][#1][#2]% change */*
+ \popmacro\fontclass
+ \fi}
+
+\def\dododefinebodyfontenvironment[#1][#2][#3]% size class settings
+ {\@@beginfontdef % \s!text goes wrong in testing because the 12pt alternative will called when typesetting the test (or so)
+ \ifcsname\??ft#2#1\c!em\endcsname
+ % we test for em as we assume it to be set
+ \else
+ \def\docommand##1%
+ {\scratchdimen\csname\??ft\s!default##1\endcsname\dimexpr#1\relax
+ \normalizebodyfontsize\scratchdimen\to\tempbodyfontsize
+ \letvalue{\??ft#2#1##1}\tempbodyfontsize}%
+ \processcommacommand[\fontrelativesizelist]\docommand
+ \copyparameters
+ [\??ft#2#1][\??ft\s!default]
+ [\c!interlinespace,\c!em]%
+ \fi
+ \getparameters[\??ft#2#1][#3]%
+ \@@endfontdef
+ % new code, see remark
+ \ifloadingfonts
+ % only runtime
+ \else\ifcsname\@size@#1\endcsname
+ % only once
+ \else
+ % prevent loop (hence \empty)
+ \letvalue{\@size@#1}\empty
+ \pushmacro\fontclass % new per 26102009
+ \edef\fontclass{#2}% % new per 26102009
+ \defineunknownfont{#1}%
+ \popmacro\fontclass % new per 26102009
+ \fi\fi
+ % so far
+ \setvalue{\@size@#1}{\docompletefontswitch[#1]}}
+
+%D {\bf Remark:} We need to cover the following cases,
+%D otherwise users can get confused:
+%D
+%D \starttyping
+%D \setupbodyfont[23pt]
+%D
+%D \definebodyfontenvironment[23pt]
+%D \setupbodyfont[23pt]
+%D
+%D \definebodyfontenvironment[23pt]
+%D \definebodyfont[23pt][rm,ss,tt][default]
+%D \setupbodyfont[23pt]
+%D \stoptyping
+
+%D Beware: while some font defs can be global, the bodyfont
+%D environment checks local. This means that multiple local
+%D checks resulting in definitions are not that efficient.
+%D So, apart from an occasional switch, one should define an
+%D environment at the outer level.
+
+\def\checkbodyfontenvironment[#1]%
+ {\definebodyfontenvironment[\fontclass][#1][]}
+
+\def\checkbodyfontenvironment[#1]%
+ {\ifcsname\??ft\fontclass#1\c!em\endcsname
+ % we test for em as we assume it to be set
+ \else
+ \definebodyfontenvironment[\fontclass][#1][]%
+ \fi}
+
+% this one already catches both define/setup
+
+\let\setupbodyfontenvironment\definebodyfontenvironment
+
+%D Just a couple of interface macros:
+
+\def\bodyfontvariable#1%
+ {\??ft\ifcsname\??ft\fontclass#1\endcsname\fontclass\fi#1}
+
+\def\bodyfontinterlinespecs
+ {\bodyfontvariable{\normalizedbodyfontsize\c!interlinespace}}
+
+\def\bodyfontinterlinespace
+ {\csname\bodyfontinterlinespecs\endcsname}
+
+%D We default all parameters to the main bodyfont size (begin
+%D \type{#1}), so the next setup is valid too:
+%D
+%D \starttyping
+%D \definebodyfontenvironment[24pt]
+%D \stoptyping
+%D
+%D All parameters can be redefined when needed, so one does
+%D not have to stick to the default ones.
+
+%D \macros
+%D {definebodyfont}
+%D
+%D The next step in defining a bodyfont involves the actual font
+%D files, which can be recognized by their extension
+%D \type{tfm}. Installing those file is often beyond the
+%D scope of the user and up to the system administrator.
+%D
+%D \showsetup{definebodyfont}
+%D
+%D This commands takes three arguments: a (series of) bodyfont
+%D size(s), the style group to which the definitions belong,
+%D and an alternative, as specified by the \TEX\ (math) families,
+%D extended with~a, b~\unknown.
+%D
+%D We show two examples, that show all the alternative
+%D scaling options. The \type{\tfa} alternatives can be
+%D extended with \type{\bfa}, \type{\slb}, etc. or even
+%D \type{e} and higher alternatives. The magic scaled
+%D values are derived from plain \TEX's \type {\magstep}:
+%D
+%D \starttyping
+%D \definebodyfont [12pt] [rm]
+%D [tf=cmr12,
+%D bf=cmbx12,
+%D it=cmti12,
+%D sl=cmsl12,
+%D bi=cmbxti10 at 12pt,
+%D bs=cmbxsl10 at 12pt,
+%D tfa=cmr12 scaled 1.200,
+%D tfb=cmr12 scaled 1.440,
+%D tfc=cmr12 scaled 1.728,
+%D tfd=cmr12 scaled 2.074,
+%D sc=cmcsc10 at 12pt]
+%D
+%D \definebodyfont [12pt,11pt,10pt,9pt,8pt] [rm]
+%D [tf=lbr sa 1,
+%D bf=lbd sa 1,
+%D it=lbi sa 1,
+%D sl=lbsl sa 1,
+%D bi=lbdi sa 1,
+%D bs=lbdi sa 1,
+%D tfa=lbr sa 1.200,
+%D tfb=lbr sa 1.440,
+%D tfc=lbr sa 1.728,
+%D tfd=lbr sa 2.074,
+%D sc=lbr sa 0.833]
+%D \stoptyping
+%D
+%D The second example shows that we can define more sizes at
+%D once. The main difference between these examples is that the
+%D Computer Modern Roman come in many design sizes. This means
+%D that there we cannot define them in bulk using \type{sa}.
+%D Instead of \type{rm} (roman) one can define \type{ss} (sans
+%D serif), \type{tt} (teletype), \type{hw} (hand written),
+%D \type{cg} (calygraphic) and whatever styles.
+%D
+%D The first argument may be a comma separated list. This,
+%D combined with specifications using \type{sa} can save a lot
+%D of typing. Although all arguments should be specified, we
+%D treat the second argument as optional.
+%D
+%D Defining a bodyfont involves two actions: defining the
+%D specific style related alternatives, like \type{\rma},
+%D \type{\bfa} and \type{\rmsla}, and storing the definitions
+%D of their bodyfont size related fonts. The first step is
+%D bodyfont independant but executed every time. This permits
+%D user definitions like \type{\tfw} or \type{\bfq} for real
+%D large alternatives.
+
+\unexpanded\def\definebodyfont
+ {\doquadrupleempty\redefinebodyfont}
+
+\def\redefinebodyfont[#1][#2][#3][#4]%
+ {\iffourthargument
+ \processcommacommand[#1]{\reredefinebodyfont[#2][#3][#4]}%
+ \else
+ \dodefinebodyfont[#1][#2][#3]%
+ \fi}
+
+\def\reredefinebodyfont[#1][#2][#3]#4%
+ {\pushmacro\fontclass
+ \doifelse{#4}\s!default
+ {\let\fontclass\empty}
+ {\def\fontclass{#4}}%
+ \definebodyfont[#1][#2][#3]%
+ \popmacro\fontclass}
+
+\def\dodefinebodyfont[#1][#2][#3]% body|identifier style defs|identifier
+ {\ifthirdargument
+ \doifnumberelse{#1}
+ {\doifassignmentelse{#3}
+ {% [12pt] [style] [settings]
+ \ifcsname#2\endcsname\else\normalexpanded{\noexpand\definefontstyle[#2][#2]}\fi % new
+ \processcommalist[#1]{\dododefinebodyfont{#2}{#3}}}
+ {% [12pt] [style] [identifier]
+ \dodefinedefaultbodyfont[#1][#2][#3]}} % body style identifier
+ {% [identifier] [style] [settings] % see ***
+ \setvalue{\s!default#1#2}##1##2{\normalexpanded{\noexpand\xdodefinebodyfont[##1][##2][#3]}}}%
+ \else\ifsecondargument
+ \definebodyfont[#1][\c!rm][#2]%
+ \else
+ % Maybe there are default dependencies defined which we can use ([unknown]) and
+ % if not, then we have at least to make sure some basics are set up.
+ \ifcsname\@size@#1\endcsname \else
+ \defineunknownfont{#1}%
+ \fi
+ \ifcsname\@size@#1\endcsname \else
+ \definebodyfont[#1][\c!rm][]%
+ \fi
+ \fi\fi}
+
+\def\xdodefinebodyfont[#1][#2][#3]% body|identifier style defs|identifier
+ {\checkrelativefontsize{#2}% rather new, inherit from other defs
+ \ifcsname#2\endcsname\else\normalexpanded{\noexpand\definefontstyle[#2][#2]}\fi % new
+ \processcommalist[#1]{\dododefinebodyfont{#2}{#3}}%
+ \let\relativefontsize\defaultrelativefontsize}
+
+\def\dododefinebodyfont#1#2#3% style defs body
+ {\checkbodyfontenvironment[#3]% just to be sure.
+ \processcommalist[#2]{\dodododefinebodyfont{#1}{#3}}}
+
+\def\dodododefinebodyfont#1#2#3% style body def
+ {\dododododefinebodyfont{#1}{#2}[#3]}
+
+\def\dododododefinebodyfont
+ {\ifx\fontclass\empty
+ \expandafter\dododododefinebodyfontnop
+ \else
+ \expandafter\dododododefinebodyfontyes
+ \fi}
+
+\def\dododododefinebodyfontyes#1% style body def
+ {\edef\askedbodyfontstyle{#1}%
+ \ifx\askedbodyfontstyle\c!mm
+ \expandafter\dodefinebodyfontyesmm
+ \else
+ \expandafter\dodefinebodyfontyesxx
+ \fi\askedbodyfontstyle} % we can get rid of #1
+
+\def\dododododefinebodyfontnop#1% style body def
+ {\edef\askedbodyfontstyle{#1}%
+ \ifx\askedbodyfontstyle\c!mm
+ \expandafter\dodefinebodyfontnopmm
+ \else
+ \expandafter\dodefinebodyfontnopxx
+ \fi\askedbodyfontstyle} % we can get rid of #1
+
+\def\dodefinebodyfontnopxx#1#2[#3#4#5=#6]% style body def
+ {\ifcsname#1#3#4#5\endcsname\else\checkbodyfont{#1}{#3#4}{#5}\fi% not \definefontsize[#5]
+ \@EA\let\csname*#2#1#3#4#5*\endcsname\undefined
+ \unexpanded\@EA\edef\csname#2#1#3#4#5\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#5}{\normalunexpanded{#6}}}}
+
+\def\dodefinebodyfontyesxx#1#2[#3#4#5=#6]% style body def
+ {\ifcsname#1#3#4#5\endcsname\else\checkbodyfont{#1}{#3#4}{#5}\fi% not \definefontsize[#5]
+ \fcglobal\@EA\let\csname*\fontclass#2#1#3#4#5*\endcsname\undefined
+ \unexpanded\@EA\fcxdef\csname\fontclass#2#1#3#4#5\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#5}{\normalunexpanded{#6}}}}
+
+\def\dodefinebodyfontnopmm#1#2[#3#4#5=#6]% style body def
+ {\ifcsname#1#3#4#5\endcsname\else\checkbodyfont{#1}{#3#4}{#5}\fi% not \definefontsize[#5]
+ \@EA\let\csname*#2#1#3#4#51*\endcsname\undefined
+ \@EA\let\csname*#2#1#3#4#52*\endcsname\undefined
+ \@EA\let\csname*#2#1#3#4#53*\endcsname\undefined
+ \unexpanded\@EA\edef\csname#2#1#3#4#51\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#51}{\normalunexpanded{#6}}}%
+ \unexpanded\@EA\edef\csname#2#1#3#4#52\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#52}{\normalunexpanded{#6}}}%
+ \unexpanded\@EA\edef\csname#2#1#3#4#53\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#53}{\normalunexpanded{#6}}}}
+
+\def\dodefinebodyfontyesmm#1#2[#3#4#5=#6]% style body def
+ {\ifcsname#1#3#4#5\endcsname\else\checkbodyfont{#1}{#3#4}{#5}\fi% not \definefontsize[#5]
+ \fcglobal\@EA\let\csname*\fontclass#2#1#3#4#51*\endcsname\undefined
+ \fcglobal\@EA\let\csname*\fontclass#2#1#3#4#52*\endcsname\undefined
+ \fcglobal\@EA\let\csname*\fontclass#2#1#3#4#53*\endcsname\undefined
+ \unexpanded\@EA\fcxdef\csname\fontclass#2#1#3#4#51\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#51}{\normalunexpanded{#6}}}%
+ \unexpanded\@EA\fcxdef\csname\fontclass#2#1#3#4#52\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#52}{\normalunexpanded{#6}}}%
+ \unexpanded\@EA\fcxdef\csname\fontclass#2#1#3#4#53\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#53}{\normalunexpanded{#6}}}}
+
+\def\checkbodyfont#1% tests for ttsl mmbf
+ {\edef\c!!mm{#1}%
+ \ifx\c!!mm\c!mm % prevents \max and alike (re)defs
+ \expandafter\checkmathbodyfont
+ \else
+ \expandafter\checktextbodyfont
+ \fi{#1}} % no \c!!mm, not expanded later on
+
+% some day we can do an auto-fam if needed
+
+\def\checkmathbodyfont#1#2#3% style alt size / gdef % #3 can be empty
+ {%\message{!m #1 #2 #3!}%
+ % #1 #2 #3 = signal
+ %setugvalue {#2}{\setcurrentfontalternative {#2}}% \mr \mb
+ \setugvalue {#1}{\setcurrentfontstyle {#1}}}% \mm
+
+\def\checktextbodyfont#1#2#3% style alt size / gdef % #3 can be empty
+ {%\message{!t #1 #2 #3!}%
+ \setugvalue {#1#3}{\setcurrentfontstylesize {#1}{#3}}% \rma
+ \setugvalue {#2#3}{\setcurrentfontalternativesize {#2}{#3}}% \sla
+ \setugvalue {#1#2#3}{\setcurrentfontstylealternativesize{#1}{#2}{#3}}% \rmsla
+ \setugvalue {#1}{\setcurrentfontstyle {#1}}% \rm
+ \setugvalue {#2}{\setcurrentfontalternative {#2}}% \sl
+ \setugvalue {#1\c!x}{\setcurrentfontxstylealternative {#1}}% \rmx
+ \setugvalue{#1\c!xx}{\setcurrentfontxxstylealternative {#1}}% \rmxx
+ \setugvalue {#2\c!x}{\setcurrentfontxalternative {#2}}% \slx
+ \setugvalue{#2\c!xx}{\setcurrentfontxxalternative {#2}}% \slxx
+ \setugvalue {#1#2}{\setcurrentfontstylealternative {#1}{#2}}}% \rmsl
+
+\def\dodefinedefaultbodyfont[#1][#2][#3]% sizes styles identifier
+ {\def\dododefinedefaultbodyfont##1%
+ {\def\dodododefinedefaultbodyfont####1%
+ {\def\dododododefinedefaultbodyfont########1%
+ {\ifcsname\s!default########1####1\endcsname
+ % [12pt] [style] [identifier]
+ \csname\s!default########1####1\endcsname{##1}{####1}%
+ \fi}%
+ \processcommalist[#3]\dododododefinedefaultbodyfont}%
+ \processcommalist[#2]\dodododefinedefaultbodyfont}%
+ \processcommalist[#1]\dododefinedefaultbodyfont}
+
+%D Unknown families are added to the family list! For the
+%D moment we also set the direct calls here. Some day a better
+%D solution will be implemented. The good news is that unknown
+%D fonts are defined automatically.
+
+\newif\ifdefiningunknownfont
+
+\def\dodefineunknownfont#1#2%
+ {\ifcsname\??ft\s!default#2\endcsname
+ \donetrue
+ \normalizebodyfontsize\csname\??ft\s!default#2\endcsname\dimexpr#1\relax\to\tempbodyfontsize
+ \letvalue{\??ft#1#2}\tempbodyfontsize
+ \fi}
+
+\def\dodefineunknownbodyfont#1#2% see ***
+ {\ifcsname\s!default\s!default#2\endcsname % somehow related to */*
+ \donetrue
+ \csname\s!default\s!default#2\endcsname{#1}{#2}%
+ \fi}
+
+\def\dodefineunknownsubfont#1#2%
+ {\ifcsname\@size@\csname\??ft#1#2\endcsname\endcsname
+ \else
+ \donetrue
+ \defineunknownfont{\csname\??ft#1#2\endcsname}%
+ \fi}
+
+\unexpanded\def\defineunknownfont#1%
+ {\let\c!savedtext\c!text
+ \let\c!text\s!text
+ \donefalse
+ \processcommacommand[\fontrelativesizelist]{\dodefineunknownfont{#1}}%
+ \let\c!text\c!savedtext
+ \ifdone
+ \donefalse
+ \processcommacommand
+ [\fontstylelist]
+ {\dodefineunknownbodyfont{#1}}%
+ \ifdone
+ \donefalse
+ \setvalue{\@size@#1}{\docompletefontswitch[#1]}%
+ \ifdefiningunknownfont \else
+ \definingunknownfonttrue
+ \processcommacommand[\fontrelativesizelist]{\dodefineunknownsubfont{#1}}%
+ \definingunknownfontfalse
+ \fi
+ \fi
+ \ifdone
+ \showmessage\m!fonts{14}{#1}%
+ \fi
+ \fi}
+
+%D These macros show that quite some definitions take place.
+%D Fonts are not loaded yet! This means that at format
+%D generation time, no font files are preloaded.
+
+%D \macros
+%D {everybodyfont,Everybodyfont,everyglobalbodyfont}
+%D
+%D Every change in bodyfont size has conseqences for the baseline
+%D distance and skips between paragraphs. These are initialized
+%D in other modules. Here we only provide the hooks that
+%D garantees their handling.
+
+%D At the system level one can initialize thing like:
+%D
+%D \starttyping
+%D \appendtoks \setupspacing \to \everybodyfont
+%D \stoptyping
+%D
+%D While users can add their own non standard commands like:
+%D
+%D \starttyping
+%D \EveryBodyFont{\message{changing to bodyfont \the\bodyfontsize}}
+%D \stoptyping
+%D
+%D Personnaly I never felt the need for such extensions, but
+%D at least its possible.
+
+%D \macros
+%D {globalbodyfontsize,localbodyfontsize}
+%D
+%D Next we'll do the tough job of font switching. Here we
+%D have to distinguish between the global (overal) bodyfont
+%D size and the local (sometimes in the textflow) size. We
+%D store these dimensions in two \DIMENSION\ registers.
+
+\ifdefined\globalbodyfontsize\else \newdimen\globalbodyfontsize \fi \globalbodyfontsize=12pt
+\ifdefined\localbodyfontsize \else \newdimen\localbodyfontsize \fi \localbodyfontsize =\globalbodyfontsize
+
+%D \macros
+%D {bodyfontsize}
+%D
+%D These two registers are not to be misused in calculations.
+%D For this purpose we keep a copy:
+
+\newdimen\bodyfontsize \bodyfontsize=\globalbodyfontsize
+
+%D \macros
+%D {bodyfontfactor,bodyfontpoints}
+%D
+%D For multiplication purposes we keep an auxiliary counter
+%D and macro (here the expansion is not explicitly needed):
+
+\newcount\bodyfontpoints \dimensiontocount\bodyfontsize\bodyfontpoints
+
+\edef\bodyfontfactor{\withoutpt\the\bodyfontsize}
+
+%D When we assign for instance 12pt to a \DIMENSION\ register
+%D the \type{\the}'d value comes out as 12.0pt, which is
+%D often not the way users specify the bodyfont size. Therefore
+%D we also store the normalized value.
+
+\chardef\fontdigits=2 % was 1
+
+% \def\normalizebodyfontsize#1\to#2%
+% {\@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\dimexpr#1+\ifcase\fontdigits.5\or.05\or.005\fi\points\relax000\to#2}
+%
+% \def\donormalizedbodyfontsize#1.#2#3#4#5\to#6% \points ?
+% {\edef#6% not \ifcase#2\else due to \relax adding
+% {#1%
+% \ifcase\fontdigits
+% \or \ifcase#2 \else .#2\fi % 1
+% \or \ifcase#2#3 \else .#2\ifcase#3 \else #3\fi\fi % 2
+% \else \ifcase#2#3#4 \else .#2\ifcase#4 \ifcase#3 \else#3\fi \else#3#4\fi\fi % 3
+% \fi
+% \s!pt}}
+
+\def\normalizebodyfontsize#1\to#2%
+ {\edef#2{\ctxlua{fonts.nbfs(\number\dimexpr#1\relax,\number\fontdigits)}}}
+
+\def\thenormalizedbodyfontsize#1%
+ {\ctxlua{fonts.nbfs(\number\dimexpr#1\relax,\number\fontdigits)}}
+
+\normalizebodyfontsize\bodyfontsize\to\normalizedglobalbodyfontsize
+\normalizebodyfontsize\bodyfontsize\to\normalizedlocalbodyfontsize
+\normalizebodyfontsize\bodyfontsize\to\normalizedbodyfontsize
+
+%D \macros
+%D {fontstyle,fontalternative,fontsize}
+%D
+%D Within a bodyfont, fonts can come in different sizes. For
+%D instance \type{\tf} is accompanied by \type{\tfa},
+%D \type{\tfb} etc. The first two characters denote the
+%D alternative, while the third character in these sequences
+%D represents the size. The actual size is saved in a macro
+%D
+%D The style, being roman (\type{\rm}), sans serif (\type{\ss})
+%D etc. is also available in a macro in \type{rm}, \type{ss}
+%D etc. form:
+
+\let\defaultfontalternative = \c!tf
+\let\defaultfontstyle = \empty
+\let\defaultfontsize = \empty
+
+\let\fontalternative = \defaultfontalternative
+\let\fontstyle = \defaultfontstyle
+\let\fontsize = \defaultfontsize
+
+%D When \type {\loadfontfileoncetrue}, such files are
+%D only loaded once! This permits redundant loading, but at
+%D the same time forced grouping when we want continuously mix
+%D all kind of font, which of course is a kind of
+%D typographically sin. The \type{"} is made inactive if
+%D needed to prevent problems with loading files that use this
+%D character in numbers.
+
+% can be made faster (only used internally now)
+
+\def\doswitchpoints[#1]%
+ {\normalexpanded{\dodoswitchpoints{#1}}}
+
+\unexpanded \def\dodoswitchpoints#1%
+ {\ifcsname\@size@#1\endcsname \else
+ \defineunknownfont{#1}%
+ \fi%
+ %\defineunknownfontstyles{#1}%
+ \ifcsname\@size@#1\endcsname
+ \csname\@size@#1\endcsname
+ \localbodyfontsize#1\relax
+ \normalizebodyfontsize\localbodyfontsize\to\normalizedbodyfontsize
+ % \edef\fontbody{\fontbody}% to be tested but we can clean up mkiv further
+ \checkbodyfontenvironment[\normalizedbodyfontsize]%
+ \else
+ \showmessage\m!fonts4{#1}%
+ \fi}
+
+\unexpanded \def\doswitchstyle[#1]%
+ {\ifcsname\@style@#1\endcsname
+ \csname\@style@#1\endcsname
+ \edef\fontstyle{#1}%
+ \ifmmode\mr\fi % in order to be compatible with \rm in math mode
+ % \the\everybodyfont % cleaner, in setting size as well as style
+ \else
+ \showmessage\m!fonts5{#1}%
+ \fi}
+
+%D \TEX\ loads font metric files like \type{cmr10.tfm} and
+%D \type{tir.tfm} only once. In \PLAIN\ \TEX\ some font files
+%D are {\em preloaded}. This means that the font files are
+%D loaded, but not accessible yet by name. This is accomplished
+%D by saying:
+%D
+%D \starttyping
+%D \font\preloaded=cmr10 at 11pt
+%D \stoptyping
+%D
+%D and using the name \type{\preloaded} again and again, so
+%D fonts are indeed loaded, but unnamed, and therefore
+%D unaccessible. In \CONTEXT\ we don't preload fonts, not even
+%D the \PLAIN\ \TEX\ ones, although users can access them. Now
+%D why is this done?
+
+%D Defining fonts using \type{\definebodyfont} takes time, so we
+%D prefer to predefine at least the Computer Modern Roman
+%D fonts. However, loading all those fonts at definition time
+%D would take both time and space. But even worse, once fonts
+%D are loaded into memory, their encoding vector is fixed,
+%D which is a handicap when we want to distribute the compact
+%D \type{fmt} files. So what we want to do is defining fonts in
+%D a way that postpones the loading. We accomplish this by only
+%D loading the fonts when we switch to another bodyfont size.
+%D Among the other alternatives, such as loading the font at
+%D the moment of activation and redefining the activation
+%D macro afterwards, this proved to be the most efficient
+%D alternative.
+%D
+%D The next few macros take care of the one exeption on this
+%D scheme. When at format generation time we load the default
+%D font file, the one that defines the Computer Modern Fonts,
+%D we don't want the fonts metrics to end up in the format
+%D file, so we temporary prohibit loading. This means that at
+%D runtime we have to load the default bodyfont size just before
+%D we start typesetting.
+%D
+%D Therefore we have to signal the font switching macros that
+%D we are preloading fonts. As long as the next boolean is,
+%D true, no loading is done.
+
+\newif\ifloadingfonts \loadingfontstrue
+
+%D \macros
+%D {preloadfonts}
+%D
+%D Preloading is only called for once, during the startup
+%D sequence of a session. After the loading job is done, the
+%D macro relaxes itself and reset the signal.
+
+% \appendtoks
+% \to \everysetupdocument
+
+\newconditional\fontsareloaded
+
+\def\preloadfonts % never called, needs a clean up
+ {\global\loadingfontsfalse
+ \ifconditional\fontsareloaded \else
+ \doifmodeelse {*nofonts}
+ {\writestatus\m!fonts{latin modern fonts are not preloaded}}
+ {\writestatus\m!fonts{preloading latin modern fonts}%
+ \usetypescript[modern]%
+ \setuptypeface[modern]%
+ \showmessage\m!fonts6{\normalizedbodyfontsize\normalspace\fontstyle}}%
+ \fi
+ \global\let\preloadfonts\relax}
+
+% maybe add this to \everystarttext
+%
+% \ifconditional\fontsareloaded\else
+% \usetypescript[modern]%
+% \setuptypeface[modern]%
+% \fi
+
+%D Here comes the main font switching macros. These macros
+%D handle changes in size as well as returning to the global
+%D bodyfont size.
+
+\def\dosetfont#1#2% #1 = set/switch state
+ {\doifelse{#2}\v!global
+ {\restoreglobalbodyfont}
+ {\processcommacommand[#2]{\dodosetfont{#1}}% ##1 get also passed
+ \ifloadingfonts\else
+ \global\settrue\fontsareloaded
+ \doswitchpoints[\normalizedbodyfontsize]%
+ \doswitchstyle[\fontstyle]%
+ \ifx\defaultfontclass\empty
+ \let\defaultfontclass\fontclass
+ \fi
+ \fi}%
+ \chardef\currentxfontsize\zerocount}
+
+\def\dodosetfont#1#2% #1 = set/switch state | check fo rempty, else space
+ {\doifsomething{#2}{\dododosetfont{#1}{#2}{\showmessage\m!fonts4{#2}}}}
+
+% % % this can be retrofitted in mkii code % % %
+
+% \def\normalizebodyfontsize#1\to#2%
+% {\@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\dimexpr#1+\ifcase\fontdigits.5\or.05\or.005\fi\points\relax000\to#2}
+
+\def\dododosetfont#1#2#3% #1 = set/switch state ! ! ! !could also be used for mkii
+ {\doifnumberelse{#2}\dodododosetfont\redododosetfont{#1}{#2}{#3}}
+
+\def\redododosetfont#1#2#3% #1 = set/switch state ! ! ! !could also be used for mkii
+ {\edef\expandedfontthing{#2}%
+ \def\interfacedfontsize{\normalizedbodyfontsize\interfaced\expandedfontthing}%
+ \ifcsname\??ft\interfacedfontsize\endcsname
+ \edef\fontstep{\csname\bodyfontvariable\interfacedfontsize\endcsname}%
+ \normalexpanded{\noexpand\dodododosetfont{#1}{\fontstep}}{#3}%
+ \else\ifx\expandedfontthing\v!reset
+ \let\fontstyle\empty % new 31/7/2006
+ \let\fontsize \empty
+ \else
+ \ifcsname\@style@\expandedfontthing\endcsname
+ \let\fontstyle\expandedfontthing
+ \else
+ \setcurrentfontclass\expandedfontthing
+ \ifcase#1\relax
+ \let\globalfontclass\globalfontclass
+ \else
+ \let\globalfontclass\fontclass
+ \fi
+ \ifx\fontclass\empty
+ \let\fontstyle\c!rm
+ \else\ifcsname\??tf\fontclass\s!default\endcsname
+ \edef\fontstyle{\csname\??tf\fontclass\s!default\endcsname}%
+ \else
+ \let\fontstyle\c!rm
+ \fi\fi
+ \fi
+ \fi\fi}
+
+\def\dodododosetfont#1#2#3% #1 = set/switch state
+ {\normalizebodyfontsize#2\to\normalizedsetfont
+ \ifcsname\@size@\normalizedsetfont\endcsname \else
+ \defineunknownfont{#2}%
+ \fi
+ \ifcsname\@size@\normalizedsetfont\endcsname
+ \localbodyfontsize\normalizedsetfont
+ \let\normalizedbodyfontsize\normalizedsetfont
+ \else
+ #3\dosetsubstitutefont{#1}{#2}%
+ \fi}
+
+% % %
+
+%D In the previous macros we use \type{\currentxfontsize} to
+%D hold the current x||size of the font. This enables us to
+%D support for instance \type{\sl} inside a \type{\tx} switch.
+
+\chardef\currentxfontsize=0
+
+%D When users specify for instance a 13 point bodyfont while no
+%D such bodyfont is defined, the system automatically tries to
+%D find a best fit, that is the nearest smaller defined
+%D bodyfontzize. A smaller one is definitely better than a larger
+%D one, simply because otherwise a lot of overfull box messages
+%D are more probable to occur. By taking a value slightly
+%D smaller than half a point, we can use the next method.
+
+\def\dosetsubstitutefont#1#2% #1 = set/switch state
+ {\scratchdimen#2\relax
+ \advance\scratchdimen .499\points
+ \dimensiontocount\scratchdimen\scratchcounter
+ \advance\scratchcounter \minusone
+ \ifnum\scratchcounter>\plusthree
+ \dododosetfont{#1}{\the\scratchcounter\s!pt}{}%
+ \fi}
+
+% The following bunch of macros deals with the (run time)
+% expansion of names onto the definitions made by \type
+% {\definebodyfont}.
+
+% \let\fontbody \empty % ... 10pt 11pt 12pt ...
+% \let\fontstyle \empty % rm ss tt mm hw cg ...
+% \let\fontalternative\empty % tf bf sl it bs bi sc ...
+% \let\fontsize \empty % xy-abcd ...
+
+\def\defaultfontbody{\normalizedbodyfontsize}
+
+\let\fontbody\defaultfontbody
+
+\let\fontclass\empty \let\globalfontclass\fontclass
+
+% we need to check the fontclass
+
+\def\registerfontclass#1%
+ {\letgvalue{\@fontclass@#1}\v!yes} % global ?
+
+\edef\@no@fontclass@{\@fontclass@:?:}
+
+\def\setcurrentfontclass#1%
+ {\ifcsname\@fontclass@#1\endcsname
+ \edef\fontclass{#1}%
+ \else\ifcsname\@no@fontclass@#1\endcsname
+ % already tried
+ \else\ifcase\currentgrouplevel
+ \trycurrentfontclass{#1}%
+ \fi\fi\fi}
+
+\def\savefontclassparameters#1#2#3#4% #1=rm|ss|.. rscale features fallbacks
+ {\setxvalue{\fontclass#1\s!rscale }{#2}%
+ \setxvalue{\fontclass#1\s!features }{#3}%
+ \setxvalue{\fontclass#1\s!fallbacks}{#4}}
+
+\settrue\autotypescripts
+
+% \def\trycurrentfontclass#1%
+% {\ifconditional\autotypescripts
+% \usetypescript[#1]%
+% \ifcsname\@fontclass@#1\endcsname
+% \edef\fontclass{#1}%
+% \else
+% \letvalue{\@no@fontclass@#1}\empty
+% \fi
+% \else
+% \letvalue{\@no@fontclass@#1}\empty
+% \fi}
+
+\def\trycurrentfontclass#1%
+ {\ifconditional\autotypescripts
+ % try to load typescript #1
+ \usetypescript[#1]%
+ \ifcsname\@fontclass@#1\endcsname
+ \edef\fontclass{#1}%
+ \else
+ % try to load type-#1.mkiv
+ \usetypescriptfile[\f!typeprefix#1]%
+ % try to load typescript #1
+ \usetypescript[#1]%
+ \ifcsname\@fontclass@#1\endcsname
+ \edef\fontclass{#1}%
+ \else
+ % todo: message
+ \letvalue{\@no@fontclass@#1}\empty
+ \fi
+ \fi
+ \else
+ % todo: message
+ \letvalue{\@no@fontclass@#1}\empty
+ \fi}
+
+\let\defaultfontstyle \c!rm
+\let\defaultfontalternative \c!tf
+\let\defaultfontsize \empty
+
+%D \macros
+%D {bigmath,nobigmath}
+%D
+%D We can inhibit this slow||downer with:
+
+% these can best be combined
+
+% 0=never 1=everymath 2=always
+
+\chardef\synchronizebigmathflag=1
+
+\appendtoks
+ \ifcase\synchronizebigmathflag
+ % never
+ \or
+ \synchronizebigmath
+ \or
+ % always
+ \fi
+\to \everymathematics
+
+\def\nobigmath {\chardef\synchronizebigmathflag\zerocount}
+\def\autobigmath{\chardef\synchronizebigmathflag\plusone\synchronizebigmath}
+\def\bigmath {\chardef\synchronizebigmathflag\plustwo\synchronizebigmath}
+
+\let\bigmathfontsize\empty
+
+\def\synchronizebigmath
+ {\ifx\bigmathfontsize\fontsize
+ % already in sync
+ \else
+ \let\bigmathfontsize\fontsize
+ \synchronizemath
+ \fi}
+
+\def\checkbigmathsynchronization
+ {\ifcase\synchronizebigmathflag
+ % never
+ \or
+ \ifmmode \synchronizebigmath \fi
+ \or
+ \synchronizebigmath
+ \fi}
+
+%D So far for synchronisation. (We can inline the following macros.)
+
+\def\dosetcurrentfontsize#1%
+ {\edef\fontsize{#1}%
+ \checkbigmathsynchronization}
+
+\def\dosetcurrentfontalternative#1%
+ {\edef\fontalternative{#1}}
+
+\def\setcurrentfont#1#2#3#4%
+ {%\message{[1 #1 #2 #3 #4]}%
+ \edef\fontbody{#1}%
+ \edef\fontstyle{#2}%
+ \dosetcurrentfontalternative{#3}%
+ \dosetcurrentfontsize{#4}%
+ \synchronizefont}
+
+\def\setcurrentfontbody#1%
+ {%\message{[2 #1]}%
+ \edef\fontbody{#1}%
+ \synchronizefont}
+
+% For Taco: optional fall backs:
+
+\ifx\checkfontclass\undefined \let\checkfontclass\gobbleoneargument \fi % implemented in type-ini
+
+% \def\setcurrentfontstyle#1%
+% {%\message{[3 #1]}%
+% \checkfontclass{#1}%
+% \edef\fontstyle{#1}%
+% \ifmmode\mr\fi % otherwise \rm not downward compatible
+% \synchronizefont}
+
+\def\setcurrentfontstyle#1%
+ {%\message{[3 #1]}%
+ \edef\fontstyle{#1}%
+ \checkfontclass\fontstyle
+ \ifmmode\mr\fi % otherwise \rm not downward compatible
+ \synchronizefont}
+
+\def\setcurrentfontbodyalternative#1#2%
+ {%\message{[4 #1 #2]}%
+ \edef\fontbody{#1}%
+ \dosetcurrentfontalternative{#2}%
+ \synchronizefont}
+
+\def\setcurrentfontalternative#1%
+ {%\message{[5 #1]}%
+ \dosetcurrentfontalternative{#1}%
+ \synchronizefont}
+
+\def\setcurrentfontsize#1%
+ {%\message{[6 #1]}%
+ \dosetcurrentfontsize{#1}%
+ \synchronizefont}
+
+\def\setcurrentfontstylealternative#1#2% \rmsl
+ {%\message{[7 #1 #2]}%
+ \edef\fontstyle{#1}%
+ \dosetcurrentfontalternative{#2}%
+ \synchronizefont}
+
+\def\setcurrentfontstylesize#1#2% \rmsla
+ {%\message{[8 #1 #2]}%
+ \edef\fontstyle{#1}%
+ \dosetcurrentfontsize{#2}%
+ \synchronizefont}
+
+\def\setcurrentfontalternativesize#1#2% \sla
+ {%\message{[9 #1 #2]}%
+ \dosetcurrentfontalternative{#1}%
+ \dosetcurrentfontsize{#2}%
+ \synchronizefont}
+
+\def\setcurrentfontstylealternativesize#1#2#3% \rmsla
+ {%\message{[10 #1 #2 #3]}%
+ \edef\fontstyle{#1}%
+ \dosetcurrentfontalternative{#2}%
+ \dosetcurrentfontsize{#3}%
+ \synchronizefont}
+
+%D In principle one can assign alternative fallback routines.
+%D Some day we will.
+
+\newtoks\fontstrategies
+\newif\iftryingfont
+
+\let\fontstrategy\relax
+
+\def\synchronizefont % we can have dups i.e. no need to let fontstrategy
+ {\tryingfonttrue
+ \ifx\fontclass\empty
+ \applyfontstrategies
+ \else
+ \applyfontclassstrategies
+ \fi
+ \autofontsizefalse
+ \ifskipfontcharacteristics
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \fi}
+
+\def\fontclassstrategiesa % --- --- --- --- % pt tt bf a
+ {\ifcsname\fontclass\fontbody \fontstyle \fontalternative \fontsize\endcsname
+ \autofontsizefalse
+ \csname\fontclass\fontbody \fontstyle \fontalternative \fontsize\endcsname
+ \else
+ \expandafter\fontclassstrategiesb
+ \fi}
+
+\def\fontclassstrategiesb % --- --- --- def % pt tt bf
+ {\ifcsname\fontclass\fontbody \fontstyle \fontalternative \defaultfontsize\endcsname
+ \autofontsizetrue
+ \csname\fontclass\fontbody \fontstyle \fontalternative \defaultfontsize\endcsname
+ \else
+ \expandafter\fontclassstrategiesc
+ \fi}
+
+\def\fontclassstrategiesc % --- --- def --- % pt tt tf a
+ {\ifcsname\fontclass\fontbody \fontstyle \defaultfontalternative \fontsize\endcsname
+ \autofontsizetrue
+ \csname\fontclass\fontbody \fontstyle \defaultfontalternative \fontsize\endcsname
+ \else
+ \expandafter\fontclassstrategiesd
+ \fi}
+
+\def\fontclassstrategiesd % --- --- def def % pt tt tf
+ {\ifcsname\fontclass\fontbody \fontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \autofontsizetrue
+ \csname\fontclass\fontbody \fontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \else
+ \expandafter\fontclassstrategiese
+ \fi}
+
+\def\fontclassstrategiese % --- def def def % pt rm tf
+ {\ifcsname\fontclass\fontbody \defaultfontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \autofontsizefalse
+ \csname\fontclass\fontbody \defaultfontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \else
+ \expandafter\fontclassstrategiesf
+ \fi}
+
+\def\fontclassstrategiesf % def def def def % rm tf
+ {\ifcsname\fontclass\defaultfontbody \defaultfontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \autofontsizetrue
+ \csname\fontclass\defaultfontbody \defaultfontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \else
+ \expandafter\fontstrategiesa
+ \fi}
+
+% no class
+
+\def\fontstrategiesa % --- --- --- --- % pt tt bf a
+ {\ifcsname\fontbody \fontstyle \fontalternative \fontsize\endcsname
+ \autofontsizefalse
+ \csname\fontbody \fontstyle \fontalternative \fontsize\endcsname
+ \else
+ \expandafter\fontstrategiesb
+ \fi}
+
+\def\fontstrategiesb % --- --- --- --- % pt tt bf a
+ {\ifcsname\fontbody \fontstyle \fontalternative \defaultfontsize\endcsname
+ \autofontsizetrue
+ \csname\fontbody \fontstyle \fontalternative \defaultfontsize\endcsname
+ \else
+ \expandafter\fontstrategiesc
+ \fi}
+
+\def\fontstrategiesc % --- --- --- --- % pt tt bf a
+ {\ifcsname\fontbody \fontstyle \defaultfontalternative \fontsize\endcsname
+ \autofontsizetrue
+ \csname\fontbody \fontstyle \defaultfontalternative \fontsize\endcsname
+ \else
+ \expandafter\fontstrategiesd
+ \fi}
+
+\def\fontstrategiesd % --- --- --- --- % pt tt bf a
+ {\ifcsname\fontbody \fontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \autofontsizetrue
+ \csname\fontbody \fontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \else
+ \expandafter\fontstrategiese
+ \fi}
+
+\def\fontstrategiese % --- --- --- --- % pt tt bf a
+ {\ifcsname\fontbody \defaultfontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \autofontsizefalse
+ \csname\fontbody \defaultfontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \else
+ \expandafter\fontstrategiesf
+ \fi}
+
+\def\fontstrategiesf % --- --- --- --- % pt tt bf a
+ {\ifcsname\defaultfontbody \defaultfontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \autofontsizetrue
+ \csname\defaultfontbody \defaultfontstyle \defaultfontalternative \defaultfontsize\endcsname
+ \fi}
+
+\let\applyfontstrategies \fontstrategiesa
+\let\applyfontclassstrategies\fontclassstrategiesa
+
+%D Let's synchronize:
+
+\newif\ifsynchronizefonts \synchronizefontstrue
+
+\prependtoks
+ \ifsynchronizefonts
+ \synchronizemath
+ \synchronizefont % problem: syncs last font
+ \fi
+\to \everybodyfont
+
+%D Setting the normal sizes as well as the x and xx smaller
+%D sizes is accomplished by the next set of macros. When in
+%D math mode, the commands \type{\tx} and \type{\txx} are
+%D just a switch to the script and double script styles, but
+%D in text mode the values defined by the bodyfontenvironment are
+%D used. Here we also set \type{\currentxfontsize}.
+
+\def\dosetcurrentfontxxxalternative#1#2#3#4%
+ {\chardef\currentxfontsize#2\relax
+ \ifmmode
+ #4%
+ \else\ifcsname\bodyfontvariable{\normalizedbodyfontsize#3}\endcsname
+ \setcurrentfontbodyalternative{\csname\bodyfontvariable\normalizedbodyfontsize#3\endcsname}{#1}%
+ \fi\fi}
+
+\def\setcurrentfontxalternative#1%
+ {\dosetcurrentfontxxxalternative{#1}1\c!x\scriptstyle
+ \let\tx\txx}
+
+\def\setcurrentfontxxalternative#1%
+ {\dosetcurrentfontxxxalternative{#1}2\c!xx\scriptscriptstyle
+ \let\tx\empty
+ \let\txx\empty}
+
+\def\checknestedxfontsize % option
+ {\ifcase\currentxfontsize\else\ifx\fontsize\empty\else
+ \chardef\currentxfontsize\zeropoint
+ \let\fontsize\empty
+ \let\tx\normaltx
+ \let\txx\normaltxx
+ \fi\fi}
+
+\def\setcurrentfontxalternative#1%
+ {\checknestedxfontsize
+ \dosetcurrentfontxxxalternative{#1}1\c!x\scriptstyle
+ \let\tx\txx}
+
+\def\setcurrentfontxxalternative#1%
+ {\checknestedxfontsize
+ \dosetcurrentfontxxxalternative{#1}2\c!xx\scriptscriptstyle
+ \let\tx\empty
+ \let\txx\empty}
+
+% This alterative is not really needed, but for old time's sake
+% we keep it there. We can speed it up when needed.
+
+\def\setcurrentfontxstylealternative #1{\csname#1\endcsname\tx}
+\def\setcurrentfontxxstylealternative#1{\csname#1\endcsname\txx}
+
+%D These macros also show us that when we call for \type{\tx},
+%D this macro is redefined to be \type{\txx}. Therefore calls
+%D like:
+%D
+%D \startbuffer
+%D {small \tx is \tx beautiful}
+%D {small \tx is \txx beautiful}
+%D {small \txx is \tx beautiful}
+%D {small \txx is \txx beautiful}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D result in:
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D Setting the main size involves the style list and therefore
+%D takes a bit more time. Keep in mind that the fontsize is
+%D represented by a character or empty.
+
+\unexpanded\def\tx {\setcurrentfontxalternative \fontalternative}
+\unexpanded\def\txx{\setcurrentfontxxalternative\fontalternative}
+
+\let\normaltx \tx
+\let\normaltxx\txx
+
+%D \macros
+%D {definefontstyle}
+%D
+%D When setting of switching the overall style we can use the
+%D short identifier like rm and ss, but when defined we can
+%D also use more verbose names like roman or sansserif. Such
+%D names are defined by:
+%D
+%D \starttyping
+%D \definefontstyle [serif,rm] [rm]
+%D \definefontstyle [sansserif,ss] [ss]
+%D \stoptyping
+
+\def\dodefinefontstyle[#1][#2]%
+ {\rawdoifinsetelse{#2}{\fontstylelist}
+ {%\debuggerinfo\m!fonts{unknown style #2}%
+ }
+ {%\debuggerinfo\m!fonts8{#2\space (#1)}%
+ \addtocommalist{#2}\fontstylelist}%
+ % check kan hier
+ \def\docommand##1%
+ {\setvalue{\@shortstyle@##1}{#2}%
+ \setvalue{\@style@##1}{\csname#2\endcsname}}%
+ \processcommalist[#1]\docommand}
+
+\unexpanded\def\definefontstyle
+ {\dodoubleargument\dodefinefontstyle}
+
+\def\setfontstyle#1#2% #1:name (roman, romaan) #2:style (rm)
+ {\edef\fontstyle{#1}%
+ \checkfontnamecombinations
+ \setcurrentfontstyle\normalizedbodyfontsize}
+
+%D When asking for a complete font switch, for instance from 10
+%D to 12~points, the next macro does the job. First we
+%D normalize the size, next we define the current range of
+%D text, script and scriptscript sizes, then we set the text
+%D fonts and the math families and finally we activate the
+%D default typeface and also set the font specific parameters
+%D assigned to \type{\everybodyfont}
+
+\def\dosetbodyfontface#1#2%
+ {\edef#1{\csname\bodyfontvariable\normalizedbodyfontsize#2\endcsname}}
+
+\def\docompletefontswitch[#1]%
+ {\bodyfontsize#1\relax
+ \dimensiontocount\bodyfontsize\bodyfontpoints % rounded, still used in m-chart
+ \edef\bodyfontfactor{\withoutpt\the\bodyfontsize}%
+ \normalizebodyfontsize\bodyfontsize\to\normalizedbodyfontsize
+ \dosetbodyfontface \textface \s!text
+ \dosetbodyfontface \scriptface \s!script
+ \dosetbodyfontface \scriptscriptface \s!scriptscript}
+
+\docompletefontswitch[12pt] % init
+
+%D \macros
+%D {setupbodyfont,switchtobodyfont}
+%D
+%D The next two macros are user ones. With \type{\setupbodyfont}
+%D one can set the document bodyfont size, font family, style
+%D and/or options defined in files, for example:
+%D
+%D \starttyping
+%D \setupbodyfont[modern,12pt,roman]
+%D \stoptyping
+%D
+%D This command affects the document as a whole: text, headers
+%D and footers. The second macro however affects only the text:
+%D
+%D \starttyping
+%D \switchtobodyfont[10pt]
+%D \stoptyping
+%D
+%D So we've got:
+%D
+%D \showsetup{setupbodyfont}
+%D \showsetup{switchtobodyfont}
+%D
+%D Both macros look alike. The second one also has to take
+%D all kind of keywords into account.
+
+\ifx\saveinterlinespace \undefined \let\saveinterlinespace \relax \fi
+\ifx\restoreinterlinespace\undefined \let\restoreinterlinespace\relax \fi
+
+% \newtoks \everysetupbodyfont
+% \newtoks \everyswitchtobodyfont
+
+\chardef\bodyfontsetstate=0
+
+\definecomplexorsimple\setupbodyfont
+
+\def\simplesetupbodyfont
+ {\restoreglobalbodyfont
+ \saveinterlinespace}
+
+\def\complexsetupbodyfont[#1]%
+ {\doifsomething{#1}
+ {\dosetfont1{#1}%
+ \globalbodyfontsize\localbodyfontsize
+ \normalizebodyfontsize\globalbodyfontsize\to\normalizedglobalbodyfontsize
+ \let\globalfontstyle\fontstyle
+ \ifloadingfonts\else
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace
+ \fi
+ \the\everysetupbodyfont}}
+
+\unexpanded\def\switchtobodyfont[#1]%
+ {\doifsomething{#1}
+ {\ifcsname\??ft\normalizedbodyfontsize\interfaced{#1}\endcsname
+ \setbodyfontstep{#1}% so we have a fast [small] switch
+ \else
+ \dosetfont0{#1}%
+ \fi
+ \the\everybodyfont
+ \the\everyswitchtobodyfont}}
+
+%D The following alternative is meant for math||to||text
+%D switching and will be optimized.
+
+\def\fastswitchtobodyfont#1%
+ {\ifcsname\??ft\normalizedbodyfontsize#1\endcsname
+ \edef\futurebodyfontsize{\csname\??ft\normalizedbodyfontsize#1\endcsname}%
+ \ifcsname\@size@\futurebodyfontsize\endcsname
+ \csname\@size@\futurebodyfontsize\endcsname
+ \localbodyfontsize\futurebodyfontsize\relax
+ \fi
+ \fi
+ \csname\@style@\fontstyle\endcsname
+ \the\everybodyfont}
+
+%D \starttyping
+%D $\cases{& \ccaron}$ $x=\hbox{\ccaron $x=\hbox{\ccaron}$}$
+%D \stoptyping
+
+\def\setfontcharacteristics
+ {\the\everyfont}
+
+%D Predefined:
+
+% \installfontfeature[otf][tlig]
+% \installfontfeature[otf][trep]
+
+%D tricky but ok:
+
+\appendtoks\ctxlua{fonts.tfm.cleanup()}\to\everyshipout
+
+%D Todo:
+
+% \def\os{\groupedcommand{\setfontfeature{oldstyle}}{}}
+
+%D Experimental:
+
+\unexpanded\def\definefontfeature
+ {\dotripleargument\dodefinefontfeature}
+
+\def\dodefinefontfeature[#1][#2][#3]%
+ {\global\expandafter\chardef\csname\??fq=#1\endcsname % beware () needed as we get two values returned
+ \ctxlua{tex.write((fonts.define.specify.preset_context("#1","#2","#3")))}\relax}
+
+\definefontfeature
+ [default]
+ [%mode=node,
+ liga=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes
+
+\definefontfeature
+ [smallcaps]
+ [%mode=node,liga=yes,
+ smcp=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes
+
+\definefontfeature
+ [oldstyle]
+ [%mode=node,
+ onum=yes,liga=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes
+
+\definefontfeature % == default unless redefined
+ [ligatures]
+ [%mode=node,
+ liga=yes,kern=yes,tlig=yes,trep=yes]
+
+\definefontfeature % can be used for type1 fonts
+ [complete]
+ [liga=yes,kern=yes,compose=yes,tlig=yes,trep=yes]
+
+\definefontfeature
+ [arabic]
+ [mode=node,language=dflt,script=arab,ccmp=yes,
+ init=yes,medi=yes,fina=yes,isol=yes,
+ liga=yes,dlig=yes,rlig=yes,clig=yes,calt=yes,
+ mark=yes,mkmk=yes,kern=yes,curs=yes]
+
+\definefontfeature
+ [none]
+ [mode=none,features=no]
+
+\definefontfeature
+ [virtualmath]
+ [mode=base,liga=yes,kern=yes,tlig=yes,trep=yes]
+
+% for the moment here, this will change but we need it for mk.tex
+
+\definefontfeature[math-text] [virtualmath][ssty=no]
+\definefontfeature[math-script] [virtualmath][ssty=1,mathsize=yes]
+\definefontfeature[math-scriptscript][virtualmath][ssty=2,mathsize=yes]
+
+\definefontfeature [math-nostack-text] [math-text] [nostackmath=yes]
+\definefontfeature [math-nostack-script] [math-script] [nostackmath=yes]
+\definefontfeature [math-nostack-scriptscript][math-scriptscript][nostackmath=yes]
+
+% \definefontfeature[mathtext] [math-text]
+% \definefontfeature[mathscript] [math-script]
+% \definefontfeature[mathscriptscript] [math-scriptscript]
+
+%D Also new, handy for manuals:
+
+\unexpanded\def\fontchar#1{\ctxlua{fonts.char("#1")}}
+
+\let\otfchar\fontchar % will disappear, for compatibility only
+\let\afmchar\fontchar % will disappear, for compatibility only
+
+%D: We cannot yet inherit because no colors are predefined.
+
+\definecolor[font:init][r=.75]
+\definecolor[font:medi][g=.75]
+\definecolor[font:fina][b=.75]
+\definecolor[font:isol][r=.75,g=.75] % [y=.75]
+\definecolor[font:mark][r=.75,b=.75] % [m=.75]
+\definecolor[font:rest][g=.75,b=.75] % [c=.75]
+
+%D Experimental!
+
+\def\installfontfeature
+ {\dodoubleargument\doinstallfontfeature}
+
+\def\doinstallfontfeature[#1][#2]%
+ {\writestatus\m!fonts{installing font features was experimental}} % \ctxlua{fonts.install_feature("#1","#2")}}
+
+%D Not yet in \MKII.
+
+\def\fontfeatureslist
+ {\dodoubleargument\dofontfeatureslist}
+
+\def\dofontfeatureslist[#1][#2]% todo: arg voor type
+ {\ctxlua{tex.sprint(tex.ctxcatcodes,fonts.define.specify.context_tostring("#1","otf","\luaescapestring{#2}","yes","no",true,{"number"}))}}
+
+\attribute\zerocount\zerocount % first in list, so fast match
+
+\let\currentfeature\empty
+
+% ! ! ! very experimental, some test code for idris advanced features ! ! !
+%
+% \startbuffer
+% \definefontfeature[smallcaps][smallcaps][script=latn]
+% \definefontfeature[oldstyle] [oldstyle] [script=latn]
+%
+% \definedfont[name:cambria at 15pt]
+%
+% Hello there {\setff{smallcaps}capped 123 \setff{oldstyle}123!} \blank
+% Hello there {\addff{smallcaps}capped 123 \addff{oldstyle}123!} \blank
+% Hello there {\addff{smallcaps}capped \subff{smallcaps}normal} \blank
+% \stopbuffer
+%
+% \typebuffer \getbuffer
+
+\def\featureattribute#1{\ctxlua{tex.sprint(fonts.define.specify.context_number("#1"))}}
+\def\setfontfeature #1{\edef\currentfeature{#1}\attribute\zerocount\featureattribute{#1}\relax}
+\def\resetfontfeature#1{\let\currentfeature\empty\attribute\zerocount\zerocount} % initial value
+
+\def\addfontfeaturetoset #1{\ctxlua{fonts.withset("#1", 1)}} % merge
+\def\subtractfontfeaturefromset #1{\ctxlua{fonts.withset("#1",-1)}} % merge
+\def\addfontfeaturetofont #1{\ctxlua{fonts.withfnt("#1", 2)}} % overload
+\def\subtractfontfeaturefromfont#1{\ctxlua{fonts.withfnt("#1",-2)}} % overload
+
+\let\setff\setfontfeature
+\let\addfs\addfontfeaturetoset
+\let\subfs\subtractfontfeaturefromset
+\let\addff\addfontfeaturetofont
+\let\subff\subtractfontfeaturefromfont
+
+%D The next auxilliary macro is an alternative to \type
+%D {\fontname}.
+
+\def\purefontname#1{\ctxlua{file.basename("\fontname#1"}} % will be function using id
+
+%D \macros
+%D {switchstyleonly}
+%D
+%D For switching a style but keeping the alternative, there
+%D is:
+%D
+%D \starttyping
+%D {\bf text \switchstyleonly\ss text}
+%D {\bf text \switchstyleonly[ss]text}
+%D {\sl text \switchstyleonly[sansserif]text}
+%D \stoptyping
+
+\definecomplexorsimple\switchstyleonly
+
+\def\simpleswitchstyleonly#1% stupid version
+ {\complexswitchstyleonly[\checkedstrippedcsname#1]}
+
+\def\complexswitchstyleonly[#1]% todo : check
+ {\setcurrentfontstyle{\csname\@shortstyle@#1\endcsname}%
+ \the\everybodyfont} % needed ?
+
+%D \macros
+%D {os}
+%D
+%D In good old \TEX, the old style numerals were often taken
+%D from the math fonts. No longer.
+
+\definefontfeature
+ [just-os]
+ [mode=node,onum=yes]
+
+% \def\sc{\setfontfeature{smallcaps}}
+\unexpanded\def\os{\setfontfeature{just-os}}
+
+%D Code for switching to fraktur and script has also been
+%D changed. We now have an alphabet switcher.
+
+\ifx\mathtext\undefined \let\mathtext\hbox \fi
+
+%D \macros
+%D {definebodyfontswitch}
+%D
+%D \PLAIN\ \TEX\ defines some macro's like \type{\tenpoint}
+%D to switch to a specific bodyfontsize. Just for the sake of
+%D compatibility we can define them like:
+%D
+%D \starttyping
+%D \definebodyfontswitch [twelvepoint] [12pt]
+%D \stoptyping
+%D
+%D We don't support language specific synonyms here, mainly
+%D because \PLAIN\ \TEX\ is english anyway.
+
+\def\dodefinebodyfontswitch[#1][#2]%
+ {\def\docommand##1{\setvalue{##1}{\switchtobodyfont[#2]}}%
+ \processcommalist[#1]\docommand}
+
+\unexpanded\def\definebodyfontswitch
+ {\dodoubleargument\dodefinebodyfontswitch}
+
+%D \macros
+%D {setsmallbodyfont,setmainbodyfont,setbigbodyfont}
+%D
+%D When we're typesetting at for instance 10pt, we can call for
+%D the \type{small} as well as the \type{big} alternative,
+%D related to this main size, using \type{\switchtobodyfont[small]}.
+%D The three alternatives can be activated by the next three
+%D system calls and are defined by the bodyfontenvironment.
+
+\let\fontstep\empty % we can use \fontstep for tracing purposes
+
+\def\setbodyfontstep#1%
+ {\edef\fontstep{\csname\bodyfontvariable\normalizedbodyfontsize\interfaced{#1}\endcsname}%
+ \doswitchpoints[\fontstep]%
+ \doswitchstyle[\fontstyle]}
+
+\unexpanded\def\setsmallbodyfont{\setbodyfontstep\v!small\the\everybodyfont}
+\unexpanded\def\setbigbodyfont {\setbodyfontstep\v!big \the\everybodyfont}
+
+\unexpanded\def\setmainbodyfont
+ {\doswitchpoints[\normalizedbodyfontsize]%
+ \doswitchstyle[\fontstyle]%
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace}
+
+%D \macros
+%D {restoreglobalbodyfont}
+%D
+%D Users can set whatever font available while typesetting text.
+%D Pagenumbers, footers, headers etc. however must be typeset
+%D in the main bodyfont and style of the document. Returning to
+%D the global state can be done with the next macro:
+
+\let\globalfontstyle\c!rm
+
+\def\fullrestoreglobalbodyfont
+ {\let\fontsize\defaultfontsize
+ \let\fontbody\defaultfontbody
+ \chardef\currentxfontsize\zerocount
+ \let\fontclass\globalfontclass
+ \doswitchpoints[\normalizedglobalbodyfontsize]%
+ \doswitchstyle[\globalfontstyle]%
+ \redoconvertfont % just in case a pagebreak occurs
+ \tf
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace}
+
+\def\partialrestoreglobalbodyfont
+ {\let\fontsize\defaultfontsize
+ \let\fontbody\defaultfontbody
+ \chardef\currentxfontsize\zerocount
+ \redoconvertfont
+ \tf
+ \the\everybodyfont % indeed needed
+ \the\everyglobalbodyfont % indeed needed
+ \saveinterlinespace}
+
+\def\restoreglobalbodyfont % ook style etc
+ {\ifx\fontclass\globalfontclass
+ \ifx\fontstyle\globalfontstyle
+ \ifx\normalizedbodyfontsize\normalizedglobalbodyfontsize
+ \partialrestoreglobalbodyfont
+ \else
+ \fullrestoreglobalbodyfont
+ \fi
+ \else
+ \fullrestoreglobalbodyfont
+ \fi
+ \else
+ \fullrestoreglobalbodyfont
+ \fi}
+
+% in case of troubles: \let\restorebodyfont\fullrestoreglobalbodyfont
+
+%D This macro has to be called when entering the pagebody
+%D handling routine as well as the footnote insert routine.
+%D Users can access this feature |<|for instance when one wants
+%D to typeset tables and alike in the main bodyfont and style
+%D while the running text is temporary set to a smaller one|>|
+%D by saying \type{\switchtobodyfont[global]}.
+
+%D \macros
+%D {rasterfont}
+%D
+%D There are (at the moment) two situations in which we want to
+%D have fast access to a particular font. When we are using
+%D \TEX\ to typeset rasters, we use small {\rasterfont.}'s
+%D (a rather small period indeed), the same as \PICTEX\ uses
+%D for drawing purposes.
+
+\definefont [rasterfont] [Serif at 5pt]
+
+%D \macros
+%D {infofont}
+%D
+%D The second situation occurs when we enable the info mode,
+%D and put all kind of status information in the margin. We
+%D don't want huge switches to the main bodyfont and style, so
+%D here too we use a direct method.
+
+\let\infofont\relax % satisfy dep checker
+
+\definefont [infofont] [Mono at 6pt] % todo \the\everybodyfont
+
+%D \macros
+%D {definealternativestyle}
+%D
+%D In the main modules we are going to implement lots of
+%D parameterized commands and one of these parameters will
+%D concern the font to use. To suit consistent use of fonts we
+%D here implement a mechanism for defining the keywords that
+%D present a particular style or alternative.
+%D
+%D \starttyping
+%D \definealternativestyle [keywords] [\style] [\nostyle]
+%D \stoptyping
+%D
+%D The first command is used in the normal textflow, while the
+%D second command takes care of headings and alike. Consider
+%D the next two definitions:
+%D
+%D \starttyping
+%D \definealternativestyle [bold] [\bf] []
+%D \definealternativestyle [cap] [\cap] [\cap]
+%D \stoptyping
+%D
+%D A change \type{\bf} in a heading which is to be set in
+%D \type{\tfd} does not look that well, so therefore we leave
+%D the second argument of \type{\definealternativestyle} empty.
+%D When we capatalize characters using the pseudo small cap
+%D command \type{\cap}, we want this to take effect in both
+%D text and headings, which is accomplished by assigning both
+%D arguments.
+
+\def\dodefinealternativestyle[#1][#2][#3]%
+ {\def\docommand##1%
+ {\ifcsname##1\endcsname\else\setuvalue{##1}{\groupedcommand{#2}{}}\fi
+ \setvalue{\@letter@ ##1}{#2}%
+ \setvalue{\@noletter@##1}{#3}}%
+ \processcommalist[#1]\docommand}
+
+\unexpanded\def\definealternativestyle
+ {\dotripleempty\dodefinealternativestyle}
+
+\unexpanded\def\definestyle{\definealternativestyle}
+
+%D Maybe too geneneric, but probably ok is the following. (Maybe one
+%D day we will use a dedicated grouped command for styles.)
+
+\appendtoks
+ \let\groupedcommand\thirdofthreearguments
+\to \simplifiedcommands
+
+%D This command also defines the keyword as command. This means
+%D that the example definition of \type{bold} we gave before,
+%D results in a command \type{\bold} which can be used as:
+%D
+%D \startbuffer
+%D He's a \bold{bold} man with a {\bold head}.
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or
+%D
+%D \startvoorbeeld
+%D \definealternativestyle[bold][\bf][]\getbuffer
+%D \stopvoorbeeld
+%D
+%D Such definitions are of course unwanted for \type{\cap}
+%D because this would result in an endless recursive call.
+%D Therefore we check on the existance of both the command and
+%D the substitution. The latter is needed because for instance
+%D \type{\type} is an entirely diferent command. That command
+%D handles verbatim, while the style command would just switch
+%D to teletype font. This is just an example of a tricky
+%D naming coincidence.
+
+%D \macros
+%D {doconvertfont,noconvertfont,
+%D dontconvertfont,redoconvertfont}
+%D
+%D After having defined such keywords, we can call for them by
+%D using
+%D
+%D \starttyping
+%D \doconvertfont{keyword}{text}
+%D \stoptyping
+%D
+%D We deliberately pass an argument. This enables us to
+%D assign converters that handle one argument, like
+%D \type{\cap}.
+%D
+%D By default the first specification is used to set the style,
+%D exept when we say \type{\dontconvertfont}, after which the
+%D second specification is used. We can also directly call for
+%D \type{\noconvertfont}. In nested calls, we can restore the
+%D conversion by saying \type{\redoconvertfont}.
+
+% subtle ... \expandafter is needed else problems with lookahead caps
+
+\def\@@dodoconvertfont{\csname\@letter@ \p!defined\expandafter\endcsname\gobbleoneargument}
+\def\@@donoconvertfont{\csname\@noletter@\p!defined\endcsname}
+\def\@@redoconvertfont{\csname \p!defined\expandafter\endcsname\gobbleoneargument}
+
+% beware: p!defined can contain crap like \edef crap {...} and such
+% so we need to pass #1 as well
+
+\unexpanded\def\dodoconvertfont#1% #2% we need the protection
+ {\edef\p!defined{#1}%
+ \ifx\p!defined\empty\else
+ \@EA\dododoconvertfont
+ \fi{#1}}
+
+\def\dododoconvertfont % #1
+ {\ifcsname\@letter@\detokenize\@EA{\p!defined}\endcsname
+ \@EA\@@dodoconvertfont
+ \else\ifcsname\detokenize\@EA{\p!defined}\endcsname
+ \@EAEAEA\@@redoconvertfont
+ \else
+ \@EAEAEA\firstofoneargument
+ \fi\fi} % {#1}
+
+\let\doconvertfont\dodoconvertfont
+
+\unexpanded\def\noconvertfont#1% #2%
+ {\edef\p!defined{#1}%
+ \ifx\p!defined\empty
+ \else
+ \@EA\nononoconvertfont
+ \fi}
+
+\def\nononoconvertfont
+ {\ifcsname\@noletter@\detokenize\@EA{\p!defined}\endcsname
+ \@EA\@@donoconvertfont
+ \fi}
+
+%D Extras:
+
+\unexpanded\def\dontconvertfont{\let\doconvertfont\noconvertfont}
+\unexpanded\def\redoconvertfont{\let\doconvertfont\dodoconvertfont}
+
+%D These commands are not grouped! Grouping is most probably
+%D done by the calling macro's and would lead to unnecessary
+%D overhead.
+
+%D \macros
+%D {em,emphasistypeface,emphasisboldface}
+%D
+%D The next macro started as a copy of Donald Arseneau's
+%D \type{\em} (\TUGNEWS\ Vol.~3, no.~1, 1994). His
+%D implementation was a bit more sophisticated version of the
+%D standard \LATEX\ one. We furter enhanced the macro, so now
+%D it also adapts itself to boldface mode. Because we favor
+%D {\sl slanted} type over {\it italic}, we made the emphasis
+%D adaptable, for instance:
+%D
+%D \starttyping
+%D \def\emphasistypeface {\it}
+%D \def\emphasisboldface {\bi}
+%D \stoptyping
+%D
+%D But we prefer:
+
+\def\emphasistypeface {\sl}
+\def\emphasisboldface {\bs}
+
+%D or even better:
+
+\def\doemphasistypeface#1#2%
+ {\edef\emphasizedtypeface{\csname\??ft\fontclass\normalizedbodyfontsize\c!em\endcsname}%
+ \ifx\emphasizedtypeface\v!slanted
+ #1%
+ \else\ifx\emphasizedtypeface\v!italic
+ #2%
+ \else\ifx\emphasizedtypeface\v!empty
+ \edef\emphasizedtypeface{\csname\??ft\normalizedbodyfontsize\c!em\endcsname}%
+ \ifx\emphasizedtypeface\v!slanted
+ #1%
+ \else\ifx\emphasizedtypeface\v!italic
+ #2%
+ \else
+ \getvalue\emphasizedtypeface
+ \fi\fi
+ \else
+ \getvalue\emphasizedtypeface
+ \fi\fi\fi}
+
+\def\emphasistypeface{\doemphasistypeface\sl\it}
+\def\emphasisboldface{\doemphasistypeface\bs\bi}
+
+%D To be set with the default body font environment: \type
+%D {em} being \type {slanted} or \type {italic}.
+
+\newconditional\emneeded
+
+\newtoks\everyemphasized
+
+\unexpanded\def\em
+ {\relax
+ \ifdim\slantperpoint>\zeropoint
+ \settrue\emneeded
+ \else
+ \setfalse\emneeded
+ \fi
+ \setemphasisboldface % new
+ \ifx\fontalternative\c!it
+ \def\emphasistypeface{\it}\tf
+ \else\ifx\fontalternative\c!sl
+ \def\emphasistypeface{\sl}\tf
+ \else\ifx\fontalternative\c!bf
+ \emphasisboldface
+ \else\ifx\fontalternative\c!bs
+ \def\emphasisboldface{\bs}\bf
+ \else\ifx\fontalternative\c!bi
+ \def\emphasisboldface{\bi}\bf
+ \else
+ \emphasistypeface
+ \fi\fi\fi\fi\fi
+ \the\everyemphasized
+ \ifconditional\emneeded\relax
+ \else
+ \expandafter\aftergroup
+ \fi
+ \emphasiscorrection}
+
+% compare ...
+%
+% \appendtoks \red \to \everyemphasized
+% \setupbodyfontenvironment [default] [em={\italic\color[red]}]
+
+%D The next feature was not present in previous versions. It
+%D takes care of \type {\em \bf ...} sitiations.
+
+\def\setemphasisboldface
+ {\let\savedemphasisboldface\bf
+ \let\setemphasisboldface\relax
+ \unexpanded\def\bf
+ {%\relax
+ \let\bf\relax % new
+ \ifx\fontalternative\c!it
+ \bi
+ \else\ifx\fontalternative\c!sl
+ \bs
+ \else
+ \savedemphasisboldface
+ \fi\fi
+ \let\bf\savedemphasisboldface}}
+
+%D Donald's (adapted) macros take the next character into
+%D account when placing italic correction. As a bonus we also
+%D look for something that looks like a dash, in which case we
+%D don't correct.
+
+\let\italiccorrection=\/ % tex primitive
+
+\def\emphasiscorrection
+ {\ifhmode
+ \expandafter\emphasislook
+ \fi}
+
+\def\emphasislook
+ {\begingroup
+ \futurelet\next\emphasistest}
+
+\def\emphasistest
+ {\ifcat\noexpand\next,% still ok?
+ \expandafter\doemphasiscorrection
+ \else
+ \expandafter\dododoemphasiscorrection
+ \fi}
+
+\def\doemphasiscorrection
+ {\futurelet\next\dodoemphasiscorrection}
+
+\def\dodoemphasiscorrection
+ {\setbox\scratchbox\hbox{\next}%
+ \ifdim\ht\scratchbox=\zeropoint % probably a space
+ \expandafter\dododoemphasiscorrection
+ \else\ifdim\ht\scratchbox<.3ex
+ \expandafter\expandafter\expandafter\endgroup
+ \else
+ \expandafter\expandafter\expandafter\dododoemphasiscorrection
+ \fi\fi}
+
+\def\dododoemphasiscorrection
+ {\scratchskip\lastskip
+ \ifdim\scratchskip=\zeropoint\relax % == \ifzeropt\scratchskip
+ \italiccorrection\relax
+ \else
+ \unskip\italiccorrection\hskip\scratchskip
+ \fi
+ \endgroup}
+
+%D We end with some examples which show the behavior when
+%D some punctuation is met. We also show how the mechanism
+%D adapts itself to bold, italic and slanted typing.
+%D
+%D \startbuffer
+%D test {test}test \par
+%D test {\sl test}test \par
+%D test {\em test}test \par
+%D test {\em test}--test \par
+%D
+%D test {test}, test \par
+%D test {\em test}, test \par
+%D
+%D test {\em test {\em test {\em test} test} test} test \par
+%D test {\bf test {\em test {\em test} test} test} test \par
+%D test {\sl test {\em test {\em test} test} test} test \par
+%D test {\it test {\em test {\em test} test} test} test \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D We get:
+%D
+%D \startvoorbeeld
+%D \startpacked
+%D \getbuffer
+%D \stoppacked
+%D \stopvoorbeeld
+
+%D \macros
+%D {emphbf,emphit,emphsl,emphtf}
+%D
+%D The next emphasis alternatives are for \THANH. They adapt
+%D their style as good as possible.
+
+\def\emphbf{\groupedcommand{\bf\def\emphit{\bi}\def\emphsl{\bs}}{}}
+\def\emphit{\groupedcommand{\it\def\emphbf{\bi}\def\emphsl{\sl}}{}}
+\def\emphsl{\groupedcommand{\sl\def\emphbf{\bs}\def\emphit{\it}}{}}
+\def\emphtf{\groupedcommand{\tf\def\emphbf{\bf}\def\emphit{\it}\def\emphsl{\sl}}{}}
+
+%D \startbuffer
+%D TEXT {\emphbf text \emphit text \emphtf text \emphsl text} TEXT
+%D TEXT \emphbf{text \emphit{text} \emphtf{text} \emphsl{text}} TEXT
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+%D \macros
+%D {setfont}
+%D
+%D Every now and then we want to define a font directly, for
+%D instance when we typeset title pages. The next macro saves
+%D some typing:
+
+\def\setfont% geen \dosetfont mogelijk
+ {\def\next{\nextfont\setupinterlinespace}% hm, we need to use \setuplocalinterlinespace
+ \afterassignment\next\font\nextfont=}
+
+%D One can call this macro as:
+%D
+%D \starttyping
+%D \setfont cmr10 at 60pt
+%D \stoptyping
+%D
+%D After which the font is active and the baselines and
+%D struts are set.
+
+%D \macros
+%D {showbodyfont}
+%D
+%D One can call for a rather simple overview of a bodyfont and the
+%D relations between its alternative fonts.
+%D
+%D \showsetup{showbodyfont}
+%D
+%D The current bodyfont (here we omitted the argument) looks like:
+%D
+%D \showbodyfont
+%D
+%D The implementation is rather straightforward in using
+%D \type{\halign}.
+
+\fetchruntimecommand \showbodyfont {\f!fontprefix\s!run.mkiv}
+
+%D \macros
+%D {showfontstrip, testminimalbaseline, showminimalbaseline}
+%D
+%D The next command can come in handy when combining
+%D different fonts into a collection (typeface) and
+%D determining optimal baseline distances.
+%D
+%D \showfontstrip \blank \showminimalbaseline
+
+\fetchruntimecommand \showfontstrip {\f!fontprefix\s!run.mkiv}
+\fetchruntimecommand \testminimalbaseline {\f!fontprefix\s!run.mkiv}
+\fetchruntimecommand \showminimalbaseline {\f!fontprefix\s!run.mkiv}
+
+%D \macros
+%D {showkerning}
+%D
+%D A goody is:
+%D
+%D \showkerning{Can you guess what kerning is?}
+
+\fetchruntimecommand \showkerning {\f!fontprefix\s!run.mkiv}
+
+%D \macros
+%D {showbodyfontenvironment}
+%D
+%D The current bodyfontenvironment is:
+%D
+%D \showbodyfontenvironment
+%D
+%D This overview is generated using:
+%D
+%D \showsetup{showbodyfontenvironment}
+
+\fetchruntimecommand \showbodyfontenvironment {\f!fontprefix\s!run.mkiv}
+
+%D \macros
+%D {showfont,showfontstyle,showligatures}
+%D
+%D The following command generates a fontmap:
+%D
+%D \startbuffer
+%D \showfont[SansBold at 12pt]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \getbuffer
+
+% to be internationalized
+
+\fetchruntimecommand \showfont {\f!fontprefix\s!run.mkiv}
+\fetchruntimecommand \showfontstyle {\f!fontprefix\s!run.mkiv}
+\fetchruntimecommand \showligature {\f!fontprefix\s!run.mkiv}
+\fetchruntimecommand \showligatures {\f!fontprefix\s!run.mkiv}
+\fetchruntimecommand \showcharratio {\f!fontprefix\s!run.mkiv}
+
+%D \macros
+%D {getglyph, symbolicfont}
+%D
+%D Individual glyphs can be accessed by using
+%D
+%D \starttyping
+%D \getglyph{fontname}{character}
+%D \stoptyping
+%D
+%D This macro is used in for instance the symbol modules and
+%D as one can see, it does obey the small and even smaller
+%D sizes. The \type {\symbolicfont} macro can be used to
+%D switch to a font named \type {fontname} (see \type
+%D {cont-log} and \type {symb-eur} for examples of symbolic
+%D definitions.
+
+\def\fontstringA
+ {\ifx\fontstyle\c!rm \s!Serif \else
+ \ifx\fontstyle\c!ss \s!Sans \else
+ \ifx\fontstyle\c!tt \s!Mono \else
+ \s!Serif \fi\fi\fi}
+
+\def\fontstringB
+ {\ifx\fontstyle\c!rm \s!Regular \else
+ \ifx\fontstyle\c!ss \s!Support \else
+ \ifx\fontstyle\c!tt \s!Type \else
+ \s!Serif \fi\fi\fi}
+
+\def\fontstringC
+ {\ifx\fontalternative\c!bf \s!Bold \else
+ \ifx\fontalternative\c!sl \s!Slanted \else
+ \ifx\fontalternative\c!it \s!Italic \else
+ \ifx\fontalternative\c!bs \s!BoldSlanted \else
+ \ifx\fontalternative\c!bi \s!BoldItalic \fi\fi\fi\fi\fi}
+
+\def\fontstringD % default fontstyle
+ {\expandafter\ifx\csname\??tf\fontclass\s!default\endcsname\c!rm \s!Serif \else
+ \expandafter\ifx\csname\??tf\fontclass\s!default\endcsname\c!ss \s!Sans \else
+ \expandafter\ifx\csname\??tf\fontclass\s!default\endcsname\c!tt \s!Mono \else
+ \s!Serif \fi\fi\fi}
+
+% potential generalization:
+
+% \letvalue{\??ff:t:\c!rm}\s!Serif
+% \letvalue{\??ff:t:\c!ss}\s!Sans
+% \letvalue{\??ff:t:\c!tt}\s!Mono
+%
+% \letvalue{\??ff:s:\c!bf}\s!Bold
+% \letvalue{\??ff:s:\c!sl}\s!Slanted
+% \letvalue{\??ff:s:\c!it}\s!Italic
+% \letvalue{\??ff:s:\c!bs}\s!BoldSlanted
+% \letvalue{\??ff:s:\c!bi}\s!BoldItalic
+%
+% \letvalue{\??ff:a:\c!rm}\s!Regular
+% \letvalue{\??ff:a:\c!ss}\s!Support
+% \letvalue{\??ff:a:\c!tt}\s!Type
+%
+% \def\fontstringA{\executeifdefined{\??ff:t:\fontstyle}\s!Serif}
+% \def\fontstringB{\executeifdefined{\??ff:a:\fontstyle}\s!Serif}
+% \def\fontstringC{\executeifdefined{\??ff:s:\fontstyle}\empty}
+% \def\fontstringD{\executeifdefined{\??ff:t:\csname\??tf\fontclass\s!default\endcsname}\s!Serif}
+
+\def\glyphfontfile#1%
+ {#1%
+ \ifcsname\??ff#1\fontstringA\fontstringC\endcsname
+ \fontstringA\fontstringC
+ \else\ifcsname\??ff#1\fontstringB\fontstringC\endcsname
+ \fontstringB\fontstringC
+ \else\ifcsname\??ff#1\fontstringA\endcsname
+ \fontstringA
+ \else\ifcsname\??ff#1\fontstringB\endcsname
+ \fontstringB
+ \else\ifcsname\??ff#1\fontstringC\endcsname
+ \fontstringC
+ \fi\fi\fi\fi\fi}
+
+%D The next macro can be used to make decisions based on the shape:
+
+\def\doifitalicelse#1#2%
+ {\ifx\fontalternative\c!sl#1\else
+ \ifx\fontalternative\c!it#1\else
+ \ifx\fontalternative\c!bs#1\else
+ \ifx\fontalternative\c!bi#1\else#2\fi\fi\fi\fi}
+
+%D For an example of usage of the following command,
+%D see \type {cont-log.tex}.
+%D
+%D \starttyping
+%D \def\symbolicfont#1{\definedfont[\glyphfontfile{#1} sa *]}
+%D \stoptyping
+%D
+%D Since we know what scaling it to be applied, we can
+%D implement a much faster alternative:
+
+\let\thedefinedfont\relax
+
+\def\symbolicsizedfont#1#2#3%
+ {\scaledfontsize#1%
+ \scaledfontsize#2\scaledfontsize
+ \font\thedefinedfont=\truefontname{\glyphfontfile{#3}} at \currentfontbodyscale\scaledfontsize\relax
+ \thedefinedfont}
+
+\def\symbolicscaledfont
+ {\symbolicsizedfont\fontbody}
+
+\unexpanded\def\symbolicfont
+ {\symbolicsizedfont\fontbody\plusone}
+
+\unexpanded\def\getglyph#1#2% slow, faster, much faster
+ %{{\definefont[\s!dummy][\glyphfontfile{#1} sa \currentfontscale]\dummy#2}}
+ %{{\definefont[\s!dummy][\glyphfontfile{#1} sa *]\dummy#2}}
+ %{{\symbolicfont{#1}#2}}
+ {{\symbolicfont{#1}\doifnumberelse{#2}\char\donothing#2}}
+
+\unexpanded\def\getscaledglyph#1#2#3%
+ {{\symbolicscaledfont{#1}{#2}\doifnumberelse{#3}\char\donothing#3}}
+
+\unexpanded\def\getrawglyph#1#2% for simple symbols
+ {{\scaledfontsize\fontbody
+ \font\thedefinedfont=#1 at \currentfontbodyscale\scaledfontsize\relax
+ \thedefinedfont\doifnumberelse{#2}\char\donothing#2}}
+
+%D The last implementation of \type {\getglyph} permits
+%D definitions like:
+%D
+%D \starttyping
+%D \definefontsynonym [EuroSans] [eurose]
+%D \definefontsynonym [EuroSansBold] [euroseb]
+%D \definefontsynonym [EuroSansItalic] [eurosei]
+%D \definefontsynonym [EuroSansSlanted] [eurosei]
+%D \definefontsynonym [EuroSansBoldItalic] [eurosebi]
+%D \definefontsynonym [EuroSansBoldSlanted] [eurosebi]
+%D
+%D \definesymbol [euro] [\getglyph{Euro}{\char160}]
+%D
+%D \def\euro{\symbol[euro]}
+%D \stoptyping
+%D
+%D These definitions guarantee that the next calls work okay:
+%D
+%D \starttyping
+%D \ss \tf\euro \bf\euro \sla\euro \itd\euro \bs\euro \bic\euro
+%D \stoptyping
+%D
+%D The shape as well as the size is adapted to the current
+%D environment.
+
+%D \macros
+%D {ss, SS, sz}
+%D
+%D We are going to redefine \type{\ss} but for those wo still
+%D want to have access to the german \SS, we save it's value in
+%D \type{\SS}. Ok, I should have used \type{\sf} instead of
+%D \type{\ss} in the first place.
+
+\ifx\undefined\SS \let\SS=\ss \fi
+\ifx\undefined\sz \let\sz=\ss \fi
+
+%D Personally I think that using \TEX\ macro packages is
+%D complicated by the way fonts are handled. Apart from the
+%D many encodings, we also deal with different naming schemes.
+%D Confronted with this problem, I decided to change the
+%D definitions into:
+%D
+%D \starttyping
+%D \definebodyfont [12pt] [rm] [tf=Times-Roman at 12pt]
+%D \stoptyping
+%D
+%D combined with for instance:
+%D
+%D \starttyping
+%D \definefontsynonym [Times-Roman] [tir]
+%D \stoptyping
+
+%D Now we're up to some definitions.
+
+\definebodyfontenvironment
+ [\s!default]
+ [ \s!text=1.0,
+ \s!script=0.7,
+ \s!scriptscript=0.5,
+ \c!a=1.200,
+ \c!b=1.440,
+ \c!c=1.728,
+ \c!d=2.074,
+ *=\currentfontscale, % wildcard
+ \c!x=0.8,
+ \c!xx=0.6,
+ \c!big=1.2,
+ \c!small=0.8,
+ \c!interlinespace=,
+ \c!em=\v!slanted]
+
+\definebodyfontenvironment
+ [20.7pt]
+ [ \s!text=20.7pt,
+ \s!script=\!!fourteenpointfour,
+ \s!scriptscript=\!!twelvepoint,
+ \c!x=17.3pt,
+ \c!xx=\!!fourteenpointfour,
+ \c!big=20.7pt, % !!!!
+ \c!small=17.3pt]
+
+\definebodyfontenvironment
+ [17.3pt]
+ [ \s!text=17.3pt,
+ \s!script=\!!twelvepoint,
+ \s!scriptscript=\!!tenpoint,
+ \c!x=\!!fourteenpointfour,
+ \c!xx=\!!twelvepoint,
+ \c!big=20.7pt,
+ \c!small=\!!fourteenpointfour]
+
+\definebodyfontenvironment
+ [\!!fourteenpointfour]
+ [ \s!text=\!!fourteenpointfour,
+ \s!script=\!!elevenpoint,
+ \s!scriptscript=\!!ninepoint,
+ \c!x=\!!twelvepoint,
+ \c!xx=\!!tenpoint,
+ \c!big=17.3pt,
+ \c!small=\!!twelvepoint]
+
+\definebodyfontenvironment
+ [\!!twelvepoint]
+ [ \s!text=\!!twelvepoint,
+ \s!script=\!!ninepoint,
+ \s!scriptscript=\!!sevenpoint,
+ \c!x=\!!tenpoint,
+ \c!xx=\!!eightpoint,
+ \c!big=\!!fourteenpointfour,
+ \c!small=\!!tenpoint]
+
+\definebodyfontenvironment
+ [\!!elevenpoint]
+ [ \s!text=\!!elevenpoint,
+ \s!script=\!!eightpoint,
+ \s!scriptscript=\!!sixpoint,
+ \c!x=\!!ninepoint,
+ \c!xx=\!!sevenpoint,
+ \c!big=\!!twelvepoint,
+ \c!small=\!!ninepoint]
+
+\definebodyfontenvironment
+ [\!!tenpoint]
+ [ \s!text=\!!tenpoint,
+ \s!script=\!!sevenpoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!eightpoint,
+ \c!xx=\!!sixpoint,
+ \c!big=\!!twelvepoint,
+ \c!small=\!!eightpoint]
+
+\definebodyfontenvironment
+ [\!!ninepoint]
+ [ \s!text=\!!ninepoint,
+ \s!script=\!!sevenpoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!sevenpoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!elevenpoint,
+ \c!small=\!!sevenpoint]
+
+\definebodyfontenvironment
+ [\!!eightpoint]
+ [ \s!text=\!!eightpoint,
+ \s!script=\!!sixpoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!sixpoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!tenpoint,
+ \c!small=\!!sixpoint]
+
+\definebodyfontenvironment
+ [\!!sevenpoint]
+ [ \s!text=\!!sevenpoint,
+ \s!script=\!!sixpoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!sixpoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!ninepoint,
+ \c!small=\!!fivepoint]
+
+\definebodyfontenvironment
+ [\!!sixpoint]
+ [ \s!text=\!!sixpoint,
+ \s!script=\!!fivepoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!fivepoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!eightpoint,
+ \c!small=\!!fivepoint]
+
+\definebodyfontenvironment
+ [\!!fivepoint]
+ [ \s!text=\!!fivepoint,
+ \s!script=\!!fivepoint,
+ \s!scriptscript=\!!fivepoint,
+ \c!x=\!!fivepoint,
+ \c!xx=\!!fivepoint,
+ \c!big=\!!sevenpoint,
+ \c!small=\!!fivepoint]
+
+\definebodyfontenvironment
+ [\!!fourpoint]
+ [ \s!text=\!!fourpoint,
+ \s!script=\!!fourpoint,
+ \s!scriptscript=\!!fourpoint,
+ \c!x=\!!fourpoint,
+ \c!xx=\!!fourpoint,
+ \c!big=\!!sixpoint,
+ \c!small=\!!fourpoint]
+
+\definebodyfontswitch [fourteenpointfour] [\!!fourteenpointfour]
+\definebodyfontswitch [twelvepoint] [\!!twelvepoint]
+\definebodyfontswitch [elevenpoint] [\!!elevenpoint]
+\definebodyfontswitch [tenpoint] [\!!tenpoint]
+\definebodyfontswitch [ninepoint] [\!!ninepoint]
+\definebodyfontswitch [eightpoint] [\!!eightpoint]
+\definebodyfontswitch [sevenpoint] [\!!sevenpoint]
+\definebodyfontswitch [sixpoint] [\!!sixpoint]
+\definebodyfontswitch [fivepoint] [\!!fivepoint]
+\definebodyfontswitch [fourpoint] [\!!fourpoint]
+
+% \definebodyfontswitch [xii] [\!!twelvepoint]
+% \definebodyfontswitch [xi] [\!!elevenpoint]
+% \definebodyfontswitch [x] [\!!tenpoint]
+% \definebodyfontswitch [ix] [\!!ninepoint]
+% \definebodyfontswitch [viii] [\!!eightpoint]
+% \definebodyfontswitch [vii] [\!!sevenpoint]
+% \definebodyfontswitch [vi] [\!!sixpoint]
+
+%D So far.
+
+\definefontstyle [\c!mm] [\c!mm]
+\definefontstyle [\c!rm,\v!roman,\v!serif,\v!regular] [\c!rm]
+\definefontstyle [\c!ss,\v!sansserif,\v!sans,\v!support] [\c!ss]
+\definefontstyle [\c!tt,\v!teletype,\v!type,\v!mono] [\c!tt]
+\definefontstyle [\c!hw,\v!handwritten] [\c!hw]
+\definefontstyle [\c!cg,\v!calligraphic] [\c!cg]
+
+\definefontalternative[\c!tf]
+\definefontalternative[\c!bf]
+\definefontalternative[\c!it]
+\definefontalternative[\c!sl]
+\definefontalternative[\c!bs]
+\definefontalternative[\c!bi]
+\definefontalternative[\c!sc]
+
+\definefontsize[\c!a] \definefontsize[\c!b]
+\definefontsize[\c!c] \definefontsize[\c!d]
+
+\definealternativestyle [\v!mediaeval] [\os] []
+\definealternativestyle [\v!normal] [\tf] []
+\definealternativestyle [\v!bold] [\bf] []
+\definealternativestyle [\v!type] [\tt] []
+\definealternativestyle [\v!mono] [\tt] []
+\definealternativestyle [\v!slanted] [\sl] []
+\definealternativestyle [\v!italic] [\it] []
+\definealternativestyle [\v!boldslanted,\v!slantedbold] [\bs] []
+\definealternativestyle [\v!bolditalic,\v!italicbold] [\bi] []
+\definealternativestyle [\v!small,\v!smallnormal] [\tfx] []
+\definealternativestyle [\v!smallbold] [\bfx] []
+\definealternativestyle [\v!smalltype] [\ttx] []
+\definealternativestyle [\v!smallslanted] [\slx] []
+\definealternativestyle [\v!smallboldslanted,\v!smallslantedbold] [\bsx] []
+\definealternativestyle [\v!smallbolditalic,\v!smallitalicbold] [\bix] []
+
+\definealternativestyle [\v!sans,\v!sansserif] [\ss] []
+\definealternativestyle [\v!sansbold] [\ss\bf] []
+
+%D Slow but handy:
+
+\definealternativestyle [\v!smallbodyfont] [\setsmallbodyfont] []
+\definealternativestyle [\v!bigbodyfont] [\setbigbodyfont] []
+
+%D We treat {\sc Small Caps} and \cap {Pseudo Caps} a bit
+%D different. We also provide an \WORD {uppercase} style.
+
+\definealternativestyle [\v!cap,\v!capital] [\smallcapped] [\smallcapped]
+\definealternativestyle [\v!smallcaps] [\sc] [\sc]
+\definealternativestyle [\v!WORD] [\WORD] [\WORD]
+
+%D \macros
+%D {fontstylesuffix}
+%D
+%D The next macro is used to map non latin fontnames on
+%D fonts. See \type {font-uni} for an example of its use.
+
+\def\fontstylesuffix% why the \s!Regular ? see \getglyph
+ {\ifx\fontalternative\c!tf \s!Regular \else
+ \ifx\fontalternative\c!bf \s!Bold \else
+ \ifx\fontalternative\c!sl \s!Slanted \else
+ \ifx\fontalternative\c!it \s!Italic \else
+ \ifx\fontalternative\c!bs \s!BoldSlanted \else
+ \ifx\fontalternative\c!bi \s!BoldItalic \else
+ \ifx\fontalternative\c!sc \s!Caps \else
+ \s!Regular \fi\fi\fi\fi\fi\fi\fi}%
+
+%D \macros
+%D {definefontvariant,fontvariant,variant}
+%D
+%D This command is obsolete in \MKIV\ as we have features. It might
+%D come back using the local features handlers.
+
+\unexpanded\def\definefontvariant{\dotripleargument\dodefinefontvariant}
+
+\def\dodefinefontvariant[#1][#2][#3]{}
+\def\variant [#1]{}
+
+\ifdefined\Var\else \let\Var\variant \fi
+
+%D By default we load the Computer Modern Roman fonts (but
+%D not yet at this moment) and activate the 12pt roman
+%D bodyfont. Sans serif and teletype are also available and
+%D can be called for by \type{\ss} and \type{\tt}. Loading
+%D takes place elsewhere.
+%D
+%D For tracing purposes we define:
+
+\definefont[tinyfont][Mono at 1ex]
+
+% \tracinglostchars=1
+
+% this needs some interfacing
+%
+% \setupfonts[check=...]
+
+\def\checkcharactersinfont {\ctxlua{fonts.checkers.enable()}}
+\def\removemissingcharacters{\ctxlua{fonts.checkers.enable(true)}}
+
+%D New commands (not yet interfaced):
+
+\def\style[#1]% for inline usage, like \color
+ {\groupedcommand{\ifcsname#1\endcsname\csname#1\endcsname\else\definedfont[#1]\fi}{}}
+
+\unexpanded\def\startstyle[#1]%
+ {\begingroup
+ \ifcsname#1\endcsname\csname#1\endcsname\else\definedfont[#1]\fi}
+
+\unexpanded\def\stopstyle
+ {\endgroup}
+
+%D Still experimental (might even go away).
+
+% \definestylecollection[mine]
+
+% \definestyleinstance[mine][default][sorry]
+% \definestyleinstance[mine][tt][bs][ttbs:\rm\sl]
+% \definestyleinstance[mine][tt][bf][ttbf:\rm\sl]
+% \definestyleinstance[mine][bf][\sl]
+% \definestyleinstance[mine][sl][\tt]
+
+% {\bf test \mine test \sl test \mine test \bs oeps \mine oeps {\tt test \mine \bf test}}
+
+\unexpanded\def\definestylecollection
+ {\dosingleargument\dodefinestylecollection}
+
+\def\dodefinestylecollection[#1]%
+ {\iffirstargument
+ \setuvalue{#1}{\styleinstance[#1]}%
+ \def\docommand##1%
+ {\def\dodocommand####1{\letbeundefined{\??sx##1:####1:\commalistelement}}%
+ \processcommacommand[\fontalternativelist,\s!default]\dodocommand}%
+ \processcommacommand[\fontstylelist,\s!default]\docommand
+ \fi}
+
+\unexpanded\def\definestyleinstance
+ {\doquadrupleargument\dodefinestyleinstance}
+
+\def\dodefinestyleinstance[#1][#2][#3][#4]% [name] [rm|ss|tt|..] [sl|bf|...] [whatever]
+ {\iffirstargument
+ \ifcsname#1\endcsname\else\definestylecollection[#1]\fi
+ \fi
+ \iffourthargument
+ \setvalue{\??sx#1:#2:#3}{#4}%
+ \else\ifthirdargument
+ \setvalue{\??sx#1::#2}{#3}%
+ \else\ifsecondargument
+ \letvalue{\??sx#1::#2}\empty
+ \fi\fi\fi}
+
+\unexpanded\def\styleinstance[#1]% will be made faster
+ {%\begingroup\normalexpanded{\noexpand\infofont[#1:\fontstyle:\fontalternative]}\endgroup
+ \executeifdefined{\??sx#1:\fontstyle:\fontalternative}%
+ {\executeifdefined{\??sx#1:\fontstyle:\s!default}%
+ {\executeifdefined{\??sx#1::\fontalternative}
+ {\getvalue {\??sx#1::\s!default}}}}}
+
+% \unexpanded\def\styleinstance[#1]%
+% {\csname\??sx#1%
+% \ifcsname:\fontstyle:\fontalternative\endcsname
+% :\fontstyle:\fontalternative
+% \else\ifcsname:\fontstyle:\s!default\endcsname
+% :\fontstyle:\s!default
+% \else\ifcsname::\fontalternative\endcsname
+% ::\fontalternative
+% \else\ifcsname::\s!default\endcsname
+% ::\s!default
+% \else
+% % nothing, \relax
+% \fi\fi\fi\fi
+% \endcsname}
+
+%D goodies:
+
+\def\showchardata#1{\ctxlua{fonts.show_char_data("#1")}}
+\def\showfontdata {\ctxlua{fonts.show_font_parameters()}}
+
+%D some low level helpers
+%D
+%D \starttyping
+%D \def\TestLookup#1%
+%D {\dolookupfontbyspec{#1}
+%D pattern: #1, found: \dolookupnoffound
+%D \blank
+%D \dorecurse {\dolookupnoffound} {%
+%D \recurselevel:~\dolookupgetkeyofindex{fontname}{\recurselevel}\quad
+%D }%
+%D \blank}
+%D
+%D \TestLookup{familyname=helveticaneue}
+%D \TestLookup{familyname=helveticaneue,weight=bold}
+%D \TestLookup{familyname=helveticaneue,weight=bold,style=italic}
+%D \stoptyping
+
+% we can also move the lookups to the fonts.namespace (of commands)
+
+\def\dolookupfontbyspec #1{\ctxlua{fonts.names.lookup("#1")}}
+\def\dolookupnoffound {\ctxlua{tex.write(fonts.names.noflookups())}}
+\def\dolookupgetkeyofindex#1#2{\ctxlua{tex.write(fonts.names.getlookupkey("#1",#2))}}
+\def\dolookupgetkey #1{\ctxlua{tex.write(fonts.names.getlookupkey("#1"))}}
+\def\cleanfontname #1{\ctxlua{fonts.cleanname("#1")}}
+
+\protect \endinput
+
+% \startluacode
+% function commands.doifelsecurrentfonthasfeature(name)
+% local f = fonts.ids[font.current()]
+% f = f and f.shared
+% f = f and f.otfdata
+% f = f and f.luatex
+% f = f and f.features
+% commands.doifelse(f and (f.gpos[name] or f.gsub[name]))
+% end
+% \stopluacode
+
+% \def\doifelsecurrentfonthasfeature#1%
+% {\ctxlua{commands.doifelsecurrentfonthasfeature("#1")}}
+
+% \doifelsecurrentfonthasfeature{smcp}{YES}{NO}
+% \doifelsecurrentfonthasfeature{crap}{YES}{NO}
+% \doifelsecurrentfonthasfeature{kern}{YES}{NO}
diff --git a/tex/context/base/font-jap.mkii b/tex/context/base/font-jap.mkii
new file mode 100644
index 000000000..42480df43
--- /dev/null
+++ b/tex/context/base/font-jap.mkii
@@ -0,0 +1,83 @@
+%D \module
+%D [ file=font-jap,
+%D version=2006.01.13,
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Japanese,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D suggestions=Wang Lei,
+%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.
+
+\ifx\handlejapaneseunicodeglyph\undefined \else \endinput \fi
+\ifx\handlechineseunicodeglyph \undefined \input font-chi.tex \fi
+
+\writestatus{loading}{ConTeXt Font Macros / Japanese}
+
+\unprotect
+
+\newif\iftracejapanese
+
+\let\japaneseencoding\empty
+
+\def\setjapaneseencoding
+ {\getfontfileparameters\unicodestyle
+ \ifx\currentfontfileencoding\undefined \else
+ \let\japaneseencoding\currentfontfileencoding
+ \fi}
+
+\def\japaneseunicodescale {\chineseunicodescale }
+\def\japaneseunicodeheight {\chineseunicodeheight }
+\def\japaneseunicodedepth {\chineseunicodedepth }
+\def\japaneseinterglyphskip{\chineseinterglyphskip}
+\def\japanesesurroundskip {\chinesesurroundskip }
+
+\setupunicodefont
+ [japanese]
+ [ \c!scale=\japaneseunicodescale,
+ \c!height=\japaneseunicodeheight,
+ \c!depth=\japaneseunicodedepth,
+ \c!strut=\v!yes,
+ \c!interlinespace=\v!yes,
+ \c!conversion=\japanesenumber,
+ \c!commands=\setjapaneseencoding, % needed for digits
+ \c!command=\handlejapaneseunicodeglyph]
+
+\def\japanesenumber{\numbers}
+
+\def\handlejapaneseunicodeglyph
+ {\begingroup
+% \let\chineseunicodescale \japaneseunicodescale
+% \let\chineseunicodeheight \japaneseunicodeheight
+% \let\chineseunicodedepth \japaneseunicodedepth
+% \let\chineseinterglyphskip\japaneseinterglyphskip
+% \let\chinesesurroundskip \japanesesurroundskip
+ \iftracejapanese\tracechinesetrue\else\tracechinesefalse\fi
+ \handlechineseunicodeglyph
+ \endgroup}
+
+\doifelse \currentregime {utf} {
+
+ % todo: typescripts
+
+ \definefontsynonym [JapaneseRegular] [uni-cybercjk-][encoding=cjk-uni]
+ \definefontsynonym [JapaneseSlanted] [uni-cybercjk-][encoding=cjk-uni]
+ \definefontsynonym [JapaneseItalic] [uni-cybercjk-][encoding=cjk-uni]
+ \definefontsynonym [JapaneseBold] [uni-cybercjk-][encoding=cjk-uni]
+ \definefontsynonym [JapaneseBoldSlanted][uni-cybercjk-][encoding=cjk-uni]
+ \definefontsynonym [JapaneseBoldItalic] [uni-cybercjk-][encoding=cjk-uni]
+
+ \loadmapfile[uni-cybercjk.map]
+
+ \defineunicodefont [Japanese] [Japanese] [japanese]
+
+} {
+ \writestatus{Japanese}{No fonts defined}
+}
+
+\Japanese
+
+\protect \endinput
diff --git a/tex/context/base/font-log.lua b/tex/context/base/font-log.lua
new file mode 100644
index 000000000..97cb4ff7c
--- /dev/null
+++ b/tex/context/base/font-log.lua
@@ -0,0 +1,58 @@
+if not modules then modules = { } end modules ['font-log'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, format, lower, concat = next, string.format, string.lower, table.concat
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+fonts.logger = fonts.logger or { }
+
+--[[ldx--
+
The following functions are used for reporting about the fonts
+used. The message itself is not that useful in regular runs but since
+we now have several readers it may be handy to know what reader is
+used for which font.
+--ldx]]--
+
+function fonts.logger.save(tfmtable,source,specification) -- save file name in spec here ! ! ! ! ! !
+ if tfmtable and specification and specification.specification then
+ local name = lower(specification.name)
+ if trace_defining and not fonts.used[name] then
+ logs.report("define font","registering %s as %s (used: %s)",file.basename(specification.name),source,file.basename(specification.filename))
+ end
+ specification.source = source
+ fonts.loaded[lower(specification.specification)] = specification
+ -- fonts.used[name] = source
+ fonts.used[lower(specification.filename or specification.name)] = source
+ end
+end
+
+function fonts.logger.report(complete)
+ local t = { }
+ for name, used in table.sortedhash(fonts.used) do
+ if complete then
+ t[#t+1] = used .. "->" .. file.basename(name)
+ else
+ t[#t+1] = file.basename(name)
+ end
+ end
+ return t
+end
+
+function fonts.logger.format(name)
+ return fonts.used[name] or "unknown"
+end
+
+statistics.register("loaded fonts", function()
+ if next(fonts.used) then
+ local t = fonts.logger.report()
+ return (#t > 0 and format("%s files: %s",#t,concat(t,separator or " "))) or "none"
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/font-map.lua b/tex/context/base/font-map.lua
new file mode 100644
index 000000000..299508764
--- /dev/null
+++ b/tex/context/base/font-map.lua
@@ -0,0 +1,370 @@
+if not modules then modules = { } end modules ['font-map'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+local match, format, find, concat, gsub, lower = string.match, string.format, string.find, table.concat, string.gsub, string.lower
+local lpegmatch = lpeg.match
+local utfbyte = utf.byte
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local trace_unimapping = false trackers.register("otf.unimapping", function(v) trace_unimapping = v end)
+
+local ctxcatcodes = tex and tex.ctxcatcodes
+
+--[[ldx--
+
Eventually this code will disappear because map files are kind
+of obsolete. Some code may move to runtime or auxiliary modules.
+
The name to unciode related code will stay of course.
+--ldx]]--
+
+fonts = fonts or { }
+fonts.map = fonts.map or { }
+
+local function load_lum_table(filename) -- will move to font goodies
+ local lumname = file.replacesuffix(file.basename(filename),"lum")
+ local lumfile = resolvers.find_file(lumname,"map") or ""
+ if lumfile ~= "" and lfs.isfile(lumfile) then
+ if trace_loading or trace_unimapping then
+ logs.report("load otf","enhance: loading %s ",lumfile)
+ end
+ lumunic = dofile(lumfile)
+ return lumunic, lumfile
+ end
+end
+
+local hex = lpeg.R("AF","09")
+local hexfour = (hex*hex*hex*hex) / function(s) return tonumber(s,16) end
+local hexsix = (hex^1) / function(s) return tonumber(s,16) end
+local dec = (lpeg.R("09")^1) / tonumber
+local period = lpeg.P(".")
+
+local unicode = lpeg.P("uni") * (hexfour * (period + lpeg.P(-1)) * lpeg.Cc(false) + lpeg.Ct(hexfour^1) * lpeg.Cc(true))
+local ucode = lpeg.P("u") * (hexsix * (period + lpeg.P(-1)) * lpeg.Cc(false) + lpeg.Ct(hexsix ^1) * lpeg.Cc(true))
+local index = lpeg.P("index") * dec * lpeg.Cc(false)
+
+local parser = unicode + ucode + index
+
+local parsers = { }
+
+local function make_name_parser(str)
+ if not str or str == "" then
+ return parser
+ else
+ local p = parsers[str]
+ if not p then
+ p = lpeg.P(str) * period * dec * lpeg.Cc(false)
+ parsers[str] = p
+ end
+ return p
+ end
+end
+
+--~ local parser = fonts.map.make_name_parser("Japan1")
+--~ local parser = fonts.map.make_name_parser()
+--~ local function test(str)
+--~ local b, a = lpegmatch(parser,str)
+--~ print((a and table.serialize(b)) or b)
+--~ end
+--~ test("a.sc")
+--~ test("a")
+--~ test("uni1234")
+--~ test("uni1234.xx")
+--~ test("uni12349876")
+--~ test("index1234")
+--~ test("Japan1.123")
+
+local function tounicode16(unicode)
+ if unicode < 0x10000 then
+ return format("%04X",unicode)
+ else
+ return format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00)
+ end
+end
+
+local function tounicode16sequence(unicodes)
+ local t = { }
+ for l=1,#unicodes do
+ local unicode = unicodes[l]
+ if unicode < 0x10000 then
+ t[l] = format("%04X",unicode)
+ else
+ t[l] = format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00)
+ end
+ end
+ return concat(t)
+end
+
+--~ This is quite a bit faster but at the cost of some memory but if we
+--~ do this we will also use it elsewhere so let's not follow this route
+--~ now. I might use this method in the plain variant (no caching there)
+--~ but then I need a flag that distinguishes between code branches.
+--~
+--~ local cache = { }
+--~
+--~ function fonts.map.tounicode16(unicode)
+--~ local s = cache[unicode]
+--~ if not s then
+--~ if unicode < 0x10000 then
+--~ s = format("%04X",unicode)
+--~ else
+--~ s = format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00)
+--~ end
+--~ cache[unicode] = s
+--~ end
+--~ return s
+--~ end
+
+fonts.map.load_lum_table = load_lum_table
+fonts.map.make_name_parser = make_name_parser
+fonts.map.tounicode16 = tounicode16
+fonts.map.tounicode16sequence = tounicode16sequence
+
+local separator = lpeg.S("_.")
+local other = lpeg.C((1 - separator)^1)
+local ligsplitter = lpeg.Ct(other * (separator * other)^0)
+
+--~ print(table.serialize(lpegmatch(ligsplitter,"this")))
+--~ print(table.serialize(lpegmatch(ligsplitter,"this.that")))
+--~ print(table.serialize(lpegmatch(ligsplitter,"japan1.123")))
+--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more")))
+--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more.that")))
+
+fonts.map.add_to_unicode = function(data,filename)
+ local unicodes = data.luatex and data.luatex.unicodes
+ if not unicodes then
+ return
+ end
+ -- we need to move this code
+ unicodes['space'] = unicodes['space'] or 32
+ unicodes['hyphen'] = unicodes['hyphen'] or 45
+ unicodes['zwj'] = unicodes['zwj'] or 0x200D
+ unicodes['zwnj'] = unicodes['zwnj'] or 0x200C
+ -- the tounicode mapping is sparse and only needed for alternatives
+ local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.private, format("%04X",utfbyte("?"))
+ data.luatex.tounicode, data.luatex.originals = tounicode, originals
+ local lumunic, uparser, oparser
+ if false then -- will become an option
+ lumunic = load_lum_table(filename)
+ lumunic = lumunic and lumunic.tounicode
+ end
+ local cidinfo, cidnames, cidcodes = data.cidinfo
+ local usedmap = cidinfo and cidinfo.usedname
+ usedmap = usedmap and lower(usedmap)
+ usedmap = usedmap and fonts.cid.map[usedmap]
+ if usedmap then
+ oparser = usedmap and make_name_parser(cidinfo.ordering)
+ cidnames = usedmap.names
+ cidcodes = usedmap.unicodes
+ end
+ uparser = make_name_parser()
+ local aglmap = fonts.map and fonts.map.agl_to_unicode
+ for index, glyph in next, data.glyphs do
+ local name, unic = glyph.name, glyph.unicode or -1 -- play safe
+ if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then
+ local unicode = (lumunic and lumunic[name]) or (aglmap and aglmap[name])
+ if unicode then
+ originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
+ end
+ -- cidmap heuristics, beware, there is no guarantee for a match unless
+ -- the chain resolves
+ if (not unicode) and usedmap then
+ local foundindex = lpegmatch(oparser,name)
+ if foundindex then
+ unicode = cidcodes[foundindex] -- name to number
+ if unicode then
+ originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
+ else
+ local reference = cidnames[foundindex] -- number to name
+ if reference then
+ local foundindex = lpegmatch(oparser,reference)
+ if foundindex then
+ unicode = cidcodes[foundindex]
+ if unicode then
+ originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
+ end
+ end
+ if not unicode then
+ local foundcodes, multiple = lpegmatch(uparser,reference)
+ if foundcodes then
+ if multiple then
+ originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true
+ else
+ originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ -- a.whatever or a_b_c.whatever or a_b_c (no numbers)
+ if not unicode then
+ local split = lpegmatch(ligsplitter,name)
+ local nplit = (split and #split) or 0
+ if nplit == 0 then
+ -- skip
+ elseif nplit == 1 then
+ local base = split[1]
+ unicode = unicodes[base] or (aglmap and aglmap[base])
+ if unicode then
+ if type(unicode) == "table" then
+ unicode = unicode[1]
+ end
+ originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
+ end
+ else
+ local t = { }
+ for l=1,nplit do
+ local base = split[l]
+ local u = unicodes[base] or (aglmap and aglmap[base])
+ if not u then
+ break
+ elseif type(u) == "table" then
+ t[#t+1] = u[1]
+ else
+ t[#t+1] = u
+ end
+ end
+ if #t > 0 then -- done then
+ originals[index], tounicode[index], nl, unicode = t, tounicode16sequence(t), nl + 1, true
+ end
+ end
+ end
+ -- last resort
+ if not unicode then
+ local foundcodes, multiple = lpegmatch(uparser,name)
+ if foundcodes then
+ if multiple then
+ originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true
+ else
+ originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes
+ end
+ end
+ end
+ if not unicode then
+ originals[index], tounicode[index] = 0xFFFD, "FFFD"
+ end
+ end
+ end
+ if trace_unimapping then
+ for index, glyph in table.sortedhash(data.glyphs) do
+ local toun, name, unic = tounicode[index], glyph.name, glyph.unicode or -1 -- play safe
+ if toun then
+ logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun)
+ else
+ logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic)
+ end
+ end
+ end
+ if trace_loading and (ns > 0 or nl > 0) then
+ logs.report("load otf","enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
+ end
+end
+
+-- the following is sort of obsolete
+--
+-- fonts.map.data = fonts.map.data or { }
+-- fonts.map.encodings = fonts.map.encodings or { }
+-- fonts.map.loaded = fonts.map.loaded or { }
+-- fonts.map.line = fonts.map.line or { }
+--
+-- function fonts.map.line.pdftex(e)
+-- if e.name and e.fontfile then
+-- local fullname = e.fullname or ""
+-- if e.slant and e.slant ~= 0 then
+-- if e.encoding then
+-- pdf.mapline(format('= %s %s "%g SlantFont" <%s <%s',e.name,fullname,e.slant,e.encoding,e.fontfile)))
+-- else
+-- pdf.mapline(format('= %s %s "%g SlantFont" <%s',e.name,fullname,e.slant,e.fontfile)))
+-- end
+-- elseif e.extend and e.extend ~= 1 and e.extend ~= 0 then
+-- if e.encoding then
+-- pdf.mapline(format('= %s %s "%g ExtendFont" <%s <%s',e.name,fullname,e.extend,e.encoding,e.fontfile)))
+-- else
+-- pdf.mapline(format('= %s %s "%g ExtendFont" <%s',e.name,fullname,e.extend,e.fontfile)))
+-- end
+-- else
+-- if e.encoding then
+-- pdf.mapline(format('= %s %s <%s <%s',e.name,fullname,e.encoding,e.fontfile)))
+-- else
+-- pdf.mapline(format('= %s %s <%s',e.name,fullname,e.fontfile)))
+-- end
+-- end
+-- else
+-- return nil
+-- end
+-- end
+--
+-- function fonts.map.flush(backend) -- will also erase the accumulated data
+-- local flushline = fonts.map.line[backend or "pdftex"] or fonts.map.line.pdftex
+-- for _, e in next, fonts.map.data do
+-- flushline(e)
+-- end
+-- fonts.map.data = { }
+-- end
+--
+-- fonts.map.line.dvips = fonts.map.line.pdftex
+-- fonts.map.line.dvipdfmx = function() end
+--
+-- function fonts.map.convert_entries(filename)
+-- if not fonts.map.loaded[filename] then
+-- fonts.map.data, fonts.map.encodings = fonts.map.load_file(filename,fonts.map.data, fonts.map.encodings)
+-- fonts.map.loaded[filename] = true
+-- end
+-- end
+--
+-- function fonts.map.load_file(filename, entries, encodings)
+-- entries = entries or { }
+-- encodings = encodings or { }
+-- local f = io.open(filename)
+-- if f then
+-- local data = f:read("*a")
+-- if data then
+-- for line in gmatch(data,"(.-)[\n\t]") do
+-- if find(line,"^[%#%%%s]") then
+-- -- print(line)
+-- else
+-- local extend, slant, name, fullname, fontfile, encoding
+-- line = gsub(line,'"(.+)"', function(s)
+-- extend = find(s,'"([^"]+) ExtendFont"')
+-- slant = find(s,'"([^"]+) SlantFont"')
+-- return ""
+-- end)
+-- if not name then
+-- -- name fullname encoding fontfile
+-- name, fullname, encoding, fontfile = match(line,"^(%S+)%s+(%S*)[%s<]+(%S*)[%s<]+(%S*)%s*$")
+-- end
+-- if not name then
+-- -- name fullname (flag) fontfile encoding
+-- name, fullname, fontfile, encoding = match(line,"^(%S+)%s+(%S*)[%d%s<]+(%S*)[%s<]+(%S*)%s*$")
+-- end
+-- if not name then
+-- -- name fontfile
+-- name, fontfile = match(line,"^(%S+)%s+[%d%s<]+(%S*)%s*$")
+-- end
+-- if name then
+-- if encoding == "" then encoding = nil end
+-- entries[name] = {
+-- name = name, -- handy
+-- fullname = fullname,
+-- encoding = encoding,
+-- fontfile = fontfile,
+-- slant = tonumber(slant),
+-- extend = tonumber(extend)
+-- }
+-- encodings[name] = encoding
+-- elseif line ~= "" then
+-- -- print(line)
+-- end
+-- end
+-- end
+-- end
+-- f:close()
+-- end
+-- return entries, encodings
+-- end
diff --git a/tex/context/base/font-mis.lua b/tex/context/base/font-mis.lua
new file mode 100644
index 000000000..80a56332a
--- /dev/null
+++ b/tex/context/base/font-mis.lua
@@ -0,0 +1,101 @@
+if not modules then modules = { } end modules ['font-mis'] = {
+ version = 1.001,
+ comment = "companion to luatex-fonts.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next = next
+local lower, strip = string.lower, string.strip
+
+fonts.otf = fonts.otf or { }
+
+fonts.otf.version = fonts.otf.version or 2.650
+fonts.otf.pack = true
+fonts.otf.cache = containers.define("fonts", "otf", fonts.otf.version, true)
+
+function fonts.otf.loadcached(filename,format,sub)
+ -- no recache when version mismatch
+ local name = file.basename(file.removesuffix(filename))
+ if sub == "" then sub = false end
+ local hash = name
+ if sub then
+ hash = hash .. "-" .. sub
+ end
+ hash = containers.cleanname(hash)
+ local data = containers.read(fonts.otf.cache(), hash)
+ if data and not data.verbose then
+ fonts.otf.enhancers.unpack(data)
+ return data
+ else
+ return nil
+ end
+end
+
+local featuregroups = { "gsub", "gpos" }
+
+function fonts.get_features(name,t,script,language)
+ local t = lower(t or (name and file.extname(name)) or "")
+ if t == "otf" or t == "ttf" or t == "ttc" or t == "dfont" then
+ local filename = resolvers.find_file(name,t) or ""
+ if filename ~= "" then
+ local data = fonts.otf.loadcached(filename)
+ if data and data.luatex and data.luatex.features then
+ return data.luatex.features
+ else
+ local ff = fontloader.open(filename)
+ if ff then
+ local data = fontloader.to_table(ff)
+ fontloader.close(ff)
+ local features = { }
+ for k=1,#featuregroups do
+ local what = featuregroups[k]
+ local dw = data[what]
+ if dw then
+ local f = { }
+ features[what] = f
+ for i=1,#dw do
+ local d = dw[i]
+ local dfeatures = d.features
+ if dfeatures then
+ for i=1,#dfeatures do
+ local df = dfeatures[i]
+ local tag = strip(lower(df.tag))
+ local ft = f[tag] if not ft then ft = {} f[tag] = ft end
+ local dfscripts = df.scripts
+ for i=1,#dfscripts do
+ local ds = dfscripts[i]
+ local scri = strip(lower(ds.script))
+ local fts = ft[scri] if not fts then fts = {} ft[scri] = fts end
+ local dslangs = ds.langs
+ for i=1,#dslangs do
+ local lang = dslangs[i]
+ lang = strip(lower(lang))
+ if scri == script then
+ if lang == language then
+ fts[lang] = 'sl'
+ else
+ fts[lang] = 's'
+ end
+ else
+ if lang == language then
+ fts[lang] = 'l'
+ else
+ fts[lang] = true
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ return features
+ end
+ end
+ end
+ end
+ return nil, nil
+end
diff --git a/tex/context/base/font-ota.lua b/tex/context/base/font-ota.lua
new file mode 100644
index 000000000..0b61e17d1
--- /dev/null
+++ b/tex/context/base/font-ota.lua
@@ -0,0 +1,286 @@
+if not modules then modules = { } end modules ['font-ota'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (analysing)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this might become scrp-*.lua
+
+local type, tostring, match, format, concat = type, tostring, string.match, string.format, table.concat
+
+if not trackers then trackers = { register = function() end } end
+
+local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
+local trace_cjk = false trackers.register("cjk.injections", function(v) trace_cjk = v end)
+
+trackers.register("cjk.analyzing","otf.analyzing")
+
+fonts = fonts or { }
+fonts.analyzers = fonts.analyzers or { }
+fonts.analyzers.initializers = fonts.analyzers.initializers or { node = { otf = { } } }
+fonts.analyzers.methods = fonts.analyzers.methods or { node = { otf = { } } }
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local initializers = fonts.analyzers.initializers
+local methods = fonts.analyzers.methods
+
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local penalty = node.id('penalty')
+
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local traverse_id = node.traverse_id
+local traverse_node_list = node.traverse
+
+local fontdata = fonts.ids
+local state = attributes.private('state')
+
+local fcs = (fonts.color and fonts.color.set) or function() end
+local fcr = (fonts.color and fonts.color.reset) or function() end
+
+local a_to_script = otf.a_to_script
+local a_to_language = otf.a_to_language
+
+-- in the future we will use language/script attributes instead of the
+-- font related value, but then we also need dynamic features which is
+-- somewhat slower; and .. we need a chain of them
+
+function fonts.initializers.node.otf.analyze(tfmdata,value,attr)
+ if attr and attr > 0 then
+ script, language = a_to_script[attr], a_to_language[attr]
+ else
+ script, language = tfmdata.script, tfmdata.language
+ end
+ local action = initializers[script]
+ if action then
+ if type(action) == "function" then
+ return action(tfmdata,value)
+ else
+ local action = action[language]
+ if action then
+ return action(tfmdata,value)
+ end
+ end
+ end
+ return nil
+end
+
+function fonts.methods.node.otf.analyze(head,font,attr)
+ local tfmdata = fontdata[font]
+ local script, language
+ if attr and attr > 0 then
+ script, language = a_to_script[attr], a_to_language[attr]
+ else
+ script, language = tfmdata.script, tfmdata.language
+ end
+ local action = methods[script]
+ if action then
+ if type(action) == "function" then
+ return action(head,font,attr)
+ else
+ action = action[language]
+ if action then
+ return action(head,font,attr)
+ end
+ end
+ end
+ return head, false
+end
+
+otf.features.register("analyze",true) -- we always analyze
+table.insert(fonts.triggers,"analyze") -- we need a proper function for doing this
+
+-- latin
+
+fonts.analyzers.methods.latn = fonts.analyzers.aux.setstate
+
+-- this info eventually will go into char-def
+
+local zwnj = 0x200C
+local zwj = 0x200D
+
+local isol = {
+ [0x0600] = true, [0x0601] = true, [0x0602] = true, [0x0603] = true,
+ [0x0608] = true, [0x060B] = true, [0x0621] = true, [0x0674] = true,
+ [0x06DD] = true, [zwnj] = true,
+}
+
+local isol_fina = {
+ [0x0622] = true, [0x0623] = true, [0x0624] = true, [0x0625] = true,
+ [0x0627] = true, [0x0629] = true, [0x062F] = true, [0x0630] = true,
+ [0x0631] = true, [0x0632] = true, [0x0648] = true, [0x0671] = true,
+ [0x0672] = true, [0x0673] = true, [0x0675] = true, [0x0676] = true,
+ [0x0677] = true, [0x0688] = true, [0x0689] = true, [0x068A] = true,
+ [0x068B] = true, [0x068C] = true, [0x068D] = true, [0x068E] = true,
+ [0x068F] = true, [0x0690] = true, [0x0691] = true, [0x0692] = true,
+ [0x0693] = true, [0x0694] = true, [0x0695] = true, [0x0696] = true,
+ [0x0697] = true, [0x0698] = true, [0x0699] = true, [0x06C0] = true,
+ [0x06C3] = true, [0x06C4] = true, [0x06C5] = true, [0x06C6] = true,
+ [0x06C7] = true, [0x06C8] = true, [0x06C9] = true, [0x06CA] = true,
+ [0x06CB] = true, [0x06CD] = true, [0x06CF] = true, [0x06D2] = true,
+ [0x06D3] = true, [0x06D5] = true, [0x06EE] = true, [0x06EF] = true,
+ [0x0759] = true, [0x075A] = true, [0x075B] = true, [0x076B] = true,
+ [0x076C] = true, [0x0771] = true, [0x0773] = true, [0x0774] = true,
+ [0x0778] = true, [0x0779] = true, [0xFEF5] = true, [0xFEF7] = true,
+ [0xFEF9] = true, [0xFEFB] = true,
+}
+
+local isol_fina_medi_init = {
+ [0x0626] = true, [0x0628] = true, [0x062A] = true, [0x062B] = true,
+ [0x062C] = true, [0x062D] = true, [0x062E] = true, [0x0633] = true,
+ [0x0634] = true, [0x0635] = true, [0x0636] = true, [0x0637] = true,
+ [0x0638] = true, [0x0639] = true, [0x063A] = true, [0x063B] = true,
+ [0x063C] = true, [0x063D] = true, [0x063E] = true, [0x063F] = true,
+ [0x0640] = true, [0x0641] = true, [0x0642] = true, [0x0643] = true,
+ [0x0644] = true, [0x0645] = true, [0x0646] = true, [0x0647] = true,
+ [0x0649] = true, [0x064A] = true, [0x066E] = true, [0x066F] = true,
+ [0x0678] = true, [0x0679] = true, [0x067A] = true, [0x067B] = true,
+ [0x067C] = true, [0x067D] = true, [0x067E] = true, [0x067F] = true,
+ [0x0680] = true, [0x0681] = true, [0x0682] = true, [0x0683] = true,
+ [0x0684] = true, [0x0685] = true, [0x0686] = true, [0x0687] = true,
+ [0x069A] = true, [0x069B] = true, [0x069C] = true, [0x069D] = true,
+ [0x069E] = true, [0x069F] = true, [0x06A0] = true, [0x06A1] = true,
+ [0x06A2] = true, [0x06A3] = true, [0x06A4] = true, [0x06A5] = true,
+ [0x06A6] = true, [0x06A7] = true, [0x06A8] = true, [0x06A9] = true,
+ [0x06AA] = true, [0x06AB] = true, [0x06AC] = true, [0x06AD] = true,
+ [0x06AE] = true, [0x06AF] = true, [0x06B0] = true, [0x06B1] = true,
+ [0x06B2] = true, [0x06B3] = true, [0x06B4] = true, [0x06B5] = true,
+ [0x06B6] = true, [0x06B7] = true, [0x06B8] = true, [0x06B9] = true,
+ [0x06BA] = true, [0x06BB] = true, [0x06BC] = true, [0x06BD] = true,
+ [0x06BE] = true, [0x06BF] = true, [0x06C1] = true, [0x06C2] = true,
+ [0x06CC] = true, [0x06CE] = true, [0x06D0] = true, [0x06D1] = true,
+ [0x06FA] = true, [0x06FB] = true, [0x06FC] = true, [0x06FF] = true,
+ [0x0750] = true, [0x0751] = true, [0x0752] = true, [0x0753] = true,
+ [0x0754] = true, [0x0755] = true, [0x0756] = true, [0x0757] = true,
+ [0x0758] = true, [0x075C] = true, [0x075D] = true, [0x075E] = true,
+ [0x075F] = true, [0x0760] = true, [0x0761] = true, [0x0762] = true,
+ [0x0763] = true, [0x0764] = true, [0x0765] = true, [0x0766] = true,
+ [0x0767] = true, [0x0768] = true, [0x0769] = true, [0x076A] = true,
+ [0x076D] = true, [0x076E] = true, [0x076F] = true, [0x0770] = true,
+ [0x0772] = true, [0x0775] = true, [0x0776] = true, [0x0777] = true,
+ [0x077A] = true, [0x077B] = true, [0x077C] = true, [0x077D] = true,
+ [0x077E] = true, [0x077F] = true, [zwj] = true,
+}
+
+local arab_warned = { }
+
+-- todo: gref
+
+local function warning(current,what)
+ local char = current.char
+ if not arab_warned[char] then
+ log.report("analyze","arab: character %s (U+%04X) has no %s class", char, char, what)
+ arab_warned[char] = true
+ end
+end
+
+function fonts.analyzers.methods.nocolor(head,font,attr)
+ for n in traverse_node_list(head,glyph) do
+ if not font or n.font == font then
+ fcr(n)
+ end
+ end
+ return head, true
+end
+
+local function finish(first,last)
+ if last then
+ if first == last then
+ local fc = first.char
+ if isol_fina_medi_init[fc] or isol_fina[fc] then
+ set_attribute(first,state,4) -- isol
+ if trace_analyzing then fcs(first,"font:isol") end
+ else
+ warning(first,"isol")
+ set_attribute(first,state,0) -- error
+ if trace_analyzing then fcr(first) end
+ end
+ else
+ local lc = last.char
+ if isol_fina_medi_init[lc] or isol_fina[lc] then -- why isol here ?
+ -- if laststate == 1 or laststate == 2 or laststate == 4 then
+ set_attribute(last,state,3) -- fina
+ if trace_analyzing then fcs(last,"font:fina") end
+ else
+ warning(last,"fina")
+ set_attribute(last,state,0) -- error
+ if trace_analyzing then fcr(last) end
+ end
+ end
+ first, last = nil, nil
+ elseif first then
+ -- first and last are either both set so we never com here
+ local fc = first.char
+ if isol_fina_medi_init[fc] or isol_fina[fc] then
+ set_attribute(first,state,4) -- isol
+ if trace_analyzing then fcs(first,"font:isol") end
+ else
+ warning(first,"isol")
+ set_attribute(first,state,0) -- error
+ if trace_analyzing then fcr(first) end
+ end
+ first = nil
+ end
+ return first, last
+end
+
+function fonts.analyzers.methods.arab(head,font,attr) -- maybe make a special version with no trace
+ local tfmdata = fontdata[font]
+ local marks = tfmdata.marks
+ local first, last, current, done = nil, nil, head, false
+ while current do
+ if current.id == glyph and current.subtype<256 and current.font == font and not has_attribute(current,state) then
+ done = true
+ local char = current.char
+ if marks[char] then
+ set_attribute(current,state,5) -- mark
+ if trace_analyzing then fcs(current,"font:mark") end
+ elseif isol[char] then -- can be zwj or zwnj too
+ first, last = finish(first,last)
+ set_attribute(current,state,4) -- isol
+ if trace_analyzing then fcs(current,"font:isol") end
+ first, last = nil, nil
+ elseif not first then
+ if isol_fina_medi_init[char] then
+ set_attribute(current,state,1) -- init
+ if trace_analyzing then fcs(current,"font:init") end
+ first, last = first or current, current
+ elseif isol_fina[char] then
+ set_attribute(current,state,4) -- isol
+ if trace_analyzing then fcs(current,"font:isol") end
+ first, last = nil, nil
+ else -- no arab
+ first, last = finish(first,last)
+ end
+ elseif isol_fina_medi_init[char] then
+ first, last = first or current, current
+ set_attribute(current,state,2) -- medi
+ if trace_analyzing then fcs(current,"font:medi") end
+ elseif isol_fina[char] then
+ if not has_attribute(last,state,1) then
+ -- tricky, we need to check what last may be !
+ set_attribute(last,state,2) -- medi
+ if trace_analyzing then fcs(last,"font:medi") end
+ end
+ set_attribute(current,state,3) -- fina
+ if trace_analyzing then fcs(current,"font:fina") end
+ first, last = nil, nil
+ elseif char >= 0x0600 and char <= 0x06FF then
+ if trace_analyzing then fcs(current,"font:rest") end
+ first, last = finish(first,last)
+ else --no
+ first, last = finish(first,last)
+ end
+ else
+ first, last = finish(first,last)
+ end
+ current = current.next
+ end
+ first, last = finish(first,last)
+ return head, done
+end
diff --git a/tex/context/base/font-otb.lua b/tex/context/base/font-otb.lua
new file mode 100644
index 000000000..a3d347737
--- /dev/null
+++ b/tex/context/base/font-otb.lua
@@ -0,0 +1,373 @@
+if not modules then modules = { } end modules ['font-otb'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local concat = table.concat
+local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+local lpegmatch = lpeg.match
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local trace_baseinit = false trackers.register("otf.baseinit", function(v) trace_baseinit = v end)
+local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false trackers.register("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false trackers.register("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false trackers.register("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
+local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
+
+local wildcard = "*"
+local default = "dflt"
+
+local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
+
+local pcache, fcache = { }, { } -- could be weak
+
+local function gref(descriptions,n)
+ if type(n) == "number" then
+ local name = descriptions[n].name
+ if name then
+ return format("U+%04X (%s)",n,name)
+ else
+ return format("U+%04X")
+ end
+ elseif n then
+ local num, nam = { }, { }
+ for i=1,#n do
+ local ni = n[i]
+ num[i] = format("U+%04X",ni)
+ nam[i] = descriptions[ni].name or "?"
+ end
+ return format("%s (%s)",concat(num," "), concat(nam," "))
+ else
+ return "?"
+ end
+end
+
+local function cref(kind,lookupname)
+ if lookupname then
+ return format("feature %s, lookup %s",kind,lookupname)
+ else
+ return format("feature %s",kind)
+ end
+end
+
+local function resolve_ligatures(tfmdata,ligatures,kind)
+ kind = kind or "unknown"
+ local unicodes = tfmdata.unicodes
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local changed = tfmdata.changed
+ local done = { }
+ while true do
+ local ok = false
+ for k,v in next, ligatures do
+ local lig = v[1]
+ if not done[lig] then
+ local ligs = lpegmatch(split_at_space,lig)
+ if #ligs == 2 then
+ local uc = v[2]
+ local c, f, s = characters[uc], ligs[1], ligs[2]
+ local uft, ust = unicodes[f] or 0, unicodes[s] or 0
+ if not uft or not ust then
+ logs.report("define otf","%s: unicode problem with base ligature %s = %s + %s",cref(kind),gref(descriptions,uc),gref(descriptions,uft),gref(descriptions,ust))
+ -- some kind of error
+ else
+ if type(uft) == "number" then uft = { uft } end
+ if type(ust) == "number" then ust = { ust } end
+ for ufi=1,#uft do
+ local uf = uft[ufi]
+ for usi=1,#ust do
+ local us = ust[usi]
+ if changed[uf] or changed[us] then
+ if trace_baseinit and trace_ligatures then
+ logs.report("define otf","%s: base ligature %s + %s ignored",cref(kind),gref(descriptions,uf),gref(descriptions,us))
+ end
+ else
+ local first, second = characters[uf], us
+ if first and second then
+ local t = first.ligatures
+ if not t then
+ t = { }
+ first.ligatures = t
+ end
+ if type(uc) == "number" then
+ t[second] = { type = 0, char = uc }
+ else
+ t[second] = { type = 0, char = uc[1] } -- can this still happen?
+ end
+ if trace_baseinit and trace_ligatures then
+ logs.report("define otf","%s: base ligature %s + %s => %s",cref(kind),gref(descriptions,uf),gref(descriptions,us),gref(descriptions,uc))
+ end
+ end
+ end
+ end
+ end
+ end
+ ok, done[lig] = true, descriptions[uc].name
+ end
+ end
+ end
+ if ok then
+ -- done has "a b c" = "a_b_c" and ligatures the already set ligatures: "a b" = 123
+ -- and here we add extras (f i i = fi + i and alike)
+ --
+ -- we could use a hash for fnc and pattern
+ --
+ -- this might be interfering !
+ for d,n in next, done do
+ local pattern = pcache[d] if not pattern then pattern = "^(" .. d .. ") " pcache[d] = pattern end
+ local fnc = fcache[n] if not fnc then fnc = function() return n .. " " end fcache[n] = fnc end
+ for k,v in next, ligatures do
+ v[1] = gsub(v[1],pattern,fnc)
+ end
+ end
+ else
+ break
+ end
+ end
+end
+
+local splitter = lpeg.splitat(" ")
+
+function prepare_base_substitutions(tfmdata,kind,value) -- we can share some code with the node features
+ if value then
+ local otfdata = tfmdata.shared.otfdata
+ local validlookups, lookuplist = otf.collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
+ if validlookups then
+ local ligatures = { }
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local indices = tfmdata.indices
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local changed = tfmdata.changed
+ --
+ local actions = {
+ substitution = function(p,lookup,k,glyph,unicode)
+ local pv = p[2] -- p.variant
+ if pv then
+ local upv = unicodes[pv]
+ if upv then
+ if type(upv) == "table" then
+ upv = upv[1]
+ end
+ if characters[upv] then
+ if trace_baseinit and trace_singles then
+ logs.report("define otf","%s: base substitution %s => %s",cref(kind,lookup),gref(descriptions,k),gref(descriptions,upv))
+ end
+ changed[k] = upv
+ end
+ end
+ end
+ end,
+ alternate = function(p,lookup,k,glyph,unicode)
+ local pc = p[2] -- p.components
+ if pc then
+ -- a bit optimized ugliness
+ if value == 1 then
+ pc = lpegmatch(splitter,pc)
+ elseif value == 2 then
+ local a, b = lpegmatch(splitter,pc)
+ pc = b or a
+ else
+ pc = { lpegmatch(splitter,pc) }
+ pc = pc[value] or pc[#pc]
+ end
+ if pc then
+ local upc = unicodes[pc]
+ if upc then
+ if type(upc) == "table" then
+ upc = upc[1]
+ end
+ if characters[upc] then
+ if trace_baseinit and trace_alternatives then
+ logs.report("define otf","%s: base alternate %s %s => %s",cref(kind,lookup),tostring(value),gref(descriptions,k),gref(descriptions,upc))
+ end
+ changed[k] = upc
+ end
+ end
+ end
+ end
+ end,
+ ligature = function(p,lookup,k,glyph,unicode)
+ local pc = p[2]
+ if pc then
+ if trace_baseinit and trace_ligatures then
+ local upc = { lpegmatch(splitter,pc) }
+ for i=1,#upc do upc[i] = unicodes[upc[i]] end
+ -- we assume that it's no table
+ logs.report("define otf","%s: base ligature %s => %s",cref(kind,lookup),gref(descriptions,upc),gref(descriptions,k))
+ end
+ ligatures[#ligatures+1] = { pc, k }
+ end
+ end,
+ }
+ --
+ for k,c in next, characters do
+ local glyph = descriptions[k]
+ local lookups = glyph.slookups
+ if lookups then
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local p = lookups[lookup]
+ if p then
+ local a = actions[p[1]]
+ if a then
+ a(p,lookup,k,glyph,unicode)
+ end
+ end
+ end
+ end
+ local lookups = glyph.mlookups
+ if lookups then
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local ps = lookups[lookup]
+ if ps then
+ for i=1,#ps do
+ local p = ps[i]
+ local a = actions[p[1]]
+ if a then
+ a(p,lookup,k,glyph,unicode)
+ end
+ end
+ end
+ end
+ end
+ end
+ resolve_ligatures(tfmdata,ligatures,kind)
+ end
+ else
+ tfmdata.ligatures = tfmdata.ligatures or { } -- left over from what ?
+ end
+end
+
+local function prepare_base_kerns(tfmdata,kind,value) -- todo what kind of kerns, currently all
+ if value then
+ local otfdata = tfmdata.shared.otfdata
+ local validlookups, lookuplist = otf.collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
+ if validlookups then
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local indices = tfmdata.indices
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local sharedkerns = { }
+ for u, chr in next, characters do
+ local d = descriptions[u]
+ if d then
+ local dk = d.mykerns -- shared
+ if dk then
+ local s = sharedkerns[dk]
+ if s == false then
+ -- skip
+ elseif s then
+ chr.kerns = s
+ else
+ local t, done = chr.kerns or { }, false
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local kerns = dk[lookup]
+ if kerns then
+ for k, v in next, kerns do
+ if v ~= 0 and not t[k] then -- maybe no 0 test here
+ t[k], done = v, true
+ if trace_baseinit and trace_kerns then
+ logs.report("define otf","%s: base kern %s + %s => %s",cref(kind,lookup),gref(descriptions,u),gref(descriptions,k),v)
+ end
+ end
+ end
+ end
+ end
+ if done then
+ sharedkerns[dk] = t
+ chr.kerns = t -- no empty assignments
+ else
+ sharedkerns[dk] = false
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+-- In principle we could register each feature individually which was
+-- what we did in earlier versions. However, after the rewrite it
+-- made more sense to collect them in an overall features initializer
+-- just as with the node variant. There it was needed because we need
+-- to do complete mixed runs and not run featurewise (as we did before).
+
+local supported_gsub = {
+ 'liga', 'dlig', 'rlig', 'hlig',
+ 'pnum', 'onum', 'tnum', 'lnum',
+ 'zero',
+ 'smcp', 'cpsp', 'c2sc', 'ornm', 'aalt',
+ 'hwid', 'fwid',
+ 'ssty', 'rtlm', -- math
+-- 'tlig', 'trep',
+}
+
+local supported_gpos = {
+ 'kern'
+}
+
+function otf.features.register_base_substitution(tag)
+ supported_gsub[#supported_gsub+1] = tag
+end
+function otf.features.register_base_kern(tag)
+ supported_gsub[#supported_gpos+1] = tag
+end
+
+local basehash, basehashes = { }, 1
+
+function fonts.initializers.base.otf.features(tfmdata,value)
+ if true then -- value then
+ -- not shared
+ local t = trace_preparing and os.clock()
+ local features = tfmdata.shared.features
+ if features then
+ local h = { }
+ for f=1,#supported_gsub do
+ local feature = supported_gsub[f]
+ local value = features[feature]
+ prepare_base_substitutions(tfmdata,feature,value)
+ if value then
+ h[#h+1] = feature .. "=" .. tostring(value)
+ end
+ end
+ for f=1,#supported_gpos do
+ local feature = supported_gpos[f]
+ local value = features[feature]
+ prepare_base_kerns(tfmdata,feature,features[feature])
+ if value then
+ h[#h+1] = feature .. "=" .. tostring(value)
+ end
+ end
+ local hash = concat(h," ")
+ local base = basehash[hash]
+ if not base then
+ basehashes = basehashes + 1
+ base = basehashes
+ basehash[hash] = base
+ end
+ -- We need to make sure that luatex sees the difference between
+ -- base fonts that have different glyphs in the same slots in fonts
+ -- that have the same fullname (or filename). LuaTeX will merge fonts
+ -- eventually (and subset later on). If needed we can use a more
+ -- verbose name as long as we don't use <()<>[]{}/%> and the length
+ -- is < 128.
+ tfmdata.fullname = tfmdata.fullname .. "-" .. base -- tfmdata.psname is the original
+ --~ logs.report("otf define","fullname base hash: '%s', featureset '%s'",tfmdata.fullname,hash)
+ end
+ if trace_preparing then
+ logs.report("otf define","preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ end
+ end
+end
diff --git a/tex/context/base/font-otc.lua b/tex/context/base/font-otc.lua
new file mode 100644
index 000000000..357d347b1
--- /dev/null
+++ b/tex/context/base/font-otc.lua
@@ -0,0 +1,213 @@
+if not modules then modules = { } end modules ['font-otc'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (context)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, insert = string.format, table.insert
+local type, next = type, next
+
+-- we assume that the other otf stuff is loaded already
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+-- instead of "script = "DFLT", langs = { 'dflt' }" we now use wildcards (we used to
+-- have always); some day we can write a "force always when true" trick for other
+-- features as well
+--
+-- we could have a tnum variant as well
+
+local extra_lists = {
+ tlig = {
+ {
+ endash = "hyphen hyphen",
+ emdash = "hyphen hyphen hyphen",
+ -- quotedblleft = "quoteleft quoteleft",
+ -- quotedblright = "quoteright quoteright",
+ -- quotedblleft = "grave grave",
+ -- quotedblright = "quotesingle quotesingle",
+ -- quotedblbase = "comma comma",
+ },
+ },
+ trep = {
+ {
+ -- [0x0022] = 0x201D,
+ [0x0027] = 0x2019,
+ -- [0x0060] = 0x2018,
+ },
+ },
+ anum = {
+ { -- arabic
+ [0x0030] = 0x0660,
+ [0x0031] = 0x0661,
+ [0x0032] = 0x0662,
+ [0x0033] = 0x0663,
+ [0x0034] = 0x0664,
+ [0x0035] = 0x0665,
+ [0x0036] = 0x0666,
+ [0x0037] = 0x0667,
+ [0x0038] = 0x0668,
+ [0x0039] = 0x0669,
+ },
+ { -- persian
+ [0x0030] = 0x06F0,
+ [0x0031] = 0x06F1,
+ [0x0032] = 0x06F2,
+ [0x0033] = 0x06F3,
+ [0x0034] = 0x06F4,
+ [0x0035] = 0x06F5,
+ [0x0036] = 0x06F6,
+ [0x0037] = 0x06F7,
+ [0x0038] = 0x06F8,
+ [0x0039] = 0x06F9,
+ },
+ },
+}
+
+local extra_features = { -- maybe just 1..n so that we prescribe order
+ tlig = {
+ {
+ features = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "tlig", comment = "added bij mkiv" }, },
+ name = "ctx_tlig_1",
+ subtables = { { name = "ctx_tlig_1_s" } },
+ type = "gsub_ligature",
+ flags = { },
+ },
+ },
+ trep = {
+ {
+ features = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "trep", comment = "added bij mkiv" }, },
+ name = "ctx_trep_1",
+ subtables = { { name = "ctx_trep_1_s" } },
+ type = "gsub_single",
+ flags = { },
+ },
+ },
+ anum = {
+ {
+ features = { { scripts = { { script = "arab", langs = { "dflt", "FAR" }, } }, tag = "anum", comment = "added bij mkiv" }, },
+ name = "ctx_anum_1",
+ subtables = { { name = "ctx_anum_1_s" } },
+ type = "gsub_single",
+ flags = { },
+ },
+ {
+ features = { { scripts = { { script = "arab", langs = { "URD" }, } }, tag = "anum", comment = "added bij mkiv" }, },
+ name = "ctx_anum_2",
+ subtables = { { name = "ctx_anum_2_s" } },
+ type = "gsub_single",
+ flags = { },
+ },
+ },
+}
+
+fonts.otf.enhancers["add some missing characters"] = function(data,filename)
+ -- todo
+end
+
+fonts.otf.enhancers["enrich with features"] = function(data,filename)
+ -- could be done elsewhere (true can be #)
+ local used = { }
+ for i=1,#otf.glists do
+ local g = data[otf.glists[i]]
+ if g then
+ for i=1,#g do
+ local f = g[i].features
+ if f then
+ for i=1,#f do
+ local t = f[i].tag
+ if t then used[t] = true end
+ end
+ end
+ end
+ end
+ end
+ --
+ local glyphs = data.glyphs
+ local indices = data.map.map
+ data.gsub = data.gsub or { }
+ for kind, specifications in next, extra_features do
+ if not used[kind] then
+ local done = 0
+ for s=1,#specifications do
+ local added = false
+ local specification = specifications[s]
+ local list = extra_lists[kind][s]
+ local name = specification.name .. "_s"
+ if specification.type == "gsub_ligature" then
+ for unicode, index in next, indices do
+ local glyph = glyphs[index]
+ local ligature = list[glyph.name]
+ if ligature then
+ local o = glyph.lookups or { }
+ -- o[name] = { "ligature", ligature, glyph.name }
+ o[name] = {
+ {
+ ["type"] = "ligature",
+ ["specification"] = {
+ char = glyph.name,
+ components = ligature,
+ }
+ }
+ }
+ glyph.lookups, done, added = o, done+1, true
+ end
+ end
+ elseif specification.type == "gsub_single" then
+ for unicode, index in next, indices do
+ local glyph = glyphs[index]
+ local r = list[unicode]
+ if r then
+ local replacement = indices[r]
+ if replacement and glyphs[replacement] then
+ local o = glyph.lookups or { }
+ -- o[name] = { { "substitution", glyphs[replacement].name } }
+ o[name] = {
+ {
+ ["type"] = "substitution",
+ ["specification"] = {
+ variant = glyphs[replacement].name,
+ }
+ }
+ }
+ glyph.lookups, done, added = o, done+1, true
+ end
+ end
+ end
+ end
+ if added then
+ insert(data.gsub,s,table.fastcopy(specification)) -- right order
+ end
+ end
+ if done > 0 then
+ if trace_loading then
+ logs.report("load otf","enhance: registering %s feature (%s glyphs affected)",kind,done)
+ end
+ end
+ end
+ end
+end
+
+otf.tables.features['tlig'] = 'TeX Ligatures'
+otf.tables.features['trep'] = 'TeX Replacements'
+otf.tables.features['anum'] = 'Arabic Digits'
+
+otf.features.register_base_substitution('tlig')
+otf.features.register_base_substitution('trep')
+otf.features.register_base_substitution('anum')
+
+-- the functionality is defined elsewhere
+
+fonts.initializers.base.otf.equaldigits = fonts.initializers.common.equaldigits
+fonts.initializers.node.otf.equaldigits = fonts.initializers.common.equaldigits
+
+fonts.initializers.base.otf.lineheight = fonts.initializers.common.lineheight
+fonts.initializers.node.otf.lineheight = fonts.initializers.common.lineheight
+
+fonts.initializers.base.otf.compose = fonts.initializers.common.compose
+fonts.initializers.node.otf.compose = fonts.initializers.common.compose
diff --git a/tex/context/base/font-otd.lua b/tex/context/base/font-otd.lua
new file mode 100644
index 000000000..41e885331
--- /dev/null
+++ b/tex/context/base/font-otd.lua
@@ -0,0 +1,78 @@
+if not modules then modules = { } end modules ['font-otd'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+
+local otf = fonts.otf
+local fontdata = fonts.ids
+
+otf.features = otf.features or { }
+otf.features.default = otf.features.default or { }
+
+local context_setups = fonts.define.specify.context_setups
+local context_numbers = fonts.define.specify.context_numbers
+
+local a_to_script = { } otf.a_to_script = a_to_script
+local a_to_language = { } otf.a_to_language = a_to_language
+
+function otf.set_dynamics(font,dynamics,attribute)
+ features = context_setups[context_numbers[attribute]] -- can be moved to caller
+ if features then
+ local script = features.script or 'dflt'
+ local language = features.language or 'dflt'
+ local ds = dynamics[script]
+ if not ds then
+ ds = { }
+ dynamics[script] = ds
+ end
+ local dsl = ds[language]
+ if not dsl then
+ dsl = { }
+ ds[language] = dsl
+ end
+ local dsla = dsl[attribute]
+ if dsla then
+ -- if trace_dynamics then
+ -- logs.report("otf define","using dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language)
+ -- end
+ return dsla
+ else
+ local tfmdata = fontdata[font]
+ a_to_script [attribute] = script
+ a_to_language[attribute] = language
+ -- we need to save some values
+ local saved = {
+ script = tfmdata.script,
+ language = tfmdata.language,
+ mode = tfmdata.mode,
+ features = tfmdata.shared.features
+ }
+ tfmdata.mode = "node"
+ tfmdata.language = language
+ tfmdata.script = script
+ tfmdata.shared.features = { }
+ -- end of save
+ dsla = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default))
+ if trace_dynamics then
+ logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language)
+ end
+ -- we need to restore some values
+ tfmdata.script = saved.script
+ tfmdata.language = saved.language
+ tfmdata.mode = saved.mode
+ tfmdata.shared.features = saved.features
+ -- end of restore
+ dynamics[script][language][attribute] = dsla -- cache
+ return dsla
+ end
+ end
+ return nil -- { }
+end
diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua
new file mode 100644
index 000000000..9cecf21f0
--- /dev/null
+++ b/tex/context/base/font-otf.lua
@@ -0,0 +1,1752 @@
+if not modules then modules = { } end modules ['font-otf'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local concat, getn, utfbyte = table.concat, table.getn, utf.byte
+local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+local abs = math.abs
+local lpegmatch = lpeg.match
+
+local trace_private = false trackers.register("otf.private", function(v) trace_private = v end)
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local trace_features = false trackers.register("otf.features", function(v) trace_features = v end)
+local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
+local trace_sequences = false trackers.register("otf.sequences", function(v) trace_sequences = v end)
+local trace_math = false trackers.register("otf.math", function(v) trace_math = v end)
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+--~ trackers.enable("otf.loading")
+
+--[[ldx--
+
The fontforge table has organized lookups in a certain way. A first implementation
+of this code was organized featurewise: information related to features was
+collected and processing boiled down to a run over the features. The current
+implementation honors the order in the main feature table. Since we can reorder this
+table as we want, we can eventually support several models of processing. We kept
+the static as well as dynamic feature processing, because it had proved to be
+rather useful. The formerly three loop variants have beem discarded but will
+reapear at some time.
+
+
+we loop over all lookups
+for each lookup we do a run over the list of glyphs
+but we only process them for features that are enabled
+if we're dealing with a contextual lookup, we loop over all contexts
+in that loop we quit at a match and then process the list of sublookups
+we always continue after the match
+
+
+
In we do this for each font that is used in a list, so in
+practice we have quite some nested loops.
+
+
We process the whole list and then consult the glyph nodes. An alternative approach
+is to collect strings of characters using the same font including spaces (because some
+lookups involve spaces). However, we then need to reconstruct the list which is no fun.
+Also, we need to carry quite some information, like attributes, so eventually we don't
+gain much (if we gain something at all).
+
+
Another consideration has been to operate on sublists (subhead, subtail) but again
+this would complicate matters as we then neext to keep track of a changing subhead
+and subtail. On the other hand, this might save some runtime. The number of changes
+involved is not that large. This only makes sense when we have many fonts in a list
+and don't change to frequently.
+--ldx]]--
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+fonts.tfm = fonts.tfm or { }
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local fontdata = fonts.ids
+
+otf.tables = otf.tables or { } -- defined in font-ott.lua
+otf.meanings = otf.meanings or { } -- defined in font-ott.lua
+otf.tables.features = otf.tables.features or { } -- defined in font-ott.lua
+otf.tables.languages = otf.tables.languages or { } -- defined in font-ott.lua
+otf.tables.scripts = otf.tables.scripts or { } -- defined in font-ott.lua
+
+otf.features = otf.features or { }
+otf.features.list = otf.features.list or { }
+otf.features.default = otf.features.default or { }
+
+otf.enhancers = otf.enhancers or { }
+otf.glists = { "gsub", "gpos" }
+
+otf.version = 2.650 -- beware: also sync font-mis.lua
+otf.pack = true -- beware: also sync font-mis.lua
+otf.syncspace = true
+otf.notdef = false
+otf.cache = containers.define("fonts", "otf", otf.version, true)
+otf.cleanup_aat = false -- only context
+
+local wildcard = "*"
+local default = "dflt"
+
+--[[ldx--
+
We start with a lot of tables and related functions.
+--ldx]]--
+
+local function load_featurefile(ff,featurefile)
+ if featurefile then
+ featurefile = resolvers.find_file(file.addsuffix(featurefile,'fea'),'fea')
+ if featurefile and featurefile ~= "" then
+ if trace_loading then
+ logs.report("load otf", "featurefile: %s", featurefile)
+ end
+ fontloader.apply_featurefile(ff, featurefile)
+ end
+ end
+end
+
+function otf.enhance(name,data,filename,verbose)
+ local enhancer = otf.enhancers[name]
+ if enhancer then
+ if (verbose ~= nil and verbose) or trace_loading then
+ logs.report("load otf","enhance: %s (%s)",name,filename)
+ end
+ enhancer(data,filename)
+ end
+end
+
+local enhancers = {
+ -- pack and unpack are handled separately; they might even be moved
+ -- away from the enhancers namespace
+ "patch bugs",
+ "merge cid fonts", "prepare unicode", "cleanup ttf tables", "compact glyphs", "reverse coverage",
+ "cleanup aat", "enrich with features", "add some missing characters",
+ "reorganize mark classes",
+ "reorganize kerns", -- moved here
+ "flatten glyph lookups", "flatten anchor tables", "flatten feature tables",
+ "simplify glyph lookups", -- some saving
+ "prepare luatex tables",
+ "analyse features", "rehash features",
+ "analyse anchors", "analyse marks", "analyse unicodes", "analyse subtables",
+ "check italic correction","check math",
+ "share widths",
+ "strip not needed data",
+ "migrate metadata",
+ "check math parameters",
+}
+
+function otf.load(filename,format,sub,featurefile)
+ local name = file.basename(file.removesuffix(filename))
+ if featurefile then
+ name = name .. "@" .. file.removesuffix(file.basename(featurefile))
+ end
+ if sub == "" then sub = false end
+ local hash = name
+ if sub then
+ hash = hash .. "-" .. sub
+ end
+ hash = containers.cleanname(hash)
+ local data = containers.read(otf.cache(), hash)
+ local size = lfs.attributes(filename,"size") or 0
+ if not data or data.verbose ~= fonts.verbose or data.size ~= size then
+ logs.report("load otf","loading: %s (hash: %s)",filename,hash)
+ local ff, messages
+ if sub then
+ ff, messages = fontloader.open(filename,sub)
+ else
+ ff, messages = fontloader.open(filename)
+ end
+ if trace_loading and messages and #messages > 0 then
+ if type(messages) == "string" then
+ logs.report("load otf","warning: %s",messages)
+ else
+ for m=1,#messages do
+ logs.report("load otf","warning: %s",tostring(messages[m]))
+ end
+ end
+ else
+ logs.report("load otf","font loaded okay")
+ end
+ if ff then
+ load_featurefile(ff,featurefile)
+ data = fontloader.to_table(ff)
+ fontloader.close(ff)
+ if data then
+ logs.report("load otf","file size: %s", size)
+ logs.report("load otf","enhancing ...")
+ for e=1,#enhancers do
+ otf.enhance(enhancers[e],data,filename)
+ io.flush() -- we want instant messages
+ end
+ if otf.pack and not fonts.verbose then
+ otf.enhance("pack",data,filename)
+ end
+ data.size = size
+ data.verbose = fonts.verbose
+ logs.report("load otf","saving in cache: %s",filename)
+ data = containers.write(otf.cache(), hash, data)
+ collectgarbage("collect")
+ data = containers.read(otf.cache(), hash) -- this frees the old table and load the sparse one
+ collectgarbage("collect")
+ else
+ logs.report("load otf","loading failed (table conversion error)")
+ end
+ else
+ logs.report("load otf","loading failed (file read error)")
+ end
+ end
+ if data then
+ if trace_defining then
+ logs.report("define font","loading from cache: %s",hash)
+ end
+ otf.enhance("unpack",data,filename,false) -- no message here
+ otf.add_dimensions(data)
+ if trace_sequences then
+ otf.show_feature_order(data,filename)
+ end
+ end
+ return data
+end
+
+function otf.add_dimensions(data)
+ -- todo: forget about the width if it's the defaultwidth (saves mem)
+ -- we could also build the marks hash here (instead of storing it)
+ if data then
+ local force = otf.notdef
+ local luatex = data.luatex
+ local defaultwidth = luatex.defaultwidth or 0
+ local defaultheight = luatex.defaultheight or 0
+ local defaultdepth = luatex.defaultdepth or 0
+ for _, d in next, data.glyphs do
+ local bb, wd = d.boundingbox, d.width
+ if not wd then
+ d.width = defaultwidth
+ elseif wd ~= 0 and d.class == "mark" then
+ d.width = -wd
+ end
+ if force and not d.name then
+ d.name = ".notdef"
+ end
+ if bb then
+ local ht, dp = bb[4], -bb[2]
+ if ht == 0 or ht < 0 then
+ -- no need to set it and no negative heights, nil == 0
+ else
+ d.height = ht
+ end
+ if dp == 0 or dp < 0 then
+ -- no negative depths and no negative depths, nil == 0
+ else
+ d.depth = dp
+ end
+ end
+ end
+ end
+end
+
+function otf.show_feature_order(otfdata,filename)
+ local sequences = otfdata.luatex.sequences
+ if sequences and #sequences > 0 then
+ if trace_loading then
+ logs.report("otf check","font %s has %s sequences",filename,#sequences)
+ logs.report("otf check"," ")
+ end
+ for nos=1,#sequences do
+ local sequence = sequences[nos]
+ local typ = sequence.type or "no-type"
+ local name = sequence.name or "no-name"
+ local subtables = sequence.subtables or { "no-subtables" }
+ local features = sequence.features
+ if trace_loading then
+ logs.report("otf check","%3i %-15s %-20s [%s]",nos,name,typ,concat(subtables,","))
+ end
+ if features then
+ for feature, scripts in next, features do
+ local tt = { }
+ for script, languages in next, scripts do
+ local ttt = { }
+ for language, _ in next, languages do
+ ttt[#ttt+1] = language
+ end
+ tt[#tt+1] = format("[%s: %s]",script,concat(ttt," "))
+ end
+ if trace_loading then
+ logs.report("otf check"," %s: %s",feature,concat(tt," "))
+ end
+ end
+ end
+ end
+ if trace_loading then
+ logs.report("otf check","\n")
+ end
+ elseif trace_loading then
+ logs.report("otf check","font %s has no sequences",filename)
+ end
+end
+
+-- todo: normalize, design_size => designsize
+
+otf.enhancers["reorganize mark classes"] = function(data,filename)
+ if data.mark_classes then
+ local unicodes = data.luatex.unicodes
+ local reverse = { }
+ for name, class in next, data.mark_classes do
+ local t = { }
+ for s in gmatch(class,"[^ ]+") do
+ local us = unicodes[s]
+ if type(us) == "table" then
+ for u=1,#us do
+ t[us[u]] = true
+ end
+ else
+ t[us] = true
+ end
+ end
+ reverse[name] = t
+ end
+ data.luatex.markclasses = reverse
+ data.mark_classes = nil
+ end
+end
+
+otf.enhancers["prepare luatex tables"] = function(data,filename)
+ data.luatex = data.luatex or { }
+ local luatex = data.luatex
+ luatex.filename = filename
+ luatex.version = otf.version
+ luatex.creator = "context mkiv"
+end
+
+otf.enhancers["cleanup aat"] = function(data,filename)
+ if otf.cleanup_aat then
+ end
+end
+
+local function analyze_features(g, features)
+ if g then
+ local t, done = { }, { }
+ for k=1,#g do
+ local f = features or g[k].features
+ if f then
+ for k=1,#f do
+ -- scripts and tag
+ local tag = f[k].tag
+ if not done[tag] then
+ t[#t+1] = tag
+ done[tag] = true
+ end
+ end
+ end
+ end
+ if #t > 0 then
+ return t
+ end
+ end
+ return nil
+end
+
+otf.enhancers["analyse features"] = function(data,filename)
+ -- local luatex = data.luatex
+ -- luatex.gposfeatures = analyze_features(data.gpos)
+ -- luatex.gsubfeatures = analyze_features(data.gsub)
+end
+
+otf.enhancers["rehash features"] = function(data,filename)
+ local features = { }
+ data.luatex.features = features
+ for k, what in next, otf.glists do
+ local dw = data[what]
+ if dw then
+ local f = { }
+ features[what] = f
+ for i=1,#dw do
+ local d= dw[i]
+ local dfeatures = d.features
+ if dfeatures then
+ for i=1,#dfeatures do
+ local df = dfeatures[i]
+ local tag = strip(lower(df.tag))
+ local ft = f[tag] if not ft then ft = {} f[tag] = ft end
+ local dscripts = df.scripts
+ for script, languages in next, dscripts do
+ script = strip(lower(script))
+ local fts = ft[script] if not fts then fts = {} ft[script] = fts end
+ for i=1,#languages do
+ fts[strip(lower(languages[i]))] = true
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["analyse anchors"] = function(data,filename)
+ local classes = data.anchor_classes
+ local luatex = data.luatex
+ local anchor_to_lookup, lookup_to_anchor = { }, { }
+ luatex.anchor_to_lookup, luatex.lookup_to_anchor = anchor_to_lookup, lookup_to_anchor
+ if classes then
+ for c=1,#classes do
+ local class = classes[c]
+ local anchor = class.name
+ local lookups = class.lookup
+ if type(lookups) ~= "table" then
+ lookups = { lookups }
+ end
+ local a = anchor_to_lookup[anchor]
+ if not a then a = { } anchor_to_lookup[anchor] = a end
+ for l=1,#lookups do
+ local lookup = lookups[l]
+ local l = lookup_to_anchor[lookup]
+ if not l then l = { } lookup_to_anchor[lookup] = l end
+ l[anchor] = true
+ a[lookup] = true
+ end
+ end
+ end
+end
+
+otf.enhancers["analyse marks"] = function(data,filename)
+ local glyphs = data.glyphs
+ local marks = { }
+ data.luatex.marks = marks
+ for unicode, index in next, data.luatex.indices do
+ local glyph = glyphs[index]
+ if glyph.class == "mark" then
+ marks[unicode] = true
+ end
+ end
+end
+
+otf.enhancers["analyse unicodes"] = fonts.map.add_to_unicode
+
+otf.enhancers["analyse subtables"] = function(data,filename)
+ data.luatex = data.luatex or { }
+ local luatex = data.luatex
+ local sequences = { }
+ local lookups = { }
+ luatex.sequences = sequences
+ luatex.lookups = lookups
+ for _, g in next, { data.gsub, data.gpos } do
+ for k=1,#g do
+ local gk = g[k]
+ local typ = gk.type
+ if typ == "gsub_contextchain" or typ == "gpos_contextchain" then
+ gk.chain = 1
+ elseif typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain" then
+ gk.chain = -1
+ else
+ gk.chain = 0
+ end
+ local features = gk.features
+ if features then
+ sequences[#sequences+1] = gk
+ -- scripts, tag, ismac
+ local t = { }
+ for f=1,#features do
+ local feature = features[f]
+ local hash = { }
+ -- only script and langs matter
+ for s, languages in next, feature.scripts do
+ s = lower(s)
+ local h = hash[s]
+ if not h then h = { } hash[s] = h end
+ for l=1,#languages do
+ h[strip(lower(languages[l]))] = true
+ end
+ end
+ t[feature.tag] = hash
+ end
+ gk.features = t
+ else
+ lookups[gk.name] = gk
+ gk.name = nil
+ end
+ local subtables = gk.subtables
+ if subtables then
+ local t = { }
+ for s=1,#subtables do
+ local subtable = subtables[s]
+ local name = subtable.name
+ t[#t+1] = name
+ end
+ gk.subtables = t
+ end
+ local flags = gk.flags
+ if flags then
+ gk.flags = { -- forcing false packs nicer
+ (flags.ignorecombiningmarks and "mark") or false,
+ (flags.ignoreligatures and "ligature") or false,
+ (flags.ignorebaseglyphs and "base") or false,
+ flags.r2l or false,
+ }
+ if flags.mark_class then
+ gk.markclass = luatex.markclasses[flags.mark_class]
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["merge cid fonts"] = function(data,filename)
+ -- we can also move the names to data.luatex.names which might
+ -- save us some more memory (at the cost of harder tracing)
+ if data.subfonts then
+ if data.glyphs and next(data.glyphs) then
+ logs.report("load otf","replacing existing glyph table due to subfonts")
+ end
+ local cidinfo = data.cidinfo
+ local verbose = fonts.verbose
+ if cidinfo.registry then
+ local cidmap, cidname = fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement)
+ if cidmap then
+ cidinfo.usedname = cidmap.usedname
+ local glyphs, uni_to_int, int_to_uni, nofnames, nofunicodes = { }, { }, { }, 0, 0
+ local unicodes, names = cidmap.unicodes, cidmap.names
+ for n, subfont in next, data.subfonts do
+ for index, g in next, subfont.glyphs do
+ if not next(g) then
+ -- dummy entry
+ else
+ local unicode, name = unicodes[index], names[index]
+ g.cidindex = n
+ g.boundingbox = g.boundingbox -- or zerobox
+ g.name = g.name or name or "unknown"
+ if unicode then
+ uni_to_int[unicode] = index
+ int_to_uni[index] = unicode
+ nofunicodes = nofunicodes + 1
+ g.unicode = unicode
+ elseif name then
+ nofnames = nofnames + 1
+ g.unicode = -1
+ end
+ glyphs[index] = g
+ end
+ end
+ subfont.glyphs = nil
+ end
+ if trace_loading then
+ logs.report("load otf","cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes, nofnames, nofunicodes+nofnames)
+ end
+ data.glyphs = glyphs
+ data.map = data.map or { }
+ data.map.map = uni_to_int
+ data.map.backmap = int_to_uni
+ elseif trace_loading then
+ logs.report("load otf","unable to remap cid font, missing cid file for %s",filename)
+ end
+ elseif trace_loading then
+ logs.report("load otf","font %s has no glyphs",filename)
+ end
+ end
+end
+
+otf.enhancers["prepare unicode"] = function(data,filename)
+ local luatex = data.luatex
+ if not luatex then luatex = { } data.luatex = luatex end
+ local indices, unicodes, multiples, internals = { }, { }, { }, { }
+ local glyphs = data.glyphs
+ local mapmap = data.map
+ if not mapmap then
+ logs.report("load otf","no map in %s",filename)
+ mapmap = { }
+ data.map = { map = mapmap }
+ elseif not mapmap.map then
+ logs.report("load otf","no unicode map in %s",filename)
+ mapmap = { }
+ data.map.map = mapmap
+ else
+ mapmap = mapmap.map
+ end
+ local criterium = fonts.private
+ local private = fonts.private
+ for index, glyph in next, glyphs do
+ if index > 0 then
+ local name = glyph.name
+ if name then
+ local unicode = glyph.unicode
+ if unicode == -1 or unicode >= criterium then
+ glyph.unicode = private
+ indices[private] = index
+ unicodes[name] = private
+ internals[index] = true
+ if trace_private then
+ logs.report("load otf","enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private)
+ end
+ private = private + 1
+ else
+ indices[unicode] = index
+ unicodes[name] = unicode
+ end
+ end
+ end
+ end
+ -- beware: the indices table is used to initialize the tfm table
+ for unicode, index in next, mapmap do
+ if not internals[index] then
+ local name = glyphs[index].name
+ if name then
+ local un = unicodes[name]
+ if not un then
+ unicodes[name] = unicode -- or 0
+ elseif type(un) == "number" then
+ if un ~= unicode then
+ multiples[#multiples+1] = name
+ unicodes[name] = { un, unicode }
+ indices[unicode] = index
+ end
+ else
+ local ok = false
+ for u=1,#un do
+ if un[u] == unicode then
+ ok = true
+ break
+ end
+ end
+ if not ok then
+ multiples[#multiples+1] = name
+ un[#un+1] = unicode
+ indices[unicode] = index
+ end
+ end
+ end
+ end
+ end
+ if trace_loading then
+ if #multiples > 0 then
+ logs.report("load otf","%s glyph are reused: %s",#multiples, concat(multiples," "))
+ else
+ logs.report("load otf","no glyph are reused")
+ end
+ end
+ luatex.indices = indices
+ luatex.unicodes = unicodes
+ luatex.private = private
+end
+
+otf.enhancers["cleanup ttf tables"] = function(data,filename)
+ local ttf_tables = data.ttf_tables
+ if ttf_tables then
+ for k=1,#ttf_tables do
+ if ttf_tables[k].data then ttf_tables[k].data = "deleted" end
+ end
+ end
+ data.ttf_tab_saved = nil
+end
+
+otf.enhancers["compact glyphs"] = function(data,filename)
+ table.compact(data.glyphs) -- needed?
+ if data.subfonts then
+ for _, subfont in next, data.subfonts do
+ table.compact(subfont.glyphs) -- needed?
+ end
+ end
+end
+
+otf.enhancers["reverse coverage"] = function(data,filename)
+ -- we prefer the before lookups in a normal order
+ if data.lookups then
+ for _, v in next, data.lookups do
+ if v.rules then
+ for _, vv in next, v.rules do
+ local c = vv.coverage
+ if c and c.before then
+ c.before = table.reverse(c.before)
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["check italic correction"] = function(data,filename)
+ local glyphs = data.glyphs
+ local ok = false
+ for index, glyph in next, glyphs do
+ local ic = glyph.italic_correction
+ if ic then
+ if ic ~= 0 then
+ glyph.italic = ic
+ end
+ glyph.italic_correction = nil
+ ok = true
+ end
+ end
+ -- we can use this to avoid calculations
+ otf.tables.valid_fields[#otf.tables.valid_fields+1] = "has_italic"
+ data.has_italic = true
+end
+
+otf.enhancers["check math"] = function(data,filename)
+ if data.math then
+ -- we move the math stuff into a math subtable because we then can
+ -- test faster in the tfm copy
+ local glyphs = data.glyphs
+ local unicodes = data.luatex.unicodes
+ for index, glyph in next, glyphs do
+ local mk = glyph.mathkern
+ local hv = glyph.horiz_variants
+ local vv = glyph.vert_variants
+ if mk or hv or vv then
+ local math = { }
+ glyph.math = math
+ if mk then
+ for k, v in next, mk do
+ if not next(v) then
+ mk[k] = nil
+ end
+ end
+ math.kerns = mk
+ glyph.mathkern = nil
+ end
+ if hv then
+ math.horiz_variants = hv.variants
+ local p = hv.parts
+ if p then
+ if #p>0 then
+ for i=1,#p do
+ local pi = p[i]
+ pi.glyph = unicodes[pi.component] or 0
+ end
+ math.horiz_parts = p
+ end
+ end
+ local ic = hv.italic_correction
+ if ic and ic ~= 0 then
+ math.horiz_italic_correction = ic
+ end
+ glyph.horiz_variants = nil
+ end
+ if vv then
+ local uc = unicodes[index]
+ math.vert_variants = vv.variants
+ local p = vv.parts
+ if p then
+ if #p>0 then
+ for i=1,#p do
+ local pi = p[i]
+ pi.glyph = unicodes[pi.component] or 0
+ end
+ math.vert_parts = p
+ end
+ end
+ local ic = vv.italic_correction
+ if ic and ic ~= 0 then
+ math.vert_italic_correction = ic
+ end
+ glyph.vert_variants = nil
+ end
+ local ic = glyph.italic_correction
+ if ic then
+ if ic ~= 0 then
+ math.italic_correction = ic
+ end
+ glyph.italic_correction = nil
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["share widths"] = function(data,filename)
+ local glyphs = data.glyphs
+ local widths = { }
+ for index, glyph in next, glyphs do
+ local width = glyph.width
+ widths[width] = (widths[width] or 0) + 1
+ end
+ -- share width for cjk fonts
+ local wd, most = 0, 1
+ for k,v in next, widths do
+ if v > most then
+ wd, most = k, v
+ end
+ end
+ if most > 1000 then
+ if trace_loading then
+ logs.report("load otf", "most common width: %s (%s times), sharing (cjk font)",wd,most)
+ end
+ for k, v in next, glyphs do
+ if v.width == wd then
+ v.width = nil
+ end
+ end
+ data.luatex.defaultwidth = wd
+ end
+end
+
+-- kern: ttf has a table with kerns
+
+--~ otf.enhancers["reorganize kerns"] = function(data,filename)
+--~ local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
+--~ local mkdone = false
+--~ for index, glyph in next, data.glyphs do
+--~ if glyph.kerns then
+--~ local mykerns = { }
+--~ for k,v in next, glyph.kerns do
+--~ local vc, vo, vl = v.char, v.off, v.lookup
+--~ if vc and vo and vl then -- brrr, wrong! we miss the non unicode ones
+--~ local uvc = unicodes[vc]
+--~ if not uvc then
+--~ if trace_loading then
+--~ logs.report("load otf","problems with unicode %s of kern %s at glyph %s",vc,k,index)
+--~ end
+--~ else
+--~ if type(vl) ~= "table" then
+--~ vl = { vl }
+--~ end
+--~ for l=1,#vl do
+--~ local vll = vl[l]
+--~ local mkl = mykerns[vll]
+--~ if not mkl then
+--~ mkl = { }
+--~ mykerns[vll] = mkl
+--~ end
+--~ if type(uvc) == "table" then
+--~ for u=1,#uvc do
+--~ mkl[uvc[u]] = vo
+--~ end
+--~ else
+--~ mkl[uvc] = vo
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~ glyph.mykerns = mykerns
+--~ glyph.kerns = nil -- saves space and time
+--~ mkdone = true
+--~ end
+--~ end
+--~ if trace_loading and mkdone then
+--~ logs.report("load otf", "replacing 'kerns' tables by 'mykerns' tables")
+--~ end
+--~ if data.kerns then
+--~ if trace_loading then
+--~ logs.report("load otf", "removing global 'kern' table")
+--~ end
+--~ data.kerns = nil
+--~ end
+--~ local dgpos = data.gpos
+--~ if dgpos then
+--~ for gp=1,#dgpos do
+--~ local gpos = dgpos[gp]
+--~ local subtables = gpos.subtables
+--~ if subtables then
+--~ for s=1,#subtables do
+--~ local subtable = subtables[s]
+--~ local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes
+--~ if kernclass then -- the next one is quite slow
+--~ for k=1,#kernclass do
+--~ local kcl = kernclass[k]
+--~ local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
+--~ if type(lookups) ~= "table" then
+--~ lookups = { lookups }
+--~ end
+--~ for l=1,#lookups do
+--~ local lookup = lookups[l]
+--~ -- weird, as maxfirst and maxseconds can have holes
+--~ local maxfirsts, maxseconds = getn(firsts), getn(seconds)
+--~ if trace_loading then
+--~ logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds)
+--~ end
+--~ for fk, fv in next, firsts do
+--~ for first in gmatch(fv,"[^ ]+") do
+--~ local first_unicode = unicodes[first]
+--~ if type(first_unicode) == "number" then
+--~ first_unicode = { first_unicode }
+--~ end
+--~ for f=1,#first_unicode do
+--~ local glyph = glyphs[mapmap[first_unicode[f]]]
+--~ if glyph then
+--~ local mykerns = glyph.mykerns
+--~ if not mykerns then
+--~ mykerns = { } -- unicode indexed !
+--~ glyph.mykerns = mykerns
+--~ end
+--~ local lookupkerns = mykerns[lookup]
+--~ if not lookupkerns then
+--~ lookupkerns = { }
+--~ mykerns[lookup] = lookupkerns
+--~ end
+--~ for sk, sv in next, seconds do
+--~ local offset = offsets[(fk-1) * maxseconds + sk]
+--~ --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
+--~ for second in gmatch(sv,"[^ ]+") do
+--~ local second_unicode = unicodes[second]
+--~ if type(second_unicode) == "number" then
+--~ lookupkerns[second_unicode] = offset
+--~ else
+--~ for s=1,#second_unicode do
+--~ lookupkerns[second_unicode[s]] = offset
+--~ end
+--~ end
+--~ end
+--~ end
+--~ elseif trace_loading then
+--~ logs.report("load otf", "no glyph data for U+%04X", first_unicode[f])
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~ subtable.comment = "The kernclass table is merged into mykerns in the indexed glyph tables."
+--~ subtable.kernclass = { }
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+
+otf.enhancers["reorganize kerns"] = function(data,filename)
+ local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
+ local mkdone = false
+ for index, glyph in next, data.glyphs do
+ if glyph.kerns then
+ local mykerns = { }
+ for k,v in next, glyph.kerns do
+ local vc, vo, vl = v.char, v.off, v.lookup
+ if vc and vo and vl then -- brrr, wrong! we miss the non unicode ones
+ local uvc = unicodes[vc]
+ if not uvc then
+ if trace_loading then
+ logs.report("load otf","problems with unicode %s of kern %s at glyph %s",vc,k,index)
+ end
+ else
+ if type(vl) ~= "table" then
+ vl = { vl }
+ end
+ for l=1,#vl do
+ local vll = vl[l]
+ local mkl = mykerns[vll]
+ if not mkl then
+ mkl = { }
+ mykerns[vll] = mkl
+ end
+ if type(uvc) == "table" then
+ for u=1,#uvc do
+ mkl[uvc[u]] = vo
+ end
+ else
+ mkl[uvc] = vo
+ end
+ end
+ end
+ end
+ end
+ glyph.mykerns = mykerns
+ glyph.kerns = nil -- saves space and time
+ mkdone = true
+ end
+ end
+ if trace_loading and mkdone then
+ logs.report("load otf", "replacing 'kerns' tables by 'mykerns' tables")
+ end
+ if data.kerns then
+ if trace_loading then
+ logs.report("load otf", "removing global 'kern' table")
+ end
+ data.kerns = nil
+ end
+ local dgpos = data.gpos
+ if dgpos then
+ local separator = lpeg.P(" ")
+ local other = ((1 - separator)^0) / unicodes
+ local splitter = lpeg.Ct(other * (separator * other)^0)
+ for gp=1,#dgpos do
+ local gpos = dgpos[gp]
+ local subtables = gpos.subtables
+ if subtables then
+ for s=1,#subtables do
+ local subtable = subtables[s]
+ local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes
+ if kernclass then -- the next one is quite slow
+ for k=1,#kernclass do
+ local kcl = kernclass[k]
+ local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
+ if type(lookups) ~= "table" then
+ lookups = { lookups }
+ end
+ local split = { }
+ for l=1,#lookups do
+ local lookup = lookups[l]
+ -- weird, as maxfirst and maxseconds can have holes, first seems to be indexed, seconds starts at 2
+ local maxfirsts, maxseconds = getn(firsts), getn(seconds)
+ for _, s in next, firsts do
+ split[s] = split[s] or lpegmatch(splitter,s)
+ end
+ for _, s in next, seconds do
+ split[s] = split[s] or lpegmatch(splitter,s)
+ end
+ if trace_loading then
+ logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds)
+ end
+ local function do_it(fk,first_unicode)
+ local glyph = glyphs[mapmap[first_unicode]]
+ if glyph then
+ local mykerns = glyph.mykerns
+ if not mykerns then
+ mykerns = { } -- unicode indexed !
+ glyph.mykerns = mykerns
+ end
+ local lookupkerns = mykerns[lookup]
+ if not lookupkerns then
+ lookupkerns = { }
+ mykerns[lookup] = lookupkerns
+ end
+ local baseoffset = (fk-1) * maxseconds
+ for sk=2,maxseconds do
+ local sv = seconds[sk]
+ local offset = offsets[baseoffset + sk]
+ --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
+ local splt = split[sv]
+ if splt then
+ for i=1,#splt do
+ local second_unicode = splt[i]
+ if tonumber(second_unicode) then
+ lookupkerns[second_unicode] = offset
+ else
+ for s=1,#second_unicode do
+ lookupkerns[second_unicode[s]] = offset
+ end
+ end
+ end
+ end
+ end
+ elseif trace_loading then
+ logs.report("load otf", "no glyph data for U+%04X", first_unicode)
+ end
+ end
+ for fk=1,#firsts do
+ local fv = firsts[fk]
+ local splt = split[fv]
+ if splt then
+ for i=1,#splt do
+ local first_unicode = splt[i]
+ if tonumber(first_unicode) then
+ do_it(fk,first_unicode)
+ else
+ for f=1,#first_unicode do
+ do_it(fk,first_unicode[f])
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ subtable.comment = "The kernclass table is merged into mykerns in the indexed glyph tables."
+ subtable.kernclass = { }
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["strip not needed data"] = function(data,filename)
+ local verbose = fonts.verbose
+ local int_to_uni = data.luatex.unicodes
+ for k, v in next, data.glyphs do
+ local d = v.dependents
+ if d then v.dependents = nil end
+ local a = v.altuni
+ if a then v.altuni = nil end
+ if verbose then
+ local code = int_to_uni[k]
+ -- looks like this is done twice ... bug?
+ if code then
+ local vu = v.unicode
+ if not vu then
+ v.unicode = code
+ elseif type(vu) == "table" then
+ if vu[#vu] == code then
+ -- weird
+ else
+ vu[#vu+1] = code
+ end
+ elseif vu ~= code then
+ v.unicode = { vu, code }
+ end
+ end
+ else
+ v.unicode = nil
+ v.index = nil
+ end
+ end
+ data.luatex.comment = "Glyph tables have their original index. When present, mykern tables are indexed by unicode."
+ data.map = nil
+ data.names = nil -- funny names for editors
+ data.glyphcnt = nil
+ data.glyphmax = nil
+ if true then
+ data.gpos = nil
+ data.gsub = nil
+ data.anchor_classes = nil
+ end
+end
+
+otf.enhancers["migrate metadata"] = function(data,filename)
+ local global_fields = otf.tables.global_fields
+ local metadata = { }
+ for k,v in next, data do
+ if not global_fields[k] then
+ metadata[k] = v
+ data[k] = nil
+ end
+ end
+ data.metadata = metadata
+ -- goodies
+ local pfminfo = data.pfminfo
+ metadata.isfixedpitch = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose["proportion"] == "Monospaced")
+ metadata.charwidth = pfminfo and pfminfo.avgwidth
+end
+
+local private_math_parameters = {
+ "FractionDelimiterSize",
+ "FractionDelimiterDisplayStyleSize",
+}
+
+otf.enhancers["check math parameters"] = function(data,filename)
+ local mathdata = data.metadata.math
+ if mathdata then
+ for m=1,#private_math_parameters do
+ local pmp = private_math_parameters[m]
+ if not mathdata[pmp] then
+ if trace_loading then
+ logs.report("load otf", "setting math parameter '%s' to 0", pmp)
+ end
+ mathdata[pmp] = 0
+ end
+ end
+ end
+end
+
+otf.enhancers["flatten glyph lookups"] = function(data,filename)
+ for k, v in next, data.glyphs do
+ local lookups = v.lookups
+ if lookups then
+ for kk, vv in next, lookups do
+ for kkk=1,#vv do
+ local vvv = vv[kkk]
+ local s = vvv.specification
+ if s then
+ local t = vvv.type
+ if t == "ligature" then
+ vv[kkk] = { "ligature", s.components, s.char }
+ elseif t == "alternate" then
+ vv[kkk] = { "alternate", s.components }
+ elseif t == "substitution" then
+ vv[kkk] = { "substitution", s.variant }
+ elseif t == "multiple" then
+ vv[kkk] = { "multiple", s.components }
+ elseif t == "position" then
+ vv[kkk] = { "position", { s.x or 0, s.y or 0, s.h or 0, s.v or 0 } }
+ elseif t == "pair" then
+ local one, two, paired = s.offsets[1], s.offsets[2], s.paired or ""
+ if one then
+ if two then
+ vv[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0 } }
+ else
+ vv[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 } }
+ end
+ else
+ if two then
+ vv[kkk] = { "pair", paired, { }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0} } -- maybe nil instead of { }
+ else
+ vv[kkk] = { "pair", paired }
+ end
+ end
+ else
+ if trace_loading then
+ logs.report("load otf", "flattening needed, report to context list")
+ end
+ for a, b in next, s do
+ if trace_loading and vvv[a] then
+ logs.report("load otf", "flattening conflict, report to context list")
+ end
+ vvv[a] = b
+ end
+ vvv.specification = nil
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["simplify glyph lookups"] = function(data,filename)
+ for k, v in next, data.glyphs do
+ local lookups = v.lookups
+ if lookups then
+ local slookups, mlookups
+ for kk, vv in next, lookups do
+ if #vv == 1 then
+ if not slookups then
+ slookups = { }
+ v.slookups = slookups
+ end
+ slookups[kk] = vv[1]
+ else
+ if not mlookups then
+ mlookups = { }
+ v.mlookups = mlookups
+ end
+ mlookups[kk] = vv
+ end
+ end
+ v.lookups = nil
+ end
+ end
+end
+
+otf.enhancers["flatten anchor tables"] = function(data,filename)
+ for k, v in next, data.glyphs do
+ if v.anchors then
+ for kk, vv in next, v.anchors do
+ for kkk, vvv in next, vv do
+ if vvv.x or vvv.y then
+ vv[kkk] = { vvv.x or 0, vvv.y or 0 }
+ else
+ for kkkk=1,#vvv do
+ local vvvv = vvv[kkkk]
+ vvv[kkkk] = { vvvv.x or 0, vvvv.y or 0 }
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["flatten feature tables"] = function(data,filename)
+ -- is this needed? do we still use them at all?
+ for _, tag in next, otf.glists do
+ if data[tag] then
+ if trace_loading then
+ logs.report("load otf", "flattening %s table", tag)
+ end
+ for k, v in next, data[tag] do
+ local features = v.features
+ if features then
+ for kk=1,#features do
+ local vv = features[kk]
+ local t = { }
+ local scripts = vv.scripts
+ for kkk=1,#scripts do
+ local vvv = scripts[kkk]
+ t[vvv.script] = vvv.langs
+ end
+ vv.scripts = t
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers.patches = otf.enhancers.patches or { }
+
+otf.enhancers["patch bugs"] = function(data,filename)
+ local basename = file.basename(lower(filename))
+ for pattern, action in next, otf.enhancers.patches do
+ if find(basename,pattern) then
+ action(data,filename)
+ end
+ end
+end
+
+-- tex features
+
+fonts.otf.enhancers["enrich with features"] = function(data,filename)
+ -- later, ctx only
+end
+
+function otf.features.register(name,default)
+ otf.features.list[#otf.features.list+1] = name
+ otf.features.default[name] = default
+end
+
+-- for context this will become a task handler
+
+function otf.set_features(tfmdata,features)
+ local processes = { }
+ if features and next(features) then
+ local lists = { -- why local
+ fonts.triggers,
+ fonts.processors,
+ fonts.manipulators,
+ }
+ local mode = tfmdata.mode or fonts.mode -- or features.mode
+ local initializers = fonts.initializers
+ local fi = initializers[mode]
+ if fi then
+ local fiotf = fi.otf
+ if fiotf then
+ local done = { }
+ for l=1,4 do
+ local list = lists[l]
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ local value = features[f]
+ if value and fiotf[f] then -- brr
+ if not done[f] then -- so, we can move some to triggers
+ if trace_features then
+ logs.report("define otf","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown', tfmdata.fullname or 'unknown')
+ end
+ fiotf[f](tfmdata,value) -- can set mode (no need to pass otf)
+ mode = tfmdata.mode or fonts.mode -- keep this, mode can be set local !
+ local im = initializers[mode]
+ if im then
+ fiotf = initializers[mode].otf
+ end
+ done[f] = true
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ local fm = fonts.methods[mode] -- todo: zonder node/mode otf/...
+ if fm then
+ local fmotf = fm.otf
+ if fmotf then
+ for l=1,4 do
+ local list = lists[l]
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ if fmotf[f] then -- brr
+ if trace_features then
+ logs.report("define otf","installing feature handler %s for mode %s for font %s",f,mode or 'unknown', tfmdata.fullname or 'unknown')
+ end
+ processes[#processes+1] = fmotf[f]
+ end
+ end
+ end
+ end
+ end
+ else
+ -- message
+ end
+ end
+ return processes, features
+end
+
+function otf.otf_to_tfm(specification)
+ local name = specification.name
+ local sub = specification.sub
+ local filename = specification.filename
+ local format = specification.format
+ local features = specification.features.normal
+ local cache_id = specification.hash
+ local tfmdata = containers.read(tfm.cache(),cache_id)
+--~ print(cache_id)
+ if not tfmdata then
+ local otfdata = otf.load(filename,format,sub,features and features.featurefile)
+ if otfdata and next(otfdata) then
+ otfdata.shared = otfdata.shared or {
+ featuredata = { },
+ anchorhash = { },
+ initialized = false,
+ }
+ tfmdata = otf.copy_to_tfm(otfdata,cache_id)
+ if tfmdata and next(tfmdata) then
+ tfmdata.unique = tfmdata.unique or { }
+ tfmdata.shared = tfmdata.shared or { } -- combine
+ local shared = tfmdata.shared
+ shared.otfdata = otfdata
+ shared.features = features -- default
+ shared.dynamics = { }
+ shared.processes = { }
+ shared.set_dynamics = otf.set_dynamics -- fast access and makes other modules independent
+ -- this will be done later anyway, but it's convenient to have
+ -- them already for fast access
+ tfmdata.luatex = otfdata.luatex
+ tfmdata.indices = otfdata.luatex.indices
+ tfmdata.unicodes = otfdata.luatex.unicodes
+ tfmdata.marks = otfdata.luatex.marks
+ tfmdata.originals = otfdata.luatex.originals
+ tfmdata.changed = { }
+ tfmdata.has_italic = otfdata.metadata.has_italic
+ if not tfmdata.language then tfmdata.language = 'dflt' end
+ if not tfmdata.script then tfmdata.script = 'dflt' end
+ shared.processes, shared.features = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default))
+ end
+ end
+ containers.write(tfm.cache(),cache_id,tfmdata)
+ end
+ return tfmdata
+end
+
+--~ {
+--~ ['boundingbox']={ 95, -458, 733, 1449 },
+--~ ['class']="base",
+--~ ['name']="braceleft",
+--~ ['unicode']=123,
+--~ ['vert_variants']={
+--~ ['italic_correction']=0,
+--~ ['parts']={
+--~ { ['component']="uni23A9", ['endConnectorLength']=1000, ['fullAdvance']=2546, ['is_extender']=0, ['startConnectorLength']=0, }, -- bot
+--~ { ['component']="uni23AA", ['endConnectorLength']=2500, ['fullAdvance']=2501, ['is_extender']=1, ['startConnectorLength']=2500, }, -- rep
+--~ { ['component']="uni23A8", ['endConnectorLength']=1000, ['fullAdvance']=4688, ['is_extender']=0, ['startConnectorLength']=1000, }, -- mid
+--~ { ['component']="uni23AA", ['endConnectorLength']=2500, ['fullAdvance']=2501, ['is_extender']=1, ['startConnectorLength']=2500, }, -- rep
+--~ { ['component']="uni23A7", ['endConnectorLength']=0, ['fullAdvance']=2546, ['is_extender']=0, ['startConnectorLength']=1000, }, -- top
+--~ },
+--~ ['variants']="braceleft braceleft.vsize1 braceleft.vsize2 braceleft.vsize3 braceleft.vsize4 braceleft.vsize5 braceleft.vsize6 braceleft.vsize7",
+--~ },
+--~ ['width']=793,
+--~ },
+
+-- the first version made a top/mid/not extensible table, now we just pass on the variants data
+-- and deal with it in the tfm scaler (there is no longer an extensible table anyway)
+
+-- we cannot share descriptions as virtual fonts might extend them (ok, we could
+-- use a cache with a hash
+
+fonts.formats.dfont = "truetype"
+fonts.formats.ttc = "truetype"
+fonts.formats.ttf = "truetype"
+fonts.formats.otf = "opentype"
+
+function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder the tma to unicode (nasty due to one->many)
+ if data then
+ local glyphs, pfminfo, metadata = data.glyphs or { }, data.pfminfo or { }, data.metadata or { }
+ local luatex = data.luatex
+ local unicodes = luatex.unicodes -- names to unicodes
+ local indices = luatex.indices
+ local characters, parameters, math_parameters, descriptions = { }, { }, { }, { }
+ local designsize = metadata.designsize or metadata.design_size or 100
+ if designsize == 0 then
+ designsize = 100
+ end
+ local spaceunits = 500
+ -- indices maps from unicodes to indices
+ for u, i in next, indices do
+ characters[u] = { } -- we need this because for instance we add protruding info and loop over characters
+ descriptions[u] = glyphs[i]
+ end
+ -- math
+ if metadata.math then
+ -- parameters
+ for name, value in next, metadata.math do
+ math_parameters[name] = value
+ end
+ -- we could use a subset
+ for u, char in next, characters do
+ local d = descriptions[u]
+ local m = d.math
+ -- we have them shared because that packs nicer
+ -- we could prepare the variants and keep 'm in descriptions
+ if m then
+ local variants = m.horiz_variants
+ if variants then
+ local c = char
+ for n in gmatch(variants,"[^ ]+") do
+ local un = unicodes[n]
+ if un and u ~= un then
+ c.next = un
+ c = characters[un]
+ end
+ end
+ c.horiz_variants = m.horiz_parts
+ else
+ local variants = m.vert_variants
+ if variants then
+ local c = char
+ for n in gmatch(variants,"[^ ]+") do
+ local un = unicodes[n]
+ if un and u ~= un then
+ c.next = un
+ c = characters[un]
+ end
+ end
+ c.vert_variants = m.vert_parts
+ c.vert_italic_correction = m.vert_italic_correction
+ end
+ end
+ local kerns = m.kerns
+ if kerns then
+ char.mathkerns = kerns
+ end
+ end
+ end
+ end
+ -- end math
+ local endash, emdash, space = 0x20, 0x2014, "space" -- unicodes['space'], unicodes['emdash']
+ if metadata.isfixedpitch then
+ if descriptions[endash] then
+ spaceunits, spacer = descriptions[endash].width, "space"
+ end
+ if not spaceunits and descriptions[emdash] then
+ spaceunits, spacer = descriptions[emdash].width, "emdash"
+ end
+ if not spaceunits and metadata.charwidth then
+ spaceunits, spacer = metadata.charwidth, "charwidth"
+ end
+ else
+ if descriptions[endash] then
+ spaceunits, spacer = descriptions[endash].width, "space"
+ end
+ if not spaceunits and descriptions[emdash] then
+ spaceunits, spacer = descriptions[emdash].width/2, "emdash/2"
+ end
+ if not spaceunits and metadata.charwidth then
+ spaceunits, spacer = metadata.charwidth, "charwidth"
+ end
+ end
+ spaceunits = tonumber(spaceunits) or tfm.units/2 -- 500 -- brrr
+ -- we need a runtime lookup because of running from cdrom or zip, brrr (shouldn't we use the basename then?)
+ local filename = fonts.tfm.checked_filename(luatex)
+ local fontname = metadata.fontname
+ local fullname = metadata.fullname or fontname
+ local cidinfo = data.cidinfo
+ local units = metadata.units_per_em or 1000
+ --
+ cidinfo.registry = cidinfo and cidinfo.registry or "" -- weird here, fix upstream
+ --
+ parameters.slant = 0
+ parameters.space = spaceunits -- 3.333 (cmr10)
+ parameters.space_stretch = units/2 -- 500 -- 1.666 (cmr10)
+ parameters.space_shrink = 1*units/3 -- 333 -- 1.111 (cmr10)
+ parameters.x_height = 2*units/5 -- 400
+ parameters.quad = units -- 1000
+ if spaceunits < 2*units/5 then
+ -- todo: warning
+ end
+ local italicangle = metadata.italicangle
+ if italicangle then -- maybe also in afm _
+ parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
+ end
+ if metadata.isfixedpitch then
+ parameters.space_stretch = 0
+ parameters.space_shrink = 0
+ elseif otf.syncspace then --
+ parameters.space_stretch = spaceunits/2
+ parameters.space_shrink = spaceunits/3
+ end
+ parameters.extra_space = parameters.space_shrink -- 1.111 (cmr10)
+ if pfminfo.os2_xheight and pfminfo.os2_xheight > 0 then
+ parameters.x_height = pfminfo.os2_xheight
+ else
+ local x = 0x78 -- unicodes['x']
+ if x then
+ local x = descriptions[x]
+ if x then
+ parameters.x_height = x.height
+ end
+ end
+ end
+ --
+ return {
+ characters = characters,
+ parameters = parameters,
+ math_parameters = math_parameters,
+ descriptions = descriptions,
+ indices = indices,
+ unicodes = unicodes,
+ type = "real",
+ direction = 0,
+ boundarychar_label = 0,
+ boundarychar = 65536,
+ designsize = (designsize/10)*65536,
+ spacer = "500 units",
+ encodingbytes = 2,
+ filename = filename,
+ fontname = fontname,
+ fullname = fullname,
+ psname = fontname or fullname,
+ name = filename or fullname,
+ units = units,
+ format = fonts.fontformat(filename,"opentype"),
+ cidinfo = cidinfo,
+ ascender = abs(metadata.ascent or 0),
+ descender = abs(metadata.descent or 0),
+ spacer = spacer,
+ italicangle = italicangle,
+ }
+ else
+ return nil
+ end
+end
+
+otf.features.register('mathsize')
+
+function tfm.read_from_open_type(specification)
+ local tfmtable = otf.otf_to_tfm(specification)
+ if tfmtable then
+ local otfdata = tfmtable.shared.otfdata
+ tfmtable.name = specification.name
+ tfmtable.sub = specification.sub
+ local s = specification.size
+ local m = otfdata.metadata.math
+ if m then
+ -- this will move to a function
+ local f = specification.features
+ if f then
+ local f = f.normal
+ if f and f.mathsize then
+ local mathsize = specification.mathsize or 0
+ if mathsize == 2 then
+ local p = m.ScriptPercentScaleDown
+ if p then
+ local ps = p * specification.textsize / 100
+ if trace_math then
+ logs.report("define font","asked script size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
+ end
+ s = ps
+ end
+ elseif mathsize == 3 then
+ local p = m.ScriptScriptPercentScaleDown
+ if p then
+ local ps = p * specification.textsize / 100
+ if trace_math then
+ logs.report("define font","asked scriptscript size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
+ end
+ s = ps
+ end
+ end
+ end
+ end
+ end
+ tfmtable = tfm.scale(tfmtable,s,specification.relativeid)
+ if tfm.fontname_mode == "specification" then
+ -- not to be used in context !
+ local specname = specification.specification
+ if specname then
+ tfmtable.name = specname
+ if trace_defining then
+ logs.report("define font","overloaded fontname: '%s'",specname)
+ end
+ end
+ end
+ fonts.logger.save(tfmtable,file.extname(specification.filename),specification)
+ end
+--~ print(tfmtable.fullname)
+ return tfmtable
+end
+
+-- helpers
+
+function otf.collect_lookups(otfdata,kind,script,language)
+ -- maybe store this in the font
+ local sequences = otfdata.luatex.sequences
+ if sequences then
+ local featuremap, featurelist = { }, { }
+ for s=1,#sequences do
+ local sequence = sequences[s]
+ local features = sequence.features
+ features = features and features[kind]
+ features = features and (features[script] or features[default] or features[wildcard])
+ features = features and (features[language] or features[default] or features[wildcard])
+ if features then
+ local subtables = sequence.subtables
+ if subtables then
+ for s=1,#subtables do
+ local ss = subtables[s]
+ if not featuremap[s] then
+ featuremap[ss] = true
+ featurelist[#featurelist+1] = ss
+ end
+ end
+ end
+ end
+ end
+ if #featurelist > 0 then
+ return featuremap, featurelist
+ end
+ end
+ return nil, nil
+end
diff --git a/tex/context/base/font-oti.lua b/tex/context/base/font-oti.lua
new file mode 100644
index 000000000..4cb270626
--- /dev/null
+++ b/tex/context/base/font-oti.lua
@@ -0,0 +1,57 @@
+if not modules then modules = { } end modules ['font-oti'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- i need to check features=yes|no also in relation to hashing
+
+local lower = string.lower
+
+local otf = fonts.otf
+
+otf.default_language = 'latn'
+otf.default_script = 'dflt'
+
+local languages = otf.tables.languages
+local scripts = otf.tables.scripts
+
+function otf.features.language(tfmdata,value)
+ if value then
+ value = lower(value)
+ if languages[value] then
+ tfmdata.language = value
+ end
+ end
+end
+
+function otf.features.script(tfmdata,value)
+ if value then
+ value = lower(value)
+ if scripts[value] then
+ tfmdata.script = value
+ end
+ end
+end
+
+function otf.features.mode(tfmdata,value)
+ if value then
+ tfmdata.mode = lower(value)
+ end
+end
+
+fonts.initializers.base.otf.language = otf.features.language
+fonts.initializers.base.otf.script = otf.features.script
+fonts.initializers.base.otf.mode = otf.features.mode
+fonts.initializers.base.otf.method = otf.features.mode
+
+fonts.initializers.node.otf.language = otf.features.language
+fonts.initializers.node.otf.script = otf.features.script
+fonts.initializers.node.otf.mode = otf.features.mode
+fonts.initializers.node.otf.method = otf.features.mode
+
+otf.features.register("features",true) -- we always do features
+table.insert(fonts.processors,"features") -- we need a proper function for doing this
+
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
new file mode 100644
index 000000000..d4f89adc6
--- /dev/null
+++ b/tex/context/base/font-otn.lua
@@ -0,0 +1,2660 @@
+if not modules then modules = { } end modules ['font-otn'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is still somewhat preliminary and it will get better in due time;
+-- much functionality could only be implemented thanks to the husayni font
+-- of Idris Samawi Hamid to who we dedicate this module.
+
+-- I'm in the process of cleaning up the code (which happens in another
+-- file) so don't rely on things staying the same.
+
+-- some day when we can jit this, we can use more functions
+
+-- we can use more lpegs when lpeg is extended with function args and so
+-- resolving to unicode does not gain much
+
+-- in retrospect it always looks easy but believe it or not, it took a lot
+-- of work to get proper open type support done: buggy fonts, fuzzy specs,
+-- special made testfonts, many skype sessions between taco, idris and me,
+-- torture tests etc etc ... unfortunately the code does not show how much
+-- time it took ...
+
+-- todo:
+--
+-- kerning is probably not yet ok for latin around dics nodes
+-- extension infrastructure (for usage out of context)
+-- sorting features according to vendors/renderers
+-- alternative loop quitters
+-- check cursive and r2l
+-- find out where ignore-mark-classes went
+-- remove unused tables
+-- slide tail (always glue at the end so only needed once
+-- default features (per language, script)
+-- cleanup kern(class) code, remove double info
+-- handle positions (we need example fonts)
+-- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere)
+
+--[[ldx--
+
This module is a bit more split up that I'd like but since we also want to test
+with plain it has to be so. This module is part of
+and discussion about improvements and functionality mostly happens on the
+ mailing list.
+
+
The specification of OpenType is kind of vague. Apart from a lack of a proper
+free specifications there's also the problem that Microsoft and Adobe
+may have their own interpretation of how and in what order to apply features.
+In general the Microsoft website has more detailed specifications and is a
+better reference. There is also some information in the FontForge help files.
+
+
Because there is so much possible, fonts might contain bugs and/or be made to
+work with certain rederers. These may evolve over time which may have the side
+effect that suddenly fonts behave differently.
+
+
After a lot of experiments (mostly by Taco, me and Idris) we're now at yet another
+implementation. Of course all errors are mine and of course the code can be
+improved. There are quite some optimizations going on here and processing speed
+is currently acceptable. Not all functions are implemented yet, often because I
+lack the fonts for testing. Many scripts are not yet supported either, but I will
+look into them as soon as users ask for it.
+
+
Because there are different interpretations possible, I will extend the code
+with more (configureable) variants. I can also add hooks for users so that they can
+write their own extensions.
+
+
Glyphs are indexed not by unicode but in their own way. This is because there is no
+relationship with unicode at all, apart from the fact that a font might cover certain
+ranges of characters. One character can have multiple shapes. However, at the
+ end we use unicode so and all extra glyphs are mapped into a private
+space. This is needed because we need to access them and has to include
+then in the output eventually.
+
+
The raw table as it coms from gets reorganized in to fit out needs.
+In that table is packed (similar tables are shared) and cached on disk
+so that successive runs can use the optimized table (after loading the table is
+unpacked). The flattening code used later is a prelude to an even more compact table
+format (and as such it keeps evolving).
+
+
This module is sparsely documented because it is a moving target. The table format
+of the reader changes and we experiment a lot with different methods for supporting
+features.
+
+
As with the code, we may decide to store more information in the
+ table.
+
+
Incrementing the version number will force a re-cache. We jump the number by one
+when there's a fix in the library or code that
+results in different tables.
+--ldx]]--
+
+-- action handler chainproc chainmore comment
+--
+-- gsub_single ok ok ok
+-- gsub_multiple ok ok not implemented yet
+-- gsub_alternate ok ok not implemented yet
+-- gsub_ligature ok ok ok
+-- gsub_context ok --
+-- gsub_contextchain ok --
+-- gsub_reversecontextchain ok --
+-- chainsub -- ok
+-- reversesub -- ok
+-- gpos_mark2base ok ok
+-- gpos_mark2ligature ok ok
+-- gpos_mark2mark ok ok
+-- gpos_cursive ok untested
+-- gpos_single ok ok
+-- gpos_pair ok ok
+-- gpos_context ok --
+-- gpos_contextchain ok --
+--
+-- actions:
+--
+-- handler : actions triggered by lookup
+-- chainproc : actions triggered by contextual lookup
+-- chainmore : multiple substitutions triggered by contextual lookup (e.g. fij -> f + ij)
+--
+-- remark: the 'not implemented yet' variants will be done when we have fonts that use them
+-- remark: we need to check what to do with discretionaries
+
+local concat, insert, remove = table.concat, table.insert, table.remove
+local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+local lpegmatch = lpeg.match
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local trace_lookups = false trackers.register("otf.lookups", function(v) trace_lookups = v end)
+local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false trackers.register("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false trackers.register("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false trackers.register("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_contexts = false trackers.register("otf.contexts", function(v) trace_contexts = v end)
+local trace_marks = false trackers.register("otf.marks", function(v) trace_marks = v end)
+local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
+local trace_cursive = false trackers.register("otf.cursive", function(v) trace_cursive = v end)
+local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
+local trace_bugs = false trackers.register("otf.bugs", function(v) trace_bugs = v end)
+local trace_details = false trackers.register("otf.details", function(v) trace_details = v end)
+local trace_applied = false trackers.register("otf.applied", function(v) trace_applied = v end)
+local trace_steps = false trackers.register("otf.steps", function(v) trace_steps = v end)
+local trace_skips = false trackers.register("otf.skips", function(v) trace_skips = v end)
+local trace_directions = false trackers.register("otf.directions", function(v) trace_directions = v end)
+
+trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)
+trackers.register("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end)
+
+trackers.register("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
+trackers.register("otf.positions","otf.marks,otf.kerns,otf.cursive")
+trackers.register("otf.actions","otf.replacements,otf.positions")
+trackers.register("otf.injections","nodes.injections")
+
+trackers.register("*otf.sample","otf.steps,otf.actions,otf.analyzing")
+
+local insert_node_after = node.insert_after
+local delete_node = nodes.delete
+local copy_node = node.copy
+local find_node_tail = node.tail or node.slide
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+
+local zwnj = 0x200C
+local zwj = 0x200D
+local wildcard = "*"
+local default = "dflt"
+
+local split_at_space = lpeg.splitters[" "] or lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
+
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local kern = node.id('kern')
+local disc = node.id('disc')
+local whatsit = node.id('whatsit')
+
+local state = attributes.private('state')
+local markbase = attributes.private('markbase')
+local markmark = attributes.private('markmark')
+local markdone = attributes.private('markdone')
+local cursbase = attributes.private('cursbase')
+local curscurs = attributes.private('curscurs')
+local cursdone = attributes.private('cursdone')
+local kernpair = attributes.private('kernpair')
+
+local set_mark = nodes.set_mark
+local set_cursive = nodes.set_cursive
+local set_kern = nodes.set_kern
+local set_pair = nodes.set_pair
+
+local markonce = true
+local cursonce = true
+local kernonce = true
+
+local fontdata = fonts.ids
+
+otf.features.process = { }
+
+-- we share some vars here, after all, we have no nested lookups and
+-- less code
+
+local tfmdata = false
+local otfdata = false
+local characters = false
+local descriptions = false
+local marks = false
+local indices = false
+local unicodes = false
+local currentfont = false
+local lookuptable = false
+local anchorlookups = false
+local handlers = { }
+local rlmode = 0
+local featurevalue = false
+
+-- we cheat a bit and assume that a font,attr combination are kind of ranged
+
+local context_setups = fonts.define.specify.context_setups
+local context_numbers = fonts.define.specify.context_numbers
+local context_merged = fonts.define.specify.context_merged
+
+-- we cannot optimize with "start = first_character(head)" because then we don't
+-- know which rlmode we're in which messes up cursive handling later on
+--
+-- head is always a whatsit so we can safely assume that head is not changed
+
+local special_attributes = {
+ init = 1,
+ medi = 2,
+ fina = 3,
+ isol = 4
+}
+
+-- we use this for special testing and documentation
+
+local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
+local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
+local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf direct",...)
+end
+local function logwarning(...)
+ logs.report("otf direct",...)
+end
+
+local function gref(n)
+ if type(n) == "number" then
+ local description = descriptions[n]
+ local name = description and description.name
+ if name then
+ return format("U+%04X (%s)",n,name)
+ else
+ return format("U+%04X",n)
+ end
+ elseif not n then
+ return ""
+ else
+ local num, nam = { }, { }
+ for i=1,#n do
+ local ni = n[i]
+ num[#num+1] = format("U+%04X",ni)
+ local dni = descriptions[ni]
+ nam[#num] = (dni and dni.name) or "?"
+ end
+ return format("%s (%s)",concat(num," "), concat(nam," "))
+ end
+end
+
+local function cref(kind,chainname,chainlookupname,lookupname,index)
+ if index then
+ return format("feature %s, chain %s, sub %s, lookup %s, index %s",kind,chainname,chainlookupname,lookupname,index)
+ elseif lookupname then
+ return format("feature %s, chain %s, sub %s, lookup %s",kind,chainname or "?",chainlookupname or "?",lookupname)
+ elseif chainlookupname then
+ return format("feature %s, chain %s, sub %s",kind,chainname or "?",chainlookupname)
+ elseif chainname then
+ return format("feature %s, chain %s",kind,chainname)
+ else
+ return format("feature %s",kind)
+ end
+end
+
+local function pref(kind,lookupname)
+ return format("feature %s, lookup %s",kind,lookupname)
+end
+
+-- we can assume that languages that use marks are not hyphenated
+-- we can also assume that at most one discretionary is present
+
+local function markstoligature(kind,lookupname,start,stop,char)
+ local n = copy_node(start)
+ local keep = start
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
+ end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, 2, start
+ return keep
+end
+
+local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
+ if start ~= stop then
+--~ if discfound then
+--~ local lignode = copy_node(start)
+--~ lignode.font = start.font
+--~ lignode.char = char
+--~ lignode.subtype = 2
+--~ start = node.do_ligature_n(start, stop, lignode)
+--~ if start.id == disc then
+--~ local prev = start.prev
+--~ start = start.next
+--~ end
+ if discfound then
+ -- print("start->stop",nodes.tosequence(start,stop))
+ local lignode = copy_node(start)
+ lignode.font, lignode.char, lignode.subtype = start.font, char, 2
+ local next, prev = stop.next, start.prev
+ stop.next = nil
+ lignode = node.do_ligature_n(start, stop, lignode)
+ prev.next = lignode
+ if next then
+ next.prev = lignode
+ end
+ lignode.next, lignode.prev = next, prev
+ start = lignode
+ -- print("start->end",nodes.tosequence(start))
+ else -- start is the ligature
+ local deletemarks = markflag ~= "mark"
+ local n = copy_node(start)
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
+ end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, 2, start
+ local head = current
+ if deletemarks then
+ if trace_marks then
+ while start do
+ if marks[start.char] then
+ logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char))
+ end
+ start = start.next
+ end
+ end
+ else
+ local i = 0
+ while start do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ end
+ head, current = insert_node_after(head,current,copy_node(start))
+ else
+ i = i + 1
+ end
+ start = start.next
+ end
+ start = current.next
+ while start and start.id == glyph do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ end
+ else
+ break
+ end
+ start = start.next
+ end
+ end
+ return head
+ end
+ else
+ start.char = char
+ end
+ return start
+end
+
+function handlers.gsub_single(start,kind,lookupname,replacement)
+ if trace_singles then
+ logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement))
+ end
+ start.char = replacement
+ return start, true
+end
+
+local function alternative_glyph(start,alternatives,kind,chainname,chainlookupname,lookupname) -- chainname and chainlookupname optional
+ local value, choice, n = featurevalue or tfmdata.shared.features[kind], nil, #alternatives -- global value, brrr
+ if value == "random" then
+ local r = math.random(1,n)
+ value, choice = format("random, choice %s",r), alternatives[r]
+ elseif value == "first" then
+ value, choice = format("first, choice %s",1), alternatives[1]
+ elseif value == "last" then
+ value, choice = format("last, choice %s",n), alternatives[n]
+ else
+ value = tonumber(value)
+ if type(value) ~= "number" then
+ value, choice = "default, choice 1", alternatives[1]
+ elseif value > n then
+ value, choice = format("no %s variants, taking %s",value,n), alternatives[n]
+ elseif value == 0 then
+ value, choice = format("choice %s (no change)",value), start.char
+ elseif value < 1 then
+ value, choice = format("no %s variants, taking %s",value,1), alternatives[1]
+ else
+ value, choice = format("choice %s",value), alternatives[value]
+ end
+ end
+ if not choice then
+ logwarning("%s: no variant %s for %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(start.char))
+ choice, value = start.char, format("no replacement instead of %s",value)
+ end
+ return choice, value
+end
+
+function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence)
+ local choice, index = alternative_glyph(start,alternative,kind,lookupname)
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %s (%s)",pref(kind,lookupname),gref(start.char),gref(choice),index)
+ end
+ start.char = choice
+ return start, true
+end
+
+function handlers.gsub_multiple(start,kind,lookupname,multiple)
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
+ end
+ start.char = multiple[1]
+ if #multiple > 1 then
+ for k=2,#multiple do
+ local n = copy_node(start)
+ n.char = multiple[k]
+ local sn = start.next
+ n.next = sn
+ n.prev = start
+ if sn then
+ sn.prev = n
+ end
+ start.next = n
+ start = n
+ end
+ end
+ return start, true
+end
+
+function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or maybe pass lookup ref
+ local s, stop, discfound = start.next, nil, false
+ local startchar = start.char
+ if marks[startchar] then
+ while s do
+ local id = s.id
+ if id == glyph and s.subtype<256 then
+ if s.font == currentfont then
+ local char = s.char
+ local lg = ligature[1][char]
+ if not lg then
+ break
+ else
+ stop = s
+ ligature = lg
+ s = s.next
+ end
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ if stop and ligature[2] then
+ if trace_ligatures then
+ local stopchar = stop.char
+ start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ else
+ start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ end
+ return start, true
+ end
+ else
+ local skipmark = sequence.flags[1]
+ while s do
+ local id = s.id
+ if id == glyph and s.subtype<256 then
+ if s.font == currentfont then
+ local char = s.char
+ if skipmark and marks[char] then
+ s = s.next
+ else
+ local lg = ligature[1][char]
+ if not lg then
+ break
+ else
+ stop = s
+ ligature = lg
+ s = s.next
+ end
+ end
+ else
+ break
+ end
+ elseif id == disc then
+ discfound = true
+ s = s.next
+ else
+ break
+ end
+ end
+ if stop and ligature[2] then
+ if trace_ligatures then
+ local stopchar = stop.char
+ start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ else
+ start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ end
+ return start, true
+ end
+ end
+ return start, false
+end
+
+--[[ldx--
+
We get hits on a mark, but we're not sure if the it has to be applied so
+we need to explicitly test for basechar, baselig and basemark entries.
+--ldx]]--
+
+function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
+ local markchar = start.char
+ if marks[markchar] then
+ local base = start.prev -- [glyph] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+ end
+ end
+ end
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ end
+ if baseanchors then
+ local baseanchors = baseanchors['basechar']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
+ pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s, no matching anchors for mark %s and base %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ fonts.register_message(currentfont,basechar,"no base anchors")
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",pref(kind,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
+ -- check chainpos variant
+ local markchar = start.char
+ if marks[markchar] then
+ local base = start.prev -- [glyph] [optional marks] [start=mark]
+ local index = 1
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ else
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+ end
+ end
+ end
+ local i = has_attribute(start,markdone)
+ if i then index = i end
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ if baseanchors then
+ local baseanchors = baseanchors['baselig']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ ba = ba[index]
+ if ba then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ if trace_marks then
+ logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
+ pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and baselig %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ fonts.register_message(currentfont,basechar,"no base anchors")
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",pref(kind,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
+ local markchar = start.char
+ if marks[markchar] then
+--~ local alreadydone = markonce and has_attribute(start,markmark)
+--~ if not alreadydone then
+ local base = start.prev -- [glyph] [basemark] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then -- subtype test can go
+ local basechar = base.char
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ if baseanchors then
+ baseanchors = baseanchors['basemark']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
+ pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start,true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ fonts.register_message(currentfont,basechar,"no base anchors")
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark",pref(kind,lookupname))
+ end
+--~ elseif trace_marks and trace_details then
+--~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone)
+--~ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return start,false
+end
+
+function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to be checked
+ local alreadydone = cursonce and has_attribute(start,cursbase)
+ if not alreadydone then
+ local done = false
+ local startchar = start.char
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
+ end
+ else
+ local nxt = start.next
+ while not done and nxt and nxt.id == glyph and nxt.subtype<256 and nxt.font == currentfont do
+ local nextchar = nxt.char
+ if marks[nextchar] then
+ -- should not happen (maybe warning)
+ nxt = nxt.next
+ else
+ local entryanchors = descriptions[nextchar]
+ if entryanchors then
+ entryanchors = entryanchors.anchors
+ if entryanchors then
+ entryanchors = entryanchors['centry']
+ if entryanchors then
+ local al = anchorlookups[lookupname]
+ for anchor, entry in next, entryanchors do
+ if al[anchor] then
+ local exit = exitanchors[anchor]
+ if exit then
+ local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ if trace_cursive then
+ logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
+ end
+ done = true
+ break
+ end
+ end
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
+ fonts.register_message(currentfont,startchar,"no entry anchors")
+ end
+ break
+ end
+ end
+ end
+ return start, done
+ else
+ if trace_cursive and trace_details then
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ end
+ return start, false
+ end
+end
+
+function handlers.gpos_single(start,kind,lookupname,kerns,sequence)
+ local startchar = start.char
+ local dx, dy, w, h = set_pair(start,tfmdata.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
+ end
+ return start, false
+end
+
+function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
+ -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
+ -- todo: kerns in components of ligatures
+ local snext = start.next
+ if not snext then
+ return start, false
+ else
+ local prev, done = start, false
+ local factor = tfmdata.factor
+ while snext and snext.id == glyph and snext.subtype<256 and snext.font == currentfont do
+ local nextchar = snext.char
+local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = snext.next
+ else
+ local krn = kerns[nextchar]
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if krn[1] == "pair" then
+ local a, b = krn[3], krn[4]
+ if a and #a > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
+ if trace_kerns then
+ logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else
+ logs.report("%s: check this out (old kern stuff)",pref(kind,lookupname))
+ local a, b = krn[3], krn[7]
+ if a and a ~= 0 then
+ local k = set_kern(snext,factor,rlmode,a)
+ if trace_kerns then
+ logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ end
+ end
+ if b and b ~= 0 then
+ logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
+ end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = set_kern(snext,factor,rlmode,krn)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return start, done
+ end
+end
+
+--[[ldx--
+
I will implement multiple chain replacements once I run into a font that uses
+it. It's not that complex to handle.
+--ldx]]--
+
+local chainmores = { }
+local chainprocs = { }
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf subchain",...)
+end
+local function logwarning(...)
+ logs.report("otf subchain",...)
+end
+
+-- ['coverage']={
+-- ['after']={ "r" },
+-- ['before']={ "q" },
+-- ['current']={ "a", "b", "c" },
+-- },
+-- ['lookups']={ "ls_l_1", "ls_l_1", "ls_l_1" },
+
+function chainmores.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname,n)
+ logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
+-- handled later:
+--
+-- function chainmores.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- end
+
+function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+ logprocess("%s: gsub_multiple not yet supported",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+ logprocess("%s: gsub_alternate not yet supported",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
+-- handled later:
+--
+-- function chainmores.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- end
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf chain",...)
+end
+local function logwarning(...)
+ logs.report("otf chain",...)
+end
+
+-- We could share functions but that would lead to extra function calls with many
+-- arguments, redundant tests and confusing messages.
+
+function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname)
+ logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
+-- The reversesub is a special case, which is why we need to store the replacements
+-- in a bit weird way. There is no lookup and the replacement comes from the lookup
+-- itself. It is meant mostly for dealing with Urdu.
+
+function chainprocs.reversesub(start,stop,kind,chainname,currentcontext,cache,replacements)
+ local char = start.char
+ local replacement = replacements[char]
+ if replacement then
+ if trace_singles then
+ logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement))
+ end
+ start.char = replacement
+ return start, true
+ else
+ return start, false
+ end
+end
+
+--[[ldx--
+
This chain stuff is somewhat tricky since we can have a sequence of actions to be
+applied: single, alternate, multiple or ligature where ligature can be an invalid
+one in the sense that it will replace multiple by one but not neccessary one that
+looks like the combination (i.e. it is the counterpart of multiple then). For
+example, the following is valid:
Therefore we we don't really do the replacement here already unless we have the
+single lookup case. The efficiency of the replacements can be improved by deleting
+as less as needed but that would also mke the code even more messy.
+--ldx]]--
+
+local function delete_till_stop(start,stop,ignoremarks)
+ if start ~= stop then
+ -- todo keep marks
+ local done = false
+ while not done do
+ done = start == stop
+ delete_node(start,start.next)
+ end
+ end
+end
+
+--[[ldx--
+
Here we replace start by a single variant, First we delete the rest of the
+match.
+--ldx]]--
+
+function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+ -- todo: marks ?
+ if not chainindex then
+ delete_till_stop(start,stop) -- ,currentlookup.flags[1])
+ end
+ local current = start
+ local subtables = currentlookup.subtables
+ while current do
+ if current.id == glyph then
+ local currentchar = current.char
+ local lookupname = subtables[1]
+ local replacement = cache.gsub_single[lookupname]
+ if not replacement then
+ if trace_bugs then
+ logwarning("%s: no single hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
+ end
+ else
+ replacement = replacement[currentchar]
+ if not replacement then
+ if trace_bugs then
+ logwarning("%s: no single for %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar))
+ end
+ else
+ if trace_singles then
+ logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
+ end
+ current.char = replacement
+ end
+ end
+ return start, true
+ elseif current == stop then
+ break
+ else
+ current = current.next
+ end
+ end
+ return start, false
+end
+
+chainmores.gsub_single = chainprocs.gsub_single
+
+--[[ldx--
+
Here we replace start by a sequence of new glyphs. First we delete the rest of
+the match.
+--ldx]]--
+
+function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ delete_till_stop(start,stop)
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local replacements = cache.gsub_multiple[lookupname]
+ if not replacements then
+ if trace_bugs then
+ logwarning("%s: no multiple hits",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ else
+ replacements = replacements[startchar]
+ if not replacements then
+ if trace_bugs then
+ logwarning("%s: no multiple for %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar))
+ end
+ else
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))
+ end
+ local sn = start.next
+ for k=1,#replacements do
+ if k == 1 then
+ start.char = replacements[k]
+ else
+ local n = copy_node(start) -- maybe delete the components and such
+ n.char = replacements[k]
+ n.next, n.prev = sn, start
+ if sn then
+ sn.prev = n
+ end
+ start.next, start = n, n
+ end
+ end
+ return start, true
+ end
+ end
+ return start, false
+end
+
+--[[ldx--
+
Here we replace start by new glyph. First we delete the rest of the match.
+--ldx]]--
+
+function chainprocs.gsub_alternate(start,stop,kind,lookupname,currentcontext,cache,currentlookup)
+ -- todo: marks ?
+ delete_till_stop(start,stop)
+ local current = start
+ local subtables = currentlookup.subtables
+ while current do
+ if current.id == glyph then
+ local currentchar = current.char
+ local lookupname = subtables[1]
+ local alternatives = cache.gsub_alternate[lookupname]
+ if not alternatives then
+ if trace_bugs then
+ logwarning("%s: no alternative hits",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ else
+ alternatives = alternatives[currentchar]
+ if not alternatives then
+ if trace_bugs then
+ logwarning("%s: no alternative for %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar))
+ end
+ else
+ local choice, index = alternative_glyph(current,alternatives,kind,chainname,chainlookupname,lookupname)
+ current.char = choice
+ if trace_alternatives then
+ logprocess("%s: replacing single %s by alternative %s (%s)",cref(kind,chainname,chainlookupname,lookupname),index,gref(currentchar),gref(choice),index)
+ end
+ end
+ end
+ return start, true
+ elseif current == stop then
+ break
+ else
+ current = current.next
+ end
+ end
+ return start, false
+end
+
+--[[ldx--
+
When we replace ligatures we use a helper that handles the marks. I might change
+this function (move code inline and handle the marks by a separate function). We
+assume rather stupid ligatures (no complex disc nodes).
+--ldx]]--
+
+function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local ligatures = cache.gsub_ligature[lookupname]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligature hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
+ end
+ else
+ ligatures = ligatures[startchar]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
+ end
+ else
+ local s, discfound, last, nofreplacements = start.next, false, stop, 0
+ while s do
+ local id = s.id
+ if id == disc then
+ s = s.next
+ discfound = true
+ else
+ local schar = s.char
+ if marks[schar] then -- marks
+ s = s.next
+ else
+ local lg = ligatures[1][schar]
+ if not lg then
+ break
+ else
+ ligatures, last, nofreplacements = lg, s, nofreplacements + 1
+ if s == stop then
+ break
+ else
+ s = s.next
+ end
+ end
+ end
+ end
+ end
+ local l2 = ligatures[2]
+ if l2 then
+ if chainindex then
+ stop = last
+ end
+ if trace_ligatures then
+ if start == stop then
+ logprocess("%s: replacing character %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
+ else
+ logprocess("%s: replacing character %s upto %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
+ end
+ end
+ start = toligature(kind,lookup,start,stop,l2,currentlookup.flags[1],discfound)
+ return start, true, nofreplacements
+ elseif trace_bugs then
+ if start == stop then
+ logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
+ else
+ logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char))
+ end
+ end
+ end
+ end
+ return start, false, 0
+end
+
+chainmores.gsub_ligature = chainprocs.gsub_ligature
+
+function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = cache.gpos_mark2base[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+ end
+ end
+ end
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ local baseanchors = baseanchors['basechar']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s, no matching anchors for mark %s and base %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = cache.gpos_mark2ligature[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [optional marks] [start=mark]
+ local index = 1
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ else
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",cref(kind,chainname,chainlookupname,lookupname),markchar)
+ end
+ return start, false
+ end
+ end
+ end
+ -- todo: like marks a ligatures hash
+ local i = has_attribute(start,markdone)
+ if i then index = i end
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ local baseanchors = baseanchors['baselig']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ ba = ba[index]
+ if ba then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and baselig %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("feature %s, lookup %s: prev node is no char",kind,lookupname)
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+--~ local alreadydone = markonce and has_attribute(start,markmark)
+--~ if not alreadydone then
+ -- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = cache.gpos_mark2mark[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [basemark] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then -- subtype test can go
+ local basechar = base.char
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ baseanchors = baseanchors['basemark']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and basemark %s",gref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+--~ elseif trace_marks and trace_details then
+--~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone)
+--~ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return start, false
+end
+
+-- ! ! ! untested ! ! !
+
+function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local alreadydone = cursonce and has_attribute(start,cursbase)
+ if not alreadydone then
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local exitanchors = cache.gpos_cursive[lookupname]
+ if exitanchors then
+ exitanchors = exitanchors[startchar]
+ end
+ if exitanchors then
+ local done = false
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
+ end
+ else
+ local nxt = start.next
+ while not done and nxt and nxt.id == glyph and nxt.subtype<256 and nxt.font == currentfont do
+ local nextchar = nxt.char
+ if marks[nextchar] then
+ -- should not happen (maybe warning)
+ nxt = nxt.next
+ else
+ local entryanchors = descriptions[nextchar]
+ if entryanchors then
+ entryanchors = entryanchors.anchors
+ if entryanchors then
+ entryanchors = entryanchors['centry']
+ if entryanchors then
+ local al = anchorlookups[lookupname]
+ for anchor, entry in next, entryanchors do
+ if al[anchor] then
+ local exit = exitanchors[anchor]
+ if exit then
+ local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ if trace_cursive then
+ logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
+ end
+ done = true
+ break
+ end
+ end
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
+ fonts.register_message(currentfont,startchar,"no entry anchors")
+ end
+ break
+ end
+ end
+ end
+ return start, done
+ else
+ if trace_cursive and trace_details then
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ end
+ return start, false
+ end
+ end
+ return start, false
+end
+
+function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex,sequence)
+ -- untested
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = cache.gpos_single[lookupname]
+ if kerns then
+ kerns = kerns[startchar]
+ if kerns then
+ local dx, dy, w, h = set_pair(start,tfmdata.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
+ end
+ end
+ end
+ return start, false
+end
+
+-- when machines become faster i will make a shared function
+
+function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex,sequence)
+-- logwarning("%s: gpos_pair not yet supported",cref(kind,chainname,chainlookupname))
+ local snext = start.next
+ if snext then
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = cache.gpos_pair[lookupname]
+ if kerns then
+ kerns = kerns[startchar]
+ if kerns then
+ local prev, done = start, false
+ local factor = tfmdata.factor
+ while snext and snext.id == glyph and snext.subtype<256 and snext.font == currentfont do
+ local nextchar = snext.char
+ local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = snext.next
+ else
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if krn[1] == "pair" then
+ local a, b = krn[3], krn[4]
+ if a and #a > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
+ if trace_kerns then
+ logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else
+ logs.report("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
+ local a, b = krn[3], krn[7]
+ if a and a ~= 0 then
+ local k = set_kern(snext,factor,rlmode,a)
+ if trace_kerns then
+ logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ end
+ end
+ if b and b ~= 0 then
+ logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
+ end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = set_kern(snext,factor,rlmode,krn)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return start, done
+ end
+ end
+ end
+ return start, false
+end
+
+-- what pointer to return, spec says stop
+-- to be discussed ... is bidi changer a space?
+-- elseif char == zwnj and sequence[n][32] then -- brrr
+
+-- somehow l or f is global
+-- we don't need to pass the currentcontext, saves a bit
+-- make a slow variant then can be activated but with more tracing
+
+local function show_skip(kind,chainname,char,ck,class)
+ if ck[9] then
+ logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s (%s=>%s)",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
+ else
+ logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s",cref(kind,chainname),gref(char),class,ck[1],ck[2])
+ end
+end
+
+local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,cache)
+ -- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
+ local flags, done = sequence.flags, false
+ local skipmark, skipligature, skipbase = flags[1], flags[2], flags[3]
+ local someskip = skipmark or skipligature or skipbase -- could be stored in flags for a fast test (hm, flags could be false !)
+ local markclass = sequence.markclass -- todo, first we need a proper test
+ local skipped = false
+ for k=1,#contexts do
+ local match, current, last = true, start, start
+ local ck = contexts[k]
+ local seq = ck[3]
+ local s = #seq
+ -- f..l = mid string
+ if s == 1 then
+ -- never happens
+ match = current.id == glyph and current.subtype<256 and current.font == currentfont and seq[1][current.char]
+ else
+ -- todo: better space check (maybe check for glue)
+ local f, l = ck[4], ck[5]
+ if f == l then
+ -- already a hit
+ match = true
+ else
+ -- no need to test first hit (to be optimized)
+ local n = f + 1
+ last = last.next
+ -- we cannot optimize for n=2 because there can be disc nodes
+ -- if not someskip and n == l then
+ -- -- n=2 and no skips then faster loop
+ -- match = last and last.id == glyph and last.subtype<256 and last.font == currentfont and seq[n][last.char]
+ -- else
+ while n <= l do
+ if last then
+ local id = last.id
+ if id == glyph then
+ if last.subtype<256 and last.font == currentfont then
+ local char = last.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ skipped = true
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
+ last = last.next
+ elseif seq[n][char] then
+ if n < l then
+ last = last.next
+ end
+ n = n + 1
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ elseif id == disc then -- what to do with kerns?
+ last = last.next
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ end
+ -- end
+ end
+ if match and f > 1 then
+ -- before
+ local prev = start.prev
+ if prev then
+ local n = f-1
+ while n >= 1 do
+ if prev then
+ local id = prev.id
+ if id == glyph then
+ if prev.subtype<256 and prev.font == currentfont then -- normal char
+ local char = prev.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ skipped = true
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
+ elseif seq[n][char] then
+ n = n -1
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ elseif id == disc then
+ -- skip 'm
+ elseif seq[n][32] then
+ n = n -1
+ else
+ match = false break
+ end
+ prev = prev.prev
+ elseif seq[n][32] then
+ n = n -1
+ else
+ match = false break
+ end
+ end
+ elseif f == 2 then
+ match = seq[1][32]
+ else
+ for n=f-1,1 do
+ if not seq[n][32] then
+ match = false break
+ end
+ end
+ end
+ end
+ if match and s > l then
+ -- after
+ local current = last.next
+ if current then
+ -- removed optimization for s-l == 1, we have to deal with marks anyway
+ local n = l + 1
+ while n <= s do
+ if current then
+ local id = current.id
+ if id == glyph then
+ if current.subtype<256 and current.font == currentfont then -- normal char
+ local char = current.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ skipped = true
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
+ elseif seq[n][char] then
+ n = n + 1
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ elseif id == disc then
+ -- skip 'm
+ elseif seq[n][32] then -- brrr
+ n = n + 1
+ else
+ match = false break
+ end
+ current = current.next
+ elseif seq[n][32] then
+ n = n + 1
+ else
+ match = false break
+ end
+ end
+ elseif s-l == 1 then
+ match = seq[s][32]
+ else
+ for n=l+1,s do
+ if not seq[n][32] then
+ match = false break
+ end
+ end
+ end
+ end
+ end
+ if match then
+ -- ck == currentcontext
+ if trace_contexts then
+ local rule, lookuptype, f, l = ck[1], ck[2], ck[4], ck[5]
+ local char = start.char
+ if ck[9] then
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s (%s=>%s)",cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10])
+ else
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s",cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype)
+ end
+ end
+ local chainlookups = ck[6]
+ if chainlookups then
+ local nofchainlookups = #chainlookups
+ -- we can speed this up if needed
+ if nofchainlookups == 1 then
+ local chainlookupname = chainlookups[1]
+ local chainlookup = lookuptable[chainlookupname]
+ local cp = chainprocs[chainlookup.type]
+ if cp then
+ start, done = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,nil,sequence)
+ else
+ logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ end
+ else
+ -- actually this needs a more complex treatment for which we will use chainmores
+--~ local i = 1
+--~ repeat
+--~ local chainlookupname = chainlookups[i]
+--~ local chainlookup = lookuptable[chainlookupname]
+--~ local cp = chainmores[chainlookup.type]
+--~ if cp then
+--~ local ok, n
+--~ start, ok, n = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,i,sequence)
+--~ -- messy since last can be changed !
+--~ if ok then
+--~ done = true
+--~ start = start.next
+--~ if n then
+--~ -- skip next one(s) if ligature
+--~ i = i + n - 1
+--~ end
+--~ end
+--~ else
+--~ logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+--~ end
+--~ i = i + 1
+--~ until i > nofchainlookups
+
+ local i = 1
+ repeat
+if skipped then
+ while true do
+ local char = start.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ start = start.next
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+end
+ local chainlookupname = chainlookups[i]
+ local chainlookup = lookuptable[chainlookupname]
+ local cp = chainmores[chainlookup.type]
+ if cp then
+ local ok, n
+ start, ok, n = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,i,sequence)
+ -- messy since last can be changed !
+ if ok then
+ done = true
+ -- skip next one(s) if ligature
+ i = i + (n or 1)
+ else
+ i = i + 1
+ end
+ else
+ logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ i = i + 1
+ end
+ start = start.next
+ until i > nofchainlookups
+
+ end
+ else
+ local replacements = ck[7]
+ if replacements then
+ start, done = chainprocs.reversesub(start,last,kind,chainname,ck,cache,replacements) -- sequence
+ else
+ done = true -- can be meant to be skipped
+ if trace_contexts then
+ logprocess("%s: skipping match",cref(kind,chainname))
+ end
+ end
+ end
+ end
+ end
+ return start, done
+end
+
+-- Because we want to keep this elsewhere (an because speed is less an issue) we
+-- pass the font id so that the verbose variant can access the relevant helper tables.
+
+local verbose_handle_contextchain = function(font,...)
+ logwarning("no verbose handler installed, reverting to 'normal'")
+ otf.setcontextchain()
+ return normal_handle_contextchain(...)
+end
+
+otf.chainhandlers = {
+ normal = normal_handle_contextchain,
+ verbose = verbose_handle_contextchain,
+}
+
+function otf.setcontextchain(method)
+ if not method or method == "normal" or not otf.chainhandlers[method] then
+ if handlers.contextchain then -- no need for a message while making the format
+ logwarning("installing normal contextchain handler")
+ end
+ handlers.contextchain = normal_handle_contextchain
+ else
+ logwarning("installing contextchain handler '%s'",method)
+ local handler = otf.chainhandlers[method]
+ handlers.contextchain = function(...)
+ return handler(currentfont,...) -- hm, get rid of ...
+ end
+ end
+ handlers.gsub_context = handlers.contextchain
+ handlers.gsub_contextchain = handlers.contextchain
+ handlers.gsub_reversecontextchain = handlers.contextchain
+ handlers.gpos_contextchain = handlers.contextchain
+ handlers.gpos_context = handlers.contextchain
+end
+
+otf.setcontextchain()
+
+local missing = { } -- we only report once
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf process",...)
+end
+local function logwarning(...)
+ logs.report("otf process",...)
+end
+
+local function report_missing_cache(typ,lookup)
+ local f = missing[currentfont] if not f then f = { } missing[currentfont] = f end
+ local t = f[typ] if not t then t = { } f[typ] = t end
+ if not t[lookup] then
+ t[lookup] = true
+ logwarning("missing cache for lookup %s of type %s in font %s (%s)",lookup,typ,currentfont,tfmdata.fullname)
+ end
+end
+
+local resolved = { } -- we only resolve a font,script,language pair once
+
+-- todo: pass all these 'locals' in a table
+
+function fonts.methods.node.otf.features(head,font,attr)
+ if trace_steps then
+ checkstep(head)
+ end
+ tfmdata = fontdata[font]
+ local shared = tfmdata.shared
+ otfdata = shared.otfdata
+ local luatex = otfdata.luatex
+ descriptions = tfmdata.descriptions
+ characters = tfmdata.characters
+ indices = tfmdata.indices
+ unicodes = tfmdata.unicodes
+ marks = tfmdata.marks
+ anchorlookups = luatex.lookup_to_anchor
+ currentfont = font
+ rlmode = 0
+ local featuredata = otfdata.shared.featuredata -- can be made local to closure
+ local sequences = luatex.sequences
+ lookuptable = luatex.lookups
+ local done = false
+ local script, language, s_enabled, a_enabled, dyn
+ local attribute_driven = attr and attr ~= 0
+ if attribute_driven then
+ local features = context_setups[context_numbers[attr]] -- could be a direct list
+ dyn = context_merged[attr] or 0
+ language, script = features.language or "dflt", features.script or "dflt"
+ a_enabled = features -- shared.features -- can be made local to the resolver
+ if dyn == 2 or dyn == -2 then
+ -- font based
+ s_enabled = shared.features
+ end
+ else
+ language, script = tfmdata.language or "dflt", tfmdata.script or "dflt"
+ s_enabled = shared.features -- can be made local to the resolver
+ dyn = 0
+ end
+ -- we can save some runtime by caching feature tests
+ local res = resolved[font] if not res then res = { } resolved[font] = res end
+ local rs = res [script] if not rs then rs = { } res [script] = rs end
+ local rl = rs [language] if not rl then rl = { } rs [language] = rl end
+ local ra = rl [attr] if ra == nil then ra = { } rl [attr] = ra end -- attr can be false
+ -- sequences always > 1 so no need for optimization
+ for s=1,#sequences do
+ local pardir, txtdir = 0, { }
+ local success = false
+ local sequence = sequences[s]
+ local r = ra[s] -- cache
+ if r == nil then
+ --
+ -- this bit will move to font-ctx and become a function
+ ---
+ local chain = sequence.chain or 0
+ local features = sequence.features
+ if not features then
+ -- indirect lookup, part of chain (todo: make this a separate table)
+ r = false -- { false, false, chain }
+ else
+ local valid, attribute, kind, what = false, false
+ for k,v in next, features do
+ -- we can quit earlier but for the moment we want the tracing
+ local s_e = s_enabled and s_enabled[k]
+ local a_e = a_enabled and a_enabled[k]
+ if s_e or a_e then
+ local l = v[script] or v[wildcard]
+ if l then
+ -- not l[language] or l[default] or l[wildcard] because we want tracing
+ -- only first attribute match check, so we assume simple fina's
+ -- default can become a font feature itself
+ if l[language] then
+ valid, what = s_e or a_e, language
+ -- elseif l[default] then
+ -- valid, what = true, default
+ elseif l[wildcard] then
+ valid, what = s_e or a_e, wildcard
+ end
+ if valid then
+ kind, attribute = k, special_attributes[k] or false
+ if a_e and dyn < 0 then
+ valid = false
+ end
+ if trace_applied then
+ local typ, action = match(sequence.type,"(.*)_(.*)")
+ logs.report("otf node mode",
+ "%s font: %03i, dynamic: %03i, kind: %s, lookup: %3i, script: %-4s, language: %-4s (%-4s), type: %s, action: %s, name: %s",
+ (valid and "+") or "-",font,attr or 0,kind,s,script,language,what,typ,action,sequence.name)
+ end
+ break
+ end
+ end
+ end
+ end
+ if valid then
+ r = { valid, attribute, chain, kind }
+ else
+ r = false -- { valid, attribute, chain, "generic" } -- false anyway, could be flag instead of table
+ end
+ end
+ ra[s] = r
+ end
+ featurevalue = r and r[1] -- todo: pass to function instead of using a global
+ if featurevalue then
+ local attribute, chain, typ, subtables = r[2], r[3], sequence.type, sequence.subtables
+ if chain < 0 then
+ -- this is a limited case, no special treatments like 'init' etc
+ local handler = handlers[typ]
+ local thecache = featuredata[typ] or { }
+ -- we need to get rid of this slide !
+ local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
+ while start do
+ local id = start.id
+ if id == glyph then
+ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) then
+--~ if start.subtype<256 and start.font == font and has_attribute(start,0,attr) then
+ for i=1,#subtables do
+ local lookupname = subtables[i]
+ local lookupcache = thecache[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ start, success = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ if success then
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ if start then start = start.prev end
+ else
+ start = start.prev
+ end
+ else
+ start = start.prev
+ end
+ end
+ else
+ local handler = handlers[typ]
+ local ns = #subtables
+ local thecache = featuredata[typ] or { }
+ local start = head -- local ?
+ rlmode = 0 -- to be checked ?
+ if ns == 1 then
+ local lookupname = subtables[1]
+ local lookupcache = thecache[lookupname]
+ if not lookupcache then
+ report_missing_cache(typ,lookupname)
+ else
+ while start do
+ local id = start.id
+ if id == glyph then
+--~ if start.font == font and start.subtype<256 and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
+ if start.font == font and start.subtype<256 and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- sequence kan weg
+ local ok
+ start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
+ if ok then
+ success = true
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ -- elseif id == glue then
+ -- if p[5] then -- chain
+ -- local pc = pp[32]
+ -- if pc then
+ -- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
+ -- if ok then
+ -- done = true
+ -- end
+ -- if start then start = start.next end
+ -- else
+ -- start = start.next
+ -- end
+ -- else
+ -- start = start.next
+ -- end
+ elseif id == whatsit then
+ local subtype = start.subtype
+ if subtype == 7 then
+ local dir = start.dir
+ if dir == "+TRT" or dir == "+TLT" then
+ insert(txtdir,dir)
+ elseif dir == "-TRT" or dir == "-TLT" then
+ remove(txtdir)
+ end
+ local d = txtdir[#txtdir]
+ if d == "+TRT" then
+ rlmode = -1
+ elseif d == "+TLT" then
+ rlmode = 1
+ else
+ rlmode = pardir
+ end
+ if trace_directions then
+ logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)
+ end
+ elseif subtype == 6 then
+ local dir = start.dir
+ if dir == "TRT" then
+ pardir = -1
+ elseif dir == "TLT" then
+ pardir = 1
+ else
+ pardir = 0
+ end
+ rlmode = pardir
+ --~ txtdir = { }
+ if trace_directions then
+ logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)
+ end
+ end
+ start = start.next
+ else
+ start = start.next
+ end
+ end
+ end
+ else
+ while start do
+ local id = start.id
+ if id == glyph then
+ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
+--~ if start.subtype<256 and start.font == font and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = thecache[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ if ok then
+ success = true
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ -- elseif id == glue then
+ -- if p[5] then -- chain
+ -- local pc = pp[32]
+ -- if pc then
+ -- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
+ -- if ok then
+ -- done = true
+ -- end
+ -- if start then start = start.next end
+ -- else
+ -- start = start.next
+ -- end
+ -- else
+ -- start = start.next
+ -- end
+ elseif id == whatsit then
+ local subtype = start.subtype
+ local subtype = start.subtype
+ if subtype == 7 then
+ local dir = start.dir
+ if dir == "+TRT" or dir == "+TLT" then
+ insert(txtdir,dir)
+ elseif dir == "-TRT" or dir == "-TLT" then
+ remove(txtdir)
+ end
+ local d = txtdir[#txtdir]
+ if d == "+TRT" then
+ rlmode = -1
+ elseif d == "+TLT" then
+ rlmode = 1
+ else
+ rlmode = pardir
+ end
+ if trace_directions then
+ logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)
+ end
+ elseif subtype == 6 then
+ local dir = start.dir
+ if dir == "TRT" then
+ pardir = -1
+ elseif dir == "TLT" then
+ pardir = 1
+ else
+ pardir = 0
+ end
+ rlmode = pardir
+ --~ txtdir = { }
+ if trace_directions then
+ logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)
+ end
+ end
+ start = start.next
+ else
+ start = start.next
+ end
+ end
+ end
+ end
+ if success then
+ done = true
+ end
+ if trace_steps then -- ?
+ registerstep(head)
+ end
+ end
+ end
+ return head, done
+end
+
+otf.features.prepare = { }
+
+-- we used to share code in the following functions but that costs a lot of
+-- memory due to extensive calls to functions (easily hundreds of thousands per
+-- document)
+
+local function split(replacement,original,cache,unicodes)
+ -- we can cache this too, but not the same (although unicode is a unique enough hash)
+ local o, t, n = { }, { }, 0
+ for s in gmatch(original,"[^ ]+") do
+ local us = unicodes[s]
+ if type(us) == "number" then -- tonumber(us)
+ o[#o+1] = us
+ else
+ o[#o+1] = us[1]
+ end
+ end
+ for s in gmatch(replacement,"[^ ]+") do
+ n = n + 1
+ local us = unicodes[s]
+ if type(us) == "number" then -- tonumber(us)
+ t[o[n]] = us
+ else
+ t[o[n]] = us[1]
+ end
+ end
+ return t
+end
+
+local function uncover(covers,result,cache,unicodes)
+ -- lpeg hardly faster (.005 sec on mk)
+ for n=1,#covers do
+ local c = covers[n]
+ local cc = cache[c]
+ if not cc then
+ local t = { }
+ for s in gmatch(c,"[^ ]+") do
+ local us = unicodes[s]
+ if type(us) == "number" then
+ t[us] = true
+ else
+ for i=1,#us do
+ t[us[i]] = true
+ end
+ end
+ end
+ cache[c] = t
+ result[#result+1] = t
+ else
+ result[#result+1] = cc
+ end
+ end
+end
+
+local function prepare_lookups(tfmdata)
+ local otfdata = tfmdata.shared.otfdata
+ local featuredata = otfdata.shared.featuredata
+ local anchor_to_lookup = otfdata.luatex.anchor_to_lookup
+ local lookup_to_anchor = otfdata.luatex.lookup_to_anchor
+ --
+ local multiple = featuredata.gsub_multiple
+ local alternate = featuredata.gsub_alternate
+ local single = featuredata.gsub_single
+ local ligature = featuredata.gsub_ligature
+ local pair = featuredata.gpos_pair
+ local position = featuredata.gpos_single
+ local kerns = featuredata.gpos_pair
+ local mark = featuredata.gpos_mark2mark
+ local cursive = featuredata.gpos_cursive
+ --
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local indices = tfmdata.indices
+ local descriptions = tfmdata.descriptions
+ --
+ -- we can change the otf table after loading but then we need to adapt base mode
+ -- as well (no big deal)
+ --
+ local action = {
+ substitution = function(p,lookup,k,glyph,unicode)
+ local old, new = unicode, unicodes[p[2]]
+ if type(new) == "table" then
+ new = new[1]
+ end
+ local s = single[lookup]
+ if not s then s = { } single[lookup] = s end
+ s[old] = new
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: substitution %s => %s",lookup,old,new)
+ --~ end
+ end,
+ multiple = function (p,lookup,k,glyph,unicode)
+ local old, new = unicode, { }
+ local m = multiple[lookup]
+ if not m then m = { } multiple[lookup] = m end
+ m[old] = new
+ for pc in gmatch(p[2],"[^ ]+") do
+ local upc = unicodes[pc]
+ if type(upc) == "number" then
+ new[#new+1] = upc
+ else
+ new[#new+1] = upc[1]
+ end
+ end
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: multiple %s => %s",lookup,old,concat(new," "))
+ --~ end
+ end,
+ alternate = function(p,lookup,k,glyph,unicode)
+ local old, new = unicode, { }
+ local a = alternate[lookup]
+ if not a then a = { } alternate[lookup] = a end
+ a[old] = new
+ for pc in gmatch(p[2],"[^ ]+") do
+ local upc = unicodes[pc]
+ if type(upc) == "number" then
+ new[#new+1] = upc
+ else
+ new[#new+1] = upc[1]
+ end
+ end
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: alternate %s => %s",lookup,old,concat(new,"|"))
+ --~ end
+ end,
+ ligature = function (p,lookup,k,glyph,unicode)
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: ligature %s => %s",lookup,p[2],glyph.name)
+ --~ end
+ local first = true
+ local t = ligature[lookup]
+ if not t then t = { } ligature[lookup] = t end
+ for s in gmatch(p[2],"[^ ]+") do
+ if first then
+ local u = unicodes[s]
+ if not u then
+ logs.report("define otf","lookup %s: ligature %s => %s ignored due to invalid unicode",lookup,p[2],glyph.name)
+ break
+ elseif type(u) == "number" then
+ if not t[u] then
+ t[u] = { { } }
+ end
+ t = t[u]
+ else
+ local tt = t
+ local tu
+ for i=1,#u do
+ local u = u[i]
+ if i==1 then
+ if not t[u] then
+ t[u] = { { } }
+ end
+ tu = t[u]
+ t = tu
+ else
+ if not t[u] then
+ tt[u] = tu
+ end
+ end
+ end
+ end
+ first = false
+ else
+ s = unicodes[s]
+ local t1 = t[1]
+ if not t1[s] then
+ t1[s] = { { } }
+ end
+ t = t1[s]
+ end
+ end
+ t[2] = unicode
+ end,
+ position = function(p,lookup,k,glyph,unicode)
+ -- not used
+ local s = position[lookup]
+ if not s then s = { } position[lookup] = s end
+ s[unicode] = p[2] -- direct pointer to kern spec
+ end,
+ pair = function(p,lookup,k,glyph,unicode)
+ local s = pair[lookup]
+ if not s then s = { } pair[lookup] = s end
+ local others = s[unicode]
+ if not others then others = { } s[unicode] = others end
+ -- todo: fast check for space
+ local two = p[2]
+ local upc = unicodes[two]
+ if not upc then
+ for pc in gmatch(two,"[^ ]+") do
+ local upc = unicodes[pc]
+ if type(upc) == "number" then
+ others[upc] = p -- direct pointer to main table
+ else
+ for i=1,#upc do
+ others[upc[i]] = p -- direct pointer to main table
+ end
+ end
+ end
+ elseif type(upc) == "number" then
+ others[upc] = p -- direct pointer to main table
+ else
+ for i=1,#upc do
+ others[upc[i]] = p -- direct pointer to main table
+ end
+ end
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: pair for U+%04X",lookup,unicode)
+ --~ end
+ end,
+ }
+ --
+ for unicode, glyph in next, descriptions do
+ local lookups = glyph.slookups
+ if lookups then
+ for lookup, p in next, lookups do
+ action[p[1]](p,lookup,k,glyph,unicode)
+ end
+ end
+ local lookups = glyph.mlookups
+ if lookups then
+ for lookup, whatever in next, lookups do
+ for i=1,#whatever do -- normaly one
+ local p = whatever[i]
+ action[p[1]](p,lookup,k,glyph,unicode)
+ end
+ end
+ end
+ local list = glyph.mykerns
+ if list then
+ for lookup, krn in next, list do
+ local k = kerns[lookup]
+ if not k then k = { } kerns[lookup] = k end
+ k[unicode] = krn -- ref to glyph, saves lookup
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: kern for U+%04X",lookup,unicode)
+ --~ end
+ end
+ end
+ local oanchor = glyph.anchors
+ if oanchor then
+ for typ, anchors in next, oanchor do -- types
+ if typ == "mark" then
+ for name, anchor in next, anchors do
+ local lookups = anchor_to_lookup[name]
+ if lookups then
+ for lookup, _ in next, lookups do
+ local f = mark[lookup]
+ if not f then f = { } mark[lookup] = f end
+ f[unicode] = anchors -- ref to glyph, saves lookup
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: mark anchor %s for U+%04X",lookup,name,unicode)
+ --~ end
+ end
+ end
+ end
+ elseif typ == "cexit" then -- or entry?
+ for name, anchor in next, anchors do
+ local lookups = anchor_to_lookup[name]
+ if lookups then
+ for lookup, _ in next, lookups do
+ local f = cursive[lookup]
+ if not f then f = { } cursive[lookup] = f end
+ f[unicode] = anchors -- ref to glyph, saves lookup
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: exit anchor %s for U+%04X",lookup,name,unicode)
+ --~ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+-- local cache = { }
+luatex = luatex or {} -- this has to change ... we need a better one
+
+function prepare_contextchains(tfmdata)
+ local otfdata = tfmdata.shared.otfdata
+ local lookups = otfdata.lookups
+ if lookups then
+ local featuredata = otfdata.shared.featuredata
+ local contextchain = featuredata.gsub_contextchain -- shared with gpos
+ local reversecontextchain = featuredata.gsub_reversecontextchain -- shared with gpos
+ local characters = tfmdata.characters
+ local unicodes = tfmdata.unicodes
+ local indices = tfmdata.indices
+ local cache = luatex.covers
+ if not cache then
+ cache = { }
+ luatex.covers = cache
+ end
+ --
+ for lookupname, lookupdata in next, otfdata.lookups do
+ local lookuptype = lookupdata.type
+ if not lookuptype then
+ logs.report("otf process","missing lookuptype for %s",lookupname)
+ else
+ local rules = lookupdata.rules
+ if rules then
+ local fmt = lookupdata.format
+ -- contextchain[lookupname][unicode]
+ if fmt == "coverage" then
+ if lookuptype ~= "chainsub" and lookuptype ~= "chainpos" then
+ logs.report("otf process","unsupported coverage %s for %s",lookuptype,lookupname)
+ else
+ local contexts = contextchain[lookupname]
+ if not contexts then
+ contexts = { }
+ contextchain[lookupname] = contexts
+ end
+ local t = { }
+ for nofrules=1,#rules do -- does #rules>1 happen often?
+ local rule = rules[nofrules]
+ local coverage = rule.coverage
+ if coverage and coverage.current then
+ local current, before, after, sequence = coverage.current, coverage.before, coverage.after, { }
+ if before then
+ uncover(before,sequence,cache,unicodes)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence,cache,unicodes)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence,cache,unicodes)
+ end
+ if sequence[1] then
+ t[#t+1] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
+ end
+ end
+ end
+ end
+ end
+ end
+ elseif fmt == "reversecoverage" then
+ if lookuptype ~= "reversesub" then
+ logs.report("otf process","unsupported reverse coverage %s for %s",lookuptype,lookupname)
+ else
+ local contexts = reversecontextchain[lookupname]
+ if not contexts then
+ contexts = { }
+ reversecontextchain[lookupname] = contexts
+ end
+ local t = { }
+ for nofrules=1,#rules do
+ local rule = rules[nofrules]
+ local reversecoverage = rule.reversecoverage
+ if reversecoverage and reversecoverage.current then
+ local current, before, after, replacements, sequence = reversecoverage.current, reversecoverage.before, reversecoverage.after, reversecoverage.replacements, { }
+ if before then
+ uncover(before,sequence,cache,unicodes)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence,cache,unicodes)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence,cache,unicodes)
+ end
+ if replacements then
+ replacements = split(replacements,current[1],cache,unicodes)
+ end
+ if sequence[1] then
+ -- this is different from normal coverage, we assume only replacements
+ t[#t+1] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
+ end
+ end
+ end
+ end
+ end
+ end
+ elseif fmt == "glyphs" then
+ if lookuptype ~= "chainsub" and lookuptype ~= "chainpos" then
+ logs.report("otf process","unsupported coverage %s for %s",lookuptype,lookupname)
+ else
+ local contexts = contextchain[lookupname]
+ if not contexts then
+ contexts = { }
+ contextchain[lookupname] = contexts
+ end
+ local t = { }
+ for nofrules=1,#rules do
+ -- nearly the same as coverage so we could as well rename it
+ local rule = rules[nofrules]
+ local glyphs = rule.glyphs
+ if glyphs and glyphs.names then
+ local fore, back, names, sequence = glyphs.fore, glyphs.back, glyphs.names, { }
+ if fore and fore ~= "" then
+ fore = lpegmatch(split_at_space,fore)
+ uncover(fore,sequence,cache,unicodes)
+ end
+ local start = #sequence + 1
+ names = lpegmatch(split_at_space,names)
+ uncover(names,sequence,cache,unicodes)
+ local stop = #sequence
+ if back and back ~= "" then
+ back = lpegmatch(split_at_space,back)
+ uncover(back,sequence,cache,unicodes)
+ end
+ if sequence[1] then
+ t[#t+1] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function fonts.initializers.node.otf.features(tfmdata,value)
+ if true then -- value then
+ if not tfmdata.shared.otfdata.shared.initialized then
+ local t = trace_preparing and os.clock()
+ local otfdata = tfmdata.shared.otfdata
+ local featuredata = otfdata.shared.featuredata
+ -- caches
+ featuredata.gsub_multiple = { }
+ featuredata.gsub_alternate = { }
+ featuredata.gsub_single = { }
+ featuredata.gsub_ligature = { }
+ featuredata.gsub_contextchain = { }
+ featuredata.gsub_reversecontextchain = { }
+ featuredata.gpos_pair = { }
+ featuredata.gpos_single = { }
+ featuredata.gpos_mark2base = { }
+ featuredata.gpos_mark2ligature = featuredata.gpos_mark2base
+ featuredata.gpos_mark2mark = featuredata.gpos_mark2base
+ featuredata.gpos_cursive = { }
+ featuredata.gpos_contextchain = featuredata.gsub_contextchain
+ featuredata.gpos_reversecontextchain = featuredata.gsub_reversecontextchain
+ --
+ prepare_contextchains(tfmdata)
+ prepare_lookups(tfmdata)
+ otfdata.shared.initialized = true
+ if trace_preparing then
+ logs.report("otf process","preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ end
+ end
+ end
+end
diff --git a/tex/context/base/font-otp.lua b/tex/context/base/font-otp.lua
new file mode 100644
index 000000000..a80c515ad
--- /dev/null
+++ b/tex/context/base/font-otp.lua
@@ -0,0 +1,504 @@
+if not modules then modules = { } end modules ['font-otp'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (packing)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: pack math (but not that much to share)
+
+local next, type, tostring = next, type, tostring
+local sort, concat = table.sort, table.concat
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+fonts.otf.enhancers = fonts.otf.enhancers or { }
+fonts.otf.glists = fonts.otf.glists or { "gsub", "gpos" }
+
+local criterium, threshold, tabstr = 1, 0, table.serialize
+
+local function tabstr(t) -- hashed from core-uti / experiment
+ local s = { }
+ for k, v in next, t do
+ if type(v) == "table" then
+ s[#s+1] = k.."={"..tabstr(v).."}"
+ else
+ s[#s+1] = k.."="..tostring(v)
+ end
+ end
+ sort(s)
+ return concat(s,",")
+end
+
+function fonts.otf.enhancers.pack(data)
+ if data then
+ local h, t, c = { }, { }, { }
+ local hh, tt, cc = { }, { }, { }
+ local function pack_1(v)
+ -- v == table
+ local tag = tabstr(v)
+ local ht = h[tag]
+ if not ht then
+ ht = #t+1
+ t[ht] = v
+ h[tag] = ht
+ c[ht] = 1
+ else
+ c[ht] = c[ht] + 1
+ end
+ return ht
+ end
+ local function pack_2(v)
+ -- v == number
+ if c[v] <= criterium then
+ return t[v]
+ else
+ -- compact hash
+ local hv = hh[v]
+ if not hv then
+ hv = #tt+1
+ tt[hv] = t[v]
+ hh[v] = hv
+ cc[hv] = c[v]
+ end
+ return hv
+ end
+ end
+ local function success(stage,pass)
+ if #t == 0 then
+ if trace_loading then
+ logs.report("load otf","pack quality: nothing to pack")
+ end
+ return false
+ elseif #t >= threshold then
+ local one, two, rest = 0, 0, 0
+ if pass == 1 then
+ for k,v in next, c do
+ if v == 1 then
+ one = one + 1
+ elseif v == 2 then
+ two = two + 1
+ else
+ rest = rest + 1
+ end
+ end
+ else
+ for k,v in next, cc do
+ if v >20 then
+ rest = rest + 1
+ elseif v >10 then
+ two = two + 1
+ else
+ one = one + 1
+ end
+ end
+ data.tables = tt
+ end
+ if trace_loading then
+ logs.report("load otf","pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)", stage, pass, one+two+rest, one, two, rest, criterium)
+ end
+ return true
+ else
+ if trace_loading then
+ logs.report("load otf","pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)", stage, pass, #t, threshold)
+ end
+ return false
+ end
+ end
+ for pass=1,2 do
+ local pack = (pass == 1 and pack_1) or pack_2
+ for k, v in next, data.glyphs do
+ v.boundingbox = pack(v.boundingbox)
+ local l = v.slookups
+ if l then
+ for k,v in next, l do
+ l[k] = pack(v)
+ end
+ end
+ local l = v.mlookups
+ if l then
+ for k,v in next, l do
+ for kk=1,#v do
+ local vkk = v[kk]
+ local what = vkk[1]
+ if what == "pair" then
+ local t = vkk[3] if t then vkk[3] = pack(t) end
+ local t = vkk[4] if t then vkk[4] = pack(t) end
+ elseif what == "position" then
+ local t = vkk[2] if t then vkk[2] = pack(t) end
+ end
+ -- v[kk] = pack(vkk)
+ end
+ end
+ end
+ local m = v.mykerns
+ if m then
+ for k,v in next, m do
+ m[k] = pack(v)
+ end
+ end
+ local m = v.math
+ if m then
+ local mk = m.kerns
+ if mk then
+ for k,v in next, mk do
+ mk[k] = pack(v)
+ end
+ end
+ end
+ local a = v.anchors
+ if a then
+ for k,v in next, a do
+ if k == "baselig" then
+ for kk, vv in next, v do
+ for kkk=1,#vv do
+ vv[kkk] = pack(vv[kkk])
+ end
+ end
+ else
+ for kk, vv in next, v do
+ v[kk] = pack(vv)
+ end
+ end
+ end
+ end
+ end
+ if data.lookups then
+ for k, v in next, data.lookups do
+ if v.rules then
+ for kk, vv in next, v.rules do
+ local l = vv.lookups
+ if l then
+ vv.lookups = pack(l)
+ end
+ local c = vv.coverage
+ if c then
+ local cc = c.before if cc then c.before = pack(cc) end
+ local cc = c.after if cc then c.after = pack(cc) end
+ local cc = c.current if cc then c.current = pack(cc) end
+ end
+ local c = vv.reversecoverage
+ if c then
+ local cc = c.before if cc then c.before = pack(cc) end
+ local cc = c.after if cc then c.after = pack(cc) end
+ local cc = c.current if cc then c.current = pack(cc) end
+ end
+ -- no need to pack vv.glyphs
+ local c = vv.glyphs
+ if c then
+ if c.fore == "" then c.fore = nil end
+ if c.back == "" then c.back = nil end
+ end
+ end
+ end
+ end
+ end
+ if data.luatex then
+ local la = data.luatex.anchor_to_lookup
+ if la then
+ for lookup, ldata in next, la do
+ la[lookup] = pack(ldata)
+ end
+ end
+ local la = data.luatex.lookup_to_anchor
+ if la then
+ for lookup, ldata in next, la do
+ la[lookup] = pack(ldata)
+ end
+ end
+ local ls = data.luatex.sequences
+ if ls then
+ for feature, fdata in next, ls do
+ local flags = fdata.flags
+ if flags then
+ fdata.flags = pack(flags)
+ end
+ local subtables = fdata.subtables
+ if subtables then
+ fdata.subtables = pack(subtables)
+ end
+ local features = fdata.features
+ if features then
+ for script, sdata in next, features do
+ features[script] = pack(sdata)
+ end
+ end
+ end
+ end
+ local ls = data.luatex.lookups
+ if ls then
+ for lookup, fdata in next, ls do
+ local flags = fdata.flags
+ if flags then
+ fdata.flags = pack(flags)
+ end
+ local subtables = fdata.subtables
+ if subtables then
+ fdata.subtables = pack(subtables)
+ end
+ end
+ end
+ local lf = data.luatex.features
+ if lf then
+ for _, g in next, fonts.otf.glists do
+ local gl = lf[g]
+ if gl then
+ for feature, spec in next, gl do
+ gl[feature] = pack(spec)
+ end
+ end
+ end
+ end
+ end
+ if not success(1,pass) then
+ return
+ end
+ end
+ if #t > 0 then
+ for pass=1,2 do
+ local pack = (pass == 1 and pack_1) or pack_2
+ for k, v in next, data.glyphs do
+ local m = v.mykerns
+ if m then
+ v.mykerns = pack(m)
+ end
+ local m = v.math
+ if m then
+ local mk = m.kerns
+ if mk then
+ m.kerns = pack(mk)
+ end
+ end
+ local a = v.anchors
+ if a then
+ v.anchors = pack(a)
+ end
+ local l = v.mlookups
+ if l then
+ for k,v in next, l do
+ for kk=1,#v do
+ v[kk] = pack(v[kk])
+ end
+ end
+ end
+ end
+ local ls = data.luatex.sequences
+ if ls then
+ for feature, fdata in next, ls do
+ fdata.features = pack(fdata.features)
+ end
+ end
+ if not success(2,pass) then
+--~ return
+ end
+ end
+ end
+ end
+end
+
+function fonts.otf.enhancers.unpack(data)
+ if data then
+ local t = data.tables
+ if t then
+ local unpacked = { }
+ for k, v in next, data.glyphs do
+ local tv = t[v.boundingbox] if tv then v.boundingbox = tv end
+ local l = v.slookups
+ if l then
+ for k,v in next, l do
+ local tv = t[v] if tv then l[k] = tv end
+ end
+ end
+ local l = v.mlookups
+ if l then
+ for k,v in next, l do
+ for i=1,#v do
+ local vi = v[i]
+ local tv = t[vi]
+ if tv then
+ v[i] = tv
+ if unpacked[tv] then
+ vi = false
+ else
+ unpacked[tv], vi = true, tv
+ end
+ end
+ if vi then
+ local what = vi[1]
+ if what == "pair" then
+ local tv = t[vi[3]] if tv then vi[3] = tv end
+ local tv = t[vi[4]] if tv then vi[4] = tv end
+ elseif what == "position" then
+ local tv = t[vi[2]] if tv then vi[2] = tv end
+ end
+ end
+ end
+ end
+ end
+ local m = v.mykerns
+ if m then
+ local tm = t[m]
+ if tm then
+ v.mykerns = tm
+ if unpacked[tm] then
+ m = false
+ else
+ unpacked[tm], m = true, tm
+ end
+ end
+ if m then
+ for k,v in next, m do
+ local tv = t[v] if tv then m[k] = tv end
+ end
+ end
+ end
+ local m = v.math
+ if m then
+ local mk = m.kerns
+ if mk then
+ local tm = t[mk]
+ if tm then
+ m.kerns = tm
+ if unpacked[tm] then
+ mk = false
+ else
+ unpacked[tm], mk = true, tm
+ end
+ end
+ if mk then
+ for k,v in next, mk do
+ local tv = t[v] if tv then mk[k] = tv end
+ end
+ end
+ end
+ end
+ local a = v.anchors
+ if a then
+ local ta = t[a]
+ if ta then
+ v.anchors = ta
+ if not unpacked[ta] then
+ unpacked[ta], a = true, ta
+ else
+ a = false
+ end
+ end
+ if a then
+ for k,v in next, a do
+ if k == "baselig" then
+ for kk, vv in next, v do
+ for kkk=1,#vv do
+ local tv = t[vv[kkk]] if tv then vv[kkk] = tv end
+ end
+ end
+ else
+ for kk, vv in next, v do
+ local tv = t[vv] if tv then v[kk] = tv end
+ end
+ end
+ end
+ end
+ end
+ end
+ if data.lookups then
+ for k, v in next, data.lookups do
+ local r = v.rules
+ if r then
+ for kk, vv in next, r do
+ local l = vv.lookups
+ if l then
+ local tv = t[l] if tv then vv.lookups = tv end
+ end
+ local c = vv.coverage
+ if c then
+ local cc = c.before if cc then local tv = t[cc] if tv then c.before = tv end end
+ cc = c.after if cc then local tv = t[cc] if tv then c.after = tv end end
+ cc = c.current if cc then local tv = t[cc] if tv then c.current = tv end end
+ end
+ local c = vv.reversecoverage
+ if c then
+ local cc = c.before if cc then local tv = t[cc] if tv then c.before = tv end end
+ cc = c.after if cc then local tv = t[cc] if tv then c.after = tv end end
+ cc = c.current if cc then local tv = t[cc] if tv then c.current = tv end end
+ end
+ -- no need to unpack vv.glyphs
+ end
+ end
+ end
+ end
+ local luatex = data.luatex
+ if luatex then
+ local la = luatex.anchor_to_lookup
+ if la then
+ for lookup, ldata in next, la do
+ local tv = t[ldata] if tv then la[lookup] = tv end
+ end
+ end
+ local la = luatex.lookup_to_anchor
+ if la then
+ for lookup, ldata in next, la do
+ local tv = t[ldata] if tv then la[lookup] = tv end
+ end
+ end
+ local ls = luatex.sequences
+ if ls then
+ for feature, fdata in next, ls do
+ local flags = fdata.flags
+ if flags then
+ local tv = t[flags] if tv then fdata.flags = tv end
+ end
+ local subtables = fdata.subtables
+ if subtables then
+ local tv = t[subtables] if tv then fdata.subtables = tv end
+ end
+ local features = fdata.features
+ if features then
+ local tv = t[features]
+ if tv then
+ fdata.features = tv
+ if not unpacked[tv] then
+ unpacked[tv], features = true, tv
+ else
+ features = false
+ end
+ end
+ if features then
+ for script, sdata in next, features do
+ local tv = t[sdata] if tv then features[script] = tv end
+ end
+ end
+ end
+ end
+ end
+ local ls = luatex.lookups
+ if ls then
+ for lookups, fdata in next, ls do
+ local flags = fdata.flags
+ if flags then
+ local tv = t[flags] if tv then fdata.flags = tv end
+ end
+ local subtables = fdata.subtables
+ if subtables then
+ local tv = t[subtables] if tv then fdata.subtables = tv end
+ end
+ end
+ end
+ local lf = luatex.features
+ if lf then
+ for _, g in next, fonts.otf.glists do
+ local gl = lf[g]
+ if gl then
+ for feature, spec in next, gl do
+ local tv = t[spec] if tv then gl[feature] = tv end
+ end
+ end
+ end
+ end
+ end
+ data.tables = nil
+ end
+ end
+end
diff --git a/tex/context/base/font-ott.lua b/tex/context/base/font-ott.lua
new file mode 100644
index 000000000..2be1bf06c
--- /dev/null
+++ b/tex/context/base/font-ott.lua
@@ -0,0 +1,956 @@
+if not modules then modules = { } end modules ['font-otf'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (tables)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+local gsub, lower = string.gsub, string.lower
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+
+local otf = fonts.otf
+
+otf.tables = otf.tables or { }
+otf.meanings = otf.meanings or { }
+
+otf.tables.scripts = {
+ ['dflt'] = 'Default',
+
+ ['arab'] = 'Arabic',
+ ['armn'] = 'Armenian',
+ ['bali'] = 'Balinese',
+ ['beng'] = 'Bengali',
+ ['bopo'] = 'Bopomofo',
+ ['brai'] = 'Braille',
+ ['bugi'] = 'Buginese',
+ ['buhd'] = 'Buhid',
+ ['byzm'] = 'Byzantine Music',
+ ['cans'] = 'Canadian Syllabics',
+ ['cher'] = 'Cherokee',
+ ['copt'] = 'Coptic',
+ ['cprt'] = 'Cypriot Syllabary',
+ ['cyrl'] = 'Cyrillic',
+ ['deva'] = 'Devanagari',
+ ['dsrt'] = 'Deseret',
+ ['ethi'] = 'Ethiopic',
+ ['geor'] = 'Georgian',
+ ['glag'] = 'Glagolitic',
+ ['goth'] = 'Gothic',
+ ['grek'] = 'Greek',
+ ['gujr'] = 'Gujarati',
+ ['guru'] = 'Gurmukhi',
+ ['hang'] = 'Hangul',
+ ['hani'] = 'CJK Ideographic',
+ ['hano'] = 'Hanunoo',
+ ['hebr'] = 'Hebrew',
+ ['ital'] = 'Old Italic',
+ ['jamo'] = 'Hangul Jamo',
+ ['java'] = 'Javanese',
+ ['kana'] = 'Hiragana and Katakana',
+ ['khar'] = 'Kharosthi',
+ ['khmr'] = 'Khmer',
+ ['knda'] = 'Kannada',
+ ['lao' ] = 'Lao',
+ ['latn'] = 'Latin',
+ ['limb'] = 'Limbu',
+ ['linb'] = 'Linear B',
+ ['math'] = 'Mathematical Alphanumeric Symbols',
+ ['mlym'] = 'Malayalam',
+ ['mong'] = 'Mongolian',
+ ['musc'] = 'Musical Symbols',
+ ['mymr'] = 'Myanmar',
+ ['nko' ] = "N'ko",
+ ['ogam'] = 'Ogham',
+ ['orya'] = 'Oriya',
+ ['osma'] = 'Osmanya',
+ ['phag'] = 'Phags-pa',
+ ['phnx'] = 'Phoenician',
+ ['runr'] = 'Runic',
+ ['shaw'] = 'Shavian',
+ ['sinh'] = 'Sinhala',
+ ['sylo'] = 'Syloti Nagri',
+ ['syrc'] = 'Syriac',
+ ['tagb'] = 'Tagbanwa',
+ ['tale'] = 'Tai Le',
+ ['talu'] = 'Tai Lu',
+ ['taml'] = 'Tamil',
+ ['telu'] = 'Telugu',
+ ['tfng'] = 'Tifinagh',
+ ['tglg'] = 'Tagalog',
+ ['thaa'] = 'Thaana',
+ ['thai'] = 'Thai',
+ ['tibt'] = 'Tibetan',
+ ['ugar'] = 'Ugaritic Cuneiform',
+ ['xpeo'] = 'Old Persian Cuneiform',
+ ['xsux'] = 'Sumero-Akkadian Cuneiform',
+ ['yi' ] = 'Yi',
+}
+
+otf.tables.languages = {
+ ['dflt'] = 'Default',
+
+ ['aba'] = 'Abaza',
+ ['abk'] = 'Abkhazian',
+ ['ady'] = 'Adyghe',
+ ['afk'] = 'Afrikaans',
+ ['afr'] = 'Afar',
+ ['agw'] = 'Agaw',
+ ['als'] = 'Alsatian',
+ ['alt'] = 'Altai',
+ ['amh'] = 'Amharic',
+ ['ara'] = 'Arabic',
+ ['ari'] = 'Aari',
+ ['ark'] = 'Arakanese',
+ ['asm'] = 'Assamese',
+ ['ath'] = 'Athapaskan',
+ ['avr'] = 'Avar',
+ ['awa'] = 'Awadhi',
+ ['aym'] = 'Aymara',
+ ['aze'] = 'Azeri',
+ ['bad'] = 'Badaga',
+ ['bag'] = 'Baghelkhandi',
+ ['bal'] = 'Balkar',
+ ['bau'] = 'Baule',
+ ['bbr'] = 'Berber',
+ ['bch'] = 'Bench',
+ ['bcr'] = 'Bible Cree',
+ ['bel'] = 'Belarussian',
+ ['bem'] = 'Bemba',
+ ['ben'] = 'Bengali',
+ ['bgr'] = 'Bulgarian',
+ ['bhi'] = 'Bhili',
+ ['bho'] = 'Bhojpuri',
+ ['bik'] = 'Bikol',
+ ['bil'] = 'Bilen',
+ ['bkf'] = 'Blackfoot',
+ ['bli'] = 'Balochi',
+ ['bln'] = 'Balante',
+ ['blt'] = 'Balti',
+ ['bmb'] = 'Bambara',
+ ['bml'] = 'Bamileke',
+ ['bos'] = 'Bosnian',
+ ['bre'] = 'Breton',
+ ['brh'] = 'Brahui',
+ ['bri'] = 'Braj Bhasha',
+ ['brm'] = 'Burmese',
+ ['bsh'] = 'Bashkir',
+ ['bti'] = 'Beti',
+ ['cat'] = 'Catalan',
+ ['ceb'] = 'Cebuano',
+ ['che'] = 'Chechen',
+ ['chg'] = 'Chaha Gurage',
+ ['chh'] = 'Chattisgarhi',
+ ['chi'] = 'Chichewa',
+ ['chk'] = 'Chukchi',
+ ['chp'] = 'Chipewyan',
+ ['chr'] = 'Cherokee',
+ ['chu'] = 'Chuvash',
+ ['cmr'] = 'Comorian',
+ ['cop'] = 'Coptic',
+ ['cos'] = 'Corsican',
+ ['cre'] = 'Cree',
+ ['crr'] = 'Carrier',
+ ['crt'] = 'Crimean Tatar',
+ ['csl'] = 'Church Slavonic',
+ ['csy'] = 'Czech',
+ ['dan'] = 'Danish',
+ ['dar'] = 'Dargwa',
+ ['dcr'] = 'Woods Cree',
+ ['deu'] = 'German',
+ ['dgr'] = 'Dogri',
+ ['div'] = 'Divehi',
+ ['djr'] = 'Djerma',
+ ['dng'] = 'Dangme',
+ ['dnk'] = 'Dinka',
+ ['dri'] = 'Dari',
+ ['dun'] = 'Dungan',
+ ['dzn'] = 'Dzongkha',
+ ['ebi'] = 'Ebira',
+ ['ecr'] = 'Eastern Cree',
+ ['edo'] = 'Edo',
+ ['efi'] = 'Efik',
+ ['ell'] = 'Greek',
+ ['eng'] = 'English',
+ ['erz'] = 'Erzya',
+ ['esp'] = 'Spanish',
+ ['eti'] = 'Estonian',
+ ['euq'] = 'Basque',
+ ['evk'] = 'Evenki',
+ ['evn'] = 'Even',
+ ['ewe'] = 'Ewe',
+ ['fan'] = 'French Antillean',
+ ['far'] = 'Farsi',
+ ['fin'] = 'Finnish',
+ ['fji'] = 'Fijian',
+ ['fle'] = 'Flemish',
+ ['fne'] = 'Forest Nenets',
+ ['fon'] = 'Fon',
+ ['fos'] = 'Faroese',
+ ['fra'] = 'French',
+ ['fri'] = 'Frisian',
+ ['frl'] = 'Friulian',
+ ['fta'] = 'Futa',
+ ['ful'] = 'Fulani',
+ ['gad'] = 'Ga',
+ ['gae'] = 'Gaelic',
+ ['gag'] = 'Gagauz',
+ ['gal'] = 'Galician',
+ ['gar'] = 'Garshuni',
+ ['gaw'] = 'Garhwali',
+ ['gez'] = "Ge'ez",
+ ['gil'] = 'Gilyak',
+ ['gmz'] = 'Gumuz',
+ ['gon'] = 'Gondi',
+ ['grn'] = 'Greenlandic',
+ ['gro'] = 'Garo',
+ ['gua'] = 'Guarani',
+ ['guj'] = 'Gujarati',
+ ['hai'] = 'Haitian',
+ ['hal'] = 'Halam',
+ ['har'] = 'Harauti',
+ ['hau'] = 'Hausa',
+ ['haw'] = 'Hawaiin',
+ ['hbn'] = 'Hammer-Banna',
+ ['hil'] = 'Hiligaynon',
+ ['hin'] = 'Hindi',
+ ['hma'] = 'High Mari',
+ ['hnd'] = 'Hindko',
+ ['ho'] = 'Ho',
+ ['hri'] = 'Harari',
+ ['hrv'] = 'Croatian',
+ ['hun'] = 'Hungarian',
+ ['hye'] = 'Armenian',
+ ['ibo'] = 'Igbo',
+ ['ijo'] = 'Ijo',
+ ['ilo'] = 'Ilokano',
+ ['ind'] = 'Indonesian',
+ ['ing'] = 'Ingush',
+ ['inu'] = 'Inuktitut',
+ ['iri'] = 'Irish',
+ ['irt'] = 'Irish Traditional',
+ ['isl'] = 'Icelandic',
+ ['ism'] = 'Inari Sami',
+ ['ita'] = 'Italian',
+ ['iwr'] = 'Hebrew',
+ ['jan'] = 'Japanese',
+ ['jav'] = 'Javanese',
+ ['jii'] = 'Yiddish',
+ ['jud'] = 'Judezmo',
+ ['jul'] = 'Jula',
+ ['kab'] = 'Kabardian',
+ ['kac'] = 'Kachchi',
+ ['kal'] = 'Kalenjin',
+ ['kan'] = 'Kannada',
+ ['kar'] = 'Karachay',
+ ['kat'] = 'Georgian',
+ ['kaz'] = 'Kazakh',
+ ['keb'] = 'Kebena',
+ ['kge'] = 'Khutsuri Georgian',
+ ['kha'] = 'Khakass',
+ ['khk'] = 'Khanty-Kazim',
+ ['khm'] = 'Khmer',
+ ['khs'] = 'Khanty-Shurishkar',
+ ['khv'] = 'Khanty-Vakhi',
+ ['khw'] = 'Khowar',
+ ['kik'] = 'Kikuyu',
+ ['kir'] = 'Kirghiz',
+ ['kis'] = 'Kisii',
+ ['kkn'] = 'Kokni',
+ ['klm'] = 'Kalmyk',
+ ['kmb'] = 'Kamba',
+ ['kmn'] = 'Kumaoni',
+ ['kmo'] = 'Komo',
+ ['kms'] = 'Komso',
+ ['knr'] = 'Kanuri',
+ ['kod'] = 'Kodagu',
+ ['koh'] = 'Korean Old Hangul',
+ ['kok'] = 'Konkani',
+ ['kon'] = 'Kikongo',
+ ['kop'] = 'Komi-Permyak',
+ ['kor'] = 'Korean',
+ ['koz'] = 'Komi-Zyrian',
+ ['kpl'] = 'Kpelle',
+ ['kri'] = 'Krio',
+ ['krk'] = 'Karakalpak',
+ ['krl'] = 'Karelian',
+ ['krm'] = 'Karaim',
+ ['krn'] = 'Karen',
+ ['krt'] = 'Koorete',
+ ['ksh'] = 'Kashmiri',
+ ['ksi'] = 'Khasi',
+ ['ksm'] = 'Kildin Sami',
+ ['kui'] = 'Kui',
+ ['kul'] = 'Kulvi',
+ ['kum'] = 'Kumyk',
+ ['kur'] = 'Kurdish',
+ ['kuu'] = 'Kurukh',
+ ['kuy'] = 'Kuy',
+ ['kyk'] = 'Koryak',
+ ['lad'] = 'Ladin',
+ ['lah'] = 'Lahuli',
+ ['lak'] = 'Lak',
+ ['lam'] = 'Lambani',
+ ['lao'] = 'Lao',
+ ['lat'] = 'Latin',
+ ['laz'] = 'Laz',
+ ['lcr'] = 'L-Cree',
+ ['ldk'] = 'Ladakhi',
+ ['lez'] = 'Lezgi',
+ ['lin'] = 'Lingala',
+ ['lma'] = 'Low Mari',
+ ['lmb'] = 'Limbu',
+ ['lmw'] = 'Lomwe',
+ ['lsb'] = 'Lower Sorbian',
+ ['lsm'] = 'Lule Sami',
+ ['lth'] = 'Lithuanian',
+ ['ltz'] = 'Luxembourgish',
+ ['lub'] = 'Luba',
+ ['lug'] = 'Luganda',
+ ['luh'] = 'Luhya',
+ ['luo'] = 'Luo',
+ ['lvi'] = 'Latvian',
+ ['maj'] = 'Majang',
+ ['mak'] = 'Makua',
+ ['mal'] = 'Malayalam Traditional',
+ ['man'] = 'Mansi',
+ ['map'] = 'Mapudungun',
+ ['mar'] = 'Marathi',
+ ['maw'] = 'Marwari',
+ ['mbn'] = 'Mbundu',
+ ['mch'] = 'Manchu',
+ ['mcr'] = 'Moose Cree',
+ ['mde'] = 'Mende',
+ ['men'] = "Me'en",
+ ['miz'] = 'Mizo',
+ ['mkd'] = 'Macedonian',
+ ['mle'] = 'Male',
+ ['mlg'] = 'Malagasy',
+ ['mln'] = 'Malinke',
+ ['mlr'] = 'Malayalam Reformed',
+ ['mly'] = 'Malay',
+ ['mnd'] = 'Mandinka',
+ ['mng'] = 'Mongolian',
+ ['mni'] = 'Manipuri',
+ ['mnk'] = 'Maninka',
+ ['mnx'] = 'Manx Gaelic',
+ ['moh'] = 'Mohawk',
+ ['mok'] = 'Moksha',
+ ['mol'] = 'Moldavian',
+ ['mon'] = 'Mon',
+ ['mor'] = 'Moroccan',
+ ['mri'] = 'Maori',
+ ['mth'] = 'Maithili',
+ ['mts'] = 'Maltese',
+ ['mun'] = 'Mundari',
+ ['nag'] = 'Naga-Assamese',
+ ['nan'] = 'Nanai',
+ ['nas'] = 'Naskapi',
+ ['ncr'] = 'N-Cree',
+ ['ndb'] = 'Ndebele',
+ ['ndg'] = 'Ndonga',
+ ['nep'] = 'Nepali',
+ ['new'] = 'Newari',
+ ['ngr'] = 'Nagari',
+ ['nhc'] = 'Norway House Cree',
+ ['nis'] = 'Nisi',
+ ['niu'] = 'Niuean',
+ ['nkl'] = 'Nkole',
+ ['nko'] = "N'ko",
+ ['nld'] = 'Dutch',
+ ['nog'] = 'Nogai',
+ ['nor'] = 'Norwegian',
+ ['nsm'] = 'Northern Sami',
+ ['nta'] = 'Northern Tai',
+ ['nto'] = 'Esperanto',
+ ['nyn'] = 'Nynorsk',
+ ['oci'] = 'Occitan',
+ ['ocr'] = 'Oji-Cree',
+ ['ojb'] = 'Ojibway',
+ ['ori'] = 'Oriya',
+ ['oro'] = 'Oromo',
+ ['oss'] = 'Ossetian',
+ ['paa'] = 'Palestinian Aramaic',
+ ['pal'] = 'Pali',
+ ['pan'] = 'Punjabi',
+ ['pap'] = 'Palpa',
+ ['pas'] = 'Pashto',
+ ['pgr'] = 'Polytonic Greek',
+ ['pil'] = 'Pilipino',
+ ['plg'] = 'Palaung',
+ ['plk'] = 'Polish',
+ ['pro'] = 'Provencal',
+ ['ptg'] = 'Portuguese',
+ ['qin'] = 'Chin',
+ ['raj'] = 'Rajasthani',
+ ['rbu'] = 'Russian Buriat',
+ ['rcr'] = 'R-Cree',
+ ['ria'] = 'Riang',
+ ['rms'] = 'Rhaeto-Romanic',
+ ['rom'] = 'Romanian',
+ ['roy'] = 'Romany',
+ ['rsy'] = 'Rusyn',
+ ['rua'] = 'Ruanda',
+ ['rus'] = 'Russian',
+ ['sad'] = 'Sadri',
+ ['san'] = 'Sanskrit',
+ ['sat'] = 'Santali',
+ ['say'] = 'Sayisi',
+ ['sek'] = 'Sekota',
+ ['sel'] = 'Selkup',
+ ['sgo'] = 'Sango',
+ ['shn'] = 'Shan',
+ ['sib'] = 'Sibe',
+ ['sid'] = 'Sidamo',
+ ['sig'] = 'Silte Gurage',
+ ['sks'] = 'Skolt Sami',
+ ['sky'] = 'Slovak',
+ ['sla'] = 'Slavey',
+ ['slv'] = 'Slovenian',
+ ['sml'] = 'Somali',
+ ['smo'] = 'Samoan',
+ ['sna'] = 'Sena',
+ ['snd'] = 'Sindhi',
+ ['snh'] = 'Sinhalese',
+ ['snk'] = 'Soninke',
+ ['sog'] = 'Sodo Gurage',
+ ['sot'] = 'Sotho',
+ ['sqi'] = 'Albanian',
+ ['srb'] = 'Serbian',
+ ['srk'] = 'Saraiki',
+ ['srr'] = 'Serer',
+ ['ssl'] = 'South Slavey',
+ ['ssm'] = 'Southern Sami',
+ ['sur'] = 'Suri',
+ ['sva'] = 'Svan',
+ ['sve'] = 'Swedish',
+ ['swa'] = 'Swadaya Aramaic',
+ ['swk'] = 'Swahili',
+ ['swz'] = 'Swazi',
+ ['sxt'] = 'Sutu',
+ ['syr'] = 'Syriac',
+ ['tab'] = 'Tabasaran',
+ ['taj'] = 'Tajiki',
+ ['tam'] = 'Tamil',
+ ['tat'] = 'Tatar',
+ ['tcr'] = 'TH-Cree',
+ ['tel'] = 'Telugu',
+ ['tgn'] = 'Tongan',
+ ['tgr'] = 'Tigre',
+ ['tgy'] = 'Tigrinya',
+ ['tha'] = 'Thai',
+ ['tht'] = 'Tahitian',
+ ['tib'] = 'Tibetan',
+ ['tkm'] = 'Turkmen',
+ ['tmn'] = 'Temne',
+ ['tna'] = 'Tswana',
+ ['tne'] = 'Tundra Nenets',
+ ['tng'] = 'Tonga',
+ ['tod'] = 'Todo',
+ ['trk'] = 'Turkish',
+ ['tsg'] = 'Tsonga',
+ ['tua'] = 'Turoyo Aramaic',
+ ['tul'] = 'Tulu',
+ ['tuv'] = 'Tuvin',
+ ['twi'] = 'Twi',
+ ['udm'] = 'Udmurt',
+ ['ukr'] = 'Ukrainian',
+ ['urd'] = 'Urdu',
+ ['usb'] = 'Upper Sorbian',
+ ['uyg'] = 'Uyghur',
+ ['uzb'] = 'Uzbek',
+ ['ven'] = 'Venda',
+ ['vit'] = 'Vietnamese',
+ ['wa' ] = 'Wa',
+ ['wag'] = 'Wagdi',
+ ['wcr'] = 'West-Cree',
+ ['wel'] = 'Welsh',
+ ['wlf'] = 'Wolof',
+ ['xbd'] = 'Tai Lue',
+ ['xhs'] = 'Xhosa',
+ ['yak'] = 'Yakut',
+ ['yba'] = 'Yoruba',
+ ['ycr'] = 'Y-Cree',
+ ['yic'] = 'Yi Classic',
+ ['yim'] = 'Yi Modern',
+ ['zhh'] = 'Chinese Hong Kong',
+ ['zhp'] = 'Chinese Phonetic',
+ ['zhs'] = 'Chinese Simplified',
+ ['zht'] = 'Chinese Traditional',
+ ['znd'] = 'Zande',
+ ['zul'] = 'Zulu'
+}
+
+otf.tables.features = {
+ ['aalt'] = 'Access All Alternates',
+ ['abvf'] = 'Above-Base Forms',
+ ['abvm'] = 'Above-Base Mark Positioning',
+ ['abvs'] = 'Above-Base Substitutions',
+ ['afrc'] = 'Alternative Fractions',
+ ['akhn'] = 'Akhands',
+ ['blwf'] = 'Below-Base Forms',
+ ['blwm'] = 'Below-Base Mark Positioning',
+ ['blws'] = 'Below-Base Substitutions',
+ ['c2pc'] = 'Petite Capitals From Capitals',
+ ['c2sc'] = 'Small Capitals From Capitals',
+ ['calt'] = 'Contextual Alternates',
+ ['case'] = 'Case-Sensitive Forms',
+ ['ccmp'] = 'Glyph Composition/Decomposition',
+ ['cjct'] = 'Conjunct Forms',
+ ['clig'] = 'Contextual Ligatures',
+ ['cpsp'] = 'Capital Spacing',
+ ['cswh'] = 'Contextual Swash',
+ ['curs'] = 'Cursive Positioning',
+ ['dflt'] = 'Default Processing',
+ ['dist'] = 'Distances',
+ ['dlig'] = 'Discretionary Ligatures',
+ ['dnom'] = 'Denominators',
+ ['dtls'] = 'Dotless Forms', -- math
+ ['expt'] = 'Expert Forms',
+ ['falt'] = 'Final glyph Alternates',
+ ['fin2'] = 'Terminal Forms #2',
+ ['fin3'] = 'Terminal Forms #3',
+ ['fina'] = 'Terminal Forms',
+ ['flac'] = 'Flattened Accents Over Capitals', -- math
+ ['frac'] = 'Fractions',
+ ['fwid'] = 'Full Width',
+ ['half'] = 'Half Forms',
+ ['haln'] = 'Halant Forms',
+ ['halt'] = 'Alternate Half Width',
+ ['hist'] = 'Historical Forms',
+ ['hkna'] = 'Horizontal Kana Alternates',
+ ['hlig'] = 'Historical Ligatures',
+ ['hngl'] = 'Hangul',
+ ['hojo'] = 'Hojo Kanji Forms',
+ ['hwid'] = 'Half Width',
+ ['init'] = 'Initial Forms',
+ ['isol'] = 'Isolated Forms',
+ ['ital'] = 'Italics',
+ ['jalt'] = 'Justification Alternatives',
+ ['jp04'] = 'JIS2004 Forms',
+ ['jp78'] = 'JIS78 Forms',
+ ['jp83'] = 'JIS83 Forms',
+ ['jp90'] = 'JIS90 Forms',
+ ['kern'] = 'Kerning',
+ ['lfbd'] = 'Left Bounds',
+ ['liga'] = 'Standard Ligatures',
+ ['ljmo'] = 'Leading Jamo Forms',
+ ['lnum'] = 'Lining Figures',
+ ['locl'] = 'Localized Forms',
+ ['mark'] = 'Mark Positioning',
+ ['med2'] = 'Medial Forms #2',
+ ['medi'] = 'Medial Forms',
+ ['mgrk'] = 'Mathematical Greek',
+ ['mkmk'] = 'Mark to Mark Positioning',
+ ['mset'] = 'Mark Positioning via Substitution',
+ ['nalt'] = 'Alternate Annotation Forms',
+ ['nlck'] = 'NLC Kanji Forms',
+ ['nukt'] = 'Nukta Forms',
+ ['numr'] = 'Numerators',
+ ['onum'] = 'Old Style Figures',
+ ['opbd'] = 'Optical Bounds',
+ ['ordn'] = 'Ordinals',
+ ['ornm'] = 'Ornaments',
+ ['palt'] = 'Proportional Alternate Width',
+ ['pcap'] = 'Petite Capitals',
+ ['pnum'] = 'Proportional Figures',
+ ['pref'] = 'Pre-base Forms',
+ ['pres'] = 'Pre-base Substitutions',
+ ['pstf'] = 'Post-base Forms',
+ ['psts'] = 'Post-base Substitutions',
+ ['pwid'] = 'Proportional Widths',
+ ['qwid'] = 'Quarter Widths',
+ ['rand'] = 'Randomize',
+ ['rkrf'] = 'Rakar Forms',
+ ['rlig'] = 'Required Ligatures',
+ ['rphf'] = 'Reph Form',
+ ['rtbd'] = 'Right Bounds',
+ ['rtla'] = 'Right-To-Left Alternates',
+ ['rtlm'] = 'Right To Left Math', -- math
+ ['ruby'] = 'Ruby Notation Forms',
+ ['salt'] = 'Stylistic Alternates',
+ ['sinf'] = 'Scientific Inferiors',
+ ['size'] = 'Optical Size',
+ ['smcp'] = 'Small Capitals',
+ ['smpl'] = 'Simplified Forms',
+ ['ss01'] = 'Stylistic Set 1',
+ ['ss02'] = 'Stylistic Set 2',
+ ['ss03'] = 'Stylistic Set 3',
+ ['ss04'] = 'Stylistic Set 4',
+ ['ss05'] = 'Stylistic Set 5',
+ ['ss06'] = 'Stylistic Set 6',
+ ['ss07'] = 'Stylistic Set 7',
+ ['ss08'] = 'Stylistic Set 8',
+ ['ss09'] = 'Stylistic Set 9',
+ ['ss10'] = 'Stylistic Set 10',
+ ['ss11'] = 'Stylistic Set 11',
+ ['ss12'] = 'Stylistic Set 12',
+ ['ss13'] = 'Stylistic Set 13',
+ ['ss14'] = 'Stylistic Set 14',
+ ['ss15'] = 'Stylistic Set 15',
+ ['ss16'] = 'Stylistic Set 16',
+ ['ss17'] = 'Stylistic Set 17',
+ ['ss18'] = 'Stylistic Set 18',
+ ['ss19'] = 'Stylistic Set 19',
+ ['ss20'] = 'Stylistic Set 20',
+ ['ssty'] = 'Script Style', -- math
+ ['subs'] = 'Subscript',
+ ['sups'] = 'Superscript',
+ ['swsh'] = 'Swash',
+ ['titl'] = 'Titling',
+ ['tjmo'] = 'Trailing Jamo Forms',
+ ['tnam'] = 'Traditional Name Forms',
+ ['tnum'] = 'Tabular Figures',
+ ['trad'] = 'Traditional Forms',
+ ['twid'] = 'Third Widths',
+ ['unic'] = 'Unicase',
+ ['valt'] = 'Alternate Vertical Metrics',
+ ['vatu'] = 'Vattu Variants',
+ ['vert'] = 'Vertical Writing',
+ ['vhal'] = 'Alternate Vertical Half Metrics',
+ ['vjmo'] = 'Vowel Jamo Forms',
+ ['vkna'] = 'Vertical Kana Alternates',
+ ['vkrn'] = 'Vertical Kerning',
+ ['vpal'] = 'Proportional Alternate Vertical Metrics',
+ ['vrt2'] = 'Vertical Rotation',
+ ['zero'] = 'Slashed Zero',
+
+ ['trep'] = 'Traditional TeX Replacements',
+ ['tlig'] = 'Traditional TeX Ligatures',
+}
+
+otf.tables.baselines = {
+ ['hang'] = 'Hanging baseline',
+ ['icfb'] = 'Ideographic character face bottom edge baseline',
+ ['icft'] = 'Ideographic character face tope edige baseline',
+ ['ideo'] = 'Ideographic em-box bottom edge baseline',
+ ['idtp'] = 'Ideographic em-box top edge baseline',
+ ['math'] = 'Mathmatical centered baseline',
+ ['romn'] = 'Roman baseline'
+}
+
+-- can be sped up by local tables
+
+function otf.tables.to_tag(id)
+ return stringformat("%4s",lower(id))
+end
+
+local function resolve(tab,id)
+ if tab and id then
+ id = lower(id)
+ return tab[id] or tab[gsub(id," ","")] or tab['dflt'] or ''
+ else
+ return "unknown"
+ end
+end
+
+function otf.meanings.script(id)
+ return resolve(otf.tables.scripts,id)
+end
+function otf.meanings.language(id)
+ return resolve(otf.tables.languages,id)
+end
+function otf.meanings.feature(id)
+ return resolve(otf.tables.features,id)
+end
+function otf.meanings.baseline(id)
+ return resolve(otf.tables.baselines,id)
+end
+
+otf.tables.to_scripts = table.reverse_hash(otf.tables.scripts )
+otf.tables.to_languages = table.reverse_hash(otf.tables.languages)
+otf.tables.to_features = table.reverse_hash(otf.tables.features )
+
+local scripts = otf.tables.scripts
+local languages = otf.tables.languages
+local features = otf.tables.features
+
+local to_scripts = otf.tables.to_scripts
+local to_languages = otf.tables.to_languages
+local to_features = otf.tables.to_features
+
+for k, v in next, to_features do
+ local stripped = gsub(k,"%-"," ")
+ to_features[stripped] = v
+ local stripped = gsub(k,"[^a-zA-Z0-9]","")
+ to_features[stripped] = v
+end
+for k, v in next, to_features do
+ to_features[lower(k)] = v
+end
+
+otf.meanings.checkers = {
+ rand = function(v)
+ return v and "random"
+ end
+}
+
+local checkers = otf.meanings.checkers
+
+function otf.meanings.normalize(features)
+ local h = { }
+ for k,v in next, features do
+ k = lower(k)
+ if k == "language" or k == "lang" then
+ v = gsub(lower(v),"[^a-z0-9%-]","")
+ k = language
+ if not languages[v] then
+ h.language = to_languages[v] or "dflt"
+ else
+ h.language = v
+ end
+ elseif k == "script" then
+ v = gsub(lower(v),"[^a-z0-9%-]","")
+ if not scripts[v] then
+ h.script = to_scripts[v] or "dflt"
+ else
+ h.script = v
+ end
+ else
+ if type(v) == "string" then
+ local b = v:is_boolean()
+ if type(b) == "nil" then
+ v = tonumber(v) or lower(v)
+ else
+ v = b
+ end
+ end
+ k = to_features[k] or k
+ local c = checkers[k]
+ h[k] = c and c(v) or v
+ end
+ end
+ return h
+end
+
+-- When I feel the need ...
+
+--~ otf.tables.aat = {
+--~ [ 0] = {
+--~ name = "allTypographicFeaturesType",
+--~ [ 0] = "allTypeFeaturesOnSelector",
+--~ [ 1] = "allTypeFeaturesOffSelector",
+--~ },
+--~ [ 1] = {
+--~ name = "ligaturesType",
+--~ [0 ] = "requiredLigaturesOnSelector",
+--~ [1 ] = "requiredLigaturesOffSelector",
+--~ [2 ] = "commonLigaturesOnSelector",
+--~ [3 ] = "commonLigaturesOffSelector",
+--~ [4 ] = "rareLigaturesOnSelector",
+--~ [5 ] = "rareLigaturesOffSelector",
+--~ [6 ] = "logosOnSelector ",
+--~ [7 ] = "logosOffSelector ",
+--~ [8 ] = "rebusPicturesOnSelector",
+--~ [9 ] = "rebusPicturesOffSelector",
+--~ [10] = "diphthongLigaturesOnSelector",
+--~ [11] = "diphthongLigaturesOffSelector",
+--~ [12] = "squaredLigaturesOnSelector",
+--~ [13] = "squaredLigaturesOffSelector",
+--~ [14] = "abbrevSquaredLigaturesOnSelector",
+--~ [15] = "abbrevSquaredLigaturesOffSelector",
+--~ },
+--~ [ 2] = {
+--~ name = "cursiveConnectionType",
+--~ [ 0] = "unconnectedSelector",
+--~ [ 1] = "partiallyConnectedSelector",
+--~ [ 2] = "cursiveSelector ",
+--~ },
+--~ [ 3] = {
+--~ name = "letterCaseType",
+--~ [ 0] = "upperAndLowerCaseSelector",
+--~ [ 1] = "allCapsSelector ",
+--~ [ 2] = "allLowerCaseSelector",
+--~ [ 3] = "smallCapsSelector ",
+--~ [ 4] = "initialCapsSelector",
+--~ [ 5] = "initialCapsAndSmallCapsSelector",
+--~ },
+--~ [ 4] = {
+--~ name = "verticalSubstitutionType",
+--~ [ 0] = "substituteVerticalFormsOnSelector",
+--~ [ 1] = "substituteVerticalFormsOffSelector",
+--~ },
+--~ [ 5] = {
+--~ name = "linguisticRearrangementType",
+--~ [ 0] = "linguisticRearrangementOnSelector",
+--~ [ 1] = "linguisticRearrangementOffSelector",
+--~ },
+--~ [ 6] = {
+--~ name = "numberSpacingType",
+--~ [ 0] = "monospacedNumbersSelector",
+--~ [ 1] = "proportionalNumbersSelector",
+--~ },
+--~ [ 7] = {
+--~ name = "appleReserved1Type",
+--~ },
+--~ [ 8] = {
+--~ name = "smartSwashType",
+--~ [ 0] = "wordInitialSwashesOnSelector",
+--~ [ 1] = "wordInitialSwashesOffSelector",
+--~ [ 2] = "wordFinalSwashesOnSelector",
+--~ [ 3] = "wordFinalSwashesOffSelector",
+--~ [ 4] = "lineInitialSwashesOnSelector",
+--~ [ 5] = "lineInitialSwashesOffSelector",
+--~ [ 6] = "lineFinalSwashesOnSelector",
+--~ [ 7] = "lineFinalSwashesOffSelector",
+--~ [ 8] = "nonFinalSwashesOnSelector",
+--~ [ 9] = "nonFinalSwashesOffSelector",
+--~ },
+--~ [ 9] = {
+--~ name = "diacriticsType",
+--~ [ 0] = "showDiacriticsSelector",
+--~ [ 1] = "hideDiacriticsSelector",
+--~ [ 2] = "decomposeDiacriticsSelector",
+--~ },
+--~ [10] = {
+--~ name = "verticalPositionType",
+--~ [ 0] = "normalPositionSelector",
+--~ [ 1] = "superiorsSelector ",
+--~ [ 2] = "inferiorsSelector ",
+--~ [ 3] = "ordinalsSelector ",
+--~ },
+--~ [11] = {
+--~ name = "fractionsType",
+--~ [ 0] = "noFractionsSelector",
+--~ [ 1] = "verticalFractionsSelector",
+--~ [ 2] = "diagonalFractionsSelector",
+--~ },
+--~ [12] = {
+--~ name = "appleReserved2Type",
+--~ },
+--~ [13] = {
+--~ name = "overlappingCharactersType",
+--~ [ 0] = "preventOverlapOnSelector",
+--~ [ 1] = "preventOverlapOffSelector",
+--~ },
+--~ [14] = {
+--~ name = "typographicExtrasType",
+--~ [0 ] = "hyphensToEmDashOnSelector",
+--~ [1 ] = "hyphensToEmDashOffSelector",
+--~ [2 ] = "hyphenToEnDashOnSelector",
+--~ [3 ] = "hyphenToEnDashOffSelector",
+--~ [4 ] = "unslashedZeroOnSelector",
+--~ [5 ] = "unslashedZeroOffSelector",
+--~ [6 ] = "formInterrobangOnSelector",
+--~ [7 ] = "formInterrobangOffSelector",
+--~ [8 ] = "smartQuotesOnSelector",
+--~ [9 ] = "smartQuotesOffSelector",
+--~ [10] = "periodsToEllipsisOnSelector",
+--~ [11] = "periodsToEllipsisOffSelector",
+--~ },
+--~ [15] = {
+--~ name = "mathematicalExtrasType",
+--~ [ 0] = "hyphenToMinusOnSelector",
+--~ [ 1] = "hyphenToMinusOffSelector",
+--~ [ 2] = "asteriskToMultiplyOnSelector",
+--~ [ 3] = "asteriskToMultiplyOffSelector",
+--~ [ 4] = "slashToDivideOnSelector",
+--~ [ 5] = "slashToDivideOffSelector",
+--~ [ 6] = "inequalityLigaturesOnSelector",
+--~ [ 7] = "inequalityLigaturesOffSelector",
+--~ [ 8] = "exponentsOnSelector",
+--~ [ 9] = "exponentsOffSelector",
+--~ },
+--~ [16] = {
+--~ name = "ornamentSetsType",
+--~ [ 0] = "noOrnamentsSelector",
+--~ [ 1] = "dingbatsSelector ",
+--~ [ 2] = "piCharactersSelector",
+--~ [ 3] = "fleuronsSelector ",
+--~ [ 4] = "decorativeBordersSelector",
+--~ [ 5] = "internationalSymbolsSelector",
+--~ [ 6] = "mathSymbolsSelector",
+--~ },
+--~ [17] = {
+--~ name = "characterAlternativesType",
+--~ [ 0] = "noAlternatesSelector",
+--~ },
+--~ [18] = {
+--~ name = "designComplexityType",
+--~ [ 0] = "designLevel1Selector",
+--~ [ 1] = "designLevel2Selector",
+--~ [ 2] = "designLevel3Selector",
+--~ [ 3] = "designLevel4Selector",
+--~ [ 4] = "designLevel5Selector",
+--~ },
+--~ [19] = {
+--~ name = "styleOptionsType",
+--~ [ 0] = "noStyleOptionsSelector",
+--~ [ 1] = "displayTextSelector",
+--~ [ 2] = "engravedTextSelector",
+--~ [ 3] = "illuminatedCapsSelector",
+--~ [ 4] = "titlingCapsSelector",
+--~ [ 5] = "tallCapsSelector ",
+--~ },
+--~ [20] = {
+--~ name = "characterShapeType",
+--~ [0 ] = "traditionalCharactersSelector",
+--~ [1 ] = "simplifiedCharactersSelector",
+--~ [2 ] = "jis1978CharactersSelector",
+--~ [3 ] = "jis1983CharactersSelector",
+--~ [4 ] = "jis1990CharactersSelector",
+--~ [5 ] = "traditionalAltOneSelector",
+--~ [6 ] = "traditionalAltTwoSelector",
+--~ [7 ] = "traditionalAltThreeSelector",
+--~ [8 ] = "traditionalAltFourSelector",
+--~ [9 ] = "traditionalAltFiveSelector",
+--~ [10] = "expertCharactersSelector",
+--~ },
+--~ [21] = {
+--~ name = "numberCaseType",
+--~ [ 0] = "lowerCaseNumbersSelector",
+--~ [ 1] = "upperCaseNumbersSelector",
+--~ },
+--~ [22] = {
+--~ name = "textSpacingType",
+--~ [ 0] = "proportionalTextSelector",
+--~ [ 1] = "monospacedTextSelector",
+--~ [ 2] = "halfWidthTextSelector",
+--~ [ 3] = "normallySpacedTextSelector",
+--~ },
+--~ [23] = {
+--~ name = "transliterationType",
+--~ [ 0] = "noTransliterationSelector",
+--~ [ 1] = "hanjaToHangulSelector",
+--~ [ 2] = "hiraganaToKatakanaSelector",
+--~ [ 3] = "katakanaToHiraganaSelector",
+--~ [ 4] = "kanaToRomanizationSelector",
+--~ [ 5] = "romanizationToHiraganaSelector",
+--~ [ 6] = "romanizationToKatakanaSelector",
+--~ [ 7] = "hanjaToHangulAltOneSelector",
+--~ [ 8] = "hanjaToHangulAltTwoSelector",
+--~ [ 9] = "hanjaToHangulAltThreeSelector",
+--~ },
+--~ [24] = {
+--~ name = "annotationType",
+--~ [ 0] = "noAnnotationSelector",
+--~ [ 1] = "boxAnnotationSelector",
+--~ [ 2] = "roundedBoxAnnotationSelector",
+--~ [ 3] = "circleAnnotationSelector",
+--~ [ 4] = "invertedCircleAnnotationSelector",
+--~ [ 5] = "parenthesisAnnotationSelector",
+--~ [ 6] = "periodAnnotationSelector",
+--~ [ 7] = "romanNumeralAnnotationSelector",
+--~ [ 8] = "diamondAnnotationSelector",
+--~ },
+--~ [25] = {
+--~ name = "kanaSpacingType",
+--~ [ 0] = "fullWidthKanaSelector",
+--~ [ 1] = "proportionalKanaSelector",
+--~ },
+--~ [26] = {
+--~ name = "ideographicSpacingType",
+--~ [ 0] = "fullWidthIdeographsSelector",
+--~ [ 1] = "proportionalIdeographsSelector",
+--~ },
+--~ [103] = {
+--~ name = "cjkRomanSpacingType",
+--~ [ 0] = "halfWidthCJKRomanSelector",
+--~ [ 1] = "proportionalCJKRomanSelector",
+--~ [ 2] = "defaultCJKRomanSelector",
+--~ [ 3] = "fullWidthCJKRomanSelector",
+--~ },
+--~ }
diff --git a/tex/context/base/font-pat.lua b/tex/context/base/font-pat.lua
new file mode 100644
index 000000000..6aba4d47e
--- /dev/null
+++ b/tex/context/base/font-pat.lua
@@ -0,0 +1,126 @@
+if not modules then modules = { } end modules ['font-pat'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local match, lower, find = string.match, string.lower, string.find
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
+-- this will become a per font patch file
+--
+-- older versions of latin modern didn't have the designsize set
+-- so for them we get it from the name
+
+local patches = fonts.otf.enhancers.patches
+
+local function patch(data,filename)
+ if data.design_size == 0 then
+ local ds = match(file.basename(lower(filename)),"(%d+)")
+ if ds then
+ if trace_loading then
+ logs.report("load otf","patching design size (%s)",ds)
+ end
+ data.design_size = tonumber(ds) * 10
+ end
+ end
+ local uni_to_ind = data.map.map
+ if not uni_to_ind[0x391] then
+ -- beware, this is a hack, features for latin often don't apply to greek
+ -- but lm has not much features anyway (and only greek for math)
+ if trace_loading then
+ logs.report("load otf","adding 13 greek capitals")
+ end
+ uni_to_ind[0x391] = uni_to_ind[0x41]
+ uni_to_ind[0x392] = uni_to_ind[0x42]
+ uni_to_ind[0x395] = uni_to_ind[0x45]
+ uni_to_ind[0x397] = uni_to_ind[0x48]
+ uni_to_ind[0x399] = uni_to_ind[0x49]
+ uni_to_ind[0x39A] = uni_to_ind[0x4B]
+ uni_to_ind[0x39C] = uni_to_ind[0x4D]
+ uni_to_ind[0x39D] = uni_to_ind[0x4E]
+ uni_to_ind[0x39F] = uni_to_ind[0x4F]
+ uni_to_ind[0x3A1] = uni_to_ind[0x52]
+ uni_to_ind[0x3A4] = uni_to_ind[0x54]
+ uni_to_ind[0x3A7] = uni_to_ind[0x58]
+ uni_to_ind[0x396] = uni_to_ind[0x5A]
+ end
+ -- better make this into a feature
+ --
+ -- local glyphs = data.glyphs
+ -- for i=0x300,0x36F do
+ -- local c = glyphs[uni_to_ind[i]]
+ -- if c and c.width == 0 then
+ -- local boundingbox = c.boundingbox
+ -- c.width = boundingbox[3] - boundingbox[1]
+ -- end
+ -- end
+end
+
+patches["^lmroman"] = patch
+patches["^lmsans"] = patch
+patches["^lmtypewriter"] = patch
+
+-- for some reason (either it's a bug in the font, or it's
+-- a problem in the library) the palatino arabic fonts don't
+-- have the mkmk features properly set up
+
+local function patch(data,filename)
+ local gpos = data.gpos
+ if gpos then
+ for k=1,#gpos do
+ local v = gpos[k]
+ if not v.features and v.type == "gpos_mark2mark" then
+ if trace_loading then
+ logs.report("load otf","patching mkmk feature (name: %s)", v.name or "?")
+ end
+ v.features = {
+ {
+ scripts = {
+ {
+ langs = { "ARA ", "FAR ", "URD ", "dflt" },
+ script = "arab",
+ },
+ },
+ tag = "mkmk"
+ }
+ }
+ end
+ end
+ end
+end
+
+patches["palatino.*arabic"] = patch
+
+local function patch_domh(data,filename,threshold)
+ local m = data.math
+ if m then
+ local d = m.DisplayOperatorMinHeight or 0
+ if d < threshold then
+ if trace_loading then
+ logs.report("load otf","patching DisplayOperatorMinHeight(%s -> %s)",d,threshold)
+ end
+ m.DisplayOperatorMinHeight = threshold
+ end
+ end
+ if tex.luatexversion < 48 then
+ for _, g in next, data.glyphs do
+ local name = g.name
+ if find(name,"^integral$") or find(name,"^integral%.vsize") then
+ local width, italic = g.width or 0, g.italic_correction or 0
+ local newwidth = width - italic
+ if trace_loading then
+ logs.report("load otf","patching width of %s: %s (width) - %s (italic) = %s",name,width,italic,newwidth)
+ end
+ g.width = newwidth
+ end
+ end
+ end
+end
+
+patches["cambria"] = function(data,filename) patch_domh(data,filename,2800) end
+patches["cambmath"] = function(data,filename) patch_domh(data,filename,2800) end
+patches["asana"] = function(data,filename) patch_domh(data,filename,1350) end
diff --git a/tex/context/base/font-run.mkii b/tex/context/base/font-run.mkii
new file mode 100644
index 000000000..0a0ddd057
--- /dev/null
+++ b/tex/context/base/font-run.mkii
@@ -0,0 +1,326 @@
+%D \module
+%D [ file=font-run,
+%D version=1998.09.11, % (second)
+%D version=2001.02.20, % (third)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Runtime Macros,
+%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.
+
+%D [This code is hooked into the core macros and saves some
+%D format space.]
+
+\unprotect
+
+\gdef\@@onlyenglish#1%
+ {\blank{\tttf \type {#1} is only available in the english interface}\blank}
+
+\gdef\dosetshowfonttitle#1%
+ {\tabskip\zeropoint
+ \parindent\zeropoint
+ \setlocalhsize
+ \doifelsenothing{#1}
+ {\def\title{[\the\bodyfontsize]}}
+ {\switchtobodyfont[#1]\def\title{[#1]}}
+ \doifsomething\fontclass
+ {\doifnot{[\fontclass]}\title
+ {\edef\title{[\fontclass]\space\title}}}}
+
+\gdef\showbodyfont
+ {\dosingleempty\doshowbodyfont}
+
+\gdef\doshowbodyfont[#1]%
+ {\ifinsidefloat\else\startbaselinecorrection\fi
+ \vbox
+ {\dosetshowfonttitle{#1}%
+ \def\bigstrut##1##2%
+ {\hbox{\vrule
+ \!!height##1\strutht
+ \!!depth ##2\strutdp
+ \!!width \zeropoint}}
+ \def\next##1##2##3%
+ {\tf##3\sc##3%
+ \sl##3\it##3\bf##3\bs##3\bi##3%
+ \tfx##3\tfxx##3%
+ \tfa##3\tfb##3\tfc##3\tfd##3&\cr}%
+ \halign to \localhsize
+ {\bigstrut{1.5}{2}##&\vrule##
+ \tabskip=\!!zeropoint \!!plus 1fill
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil#\vrule
+ \tabskip=\!!zeropoint\cr
+ \noalign{\hrule}
+ &\multispan{29}{\vrule\hfil\tttf\strut\title\hfil
+ \llap{\string\mr\hbox to 1em{\hss:\hss}$\mr \languageparameter\c!text$\quad}\vrule}\cr
+ \noalign{\hrule}\next{}{\tt\string}{}
+ \noalign{\hrule}\next{\tt\string\rm}\rm{\languageparameter\c!text}
+ \noalign{\hrule}\next{\tt\string\ss}\ss{\languageparameter\c!text}
+ \noalign{\hrule}\next{\tt\string\tt}\tt{\languageparameter\c!text}
+ \noalign{\hrule}}}
+ \ifinsidefloat\else\stopbaselinecorrection\fi}
+
+\gdef\showbodyfontenvironment
+ {\dosingleempty\doshowbodyfontenvironment}
+
+\gdef\doshowbodyfontenvironment[#1]%
+ {\ifinsidefloat\else\startbaselinecorrection\fi
+ \vbox
+ {\dosetshowfonttitle{#1}%
+ \def\next##1%
+ {&&\getvalue{\bodyfontvariable{##1\s!text}}%
+ &&\getvalue{\bodyfontvariable{##1\s!script}}%
+ &&\getvalue{\bodyfontvariable{##1\s!scriptscript}}%
+ &&\getvalue{\bodyfontvariable{##1\c!x}}%
+ &&\getvalue{\bodyfontvariable{##1\c!xx}}%
+ &&\getvalue{\bodyfontvariable{##1\interfaced\v!small}}%
+ &&\getvalue{\bodyfontvariable{##1\interfaced\v!big}}%
+ &&\edef\next{\getvalue{\bodyfontvariable{##1\c!interlinespace}}}\ifx\next\empty not set\else\next\fi&\cr
+ \noalign{\hrule}}
+ \halign to \localhsize
+ {##&\vrule##\strut
+ \tabskip=\!!zeropoint \!!plus 1fill
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil#\vrule
+ \tabskip\zeropoint\cr
+ \noalign{\hrule}
+ &\multispan{17}{\vrule\hfil\tttf\strut\title\hfil}\vrule\cr
+ \noalign{\hrule}
+ &&\tttf\tx\s!text&&\tttf\tx\s!script&&\tttf\tx\s!scriptscript
+ &&\tttf\tx\c!x&&\tttf\tx\c!xx&&\tttf\tx\v!small&&\tttf\tx\v!big
+ &&\tttf\tx\c!interlinespace&\cr
+ \noalign{\hrule}
+ \@EA\globalprocesscommalist\@EA[\bodyfontenvironmentlist]\next}}
+ \ifinsidefloat\else\stopbaselinecorrection\fi}
+
+\gdef\showfont
+ {\dodoubleempty\doshowfont}
+
+\gdef\doshowfont[#1][#2]%
+ {\bgroup
+ \boxrulewidth=.1pt
+ \setupcolors[\c!state=\v!local]%
+ \iffirstargument
+ \definefont[\s!dummy][#1]\dummy
+ \else\ifdim2.5em>.05\hsize \tx
+ \ifdim2.5em>.05\hsize \txx
+ \fi\fi\fi
+ \ifinsidefloat\else\startbaselinecorrection\fi
+ \vbox\bgroup
+ \forgetall
+ \startoverlay
+ {\vbox
+ {\tf \setstrut \dummy
+ \localcolortrue \offinterlineskip
+ \dostepwiserecurse{0}{15}{1}
+ {\let\row\recurselevel
+ \hbox
+ {\red
+ \dostepwiserecurse{0}{15}{1}
+ {\let\col\recurselevel
+ \@EA\scratchcounter\normaldblquote\hexnumber\row\hexnumber\col\relax
+ \edef\rowcol{\the\scratchcounter}%
+ \iffontchar\font\scratchcounter
+ \setbox\scratchbox\ruledhbox{\black\char\scratchcounter}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \donetrue \else \donefalse
+ \fi
+ \else
+ \setbox\scratchbox\hbox{\gray\vrule\!!width1ex\!!height.5ex\!!depth.5ex}%
+ \fi
+ \startoverlay
+ {\tf\vbox to 2.5em
+ {\vss
+ \hbox to 2.5em
+ {\dummy\ifdim\interwordspace=\zeropoint
+ \setbox\scratchbox\hbox
+ {\raise.5\dp\scratchbox\hbox
+ {\lower.5\ht\scratchbox\copy\scratchbox}}%
+ \ht\scratchbox\zeropoint
+ \dp\scratchbox\zeropoint
+ \else
+ \ht\scratchbox\strutht
+ \dp\scratchbox\strutdp
+ \strut
+ \fi
+ \hss\copy\scratchbox\hss}
+ \vss}}
+ {\tf\vbox to 2.3em
+ {\ifdone
+ \hsize2.4em
+ \blue
+ \edef\theshowfontspecs
+ {\ifnum\hyphenchar\font=\rowcol hyph\else
+ \ifnum\skewchar \font=\rowcol skew\fi\fi}%
+ \tinyfont % after \edef, else wrong font analyzed
+ \doifnot\v!unknown{#2}{{\red\theshowfontspecs}}\hfill\number\rowcol
+ \vfill
+ \octnumber\rowcol\hfill\lchexnumbers\rowcol
+ \par
+ \fi}}
+ \stopoverlay}}}
+ \par}}
+ {\tf\basegrid[\c!nx=16,\c!ny=16,\c!dx=2.5,\c!dy=2.5,\c!unit=em]}
+ \stopoverlay
+ \nointerlineskip
+ \vskip2pt
+ % the \noexpand before \blank is needed for non etex
+ \edef\ascii{name: {\noexpand\black\fontname\font}}
+ \def\do##1##2{\ifx##1\undefined\else\ifx##1\empty\else##2\fi\fi}%
+ \doifelse\v!unknown{#2}
+ {\edef\theshowfontspecs
+ {name: {\noexpand\black\fontname\font}}}
+ {\edef\theshowfontspecs
+ {name: {\noexpand\black\fontname\font}\noexpand\quad
+ \do\currentencoding{encoding: {\noexpand\black\currentencoding\noexpand\quad}}%
+ \do\currentmapping {mapping: {\noexpand\black\currentmapping \noexpand\quad}}%
+ \do\fonthandling {handling: {\noexpand\black\fonthandling }}}}%
+ \tf % also sets em
+ \hbox to 40em{\blue\hfill\tinyfont\setstrut\strut\theshowfontspecs}
+ \egroup
+ \ifinsidefloat\else\stopbaselinecorrection\fi
+ \egroup}
+
+\gdef\showfontstyle
+ {\dotripleempty\doshowfontstyle}
+
+\gdef\doshowfontstyle[#1][#2][#3]%
+ {\ifthirdargument
+ \bgroup
+ \raggedright
+ \switchtobodyfont[#1]
+ \def\dodocommand##1##2%
+ {\starttextrule{\tttf #1 ##1 ##2}
+ \nobreak \getvalue{##2}%
+ \dorecurse{255}
+ {\iffontchar\font\recurselevel\relax
+ \char\recurselevel\relax\space
+ \fi}
+ \par \nobreak
+ \stoptextrule}
+ \def\docommand##1%
+ {\getvalue{##1}\processcommacommand[#3]{\dodocommand{##1}}}
+ \processcommalist[#2]\docommand
+ \egroup
+ \else\ifsecondargument
+ \showfontstyle[#1][#2][\fontalternativelist]% math is gone
+ \else
+ \showfontstyle[#1][\c!rm]\showfontstyle[#1][\c!ss]
+ \showfontstyle[#1][\c!tt]\showfontstyle[#1][\c!mm]
+ \fi\fi}
+
+\gdef\showligature#1%
+ {\hbox{\type{#1}\enspace\red\ruledhbox{\black#1}}}
+
+\gdef\showligatures[#1]%
+ {\ifx\starttabulate\undefined
+ \@@onlyenglish\showligatures
+ \else
+ \bgroup
+ \setupcolors[\c!state=\v!local]%
+ \def\show##1{\hbox{\red\ruledhbox{\black##1}}}%
+ \definefont[\s!dummy][#1]\dummy
+ \starttabulate[|*{9}{c|}]
+ \NC\type{ff}\NC\type{fi}\NC\type{fl}\NC\type{ffi}\NC\type{ffl}\NC
+ \type{``}\NC\type{''}\NC\type{--}\NC\type{---}\NC\NR
+ \NC\show{ff}\NC\show{fi}\NC\show{fl}\NC\show{ffi}\NC\show{ffl}\NC
+ \show{``}\NC\show{''}\NC\show{--}\NC\show{---}\NC\NR
+ \stoptabulate
+ \egroup
+ \fi}
+
+\gdef\showfontstrip
+ {\dosingleempty\doshowfontstrip}
+
+\gdef\doshowfontstrip[#1]%
+ {\ifx\starttabulate\undefined
+ \@@onlyenglish\showfontstrip
+ \else
+ \bgroup
+ \def\dofontstripa##1##2%
+ {\tttf\string##1}
+ \def\dofontstripb##1##2%
+ {\ruledhbox{\switchtobodyfont[#1]##1{##2}}}
+ \def\dofontstripc##1##2%
+ {\setbox\scratchbox\hbox{\switchtobodyfont[#1]##1{##2}}%
+ \tt\tfx\the\ht\scratchbox}%
+ \def\dofontstripd##1##2%
+ {\setbox\scratchbox\hbox{\switchtobodyfont[#1]##1{##2}}%
+ \tt\tfx\the\wd\scratchbox}%
+ \def\fontstrip##1##2##3%
+ {\NC##2\rm{##3}\NC
+ ##2\ss{##3}\NC
+ ##2\tt{##3}\NC
+ ##2\mathematics{##3}\NC
+ \tttf##1\NR}
+ \starttabulate[|c|c|c|c|c|]
+ \fontstrip\relax\dofontstripa\empty
+ \TB
+ \fontstrip\relax\dofontstripb{xxxx}
+ \fontstrip\relax\dofontstripb{12345}
+ \fontstrip\relax\dofontstripb{(Agw)}
+ \TB
+ \fontstrip{(x height)}\dofontstripc{x}
+ \fontstrip{(m width)}\dofontstripd{m}
+ \stoptabulate
+ \egroup
+ \fi}
+
+\ifx\databox\undefined \newbox\databox \fi
+
+\gdef\testminimalbaseline#1%
+ {\setbox\databox\ruledhbox{#1}%
+ \scratchdimen\ht\databox
+ \advance\scratchdimen\dp\databox
+ \scratchtoks{#1}%
+ \expanded
+ {\NC \ruledhbox{\the\scratchtoks}
+ \noexpand \NC ->
+ \noexpand \NC \the\scratchdimen
+ \noexpand \NC =
+ \noexpand \NC \the\ht\databox
+ \noexpand \NC +
+ \noexpand \NC \the\dp\databox
+ \noexpand \NC \ifdim\scratchdimen<\baselineskip <
+ \else\ifdim\scratchdimen=\baselineskip =
+ \else > \fi\fi
+ \noexpand \NC \the\baselineskip
+ \noexpand \NC (\ifdim\scratchdimen>\baselineskip not \fi ok)
+ \noexpand \NC \noexpand \NR }}
+
+\gdef\showminimalbaseline
+ {\ifx\starttabulate\undefined
+ \@@onlyenglish\showminimalbaseline
+ \else
+ \starttabulate[||T|T|T|T|T|T|T|T|T|]
+ \testminimalbaseline{\hbox to 1em{\hss\showstruts\strut\hss}}%
+ \testminimalbaseline{(/)}%
+ \testminimalbaseline{$\frac{1}{2}x^2_3$}
+ \stoptabulate
+ \fi}
+
+\gdef\showkerning#1%
+ {\bgroup
+ \let\MPfshowcommand\ruledhbox
+ \setMPtext\s!dummy{#1}%
+ \startMPcode draw textext(\MPstring\s!dummy);\stopMPcode
+ \egroup}
+
+\gdef\showcharratio
+ {\dowithnextboxcontent
+ {\switchtobodyfont[10pt]}%
+ {(\expanded{\withoutpt\the\nextboxht},%
+ \expanded{\withoutpt\the\nextboxdp})}%
+ \hbox}
+
+\protect \endinput
diff --git a/tex/context/base/font-run.mkiv b/tex/context/base/font-run.mkiv
new file mode 100644
index 000000000..aad6bebe8
--- /dev/null
+++ b/tex/context/base/font-run.mkiv
@@ -0,0 +1,337 @@
+%D \module
+%D [ file=font-run,
+%D version=1998.09.11, % (second)
+%D version=2001.02.20, % (third)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Runtime Macros,
+%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.
+
+%D [This code is hooked into the core macros and saves some
+%D format space.]
+
+\unprotect
+
+\gdef\@@onlyenglish#1%
+ {\blank{\tttf \type {#1} is only available in the english interface}\blank}
+
+\gdef\dosetshowfonttitle#1%
+ {\tabskip\zeropoint
+ \parindent\zeropoint
+ \setlocalhsize
+ \doifelsenothing{#1}
+ {\def\title{[\the\bodyfontsize]}}
+ {\switchtobodyfont[#1]\def\title{[#1]}}
+ \doifsomething\fontclass
+ {\doifnot{[\fontclass]}\title
+ {\edef\title{[\fontclass]\space\title}}}}
+
+\gdef\showbodyfont
+ {\dosingleempty\doshowbodyfont}
+
+\gdef\doshowbodyfont[#1]%
+ {\ifinsidefloat\else\startbaselinecorrection\fi
+ \vbox
+ {\dosetshowfonttitle{#1}%
+ \def\bigstrut##1##2%
+ {\hbox{\vrule
+ \!!height##1\strutht
+ \!!depth ##2\strutdp
+ \!!width \zeropoint}}
+ \def\next##1##2##3%
+ {\tf##3\sc##3%
+ \sl##3\it##3\bf##3\bs##3\bi##3%
+ \tfx##3\tfxx##3%
+ \tfa##3\tfb##3\tfc##3\tfd##3&\cr}%
+ \halign to \localhsize
+ {\bigstrut{1.5}{2}##&\vrule##
+ \tabskip=\!!zeropoint \!!plus 1fill
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil#\vrule
+ \tabskip=\!!zeropoint\cr
+ \noalign{\hrule}
+ &\multispan{29}{\vrule\hfil\tttf\strut\title\hfil
+ \llap{\string\mr\hbox to 1em{\hss:\hss}$\mr \languageparameter\c!text$\quad}\vrule}\cr
+ \noalign{\hrule}\next{}{\tt\string}{}
+ \noalign{\hrule}\next{\tt\string\rm}\rm{\languageparameter\c!text}
+ \noalign{\hrule}\next{\tt\string\ss}\ss{\languageparameter\c!text}
+ \noalign{\hrule}\next{\tt\string\tt}\tt{\languageparameter\c!text}
+ \noalign{\hrule}}}
+ \ifinsidefloat\else\stopbaselinecorrection\fi}
+
+\gdef\showbodyfontenvironment
+ {\dosingleempty\doshowbodyfontenvironment}
+
+\gdef\doshowbodyfontenvironment[#1]%
+ {\ifinsidefloat\else\startbaselinecorrection\fi
+ \vbox
+ {\dosetshowfonttitle{#1}%
+ \def\next##1%
+ {&&\getvalue{\bodyfontvariable{##1\s!text}}%
+ &&\getvalue{\bodyfontvariable{##1\s!script}}%
+ &&\getvalue{\bodyfontvariable{##1\s!scriptscript}}%
+ &&\getvalue{\bodyfontvariable{##1\c!x}}%
+ &&\getvalue{\bodyfontvariable{##1\c!xx}}%
+ &&\getvalue{\bodyfontvariable{##1\interfaced\v!small}}%
+ &&\getvalue{\bodyfontvariable{##1\interfaced\v!big}}%
+ &&\edef\next{\getvalue{\bodyfontvariable{##1\c!interlinespace}}}\ifx\next\empty not set\else\next\fi&\cr
+ \noalign{\hrule}}
+ \halign to \localhsize
+ {##&\vrule##\strut
+ \tabskip=\!!zeropoint \!!plus 1fill
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##&\hfil##\hfil&\vrule##
+ &\hfil##\hfil&\vrule##&\hfil##\hfil#\vrule
+ \tabskip\zeropoint\cr
+ \noalign{\hrule}
+ &\multispan{17}{\vrule\hfil\tttf\strut\title\hfil}\vrule\cr
+ \noalign{\hrule}
+ &&\tttf\tx\s!text&&\tttf\tx\s!script&&\tttf\tx\s!scriptscript
+ &&\tttf\tx\c!x&&\tttf\tx\c!xx&&\tttf\tx\v!small&&\tttf\tx\v!big
+ &&\tttf\tx\c!interlinespace&\cr
+ \noalign{\hrule}
+ \@EA\globalprocesscommalist\@EA[\bodyfontenvironmentlist]\next}}
+ \ifinsidefloat\else\stopbaselinecorrection\fi}
+
+\gdef\showfont
+ {\dodoubleempty\doshowfont}
+
+\gdef\doshowfont[#1][#2]%
+ {\bgroup
+ \iffirstargument
+ \definefont[\s!dummy][#1]\dummy
+ \fi
+ \doifelsenothing{#2}
+ {\dodoshowfont{#1}{0}}
+ {\doifelse{#2}\v!all
+ {\dostepwiserecurse{0}{255}{1}
+ {\donefalse
+ \let\charplane\recurselevel
+ \dostepwiserecurse{0}{255}{1}
+ {\iffontchar\font\numexpr\charplane*256+\recurselevel\relax
+ \donetrue
+ \exitloop
+ \fi}%
+ \ifdone
+ \dodoshowfont{#1}\charplane
+ \fi}}
+ {\processcommalist[#2]{\dodoshowfont{#1}}}}%
+ \egroup}
+
+\gdef\dodoshowfont#1#2%
+ {\bgroup
+ \edef\charplane{\number#2}%
+ \boxrulewidth=.1pt
+ \iffirstargument
+% \definefont[\s!dummy][#1]\dummy
+ \else\ifdim2.5em>.05\hsize \tx
+ \ifdim2.5em>.05\hsize \txx
+ \fi\fi\fi
+ \ifinsidefloat\else\startbaselinecorrection\fi
+ \vbox\bgroup
+ \forgetall
+ \startoverlay
+ {\vbox
+ {\tf \setstrut \dummy
+ \offinterlineskip
+ \dostepwiserecurse{0}{15}{1}
+ {\let\row\recurselevel
+ \hbox
+ {\red
+ \dostepwiserecurse{0}{15}{1}
+ {\let\col\recurselevel
+ \@EA\scratchcounter\string"\hexnumber\row\hexnumber\col\relax
+ \edef\rowcol{\the\scratchcounter}%
+ \iffontchar\font\scratchcounter
+ \setbox\scratchbox\ruledhbox{\black\char\numexpr\charplane*256+\scratchcounter\relax}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \donetrue \else \donefalse
+ \fi
+ \else
+ \setbox\scratchbox\hbox{\gray\vrule\!!width1ex\!!height.5ex\!!depth.5ex}%
+ \fi
+ \startoverlay
+ {\tf\vbox to 2.5em
+ {\vss
+ \hbox to 2.5em
+ {\dummy\ifdim\interwordspace=\zeropoint
+ \setbox\scratchbox\hbox
+ {\raise.5\dp\scratchbox\hbox
+ {\lower.5\ht\scratchbox\copy\scratchbox}}%
+ \ht\scratchbox\zeropoint
+ \dp\scratchbox\zeropoint
+ \else
+ \ht\scratchbox\strutht
+ \dp\scratchbox\strutdp
+ \strut
+ \fi
+ \hss\copy\scratchbox\hss}
+ \vss}}
+ {\tf\vbox to 2.3em
+ {\ifdone
+ \hsize2.4em
+ \blue
+ \tinyfont
+ \hfill\number\rowcol
+ \vfill
+ \octnumber\rowcol\hfill\lchexnumbers\rowcol
+ \par
+ \fi}}
+ \stopoverlay}}}
+ \par}}
+ {\tf\basegrid[\c!nx=16,\c!ny=16,\c!dx=2.5,\c!dy=2.5,\c!unit=em]}
+ \stopoverlay
+ \nointerlineskip
+ \vskip2pt
+ % the \noexpand before \blank is needed for non etex
+ \edef\ascii{name: {\noexpand\black\fontname\font}}
+ \def\do##1##2{\ifx##1\undefined\else\ifx##1\empty\else##2\fi\fi}%
+ \edef\theshowfontspecs{name: {\noexpand\black\fontname\font}\quad plane: \charplane\enspace"\hexnumber\charplane}%
+ \tf % also sets em
+ \hbox to 40em{\blue\hfill\tinyfont\setstrut\strut\theshowfontspecs}
+ \egroup
+ \ifinsidefloat\else\stopbaselinecorrection\fi
+ \egroup}
+
+\gdef\showfontstyle
+ {\dotripleempty\doshowfontstyle}
+
+\gdef\doshowfontstyle[#1][#2][#3]%
+ {\ifthirdargument
+ \bgroup
+ \raggedright
+ \switchtobodyfont[#1]
+ \def\dodocommand##1##2%
+ {\starttextrule{\tttf #1 ##1 ##2}
+ \nobreak \getvalue{##2}%
+ \dorecurse{255}
+ {\iffontchar\font\recurselevel\relax
+ \char\recurselevel\relax\space
+ \fi}
+ \par \nobreak
+ \stoptextrule}
+ \def\docommand##1%
+ {\getvalue{##1}\processcommacommand[#3]{\dodocommand{##1}}}
+ \processcommalist[#2]\docommand
+ \egroup
+ \else\ifsecondargument
+ \showfontstyle[#1][#2][\fontalternativelist]% math is gone
+ \else
+ \showfontstyle[#1][\c!rm]\showfontstyle[#1][\c!ss]
+ \showfontstyle[#1][\c!tt]\showfontstyle[#1][\c!mm]
+ \fi\fi}
+
+\gdef\showligature#1%
+ {\hbox{\type{#1}\enspace\red\ruledhbox{\black#1}}}
+
+\gdef\showligatures[#1]%
+ {\ifx\starttabulate\undefined
+ \@@onlyenglish\showligatures
+ \else
+ \bgroup
+ \def\show##1{\hbox{\red\ruledhbox{\black##1}}}%
+ \definefont[\s!dummy][#1]\dummy
+ \starttabulate[|*{9}{c|}]
+ \NC\type{ff}\NC\type{fi}\NC\type{fl}\NC\type{ffi}\NC\type{ffl}\NC
+ \type{``}\NC\type{''}\NC\type{--}\NC\type{---}\NC\NR
+ \NC\show{ff}\NC\show{fi}\NC\show{fl}\NC\show{ffi}\NC\show{ffl}\NC
+ \show{``}\NC\show{''}\NC\show{--}\NC\show{---}\NC\NR
+ \stoptabulate
+ \egroup
+ \fi}
+
+\gdef\showfontstrip
+ {\dosingleempty\doshowfontstrip}
+
+\gdef\doshowfontstrip[#1]%
+ {\ifx\starttabulate\undefined
+ \@@onlyenglish\showfontstrip
+ \else
+ \bgroup
+ \def\dofontstripa##1##2%
+ {\tttf\string##1}
+ \def\dofontstripb##1##2%
+ {\ruledhbox{\switchtobodyfont[#1]##1{##2}}}
+ \def\dofontstripc##1##2%
+ {\setbox\scratchbox\hbox{\switchtobodyfont[#1]##1{##2}}%
+ \tt\tfx\the\ht\scratchbox}%
+ \def\dofontstripd##1##2%
+ {\setbox\scratchbox\hbox{\switchtobodyfont[#1]##1{##2}}%
+ \tt\tfx\the\wd\scratchbox}%
+ \def\fontstrip##1##2##3%
+ {\NC##2\rm{##3}\NC
+ ##2\ss{##3}\NC
+ ##2\tt{##3}\NC
+ ##2\mathematics{##3}\NC
+ \tttf##1\NR}
+ \starttabulate[|c|c|c|c|c|]
+ \fontstrip\relax\dofontstripa\empty
+ \TB
+ \fontstrip\relax\dofontstripb{xxxx}
+ \fontstrip\relax\dofontstripb{12345}
+ \fontstrip\relax\dofontstripb{(Agw)}
+ \TB
+ \fontstrip{(x height)}\dofontstripc{x}
+ \fontstrip{(m width)}\dofontstripd{m}
+ \stoptabulate
+ \egroup
+ \fi}
+
+\ifx\databox\undefined \newbox\databox \fi
+
+\gdef\testminimalbaseline#1%
+ {\setbox\databox\ruledhbox{#1}%
+ \scratchdimen\ht\databox
+ \advance\scratchdimen\dp\databox
+ \scratchtoks{#1}%
+ \expanded
+ {\NC \ruledhbox{\the\scratchtoks}
+ \noexpand \NC ->
+ \noexpand \NC \the\scratchdimen
+ \noexpand \NC =
+ \noexpand \NC \the\ht\databox
+ \noexpand \NC +
+ \noexpand \NC \the\dp\databox
+ \noexpand \NC \ifdim\scratchdimen<\baselineskip <
+ \else\ifdim\scratchdimen=\baselineskip =
+ \else > \fi\fi
+ \noexpand \NC \the\baselineskip
+ \noexpand \NC (\ifdim\scratchdimen>\baselineskip not \fi ok)
+ \noexpand \NC \noexpand \NR }}
+
+\gdef\showminimalbaseline
+ {\ifx\starttabulate\undefined
+ \@@onlyenglish\showminimalbaseline
+ \else
+ \starttabulate[||T|T|T|T|T|T|T|T|T|]
+ \testminimalbaseline{\hbox to 1em{\hss\showstruts\strut\hss}}%
+ \testminimalbaseline{(/)}%
+ \testminimalbaseline{$\frac{1}{2}x^2_3$}
+ \stoptabulate
+ \fi}
+
+\gdef\showkerning#1%
+ {\bgroup
+ \let\MPfshowcommand\ruledhbox
+ \setMPtext\s!dummy{#1}%
+ \startMPcode draw textext(\MPstring\s!dummy);\stopMPcode
+ \egroup}
+
+\gdef\showcharratio
+ {\dowithnextboxcontent
+ {\switchtobodyfont[10pt]}%
+ {(\expanded{\withoutpt\the\nextboxht},%
+ \expanded{\withoutpt\the\nextboxdp})}%
+ \hbox}
+
+\protect \endinput
diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua
new file mode 100644
index 000000000..5ad92e002
--- /dev/null
+++ b/tex/context/base/font-syn.lua
@@ -0,0 +1,1454 @@
+if not modules then modules = { } end modules ['font-syn'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: subs in lookups requests
+
+local utf = unicode.utf8
+local next, tonumber = next, tonumber
+local gsub, lower, match, find, lower, upper = string.gsub, string.lower, string.match, string.find, string.lower, string.upper
+local find, gmatch = string.find, string.gmatch
+local concat, sort, format = table.concat, table.sort, string.format
+local lpegmatch = lpeg.match
+local utfgsub, utflower = utf.gsub, utf.lower
+local unpack = unpack or table.unpack
+
+local trace_names = false trackers.register("fonts.names", function(v) trace_names = v end)
+local trace_warnings = false trackers.register("fonts.warnings", function(v) trace_warnings = v end)
+
+--[[ldx--
+
This module implements a name to filename resolver. Names are resolved
+using a table that has keys filtered from the font related files.
+--ldx]]--
+
+local texsprint = (tex and tex.sprint) or print
+
+fonts = fonts or { }
+input = input or { }
+texmf = texmf or { }
+
+fonts.names = fonts.names or { }
+fonts.names.filters = fonts.names.filters or { }
+fonts.names.data = fonts.names.data or { }
+
+local names = fonts.names
+local filters = fonts.names.filters
+
+names.version = 1.103
+names.basename = "names"
+names.saved = false
+names.loaded = false
+names.be_clever = true
+names.enabled = true
+names.autoreload = toboolean(os.env['MTX.FONTS.AUTOLOAD'] or os.env['MTX_FONTS_AUTOLOAD'] or "no")
+names.cache = containers.define("fonts","data",names.version,true)
+
+--[[ldx--
+
A few helpers.
+--ldx]]--
+
+local P, C, Cc, Cs, Carg = lpeg.P, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg
+
+-- what to do with 'thin'
+
+local weights = Cs ( -- not extra
+ P("demibold")
+ + P("semibold")
+ + P("mediumbold")
+ + P("ultrabold")
+ + P("extrabold")
+ + P("ultralight")
+ + P("bold")
+ + P("demi")
+ + P("semi")
+ + P("light")
+ + P("medium")
+ + P("heavy")
+ + P("ultra")
+ + P("black")
+ + P("bol") -- / "bold"
+ + P("regular") / "normal"
+)
+
+local styles = Cs (
+ P("reverseoblique") / "reverseitalic"
+ + P("regular") / "normal"
+ + P("italic")
+ + P("oblique") / "italic"
+ + P("slanted")
+ + P("roman") / "normal"
+ + P("ital") / "italic"
+ + P("ita") / "italic"
+)
+
+local widths = Cs(
+ P("condensed")
+ + P("thin")
+ + P("expanded")
+ + P("cond") / "condensed"
+ + P("normal")
+ + P("book") / "normal"
+)
+
+local variants = Cs( -- fax casual
+ P("smallcaps")
+ + P("oldstyle")
+ + P("caps") / "smallcaps"
+)
+
+local any = P(1)
+
+local analysed_table
+
+local analyser = Cs (
+ (
+ weights / function(s) analysed_table[1] = s return "" end
+ + styles / function(s) analysed_table[2] = s return "" end
+ + widths / function(s) analysed_table[3] = s return "" end
+ + variants / function(s) analysed_table[4] = s return "" end
+ + any
+ )^0
+)
+
+local splitter = lpeg.splitat("-")
+
+function names.splitspec(askedname)
+ local name, weight, style, width, variant = lpegmatch(splitter,askedname)
+ weight = weight and lpegmatch(weights, weight) or weight
+ style = style and lpegmatch(styles, style) or style
+ width = width and lpegmatch(widths, width) or width
+ variant = variant and lpegmatch(variants,variant) or variant
+ if trace_names then
+ logs.report("fonts","requested name '%s' split in name '%s', weight '%s', style '%s', width '%s' and variant '%s'",
+ askedname,name or '',weight or '',style or '',width or '',variant or '')
+ end
+ if not weight or not weight or not width or not variant then
+ weight, style, width, variant = weight or "normal", style or "normal", width or "normal", variant or "normal"
+ if trace_names then
+ logs.report("fonts","request '%s' normalized to '%s-%s-%s-%s-%s'",
+ askedname,name,weight,style,width,variant)
+ end
+ end
+ return name or askedname, weight, style, width, variant
+end
+
+local function analysespec(somename)
+ if somename then
+ analysed_table = { }
+ local name = lpegmatch(analyser,somename)
+ return name, analysed_table[1], analysed_table[2], analysed_table[3], analysed_table[4]
+ end
+end
+
+--[[ldx--
+
It would make sense to implement the filters in the related modules,
+but to keep the overview, we define them here.
+--ldx]]--
+
+filters.otf = fontloader.info
+filters.ttf = fontloader.info
+filters.ttc = fontloader.info
+filters.dfont = fontloader.info
+
+function fontloader.fullinfo(...)
+ local ff = fontloader.open(...)
+ if ff then
+ local d = ff and fontloader.to_table(ff)
+ d.glyphs, d.subfonts, d.gpos, d.gsub, d.lookups = nil, nil, nil, nil, nil
+ fontloader.close(ff)
+ return d
+ else
+ return nil, "error in loading font"
+ end
+end
+
+filters.otf = fontloader.fullinfo
+
+function filters.afm(name)
+ -- we could parse the afm file as well, and then report an error but
+ -- it's not worth the trouble
+ local pfbname = resolvers.find_file(file.removesuffix(name)..".pfb","pfb") or ""
+ if pfbname == "" then
+ pfbname = resolvers.find_file(file.removesuffix(file.basename(name))..".pfb","pfb") or ""
+ end
+ if pfbname ~= "" then
+ local f = io.open(name)
+ if f then
+ local hash = { }
+ for line in f:lines() do
+ local key, value = match(line,"^(.+)%s+(.+)%s*$")
+ if key and #key > 0 then
+ hash[lower(key)] = value
+ end
+ if find(line,"StartCharMetrics") then
+ break
+ end
+ end
+ f:close()
+ return hash
+ end
+ end
+ return nil, "no matching pfb file"
+end
+
+function filters.pfb(name)
+ return fontloader.info(name)
+end
+
+--[[ldx--
+
The scanner loops over the filters using the information stored in
+the file databases. Watch how we check not only for the names, but also
+for combination with the weight of a font.
+--ldx]]--
+
+filters.list = {
+ "otf", "ttf", "ttc", "dfont", "afm",
+--~ "ttc", "otf", "ttf", "dfont", "afm",
+}
+
+names.xml_configuration_file = "fonts.conf" -- a bit weird format, bonus feature
+names.environment_path_variable = "OSFONTDIR" -- the official way, in minimals etc
+
+filters.paths = { }
+filters.names = { }
+
+function names.getpaths(trace)
+ local hash, result = { }, { }
+ local function collect(t)
+ for i=1, #t do
+ local v = resolvers.clean_path(t[i])
+ v = gsub(v,"/+$","")
+ local key = lower(v)
+ if not hash[key] then
+ hash[key], result[#result+1] = true, v
+ end
+ end
+ end
+ local path = names.environment_path_variable or ""
+ if path ~= "" then
+ collect(resolvers.expanded_path_list(path))
+ end
+ if xml then
+ local confname = names.xml_configuration_file or ""
+ if confname ~= "" then
+ -- first look in the tex tree
+ local name = resolvers.find_file(confname,"other")
+ if name == "" then
+ -- after all, fontconfig is a unix thing
+ name = file.join("/etc",confname)
+ if not lfs.isfile(name) then
+ name = "" -- force quit
+ end
+ end
+ if name ~= "" and lfs.isfile(name) then
+ if trace_names then
+ logs.report("fontnames","loading fontconfig file: %s",name)
+ end
+ local xmldata = xml.load(name)
+ -- begin of untested mess
+ xml.include(xmldata,"include","",true,function(incname)
+ if not file.is_qualified_path(incname) then
+ local path = file.dirname(name) -- main name
+ if path ~= "" then
+ incname = file.join(path,incname)
+ end
+ end
+ if lfs.isfile(incname) then
+ if trace_names then
+ logs.report("fontnames","merging included fontconfig file: %s",incname)
+ end
+ return io.loaddata(incname)
+ elseif trace_names then
+ logs.report("fontnames","ignoring included fontconfig file: %s",incname)
+ end
+ end)
+ -- end of untested mess
+ local fontdirs = xml.collect_texts(xmldata,"dir",true)
+ if trace_names then
+ logs.report("fontnames","%s dirs found in fontconfig",#fontdirs)
+ end
+ collect(fontdirs)
+ end
+ end
+ end
+ function names.getpaths()
+ return result
+ end
+ return result
+end
+
+local function cleanname(name)
+ return (gsub(lower(name),"[^%a%d]",""))
+ -- once we can load files with utf names, we can play with the following:
+ -- return (utfgsub(utfgsub(lower(str),"[^%a%A%d]",""),"%s",""))
+end
+
+names.cleanname = cleanname
+
+local function check_names(result)
+ local names = result.names
+ if names then
+ for i=1,#names do
+ local name = names[i]
+ if name.lang == "English (US)" then
+ return name.names
+ end
+ end
+ end
+end
+
+local function walk_tree(pathlist,suffix,identify)
+ if pathlist then
+ for i=1,#pathlist do
+ local path = pathlist[i]
+ path = resolvers.clean_path(path .. "/")
+ path = gsub(path,"/+","/")
+ local pattern = path .. "**." .. suffix -- ** forces recurse
+ logs.report("fontnames", "globbing path %s",pattern)
+ local t = dir.glob(pattern)
+ sort(t,sorter)
+ for j=1,#t do
+ local completename = t[j]
+ identify(completename,file.basename(completename),suffix,completename)
+ end
+ end
+ end
+end
+
+local function check_name(data,result,filename,suffix,subfont)
+ -- shortcuts
+ local specifications = data.specifications
+ local families = data.families
+ -- prepare
+ local names = check_names(result)
+ -- fetch
+ local familyname = (names and names.preffamilyname) or result.familyname
+ local fullname = (names and names.fullname) or result.fullname
+ local fontname = result.fontname
+ local subfamily = (names and names.subfamily)
+ local modifiers = (names and names.prefmodifiers)
+ local weight = (names and names.weight) or result.weight
+ local italicangle = tonumber(result.italicangle)
+ local subfont = subfont or nil
+ local rawname = fullname or fontname or familyname
+ -- normalize
+ familyname = familyname and cleanname(familyname)
+ fullname = fullname and cleanname(fullname)
+ fontname = fontname and cleanname(fontname)
+ subfamily = subfamily and cleanname(subfamily)
+ modifiers = modifiers and cleanname(modifiers)
+ weight = weight and cleanname(weight)
+ italicangle = (italicangle == 0) and nil
+ -- analyse
+ local a_name, a_weight, a_style, a_width, a_variant = analysespec(fullname or fontname or familyname)
+ -- check
+ local width = a_width
+ local variant = a_variant
+ local style = modifiers and gsub(modifiers,"[^%a]","")
+ if not style and italicangle then
+ style = "italic"
+ end
+ if not variant or variant == "" then
+ variant = "normal"
+ end
+ if not weight or weight == "" then
+ weight = a_weight
+ end
+ if not style or style == "" then
+ style = a_style
+ end
+ if not familyname then
+ familyname = a_name
+ end
+ fontname = fontname or fullname or familyname or file.basename(filename)
+ fullname = fullname or fontname
+ familyname = familyname or fontname
+ specifications[#specifications + 1] = {
+ filename = filename,
+ format = lower(suffix),
+ subfont = subfont,
+ rawname = rawname,
+ familyname = familyname,
+ fullname = fullname,
+ fontname = fontname,
+ subfamily = subfamily,
+ modifiers = modifiers,
+ weight = weight,
+ style = style,
+ width = width,
+ variant = variant,
+ minsize = result.design_range_bottom or 0,
+ maxsize = result.design_range_top or 0,
+ designsize = result.design_size or 0,
+ }
+end
+
+local function cleanupkeywords()
+ local data = names.data
+ local specifications = names.data.specifications
+ if specifications then
+ local weights, styles, widths, variants = { }, { }, { }, { }
+ for i=1,#specifications do
+ local s = specifications[i]
+ -- fix (sofar styles are taken from the name, and widths from the specification)
+ local _, b_weight, b_style, b_width, b_variant = analysespec(s.weight)
+ local _, c_weight, c_style, c_width, c_variant = analysespec(s.style)
+ local _, d_weight, d_style, d_width, d_variant = analysespec(s.width)
+ local _, e_weight, e_style, e_width, e_variant = analysespec(s.variant)
+ local _, f_weight, f_style, f_width, f_variant = analysespec(s.fullname or "")
+ local weight = b_weight or c_weight or d_weight or e_weight or f_weight or "normal"
+ local style = b_style or c_style or d_style or e_style or f_style or "normal"
+ local width = b_width or c_width or d_width or e_width or f_width or "normal"
+ local variant = b_variant or c_variant or d_variant or e_variant or f_variant or "normal"
+ if not weight or weight == "" then weight = "normal" end
+ if not style or style == "" then style = "normal" end
+ if not width or width == "" then width = "normal" end
+ if not variant or variant == "" then variant = "normal" end
+ weights [weight ] = (weights [weight ] or 0) + 1
+ styles [style ] = (styles [style ] or 0) + 1
+ widths [width ] = (widths [width ] or 0) + 1
+ variants[variant] = (variants[variant] or 0) + 1
+ if weight ~= s.weight then
+ s.fontweight = s.weight
+ end
+ s.weight, s.style, s.width, s.variant = weight, style, width, variant
+ end
+ local stats = data.statistics
+ stats.used_weights, stats.used_styles, stats.used_widths, stats.used_variants = weights, styles, widths, variants
+ end
+end
+
+local function collectstatistics()
+ local data = names.data
+ local specifications = data.specifications
+ if specifications then
+ local weights, styles, widths, variants = { }, { }, { }, { }
+ for i=1,#specifications do
+ local s = specifications[i]
+ local weight, style, width, variant = s.weight, s.style, s.width, s.variant
+ if weight then weights [weight ] = (weights [weight ] or 0) + 1 end
+ if style then styles [style ] = (styles [style ] or 0) + 1 end
+ if width then widths [width ] = (widths [width ] or 0) + 1 end
+ if variant then variants[variant] = (variants[variant] or 0) + 1 end
+ end
+ local stats = data.statistics
+ stats.weights, stats.styles, stats.widths, stats.variants, stats.fonts = weights, styles, widths, variants, #specifications
+ end
+end
+
+local function collecthashes()
+ local data = names.data
+ local mappings = data.mappings
+ local fallbacks = data.fallbacks
+ local specifications = data.specifications
+ local nofmappings, noffallbacks = 0, 0
+ if specifications then
+ -- maybe multiple passes
+ for index=1,#specifications do
+ local s = specifications[index]
+ local format, fullname, fontname, familyname, weight, subfamily = s.format, s.fullname, s.fontname, s.familyname, s.weight, s.subfamily
+ local mf, ff = mappings[format], fallbacks[format]
+ if fullname and not mf[fullname] then
+ mf[fullname], nofmappings = index, nofmappings + 1
+ end
+ if fontname and not mf[fontname] then
+ mf[fontname], nofmappings = index, nofmappings + 1
+ end
+ if familyname and weight then
+ local madename = familyname .. weight
+ if not mf[madename] and not ff[madename] then
+ ff[madename], noffallbacks = index, noffallbacks + 1
+ end
+ end
+ if familyname and subfamily then
+ local extraname = familyname .. subfamily
+ if not mf[extraname] and not ff[extraname] then
+ ff[extraname], noffallbacks = index, noffallbacks + 1
+ end
+ end
+ if familyname then
+ if not mf[familyname] and not ff[familyname] then
+ ff[familyname], noffallbacks = index, noffallbacks + 1
+ end
+ end
+ end
+ end
+ return nofmappings, noffallbacks
+end
+
+local function collectfamilies()
+ local data = names.data
+ local specifications = data.specifications
+ local families = data.families
+ for index=1,#specifications do
+ local familyname = specifications[index].familyname
+ local family = families[familyname]
+ if not family then
+ families[familyname] = { index }
+ else
+ family[#family+1] = index
+ end
+ end
+end
+
+local function checkduplicate(where) -- fails on "Romantik" but that's a border case anyway
+ local data = names.data
+ local mapping = data[where]
+ local specifications, loaded = data.specifications, { }
+ if specifications and mapping then
+ for _, m in next, mapping do
+ for k, v in next, m do
+ local s = specifications[v]
+ local hash = format("%s-%s-%s-%s-%s",s.familyname,s.weight or "*",s.style or "*",s.width or "*",s.variant or "*")
+ local h = loaded[hash]
+ if h then
+ local ok = true
+ local fn = s.filename
+ for i=1,#h do
+ local hn = s.filename
+ if h[i] == fn then
+ ok = false
+ break
+ end
+ end
+ if ok then
+ h[#h+1] = fn
+ end
+ else
+ loaded[hash] = { s.filename }
+ end
+ end
+ end
+ end
+ local n = 0
+ for k, v in table.sortedhash(loaded) do
+ local nv = #v
+ if nv > 1 then
+ if trace_warnings then
+ logs.report("fontnames", "double lookup: %s => %s",k,concat(v," | "))
+ end
+ n = n + nv
+ end
+ end
+ logs.report("fontnames", "%s double lookups in %s",n,where)
+end
+
+local function checkduplicates()
+ checkduplicate("mappings")
+ checkduplicate("fallbacks")
+end
+
+local sorter = function(a,b)
+ return a > b -- to be checked
+end
+
+local function sorthashes()
+ local data, list = names.data, filters.list
+ local mappings, fallbacks, sorted_mappings, sorted_fallbacks = data.mappings, data.fallbacks, { }, { }
+ data.sorted_mappings, data.sorted_fallbacks = sorted_mappings, sorted_fallbacks
+ for i=1,#list do
+ local l = list[i]
+ sorted_mappings[l], sorted_fallbacks[l] = table.keys(mappings[l]), table.keys(fallbacks[l])
+ sort(sorted_mappings[l],sorter)
+ sort(sorted_fallbacks[l],sorter)
+ end
+ data.sorted_families = table.keys(data.families)
+ sort(data.sorted_families,sorter)
+end
+
+local function unpackreferences()
+ local data = names.data
+ local specifications = data.specifications
+ if specifications then
+ for k, v in next, data.families do
+ for i=1,#v do
+ v[i] = specifications[v[i]]
+ end
+ end
+ local mappings = data.mappings
+ if mappings then
+ for _, m in next, mappings do
+ for k, v in next, m do
+ m[k] = specifications[v]
+ end
+ end
+ end
+ local fallbacks = data.fallbacks
+ if fallbacks then
+ for _, f in next, fallbacks do
+ for k, v in next, f do
+ f[k] = specifications[v]
+ end
+ end
+ end
+ end
+end
+
+local function analysefiles()
+ local data = names.data
+ local done, totalnofread, totalnofskipped = { }, 0, 0
+ local skip_paths, skip_names = filters.paths, filters.names
+ local function identify(completename,name,suffix,storedname)
+ local basename = file.basename(completename)
+ local basepath = file.dirname(completename)
+ if done[name] then
+ -- already done (avoid otf afm clash)
+ elseif not io.exists(completename) then
+ -- weird error
+ elseif not file.is_qualified_path(completename) and resolvers.find_file(completename,suffix) == "" then
+ -- not locateble by backend anyway
+ else
+ nofread = nofread + 1
+ if #skip_paths > 0 then
+ for i=1,#skip_paths do
+ if find(basepath,skip_paths[i]) then
+ if trace_names then
+ logs.report("fontnames","rejecting path of %s font %s",suffix,completename)
+ logs.push()
+ end
+ return
+ end
+ end
+ end
+ if #skip_names > 0 then
+ for i=1,#skip_paths do
+ if find(basename,skip_names[i]) then
+ done[name] = true
+ if trace_names then
+ logs.report("fontnames","rejecting name of %s font %s",suffix,completename)
+ logs.push()
+ end
+ return
+ end
+ end
+ end
+ if trace_names then
+ logs.report("fontnames","identifying %s font %s",suffix,completename)
+ logs.push()
+ end
+ local result, message = filters[lower(suffix)](completename)
+ if trace_names then
+ logs.pop()
+ end
+ if result then
+ if not result[1] then
+ local ok = check_name(data,result,storedname,suffix)
+ if not ok then
+ nofskipped = nofskipped + 1
+ end
+ else
+ for r=1,#result do
+ local ok = check_name(data,result[r],storedname,suffix,r-1) -- subfonts start at zero
+ if not ok then
+ nofskipped = nofskipped + 1
+ end
+ end
+ end
+ if trace_warnings and message and message ~= "" then
+ logs.report("fontnames","warning when identifying %s font %s: %s",suffix,completename,message)
+ end
+ elseif trace_warnings then
+ logs.report("fontnames","error when identifying %s font %s: %s",suffix,completename,message or "unknown")
+ end
+ done[name] = true
+ end
+ end
+ local function traverse(what, method)
+ local list = filters.list
+ for n=1,#list do
+ local suffix = list[n]
+ local t = os.gettimeofday() -- use elapser
+ nofread, nofskipped = 0, 0
+ suffix = lower(suffix)
+ logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix)
+ method(suffix)
+ suffix = upper(suffix)
+ logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix)
+ method(suffix)
+ totalnofread, totalnofskipped = totalnofread + nofread, totalnofskipped + nofskipped
+ local elapsed = os.gettimeofday() - t
+ logs.report("fontnames", "%s %s files identified, %s hash entries added, runtime %0.3f seconds",nofread,what,nofread-nofskipped,elapsed)
+ end
+ end
+ if not trace_warnings then
+ logs.report("fontnames", "warnings are disabled (tracker 'fonts.warnings')")
+ end
+ traverse("tree", function(suffix) -- TEXTREE only
+ resolvers.with_files(".*%." .. suffix .. "$", function(method,root,path,name)
+ if method == "file" then
+ local completename = root .."/" .. path .. "/" .. name
+ identify(completename,name,suffix,name,name)
+ end
+ end)
+ end)
+ if texconfig.kpse_init then
+ -- we do this only for a stupid names run, not used for context itself,
+ -- using the vars is to clumsy so we just stick to a full scan instead
+ traverse("lsr", function(suffix) -- all trees
+ local pathlist = resolvers.split_path(resolvers.show_path("ls-R") or "")
+ walk_tree(pathlist,suffix,identify)
+ end)
+ else
+ traverse("system", function(suffix) -- OSFONTDIR cum suis
+ walk_tree(names.getpaths(trace),suffix,identify)
+ end)
+ end
+ data.statistics.readfiles, data.statistics.skippedfiles = totalnofread, totalnofskipped
+end
+
+local function rejectclashes() -- just to be sure, so no explicit afm will be found then
+ local specifications, used, okay = names.data.specifications, { }, { }
+ for i=1,#specifications do
+ local s = specifications[i]
+ local f = s.fontname
+ if f then
+ local fnd, fnm = used[f], s.filename
+ if fnd then
+ if trace_warnings then
+ logs.report("fontnames", "fontname '%s' clashes, rejecting '%s' in favor of '%s'",f,fnm,fnd)
+ end
+ else
+ used[f], okay[#okay+1] = fnm, s
+ end
+ else
+ okay[#okay+1] = s
+ end
+ end
+ local d = #specifications - #okay
+ if d > 0 then
+ logs.report("fontnames", "%s files rejected due to clashes",d)
+ end
+ names.data.specifications = okay
+end
+
+local function resetdata()
+ local mappings, fallbacks = { }, { }
+ for _, k in next, filters.list do
+ mappings[k], fallbacks[k] = { }, { }
+ end
+ names.data = {
+ version = names.version,
+ mappings = mappings,
+ fallbacks = fallbacks,
+ specifications = { },
+ families = { },
+ statistics = { },
+ data_state = resolvers.data_state(),
+ }
+end
+
+function names.identify()
+ resetdata()
+ analysefiles()
+ rejectclashes()
+ collectfamilies()
+ collectstatistics()
+ cleanupkeywords()
+ collecthashes()
+ checkduplicates()
+ -- sorthashes() -- will be resorted when saved
+end
+
+function names.is_permitted(name)
+ return containers.is_usable(names.cache(), name)
+end
+function names.write_data(name,data)
+ containers.write(names.cache(),name,data)
+end
+function names.read_data(name)
+ return containers.read(names.cache(),name)
+end
+
+function names.load(reload,verbose)
+ if not names.loaded then
+ if reload then
+ if names.is_permitted(names.basename) then
+ names.identify(verbose)
+ names.write_data(names.basename,names.data)
+ else
+ logs.report("font table", "unable to access database cache")
+ end
+ names.saved = true
+ end
+ local data = names.read_data(names.basename)
+ names.data = data
+ if not names.saved then
+ if not data or not next(data) or not data.specifications or not next(data.specifications) then
+ names.load(true)
+ end
+ names.saved = true
+ end
+ if not data then
+ logs.report("font table", "accessing the data table failed")
+ else
+ unpackreferences()
+ sorthashes()
+ end
+ names.loaded = true
+ end
+end
+
+local function list_them(mapping,sorted,pattern,t,all)
+ if mapping[pattern] then
+ t[pattern] = mapping[pattern]
+ else
+ for k=1,#sorted do
+ local v = sorted[k]
+ if not t[v] and find(v,pattern) then
+ t[v] = mapping[v]
+ if not all then
+ return
+ end
+ end
+ end
+ end
+end
+
+function names.list(pattern,reload,all) -- here?
+ names.load(reload)
+ if names.loaded then
+ local t = { }
+ local data = names.data
+ if data then
+ local list = filters.list
+ local mappings, sorted_mappings = data.mappings, data.sorted_mappings
+ local fallbacks, sorted_fallbacks = data.fallbacks, data.sorted_fallbacks
+ for i=1,#list do
+ local format = list[i]
+ list_them(mappings[format],sorted_mappings[format],pattern,t,all)
+ if next(t) and not all then
+ return t
+ end
+ list_them(fallbacks[format],sorted_fallbacks[format],pattern,t,all)
+ if next(t) and not all then
+ return t
+ end
+ end
+ end
+ return t
+ end
+end
+
+local reloaded = false
+
+local function is_reloaded()
+ if not reloaded then
+ local data = names.data
+ if names.autoreload then
+ local c_status = table.serialize(resolvers.data_state())
+ local f_status = table.serialize(data.data_state)
+ if c_status == f_status then
+ -- logs.report("fonts","font database matches configuration and file hashes")
+ return
+ else
+ logs.report("fonts","font database does not match configuration and file hashes")
+ end
+ end
+ names.loaded = false
+ reloaded = true
+ io.flush()
+ names.load(true)
+ end
+end
+
+--[[ldx--
+
The resolver also checks if the cached names are loaded. Being clever
+here is for testing purposes only (it deals with names prefixed by an
+encoding name).
+--ldx]]--
+
+local function fuzzy(mapping,sorted,name,sub)
+ local condensed = gsub(name,"[^%a%d]","")
+ for k=1,#sorted do
+ local v = sorted[k]
+ if find(v,condensed) then
+ return mapping[v], v
+ end
+ end
+end
+
+-- we could cache a lookup .. maybe some day ... (only when auto loaded!)
+
+local function foundname(name,sub) -- sub is not used currently
+ local data = names.data
+ local mappings, sorted_mappings = data.mappings, data.sorted_mappings
+ local fallbacks, sorted_fallbacks = data.fallbacks, data.sorted_fallbacks
+ local list = filters.list
+ -- dilemma: we lookup in the order otf ttf ttc ... afm but now an otf fallback
+ -- can come after an afm match ... well, one should provide nice names anyway
+ -- and having two lists is not an option
+ for i=1,#list do
+ local l = list[i]
+ local found = mappings[l][name]
+ if found then
+ if trace_names then
+ logs.report("fonts","resolved via direct name match: '%s'",name)
+ end
+ return found
+ end
+ end
+ for i=1,#list do
+ local l = list[i]
+ local found, fname = fuzzy(mappings[l],sorted_mappings[l],name,sub)
+ if found then
+ if trace_names then
+ logs.report("fonts","resolved via fuzzy name match: '%s' => '%s'",name,fname)
+ end
+ return found
+ end
+ end
+ for i=1,#list do
+ local l = list[i]
+ local found = fallbacks[l][name]
+ if found then
+ if trace_names then
+ logs.report("fonts","resolved via direct fallback match: '%s'",name)
+ end
+ return found
+ end
+ end
+ for i=1,#list do
+ local l = list[i]
+ local found, fname = fuzzy(sorted_mappings[l],sorted_fallbacks[l],name,sub)
+ if found then
+ if trace_names then
+ logs.report("fonts","resolved via fuzzy fallback match: '%s' => '%s'",name,fname)
+ end
+ return found
+ end
+ end
+end
+
+function names.resolvedspecification(askedname,sub)
+ if askedname and askedname ~= "" and names.enabled then
+ askedname = cleanname(askedname)
+ names.load()
+ local found = foundname(askedname,sub)
+ if not found and is_reloaded() then
+ found = foundname(askedname,sub)
+ end
+ return found
+ end
+end
+
+function names.resolve(askedname,sub)
+ local found = names.resolvedspecification(askedname,sub)
+ if found then
+ return found.filename, found.subfont and found.rawname
+ end
+end
+
+-- specified search
+
+local function s_collect_weight_style_width_variant(found,done,all,weight,style,width,variant,family)
+ if family then
+ for i=1,#family do
+ local f = family[i]
+ if f and weight == f.weight and style == f.style and width == f.width and variant == f.variant then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+local function m_collect_weight_style_width_variant(found,done,all,weight,style,width,variant,families,sorted,strictname)
+ for i=1,#sorted do
+ local k = sorted[i]
+ local family = families[k]
+ for i=1,#family do
+ local f = family[i]
+ if not done[f] and weight == f.weight and style == f.style and width == f.width and variant == f.variant and find(f.fontname,strictname) then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+
+local function s_collect_weight_style_width(found,done,all,weight,style,width,family)
+ if family then
+ for i=1,#family do
+ local f = family[i]
+ if f and weight == f.weight and style == f.style and width == f.width then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+local function m_collect_weight_style_width(found,done,all,weight,style,width,families,sorted,strictname)
+ for i=1,#sorted do
+ local k = sorted[i]
+ local family = families[k]
+ for i=1,#family do
+ local f = family[i]
+ if not done[f] and weight == f.weight and style == f.style and width == f.width and find(f.fontname,strictname) then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+
+local function s_collect_weight_style(found,done,all,weight,style,family)
+ if family then
+ for i=1,#family do local f = family[i]
+ if f and weight == f.weight and style == f.style then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+local function m_collect_weight_style(found,done,all,weight,style,families,sorted,strictname)
+ for i=1,#sorted do
+ local k = sorted[i]
+ local family = families[k]
+ for i=1,#family do
+ local f = family[i]
+ if not done[f] and weight == f.weight and style == f.style and find(f.fontname,strictname) then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+
+local function s_collect_style_width(found,done,all,style,width,family)
+ if family then
+ for i=1,#family do local f = family[i]
+ if f and style == f.style and width == f.width then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+local function m_collect_style_width(found,done,all,style,width,families,sorted,strictname)
+ for i=1,#sorted do
+ local k = sorted[i]
+ local family = families[k]
+ for i=1,#family do
+ local f = family[i]
+ if not done[f] and style == f.style and width == f.width and find(f.fontname,strictname) then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+
+local function s_collect_weight(found,done,all,weight,family)
+ if family then
+ for i=1,#family do local f = family[i]
+ if f and weight == f.weight then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+local function m_collect_weight(found,done,all,weight,families,sorted,strictname)
+ for i=1,#sorted do
+ local k = sorted[i]
+ local family = families[k]
+ for i=1,#family do
+ local f = family[i]
+ if not done[f] and weight == f.weight and find(f.fontname,strictname) then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+
+local function s_collect_style(found,done,all,style,family)
+ if family then
+ for i=1,#family do local f = family[i]
+ if f and style == f.style then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+local function m_collect_style(found,done,all,style,families,sorted,strictname)
+ for i=1,#sorted do
+ local k = sorted[i]
+ local family = families[k]
+ for i=1,#family do
+ local f = family[i]
+ if not done[f] and style == f.style and find(f.fontname,strictname) then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+
+local function s_collect_width(found,done,all,width,family)
+ if family then
+ for i=1,#family do local f = family[i]
+ if f and width == f.width then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+local function m_collect_width(found,done,all,width,families,sorted,strictname)
+ for i=1,#sorted do
+ local k = sorted[i]
+ local family = families[k]
+ for i=1,#family do
+ local f = family[i]
+ if not done[f] and width == f.width and find(f.fontname,strictname) then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+
+local function s_collect(found,done,all,family)
+ if family then
+ for i=1,#family do local f = family[i]
+ if f then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+local function m_collect(found,done,all,families,sorted,strictname)
+ for i=1,#sorted do
+ local k = sorted[i]
+ local family = families[k]
+ for i=1,#family do
+ local f = family[i]
+ if not done[f] and find(f.fontname,strictname) then
+ found[#found+1], done[f] = f, true
+ if not all then return end
+ end
+ end
+ end
+end
+
+local function collect(stage,found,done,name,weight,style,width,variant,all)
+ local data = names.data
+ local families, sorted = data.families, data.sorted_families
+ strictname = "^".. name -- to be checked
+ local family = families[name]
+ if trace_names then
+ logs.report("fonts","resolving name '%s', weight '%s', style '%s', width '%s', variant '%s'",
+ name or "?",tostring(weight),tostring(style),tostring(width),tostring(variant))
+ end
+ --~ print(name,table.serialize(family))
+ if weight and weight ~= "" then
+ if style and style ~= "" then
+ if width and width ~= "" then
+ if variant and variant ~= "" then
+ if trace_names then
+ logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s', width '%s', variant '%s'",stage,name,weight,style,width,variant)
+ end
+ s_collect_weight_style_width_variant(found,done,all,weight,style,width,variant,family)
+ m_collect_weight_style_width_variant(found,done,all,weight,style,width,variant,families,sorted,strictname)
+ else
+ if trace_names then
+ logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s', width '%s'",stage,name,weight,style,width)
+ end
+ s_collect_weight_style_width(found,done,all,weight,style,width,family)
+ m_collect_weight_style_width(found,done,all,weight,style,width,families,sorted,strictname)
+ end
+ else
+ if trace_names then
+ logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s'",stage,name,weight,style)
+ end
+ s_collect_weight_style(found,done,all,weight,style,family)
+ m_collect_weight_style(found,done,all,weight,style,families,sorted,strictname)
+ end
+ else
+ if trace_names then
+ logs.report("fonts","resolving stage %s, name '%s', weight '%s'",stage,name,weight)
+ end
+ s_collect_weight(found,done,all,weight,family)
+ m_collect_weight(found,done,all,weight,families,sorted,strictname)
+ end
+ elseif style and style ~= "" then
+ if width and width ~= "" then
+ if trace_names then
+ logs.report("fonts","resolving stage %s, name '%s', style '%s', width '%s'",stage,name,style,width)
+ end
+ s_collect_style_width(found,done,all,style,width,family)
+ m_collect_style_width(found,done,all,style,width,families,sorted,strictname)
+ else
+ if trace_names then
+ logs.report("fonts","resolving stage %s, name '%s', style '%s'",stage,name,style)
+ end
+ s_collect_style(found,done,all,style,family)
+ m_collect_style(found,done,all,style,families,sorted,strictname)
+ end
+ elseif width and width ~= "" then
+ if trace_names then
+ logs.report("fonts","resolving stage %s, name '%s', width '%s'",stage,name,width)
+ end
+ s_collect_width(found,done,all,width,family)
+ m_collect_width(found,done,all,width,families,sorted,strictname)
+ else
+ if trace_names then
+ logs.report("fonts","resolving stage %s, name '%s'",stage,name)
+ end
+ s_collect(found,done,all,family)
+ m_collect(found,done,all,families,sorted,strictname)
+ end
+end
+
+function heuristic(name,weight,style,width,variant,all) -- todo: fallbacks
+ local found, done = { }, { }
+--~ print(name,weight,style,width,variant)
+ weight, style, width, variant = weight or "normal", style or "normal", width or "normal", variant or "normal"
+ name = cleanname(name)
+ collect(1,found,done,name,weight,style,width,variant,all)
+ -- still needed ?
+ if #found == 0 and variant ~= "normal" then -- not weight
+ variant = "normal"
+ collect(4,found,done,name,weight,style,width,variant,all)
+ end
+ if #found == 0 and width ~= "normal" then
+ width = "normal"
+ collect(2,found,done,name,weight,style,width,variant,all)
+ end
+ if #found == 0 and weight ~= "normal" then -- not style
+ weight = "normal"
+ collect(3,found,done,name,weight,style,width,variant,all)
+ end
+ if #found == 0 and style ~= "normal" then -- not weight
+ style = "normal"
+ collect(4,found,done,name,weight,style,width,variant,all)
+ end
+ --
+ local nf = #found
+ if trace_names then
+ if nf then
+ local t = { }
+ for i=1,nf do
+ t[#t+1] = format("'%s'",found[i].fontname)
+ end
+ logs.report("fonts","name '%s' resolved to %s instances: %s",name,nf,concat(t," "))
+ else
+ logs.report("fonts","name '%s' unresolved",name)
+ end
+ end
+ if all then
+ return nf > 0 and found
+ else
+ return found[1]
+ end
+end
+
+function names.specification(askedname,weight,style,width,variant,reload,all)
+ if askedname and askedname ~= "" and names.enabled then
+ askedname = lower(askedname) -- or cleanname
+ names.load(reload)
+ local found = heuristic(askedname,weight,style,width,variant,all)
+ if not found and is_reloaded() then
+ found = heuristic(askedname,weight,style,width,variant,all)
+ if not filename then
+ found = foundname(askedname) -- old method
+ end
+ end
+ return found
+ end
+end
+
+function names.collect(askedname,weight,style,width,variant,reload,all)
+ if askedname and askedname ~= "" and names.enabled then
+ askedname = lower(askedname) -- or cleanname
+ names.load(reload)
+ local list = heuristic(askedname,weight,style,width,variant,true)
+ if not list or #list == 0 and is_reloaded() then
+ list = heuristic(askedname,weight,style,width,variant,true)
+ end
+ return list
+ end
+end
+
+function names.collectspec(askedname,reload,all)
+ local name, weight, style, width, variant = names.splitspec(askedname)
+ return names.collect(name,weight,style,width,variant,reload,all)
+end
+
+function names.resolvespec(askedname,sub)
+ local found = names.specification(names.splitspec(askedname))
+ if found then
+ return found.filename, found.subfont and found.rawname
+ end
+end
+
+function names.collectfiles(askedname,reload) -- no all
+ if askedname and askedname ~= "" and names.enabled then
+ askedname = lower(askedname) -- or cleanname
+ names.load(reload)
+ local list = { }
+ local basename = file.basename
+ local specifications = names.data.specifications
+ for i=1,#specifications do
+ local s = specifications[i]
+ if find(lower(basename(s.filename)),askedname) then
+ list[#list+1] = s
+ end
+ end
+ return list
+ end
+end
+
+--[[ldx--
+
Fallbacks, not permanent but a transition thing.
+--ldx]]--
+
+names.new_to_old = {
+ ["lmroman10-capsregular"] = "lmromancaps10-oblique",
+ ["lmroman10-capsoblique"] = "lmromancaps10-regular",
+ ["lmroman10-demi"] = "lmromandemi10-oblique",
+ ["lmroman10-demioblique"] = "lmromandemi10-regular",
+ ["lmroman8-oblique"] = "lmromanslant8-regular",
+ ["lmroman9-oblique"] = "lmromanslant9-regular",
+ ["lmroman10-oblique"] = "lmromanslant10-regular",
+ ["lmroman12-oblique"] = "lmromanslant12-regular",
+ ["lmroman17-oblique"] = "lmromanslant17-regular",
+ ["lmroman10-boldoblique"] = "lmromanslant10-bold",
+ ["lmroman10-dunhill"] = "lmromandunh10-oblique",
+ ["lmroman10-dunhilloblique"] = "lmromandunh10-regular",
+ ["lmroman10-unslanted"] = "lmromanunsl10-regular",
+ ["lmsans10-demicondensed"] = "lmsansdemicond10-regular",
+ ["lmsans10-demicondensedoblique"] = "lmsansdemicond10-oblique",
+ ["lmsansquotation8-bold"] = "lmsansquot8-bold",
+ ["lmsansquotation8-boldoblique"] = "lmsansquot8-boldoblique",
+ ["lmsansquotation8-oblique"] = "lmsansquot8-oblique",
+ ["lmsansquotation8-regular"] = "lmsansquot8-regular",
+ ["lmtypewriter8-regular"] = "lmmono8-regular",
+ ["lmtypewriter9-regular"] = "lmmono9-regular",
+ ["lmtypewriter10-regular"] = "lmmono10-regular",
+ ["lmtypewriter12-regular"] = "lmmono12-regular",
+ ["lmtypewriter10-italic"] = "lmmono10-italic",
+ ["lmtypewriter10-oblique"] = "lmmonoslant10-regular",
+ ["lmtypewriter10-capsoblique"] = "lmmonocaps10-oblique",
+ ["lmtypewriter10-capsregular"] = "lmmonocaps10-regular",
+ ["lmtypewriter10-light"] = "lmmonolt10-regular",
+ ["lmtypewriter10-lightoblique"] = "lmmonolt10-oblique",
+ ["lmtypewriter10-lightcondensed"] = "lmmonoltcond10-regular",
+ ["lmtypewriter10-lightcondensedoblique"] = "lmmonoltcond10-oblique",
+ ["lmtypewriter10-dark"] = "lmmonolt10-bold",
+ ["lmtypewriter10-darkoblique"] = "lmmonolt10-boldoblique",
+ ["lmtypewritervarwd10-regular"] = "lmmonoproplt10-regular",
+ ["lmtypewritervarwd10-oblique"] = "lmmonoproplt10-oblique",
+ ["lmtypewritervarwd10-light"] = "lmmonoprop10-regular",
+ ["lmtypewritervarwd10-lightoblique"] = "lmmonoprop10-oblique",
+ ["lmtypewritervarwd10-dark"] = "lmmonoproplt10-bold",
+ ["lmtypewritervarwd10-darkoblique"] = "lmmonoproplt10-boldoblique",
+}
+
+names.old_to_new = table.swapped(names.new_to_old)
+
+function names.exists(name)
+ local found = false
+ local list = filters.list
+ for k=1,#list do
+ local v = list[k]
+ found = (resolvers.find_file(name,v) or "") ~= ""
+ if found then
+ return found
+ end
+ end
+ return ((resolvers.find_file(name,"tfm") or "") ~= "") or ((names.resolve(name) or "") ~= "")
+end
+
+-- for i=1,fonts.names.lookup(pattern) do
+-- texio.write_nl(fonts.names.getkey("filename",i))
+-- end
+
+local lastlookups, lastpattern = { }, ""
+
+function names.lookup(pattern,name,reload) -- todo: find
+ if lastpattern ~= pattern then
+ names.load(reload)
+ local specifications = names.data.specifications
+ local families = names.data.families
+ local lookups = specifications
+ if name then
+ lookups = families[name]
+ elseif not find(pattern,"=") then
+ lookups = families[pattern]
+ end
+ if trace_names then
+ logs.report("fonts","starting with %s lookups for '%s'",#lookups,pattern)
+ end
+ if lookups then
+ for key, value in gmatch(pattern,"([^=,]+)=([^=,]+)") do
+ local t = { }
+ for i=1,#lookups do
+ local s = lookups[i]
+ if s[key] == value then
+ t[#t+1] = lookups[i]
+ end
+ end
+ if trace_names then
+ logs.report("fonts","%s matches for key '%s' with value '%s'",#t,key,value)
+ end
+ lookups = t
+ end
+ end
+ lastpattern = pattern
+ lastlookups = lookups or { }
+ end
+ return #lastlookups
+end
+
+function names.getlookupkey(key,n)
+ local l = lastlookups[n or 1]
+ return (l and l[key]) or ""
+end
+
+function names.noflookups()
+ return #lastlookups
+end
+
+function names.getlookups(pattern,name,reload)
+ if pattern then
+ names.lookup(pattern,name,reload)
+ end
+ return lastlookups
+end
+
+function table.formatcolumns(result)
+ if result and #result > 0 then
+ local widths = { }
+ local first = result[1]
+ local n = #first
+ for i=1,n do
+ widths[i] = 0
+ end
+ for i=1,#result do
+ local r = result[i]
+ for j=1,n do
+ local w = #r[j]
+ if w > widths[j] then
+ widths[j] = w
+ end
+ end
+ end
+ for i=1,n do
+ widths[i] = "%-" .. widths[i] .. "s"
+ end
+ local template = concat(widths," ")
+ for i=1,#result do
+ local str = format(template,unpack(result[i]))
+ result[i] = string.strip(str)
+ end
+ end
+ return result
+end
diff --git a/tex/context/base/font-tfm.lua b/tex/context/base/font-tfm.lua
new file mode 100644
index 000000000..31ae2cae1
--- /dev/null
+++ b/tex/context/base/font-tfm.lua
@@ -0,0 +1,736 @@
+if not modules then modules = { } end modules ['font-tfm'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local next, format, match, lower, gsub = next, string.format, string.match, string.lower, string.gsub
+local concat, sortedkeys, utfbyte, serialize = table.concat, table.sortedkeys, utf.byte, table.serialize
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local trace_scaling = false trackers.register("fonts.scaling" , function(v) trace_scaling = v end)
+
+-- tfmdata has also fast access to indices and unicodes
+-- to be checked: otf -> tfm -> tfmscaled
+--
+-- watch out: no negative depths and negative eights permitted in regular fonts
+
+--[[ldx--
+
Here we only implement a few helper functions.
+--ldx]]--
+
+fonts = fonts or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+
+local tfm = fonts.tfm
+
+fonts.loaded = fonts.loaded or { }
+fonts.dontembed = fonts.dontembed or { }
+fonts.triggers = fonts.triggers or { } -- brrr
+fonts.initializers = fonts.initializers or { }
+fonts.initializers.common = fonts.initializers.common or { }
+
+local fontdata = fonts.ids
+local disc = node.id('disc')
+local glyph = node.id('glyph')
+local set_attribute = node.set_attribute
+
+--[[ldx--
+
The next function encapsulates the standard loader as
+supplied by .
+--ldx]]--
+
+tfm.resolve_vf = true -- false
+tfm.share_base_kerns = false -- true (.5 sec slower on mk but brings down mem from 410M to 310M, beware: then script/lang share too)
+tfm.mathactions = { }
+tfm.fontname_mode = "fullpath"
+
+tfm.enhance = tfm.enhance or function() end
+
+function tfm.read_from_tfm(specification)
+ local fname, tfmdata = specification.filename or "", nil
+ if fname ~= "" then
+ if trace_defining then
+ logs.report("define font","loading tfm file %s at size %s",fname,specification.size)
+ end
+ tfmdata = font.read_tfm(fname,specification.size) -- not cached, fast enough
+ if tfmdata then
+ tfmdata.descriptions = tfmdata.descriptions or { }
+ if tfm.resolve_vf then
+ fonts.logger.save(tfmdata,file.extname(fname),specification) -- strange, why here
+ fname = resolvers.findbinfile(specification.name, 'ovf')
+ if fname and fname ~= "" then
+ local vfdata = font.read_vf(fname,specification.size) -- not cached, fast enough
+ if vfdata then
+ local chars = tfmdata.characters
+ for k,v in next, vfdata.characters do
+ chars[k].commands = v.commands
+ end
+ tfmdata.type = 'virtual'
+ tfmdata.fonts = vfdata.fonts
+ end
+ end
+ end
+ tfm.enhance(tfmdata,specification)
+ end
+ elseif trace_defining then
+ logs.report("define font","loading tfm with name %s fails",specification.name)
+ end
+ return tfmdata
+end
+
+--[[ldx--
+
We need to normalize the scale factor (in scaled points). This has to
+do with the fact that uses a negative multiple of 1000 as
+a signal for a font scaled based on the design size.
+--ldx]]--
+
+local factors = {
+ pt = 65536.0,
+ bp = 65781.8,
+}
+
+function tfm.setfactor(f)
+ tfm.factor = factors[f or 'pt'] or factors.pt
+end
+
+tfm.setfactor()
+
+function tfm.scaled(scaledpoints, designsize) -- handles designsize in sp as well
+ if scaledpoints < 0 then
+ if designsize then
+ if designsize > tfm.factor then -- or just 1000 / when? mp?
+ return (- scaledpoints/1000) * designsize -- sp's
+ else
+ return (- scaledpoints/1000) * designsize * tfm.factor
+ end
+ else
+ return (- scaledpoints/1000) * 10 * tfm.factor
+ end
+ else
+ return scaledpoints
+ end
+end
+
+--[[ldx--
+
Before a font is passed to we scale it. Here we also need
+to scale virtual characters.
+--ldx]]--
+
+function tfm.get_virtual_id(tfmdata)
+ -- since we don't know the id yet, we use 0 as signal
+ if not tfmdata.fonts then
+ tfmdata.type = "virtual"
+ tfmdata.fonts = { { id = 0 } }
+ return 1
+ else
+ tfmdata.fonts[#tfmdata.fonts+1] = { id = 0 }
+ return #tfmdata.fonts
+ end
+end
+
+function tfm.check_virtual_id(tfmdata, id)
+ if tfmdata and tfmdata.type == "virtual" then
+ if not tfmdata.fonts or #tfmdata.fonts == 0 then
+ tfmdata.type, tfmdata.fonts = "real", nil
+ else
+ local vfonts = tfmdata.fonts
+ for f=1,#vfonts do
+ local fnt = vfonts[f]
+ if fnt.id and fnt.id == 0 then
+ fnt.id = id
+ end
+ end
+ end
+ end
+end
+
+--[[ldx--
+
Beware, the boundingbox is passed as reference so we may not overwrite it
+in the process; numbers are of course copies. Here 65536 equals 1pt. (Due to
+excessive memory usage in CJK fonts, we no longer pass the boundingbox.)
+--ldx]]--
+
+fonts.trace_scaling = false
+
+-- the following hack costs a bit of runtime but safes memory
+--
+-- basekerns are scaled and will be hashed by table id
+-- sharedkerns are unscaled and are be hashed by concatenated indexes
+
+--~ function tfm.check_base_kerns(tfmdata)
+--~ if tfm.share_base_kerns then
+--~ local sharedkerns = tfmdata.sharedkerns
+--~ if sharedkerns then
+--~ local basekerns = { }
+--~ tfmdata.basekerns = basekerns
+--~ return sharedkerns, basekerns
+--~ end
+--~ end
+--~ return nil, nil
+--~ end
+
+--~ function tfm.prepare_base_kerns(tfmdata)
+--~ if tfm.share_base_kerns and not tfmdata.sharedkerns then
+--~ local sharedkerns = { }
+--~ tfmdata.sharedkerns = sharedkerns
+--~ for u, chr in next, tfmdata.characters do
+--~ local kerns = chr.kerns
+--~ if kerns then
+--~ local hash = concat(sortedkeys(kerns), " ")
+--~ local base = sharedkerns[hash]
+--~ if not base then
+--~ sharedkerns[hash] = kerns
+--~ else
+--~ chr.kerns = base
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+
+-- we can have cache scaled characters when we are in node mode and don't have
+-- protruding and expansion: hash == fullname @ size @ protruding @ expansion
+-- but in practice (except from mk) the otf hash will be enough already so it
+-- makes no sense to mess up the code now
+
+local charactercache = { }
+
+-- The scaler is only used for otf and afm and virtual fonts. If
+-- a virtual font has italic correction make sure to set the
+-- has_italic flag. Some more flags will be added in the future.
+
+function tfm.calculate_scale(tfmtable, scaledpoints, relativeid)
+ if scaledpoints < 0 then
+ scaledpoints = (- scaledpoints/1000) * tfmtable.designsize -- already in sp
+ end
+ local units = tfmtable.units or 1000
+ local delta = scaledpoints/units -- brr, some open type fonts have 2048
+ return scaledpoints, delta, units
+end
+
+function tfm.do_scale(tfmtable, scaledpoints, relativeid)
+ -- tfm.prepare_base_kerns(tfmtable) -- optimalization
+ local t = { } -- the new table
+ local scaledpoints, delta, units = tfm.calculate_scale(tfmtable, scaledpoints, relativeid)
+ t.units_per_em = units or 1000
+ local hdelta, vdelta = delta, delta
+ -- unicoded unique descriptions shared cidinfo characters changed parameters indices
+ for k,v in next, tfmtable do
+ if type(v) == "table" then
+ -- print(k)
+ else
+ t[k] = v
+ end
+ end
+ local extend_factor = tfmtable.extend_factor or 0
+ if extend_factor ~= 0 and extend_factor ~= 1 then
+ hdelta = hdelta * extend_factor
+ t.extend = extend_factor * 1000
+ else
+ t.extend = 1000
+ end
+ local slant_factor = tfmtable.slant_factor or 0
+ if slant_factor ~= 0 then
+ t.slant = slant_factor * 1000
+ else
+ t.slant = 0
+ end
+ -- status
+ local isvirtual = tfmtable.type == "virtual" or tfmtable.virtualized
+ local hasmath = (tfmtable.math_parameters ~= nil and next(tfmtable.math_parameters) ~= nil) or (tfmtable.MathConstants ~= nil and next(tfmtable.MathConstants) ~= nil)
+ local nodemode = tfmtable.mode == "node"
+ local hasquality = tfmtable.auto_expand or tfmtable.auto_protrude
+ local hasitalic = tfmtable.has_italic
+ --
+ t.parameters = { }
+ t.characters = { }
+ t.MathConstants = { }
+ -- fast access
+ local descriptions = tfmtable.descriptions or { }
+ t.unicodes = tfmtable.unicodes
+ t.indices = tfmtable.indices
+ t.marks = tfmtable.marks
+t.goodies = tfmtable.goodies
+t.colorscheme = tfmtable.colorscheme
+--~ t.embedding = tfmtable.embedding
+ t.descriptions = descriptions
+ if tfmtable.fonts then
+ t.fonts = table.fastcopy(tfmtable.fonts) -- hm also at the end
+ end
+ local tp = t.parameters
+ local mp = t.math_parameters
+ local tfmp = tfmtable.parameters -- let's check for indexes
+ --
+ tp.slant = (tfmp.slant or tfmp[1] or 0)
+ tp.space = (tfmp.space or tfmp[2] or 0)*hdelta
+ tp.space_stretch = (tfmp.space_stretch or tfmp[3] or 0)*hdelta
+ tp.space_shrink = (tfmp.space_shrink or tfmp[4] or 0)*hdelta
+ tp.x_height = (tfmp.x_height or tfmp[5] or 0)*vdelta
+ tp.quad = (tfmp.quad or tfmp[6] or 0)*hdelta
+ tp.extra_space = (tfmp.extra_space or tfmp[7] or 0)*hdelta
+ local protrusionfactor = (tp.quad ~= 0 and 1000/tp.quad) or 0
+ local tc = t.characters
+ local characters = tfmtable.characters
+ local nameneeded = not tfmtable.shared.otfdata --hack
+ local changed = tfmtable.changed or { } -- for base mode
+ local ischanged = changed and next(changed)
+ local indices = tfmtable.indices
+ local luatex = tfmtable.luatex
+ local tounicode = luatex and luatex.tounicode
+ local defaultwidth = luatex and luatex.defaultwidth or 0
+ local defaultheight = luatex and luatex.defaultheight or 0
+ local defaultdepth = luatex and luatex.defaultdepth or 0
+ -- experimental, sharing kerns (unscaled and scaled) saves memory
+ -- local sharedkerns, basekerns = tfm.check_base_kerns(tfmtable)
+ -- loop over descriptions (afm and otf have descriptions, tfm not)
+ -- there is no need (yet) to assign a value to chr.tonunicode
+ local scaledwidth = defaultwidth * hdelta
+ local scaledheight = defaultheight * vdelta
+ local scaleddepth = defaultdepth * vdelta
+ local stackmath = tfmtable.ignore_stack_math ~= true
+ local private = fonts.private
+ local sharedkerns = { }
+ for k,v in next, characters do
+ local chr, description, index
+ if ischanged then
+ -- basemode hack
+ local c = changed[k]
+ if c then
+ description = descriptions[c] or v
+ v = characters[c] or v
+ index = (indices and indices[c]) or c
+ else
+ description = descriptions[k] or v
+ index = (indices and indices[k]) or k
+ end
+ else
+ description = descriptions[k] or v
+ index = (indices and indices[k]) or k
+ end
+ local width = description.width
+ local height = description.height
+ local depth = description.depth
+ if width then width = hdelta*width else width = scaledwidth end
+ if height then height = vdelta*height else height = scaledheight end
+ -- if depth then depth = vdelta*depth else depth = scaleddepth end
+ if depth and depth ~= 0 then
+ depth = delta*depth
+ if nameneeded then
+ chr = {
+ name = description.name,
+ index = index,
+ height = height,
+ depth = depth,
+ width = width,
+ }
+ else
+ chr = {
+ index = index,
+ height = height,
+ depth = depth,
+ width = width,
+ }
+ end
+ else
+ -- this saves a little bit of memory time and memory, esp for big cjk fonts
+ if nameneeded then
+ chr = {
+ name = description.name,
+ index = index,
+ height = height,
+ width = width,
+ }
+ else
+ chr = {
+ index = index,
+ height = height,
+ width = width,
+ }
+ end
+ end
+ -- if trace_scaling then
+ -- logs.report("define font","t=%s, u=%s, i=%s, n=%s c=%s",k,chr.tounicode or k,description.index,description.name or '-',description.class or '-')
+ -- end
+ if tounicode then
+ local tu = tounicode[index] -- nb: index!
+ if tu then
+ chr.tounicode = tu
+ end
+ end
+ if hasquality then
+ -- we could move these calculations elsewhere (saves calculations)
+ local ve = v.expansion_factor
+ if ve then
+ chr.expansion_factor = ve*1000 -- expansionfactor, hm, can happen elsewhere
+ end
+ local vl = v.left_protruding
+ if vl then
+ chr.left_protruding = protrusionfactor*width*vl
+ end
+ local vr = v.right_protruding
+ if vr then
+ chr.right_protruding = protrusionfactor*width*vr
+ end
+ end
+ -- todo: hasitalic
+ if hasitalic then
+ local vi = description.italic or v.italic
+ if vi and vi ~= 0 then
+ chr.italic = vi*hdelta
+ end
+ end
+ -- to be tested
+ if hasmath then
+ -- todo, just operate on descriptions.math
+ local vn = v.next
+ if vn then
+ chr.next = vn
+ else
+ local vv = v.vert_variants
+ if vv then
+ local t = { }
+ for i=1,#vv do
+ local vvi = vv[i]
+ t[i] = {
+ ["start"] = (vvi["start"] or 0)*vdelta,
+ ["end"] = (vvi["end"] or 0)*vdelta,
+ ["advance"] = (vvi["advance"] or 0)*vdelta,
+ ["extender"] = vvi["extender"],
+ ["glyph"] = vvi["glyph"],
+ }
+ end
+ chr.vert_variants = t
+ --~ local ic = v.vert_italic_correction
+ --~ if ic then
+ --~ chr.italic = ic * hdelta
+ --~ print(format("0x%05X -> %s",k,chr.italic))
+ --~ end
+ else
+ local hv = v.horiz_variants
+ if hv then
+ local t = { }
+ for i=1,#hv do
+ local hvi = hv[i]
+ t[i] = {
+ ["start"] = (hvi["start"] or 0)*hdelta,
+ ["end"] = (hvi["end"] or 0)*hdelta,
+ ["advance"] = (hvi["advance"] or 0)*hdelta,
+ ["extender"] = hvi["extender"],
+ ["glyph"] = hvi["glyph"],
+ }
+ end
+ chr.horiz_variants = t
+ end
+ end
+ end
+ local vt = description.top_accent
+ if vt then
+ chr.top_accent = vdelta*vt
+ end
+ if stackmath then
+ local mk = v.mathkerns
+ if mk then
+ local kerns = { }
+ local v = mk.top_right if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
+ end kerns.top_right = k end
+ local v = mk.top_left if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
+ end kerns.top_left = k end
+ local v = mk.bottom_left if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
+ end kerns.bottom_left = k end
+ local v = mk.bottom_right if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
+ end kerns.bottom_right = k end
+ chr.mathkern = kerns -- singular
+ end
+ end
+ end
+ if not nodemode then
+ local vk = v.kerns
+ if vk then
+ --~ if sharedkerns then
+ --~ local base = basekerns[vk] -- hashed by table id, not content
+ --~ if not base then
+ --~ base = {}
+ --~ for k,v in next, vk do base[k] = v*hdelta end
+ --~ basekerns[vk] = base
+ --~ end
+ --~ chr.kerns = base
+ --~ else
+ --~ local tt = {}
+ --~ for k,v in next, vk do tt[k] = v*hdelta end
+ --~ chr.kerns = tt
+ --~ end
+ local s = sharedkerns[vk]
+ if not s then
+ s = { }
+ for k,v in next, vk do s[k] = v*hdelta end
+ sharedkerns[vk] = s
+ end
+ chr.kerns = s
+ end
+ local vl = v.ligatures
+ if vl then
+ if true then
+ chr.ligatures = vl -- shared
+ else
+ local tt = { }
+ for i,l in next, vl do
+ tt[i] = l
+ end
+ chr.ligatures = tt
+ end
+ end
+ end
+ if isvirtual then
+ local vc = v.commands
+ if vc then
+ -- we assume non scaled commands here
+ -- tricky .. we need to scale pseudo math glyphs too
+ -- which is why we deal with rules too
+ local ok = false
+ for i=1,#vc do
+ local key = vc[i][1]
+ if key == "right" or key == "down" then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ local tt = { }
+ for i=1,#vc do
+ local ivc = vc[i]
+ local key = ivc[1]
+ if key == "right" then
+ tt[#tt+1] = { key, ivc[2]*hdelta }
+ elseif key == "down" then
+ tt[#tt+1] = { key, ivc[2]*vdelta }
+ elseif key == "rule" then
+ tt[#tt+1] = { key, ivc[2]*vdelta, ivc[3]*hdelta }
+ else -- not comment
+ tt[#tt+1] = ivc -- shared since in cache and untouched
+ end
+ end
+ chr.commands = tt
+ else
+ chr.commands = vc
+ end
+ end
+ end
+ tc[k] = chr
+ end
+ -- t.encodingbytes, t.filename, t.fullname, t.name: elsewhere
+ t.size = scaledpoints
+ t.factor = delta
+ t.hfactor = hdelta
+ t.vfactor = vdelta
+ if t.fonts then
+ t.fonts = table.fastcopy(t.fonts) -- maybe we virtualize more afterwards
+ end
+ if hasmath then
+ -- mathematics.extras.copy(t) -- can be done elsewhere if needed
+ local ma = tfm.mathactions
+ for i=1,#ma do
+ ma[i](t,tfmtable,delta,hdelta,vdelta) -- what delta?
+ end
+ end
+ -- needed for \high cum suis
+ local tpx = tp.x_height
+ if hasmath then
+ if not tp[13] then tp[13] = .86*tpx end -- mathsupdisplay
+ if not tp[14] then tp[14] = .86*tpx end -- mathsupnormal
+ if not tp[15] then tp[15] = .86*tpx end -- mathsupcramped
+ if not tp[16] then tp[16] = .48*tpx end -- mathsubnormal
+ if not tp[17] then tp[17] = .48*tpx end -- mathsubcombined
+ if not tp[22] then tp[22] = 0 end -- mathaxisheight
+ if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard
+ end
+ t.tounicode = 1
+ t.cidinfo = tfmtable.cidinfo
+ -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename
+ -- when collapsing fonts, luatex looks as both t.name and t.fullname as ttc files
+ -- can have multiple subfonts
+ if hasmath then
+ if trace_defining then
+ logs.report("define font","math enabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")
+ end
+ else
+ if trace_defining then
+ logs.report("define font","math disabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")
+ end
+ t.nomath, t.MathConstants = true, nil
+ end
+ if not t.psname then
+ -- name used in pdf file as well as for selecting subfont in ttc/dfont
+ t.psname = t.fontname or (t.fullname and fonts.names.cleanname(t.fullname))
+ end
+ if trace_defining then
+ logs.report("define font","used for accesing subfont: '%s'",t.psname or "nopsname")
+ logs.report("define font","used for subsetting: '%s'",t.fontname or "nofontname")
+ end
+--~ print(t.fontname,table.serialize(t.MathConstants))
+ return t, delta
+end
+
+--[[ldx--
+
The reason why the scaler is split, is that for a while we experimented
+with a helper function. However, in practice the calls are too slow to
+make this profitable and the based variant was just faster. A days
+wasted day but an experience richer.
+--ldx]]--
+
+tfm.auto_cleanup = true
+
+local lastfont = nil
+
+-- we can get rid of the tfm instance when we have fast access to the
+-- scaled character dimensions at the tex end, e.g. a fontobject.width
+--
+-- flushing the kern and ligature tables from memory saves a lot (only
+-- base mode) but it complicates vf building where the new characters
+-- demand this data .. solution: functions that access them
+
+function tfm.cleanup_table(tfmdata) -- we need a cleanup callback, now we miss the last one
+ if tfm.auto_cleanup then -- ok, we can hook this into everyshipout or so ... todo
+ if tfmdata.type == 'virtual' or tfmdata.virtualized then
+ for k, v in next, tfmdata.characters do
+ if v.commands then v.commands = nil end
+ -- if v.kerns then v.kerns = nil end
+ end
+ else
+ -- for k, v in next, tfmdata.characters do
+ -- if v.kerns then v.kerns = nil end
+ -- end
+ end
+ end
+end
+
+function tfm.cleanup(tfmdata) -- we need a cleanup callback, now we miss the last one
+end
+
+function tfm.scale(tfmtable, scaledpoints, relativeid)
+ local t, factor = tfm.do_scale(tfmtable, scaledpoints, relativeid)
+ t.factor = factor
+ t.ascender = factor*(tfmtable.ascender or 0)
+ t.descender = factor*(tfmtable.descender or 0)
+ t.shared = tfmtable.shared or { }
+ t.unique = table.fastcopy(tfmtable.unique or {})
+--~ print("scaling", t.name, t.factor) -- , tfm.hash_features(tfmtable.specification))
+ tfm.cleanup(t)
+ return t
+end
+
+--[[ldx--
+
Analyzers run per script and/or language and are needed in order to
+process features right.
+--ldx]]--
+
+fonts.analyzers = fonts.analyzers or { }
+fonts.analyzers.aux = fonts.analyzers.aux or { }
+fonts.analyzers.methods = fonts.analyzers.methods or { }
+fonts.analyzers.initializers = fonts.analyzers.initializers or { }
+
+-- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
+-- e.g. latin -> hyphenate, arab -> 1/2/3 analyze
+
+-- an example analyzer (should move to font-ota.lua)
+
+local state = attributes.private('state')
+
+function fonts.analyzers.aux.setstate(head,font)
+ local tfmdata = fontdata[font]
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
+ while current do
+ local id = current.id
+ if id == glyph and current.font == font then
+ local d = descriptions[current.char]
+ if d then
+ if d.class == "mark" then
+ done = true
+ set_attribute(current,state,5) -- mark
+ elseif n == 0 then
+ first, last, n = current, current, 1
+ set_attribute(current,state,1) -- init
+ else
+ last, n = current, n+1
+ set_attribute(current,state,2) -- medi
+ end
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ elseif id == disc then
+ -- always in the middle
+ set_attribute(current,state,2) -- midi
+ last = current
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ current = current.next
+ end
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ return head, done
+end
+
+function tfm.replacements(tfm,value)
+ -- tfm.characters[0x0022] = table.fastcopy(tfm.characters[0x201D])
+ -- tfm.characters[0x0027] = table.fastcopy(tfm.characters[0x2019])
+ -- tfm.characters[0x0060] = table.fastcopy(tfm.characters[0x2018])
+ -- tfm.characters[0x0022] = tfm.characters[0x201D]
+ tfm.characters[0x0027] = tfm.characters[0x2019]
+ -- tfm.characters[0x0060] = tfm.characters[0x2018]
+end
+
+-- checking
+
+function tfm.checked_filename(metadata,whatever)
+ local foundfilename = metadata.foundfilename
+ if not foundfilename then
+ local askedfilename = metadata.filename or ""
+ if askedfilename ~= "" then
+ foundfilename = resolvers.findbinfile(askedfilename,"") or ""
+ if foundfilename == "" then
+ logs.report("fonts","source file '%s' is not found",askedfilename)
+ foundfilename = resolvers.findbinfile(file.basename(askedfilename),"") or ""
+ if foundfilename ~= "" then
+ logs.report("fonts","using source file '%s' (cache mismatch)",foundfilename)
+ end
+ end
+ elseif whatever then
+ logs.report("fonts","no source file for '%s'",whatever)
+ foundfilename = ""
+ end
+ metadata.foundfilename = foundfilename
+ -- logs.report("fonts","using source file '%s'",foundfilename)
+ end
+ return foundfilename
+end
+
+-- status info
+
+statistics.register("fonts load time", function()
+ return statistics.elapsedseconds(fonts)
+end)
diff --git a/tex/context/base/font-tra.mkiv b/tex/context/base/font-tra.mkiv
new file mode 100644
index 000000000..e47c8c49d
--- /dev/null
+++ b/tex/context/base/font-tra.mkiv
@@ -0,0 +1,113 @@
+%D \module
+%D [ file=font-tra,
+%D version=2009.01.02, % or so
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Tracing,
+%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.
+
+\unprotect
+
+%D \macros
+%D {doiffontpresentelse}
+%D
+%D \starttyping
+%D \doiffontpresentelse{texnansi-lmr10}{YES}{NO}
+%D \doiffontpresentelse{adam-lindsay-modern-serif}{YES}{NO}
+%D \stoptyping
+
+\def\doiffontpresentelse#1{\ctxlua{commands.doifelse(fonts.names.exists("#1"))}}
+
+% experimental, maybe this becomes a module
+
+\newbox\otfcollector
+
+\unexpanded\def\startotfcollecting{\ctxlua{nodes.tracers.steppers.start()}}
+\unexpanded\def\stopotfcollecting {\ctxlua{nodes.tracers.steppers.stop()}}
+\def\resetotfcollecting{\ctxlua{nodes.tracers.steppers.reset()}}
+
+% Rather experimental:
+%
+% \page \showotfcomposition{arabtype*arab-default at 48pt}{-1}{الضَّرَّ} \page
+% \page \showotfcomposition{arabtype*arab-default at 48pt}{-1}{لِلّٰهِ} \page
+
+\def\showotfstepglyphs#1%
+ {\ctxlua{nodes.tracers.steppers.glyphs(\number\otfcollector,#1)}%
+ \unhbox\otfcollector}
+
+\def\otfstepcharcommand#1#2% font char
+ {\removeunwantedspaces
+ \hskip.5em plus .125em\relax
+ U+\hexnumber{#2}:\ruledhbox{\ctxlua{nodes.tracers.fontchar(#1,#2)}}%
+ \hskip.5em plus .125em\relax}
+
+\def\otfstepmessagecommand#1#2%
+ {\begingroup
+ \tttf\language\minusone
+ \veryraggedright
+ \hangindent1em
+ \hangafter\plusone
+ \dontleavehmode\hbox{\detokenize{#1}}\removeunwantedspaces
+ \doifsomething{#2}{\break\detokenize{#2}}\endgraf
+ \endgroup
+ \blank}
+
+\def\showotfstepchars#1%
+ {\ctxlua{nodes.tracers.steppers.codes(#1,\!!bs\detokenize{\otfstepcharcommand}\!!es)}}
+
+\def\showotfstepmessages#1%
+ {\ctxlua{nodes.tracers.steppers.messages(#1,\!!bs\detokenize{\otfstepmessagecommand}\!!es,true)}}
+
+\def\showotfstepfeatures
+ {\ctxlua{nodes.tracers.steppers.features()}}
+
+\def\showotfsteps
+ {\dontleavehmode\bgroup\tttf \language\minusone features: \showotfstepfeatures\egroup
+ \blank
+ \dontleavehmode\bgroup\tttf result:\egroup
+ \blank
+ \startlinecorrection
+ \ruledhbox\bgroup\box\otfcompositionbox\egroup
+ \stoplinecorrection
+ \dorecurse{\ctxlua{nodes.tracers.steppers.nofsteps()}}
+ {\blank
+ \showotfstepmessages\recurselevel
+ \blank
+ \startlinecorrection
+ \dontleavehmode\bgroup\resetallattributes\pardir TLT\textdir TLT\relax\tttf\recurselevel: \showotfstepchars\recurselevel\egroup
+ \stoplinecorrection
+ \blank
+ \startlinecorrection
+ \ruledhbox % can be mode
+ \bgroup\resetallattributes\showotfstepglyphs\recurselevel\egroup % reset is new, we don't want additional processing
+ \stoplinecorrection
+ \blank}}
+
+\unexpanded\def\startotfsample
+ {\enabletrackers[*otf.sample]% beware, kind of global
+ \startotfcollecting
+ \begingroup}
+
+\unexpanded\def\stopotfsample
+ {\endgroup
+ \stopotfcollecting
+ \disabletrackers[*otf.sample]% beware, kind of global: otf.sample
+ \showotfsteps
+ \resetotfcollecting}
+
+\newbox\otfcompositionbox
+
+\def\showotfcomposition#1#2#3% {font*features at size}, rl=-1, text
+ {\begingroup
+ \setupcolors[\c!state=\v!start]% can be option
+ \startotfsample
+ \global\setbox\otfcompositionbox\hbox{\definedfont[#1]\ifnum#2<0 \textdir TRT\else\ifnum#2>0 \textdir TLT\fi\fi\relax#3}%
+ \stopotfsample
+ \endgroup}
+
+\protect \endinput
diff --git a/tex/context/base/font-uni.mkii b/tex/context/base/font-uni.mkii
new file mode 100644
index 000000000..02ab6ce2c
--- /dev/null
+++ b/tex/context/base/font-uni.mkii
@@ -0,0 +1,444 @@
+%D \module
+%D [ file=font-uni,
+%D version=1999.10.10,
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=\UNICODE,
+%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 Font Macros / Unicode}
+
+%D In \XETEX, unicode support is straightforward, so we
+%D simply output a \type {\char} with a 16||bit number.
+
+\ifnum\texengine=\xetexengine
+ \unexpanded\def\uchar#1#2{\char\numexpr#2+#1*\pluscclvi\relax}
+ \let\uc\uchar
+ \expandafter \endinput
+\fi
+
+%D Now comes the more traditional 8 bit \TEX\ hackery.
+
+%D I wrote this module when Wang Lei asked me how to use
+%D Chinese in \CONTEXT. From the samples he sent me, I deduced
+%D that some mixture of one and two byte encoding was used,
+%D which he confirmed. Since \TEX\ normally does not use the
+%D characters $>127$, so as long as the two byte characters
+%D have a first character with code $>127$, we can use active
+%D characters to handle them. In an optimistic mood, I called
+%D this module the \UNICODE\ font module. In the module that
+%D handles Chinese, we will see that some more interpretation
+%D is involved, which is why the macros handling those
+%D characters look ahead.
+
+\unprotect
+
+%D \macros
+%D {handleunicodeflowglyph, uchar,
+%D handleunicodeglyph, insertunicodeglyph,
+%D unicodeposition, unicodeone, unicodetwo}
+%D
+%D For the moment \UNICODE\ support is rather primitive but
+%D nevertheless effective. The reference to \UNICODE\ is not
+%D entirely correct, since in many cases one will use \quote
+%D {older} mappings, but in principle, \UNICODE\ can be
+%D supported.
+%D
+%D We expect each character to come as two eight bit
+%D characters. Those doubles are handled by making all
+%D characters in the range $>127$ active, so that they can
+%D pick up the next one, and act upon both their values.
+%D Internally only numbers are used. A first implementation
+%D simply internally prefixed the second part of the \UNICODE\
+%D pair with \type {\string} or \type {\char}, but this was
+%D not that handy when it came to testing those values.
+%D Because in principle we are dealing with an encoding, the
+%D making active is handled in \type {enco-uni}.
+%D
+%D There are two commands to handle unicode characters:
+%D
+%D \starttyping
+%D \handleunicodeflowglyph{number}{character}
+%D \uchar{number}{number}
+%D \stoptyping
+%D
+%D The first one can be assigned to an active character, the
+%D second one can be used to directly access a glyph. Both
+%D command call \type {\handleunicodeglyph} that in turn
+%D calls \type {\insertunicodeglyph}. Both can be overruled
+%D in specialized modules. The low level command \type
+%D {\unicodeglyph} can best be left untouched, which is not
+%D so much a problem because there is a hook into this macro:
+%D \type {\unicodecharcommand}.
+%D
+%D In most cases one will redefine \type {\handleunicodeglyph}
+%D in such a way that it identifies special situations first,
+%D takes some actions next, calls \type {\insertunicodeglyph},
+%D if needed with \type {\unicodecharcommand} changed, and
+%D finally does some finishing:
+%D
+%D \starttyping
+%D \def\handleunicodeglyph
+%D {take actions based on \unicodeone-two-position cq. \nextutoken
+%D redefine \unicodecharcommand if needed
+%D expand \insertunicodeglyph
+%D take some final actions}
+%D \stoptyping
+
+\newcount\unicodeposition
+
+%D The multistep approach is needed to pick up the second
+%D token, since this token can have any value and any
+%D catcode.
+
+% the \relax trick prevents eating up the space (needed for
+% korean
+
+\def\handleunicodeflowglyph#1#2%
+ {\begingroup
+ \edef\unicodeone{#1}%
+ \@EA\afterassignment\@EA\dohandleunicodeflowglyph % two redundant ea's
+ \@EA\chardef\@EA\nexttoken\@EA`\string#2\relax}
+
+\def\dohandleunicodeflowglyph\relax
+ {\futurelet\nextutoken\dodohandleunicodeflowglyph}
+
+\def\dodohandleunicodeflowglyph % todo tex (or maybe no longer)
+ {\edef\unicodetwo{\the\nexttoken}%
+ \unicodeposition\numexpr\unicodeone*256+\unicodetwo\relax
+ \handleunicodeglyph
+ \endgroup}
+
+\unexpanded\def\uchar#1#2% use as standalone glyph
+ {\begingroup
+ \edef\unicodeone{#1}%
+ \edef\unicodetwo{#2}%
+ \unicodeposition\numexpr\unicodeone*256+\unicodetwo\relax
+ \handleunicodeglyph
+ \endgroup}
+
+\let\nextutoken\relax
+
+\unexpanded\def\lookaheaduchar#1#2%
+ {\def\dolookaheaduchar{\uchar{#1}{#2}\let\nextutoken\relax}%
+ \futurelet\nextutoken\dolookaheaduchar}
+
+\def\dohandleucflowglyph
+ {\unicodeposition\numexpr\unicodeone*256+\unicodetwo\relax
+ \handleunicodeglyph
+ \endgroup}
+
+\unexpanded\def\uc#1#2% used in tricky situations
+ {\begingroup
+ \edef\unicodeone{#1}%
+ \edef\unicodetwo{#2}%
+ \futurelet\nextutoken\dohandleucflowglyph}
+
+\def\insertunicodeglyph
+ {\unicodeglyph\unicodeone\unicodetwo}
+
+\let\handleunicodeglyph\insertunicodeglyph
+
+%D One can use the \type {\unicodeposition} in the macros
+%D that handle pre and post material.
+
+%D \macros
+%D {unicodestyle, unicodecharcommand}
+%D
+%D Each character pair will become one glyph. Because \TEX\
+%D cannot handle fonts with more that 256 characters, we use
+%D \TFM\ files for each range. The first character of the pair
+%D is appended to the name of a font, and the second is used to
+%D access the glyph in that font. This means that a particular
+%D font is split up in subfonts with names in the range:
+%D
+%D \starttyping
+%D 80 ... ff
+%D \stoptyping
+%D
+%D The \type {} as well as the composed name are
+%D mapped ones. The next macros take care of this mapping.
+%D Let us assume that the next mapping has taken place,
+%D
+%D \starttyping
+%D \definefontsynonym [UnicodeRegular] [gbsong]
+%D \stoptyping
+%D
+%D Let us also assume that we are dealing with the range \type
+%D {b1}. Given that a font name results from:
+%D
+%D \starttyping
+%D \truefontname{\truefontname{UnicodeRegular}b1}
+%D \stoptyping
+%D
+%D we get \type {gbsongb1}. The outer \type {\truefontname}
+%D takes care of additional mapping, so when we say:
+%D
+%D \starttyping
+%D \definefontsynonym [gbsongb1] [gbsong-b1]
+%D \stoptyping
+%D
+%D the filename used will be \type {gbsong-b1}. From the next
+%D definition it will be clear that other fontshapes are also
+%D supported. The prefix \type {Unicode} is mapped!
+%D
+%D The command \type {\unicodecharcommand} can be used to
+%D handle special cases. At that moment \type {1em} is known.
+
+\def\unicodestyle
+ {\truefontname\s!Unicode\fontstylesuffix}
+
+\let\unicodecharcommand\firstofoneargument
+
+\unexpanded\def\unicodeglyph#1#2% watch the double mapping
+ {\begingroup
+ \getvalue{@@\currentucharmapping\strippedcsname\uchar}{#1}{#2}% map to a to hex font range
+ \bodyfontsize\unicodescale\bodyfontsize
+ % readable:
+ % \doifelsefontsynonym{\unicodestyle\unicodeone}
+ % {\font\unicodefont=\truefontname{\unicodestyle\unicodeone}
+ % at \currentfontscale\bodyfontsize}
+ % {\font\unicodefont=\truefontname{\truefontname\unicodestyle\unicodeone}
+ % at \currentfontscale\bodyfontsize}%
+ % unreadable but more efficient:
+ \font\unicodefont=\truefontname{\doifelsefontsynonym{\unicodestyle
+ \unicodeone}\empty\truefontname\unicodestyle\unicodeone}
+ at \currentfontscale\bodyfontsize
+ \unicodestrut % off by default
+ \unicodefont\unicodecharcommand{\char\unicodetwo\relax}%
+ \endgroup}
+
+%D This handler is used by default, for instance in:
+%D
+%D \starttyping
+%D \defineunicodefont [MySwitch] [MyFont] % [strut=no,command=\insertunicodeglyph]
+%D
+%D \definefontsynonym [MyFontRegular40] [Sans]
+%D \definefontsynonym [MyFontBold40] [SansBold]
+%D
+%D {\MySwitch \uchar{"40}{`a}}
+%D {\MySwitch \bf \uchar{"40}{`a}}
+%D \stoptyping
+%D
+%D \starttyping
+%D \definefontsynonym [MyFontRegular] [Sans]
+%D \definefontsynonym [MyFontBold] [SansBold]
+%D \stoptyping
+%D
+%D Is also possible, but in that case the number is appended to the raw font
+%D name!
+
+%D \macros
+%D {currentucharmapping,defineucharmapping}
+%D
+%D A (plane,char) pair can be remapped using a uchar mapping
+%D function. The default mapping is to convert the plane to a
+%D lowercase hexadecimal number, and leave the number
+%D untouched. The current remapping is kept in a macro.
+
+\let\currentucharmapping\s!default
+
+\def\defineucharmapping#1%
+ {\setvalue{@@#1\strippedcsname\uchar}}
+
+\defineucharmapping{\s!default}#1#2%
+ {\edef\unicodeone{\lchexnumbers{#1}}\edef\unicodetwo{#2}}
+
+%D An example of a remapping is the following:
+%D
+%D \starttyping
+%D \defineucharmapping{GBK}#1#2%
+%D {\unicodeposition=#1
+%D \advance\unicodeposition -129
+%D \multiply\unicodeposition 190
+%D \advance\unicodeposition #2
+%D \advance\unicodeposition-\ifnum#2>127 65\else64\fi
+%D \dorepositionunicode}
+%D \stoptyping
+%D
+%D This maps the GBK vector onto a compact GBK one. The
+%D auxiliary macro is defined here as a goody.
+
+\def\dorepositionunicode
+ {\dosetdivision\unicodeposition{256}\scratchcounter
+ \advance\scratchcounter \plusone
+ \edef\unicodeone{\ifnum\scratchcounter<10 0\fi\the\scratchcounter}%
+ \dosetmodulo\unicodeposition{256}\scratchcounter
+ \edef\unicodetwo{\the\scratchcounter}}
+
+%D \macros
+%D {setunicodestrut, setunicodescale, nextutoken,
+%D handleunicodeglyph, insertunicodeglyph}
+%D
+%D A careful analysis of the previous macros, learns that the
+%D process of mapping comes down to:
+%D
+%D \startitemize[packed,n]
+%D \item taking care of preceding material (and spacing)
+%D \item defining the font at \type {\currentfontscale} $\times$
+%D \type {\unicodescale} $\times$ \type {\bodyfontsize}
+%D \item inserting a \type {\unicodestrut}
+%D \item inserting the character (glyph)
+%D \item executing some actions afterwards
+%D \stopitemize
+%D
+%D The actions before and after placing the glyph, is up to
+%D the user supplied handler. This handler (\type
+%D {\handleunicodeglpyh}) must, at a certain moment, insert
+%D the glyph using \type {\insertunicodeglyph}
+
+\def\setunicodescale#1%
+ {\def\unicodescale{#1}}
+
+\def\dosetunicodestrut#1#2% height depth
+ {\def\unicodestrut
+ {\vrule
+ \!!width \zeropoint
+ \!!height#1\strutht
+ \!!depth #2\strutdp
+ \relax}}
+
+\def\setunicodestrut#1#2% height depth
+ {\ifdim#1\strutht>\zeropoint
+ \dosetunicodestrut{#1}{#2}%
+ \else\ifdim#1\strutdp>\zeropoint
+ \dosetunicodestrut{#1}{#2}%
+ \else
+ \let\unicodestrut\empty
+ \fi\fi}
+
+\def\resetunicodestrut
+ {\let\unicodestrut\empty}
+
+%D The additional scaling and strut default to:
+
+\setunicodescale{1}
+\setunicodestrut{1}{1}
+
+%D But better is not to have a strut added by default:
+
+\resetunicodestrut
+
+%D The actual code for the additional actions as well as
+%D specific spacing is handled outside these routines. The
+%D character after the two that are under treatment is
+%D available in \type {\nextutoken}.
+
+%D \macros
+%D {defineunicodefont, setupunicodefont}
+%D
+%D Apart from this rather low level implementation, we also
+%D provide a more user friendly alternative. Given that one
+%D has defined:
+%D
+%D \starttyping
+%D \defineunicodefont
+%D [SimChi] [SimplifiedChinese]
+%D [\c!scale=0.85,
+%D \c!height=1.25,
+%D \c!depth=1.00,
+%D \c!interlinespaceinterlinie=yes,
+%D \c!conversion=\chinesenumber,
+%D \c!command=\handlechineseunicodeglyph]
+%D \stoptyping
+%D
+%D Together with:
+%D
+%D \starttyping
+%D \definefontsynonym [SimplifiedChineseRegular] [gbsong]
+%D \definefontsynonym [SimplifiedChineseSlanted] [gbsongsl]
+%D \stoptyping
+%D
+%D we can now switch to Simplified Chinese by saying \type
+%D {SimChi}. Some values can be changed afterwards with
+%D
+%D \starttyping
+%D \setupunicodefont[SimChi][...=...]
+%D \stoptyping
+%D
+%D Specific initializations can be assigned to \type
+%D {commands}.
+
+\def\defineunicodefont
+ {\dotripleempty\dodefineunicodefont}
+
+\def\dodefineunicodefont[#1][#2][#3]%
+ {\doifassignmentelse{#3}
+ {\setupunicodefont[#1][#3]}
+ {\doifelsenothing{#3}
+ {\setupunicodefont[#1][#3]}
+ {\copyparameters
+ [\??uc#1][\??uc#3]
+ [\c!height,\c!depth,\c!scale,\c!commands,\c!strut,
+ \c!interlinespace,\c!command,\c!conversion]}}%
+ \doifelsenothing{#2}
+ {\setvalue{#1}{[uc font #1 undefined]}}
+ {\setvalue{\??uc#1\c!file}{#2}%
+ \doifundefined{\??ff#2\s!Bold}
+ {\definefontsynonym[#2\s!Bold] [#2\s!Regular]%
+ \definefontsynonym[#2\s!Slanted] [#2\s!Regular]%
+ \definefontsynonym[#2\s!Italic] [#2\s!Regular]%
+ \definefontsynonym[#2\s!BoldSlanted][#2\s!Slanted]%
+ \definefontsynonym[#2\s!BoldItalic] [#2\s!Italic]}%
+ \unexpanded\setvalue{#1}{\enableunicodefont{#1}}}}
+
+\def\setupunicodefont
+ {\dodoubleempty\dosetupunicodefont}
+
+\def\dosetupunicodefont[#1][#2]% also predefines
+ {\doifundefined{\??uc#1\c!command}
+ {\copyparameters
+ [\??uc#1][\??uc\s!default]
+ [\c!height,\c!depth,\c!scale,\c!commands,\v!strut,
+ \c!interlinespace,\c!command,\c!conversion]}%
+ \getparameters[\??uc#1][#2]}
+
+\def\enableunicodefont#1%
+ {\definefontsynonym[\s!Unicode][\getvalue{\??uc#1\c!file}]%
+ \def\unicodescale {\getvalue{\??uc#1\c!scale}}%
+ \def\unicodeheight {\getvalue{\??uc#1\c!height}}%
+ \def\unicodedepth {\getvalue{\??uc#1\c!depth}}%
+ \def\unicodedigits {\getvalue{\??uc#1\c!conversion}}%
+ \def\handleunicodeglyph {\getvalue{\??uc#1\c!command}}%
+ \doifnot\currentregime{utf}{\enableregime[unicode]}%
+ % the following \relax's are realy needed
+ \doifvalue{\??uc#1\c!interlinespace}\v!yes
+ \setupinterlinespace\relax
+ \doifelsevalue{\??uc#1\c!strut}\v!yes
+ {\setunicodestrut\unicodeheight\unicodedepth}
+ {\resetunicodestrut}%
+ \getvalue{\??uc#1\c!commands}\relax}
+
+%D \macros
+%D {unicodedigits}
+%D
+%D For convenience we also predefine a number conversion
+%D macro:
+
+\let\unicodedigits\number
+
+%D Because we cannot be sure of the pressence of all font
+%D styles, we remap some by default.
+
+\definefontsynonym [\s!Unicode\s!Bold] [\s!Unicode\s!Regular]
+\definefontsynonym [\s!Unicode\s!Slanted] [\s!Unicode\s!Regular]
+\definefontsynonym [\s!Unicode\s!Italic] [\s!Unicode\s!Regular]
+\definefontsynonym [\s!Unicode\s!BoldSlanted] [\s!Unicode\s!Slanted]
+\definefontsynonym [\s!Unicode\s!BoldItalic] [\s!Unicode\s!Italic]
+
+\setupunicodefont
+ [\s!default]
+ [\c!height=1,
+ \c!depth=1,
+ \c!scale=1,
+ \c!strut=\v!no,
+ \c!interlinespace=\v!no,
+ \c!command=\insertunicodeglyph,
+ \c!conversion=\number]
+
+\protect \endinput
diff --git a/tex/context/base/font-uni.mkiv b/tex/context/base/font-uni.mkiv
new file mode 100644
index 000000000..40ab75ed6
--- /dev/null
+++ b/tex/context/base/font-uni.mkiv
@@ -0,0 +1,26 @@
+%D \module
+%D [ file=font-uni,
+%D version=2008.11.03, % 1999.10.10,
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=\UNICODE,
+%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 Font Macros / Unicode}
+
+%D In \MKIV\ we only provide the \type {\uchar} macro and
+%D implement it as just an \UTF\ converter. We expand it so
+%D best not use not use it for active characters.
+
+\unprotect
+
+\def\uchar#1#2{\ctxlua{commands.uchar(\number#1,\number#2)}}
+
+\let\uc\uchar
+
+\protect \endinput
diff --git a/tex/context/base/font-unk.mkii b/tex/context/base/font-unk.mkii
new file mode 100644
index 000000000..30f824781
--- /dev/null
+++ b/tex/context/base/font-unk.mkii
@@ -0,0 +1,187 @@
+%D \module
+%D [ file=font-unk,
+%D version=1998.09.10,
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Unknown Defaults,
+%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.
+
+%D This module is rather important, because it enables us to
+%D define and call for not yet defined fonts in a way
+%D completely independant of real font names. First we map
+%D some meaningful names onto unknown filenames.
+
+\unprotect
+
+\definefontsynonym [Serif] [unknown]
+\definefontsynonym [SerifBold] [unknown]
+\definefontsynonym [SerifItalic] [unknown]
+\definefontsynonym [SerifSlanted] [unknown]
+\definefontsynonym [SerifBoldItalic] [unknown]
+\definefontsynonym [SerifBoldSlanted] [unknown]
+\definefontsynonym [SerifCaps] [unknown]
+
+\definefontsynonym [Sans] [unknown]
+\definefontsynonym [SansBold] [unknown]
+\definefontsynonym [SansItalic] [unknown]
+\definefontsynonym [SansSlanted] [unknown]
+\definefontsynonym [SansBoldItalic] [unknown]
+\definefontsynonym [SansBoldSlanted] [unknown]
+\definefontsynonym [SansCaps] [unknown]
+
+\definefontsynonym [Mono] [unknown]
+\definefontsynonym [MonoBold] [unknown]
+\definefontsynonym [MonoItalic] [unknown]
+\definefontsynonym [MonoSlanted] [unknown]
+\definefontsynonym [MonoBoldItalic] [unknown]
+\definefontsynonym [MonoBoldSlanted] [unknown]
+\definefontsynonym [MonoCaps] [unknown]
+
+\definefontsynonym [MathRoman] [unknown]
+\definefontsynonym [MathExtension] [unknown]
+\definefontsynonym [MathItalic] [unknown]
+\definefontsynonym [MathSymbol] [unknown]
+
+\definefontsynonym [MathNoName] [unknown]
+
+\definefontsynonym [MathAlpha] [unknown]
+\definefontsynonym [MathBeta] [unknown]
+\definefontsynonym [MathGamma] [unknown]
+\definefontsynonym [MathDelta] [unknown]
+
+\definefontsynonym [MathRomanBold] [MathRoman]
+\definefontsynonym [MathExtensionBold] [MathExtension]
+\definefontsynonym [MathItalicBold] [MathItalic]
+\definefontsynonym [MathSymbolBold] [MathSymbol]
+\definefontsynonym [MathAlphaBold] [MathAlpha]
+\definefontsynonym [MathBetaBold] [MathBeta]
+\definefontsynonym [MathGammaBold] [MathGamma]
+\definefontsynonym [MathDeltaBold] [MathDelta]
+
+\definefontsynonym [Handwriting] [unknown]
+\definefontsynonym [Calligraphic] [unknown]
+
+%D This permit us to define (use) fonts that refer to the default
+%D style (so, Bold may expand to SansBold or SerifBold, depending
+%D on the default style in the typeface).
+
+% \def\setfontsynonym[#1]#2[#3]{\setvalue{\??ff\fontclass#1}{#3}}
+%
+% \setfontsynonym[\s!Normal] [\fontstringD]
+% \setfontsynonym[\s!Bold] [\fontstringD\s!Bold]
+% \setfontsynonym[\s!Italic] [\fontstringD\s!Italic]
+% \setfontsynonym[\s!Slanted] [\fontstringD\s!Slanted]
+% \setfontsynonym[\s!BoldItalic] [\fontstringD\s!BoldItalic]
+% \setfontsynonym[\s!BoldSlanted][\fontstringD\s!BoldSlanted]
+% \setfontsynonym[\s!Caps] [\fontstringD\s!Caps]
+
+\definefontsynonym[\s!Normal] [\noexpand\fontstringD]
+\definefontsynonym[\s!Bold] [\noexpand\fontstringD\noexpand\s!Bold]
+\definefontsynonym[\s!Italic] [\noexpand\fontstringD\noexpand\s!Italic]
+\definefontsynonym[\s!Slanted] [\noexpand\fontstringD\noexpand\s!Slanted]
+\definefontsynonym[\s!BoldItalic] [\noexpand\fontstringD\noexpand\s!BoldItalic]
+\definefontsynonym[\s!BoldSlanted][\noexpand\fontstringD\noexpand\s!BoldSlanted]
+\definefontsynonym[\s!Caps] [\noexpand\fontstringD\noexpand\s!Caps]
+
+%D Also handy:
+
+\definefontsynonym [Regular] [Serif]
+\definefontsynonym [RegularBold] [SerifBold]
+\definefontsynonym [RegularItalic] [SerifItalic]
+\definefontsynonym [RegularSlanted] [SerifSlanted]
+\definefontsynonym [RegularBoldItalic] [SerifBoldItalic]
+\definefontsynonym [RegularBoldSlanted] [SerifBoldSlanted]
+\definefontsynonym [RegularCaps] [SerifCaps]
+
+\definefontsynonym [Support] [Sans]
+\definefontsynonym [SupportBold] [SansBold]
+\definefontsynonym [SupportItalic] [SansItalic]
+\definefontsynonym [SupportSlanted] [SansSlanted]
+\definefontsynonym [SupportBoldItalic] [SansBoldItalic]
+\definefontsynonym [SupportBoldSlanted] [SansBoldSlanted]
+\definefontsynonym [SupportCaps] [SansCaps]
+
+%D Well, not that good an idea:
+
+\definefontsynonym [Roman] [Serif]
+\definefontsynonym [RomanBold] [SerifBold]
+\definefontsynonym [RomanItalic] [SerifItalic]
+\definefontsynonym [RomanSlanted] [SerifSlanted]
+\definefontsynonym [RomanBoldItalic] [SerifBoldItalic]
+\definefontsynonym [RomanBoldSlanted] [SerifBoldSlanted]
+\definefontsynonym [RomanCaps] [SerifCaps]
+
+\definefontsynonym [Type] [Mono]
+\definefontsynonym [TypeBold] [MonoBold]
+\definefontsynonym [TypeItalic] [MonoItalic]
+\definefontsynonym [TypeSlanted] [MonoSlanted]
+\definefontsynonym [TypeBoldItalic] [MonoBoldItalic]
+\definefontsynonym [TypeBoldSlanted] [MonoBoldSlanted]
+\definefontsynonym [TypeCaps] [MonoCaps]
+
+%D Next we define roman, sans and monospaced font sets.
+
+\definebodyfont [default] [rm]
+ [tf=Serif sa 1,
+ bf=SerifBold sa 1,
+ it=SerifItalic sa 1,
+ sl=SerifSlanted sa 1,
+ bi=SerifBoldItalic sa 1,
+ bs=SerifBoldSlanted sa 1,
+ sc=SerifCaps sa 1]
+
+\definebodyfont [default] [ss]
+ [tf=Sans sa 1,
+ bf=SansBold sa 1,
+ it=SansItalic sa 1,
+ sl=SansSlanted sa 1,
+ bi=SansBoldItalic sa 1,
+ bs=SansBoldSlanted sa 1,
+ sc=SansCaps sa 1]
+
+\definebodyfont [default] [tt]
+ [tf=Mono sa 1,
+ bf=MonoBold sa 1,
+ it=MonoItalic sa 1,
+ sl=MonoSlanted sa 1,
+ bi=MonoBoldItalic sa 1,
+ bs=MonoBoldSlanted sa 1,
+ sc=MonoCaps sa 1]
+
+\definebodyfont [default] [mm]
+ [mr=MathRoman mo 1,
+ ex=MathExtension mo 1,
+ mi=MathItalic mo 1,
+ sy=MathSymbol mo 1,
+ nn=MathNoName mo 1,
+ ma=MathAlpha mo 1,
+ mb=MathBeta mo 1,
+ mc=MathGamma mo 1,
+ md=MathDelta mo 1]
+
+\definebodyfont [bfmath] [mm]
+ [mrbf=MathRomanBold mo 1,
+ exbf=MathExtensionBold mo 1,
+ mibf=MathItalicBold mo 1,
+ sybf=MathSymbolBold mo 1,
+ mabf=MathAlphaBold mo 1,
+ mbbf=MathBetaBold mo 1,
+ mcbf=MathGammaBold mo 1,
+ mdbf=MathDeltaBold mo 1]
+
+\definebodyfont [default] [hw]
+ [tf=Handwriting sa 1]
+
+\definebodyfont [default] [cg]
+ [tf=Calligraphy sa 1]
+
+%D These definitions come into action as soon as names are
+%D mapped onto real file names (or names that themselves are
+%D mapped).
+
+\protect \endinput
diff --git a/tex/context/base/font-unk.mkiv b/tex/context/base/font-unk.mkiv
new file mode 100644
index 000000000..bd699ef71
--- /dev/null
+++ b/tex/context/base/font-unk.mkiv
@@ -0,0 +1,162 @@
+%D \module
+%D [ file=font-unk,
+%D version=1998.09.10,
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Unknown Defaults,
+%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.
+
+%D This module is rather important, because it enables us to
+%D define and call for not yet defined fonts in a way
+%D completely independant of real font names. First we map
+%D some meaningful names onto unknown filenames.
+
+\unprotect
+
+\definefontsynonym [Serif] [unknown]
+\definefontsynonym [SerifBold] [unknown]
+\definefontsynonym [SerifItalic] [unknown]
+\definefontsynonym [SerifSlanted] [unknown]
+\definefontsynonym [SerifBoldItalic] [unknown]
+\definefontsynonym [SerifBoldSlanted] [unknown]
+\definefontsynonym [SerifCaps] [unknown]
+
+\definefontsynonym [Sans] [unknown]
+\definefontsynonym [SansBold] [unknown]
+\definefontsynonym [SansItalic] [unknown]
+\definefontsynonym [SansSlanted] [unknown]
+\definefontsynonym [SansBoldItalic] [unknown]
+\definefontsynonym [SansBoldSlanted] [unknown]
+\definefontsynonym [SansCaps] [unknown]
+
+\definefontsynonym [Mono] [unknown]
+\definefontsynonym [MonoBold] [unknown]
+\definefontsynonym [MonoItalic] [unknown]
+\definefontsynonym [MonoSlanted] [unknown]
+\definefontsynonym [MonoBoldItalic] [unknown]
+\definefontsynonym [MonoBoldSlanted] [unknown]
+\definefontsynonym [MonoCaps] [unknown]
+
+\definefontsynonym [MathRoman] [unknown]
+\definefontsynonym [MathExtension] [unknown]
+\definefontsynonym [MathItalic] [unknown]
+\definefontsynonym [MathSymbol] [unknown]
+
+\definefontsynonym [MathNoName] [unknown]
+
+\definefontsynonym [MathAlpha] [unknown]
+\definefontsynonym [MathBeta] [unknown]
+\definefontsynonym [MathGamma] [unknown]
+\definefontsynonym [MathDelta] [unknown]
+
+\definefontsynonym [MathRomanBold] [MathRoman] % todo:
+\definefontsynonym [MathExtensionBold] [MathExtension] % [MathRoman]
+\definefontsynonym [MathItalicBold] [MathItalic] % [MathRoman]
+\definefontsynonym [MathSymbolBold] [MathSymbol] % [MathRoman]
+\definefontsynonym [MathAlphaBold] [MathAlpha] % [MathRoman]
+\definefontsynonym [MathBetaBold] [MathBeta] % [MathRoman]
+\definefontsynonym [MathGammaBold] [MathGamma] % [MathRoman]
+\definefontsynonym [MathDeltaBold] [MathDelta] % [MathRoman]
+
+\definefontsynonym [Handwriting] [unknown]
+\definefontsynonym [Calligraphic] [unknown]
+
+%D This permit us to define (use) fonts that refer to the default
+%D style (so, Bold may expand to SansBold or SerifBold, depending
+%D on the default style in the typeface).
+
+\definefontsynonym[\s!Normal] [\noexpand\fontstringD]
+\definefontsynonym[\s!Bold] [\noexpand\fontstringD\noexpand\s!Bold]
+\definefontsynonym[\s!Italic] [\noexpand\fontstringD\noexpand\s!Italic]
+\definefontsynonym[\s!Slanted] [\noexpand\fontstringD\noexpand\s!Slanted]
+\definefontsynonym[\s!BoldItalic] [\noexpand\fontstringD\noexpand\s!BoldItalic]
+\definefontsynonym[\s!BoldSlanted][\noexpand\fontstringD\noexpand\s!BoldSlanted]
+\definefontsynonym[\s!Caps] [\noexpand\fontstringD\noexpand\s!Caps]
+
+%D Also handy:
+
+\definefontsynonym [Regular] [Serif]
+\definefontsynonym [RegularBold] [SerifBold]
+\definefontsynonym [RegularItalic] [SerifItalic]
+\definefontsynonym [RegularSlanted] [SerifSlanted]
+\definefontsynonym [RegularBoldItalic] [SerifBoldItalic]
+\definefontsynonym [RegularBoldSlanted] [SerifBoldSlanted]
+\definefontsynonym [RegularCaps] [SerifCaps]
+
+\definefontsynonym [Support] [Sans]
+\definefontsynonym [SupportBold] [SansBold]
+\definefontsynonym [SupportItalic] [SansItalic]
+\definefontsynonym [SupportSlanted] [SansSlanted]
+\definefontsynonym [SupportBoldItalic] [SansBoldItalic]
+\definefontsynonym [SupportBoldSlanted] [SansBoldSlanted]
+\definefontsynonym [SupportCaps] [SansCaps]
+
+%D Well, not that good an idea:
+
+\definefontsynonym [Roman] [Serif]
+\definefontsynonym [RomanBold] [SerifBold]
+\definefontsynonym [RomanItalic] [SerifItalic]
+\definefontsynonym [RomanSlanted] [SerifSlanted]
+\definefontsynonym [RomanBoldItalic] [SerifBoldItalic]
+\definefontsynonym [RomanBoldSlanted] [SerifBoldSlanted]
+\definefontsynonym [RomanCaps] [SerifCaps]
+
+\definefontsynonym [Type] [Mono]
+\definefontsynonym [TypeBold] [MonoBold]
+\definefontsynonym [TypeItalic] [MonoItalic]
+\definefontsynonym [TypeSlanted] [MonoSlanted]
+\definefontsynonym [TypeBoldItalic] [MonoBoldItalic]
+\definefontsynonym [TypeBoldSlanted] [MonoBoldSlanted]
+\definefontsynonym [TypeCaps] [MonoCaps]
+
+%D Next we define roman, sans and monospaced font sets.
+
+\definebodyfont [default] [rm]
+ [tf=Serif sa 1,
+ bf=SerifBold sa 1,
+ it=SerifItalic sa 1,
+ sl=SerifSlanted sa 1,
+ bi=SerifBoldItalic sa 1,
+ bs=SerifBoldSlanted sa 1,
+ sc=SerifCaps sa 1]
+
+\definebodyfont [default] [ss]
+ [tf=Sans sa 1,
+ bf=SansBold sa 1,
+ it=SansItalic sa 1,
+ sl=SansSlanted sa 1,
+ bi=SansBoldItalic sa 1,
+ bs=SansBoldSlanted sa 1,
+ sc=SansCaps sa 1]
+
+\definebodyfont [default] [tt]
+ [tf=Mono sa 1,
+ bf=MonoBold sa 1,
+ it=MonoItalic sa 1,
+ sl=MonoSlanted sa 1,
+ bi=MonoBoldItalic sa 1,
+ bs=MonoBoldSlanted sa 1,
+ sc=MonoCaps sa 1]
+
+\definebodyfont [default] [mm]
+ [mr=MathRoman mo 1]
+
+\definebodyfont [bfmath] [mm]
+ [mr=MathRomanBold mo 1]
+
+\definebodyfont [default] [hw]
+ [tf=Handwriting sa 1]
+
+\definebodyfont [default] [cg]
+ [tf=Calligraphy sa 1]
+
+%D These definitions come into action as soon as names are
+%D mapped onto real file names (or names that themselves are
+%D mapped).
+
+\protect \endinput
diff --git a/tex/context/base/font-vf.lua b/tex/context/base/font-vf.lua
new file mode 100644
index 000000000..4f99c47b9
--- /dev/null
+++ b/tex/context/base/font-vf.lua
@@ -0,0 +1,213 @@
+if not modules then modules = { } end modules ['font-vf'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+
This is very experimental code! Not yet adapted to recent
+changes. This will change.
+--ldx]]--
+
+-- define.methods elsewhere !
+
+fonts = fonts or { }
+fonts.vf = fonts.vf or { }
+
+local vf = fonts.vf
+local tfm = fonts.tfm
+
+fonts.define = fonts.define or { }
+fonts.define.methods = fonts.define.methods or { }
+
+vf.combinations = vf.combinations or { }
+vf.aux = vf.aux or { }
+vf.aux.combine = vf.aux.combine or { }
+
+function fonts.define.methods.install(tag, rules)
+ vf.combinations[tag] = rules
+ fonts.define.methods[tag] = function(specification)
+ return vf.combine(specification,tag)
+ end
+end
+
+function vf.aux.combine.assign(g, name, from, to, start, force)
+ local f, id = vf.aux.combine.load(g,name)
+ if f and id then
+ -- optimize for whole range, then just g = f
+ if not from then from, to = 0, 0xFF00 end
+ if not to then to = from end
+ if not start then start = from end
+ local fc, gc = f.characters, g.characters
+ local fd, gd = f.descriptions, g.descriptions
+ local hn = #g.fonts+1
+ g.fonts[hn] = { id = id } -- no need to be sparse
+ for i=from,to do
+ if fc[i] and (force or not gc[i]) then
+ gc[i] = table.fastcopy(fc[i]) -- can be optimized
+ gc[i].commands = { { 'slot', hn, start } }
+ gd[i] = fd[i]
+ end
+ start = start + 1
+ end
+ if not g.parameters and #g.fonts > 0 then -- share this code !
+ g.parameters = table.fastcopy(f.parameters)
+ g.italicangle = f.italicangle
+ g.ascender = f.ascender
+ g.descender = f.descender
+ g.factor = f.factor -- brrr
+ end
+ end
+end
+
+function vf.aux.combine.process(g,list)
+ if list then
+ for _,v in next, list do
+ (vf.aux.combine.commands[v[1]] or nop)(g,v)
+ end
+ end
+end
+
+function vf.aux.combine.load(g,name)
+ return tfm.read_and_define(name or g.specification.name,g.specification.size)
+end
+
+function vf.aux.combine.names(g,name,force)
+ local f, id = tfm.read_and_define(name,g.specification.size)
+ if f and id then
+ local fc, gc = f.characters, g.characters
+ local fd, gd = f.descriptions, g.descriptions
+ g.fonts[#g.fonts+1] = { id = id } -- no need to be sparse
+ local hn = #g.fonts
+ for k, v in next, fc do
+ if force or not gc[k] then
+ gc[k] = table.fastcopy(v)
+ gc[k].commands = { { 'slot', hn, k } }
+ gd[i] = fd[i]
+ end
+ end
+ if not g.parameters and #g.fonts > 0 then -- share this code !
+ g.parameters = table.fastcopy(f.parameters)
+ g.italicangle = f.italicangle
+ g.ascender = f.ascender
+ g.descender = f.descender
+ g.factor = f.factor -- brrr
+ end
+ end
+end
+
+vf.aux.combine.commands = {
+ ["initialize"] = function(g,v) vf.aux.combine.assign (g,g.name) end,
+ ["include-method"] = function(g,v) vf.aux.combine.process (g,vf.combinations[v[2]]) end, -- name
+ ["copy-parameters"] = function(g,v) vf.aux.combine.parameters(g,v[2]) end, -- name
+ ["copy-range"] = function(g,v) vf.aux.combine.assign (g,v[2],v[3],v[4],v[5],true) end, -- name, from-start, from-end, to-start
+ ["copy-char"] = function(g,v) vf.aux.combine.assign (g,v[2],v[3],v[3],v[4],true) end, -- name, from, to
+ ["fallback-range"] = function(g,v) vf.aux.combine.assign (g,v[2],v[3],v[4],v[5],false) end, -- name, from-start, from-end, to-start
+ ["fallback-char"] = function(g,v) vf.aux.combine.assign (g,v[2],v[3],v[3],v[4],false) end, -- name, from, to
+ ["copy_names"] = function(g,v) vf.aux.combine.names (g,v[2],true) end,
+ ["fallback_names"] = function(g,v) vf.aux.combine.names (g,v[2],false) end,
+}
+
+function vf.combine(specification,tag)
+ local g = {
+ name = specification.name,
+ -- type = 'virtual',
+ virtualized = true,
+ fonts = { },
+ characters = { },
+ descriptions = { },
+ specification = table.fastcopy(specification)
+ }
+ vf.aux.combine.process(g,vf.combinations[tag])
+ return g
+end
+
+vf.aux.combine.commands["feature"] = function(g,v)
+ local key, value = v[2], v[3]
+ if key then
+ if value == nil then
+ value = true
+ end
+ if g.specification and g.specification.features.normal then
+ g.specification.features.normal[key] = value -- otf?
+ end
+ end
+end
+
+-- simple example with features
+
+fonts.define.methods.install(
+ "ligatures", {
+ { "feature", "liga" } ,
+ { "feature", "dlig" } ,
+ { "initialize" } ,
+ }
+)
+
+--~ fonts.define.methods.install (
+--~ "ligatures-x", {
+--~ { "feature", "liga" } ,
+--~ { "feature", "dlig" } ,
+--~ { "initialize" } ,
+--~ { "lineheight" }
+--~ }
+--~ )
+
+--~ fonts.define.methods.install(
+--~ "lmsymbol10", {
+--~ { "fallback_names", "lmsy10.afm" } ,
+--~ { "fallback_names", "msam10.afm" } ,
+--~ { "fallback_names", "msbm10.afm" }
+--~ }
+--~ )
+--~ \font\TestFont=dummy@lmsymbol10 at 24pt
+
+-- docu case
+
+--~ fonts.define.methods.install(
+--~ "weird", {
+--~ { "copy-range", "lmroman10-regular" } ,
+--~ { "copy-char", "lmroman10-regular", 65, 66 } ,
+--~ { "copy-range", "lmsans10-regular", 0x0100, 0x01FF } ,
+--~ { "copy-range", "lmtypewriter10-regular", 0x0200, 0xFF00 } ,
+--~ { "fallback-range", "lmtypewriter10-regular", 0x0000, 0x0200 }
+--~ }
+--~ )
+
+-- demo case -> move to module
+
+fonts.define.methods["demo-1"] = function(specification)
+ local name = specification.name -- symbolic name
+ local size = specification.size -- given size
+ local f, id = tfm.read_and_define('lmroman10-regular',size)
+ if f and id then
+ local capscale, digscale = 0.85, 0.75
+ -- f.name, f.type = name, 'virtual'
+ f.name, f.virtualized = name, true
+ f.fonts = {
+ { id = id },
+ { name = 'lmsans10-regular' , size = size*capscale }, -- forced extra name
+ { name = 'lmtypewriter10-regular', size = size*digscale } -- forced extra name
+ }
+ local i_is_of_category = characters.i_is_of_category
+ local characters, descriptions = f.characters, f.descriptions
+ local red = {'special','pdf: 1 0 0 rg'}
+ local green = {'special','pdf: 0 1 0 rg'}
+ local blue = {'special','pdf: 0 0 1 rg'}
+ local black = {'special','pdf: 0 g'}
+ for u,v in next, characters do
+ if u and i_is_of_category(u,'lu') then
+ v.width = capscale*v.width
+ v.commands = { red, {'slot',2,u}, black }
+ elseif u and i_is_of_category(u,'nd') then
+ v.width = digscale*v.width
+ v.commands = { blue, {'slot',3,u}, black }
+ else
+ v.commands = { green, {'slot',1,u}, black }
+ end
+ end
+ end
+ return f
+end
diff --git a/tex/context/base/font-xtx.lua b/tex/context/base/font-xtx.lua
new file mode 100644
index 000000000..eac75dd29
--- /dev/null
+++ b/tex/context/base/font-xtx.lua
@@ -0,0 +1,122 @@
+if not modules then modules = { } end modules ['font-xtx'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local texsprint, count = tex.sprint, tex.count
+local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
+local tostring, next = tostring, next
+local lpegmatch = lpeg.match
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+--[[ldx--
+
Choosing a font by name and specififying its size is only part of the
+game. In order to prevent complex commands, introduced
+a method to pass feature information as part of the font name. At the
+risk of introducing nasty parsing and compatinility problems, this
+syntax was expanded over time.
+
+
For the sake of users who have defined fonts using that syntax, we
+will support it, but we will provide additional methods as well.
+Normally users will not use this direct way, but use a more abstract
+interface.
+
+
The next one is the official one. However, in the plain
+variant we need to support the crappy [] specification as
+well and that does not work too well with the general design
+of the specifier.
+--ldx]]--
+
+--~ function fonts.define.specify.colonized(specification) -- xetex mode
+--~ local list = { }
+--~ if specification.detail and specification.detail ~= "" then
+--~ for v in gmatch(specification.detail,"%s*([^;]+)%s*") do
+--~ local a, b = match(v,"^(%S*)%s*=%s*(%S*)$")
+--~ if a and b then
+--~ list[a] = b:is_boolean()
+--~ if type(list[a]) == "nil" then
+--~ list[a] = b
+--~ end
+--~ else
+--~ local a, b = match(v,"^([%+%-]?)%s*(%S+)$")
+--~ if a and b then
+--~ list[b] = a ~= "-"
+--~ end
+--~ end
+--~ end
+--~ end
+--~ specification.features.normal = list
+--~ return specification
+--~ end
+
+--~ check("oeps/BI:+a;-b;c=d")
+--~ check("[oeps]/BI:+a;-b;c=d")
+--~ check("file:oeps/BI:+a;-b;c=d")
+--~ check("name:oeps/BI:+a;-b;c=d")
+
+local list = { }
+
+fonts.define.specify.colonized_default_lookup = "file"
+
+local function issome () list.lookup = fonts.define.specify.colonized_default_lookup end
+local function isfile () list.lookup = 'file' end
+local function isname () list.lookup = 'name' end
+local function thename(s) list.name = s end
+local function issub (v) list.sub = v end
+local function iscrap (s) list.crap = string.lower(s) end
+local function istrue (s) list[s] = 'yes' end
+local function isfalse(s) list[s] = 'no' end
+local function iskey (k,v) list[k] = v end
+
+local function istrue (s) list[s] = true end
+local function isfalse(s) list[s] = false end
+
+local spaces = lpeg.P(" ")^0
+local namespec = (1-lpeg.S("/:("))^0 -- was: (1-lpeg.S("/: ("))^0
+local crapspec = spaces * lpeg.P("/") * (((1-lpeg.P(":"))^0)/iscrap) * spaces
+local filename = (lpeg.P("file:")/isfile * (namespec/thename)) + (lpeg.P("[") * lpeg.P(true)/isname * (((1-lpeg.P("]"))^0)/thename) * lpeg.P("]"))
+local fontname = (lpeg.P("name:")/isname * (namespec/thename)) + lpeg.P(true)/issome * (namespec/thename)
+local sometext = (lpeg.R("az","AZ","09") + lpeg.S("+-."))^1
+local truevalue = lpeg.P("+") * spaces * (sometext/istrue)
+local falsevalue = lpeg.P("-") * spaces * (sometext/isfalse)
+local keyvalue = (lpeg.C(sometext) * spaces * lpeg.P("=") * spaces * lpeg.C(sometext))/iskey
+local somevalue = sometext/istrue
+local subvalue = lpeg.P("(") * (lpeg.C(lpeg.P(1-lpeg.S("()"))^1)/issub) * lpeg.P(")") -- for Kim
+local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces
+local options = lpeg.P(":") * spaces * (lpeg.P(";")^0 * option)^0
+local pattern = (filename + fontname) * subvalue^0 * crapspec^0 * options^0
+
+local normalize_meanings = fonts.otf.meanings.normalize
+
+function fonts.define.specify.colonized(specification) -- xetex mode
+ list = { }
+ lpegmatch(pattern,specification.specification)
+--~ for k, v in next, list do
+--~ list[k] = v:is_boolean()
+--~ if type(list[a]) == "nil" then
+--~ list[k] = v
+--~ end
+--~ end
+ list.crap = nil -- style not supported, maybe some day
+ if list.name then
+ specification.name = list.name
+ list.name = nil
+ end
+ if list.lookup then
+ specification.lookup = list.lookup
+ list.lookup = nil
+ end
+ if list.sub then
+ specification.sub = list.sub
+ list.sub = nil
+ end
+-- specification.features.normal = list
+ specification.features.normal = normalize_meanings(list)
+ return specification
+end
+
+fonts.define.register_split(":", fonts.define.specify.colonized)
diff --git a/tex/context/base/font-xtx.mkii b/tex/context/base/font-xtx.mkii
new file mode 100644
index 000000000..d6086b44e
--- /dev/null
+++ b/tex/context/base/font-xtx.mkii
@@ -0,0 +1,376 @@
+%D \module
+%D [ file=font-xtx,
+%D version=2004.09.11,
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=\XETEX\ Hacks,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\ifnum\texengine=\xetexengine
+ \writestatus{loading}{ConTeXt Font Macros / XeTeX Hacks}
+\else
+ \endinput
+\fi
+
+\unprotect
+
+%D Loading:
+
+%D for some reason xetex does not support [filename] for tfm files and
+%D quotes also behave kind of strange " vs ' vs [ vs ...
+%D
+%D \starttyping
+%D \font\myfont = msam7 % ok
+%D \font\myfont = "msam7" % also ok
+%D \font\myfont = "msam7" at 8pt % error
+%D \stoptyping
+
+\newconditional\tracexetexfonts
+
+%D Because \XETEX\ is not that fast on locating fonts we cache lookups so
+%D that we minimize the test. It saves a little bit of runtime, depending
+%D on the number of fonts loaded (which is normally not that much).
+
+\def\doiffoundXTXfontelse#1#2%
+ {\ifcsname xtx@fnt@#2\somefontspec\endcsname
+ \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{already checked #1: #2\somefontspec\space (state: \number\csname xtx@fnt@#2\somefontspec\endcsname)}%
+ \fi
+ \else
+ \suppressfontnotfounderror\plusone
+ \font\xetextempfont=#2\somefontspec\relax
+ \suppressfontnotfounderror\zerocount
+ \edef\xetextempfont{\fontname\xetextempfont}%
+ \global\expandafter\chardef\csname xtx@fnt@#2\somefontspec\endcsname
+ \ifx\xetextempfont\nullfontname
+ \zerocount \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{not found #1: #2\somefontspec}%
+ \fi
+ \else
+ \plusone \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{found #1: #2\somefontspec}%
+ \fi
+ \fi
+ \fi
+ \ifcase\csname xtx@fnt@#2\somefontspec\endcsname
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\def\docheckfontfilenameprefix#1:#2:#3#4\relax
+ {\edef\!!stringa{#1}%
+ \edef\!!stringb{#2}%
+ \ifx\!!stringb\empty
+ % no prefix
+ \let\checkedfontfile\!!stringa
+ \doiffoundXTXfontelse{1a}{\checkedfontfile\checkedfontfeatures}
+ {\edef\checkedfontfile{\checkedfontfile\checkedfontfeatures}}
+ {\doiffoundXTXfontelse{1b}{"\checkedfontfile\checkedfontfeatures"}
+ {\edef\checkedfontfile{"\checkedfontfile\checkedfontfeatures"}}
+ {\doiffoundXTXfontelse{1c}{"[\checkedfontfile]\checkedfontfeatures"}
+ {\edef\checkedfontfile{"[\checkedfontfile]\checkedfontfeatures"}}
+ {}}}%
+ \else\ifx\!!stringa\v!file
+ % force file, only file check when no spaces
+ \let\checkedfontfile\!!stringb
+ \doiffoundXTXfontelse{2a}{"[\checkedfontfile]\checkedfontfeatures"}
+ {\edef\checkedfontfile{"[\checkedfontfile]\checkedfontfeatures"}}
+ {\doiffoundXTXfontelse{2b}{"\checkedfontfile\checkedfontfeatures"}
+ {\edef\checkedfontfile{"\checkedfontfile\checkedfontfeatures"}}
+ {}}%
+ \else\ifx\!!stringa\v!name
+ % force name, always lookup by xetex itself, "" forces otf/ttf/type1
+ \edef\checkedfontfile{"\!!stringb\checkedfontfeatures"}%
+ \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{no checking 3a: \checkedfontfile}%
+ \fi
+ \else
+ % whatever, maybe even xetex spec, forget about features
+ \edef\checkedfontfile{"\!!stringa\!!stringb"}%
+ \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{no checking 3b: \checkedfontfile}%
+ \fi
+ \fi\fi\fi}
+
+\newconditional\enabledfontfeatures
+
+\def\checkfontfilename% -- todo: integrate so that we call do.. directly
+ {\expandafter\docheckfontfilename\fontfile*\empty*\relax}
+
+\def\docheckfontfilename#1*#2#3*#4\relax % class overrules file
+ {\settrue\enabledfontfeatures
+ \edef\checkedfontfeatures
+ {\expandafter\ifx\csname\fontclass\s!features\endcsname\empty
+ \ifx\@@fontfeatures\empty\ifx#2\empty\else#2#3\fi\else\@@fontfeatures\fi
+ \else\expandafter\ifx\csname\fontclass\s!features\endcsname\relax % redundant, will go away
+ \ifx\@@fontfeatures\empty\ifx#2\empty\else#2#3\fi\else\@@fontfeatures\fi
+ \else
+ \csname\fontclass\s!features\endcsname
+ \fi\fi}%
+ \ifx\checkedfontfeatures\empty
+ % done
+ \else
+ \edef\checkedfontfeatures{\executeifdefined{\??fa\checkedfontfeatures}\empty}%
+ \ifx\checkedfontfeatures\empty
+ % done
+ \else
+ \let\convertedfontfeatures\empty
+ \processcommacommand[\checkedfontfeatures]\doconvertfontfeatures % raw
+ \ifx\convertedfontfeatures\empty
+ \let\checkedfontfeatures\empty
+ \else\ifconditional\enabledfontfeatures
+ \edef\checkedfontfeatures{:\convertedfontfeatures}%
+ \else
+ \let\checkedfontfeatures\empty
+ \fi\fi
+ \fi
+ \fi
+ \docheckfontfilenameprefix#1:\empty:\empty\relax
+ \doshowcheckedfontfeatures}
+
+\edef\@@fontfeaturesareno {features\v!no}
+\edef\@@fontfeaturesareoff{features\v!off}
+
+\def\dodoconvertfontfeatures#1=#2#3=#4\relax
+ {\ifx#2\empty
+ % invalid feature
+ \else\ifcsname @xtx@#1@#2#3\endcsname
+ \expandafter\ifx\csname @xtx@#1@#2#3\endcsname\empty\else
+ \edef\convertedfontfeatures{\convertedfontfeatures\csname @xtx@#1@#2#3\endcsname;}%
+ \fi
+ \else
+ \edef\!!stringa{#1}%
+ \edef\!!stringb{#2#3}%
+ \edef\!!stringc{#1#2#3}%
+ \ifx\!!stringc\@@fontfeaturesareoff
+ \setfalse\enabledfontfeatures
+ \else\ifx\!!stringc\@@fontfeaturesareno
+ \setfalse\enabledfontfeatures
+ \else
+ \edef\convertedfontfeatures
+ {\convertedfontfeatures
+ \ifx\!!stringb\v!yes
+ +\!!stringa
+ \else\ifx\!!stringb\v!on
+ +\!!stringa
+ \else\ifx\!!stringb\v!no
+ -\!!stringa
+ \else\ifx\!!stringb\v!off
+ -\!!stringa
+ \else
+ \!!stringa=\!!stringb
+ \fi\fi\fi\fi;}%
+ \fi\fi
+ \fi\fi}
+
+\def\doconvertfontfeatures#1%
+ {\dodoconvertfontfeatures#1=\empty=\relax}
+
+\def\remapfontfeature #1 #2 #3 {\setevalue{@xtx@#1@#2}{#3}}
+
+% this may move to another file, maybe font-xtx
+
+\remapfontfeature tlig yes mapping=tlig
+%remapfontfeature tlig no mapping=
+\remapfontfeature trep yes {}
+\remapfontfeature trep no {}
+\remapfontfeature texligatures yes mapping=tlig
+%remapfontfeature texligatures no mapping=
+%remapfontfeature texquotes yes mapping=tex-text
+%remapfontfeature texquotes no mapping=
+
+%D Variants:
+
+\unexpanded\def\variant[#1]%
+ {\dosetscaledfont
+ \font\variantfont\truefontname{\fontstringA\fontstylesuffix\fontvariant\fontstringA{#1}} at \scaledfont
+ \variantfont}
+
+%D Possible optimizations:
+
+% \def\updatefontparameters
+% {\edef\@@fontfeatures{\truefontdata\fontfile\s!features}%
+% \edef\@@fontskewchar{\truefontdata\fontfile\s!skewchar}}
+
+% \def\setfontcharacteristics
+% {\updatefontparameters % redundant, will go away, faster too
+% \the\everyfont}
+
+% \let\synchronizepatternswithfont\relax
+
+%D Names:
+
+% We need to move the feature into the filename else it may be
+% overloaded by another reference. For instance the definition of
+% a regular and caps variant can use the same font.
+
+% We could use an indirect method ... store in 'array' and refer to
+% slot.
+
+\def\definefontsynonym[#1]#2[#3]%
+ {\edef\@@fontname{#1}%
+ \edef\@@fontfile{#3}%
+ \doifnextoptionalelse\dodefinefontsynonym\nodefinefontsynonym}
+
+\def\nodefinefontsynonym
+ {\@EA\let\csname\??ff\fontclass\@@fontname\endcsname\@@fontfile}
+
+\def\dodefinefontsynonym[#1]%
+ {\edef\@@fontdata{#1}%
+ \ifx\@@fontdata\empty
+ \nodefinefontsynonym
+ \else
+ \ifx\fontclass\empty
+ \getfontparameters
+ \else
+ \getglobalfontparameters
+ \fi
+ \ifcsname\??ff\@@fontfile\s!features\endcsname
+ \@EA\edef\csname\??ff\fontclass\@@fontname\endcsname{\@@fontfile*\csname\??ff\@@fontfile\s!features\endcsname}%
+ \@EA\let\csname\??ff\@@fontfile\s!features\endcsname\undefined
+ \else
+ \nodefinefontsynonym
+ \fi
+ \fi}
+
+\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater
+
+% simple version
+%
+% \def\truefontname#1%
+% {\@EA\dotruefontname#1*\relax}
+%
+% \def\dotruefontname#1*#2\relax
+% {\ifcsname\??ff\fontclass#1\endcsname
+% \@EA\truefontname\csname\??ff\fontclass#1\endcsname
+% \else\ifcsname\??ff#1\endcsname
+% \@EA\truefontname\csname\??ff#1\endcsname
+% \else
+% #1%
+% \fi\fi}
+%
+% last counts
+%
+% \def\truefontname#1%
+% {\@EA\dotruefontname#1*\empty*\relax}
+%
+% \def\dotruefontname#1*#2#3*#4\relax
+% {\ifcsname\??ff\fontclass#1\endcsname
+% \ifx#2\empty
+% \@EA\truefontname\csname\??ff\fontclass#1\endcsname
+% \else
+% \@EA\truefontname\csname\??ff\fontclass#1\endcsname*#2#3%
+% \fi
+% \else\ifcsname\??ff#1\endcsname
+% \ifx#2\empty
+% \@EA\truefontname\csname\??ff#1\endcsname
+% \else
+% \@EA\truefontname\csname\??ff#1\endcsname*#2#3%
+% \fi
+% \else
+% \ifx#2\empty
+% #1%
+% \else
+% #1*#2#3%
+% \fi
+% \fi\fi}
+%
+% first counts
+
+\def\truefontname#1%
+ {\@EA\dotruefontname#1*\empty*\relax}
+
+\def\dotruefontname#1*#2#3*#4\relax
+ {\ifcsname\??ff\fontclass#1\endcsname
+ \ifx#2\empty
+ \@EA\truefontname\csname\??ff\fontclass#1\endcsname
+ \else
+ \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname*#2#3%
+ \fi
+ \else\ifcsname\??ff#1\endcsname
+ \ifx#2\empty
+ \@EA\truefontname\csname\??ff#1\endcsname
+ \else
+ \@EA\redotruefontname\csname\??ff#1\endcsname*#2#3%
+ \fi
+ \else
+ #1\ifx#2\empty\else*#2#3\fi
+ \fi\fi}
+
+\def\redotruefontname#1%
+ {\@EA\dodotruefontname#1*\relax}
+
+\def\dodotruefontname#1*#2\relax
+ {\ifcsname\??ff\fontclass#1\endcsname
+ \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname
+ \else\ifcsname\??ff#1\endcsname
+ \@EA\redotruefontname\csname\??ff#1\endcsname
+ \else
+ #1%
+ \fi\fi}
+
+%D Default:
+
+\def\defaultfontfile{file:lmmono10-regular}
+
+%D Maybe:
+
+% \def\updatefontparameters
+% {\edef\@@fontfeatures{\truefontdata\fontfile \s!features}%
+% \edef\@@fontskewchar{\truefontdata\fontfile \s!skewchar}}
+
+% \def\setfontcharacteristics
+% {%\updatefontparameters % redundant, will go away, faster too
+% \the\everyfont
+% \synchronizepatternswithfont}
+
+\protect \endinput
+
+% \starttypescript[serif] [myzhfont]
+% \definefontsynonym [Serif] [file:SimSun]
+% \definefontsynonym [SerifBold] [file:SimSun]
+% \definefontsynonym [SerifItalic] [file:SimSun]
+% \definefontsynonym [SerifBoldItalic] [file:SimSun]
+% \stoptypescript
+% \starttypescript[sans] [myzhfont]
+% \definefontsynonym [Sans] [file:SimSun]
+% \definefontsynonym [SansBold] [file:SimSun]
+% \definefontsynonym [SansItalic] [file:SimSun]
+% \definefontsynonym [SansBoldItalic] [file:SimSun]
+% \stoptypescript
+% \starttypescript[mono] [myzhfont]
+% \definefontsynonym [Mono] [file:SimSun]
+% \definefontsynonym [MonoBold] [file:SimSun]
+% \definefontsynonym [MonoItalic] [file:SimSun]
+% \definefontsynonym [MonoBoldItalic] [file:SimSun]
+% \stoptypescript
+% \definetypeface [myzhfont] [rm] [serif][myzhfont] [default]
+% \definetypeface [myzhfont] [ss] [sans] [myzhfont] [default]
+% \definetypeface [myzhfont] [tt] [mono] [myzhfont] [default]
+
+% \starttext
+% % on windows: make sure fonts.conf has no cache mentioned
+% %
+% % 64 sec xetex, 11 sec luatex (56 sec xetex when \nobigmath)
+% %
+% \setupbodyfont[myzhfont] \dorecurse{10000}{{hello {\switchtobodyfont[myzhfont] 你好}}\par}
+% %
+% % 67 sec xetex, 11.5 sec luatex
+% %
+% % \dorecurse{10000}{{hello {\switchtobodyfont[myzhfont] 你好}}\par}
+% %
+% % 5 sec xetex, 7 sec luatex
+% %
+% % \setupbodyfont[myzhfont] \dorecurse{10000}{{hello {你好}}\par}
+% %
+% % 5 sec xetex, 7 sec luatex
+% %
+% % \setupbodyfont[myzhfont] \dorecurse{10000}{{\bf hello {你好}}\par}
+% \stoptext
+
diff --git a/tex/context/base/grph-fig.mkii b/tex/context/base/grph-fig.mkii
new file mode 100644
index 000000000..c7f990af2
--- /dev/null
+++ b/tex/context/base/grph-fig.mkii
@@ -0,0 +1,559 @@
+%D \module
+%D [ file=grph-fig,
+%D version=2006.08.26, % overhaul of 1997.03.31
+%D title=\CONTEXT\ Graphic Macros,
+%D subtitle=Figure Inclusion,
+%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 Graphic Macros / Figure Handling}
+
+\unprotect
+
+\def\setupexternalfigures
+ {\dosingleempty\dosetupexternalfigures}
+
+\def\dosetupexternalfigures[#1]%
+ {\getparameters[\??ef][#1]% local settings
+ \getparameters[\??ex][#1]% global settings
+ \setfigurepathlist} % the path may be used elsewhere too (as in x-res-04)
+
+\presetlocalframed[\??ef]
+
+\newconditional\externalfigurelevel % true=background false=normal
+\newconditional\externalfigureflush % true=place false=ignore
+
+\setfalse\externalfigurelevel
+\settrue \externalfigureflush
+
+\def\doplaceexternalfigure[#1][#2][#3][#4][#5]%
+ {\doifsomething{#2}% catches \defineexternalfigure dummies
+ {\doifundefinedelse{\??ef\??ef#2}
+ {\dodoplaceexternalfigure[#1][#2][#3][#4][#5]}
+ {\doifelse{#1}{#2}
+ {\dodoplaceexternalfigure[#1][#2][#3][#4][#5]}
+ {\getvalue{\??ef\??ef#2}[#5]}}}}
+
+\def\dodoplaceexternalfigure[#1][#2][#3][#4][#5]%
+ {\bgroup
+ \pushmacro\textunderscore
+ \edef\textunderscore{\string_}% brrr, temp hack, still needed?
+ \calculateexternalfigure [][#1][#2][#3][#4][#5]% [] is dummy dwcomp
+ \calculateexternalscreenfigure[][#1][#2][#3][#4][#5]% [] is dummy dwcomp
+ \popmacro\textunderscore
+ \box\foundexternalfigure
+ \egroup}
+
+\def\externalfigurereplacement#1#2#3%
+ {\setupcolors
+ [\c!state=\v!local]%
+ \expanded{\localframed
+ [\??ef]
+ [\c!width=\figurewidth,
+ \c!height=\figureheight,
+ \c!background=\v!screen,
+ \c!backgroundscreen=.8,
+ \c!frame=\@@efframe]}%
+ {\tt\tfxx \nohyphens
+ name: \expanded{\verbatimstring{#1}}\\%
+ file: \expanded{\verbatimstring{#2}}\\%
+ state: \expanded{\verbatimstring{#3}}}}
+
+\def\externalfigureplaceholder#1#2#3%
+ {\localframed
+ [\??ef]
+ [\c!width=#2,
+ \c!height=#3,
+ \c!frame=\v!on]%
+ {\tt\tfxx \nohyphens
+ name: \expanded{\verbatimstring{#1}}\\%
+ state: \expanded{\verbatimstring{placeholder}}}}
+
+% new: more convenient/efficient than
+%
+% \use..[a][a][setting] \externalfigure[b][a]
+%
+% is equivalent to:
+%
+% \def..[a][setting] \externalfigure[b][a]
+%
+% see x-res modules for usage:
+%
+% \defineexternalfigure[name][settings]
+
+\def\defineexternalfigure
+ {\dodoubleargument\dodefineexternalfigure}
+
+\def\dodefineexternalfigure[#1][#2]%
+ {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][][][#2]}}
+
+\def\getexternalfigure#1% efef has 4 args already and take an 5th
+ {\wait} % OBSOLETE
+
+% \useexternalfigure[alpha][koe]
+% \useexternalfigure[beta] [koe] [breedte=1cm]
+% \useexternalfigure[gamma][koe][alpha]
+% \useexternalfigure[delta][koe][alpha][breedte=2cm]
+%
+% volle breedte: \externalfigure[koe] \par
+% 3cm breed: \externalfigure[koe] [breedte=3cm] \par
+% volle breedte: \externalfigure[alpha] \par
+% 1cm breed: \externalfigure[beta] \par
+% volle breedte: \externalfigure[gamma] \par
+% 2cm breed: \externalfigure[delta] \par
+% 4cm breed: \externalfigure[beta] [breedte=4cm] \par
+% 5cm breed: \externalfigure[gamma][breedte=5cm] \par
+
+% \defineexternalfigure[a][width=10cm]
+% \defineexternalfigure[b][width=5cm]
+% \externalfigure[cow][a]
+% \externalfigure[cow][b][height=8cm]
+
+% \useexternalfigure[x][cow][width=10cm,height=1cm]
+% \externalfigure[x]
+% \externalfigure[x][width=3cm]
+
+\def\useexternalfigure
+ {\doquadrupleempty\douseexternalfigure}
+
+% [label] [filename]
+% [label] [filename] [parent]
+% [label] [filename] [parent] [settings]
+% [label] [filename] [settings]
+
+\def\useexternalfigure
+ {\doquadrupleempty\douseexternalfigure}
+
+\def\douseexternalfigure[#1][#2][#3][#4]%
+ {\doifelsenothing{#1}
+ {\doifsomething{#2}
+ {\doifassignmentelse{#3}
+ {\setvalue{\??ef\??ef#2}{\doplaceexternalfigure[#2][#2][#3][#4]}}
+ {\setvalue{\??ef\??ef#2}{\doplaceexternalfigure[#2][#2][][#4]}}}}
+ {\doifelsenothing{#2}
+ {\doifassignmentelse{#3}
+ {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][#1][][#3]}}
+ {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][#1][#3][#4]}}}
+ {\doifassignmentelse{#3}
+ {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][#2][][#3]}}
+ {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][#2][#3][#4]}}}}}
+
+\def\dosetefparameters#1#2#3% parent_id use_settings current_settings
+ {\doifelsenothing{#1} % inherit from parent
+ {\getparameters[\??ef][#2,#3]}
+ {\doifdefinedelse{\??ef\??ef#1}
+ {\pushmacro\doplaceexternalfigure
+ \def\doplaceexternalfigure[##1][##2][##3][##4]{\getparameters[\??ef][##4,#2,#3]}%
+ \getvalue{\??ef\??ef#1}%
+ \popmacro\doplaceexternalfigure}
+ {\getparameters[\??ef][#2,#3]}}}
+
+\unexpanded\def\externalfigure
+ {\dotripleempty\doexternalfigure}
+
+\def\doexternalfigure[#1][#2][#3]% [label][file][settings] | [file][settings] | [file][parent][settings]
+ {\bgroup
+ \doifelsenothing{#1}
+ {\framed[\c!width=\defaultfigurewidth,\c!height=\defaultfigureheight]{external\\figure\\no name}}
+ {\doifundefinedelse{\??ef\??ef#1}
+ {\useexternalfigure[\s!dummy][#1][#2][#3]%
+ \getvalue{\??ef\??ef\s!dummy}[]} % [] is dummy arg 5
+ {\doifassignmentelse{#2}
+ {\getvalue{\??ef\??ef#1}[#2]}%
+ {\getvalue{\??ef\??ef#1}[#3]}}}%
+ \globallet\currentresourcecomment\empty
+ \egroup}
+
+\long\def\resourcecomment#1%
+ {\long\gdef\currentresourcecomment{#1}}
+
+\long\def\startresourcecomment#1\stopresourcecomment
+ {\long\gdef\currentresourcecomment{#1}}
+
+\let\currentresourcecomment\empty
+
+\def\showexternalfigures % maybe run time command is better, but no core-run, unless figs-run ...
+ {%\writestatus\m!systems{for \string\showexternalfigures\space see \truefilename{x-res-20}.tex}
+ \usemodule[res-20]\showexternalfigures} % so for the moment we do it this way
+
+\def\overlayfigure#1%
+ {\externalfigure[#1][\c!width=\overlaywidth,\c!height=\overlayheight]}
+
+%D Still undocumented! No one uses it I think, better be done with layers.
+
+\newcount\efreference
+\newdimen\efxsteps
+\newdimen\efysteps
+
+\def\calculateefsteps
+ {\ifnum0\@@exxmax=\zerocount
+ \ifnum0\@@exymax=\zerocount
+ \def\@@exymax{24}%
+ \fi
+ \efysteps\figureheight \divide\efysteps \@@exymax
+ \efxsteps\efysteps
+ \dimen0=\figurewidth
+ \advance\dimen0 \efysteps
+ \divide \dimen0 \efysteps
+ \edef\@@exxmax{\number\dimen0}%
+ \else
+ \efxsteps\figurewidth \divide\efxsteps \@@exxmax
+ \efysteps\figureheight \divide\efysteps \@@exymax
+ \fi}
+
+\def\efcomment#1(#2,#3)#4(#5,#6)% {kader}(x,y)(h,b)[...]{tekst}
+ {\def\complexefdocomment[##1]##2%
+ {\position(#2,#3)%
+ {\setnostrut
+ \framed
+ [\c!width=#5\efxsteps,
+ \c!height=#6\exysteps,
+ \c!offset=\v!none,
+ \c!frame=#1,
+ ##1]%
+ {##2}}}%
+ \complexorsimpleempty\efdocomment}
+
+\def\efnocomment(#1,#2)#3(#4,#5)% (x,y)(h,b)[...]{tekst}
+ {\def\complexefdonocomment[##1]##2{}%
+ \complexorsimpleempty\efdonocomment}
+
+\def\efdomarker(#1,#2)#3#4% (h,b){kader}{tekst}
+ {\framed
+ [\c!width=#1\efxsteps,
+ \c!height=#2\efysteps,
+ \c!offset=\v!none,
+ \c!frame=#3]%
+ {#4}}
+
+\def\effigure#1%
+ {\position(0,0){\getvalue{#1}}}
+
+\def\efdoarea(#1,#2)#3#4% (h,b){kader}{tekst}
+ {\bgroup
+ \setnostrut
+ \framed
+ [\c!width=#1\efxsteps,
+ \c!height=#2\efysteps,
+ \c!offset=\!!zeropoint,
+ \c!frame=#3]
+ {#4}%
+ \egroup}
+
+\def\efgoto(#1,#2)#3[#4]% (h,b)kader[ref]
+ {\setbox0=\vbox{\efdoarea(#1,#2)#3{}}%
+ \gotobox{\copy0}[#4]}
+
+\def\efmark(#1,#2)#3(#4,#5)#6[#7]%
+ {\advance\efreference \plusone
+ \position(#1,#2)
+ {\hbox{\the\efreference}}%
+ \position(#1,#2)
+ {\gotosomeinternal\s!vwb{#7}\realfolio
+ {\efdomarker(#4,#5)\v!on{\thisissomeinternal\s!vwa{#7}}}}}
+
+\def\eftext#1(#2,#3)#4(#5,#6)#7[#8]%
+ {\advance\efreference \plusone
+ \hbox
+ {\quad
+ \thisissomeinternal\s!vwb{#8}%
+ \gotosomeinternal \s!vwa{#8}\realfolio
+ {\hbox to 1.5em{\the\efreference\presetgoto\hfill}}%
+ \quad#1 (#2,#3) (#5,#6) [#8]\hfill}%
+ \endgraf}
+
+\def\efthisis(#1,#2)#3[#4]%
+ {\efdoarea(#1,#2){#3}{\pagereference[#4]}}
+
+\newbox\colorbarbox
+
+\def\makecolorbar[#1]%
+ {\def\docommand##1%
+ {\color[##1]
+ {\blackrule
+ [\c!width=2em,
+ \c!height=1ex,
+ \c!depth=\!!zeropoint]}%
+ \endgraf}%
+ \global\setbox\colorbarbox\vbox
+ {\forgetall
+ \processcommalist[#1]\docommand}%
+ \global\setbox\colorbarbox\vbox
+ {\hskip2em\box\colorbarbox}%
+ \global\wd\colorbarbox\zeropoint}
+
+\def\placestartfigure[#1][#2][#3]#4\placestopfigure[#5]%
+ {\hbox
+ {\setbox0\hbox
+ {\useexternalfigure[\s!dummy][#2][#3,#5]%
+ \externalfigure[\s!dummy]}%
+ \calculateefsteps
+ \startpositioning
+ \def\referring(##1,##2)##3(##4,##5)##6[##7]%
+ {\position(##1,##2){\efgoto(##4,##5){\@@exframes}[##7]}}%
+ \def\marking(##1,##2)##3(##4,##5)##6[##7]%
+ {\position(##1,##2){\efthisis(##4,##5){\@@exframes}[##7]}}%
+ \def\remark{\efnocomment}%
+ \def\colorbar##1[##2]{}%
+ \position(0,0){\box0}%
+ \linewidth\onepoint
+ \setuppositioning
+ [\c!unit=pt,
+ \c!xscale=\withoutpt\the\efxsteps,
+ \c!yscale=\withoutpt\the\efysteps,
+ \c!factor=1]%
+ \ignorespaces#4%
+ \def\referring(##1,##2)##3(##4,##5)##6[##7]%
+ {}%
+ \let\marking\referring
+ \def\remark{\efcomment\v!no}%
+ \def\colorbar##1[##2]{\makecolorbar[##2]}%
+ \ignorespaces#4%
+ \stoppositioning
+ \box\colorbarbox}}
+
+\def\dodostartfigure[#1][#2][#3]#4\stopfigure
+ {\doifelse\v!test\@@exoption
+ {\teststartfigure[#1][#2][#3]#4\teststopfigure
+ \let\@@exframes\v!on}
+ {\let\@@exframes\v!off}%
+ \setvalue{\??ef\??ef#1}%
+ {\dosingleempty{\placestartfigure[#1][#2][#3]#4\placestopfigure}}%
+ }% no longer \doifundefined{#1}{\setvalue{#1}{\getexternalfigure{#1}}}}
+
+% De onderstaande macro mag niet zondermeer worden aangepast
+% en is afgestemd op gebruik in de handleiding.
+
+\def\teststartfigure[#1][#2][#3]#4\teststopfigure%
+ {\begingroup
+ \setbox0\hbox
+ {\useexternalfigure[\s!dummy][#2][\c!wfactor=\v!max]%
+ \externalfigure[\s!dummy]}%
+ \def\referring{\efmark}%
+ \def\marking{\efmark}%
+ \def\remark{\efcomment\v!yes}%
+ \def\colorbar##1[##2]{}%
+ \efreference\zerocount
+ \setbox0\vbox
+ {\hsize240pt
+ \startpositioning
+ \calculateefsteps
+ \position(0,0)
+ {\box0}%
+ \position(0,0)
+ {\basegrid
+ [\c!nx=\@@exxmax,
+ \c!dx=\withoutpt\the\efxsteps,
+ \c!ny=\@@exymax,
+ \c!dy=\withoutpt\the\efysteps,
+ \c!xstep=1,
+ \c!ystep=1,
+ \c!scale=1,
+ \c!offset=\v!no,
+ \c!unit=pt]}%
+ \setuppositioning
+ [\c!unit=pt,
+ \c!xscale=\withoutpt\the\efxsteps,
+ \c!yscale=\withoutpt\the\efysteps,
+ \c!factor=1]%
+ \linewidth\onepoint
+ \ignorespaces#4\relax
+ \stoppositioning
+ \vfill}%
+ \efreference\zerocount
+ \def\referring{\eftext{$\rightarrow$}}%
+ \def\marking{\eftext{$\leftarrow$}}%
+ \def\remark{\efnocomment}%
+ \def\colorbar##1[##2]{}%
+ \setbox2\vbox
+ {{\tfa\doifelsenothing{#1}{#2}{#1}}
+ \blank
+ \tfxx#4
+ \vfilll}%
+ \ifdim\ht0>\ht2
+ \ht2\ht0
+ \else
+ \ht0\ht2
+ \fi
+ \hbox
+ {\hskip3em
+ \vtop{\vskip12pt\box0\vskip6pt}%
+ \vtop{\vskip12pt\box2\vskip6pt}}%
+ \endgroup}
+
+\def\dodostartfigure[#1][#2][#3]#4\stopfigure
+ {\doifelse\v!test\@@exoption
+ {\teststartfigure[#1][#2][#3]#4\teststopfigure
+ \let\@@exframe\v!on}
+ {\let\@@exframe\v!off}%
+ \setvalue{\??ef\??ef#1}%
+ {\def\next{\placestartfigure[#1][#2][#3]#4\placestopfigure}%
+ \dosingleempty\next}%
+ }% no longer: \doifundefined{#1}{\setvalue{#1}{\getexternalfigure{#1}}}}
+
+\long\def\dostartfigure#1%
+ {\dotripleargument\dodostartfigure#1\stopfigure}
+
+\def\startfigure
+ {\grabuntil{\e!stop\v!figure}\dostartfigure}
+
+%D defining sound tracks:
+%D
+%D \starttyping
+%D \useexternalsoundtrack[label][file]
+%D \stoptyping
+%D
+%D associated actions: StartSound StopSound PauseSound ResumeSound
+%D
+%D Todo: like external figures, also search on path,
+%D although, they need to be present ar viewing time, so ...
+
+\def\useexternalsoundtrack
+ {\dodoubleargument\douseexternalsoundtrack}
+
+\def\douseexternalsoundtrack[#1][#2]%
+ {\setgvalue{\??sd:#1}{#2}}
+
+\def\checksoundtrack#1%
+ {\iflocation
+ \doifdefined{\??sd:#1}{\doifvaluesomething{\??sd:#1}
+ {\doinsertsoundtrack{\getvalue{\??sd:#1}}{#1}\@@sdoption
+ % brr, \..empty not really needed and maybe even wrong;
+ % also, not here but in driver
+ % well, no: sounds need to be reinitialize each time (i.e., be on page), so no
+ }}% \letgvalueempty{\??sd:#1}}}%
+ \fi}
+
+\setexecutecommandcheck {startsound} \checksoundtrack
+
+\def\setupexternalsoundtracks
+ {\dodoubleargument\getparameters[\??sd]}
+
+\setupexternalsoundtracks
+ [\c!option=]
+
+%D NEW: used in styledesign manual
+
+% \setbuffer[typeset-b]\endbuffer
+% \setbuffer[typeset-a]\endbuffer
+%
+% todo:
+%
+% \appendtoks \setbuffer[typeset-b]\endbuffer\to \everystarttext
+% \appendtoks \setbuffer[typeset-a]\endbuffer\to \everystarttext
+
+\def\typesetbuffer
+ {\dodoubleempty\dotypesetbuffer}
+
+\newcounter\noftypesetbuffers % all loaded at the end
+
+\defineexternalfigure
+ [typeset]
+ [\c!background=\v!color,
+ \c!backgroundcolor=\s!white]
+
+\def\dotypesetbuffer[#1][#2]% beware: this will mix up the mp graphics
+ {\bgroup
+ \def\TEXbufferfile##1{\bufferprefix##1.tex}%
+ \expanded{\setbuffer[typeset]%
+ \def\noexpand\bufferprefix{\ifprotectbuffers\jobname-\fi typeset-}}%
+ \starttext
+ \getbuffer[b,#1,a]%
+ \stoptext
+ \endbuffer
+ \doglobal\increment\noftypesetbuffers
+ % batch is needed
+ \executesystemcommand{texmfstart texexec --batch --pdf --result=\bufferprefix typeset-\noftypesetbuffers\space \bufferprefix typeset.tex}%
+ %\externalfigure[\bufferprefix typeset-\noftypesetbuffers.pdf][\c!object=\v!no,#2]%
+ \externalfigure[\bufferprefix typeset-\noftypesetbuffers.pdf][#2]%
+ \egroup}
+
+% for me only (manuals and such)
+
+\definesystemvariable{tz}
+
+\def\definetypesetting{\dotripleempty\dodefinetypesetting}
+\def\typesetfile {\dotripleempty\dotypesetfile}
+
+\def\dodefinetypesetting[#1][#2][#3]%
+ {\doifsomething{#1}{\setvalue{\??tz#1}{\dodotypesetfile{#2}{#3}}}}
+
+\def\dotypesetfile[#1][#2][#3]%
+ {\executeifdefined{\??tz#1}\gobbletwoarguments{#2}{#3}}
+
+\def\dodotypesetfile#1#2#3#4% args settings file settings
+ {\doifmode{*\v!first}{\executesystemcommand{texmfstart texexec.pl --batch --pdf #1 #3}}%
+ \doglobal\beforesplitstring#3\at.\to\typesetfilename
+ \externalfigure[\typesetfilename.pdf][#2,#4]}
+
+\setupexternalfigures
+ [\c!option=,
+ \c!object=\v!yes, % we only check for no
+ \c!reset=\v!no,
+ \c!maxwidth=\@@efwidth,
+ \c!maxheight=\@@efheight,
+ \c!bodyfont=\bodyfontsize,
+ \c!directory=,
+ \c!file=\f!utilityfilename.\f!figureextension,
+ \c!radius=.5\bodyfontsize,
+ \c!corner=\v!rectangular,
+ \c!frame=\v!off,
+ \c!background=, % new
+ \c!splitcolor=\s!white,
+ \c!conversion=,
+ \c!prefix=,
+ \c!cache=,
+% \c!grid=,
+ \c!equalwidth=,
+ \c!equalheight=,
+ \c!location={\v!local,\v!global}]
+
+\setupexternalfigures
+ [\c!frames=\v!off,
+ \c!ymax=24,
+ \c!xmax=]
+
+\useexternalfigure
+ [buffer] [\jobname] [\c!type=\v!buffer,\c!object=\v!no]
+
+\protect \endinput
+
+% alternative for positioning
+
+% \definelayer[figure][width=\overlaywidth,height=\overlayheight]
+% \defineoverlay[figure][{\directsetup{figure}\tightlayer[figure]}]
+
+% \setupcolors[state=start]
+
+% \starttext
+
+% \startsetups figure
+% \setlayerframed[figure][preset=rightbottom,x=.25\layerwidth,y=.25\layerheight]{HERE}
+% \setlayerframed[figure][preset=leftbottom, x=.15\layerwidth,y=.35\layerheight]{THERE}
+% \stopsetups
+
+% \externalfigure[cow][background={foreground,figure},width=4cm,height=8cm]
+
+% \startsetups figure
+% \setlayerframed[figure][preset=righttop,x=.25\layerwidth,y=.25\layerheight]{MORE}
+% \setlayerframed[figure][preset=middle,foregroundcolor=green]{EVEN MORE}
+% \stopsetups
+
+% \externalfigure[cow][background={foreground,figure},width=14cm,height=2cm]
+
+% \defineexternalfigure[whatever][background={foreground,figure}]
+
+% \startsetups figure
+% \setlayerframed[figure][preset=righttop,x=.25\layerwidth,y=.25\layerheight]{\red MORE}
+% \setlayerframed[figure][preset=middle,foregroundcolor=green]{EVEN MORE}
+% \stopsetups
+
+% \externalfigure[cow][whatever][width=14cm,height=4cm]
+
+% \stoptext
+
diff --git a/tex/context/base/grph-fig.mkiv b/tex/context/base/grph-fig.mkiv
new file mode 100644
index 000000000..e10dc0a32
--- /dev/null
+++ b/tex/context/base/grph-fig.mkiv
@@ -0,0 +1,640 @@
+%D \module
+%D [ file=grph-fig,
+%D version=2006.08.26, % overhaul of 1997.03.31
+%D title=\CONTEXT\ Graphic Macros,
+%D subtitle=Figure Inclusion,
+%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 Graphic Macros / Figure Handling}
+
+\unprotect
+
+\unexpanded\def\setupexternalfigures
+ {\dosingleempty\dosetupexternalfigures}
+
+\def\dosetupexternalfigures[#1]%
+ {\getparameters[\??ef][#1]% local settings
+ \getparameters[\??ex][#1]% global settings
+ \setfigurepathlist} % the path may be used elsewhere too (as in x-res-04)
+
+\presetlocalframed[\??ef]
+
+\newconditional\externalfigurelevel % true=background false=normal
+\newconditional\externalfigureflush % true=place false=ignore
+
+\setfalse\externalfigurelevel
+\settrue \externalfigureflush
+
+\def\doplaceexternalfigure[#1][#2][#3][#4][#5]%
+ {\doifsomething{#2}% catches \defineexternalfigure dummies
+ {\doifundefinedelse{\??ef\??ef#2}
+ {\dodoplaceexternalfigure[#1][#2][#3][#4][#5]}
+ {\doifelse{#1}{#2}
+ {\dodoplaceexternalfigure[#1][#2][#3][#4][#5]}
+ {\getvalue{\??ef\??ef#2}[#5]}}}}
+
+\def\dodoplaceexternalfigure[#1][#2][#3][#4][#5]%
+ {\bgroup
+ \pushmacro\textunderscore
+ \edef\textunderscore{\string_}% brrr, temp hack, still needed?
+ \calculateexternalfigure[][#1][#2][#3][#4][#5]% [] is dummy dwcomp
+ \popmacro\textunderscore
+ \box\foundexternalfigure
+ \egroup}
+
+\def\externalfigurereplacement#1#2#3%
+ {\setupcolors
+ [\c!state=\v!local]%
+ \expanded{\localframed
+ [\??ef]
+ [\c!width=\figurewidth,
+ \c!height=\figureheight,
+ \c!background=\v!color,
+ \c!backgroundcolor=missingfigurecolor,
+ \c!frame=\@@efframe]}%
+ {\tt\tfxx \nohyphens
+ name: \expanded{\verbatimstring{#1}}\\%
+ file: \expanded{\verbatimstring{#2}}\\%
+ state: \expanded{\verbatimstring{#3}}}}
+
+\definecolor[missingfigurecolor][s=.8]
+
+\def\externalfigureplaceholder#1#2#3%
+ {\localframed
+ [\??ef]
+ [\c!width=#2,
+ \c!height=#3,
+ \c!frame=\v!on]%
+ {\tt\tfxx \nohyphens
+ name: \expanded{\verbatimstring{#1}}\\%
+ state: \expanded{\verbatimstring{placeholder}}}}
+
+% new: more convenient/efficient than
+%
+% \use..[a][a][setting] \externalfigure[b][a]
+%
+% is equivalent to:
+%
+% \def..[a][setting] \externalfigure[b][a]
+%
+% see x-res modules for usage:
+%
+% \defineexternalfigure[name][settings]
+
+\unexpanded\def\defineexternalfigure
+ {\dodoubleargument\dodefineexternalfigure}
+
+\def\dodefineexternalfigure[#1][#2]%
+ {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][][][#2]}}
+
+\def\getexternalfigure#1% efef has 4 args already and take an 5th
+ {\wait} % OBSOLETE
+
+% \useexternalfigure[alpha][koe]
+% \useexternalfigure[beta] [koe] [breedte=1cm]
+% \useexternalfigure[gamma][koe][alpha]
+% \useexternalfigure[delta][koe][alpha][breedte=2cm]
+%
+% volle breedte: \externalfigure[koe] \par
+% 3cm breed: \externalfigure[koe] [breedte=3cm] \par
+% volle breedte: \externalfigure[alpha] \par
+% 1cm breed: \externalfigure[beta] \par
+% volle breedte: \externalfigure[gamma] \par
+% 2cm breed: \externalfigure[delta] \par
+% 4cm breed: \externalfigure[beta] [breedte=4cm] \par
+% 5cm breed: \externalfigure[gamma][breedte=5cm] \par
+
+% \defineexternalfigure[a][width=10cm]
+% \defineexternalfigure[b][width=5cm]
+% \externalfigure[cow][a]
+% \externalfigure[cow][b][height=8cm]
+
+% \useexternalfigure[x][cow][width=10cm,height=1cm]
+% \externalfigure[x]
+% \externalfigure[x][width=3cm]
+
+\def\useexternalfigure
+ {\doquadrupleempty\douseexternalfigure}
+
+% [label] [filename]
+% [label] [filename] [parent]
+% [label] [filename] [parent] [settings]
+% [label] [filename] [settings]
+
+\def\useexternalfigure
+ {\doquadrupleempty\douseexternalfigure}
+
+% \def\douseexternalfigure[#1][#2][#3][#4]%
+% {\doifelsenothing{#1}
+% {\doifsomething{#2}
+% {\doifassignmentelse{#3}
+% {\setvalue{\??ef\??ef#2}{\doplaceexternalfigure[#2][#2][#3][#4]}}
+% {\setvalue{\??ef\??ef#2}{\doplaceexternalfigure[#2][#2][][#4]}}}}
+% {\doifelsenothing{#2}
+% {\doifassignmentelse{#3}
+% {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][#1][][#3]}}
+% {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][#1][#3][#4]}}}
+% {\doifassignmentelse{#3}
+% {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][#2][][#3]}}
+% {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][#2][#3][#4]}}}}}
+
+\def\douseexternalfigure[#1][#2][#3][#4]%
+ {\doifelsenothing{#1}
+ {\doifsomething{#2}
+ {\doifassignmentelse{#3}
+ {\dodouseexternalfigure{#2}{#2}{#3}{#4}}
+ {\dodouseexternalfigure{#2}{#2}{}{#4}}}}
+ {\doifelsenothing{#2}
+ {\doifassignmentelse{#3}
+ {\dodouseexternalfigure{#1}{#1}{}{#3}}
+ {\dodouseexternalfigure{#1}{#1}{#3}{#4}}}
+ {\doifassignmentelse{#3}
+ {\dodouseexternalfigure{#1}{#2}{}{#3}}
+ {\dodouseexternalfigure{#1}{#2}{#3}{#4}}}}}
+
+\def\dodouseexternalfigure#1#2#3#4%
+ {\setvalue{\??ef\??ef#1}{\doplaceexternalfigure[#1][#2][#3][#4]}%
+ \doanalyseexternalfigurecollection[#2][#4]}
+
+\newconditional\inexternalfigurecollection
+\newdimen\xexternalfigurecollectionminwidth
+\newdimen\xexternalfigurecollectionmaxwidth
+\newdimen\xexternalfigurecollectionminheight
+\newdimen\xexternalfigurecollectionmaxheight
+
+\def\doanalyseexternalfigurecollection[#1][#2]%
+ {\ifconditional\inexternalfigurecollection
+ \setfalse\inexternalfigurecollection
+ \getfiguredimensions[#1][#2]%
+ \settrue\inexternalfigurecollection
+ \scratchdimen\naturalfigurewidth
+ \ifdim\scratchdimen>\xexternalfigurecollectionmaxwidth \xexternalfigurecollectionmaxwidth \scratchdimen \fi
+ \ifdim\scratchdimen<\xexternalfigurecollectionminwidth \xexternalfigurecollectionminwidth \scratchdimen \fi
+ \scratchdimen\naturalfigureheight
+ \ifdim\scratchdimen>\xexternalfigurecollectionmaxheight \xexternalfigurecollectionmaxheight\scratchdimen \fi
+ \ifdim\scratchdimen<\xexternalfigurecollectionminheight \xexternalfigurecollectionminheight\scratchdimen \fi
+ \fi}
+
+\unexpanded\def\startexternalfigurecollection[#1]%
+ {\begingroup
+ \def\currentexternalfigurecollection{#1}%
+ \settrue\inexternalfigurecollection
+ \xexternalfigurecollectionminwidth \maxdimen
+ \xexternalfigurecollectionmaxwidth \zeropoint
+ \xexternalfigurecollectionminheight\maxdimen
+ \xexternalfigurecollectionmaxheight\zeropoint}
+
+\unexpanded\def\stopexternalfigurecollection
+ {\setxvalue{\??ef:c:\currentexternalfigurecollection:\c!minwidth }{\the\xexternalfigurecollectionminwidth }%
+ \setxvalue{\??ef:c:\currentexternalfigurecollection:\c!maxwidth }{\the\xexternalfigurecollectionmaxwidth }%
+ \setxvalue{\??ef:c:\currentexternalfigurecollection:\c!minheight}{\the\xexternalfigurecollectionminheight}%
+ \setxvalue{\??ef:c:\currentexternalfigurecollection:\c!maxheight}{\the\xexternalfigurecollectionmaxheight}%
+ \endgroup}
+
+\def\externalfigurecollectionparameter#1#2%
+ {\csname\ifcsname\??ef:c:#1:#2\endcsname\??ef:c:#1:#2\else\s!empty\fi\endcsname}
+
+\def\externalfigurecollectionminwidth #1{\externalfigurecollectionparameter{#1}\c!minwidth }
+\def\externalfigurecollectionmaxwidth #1{\externalfigurecollectionparameter{#1}\c!maxwidth }
+\def\externalfigurecollectionminheight#1{\externalfigurecollectionparameter{#1}\c!minheight}
+\def\externalfigurecollectionmaxheight#1{\externalfigurecollectionparameter{#1}\c!maxheight}
+
+\let\efcparameter\externalfigurecollectionparameter
+\let\efcminwidth \externalfigurecollectionminwidth
+\let\efcmaxwidth \externalfigurecollectionmaxwidth
+\let\efcminheight\externalfigurecollectionminheight
+\let\efcmaxheight\externalfigurecollectionmaxheight
+
+% \startexternalfigurecollection[name]
+% \useexternalfigure[cow] [cow.pdf]
+% \useexternalfigure[mill][mill.png]
+% \stopexternalfigurecollection
+% \starttext
+% \bTABLE
+% \bTR
+% \bTD \externalfigure[cow] [height=\externalfigurecollectionmaxheight{name}] \eTD
+% \bTD \externalfigure[mill][height=\externalfigurecollectionmaxheight{name}] \eTD
+% \eTR
+% \eTABLE
+% \stoptext
+
+\def\dosetefparameters#1#2#3% parent_id use_settings current_settings
+ {\doifelsenothing{#1} % inherit from parent
+ {\getparameters[\??ef][#2,#3]}
+ {\doifdefinedelse{\??ef\??ef#1}
+ {\pushmacro\doplaceexternalfigure
+ \def\doplaceexternalfigure[##1][##2][##3][##4]{\getparameters[\??ef][##4,#2,#3]}%
+ \getvalue{\??ef\??ef#1}%
+ \popmacro\doplaceexternalfigure}
+ {\getparameters[\??ef][#2,#3]}}}
+
+\unexpanded\def\externalfigure
+ {\dotripleempty\doexternalfigure}
+
+\def\doexternalfigure[#1][#2][#3]% [label][file][settings] | [file][settings] | [file][parent][settings]
+ {\bgroup
+ \doifelsenothing{#1}
+ {\framed[\c!width=\defaultfigurewidth,\c!height=\defaultfigureheight]{external\\figure\\no name}}
+ {\doifundefinedelse{\??ef\??ef#1}
+ {\useexternalfigure[\s!dummy][#1][#2][#3]%
+ \getvalue{\??ef\??ef\s!dummy}[]} % [] is dummy arg 5
+ {\doifassignmentelse{#2}
+ {\getvalue{\??ef\??ef#1}[#2]}%
+ {\getvalue{\??ef\??ef#1}[#3]}}}%
+ \globallet\currentresourcecomment\empty
+ \egroup}
+
+\long\def\resourcecomment#1%
+ {\long\gdef\currentresourcecomment{#1}}
+
+\long\unexpanded\def\startresourcecomment#1\stopresourcecomment
+ {\long\gdef\currentresourcecomment{#1}}
+
+\let\currentresourcecomment\empty
+
+\def\showexternalfigures % maybe run time command is better, but no core-run, unless figs-run ...
+ {%\writestatus\m!systems{for \string\showexternalfigures\space see \truefilename{x-res-20}.tex}
+ \usemodule[res-20]\showexternalfigures} % so for the moment we do it this way
+
+\def\overlayfigure#1%
+ {\externalfigure[#1][\c!width=\overlaywidth,\c!height=\overlayheight]}
+
+%D Still undocumented! No one uses it I think, better be done with layers.
+
+% when there is need for this i'll reimplement it
+%
+% \newcount\efreference
+% \newdimen\efxsteps
+% \newdimen\efysteps
+%
+% \def\calculateefsteps
+% {\ifnum0\@@exxmax=\zerocount
+% \ifnum0\@@exymax=\zerocount
+% \def\@@exymax{24}%
+% \fi
+% \efysteps\figureheight \divide\efysteps \@@exymax
+% \efxsteps\efysteps
+% \dimen0=\figurewidth
+% \advance\dimen0 \efysteps
+% \divide \dimen0 \efysteps
+% \edef\@@exxmax{\number\dimen0}%
+% \else
+% \efxsteps\figurewidth \divide\efxsteps \@@exxmax
+% \efysteps\figureheight \divide\efysteps \@@exymax
+% \fi}
+%
+% \def\efcomment#1(#2,#3)#4(#5,#6)% {kader}(x,y)(h,b)[...]{tekst}
+% {\def\complexefdocomment[##1]##2%
+% {\position(#2,#3)%
+% {\setnostrut
+% \framed
+% [\c!width=#5\efxsteps,
+% \c!height=#6\exysteps,
+% \c!offset=\v!none,
+% \c!frame=#1,
+% ##1]%
+% {##2}}}%
+% \complexorsimpleempty\efdocomment}
+%
+% \def\efnocomment(#1,#2)#3(#4,#5)% (x,y)(h,b)[...]{tekst}
+% {\def\complexefdonocomment[##1]##2{}%
+% \complexorsimpleempty\efdonocomment}
+%
+% \def\efdomarker(#1,#2)#3#4% (h,b){kader}{tekst}
+% {\framed
+% [\c!width=#1\efxsteps,
+% \c!height=#2\efysteps,
+% \c!offset=\v!none,
+% \c!frame=#3]%
+% {#4}}
+%
+% \def\effigure#1%
+% {\position(0,0){\getvalue{#1}}}
+%
+% \def\efdoarea(#1,#2)#3#4% (h,b){kader}{tekst}
+% {\bgroup
+% \setnostrut
+% \framed
+% [\c!width=#1\efxsteps,
+% \c!height=#2\efysteps,
+% \c!offset=\!!zeropoint,
+% \c!frame=#3]
+% {#4}%
+% \egroup}
+%
+% \def\efgoto(#1,#2)#3[#4]% (h,b)kader[ref]
+% {\setbox0=\vbox{\efdoarea(#1,#2)#3{}}%
+% \gotobox{\copy0}[#4]}
+%
+% \def\efmark(#1,#2)#3(#4,#5)#6[#7]%
+% {\advance\efreference \plusone
+% \position(#1,#2)
+% {\hbox{\the\efreference}}%
+% \position(#1,#2)
+% {\gotosomeinternal\s!vwb{#7}\realfolio
+% {\efdomarker(#4,#5)\v!on{\thisissomeinternal\s!vwa{#7}}}}}
+%
+% \def\eftext#1(#2,#3)#4(#5,#6)#7[#8]%
+% {\advance\efreference \plusone
+% \hbox
+% {\quad
+% \thisissomeinternal\s!vwb{#8}%
+% \gotosomeinternal \s!vwa{#8}\realfolio
+% {\hbox to 1.5em{\the\efreference\presetgoto\hfill}}%
+% \quad#1 (#2,#3) (#5,#6) [#8]\hfill}%
+% \endgraf}
+%
+% \def\efthisis(#1,#2)#3[#4]%
+% {\efdoarea(#1,#2){#3}{\pagereference[#4]}}
+
+\newbox\colorbarbox
+
+\def\makecolorbar[#1]%
+ {\def\docommand##1%
+ {\color[##1]
+ {\blackrule
+ [\c!width=2em,
+ \c!height=1ex,
+ \c!depth=\!!zeropoint]}%
+ \endgraf}%
+ \global\setbox\colorbarbox\vbox
+ {\forgetall
+ \processcommalist[#1]\docommand}%
+ \global\setbox\colorbarbox\vbox
+ {\hskip2em\box\colorbarbox}%
+ \global\wd\colorbarbox\zeropoint}
+
+\unexpanded\def\placestartfigure[#1][#2][#3]#4\placestopfigure[#5]%
+ {\hbox
+ {\setbox0\hbox
+ {\useexternalfigure[\s!dummy][#2][#3,#5]%
+ \externalfigure[\s!dummy]}%
+ \calculateefsteps
+ \startpositioning
+ \def\referring(##1,##2)##3(##4,##5)##6[##7]%
+ {\position(##1,##2){\efgoto(##4,##5){\@@exframes}[##7]}}%
+ \def\marking(##1,##2)##3(##4,##5)##6[##7]%
+ {\position(##1,##2){\efthisis(##4,##5){\@@exframes}[##7]}}%
+ \def\remark{\efnocomment}%
+ \def\colorbar##1[##2]{}%
+ \position(0,0){\box0}%
+ \linewidth\onepoint
+ \setuppositioning
+ [\c!unit=pt,
+ \c!xscale=\withoutpt\the\efxsteps,
+ \c!yscale=\withoutpt\the\efysteps,
+ \c!factor=1]%
+ \ignorespaces#4%
+ \def\referring(##1,##2)##3(##4,##5)##6[##7]%
+ {}%
+ \let\marking\referring
+ \def\remark{\efcomment\v!no}%
+ \def\colorbar##1[##2]{\makecolorbar[##2]}%
+ \ignorespaces#4%
+ \stoppositioning
+ \box\colorbarbox}}
+
+\def\dodostartfigure[#1][#2][#3]#4\stopfigure
+ {\doifelse\v!test\@@exoption
+ {\teststartfigure[#1][#2][#3]#4\teststopfigure
+ \let\@@exframes\v!on}
+ {\let\@@exframes\v!off}%
+ \setvalue{\??ef\??ef#1}%
+ {\dosingleempty{\placestartfigure[#1][#2][#3]#4\placestopfigure}}%
+ }% no longer \doifundefined{#1}{\setvalue{#1}{\getexternalfigure{#1}}}}
+
+% De onderstaande macro mag niet zondermeer worden aangepast
+% en is afgestemd op gebruik in de handleiding.
+
+\def\teststartfigure[#1][#2][#3]#4\teststopfigure%
+ {\begingroup
+ \setbox0\hbox
+ {\useexternalfigure[\s!dummy][#2][\c!wfactor=\v!max]%
+ \externalfigure[\s!dummy]}%
+ \def\referring{\efmark}%
+ \def\marking{\efmark}%
+ \def\remark{\efcomment\v!yes}%
+ \def\colorbar##1[##2]{}%
+ \efreference\zerocount
+ \setbox0\vbox
+ {\hsize240pt
+ \startpositioning
+ \calculateefsteps
+ \position(0,0)
+ {\box0}%
+ \position(0,0)
+ {\basegrid
+ [\c!nx=\@@exxmax,
+ \c!dx=\withoutpt\the\efxsteps,
+ \c!ny=\@@exymax,
+ \c!dy=\withoutpt\the\efysteps,
+ \c!xstep=1,
+ \c!ystep=1,
+ \c!scale=1,
+ \c!offset=\v!no,
+ \c!unit=pt]}%
+ \setuppositioning
+ [\c!unit=pt,
+ \c!xscale=\withoutpt\the\efxsteps,
+ \c!yscale=\withoutpt\the\efysteps,
+ \c!factor=1]%
+ \linewidth\onepoint
+ \ignorespaces#4\relax
+ \stoppositioning
+ \vfill}%
+ \efreference\zerocount
+ \def\referring{\eftext{$\rightarrow$}}%
+ \def\marking{\eftext{$\leftarrow$}}%
+ \def\remark{\efnocomment}%
+ \def\colorbar##1[##2]{}%
+ \setbox2\vbox
+ {{\tfa\doifelsenothing{#1}{#2}{#1}}
+ \blank
+ \tfxx#4
+ \vfilll}%
+ \ifdim\ht0>\ht2
+ \ht2\ht0
+ \else
+ \ht0\ht2
+ \fi
+ \hbox
+ {\hskip3em
+ \vtop{\vskip12pt\box0\vskip6pt}%
+ \vtop{\vskip12pt\box2\vskip6pt}}%
+ \endgroup}
+
+\def\dodostartfigure[#1][#2][#3]#4\stopfigure
+ {\doifelse\v!test\@@exoption
+ {\teststartfigure[#1][#2][#3]#4\teststopfigure
+ \let\@@exframe\v!on}
+ {\let\@@exframe\v!off}%
+ \setvalue{\??ef\??ef#1}%
+ {\def\next{\placestartfigure[#1][#2][#3]#4\placestopfigure}%
+ \dosingleempty\next}%
+ }% no longer: \doifundefined{#1}{\setvalue{#1}{\getexternalfigure{#1}}}}
+
+\long\def\dostartfigure#1%
+ {\dotripleargument\dodostartfigure#1\stopfigure}
+
+\unexpanded\def\startfigure
+ {\grabuntil{\e!stop\v!figure}\dostartfigure}
+
+%D NEW: used in styledesign manual
+
+% beware in mkiv we don't have the typeset- prefix
+%
+% \setbuffer[typeset-b]\endbuffer
+% \setbuffer[typeset-a]\endbuffer
+%
+% todo:
+%
+% \appendtoks \setbuffer[typeset-b]\endbuffer\to \everystarttext
+% \appendtoks \setbuffer[typeset-a]\endbuffer\to \everystarttext
+
+\newcount\noftypesetbuffers
+
+\def\typesetbuffer
+ {\dodoubleempty\dotypesetbuffer}
+
+\def\dotypesetbuffer[#1][#2]% beware: this will mix up the mp graphics
+ {\ifsecondargument
+ \dodotypesetbuffer[#1][#2]%
+ \else\iffirstargument
+ \doifassignmentelse{#1}
+ {\dodotypesetbuffer[\jobname][#1]}%
+ {\dodotypesetbuffer[#1][]}%
+ \else
+ \dodotypesetbuffer[\jobname][]
+ \fi\fi}
+
+% \def\dodotypesetbuffer[#1][#2]%
+% {\bgroup
+% \global\advance\noftypesetbuffers\plusone
+% \edef\bufferfilename{\jobname-buffer-\the\noftypesetbuffers}%
+% \doifmode{*\v!first}
+% {\ctxlua{buffers.save("\bufferfilename.tmp","#1",true)}%
+% \executesystemcommand{context \bufferfilename.tmp}}%
+% \externalfigure[\bufferfilename.pdf][#2]%
+% \egroup}
+
+\def\dodotypesetbuffer[#1][#2]%
+ {\bgroup
+ \global\advance\noftypesetbuffers\plusone
+ \edef\bufferfilename{\jobname-buffer-\the\noftypesetbuffers}%
+ \ctxlua{buffers.run("\bufferfilename.tmp","#1",true)}%
+ \externalfigure[\bufferfilename.pdf][#2]%
+ \egroup}
+
+\def\dodotypesetbufferindeed#1%
+ {}
+
+% for me only (manuals and such)
+%
+% \definetypesetting [name] [options] [settings-a]
+%
+% \typesetfile [name] [file] [settings-b]
+% \typesetfile [file] [options] [settings-b]
+% \typesetfile [file] [settings-b]
+% \typesetfile [file]
+%
+% \enabletrackers[files.run]
+% \starttext
+% \typesetfile[oepsoeps.tex][width=10cm,frame=on]
+% \stoptext
+
+\definesystemvariable{tz}
+
+\unexpanded\def\definetypesetting{\dotripleempty\dodefinetypesetting}
+\def\typesetfile {\dotripleempty\dotypesetfile}
+
+\unexpanded\def\definetypesetting{\dotripleempty\dodefinetypesetting}
+\def\typesetfile {\dotripleempty\dotypesetfile}
+
+\def\dodefinetypesetting[#1][#2][#3]% options settings-a
+ {\doifsomething{#1}{\setvalue{\??tz#1}{\dodotypesetfile{#2}{#3}}}}
+
+\def\dotypesetfile[#1][#2][#3]% filename settings-b | filename options settings
+ {\ifcsname\??tz#1\endcsname
+ \csname\??tz#1\endcsname{#2}{#3}%
+ \else\ifthirdargument % filename options settings
+ \dodotypesetfile{#2}{#3}{#1}{}%
+ \else\ifsecondargument % filename settings
+ \dodotypesetfile{}{#2}{#1}{}%
+ \fi\fi\fi}
+
+\def\dodotypesetfile#1#2#3#4% options settings-a filename settings-b
+ {\edef\typesetfilename{\ctxlua{tex.write(jobfiles.run("#3","#1"))}}%
+ \expanded{\externalfigure[\typesetfilename]}[#2,#4]}
+
+\setupexternalfigures
+ [\c!option=,
+ \c!object=\v!yes, % we only check for no
+ \c!reset=\v!no,
+ \c!maxwidth=\@@efwidth,
+ \c!maxheight=\@@efheight,
+ \c!bodyfont=\bodyfontsize,
+ \c!directory=,
+ \c!file=\f!utilityfilename.\f!figureextension,
+ \c!radius=.5\bodyfontsize,
+ \c!corner=\v!rectangular,
+ \c!frame=\v!off,
+ \c!background=, % new
+ \c!splitcolor=\s!white,
+ \c!conversion=,
+ \c!prefix=,
+ \c!cache=,
+% \c!grid=,
+ \c!equalwidth=,
+ \c!equalheight=,
+ \c!location={\v!local,\v!global}]
+
+\setupexternalfigures
+ [\c!frames=\v!off,
+ \c!ymax=24,
+ \c!xmax=]
+
+\useexternalfigure
+ [buffer] [\jobname.buffer] [\c!object=\v!no]
+
+\protect \endinput
+
+% alternative for positioning
+
+% \definelayer[figure][width=\overlaywidth,height=\overlayheight]
+% \defineoverlay[figure][{\directsetup{figure}\tightlayer[figure]}]
+
+% \setupcolors[state=start]
+
+% \starttext
+
+% \startsetups figure
+% \setlayerframed[figure][preset=rightbottom,x=.25\layerwidth,y=.25\layerheight]{HERE}
+% \setlayerframed[figure][preset=leftbottom, x=.15\layerwidth,y=.35\layerheight]{THERE}
+% \stopsetups
+
+% \externalfigure[cow][background={foreground,figure},width=4cm,height=8cm]
+
+% \startsetups figure
+% \setlayerframed[figure][preset=righttop,x=.25\layerwidth,y=.25\layerheight]{MORE}
+% \setlayerframed[figure][preset=middle,foregroundcolor=green]{EVEN MORE}
+% \stopsetups
+
+% \externalfigure[cow][background={foreground,figure},width=14cm,height=2cm]
+
+% \defineexternalfigure[whatever][background={foreground,figure}]
+
+% \startsetups figure
+% \setlayerframed[figure][preset=righttop,x=.25\layerwidth,y=.25\layerheight]{\red MORE}
+% \setlayerframed[figure][preset=middle,foregroundcolor=green]{EVEN MORE}
+% \stopsetups
+
+% \externalfigure[cow][whatever][width=14cm,height=4cm]
+
+% \stoptext
+
diff --git a/tex/context/base/grph-fil.lua b/tex/context/base/grph-fil.lua
new file mode 100644
index 000000000..2e32c7a60
--- /dev/null
+++ b/tex/context/base/grph-fil.lua
@@ -0,0 +1,42 @@
+if not modules then modules = { } end modules ['grph-fil'] = {
+ version = 1.001,
+ comment = "companion to grph-fig.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, concat = string.format, table.concat
+
+local trace_run = false trackers.register("files.run",function(v) trace_run = v end)
+
+local command = "context %s"
+
+jobfiles = jobfiles or { }
+jobfiles.collected = jobfiles.collected or { }
+jobfiles.tobesaved = jobfiles.tobesaved or { }
+
+local tobesaved, collected = jobfiles.tobesaved, jobfiles.collected
+
+local function initializer()
+ tobesaved, collected = jobfiles.tobesaved, jobfiles.collected
+end
+
+job.register('jobfiles.collected', jobfiles.tobesaved, initializer)
+
+jobfiles.forcerun = false
+
+function jobfiles.run(name,...)
+ local oldchecksum = collected[name]
+ local newchecksum = file.checksum(name)
+ if jobfiles.forcerun or not oldchecksum or oldchecksum ~= newchecksum then
+ if trace_run then
+ commands.writestatus("buffers","changes in '%s', processing forced",name)
+ end
+ os.execute(format(command,concat({ name, ... }," ")))
+ elseif trace_run then
+ commands.writestatus("buffers","no changes in '%s', not processed",name)
+ end
+ tobesaved[name] = newchecksum
+ return file.replacesuffix(name,"pdf")
+end
diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua
new file mode 100644
index 000000000..508240a3b
--- /dev/null
+++ b/tex/context/base/grph-inc.lua
@@ -0,0 +1,1115 @@
+if not modules then modules = { } end modules ['grph-inc'] = {
+ version = 1.001,
+ comment = "companion to grph-inc.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- lowercase types
+-- mps tex tmp svg
+-- partly qualified
+-- dimensions
+-- consult rlx
+
+-- figures.boxnumber can go as we now can use names
+
+--[[
+The ConTeXt figure inclusion mechanisms are among the oldest code
+in ConTeXt and evolve dinto a complex whole. One reason is that we
+deal with backend in an abstract way. What complicates matters is
+that we deal with internal graphics as well: TeX code, MetaPost code,
+etc. Later on figure databases were introduced, which resulted in
+a plug in model for locating images. On top of that runs a conversion
+mechanism (with caching) and resource logging.
+
+Porting that to Lua is not that trivial because quite some
+status information is kept between al these stages. Of course, image
+reuse also has some price, and so I decided to implement the graphics
+inclusion in several layers: detection, loading, inclusion, etc.
+
+Object sharing and scaling can happen at each stage, depending on the
+way the resource is dealt with.
+
+The TeX-Lua mix is suboptimal. This has to do with the fact that we cannot
+run TeX code from within Lua. Some more functionality will move to Lua.
+]]--
+
+local format, lower, find, match, gsub, gmatch = string.format, string.lower, string.find, string.match, string.gsub, string.gmatch
+local texsprint, texbox = tex.sprint, tex.box
+local contains = table.contains
+local concat = table.concat
+local todimen = string.todimen
+
+local ctxcatcodes = tex.ctxcatcodes
+local variables = interfaces.variables
+
+local trace_figures = false trackers.register("figures.locating", function(v) trace_figures = v end)
+local trace_bases = false trackers.register("figures.bases", function(v) trace_bases = v end)
+local trace_programs = false trackers.register("figures.programs", function(v) trace_programs = v end)
+local trace_conversion = false trackers.register("figures.conversion", function(v) trace_conversion = v end)
+local trace_inclusion = false trackers.register("figures.inclusion", function(v) trace_inclusion = v end)
+
+--- some extra img functions ---
+
+local imgkeys = img.keys()
+
+function img.totable(imgtable)
+ local result = { }
+ for k=1,#imgkeys do
+ local key = imgkeys[k]
+ result[key] = imgtable[key]
+ end
+ return result
+end
+
+function img.serialize(i)
+ return table.serialize(img.totable(i))
+end
+
+function img.clone(i,data)
+ i.width = data.width or i.width
+ i.height = data.height or i.height
+ -- attr etc
+ return i
+end
+
+local validsizes = table.tohash(img.boxes())
+local validtypes = table.tohash(img.types())
+
+function img.check_size(size)
+ if size then
+ size = gsub(size,"box","")
+ return (validsizes[size] and size) or "crop"
+ else
+ return "crop"
+ end
+end
+
+---
+
+figures = figures or { }
+figures.loaded = figures.loaded or { }
+figures.used = figures.used or { }
+figures.found = figures.found or { }
+figures.suffixes = figures.suffixes or { }
+figures.patterns = figures.patterns or { }
+figures.boxnumber = figures.boxnumber or 0
+figures.defaultsearch = true
+figures.defaultwidth = 0
+figures.defaultheight = 0
+figures.defaultdepth = 0
+figures.n = 0
+figures.prefer_quality = true -- quality over location
+
+figures.localpaths = {
+ ".", "..", "../.."
+}
+figures.cachepaths = {
+ prefix = "",
+ path = ".",
+ subpath = ".",
+}
+
+figures.paths = table.copy(figures.localpaths)
+
+figures.order = {
+ "pdf", "mps", "jpg", "png", "jbig", "svg", "eps", "gif", "mov", "buffer", "tex",
+}
+
+figures.formats = {
+ ["pdf"] = { list = { "pdf" } },
+ ["mps"] = { patterns = { "mps", "%d+" } },
+ ["jpg"] = { list = { "jpg", "jpeg" } },
+ ["png"] = { list = { "png" } },
+ ["jbig"] = { list = { "jbig", "jbig2", "jb2" } },
+ ["svg"] = { list = { "svg", "svgz" } },
+ ["eps"] = { list = { "eps", "ai" } },
+ ["gif"] = { list = { "gif" } },
+ ["mov"] = { list = { "mov", "avi" } },
+ ["buffer"] = { list = { "tmp", "buffer", "buf" } },
+ ["tex"] = { list = { "tex" } },
+}
+
+function figures.setlookups()
+ figures.suffixes, figures.patterns = { }, { }
+ for _, format in next, figures.order do
+ local data = figures.formats[format]
+ local fs, fp = figures.suffixes, figures.patterns
+ local list = data.list
+ if list then
+ for i=1,#list do
+ fs[list[i]] = format -- hash
+ end
+ else
+ fs[format] = format
+ end
+ local patterns = data.patterns
+ if patterns then
+ for i=1,#patterns do
+ fp[#fp+1] = { patterns[i], format } -- array
+ end
+ end
+ end
+end
+
+figures.setlookups()
+
+local function register(tag,target,what)
+ local data = figures.formats[target] -- resolver etc
+ if not data then
+ data = { }
+ figures.formats[target] = data
+ end
+ local d = data[tag] -- list or pattern
+ if d and not contains(d,what) then
+ d[#d+1] = what -- suffix or patternspec
+ else
+ data[tag] = { what }
+ end
+ if not contains(figures.order,target) then
+ figures.order[#figures.order+1] = target
+ end
+ figures.setlookups()
+end
+
+function figures.registersuffix (suffix, target) register('list', target,suffix ) end
+function figures.registerpattern(pattern,target) register('pattern',target,pattern) end
+
+local last_locationset, last_pathlist = last_locationset or nil, last_pathlist or nil
+
+function figures.setpaths(locationset,pathlist)
+ if last_locationset == locationset and last_pathlist == pathlist then
+ -- this function can be called each graphic so we provide this optimization
+ return
+ end
+ local iv, t, h = interfaces.variables, figures.paths, locationset:tohash()
+ if last_locationset ~= locationset then
+ -- change == reset (actually, a 'reset' would indeed reset
+ if h[iv["local"]] then
+ t = table.fastcopy(figures.localpaths or { })
+ else
+ t = { }
+ end
+ figures.defaultsearch = h[iv["default"]]
+ last_locationset = locationset
+ end
+ if h[iv["global"]] then
+ -- for s in gmatch(pathlist,",* *([^,]+)") do
+ local list = aux.settings_to_array(pathlist)
+ for i=1,#list do
+ local s = list[i]
+ if not contains(t,s) then
+ t[#t+1] = s
+ end
+ end
+ end
+ figures.paths, last_pathlist = t, pathlist
+ if trace_figures then
+ commands.writestatus("figures","locations: %s",last_locationset)
+ commands.writestatus("figures","path list: %s",concat(figures.paths, " "))
+ end
+end
+
+-- check conversions and handle it here
+
+function figures.hash(data)
+ return data.status.hash or tostring(data.status.private) -- the
+-- return data.status.fullname .. "+".. (data.status.page or data.request.page or 1) -- img is still not perfect
+end
+
+-- interfacing to tex
+
+do
+
+ local figuredata = { }
+ local callstack = { }
+
+ function figures.new()
+ figuredata = {
+ request = {
+ name = false,
+ label = false,
+ format = false,
+ page = false,
+ width = false,
+ height = false,
+ preview = false,
+ ["repeat"] = false,
+ controls = false,
+ display = false,
+ conversion = false,
+ cache = false,
+ prefix = false,
+ size = false,
+ },
+ used = {
+ fullname = false,
+ format = false,
+ name = false,
+ path = false,
+ suffix = false,
+ width = false,
+ height = false,
+ },
+ status = {
+ status = 0,
+ converted = false,
+ cached = false,
+ fullname = false,
+ format = false,
+ },
+ }
+ return figuredata
+ end
+
+ function figures.push(request)
+ local ncs = #callstack + 1
+ if ncs == 1 then
+ statistics.starttiming(figures)
+ end
+ local figuredata = figures.new()
+ if request then
+ local iv = interfaces.variables
+ -- request.width/height are strings and are only used when no natural dimensions
+ -- can be determined; at some point the handlers might set them to numbers instead
+ -- local w, h = tonumber(request.width), tonumber(request.height)
+ request.page = math.max(tonumber(request.page) or 1,1)
+ request.size = img.check_size(request.size)
+ request.object = iv[request.object] == variables.yes
+ request["repeat"] = iv[request["repeat"]] == variables.yes
+ request.preview = iv[request.preview] == variables.yes
+ request.cache = request.cache ~= "" and request.cache
+ request.prefix = request.prefix ~= "" and request.prefix
+ request.format = request.format ~= "" and request.format
+ -- request.width = (w and w > 0) or false
+ -- request.height = (h and h > 0) or false
+ table.merge(figuredata.request,request)
+ end
+ callstack[ncs] = figuredata
+ return figuredata
+ end
+ function figures.pop()
+ local ncs = #callstack
+ figuredata = callstack[ncs]
+ callstack[ncs] = nil
+ if ncs == 1 then
+ statistics.stoptiming(figures)
+ end
+ end
+ -- maybe move texsprint to tex
+ function figures.get(category,tag,default)
+ local value = figuredata[category]
+ value = value and value[tag]
+ if not value or value == "" or value == true then
+ return default or ""
+ else
+ return value
+ end
+ end
+ function figures.tprint(category,tag,default)
+ texsprint(ctxcatcodes,figures.get(category,tag,default))
+ end
+ function figures.current()
+ return callstack[#callstack]
+ end
+
+end
+
+local defaultformat = "pdf"
+local defaultprefix = "m_k_v_i_"
+
+local function register(askedname,specification)
+ if specification then
+ local format = specification.format
+ if format then
+ local conversion = specification.conversion
+ if conversion == "" then
+ conversion = nil
+ end
+ local newformat = conversion
+ if not newformat or newformat == "" then
+ newformat = defaultformat
+ end
+ local converter = (newformat ~= format) and figures.converters[format]
+ if trace_conversion then
+ logs.report("figures","checking conversion of '%s': old format '%s', new format '%s', conversion '%s'",
+ askedname,format,newformat,conversion or "default")
+ end
+ if converter then
+ if converter[newformat] then
+ converter = converter[newformat]
+ else
+ newformat = defaultformat
+ if converter[newformat] then
+ converter = converter[newformat]
+ else
+ newformat = defaultformat
+ end
+ end
+ end
+ if converter then
+ local oldname = specification.fullname
+ local newpath = file.dirname(oldname)
+ local oldbase = file.basename(oldname)
+ local newbase = file.replacesuffix(oldbase,newformat)
+ local fc = specification.cache or figures.cachepaths.path
+ if fc and fc ~= "" and fc ~= "." then
+ newpath = fc
+ else
+ newbase = defaultprefix .. newbase
+ end
+ local subpath = specification.subpath or figures.cachepaths.subpath
+ if subpath and subpath ~= "" and subpath ~= "." then
+ newpath = newpath .. "/" .. subpath
+ end
+ local prefix = specification.prefix or figures.cachepaths.prefix
+ if prefix and prefix ~= "" then
+ newbase = prefix .. newbase
+ end
+ local newname = file.join(newpath,newbase)
+ dir.makedirs(newpath)
+ oldname = file.collapse_path(oldname)
+ newname = file.collapse_path(newname)
+ local oldtime = lfs.attributes(oldname,'modification') or 0
+ local newtime = lfs.attributes(newname,'modification') or 0
+ if oldtime > newtime then
+ if trace_conversion then
+ logs.report("figures","converting '%s' from '%s' to '%s'",askedname,format,newformat)
+ end
+ converter(oldname,newname)
+ else
+ if trace_conversion then
+ logs.report("figures","no need to convert '%s' from '%s' to '%s'",askedname,format,newformat)
+ end
+ end
+ if io.exists(newname) then
+ specification.foundname = oldname
+ specification.fullname = newname
+ specification.prefix = prefix
+ specification.subpath = subpath
+ specification.converted = true
+ format = newformat
+ elseif io.exists(oldname) then
+ specification.fullname = newname
+ specification.converted = false
+ end
+ end
+ end
+ local found = figures.suffixes[format] -- validtypes[format]
+ if not found then
+ specification.found = false
+ if trace_figures then
+ commands.writestatus("figures","format not supported: %s",format)
+ end
+ else
+ specification.found = true
+ if trace_figures then
+ if validtypes[format] then
+ commands.writestatus("figures","format natively supported by backend: %s",format)
+ else
+ commands.writestatus("figures","format supported by output file format: %s",format)
+ end
+ end
+ end
+ else
+ specification = { }
+ end
+ specification.foundname = specification.foundname or specification.fullname
+ figures.found[askedname .. "->" .. (specification.conversion or "default")] = specification
+ return specification
+end
+
+local resolve_too = true -- urls
+
+local function locate(request) -- name, format, cache
+ local askedname = resolvers.clean_path(request.name)
+ local foundname = figures.found[askedname .. "->" .. (request.conversion or "default")]
+ if foundname then
+ return foundname
+ end
+ -- protocol check
+ local hashed = url.hashed(askedname)
+ if hashed and hashed.scheme ~= "file" then
+ local foundname = resolvers.findbinfile(askedname)
+ if foundname then
+ askedname = foundname
+ end
+ end
+ -- we could use the hashed data instead
+ local askedpath= file.is_rootbased_path(askedname)
+ local askedbase = file.basename(askedname)
+ local askedformat = (request.format ~= "" and request.format ~= "unknown" and request.format) or file.extname(askedname) or ""
+ local askedcache = request.cache
+ local askedconversion = request.conversion
+ if askedformat ~= "" then
+ if trace_figures then
+ commands.writestatus("figures","strategy: forced format")
+ end
+ askedformat = lower(askedformat)
+ local format = figures.suffixes[askedformat]
+ if not format then
+ local figurepatterns = figures.patterns
+ for i=1,#figurepatterns do
+ local pattern = figurepatterns[i]
+ if find(askedformat,pattern[1]) then
+ format = pattern[2]
+ break
+ end
+ end
+ end
+ if format then
+ local foundname = figures.exists(askedname,format,resolve_too) -- not askedformat
+ if foundname then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = askedname,
+ format = format,
+ cache = askedcache,
+ foundname = foundname,
+ conversion = askedconversion,
+ })
+ end
+ end
+ if askedpath then
+ -- path and type given, todo: strip pieces of path
+ if figures.exists(askedname,askedformat,resolve_too) then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = askedname,
+ format = askedformat,
+ cache = askedcache,
+ conversion = askedconversion,
+ })
+ end
+ else
+ -- type given
+ local figurepaths = figures.paths
+ for i=1,#figurepaths do
+ local path = figurepaths[i]
+ local check = path .. "/" .. askedname
+ -- we pass 'true' as it can be an url as well, as the type
+ -- is given we don't waste much time
+ if figures.exists(check,askedformat,resolve_too) then
+ return register(check, {
+ askedname = askedname,
+ fullname = check,
+ format = askedformat,
+ cache = askedcache,
+ conversion = askedconversion,
+ })
+ end
+ end
+ if figures.defaultsearch then
+ local check = resolvers.find_file(askedname)
+ if check and check ~= "" then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = check,
+ format = askedformat,
+ cache = askedcache,
+ conversion = askedconversion,
+ })
+ end
+ end
+ end
+ elseif askedpath then
+ if trace_figures then
+ commands.writestatus("figures","strategy: rootbased path")
+ end
+ local figureorder = figures.order
+ for i=1,#figureorder do
+ local format = figureorder[i]
+ local list = figures.formats[format].list or { format }
+ for j=1,#list do
+ local suffix = list[j]
+ local check = file.addsuffix(askedname,suffix)
+ if figures.exists(check,format,resolve_too) then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = check,
+ format = format,
+ cache = askedcache,
+ conversion = askedconversion,
+ })
+ end
+ end
+ end
+ else
+ if figures.prefer_quality then
+ if trace_figures then
+ commands.writestatus("figures","strategy: unknown format, prefer quality")
+ end
+ local figurepaths = figures.paths
+ local figureorder = figures.order
+ for j=1,#figureorder do
+ local format = figureorder[j]
+ local list = figures.formats[format].list or { format }
+ for k=1,#list do
+ local suffix = list[k]
+ -- local name = file.replacesuffix(askedbase,suffix)
+ local name = file.replacesuffix(askedname,suffix)
+ for i=1,#figurepaths do
+ local path = figurepaths[i]
+ local check = path .. "/" .. name
+ local isfile = url.hashed(check).scheme == "file"
+ if not isfile then
+ if trace_figures then
+ commands.writestatus("figures","warning: skipping path %s",path)
+ end
+ elseif figures.exists(check,format,true) then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = check,
+ format = format,
+ cache = askedcache,
+ conversion = askedconversion,
+ })
+ end
+ end
+ end
+ end
+ else -- 'location'
+ if trace_figures then
+ commands.writestatus("figures","strategy: unknown format, prefer path")
+ end
+ local figurepaths = figures.paths
+ local figureorder = figures.order
+ for i=1,#figurepaths do
+ local path = figurepaths[i]
+ for j=1,#figureorder do
+ local format = figureorder[j]
+ local list = figures.formats[format].list or { format }
+ for k=1,#list do
+ local suffix = list[k]
+ local check = path .. "/" .. file.replacesuffix(askedbase,suffix)
+ if figures.exists(check,format,resolve_too) then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = check,
+ format = format,
+ cache = askedcache,
+ conversion = askedconversion,
+ })
+ end
+ end
+ end
+ end
+ end
+ if figures.defaultsearch then
+ if trace_figures then
+ commands.writestatus("figures","strategy: default tex path")
+ end
+ local figureorder = figures.order
+ for j=1,#figureorder do
+ local format = figureorder[j]
+ local list = figures.formats[format].list or { format }
+ for k=1,#list do
+ local suffix = list[k]
+ local check = resolvers.find_file(file.replacesuffix(askedname,suffix))
+ if check and check ~= "" then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = check,
+ format = format,
+ cache = askedcache,
+ conversion = askedconversion,
+ })
+ end
+ end
+ end
+ end
+ end
+ return register(askedname)
+end
+
+-- -- -- plugins -- -- --
+
+figures.existers = figures.existers or { }
+figures.checkers = figures.checkers or { }
+figures.includers = figures.includers or { }
+figures.converters = figures.converters or { }
+figures.identifiers = figures.identifiers or { }
+figures.programs = figures.programs or { }
+
+figures.identifiers.list = {
+ figures.identifiers.default
+}
+
+function figures.identifiers.default(data)
+ local dr, du, ds = data.request, data.used, data.status
+ local l = locate(dr)
+ local foundname = l.foundname
+ local fullname = l.fullname or foundname
+ if fullname then
+ du.format = l.format or false
+ du.fullname = fullname -- can be cached
+ ds.fullname = foundname -- original
+ ds.format = l.format
+ ds.status = (l.found and 10) or 0
+ end
+ return data
+end
+
+function figures.identify(data)
+ data = data or figures.current()
+ local list = figures.identifiers.list
+ for i=1,#list do
+ local identifier = list[i]
+ data = identifier(data)
+ if data.status.status > 0 then
+ break
+ end
+ end
+ return data
+end
+function figures.exists(askedname,format,resolve)
+ return (figures.existers[format] or figures.existers.generic)(askedname,resolve)
+end
+function figures.check(data)
+ data = data or figures.current()
+ local dr, du, ds = data.request, data.used, data.status
+ return (figures.checkers[ds.format] or figures.checkers.generic)(data)
+end
+function figures.include(data)
+ data = data or figures.current()
+ local dr, du, ds = data.request, data.used, data.status
+ return (figures.includers[ds.format] or figures.includers.generic)(data)
+end
+function figures.scale(data) -- will become lua code
+ texsprint(ctxcatcodes,"\\doscalefigure")
+ return data
+end
+function figures.done(data)
+ figures.n = figures.n + 1
+ data = data or figures.current()
+--~ print(table.serialize(figures.current()))
+ local dr, du, ds, nr = data.request, data.used, data.status, figures.boxnumber
+ local box = texbox[nr]
+ ds.width = box.width
+ ds.height = box.height
+ ds.xscale = ds.width /(du.width or 1)
+ ds.yscale = ds.height/(du.height or 1)
+--~ print(table.serialize(figures.current()))
+ return data
+end
+
+function figures.dummy(data)
+ data = data or figures.current()
+ local dr, du, ds, nr = data.request, data.used, data.status, figures.boxnumber
+ local box = node.hpack(node.new("hlist")) -- we need to set the dir (luatex 0.60 buglet)
+ du.width = du.width or figures.defaultwidth
+ du.height = du.height or figures.defaultheight
+ du.depth = du.depth or figures.defaultdepth
+ -- box.dir = "TLT"
+ box.width = du.width
+ box.height = du.height
+ box.depth = du.depth
+ texbox[nr] = box -- hm, should be global (to be checked for consistency)
+end
+
+-- -- -- generic -- -- --
+
+function figures.existers.generic(askedname,resolve)
+ -- not findbinfile
+ local result
+ if lfs.isfile(askedname) then
+ result = askedname
+ elseif resolve then
+ result = resolvers.findbinfile(askedname) or ""
+ if result == "" then result = false end
+ end
+ if trace_figures then
+ if result then
+ commands.writestatus("figures","found: %s -> %s",askedname,result)
+ else
+ commands.writestatus("figures","not found: %s",askedname)
+ end
+ end
+ return result
+end
+function figures.checkers.generic(data)
+ local dr, du, ds = data.request, data.used, data.status
+ local name, page, size, color = du.fullname or "unknown generic", du.page or dr.page, dr.size or "crop", dr.color or "natural"
+ local conversion = dr.conversion
+ if not conversion or conversion == "" then
+ conversion = "unknown"
+ end
+ local hash = name .. "->" .. page .. "->" .. size .. "->" .. color .. "->" .. conversion
+ local figure = figures.loaded[hash]
+ if figure == nil then
+ figure = img.new { filename = name, page = page, pagebox = dr.size }
+ backends.codeinjections.setfigurecolorspace(data,figure)
+ figure = (figure and img.scan(figure)) or false
+ local f, d = backends.codeinjections.setfigurealternative(data,figure)
+ figure, data = f or figure, d or data
+ figures.loaded[hash] = figure
+ if trace_conversion then
+ logs.report("figures","new graphic, hash: %s",hash)
+ end
+ else
+ if trace_conversion then
+ logs.report("figures","existing graphic, hash: %s",hash)
+ end
+ end
+ if figure then
+ du.width = figure.width
+ du.height = figure.height
+ du.pages = figure.pages
+ ds.private = figure
+ ds.hash = hash
+ end
+ return data
+end
+function figures.includers.generic(data)
+ local dr, du, ds = data.request, data.used, data.status
+ -- here we set the 'natural dimensions'
+ dr.width = du.width
+ dr.height = du.height
+ local hash = figures.hash(data)
+ local figure = figures.used[hash]
+ if figure == nil then
+ figure = ds.private
+ if figure then
+ figure = img.copy(figure)
+ figure = (figure and img.clone(figure,data.request)) or false
+ end
+ figures.used[hash] = figure
+ end
+ if figure then
+ local nr = figures.boxnumber
+ -- it looks like we have a leak in attributes here .. todo
+ local box = node.hpack(img.node(figure)) -- img.node(figure) not longer valid
+ box.width, box.height, box.depth = figure.width, figure.height, 0 -- new, hm, tricky, we need to do that in tex (yet)
+ texbox[nr] = box
+ ds.objectnumber = figure.objnum
+ texsprint(ctxcatcodes,"\\relocateexternalfigure")
+ end
+ return data
+end
+
+-- -- -- nongeneric -- -- --
+
+function figures.checkers.nongeneric(data,command)
+ local dr, du, ds = data.request, data.used, data.status
+ local name = du.fullname or "unknown nongeneric"
+ local hash = name
+ if dr.object then
+ -- hm, bugged
+ if not jobobjects.get("FIG::"..hash) then
+ texsprint(ctxcatcodes,command)
+ texsprint(ctxcatcodes,format("\\setobject{FIG}{%s}\\vbox{\\box\\foundexternalfigure}",hash))
+ end
+ texsprint(ctxcatcodes,format("\\global\\setbox\\foundexternalfigure\\vbox{\\getobject{FIG}{%s}}",hash))
+ else
+ texsprint(ctxcatcodes,command)
+ end
+ return data
+end
+function figures.includers.nongeneric(data)
+ return data
+end
+
+-- -- -- mov -- -- --
+
+function figures.checkers.mov(data)
+ local dr, du, ds = data.request, data.used, data.status
+ local width = todimen(dr.width or figures.defaultwidth)
+ local height = todimen(dr.height or figures.defaultheight)
+ local foundname = du.fullname
+ dr.width, dr.height = width, height
+ du.width, du.height, du.foundname = width, height, foundname
+ if trace_inclusion then
+ logs.report("figures","including movie '%s': width %s, height %s",foundname,width,height)
+ end
+ -- we need to push the node.write in between ... we could make a shared helper for this
+ context.startfoundexternalfigure(width .. "sp",height .. "sp")
+ context(function()
+ backends.codeinjections.insertmovie {
+ width = width,
+ height = height,
+ factor = number.dimenfactors.bp,
+ ["repeat"] = dr["repeat"],
+ controls = dr.controls,
+ preview = dr.preview,
+ label = dr.label,
+ foundname = foundname,
+ }
+ end)
+ context.stopfoundexternalfigure()
+ return data
+end
+
+figures.includers.mov = figures.includers.nongeneric
+
+-- -- -- mps -- -- --
+
+local function internal(askedname)
+ local spec, mprun, mpnum = match(lower(askedname),"mprun(:?)(.-)%.(%d+)")
+ if spec == ":" then
+ return mprun, mpnum
+ else
+ return "", mpnum
+ end
+end
+
+function figures.existers.mps(askedname)
+ local mprun, mpnum = internal(askedname)
+ if mpnum then
+ return askedname
+ else
+ return figures.existers.generic(askedname)
+ end
+end
+function figures.checkers.mps(data)
+ local mprun, mpnum = internal(data.used.fullname)
+ if mpnum then
+ return figures.checkers.nongeneric(data,format("\\docheckfiguremprun{%s}{%s}",mprun,mpnum))
+ else
+ return figures.checkers.nongeneric(data,format("\\docheckfiguremps{%s}",data.used.fullname))
+ end
+end
+figures.includers.mps = figures.includers.nongeneric
+
+-- -- -- buffer -- -- --
+
+function figures.existers.buffer(askedname)
+ askedname = file.nameonly(askedname)
+ return buffers.exists(askedname) and askedname
+end
+function figures.checkers.buffer(data)
+ return figures.checkers.nongeneric(data,format("\\docheckfigurebuffer{%s}", file.nameonly(data.used.fullname)))
+end
+figures.includers.buffers = figures.includers.nongeneric
+
+-- -- -- tex -- -- --
+
+function figures.existers.tex(askedname)
+ askedname = resolvers.find_file(askedname)
+ return (askedname ~= "" and askedname) or false
+end
+function figures.checkers.tex(data)
+ return figures.checkers.nongeneric(data,format("\\docheckfiguretex{%s}", data.used.fullname))
+end
+figures.includers.tex = figures.includers.nongeneric
+
+-- -- -- converters -- -- --
+
+local function makeoptions(program)
+ local to = type(options)
+ return (to == "table" and concat(options," ")) or (to == "string" and options) or ""
+end
+
+local function runprogram(...)
+ local command = format(...)
+ if trace_conversion or trace_programs then
+ logs.report("figures","running %s",command)
+ end
+ os.spawn(command)
+end
+
+-- -- -- eps -- -- --
+
+local epsconverter = { }
+figures.converters.eps = epsconverter
+
+figures.programs.gs = {
+ options = {
+ "-dAutoRotatePages=/None",
+ "-dPDFSETTINGS=/prepress",
+ "-dEPSCrop",
+ },
+ command = (os.type == "windows" and "gswin32") or "gs"
+}
+
+function epsconverter.pdf(oldname,newname)
+ local gs = figures.programs.gs
+ runprogram (
+ '%s -q -sDEVICE=pdfwrite -dNOPAUSE -dNOCACHE -dBATCH %s -sOutputFile="%s" "%s" -c quit',
+ gs.command, makeoptions(gs.options), newname, oldname
+ )
+end
+
+epsconverter.default = epsconverter.pdf
+
+-- -- -- svg -- -- --
+
+local svgconverter = { }
+figures.converters.svg = svgconverter
+figures.converters.svgz = svgconverter
+
+-- inkscape on windows only works with complete paths
+
+figures.programs.inkscape = {
+ options = {
+ "--export-dpi=600"
+ },
+ command = "inkscape"
+}
+
+function svgconverter.pdf(oldname,newname)
+ local inkscape = figures.programs.inkscape
+ runprogram (
+ '%s "%s" --export-pdf="%s" %s',
+ inkscape.command, oldname, newname, makeoptions(inkscape.options)
+ )
+end
+
+function svgconverter.png(oldname,newname)
+ local inkscape = figures.programs.inkscape
+ runprogram (
+ '%s "%s" --export-png="%s" %s',
+ inkscape.command, oldname, newname, makeoptions(inkscape.options)
+ )
+end
+
+svgconverter.default = svgconverter.pdf
+
+-- -- -- gif -- -- --
+
+local gifconverter = { }
+figures.converters.gif = gifconverter
+
+figures.programs.convert = {
+ command = "convert" -- imagemagick
+}
+
+function gifconverter.pdf(oldname,newname)
+ local convert = figures.programs.convert
+ runprogram (
+ "convert %s %s",
+ convert.command, makeoptions(convert.options), oldname, newname
+ )
+end
+
+gifconverter.default = gifconverter.pdf
+
+-- todo: lowres
+
+-- -- -- bases -- -- --
+
+figures.bases = { }
+figures.bases.list = { } -- index => { basename, fullname, xmlroot }
+figures.bases.used = { } -- [basename] => { basename, fullname, xmlroot } -- pointer to list
+figures.bases.found = { }
+figures.bases.enabled = false
+
+local bases = figures.bases
+
+function bases.use(basename)
+ if basename == "reset" then
+ bases.list, bases.used, bases.found, bases.enabled = { }, { }, { }, false
+ else
+ basename = file.addsuffix(basename,"xml")
+ if not bases.used[basename] then
+ local t = { basename, nil, nil }
+ bases.used[basename] = t
+ bases.list[#bases.list+1] = t
+ if not bases.enabled then
+ bases.enabled = true
+ xml.registerns("rlx","http://www.pragma-ade.com/schemas/rlx") -- we should be able to do this per xml file
+ end
+ if trace_bases then
+ commands.writestatus("figures","registering base '%s'",basename)
+ end
+ end
+ end
+end
+
+function bases.find(basename,askedlabel)
+ if trace_bases then
+ commands.writestatus("figures","checking for '%s' in base '%s'",askedlabel,basename)
+ end
+ basename = file.addsuffix(basename,"xml")
+ local t = bases.found[askedlabel]
+ if t == nil then
+ local base = bases.used[basename]
+ local page = 0
+ if base[2] == nil then
+ -- no yet located
+ local figurepaths = figures.paths
+ for i=1,#figurepaths do
+ local path = figurepaths[i]
+ local xmlfile = path .. "/" .. basename
+ if io.exists(xmlfile) then
+ base[2] = xmlfile
+ base[3] = xml.load(xmlfile)
+ if trace_bases then
+ commands.writestatus("figures","base '%s' loaded",xmlfile)
+ end
+ break
+ end
+ end
+ end
+ t = false
+ if base[2] and base[3] then -- rlx:library
+ for e in xml.collected(base[3],"/(*:library|figurelibrary)/*:figure/*:label") do
+ page = page + 1
+ if xml.text(e) == askedlabel then
+ t = {
+ base = file.replacesuffix(base[2],"pdf"),
+ format = "pdf",
+ name = xml.text(e,"../*:file"), -- to be checked
+ page = page,
+ }
+ bases.found[askedlabel] = t
+ if trace_bases then
+ commands.writestatus("figures","figure '%s' found in base '%s'",askedlabel,base[2])
+ end
+ return t
+ end
+ end
+ if trace_bases and not t then
+ commands.writestatus("figures","figure '%s' not found in base '%s'",askedlabel,base[2])
+ end
+ end
+ end
+ return t
+end
+
+-- we can access sequential or by name
+
+function bases.locate(askedlabel)
+ local list = bases.list
+ for i=1,#list do
+ local entry = list[i]
+ local t = bases.find(entry[1],askedlabel)
+ if t then
+ return t
+ end
+ end
+ return false
+end
+
+function figures.identifiers.base(data)
+ if bases.enabled then
+ local dr, du, ds = data.request, data.used, data.status
+ local fbl = bases.locate(dr.name or dr.label)
+ if fbl then
+ du.page = fbl.page
+ du.format = fbl.format
+ du.fullname = fbl.base
+ ds.fullname = fbl.name
+ ds.format = fbl.format
+ ds.page = fbl.page
+ ds.status = 10
+ end
+ end
+ return data
+end
+
+figures.identifiers.list = {
+ figures.identifiers.base,
+ figures.identifiers.default
+}
+
+-- tracing
+
+statistics.register("graphics processing time", function()
+ local n = figures.n
+ if n > 0 then
+ return format("%s seconds including tex, n=%s", statistics.elapsedtime(figures),n)
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/grph-inc.mkii b/tex/context/base/grph-inc.mkii
new file mode 100644
index 000000000..1bd7544d8
--- /dev/null
+++ b/tex/context/base/grph-inc.mkii
@@ -0,0 +1,1243 @@
+%D \module
+%D [ file=grph-inc, % moved from core-fig
+%D version=2006.08.26, % overhaul of 1997.03.31
+%D title=\CONTEXT\ Graphic Macros,
+%D subtitle=Figure Inclusion,
+%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 Graphic Macros / Figure Inclusion}
+
+% todo: directory : system -> \allinputpaths (so that we can \usesubpath)
+
+%D This is a reimplementation of the original module, which
+%D over time had evolved into a pretty complex whole. This
+%D was partly due to the fact that we needed to handle many
+%D formats, deal with substitute graphics, handle fallbacks
+%D and driver specifics (objects), etc. In the meantime we
+%D have more clever backends, moved away from texutil to
+%D rlxtools, can use runtime or betweentime runs etc. Also,
+%D more memory permits a cleaner implementation. Time to
+%D move on. We can now also assume that scaling is available.
+%D
+%D Another mess that can go is the llx/lly handling since
+%D drivers now automatically can determine such things.
+
+%D Messages 3 and 5 needs to be translated!
+
+\unprotect
+
+%D Due to the mere fact that \DVI|/|\PDF\ drivers differ in their
+%D needs for figure dimensions, we have to provide the width,
+%D height, horizontal and vertical scale. Also we want to
+%D specify at the user level either width and|/|or height, scale,
+%D or a factor related to the current document bodyfont size.
+%D Even better: we can also specify isometric scaling and
+%D automatically let \CONTEXT\ calculate the maximum possible
+%D dimensions. Whatever we calculate, the results will come
+%D available in the next registers.
+
+\letempty \@@DriverImageBox
+\letempty \@@DriverImageOptions
+\letempty \@@DriverImageWidth
+\letempty \@@DriverImageHeight
+\letempty \@@DriverImageFile
+\letempty \@@DriverImageLabel
+\letempty \@@DriverImageType
+\letempty \@@DriverImageMethod
+\letempty \@@DriverImagePage
+
+%D Because looking for dimensions can take many steps (locating
+%D the figure, maybe on more directories, scanning the figure
+%D on dimension, or when not found, trying to find them in the
+%D utility file, and again when not found, trying to generate
+%D such a file, and, as a last resort, trying to use the
+%D dimensions. Now when things do not work out the way we want,
+%D we can set a switch and get some information on what takes
+%D place.
+
+\newif\iftraceexternalfigures
+
+\let\traceexternalfigures\traceexternalfigurestrue
+
+\def\doshowfigurestate
+ {\iftraceexternalfigures
+ \expandafter\writestatus\expandafter\m!figures
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\doshowfiguremessage
+ {\iftraceexternalfigures
+ \expandafter\gobbletwoarguments
+ \else
+ \expandafter\showmessage\expandafter\m!figures
+ \fi}
+
+%D Another switch tells \CONTEXT\ to locate and calculate a
+%D figure, but does not actually insert it. Especially when we
+%D use \PDFTEX\ this saves a lot of time on trialruns. (Keep
+%D in mind that \PDFTEX\ is both a \TEX\ pre|| and postprocessor.)
+
+\newif\ifskipexternalfigures % can be set elsewhere
+
+% \newif\ifrunutilityfile
+% \newif\ifconsultutilityfile
+%
+% Let's save two hash entries:
+
+\let\runutilityfiletrue \relax \let\runutilityfilefalse \relax
+\let\consultutilityfiletrue\relax \let\consultutilityfilefalse\relax
+
+%D Intermediate, private.
+
+\newdimen\determinedfigurewidth
+\newdimen\determinedfigureheight
+
+\let\naturalfigureheight\!!zeropoint
+\let\naturalfigurewidth \!!zeropoint
+
+\def\defaultfigurewidth {8\lineheight}
+\def\defaultfigureheight{6\lineheight}
+
+\def\defaultfigurepathsignal{(\v!default)}
+
+\def\checknaturalfiguredimensions
+ {\edef\naturalfigurewidth{\the\dimexpr\ifzeropt\determinedfigurewidth
+ \defaultfigurewidth \else\determinedfigurewidth \fi\relax}%
+ \edef\naturalfigureheight{\the\dimexpr\ifzeropt\determinedfigureheight
+ \defaultfigureheight\else\determinedfigureheight\fi\relax}}
+
+%D Locating figures. Dilemma: we do support eps and svg parsing but drivers
+%D don't always support it.
+
+\def\figuretypes{\c!mps,\c!pdf,\c!eps,\c!svg,\c!svg z,\c!png,\c!tif,jb2,\c!jpg}
+
+\def\supportedfiguretypes{\figuretypes}
+
+\def\checksupportedfiguretypes
+ {\begingroup
+ \global\let\supportedfiguretypes\empty
+ \def\docommand##1%
+ {\doiffileinsertionsupportedelse{##1}
+ {\doglobal\addtocommalist{##1}\supportedfiguretypes}
+ \donothing}%
+ \processcommacommand[\figuretypes]\docommand
+ \gdef\checksupportedfiguretypes{\let\figuretypes\supportedfiguretypes}%
+ \endgroup
+ \checksupportedfiguretypes}
+
+%D The next box is used to store the graphic. It's globally assigned.
+
+\newbox\foundexternalfigure
+
+\chardef\figurestatus\zerocount % nothing found
+
+\def\noffigurepages{\nofinsertpages}
+
+%D Variables.
+
+\newtoks\everyexternalfigureresets
+
+\def\resetfigurevariables
+ {\the\everyexternalfigureresets}
+
+%D Example usage:
+
+\appendtoks
+ \global\let\externalfigurelog\empty
+\to\everyexternalfigureresets
+
+%D Intermediate, private
+
+\def\resetprivatefigurevariables
+ {\let \wantedfigurefull \empty
+ \let \wantedfigurepath \empty
+ \let \wantedfigurename \empty
+ \let \wantedfigurebase \empty
+ \let \wantedfiguretype \empty
+ \let \wantedfigurefullname \empty
+ \let \wantedfiguretypespec \empty
+ \let \wantedfiguremethod \empty
+ \let \wantedfigurepage \empty
+ \let \wantedfigureoptions \empty
+ \let \wantedfigureconversion\empty
+ \let \wantedfigureprefix \empty
+ \let \wantedfiguretypelist \figuretypes
+ \let \figurepathlist \empty
+ \chardef \figurestatus \zerocount
+ \let \expandedfigurename \empty
+ \global\let \analyzedfigurewidth \!!zeropoint % set by indentifying code
+ \global\let \analyzedfigureheight \!!zeropoint % set by indentifying code
+ \global\setbox\foundexternalfigure \emptybox
+ \def \frozenfigurestamp {\externalfigurestamp}} % no edef
+
+\resetprivatefigurevariables
+
+\appendtoks
+ \resetprivatefigurevariables
+\to\everyexternalfigureresets
+
+%D Private/public.
+
+\def\resetpublicfigurevariables
+ {\let\figurewidth \!!zeropoint
+ \let\figureheight \!!zeropoint
+ \let\figurenaturalwidth \!!zeropoint
+ \let\figurenaturalheight \!!zeropoint
+ \let\figurelabel \empty
+ \let\figurefileoriginal \empty
+ \let\figurefileoptions \empty
+ \let\figurefilename \empty
+ \let\figurefiletype \empty
+ \let\figurefilepage \!!zerocount
+ \let\figurefileconversion\empty
+ \let\figurefileprefix \empty
+ \let\figurefilepath \empty
+ \let\figurefilecache \empty}
+
+\resetpublicfigurevariables
+
+\appendtoks
+ \resetpublicfigurevariables
+\to\everyexternalfigureresets
+
+\newcounter\figurenestinglevel
+
+\def\pushpublicfigurevariables
+ {\ifcase\figurenestinglevel\else
+ \doshowfigurestate{variables : push}%
+ \globalpushmacro\figurewidth
+ \globalpushmacro\figureheight
+ \globalpushmacro\figurenaturalwidth
+ \globalpushmacro\figurenaturalheight
+ \globalpushmacro\figurelabel
+ \globalpushmacro\figurefileoriginal
+ \globalpushmacro\figurefileoptions
+ \globalpushmacro\figurefilename
+ \globalpushmacro\figurefiletype
+ \globalpushmacro\figurefilepage
+ \globalpushmacro\figurefileconversion
+ \globalpushmacro\figurefileprefix
+ \globalpushmacro\figurefilepath
+ \globalpushmacro\figurefilecache
+ \fi}
+
+\def\poppublicfigurevariables
+ {\ifcase\figurenestinglevel\else
+ \doshowfigurestate{variables : pop}%
+ \globalpopmacro\figurefilecache
+ \globalpopmacro\figurefilepath
+ \globalpopmacro\figurefileprefix
+ \globalpopmacro\figurefileconversion
+ \globalpopmacro\figurefilepage
+ \globalpopmacro\figurefiletype
+ \globalpopmacro\figurefilename
+ \globalpopmacro\figurefileoptions
+ \globalpopmacro\figurefileoriginal
+ \globalpopmacro\figurelabel
+ \globalpopmacro\figurenaturalheight
+ \globalpopmacro\figurenaturalwidth
+ \globalpopmacro\figureheight
+ \globalpopmacro\figurewidth
+ \fi}
+
+\def\setpublicfigurevariables % todo: type vs typespec
+ {\xdef\figurewidth {\the\wd\foundexternalfigure}%
+ \xdef\figureheight {\the\ht\foundexternalfigure}%
+ \xdef\figurenaturalwidth {\naturalfigurewidth}%
+ \xdef\figurenaturalheight {\naturalfigureheight}%
+ \xdef\figurelabel {\wantedfigurelabel}%
+ \xdef\figurefilepath {\wantedfigurepath}%
+ \xdef\figurefilename {\wantedfigurename}%
+ \xdef\figurefiletype {\wantedfiguretypespec}%
+ \xdef\figurefilepage {\wantedfigurepage}%
+ \xdef\figurefileoptions {\wantedfigureoptions}%
+ \xdef\figurefileconversion{\wantedfigureconversion}%
+ \xdef\figurefilecache {\wantedconversioncache}%
+ \xdef\figurefileprefix {\wantedconversionprefix}%
+ \xdef\figurefileoriginal {\wantedconversionname}%
+ \xdef\figurefullname {\wantedfigurepath/\wantedfigurename.\wantedfiguretypespec}%
+ \ifcase\figurestatus
+ \let\figurefiletype\empty % ?
+ \fi}
+
+\def\setpublicfigurescalevariables
+ {\edef\figurescalewidth {\finalscaleboxwidth }%
+ \edef\figurescaleheight {\finalscaleboxheight}%
+ \edef\figurescalexscale {\finalscaleboxxscale}%
+ \edef\figurescaleyscale {\finalscaleboxyscale}}
+
+\def\resetpublicfigurescalevariables
+ {\let\figurescalewidth \!!zeropoint
+ \let\figurescaleheight \!!zeropoint
+ \let\figurescalexscale \!!plusone
+ \let\figurescaleyscale \!!plusone}
+
+\resetpublicfigurescalevariables
+
+\appendtoks
+ \resetpublicfigurescalevariables
+\to \everyexternalfigureresets
+
+%D The next one is for instance used in symbols. Since
+%D we only need to reset some parameters, we can
+%D better use the fast alternative:
+%D
+%D \starttyping
+%D \def\resetexternalfigures
+%D {\getparameters[\??ef]
+%D [\c!option=,\c!maxwidth=,\c!maxheight=,
+%D \c!foregroundcolor=,\c!color=,
+%D %\c!conversion=,\c!prefix=,\c!splitcolor=,
+%D \c!frame=\v!off,\c!background=]}
+%D \stoptyping
+%D
+%D This one dropped the runtime of the \MAPS\ bibliography
+%D from over 110 seconds down to less than 105 seconds. The
+%D tremendously faster (but uglier) implementation is:
+
+\def\resetexternalfigures
+ {\let\@@efoption \empty % \let\@@efprefix\empty
+ \let\@@efmaxwidth \empty % \let\@@efcache \empty
+ \let\@@efmaxheight \empty % \let\@@efframe \v!off
+ \let\@@efforegroundcolor\empty
+ \let\@@efcolor \empty
+ \let\@@efconversion \empty
+ \let\@@efbackground \empty}
+
+%D The following code will move:
+
+\appendtoks \resetexternalfigures \to \everyoverlay
+\appendtoks \resetexternalfigures \to \everybeforepagebody % not really needed
+%appendtoks \resetexternalfigures \to \everysymbol
+
+%D We need this one for bookkeeping:
+
+\newcounter\forcedMPSobject % better something \every
+
+%D Features:
+
+% converted -> prefix, suffix
+% alternative -> other suffix
+% buffer -> prefix
+
+%D Still messy:
+
+\newtoks\everyfiguretypepresets
+
+\def\presetfiguretypeprocessing
+ {\the\everyfiguretypepresets}
+
+\def\presetspecialfigure#1%
+ {\doif\wantedfiguretype{#1}%
+ {\let\@@efobject\v!no
+ \let\@@efpreset\v!no
+ \ifx\@@efwidth \empty\def\@@efwidth {\defaultfigurewidth }\fi
+ \ifx\@@efheight\empty\def\@@efheight{\defaultfigureheight}\fi}}
+
+\appendtoks
+ \presetspecialfigure\c!mov
+ \presetspecialfigure\c!avi
+\to \everyfiguretypepresets
+
+\def\checkformpsfigurefiles % to be checked
+ {\doif\wantedfigurename{mprun}
+ {\doshowfigurestate{type check : forcing mps (mprun)}%
+ \doifnotinstring{^\bufferprefix}{^\wantedfigurename}
+ {\edef\wantedfigurename{\bufferprefix\wantedfigurename}}%
+ \let\wantedfiguremethod \c!mps
+ \let\wantedfiguretypespec\c!mps}%
+ \doifnumberelse\wantedfiguretype
+ {\doshowfigurestate{type check : forcing mps (number)}%
+ \let\wantedfiguremethod \c!mps
+ \let\wantedfiguretypespec\c!mps}
+ \donothing
+ \doif\wantedfiguretypespec\c!mps
+ {\let\wantedfiguretypelist\wantedfiguretypespec
+ \ifcase\EPSspecial\else\ifinobject\else
+ \doglobal\increment\forcedMPSobject
+ \edef\externalfigurestamp{\c!mps::\forcedMPSobject}%
+ \let\@@efobject\v!yes
+ \fi\fi}}
+
+\appendtoks
+ \checkformpsfigurefiles
+\to \everyfiguretypepresets
+
+\def\checkfortexfigurefiles % to be checked (brrr: c!) / brrr: eftype
+ {\doifinset\wantedfiguretype{\c!tex,\c!tmp}
+ {\let\wantedfiguretypespec \wantedfiguretype}%
+ \doifinset\wantedfiguretypespec{\c!tex,\c!tmp,\v!buffer}
+ {\doshowfigurestate{type check : forcing tex (\wantedfiguretypespec)}%
+ \let\wantedfiguretypelist\wantedfiguretypespec
+ \let\wantedfiguremethod \c!tex
+ \let\@@efobject\v!no
+ \doifnothing\wantedfiguretype{\let\wantedfiguretype\c!tmp}%
+ % there can be a non buffer \jobname.tmp (made by texexec)
+ \doifnotinstring{^\bufferprefix}{^\wantedfigurename}
+ {\edef\wantedfigurename{\bufferprefix\wantedfigurename}}}}
+
+\appendtoks
+ \checkfortexfigurefiles
+\to \everyfiguretypepresets
+
+\def\checkforunknownfigurefiles
+ {\doifnothing\wantedfiguretype
+ {\dogetcommacommandelement\plusone\from\@@eftype\to\commalistelement
+ \edef\wantedfigurefullname{\wantedfigurename.\commalistelement}}}
+
+\appendtoks
+ \checkforunknownfigurefiles
+\to \everyfiguretypepresets
+
+% note * : this is needed because reusable graphics
+% combined with funny page aspect aspect ratio's can lead to
+% strange side effects of preceding factor=max specs. This
+% surfaced in the metafun manual, where the two side by
+% side clipped cow heads [the second one was a reused object]
+% where the second one inherited some characteristics from
+% the factor=max one some 30 pages back. Sigh.
+
+\chardef\splitexternalfigure\zerocount % 0 nosplit 1 split/yes 2 split/no
+
+\def\checkfigurecolorsettings
+ {% seperation, seldom used
+ \doifseparatingcolorselse
+ {\let\@@efforegroundcolor\empty
+ \doifelsenothing\@@efsplit
+ {\chardef\splitexternalfigure\zerocount}
+ {\doifcolorchannelelse\@@efsplit
+ {\let\@@efobject\v!no % why?
+ \chardef\splitexternalfigure\plusone}
+ {\chardef\splitexternalfigure\plustwo}}}
+ {\chardef\splitexternalfigure\zerocount}%
+ % fake color in gray bitmaps, assumes that
+ % a transparent color is used
+ \doifsomething\@@efforegroundcolor
+ {\def\@@efbackground{\v!foreground,\v!color}%
+ \def\@@efbackgroundcolor{\@@efforegroundcolor}}%
+ \doifsomething\@@efcolor
+ {\doifcolorelse\@@efcolor
+ {\checkpredefinedcolor[\@@efcolor]%
+ \doregisterfigurecolor\@@efcolor}}%
+ \donothing}
+
+\def\setextrafiguredriveroptions
+ {\let\@@DriverImageOptions\empty
+ \doifsomething\@@efpage {\addtocommalist\@@efpage \@@DriverImageOptions}%
+ \doif \@@efpreview \v!yes{\addtocommalist\v!preview \@@DriverImageOptions}%
+ \doif \@@efcontrols\v!yes{\addtocommalist\v!controls\@@DriverImageOptions}%
+ \doif \@@efrepeat \v!yes{\addtocommalist\v!repeat \@@DriverImageOptions}%
+ \doifinsetelse\@@efsize{mediabox,cropbox,artbox,bleedbox,trimbox}
+ {\let \@@DriverImageBox \@@efsize}%
+ {\doifinsetelse\@@efsize{media,crop,art,bleed,trim}
+ {\edef\@@DriverImageBox{\@@efsize box}}%
+ {\let \@@DriverImageBox \empty}}%
+ \let\wantedfigureoptions\@@DriverImageOptions}
+
+\def\checkiffigureobjectpresent
+ {\doifnot\@@efobject\v!no
+ {\doifobjectssupportedelse
+ {\doifobjectfoundelse{FIG}\externalfigurestamp
+ {\doshowfigurestate{object found : \externalfigurestamp}%
+ \getobjectdimensions{FIG}\externalfigurestamp
+ \edef\frozenfigurestamp{\externalfigurestamp}%
+ \xdef\analyzedfigurewidth {\the\dimexpr\objectwidth \relax}%
+ \xdef\analyzedfigureheight{\the\dimexpr\objectheight\relax}%
+ \setanalyzedfiguredimensions\plusone}
+ {\doshowfigurestate{unknown object: \externalfigurestamp}}}
+ {}}}
+
+\def\checkifknownfigureobjectpresent
+ {\ifx\wantedfiguretype\empty
+ \let\savedwantedfiguretype\wantedfiguretype
+ \def\docommand##1%
+ {\ifcase\figurestatus
+ \edef\wantedfiguretype{##1}%
+ \checkiffigureobjectpresent
+ \fi}%
+ \processcommacommand[\figuretypes]\docommand
+ \ifcase\figurestatus
+ \let\wantedfiguretype\savedwantedfiguretype
+ \fi
+ \fi}
+
+\def\checkforfigurefile
+ {\ifcase\figurestatus
+ \ifconditional\externalfigureflush
+ \analyzefigurefiles
+ \fi
+ \fi}
+
+\def\externalfigurestamp % needs \edef'd macros!
+ {\ifx\wantedfigurepath\empty\else
+ -\wantedfigurepath
+ \fi
+ \wantedfigurename
+ \ifx\wantedfiguretype\empty\else
+ \ifx\wantedfiguretype\s!unknown\else
+ -\wantedfiguretype
+ \fi
+ \fi
+ \ifx\wantedfiguretypespec\empty\else
+ \ifx\wantedfiguretypespec\s!unknown\else
+ \ifx\wantedfiguretypespec\wantedfiguretype\else
+ -\wantedfiguretypespec
+ \fi
+ \fi
+ \fi
+ \ifnum\wantedfigurepage>\zeropoint
+ -\wantedfigurepage
+ \fi}
+
+\def\checkfigurerenderingoptions
+ {\ifcase\figurestatus
+ \let\@@efframe\v!on
+ \fi
+ \doif\@@exoption\v!frame
+ {\let\@@efframe\v!on}%
+ \doif\@@exoption\v!empty
+ {\skipexternalfigurestrue
+ \let\@@efframe\v!off}}
+
+\newtoks\externalfigurepostprocessors
+
+\def\resetfigureusersettings
+ {\let\@@eftype \s!unknown \let\@@efmethod \empty \let\@@efpreset\v!yes
+ \let\@@eflabel \empty \let\@@efsize \empty \let\@@efpage \!!zerocount
+ \let\@@efobject \@@exobject \let\@@efdisplay \empty
+ \let\@@efsplit \empty \let\@@efcolor \empty \let\@@efsymbol\v!no
+ \let\@@efcontrols \v!no \let\@@efpreview \v!no \let\@@efrepeat\v!no
+ \let\@@efhfactor \empty \let\@@efwfactor \empty \let\@@effactor\empty
+ \let\@@efmaxwidth \@@exmaxwidth \let\@@efmaxheight\@@exmaxheight
+ \let\@@efxscale \empty \let\@@efyscale \empty \let\@@efscale \empty
+ \let\@@efsx \!!plusone \let\@@efsy \!!plusone
+ \let\@@efwidth \empty \let\@@efheight \empty
+ \let\@@eflines \empty \let\@@efgrid \empty
+ \let\@@efconversion\@@exconversion \let\@@efprefix \@@exprefix \let\@@efcache \@@excache}
+
+%D Types and Methods are a bit history. Anyhow, user scan use the
+%D type to force the handler. So, what to do with the method. We can
+%D use that one to force a handler with a given suffix, so when no
+%D type is given, but a suffix is part of the name, the method will
+%D determine the handler.
+
+\def\checkfigureusersettings
+ {\doif\@@efreset\v!yes\resetexternalfigures
+ \doifelsenothing\@@eflabel
+ {\doifnothing\wantedfigurelabel{\let\wantedfigurelabel\wantedfigurename}}%
+ {\let\wantedfigurelabel\@@eflabel}%
+ \doifsomething\@@eftype
+ {\doifnot\@@eftype\s!unknown
+ {\edef\wantedfiguretypespec{\@@eftype}%
+ \let\wantedfiguremethod\wantedfiguretypespec}}%
+ \doifnothing\wantedfigurepage % can be set by plug in
+ {\let\wantedfigurepage\@@efpage}%
+ \doif\wantedfigurepage\empty
+ {\let\wantedfigurepage\!!zerocount}% 0 is signal !
+ \doifsomething\@@efmethod % rather untested misusage of the remapper
+ {\doifsomething\wantedfiguretype
+ {\definegraphictypesynonym[\wantedfiguretype][\@@method]}}}
+
+% #1 is now obsolete
+
+\def\calculateexternalfigure[#1][#2][#3][#4][#5][#6]% \cmd label filename parent_id preset current
+ {\doshowfigurestate{begin}%
+ \dontcomplain
+ % let's limit the search, which means that e.g. svg has to be given explicitly
+ \checksupportedfiguretypes
+ % recently added; we presume local use
+ \restorecatcodes
+ % collected resets (token list)
+ \resetfigurevariables
+\resetwantedconversionvariables % new here
+ % analyze filename and set wanted variables
+ \analyzefigurefilename{#3}{#2}%
+ \doanalyzefiguredimensionsfromfile
+ % handle user settings
+ \resetfigureusersettings
+ \dosetefparameters{#4}{#5}{#6}%
+ \checkfigureusersettings
+ \checkfigurecolorsettings
+ % adapt settings based on suffix and/or type
+ \presetfiguretypeprocessing
+ % now we really start
+ \checkiffigureobjectpresent % first guess, we may not yet know the typespec
+ \checkifknownfigureobjectpresent
+ \checkforfigurefilepresence
+ \checkiffigureobjectpresent % to be sure, in case we now know the typespec
+ \checkfigurerenderingoptions % was later, moved here
+ \checknaturalfiguredimensions % inherit from global values and/or fallbacks
+ % by now we know what we're dealing with (put in box and scale)
+ \setextrafiguredriveroptions
+ \prepackageexternalfigureobject
+ % set public variables in case postprocessing needs them
+ \pushpublicfigurevariables
+ \setpublicfigurevariables
+ \setpublicfigureconversionvariables
+ \setpublicfigurescalevariables
+ % package final graphic, only now we can apply backgrounds and such
+ \doglobal\increment\figurenestinglevel
+ \finishexternalfigure
+ \doglobal\decrement\figurenestinglevel
+ % restore variables
+ \poppublicfigurevariables
+ \doshowfigurestate{end}}
+
+\def\checkforfigurefilepresence
+ {\checkforconvertedfigure
+ \checkforfigurefile}
+
+%D Figure objects.
+
+\def\setfigureobject
+ {\doshowfigurestate{object set : \externalfigurestamp}%
+ \setobject{FIG}\externalfigurestamp}
+
+% \def\getfigureobject
+% {\doshowfigurestate{object used : \externalfigurestamp}%
+% \getobject{FIG}\externalfigurestamp}
+
+\def\getfigureobject
+ {\doshowfigurestate{object used : \frozenfigurestamp}%
+ \getobject{FIG}\frozenfigurestamp}
+
+\def\prepackageexternalfigureobject
+ {\ifcase\figurestatus
+ \doshowfiguremessage1\expandedfigurename
+ \doshowfigurestate{state : figure not found (\expandedfigurename)}%
+ \global\setbox\foundexternalfigure\naturalvbox
+ {\doscalebox\??ef{\blackrule[\c!width=\naturalfigurewidth,\c!height=\naturalfigureheight]}}%
+ \xdef\noffigurepages{0}%
+ \or
+ \doshowfiguremessage8\expandedfigurename
+ \doshowfigurestate{state : reusing existing figure}%
+ \global\setbox\foundexternalfigure\naturalvbox
+ {\doscalebox\??ef{\dowithfigure{\getfigureobject}}}%
+ \xdef\noffigurepages{\number\getvalue{\externalfigurestamp\c!n}}%
+ \or
+ \doshowfiguremessage2\expandedfigurename
+ \doshowfigurestate{state : using special figure}%
+ \setbox\scratchbox\naturalvbox % make a dummy
+ {\doscalebox\??ef{\blackrule[\c!width=\naturalfigurewidth,\c!height=\naturalfigureheight]}}%
+ \global\setbox\foundexternalfigure\naturalvbox to \finalscaleboxheight
+ {\vfill
+ \hsize\finalscaleboxwidth
+ \dowithfigure{\insertscaledfiguredriverdata}}%
+ \xdef\noffigurepages{\number\nofinsertpages}%
+ \else
+ \ifdim\naturalfigurewidth>\zeropoint
+ \ifnum\figurestatus>\!!ten\relax
+ \doshowfiguremessage3\expandedfigurename
+ \else
+ \doshowfiguremessage4\expandedfigurename
+ \fi
+ \else
+ \doshowfiguremessage5\expandedfigurename
+ \fi
+ \doshowfigurestate{state : using found figure}% 3=self 4=rlx
+ \doifelse\@@efobject\v!no
+ {\donefalse}
+ {\doifobjectssupportedelse\donetrue\donefalse}%
+ \ifdone
+ % make an object and use it
+ \packageexternalfigureobject
+ \setfigureobject\vbox{\box\foundexternalfigure}%
+ \setxvalue{\externalfigurestamp\c!n}{\number\nofinsertpages}%
+ \global\setbox\foundexternalfigure\naturalvbox
+ {\doscalebox\??ef{\dowithfigure{\getfigureobject}}}%
+ \xdef\noffigurepages{\number\getvalue{\externalfigurestamp\c!n}}%
+ \else
+ % maybe a tex figure
+ \global\setbox\foundexternalfigure\naturalvbox
+ {\doscalebox\??ef{\dowithfigure{\box\foundexternalfigure}}}%
+ \xdef\noffigurepages{\number\nofinsertpages}%
+ \fi
+ \fi
+ \global\wd\foundexternalfigure\finalscaleboxwidth
+ \global\ht\foundexternalfigure\finalscaleboxheight
+ \global\let\lastfigureobjectname\externalfigurestamp
+ \doresetobjects} % clean up driver left overs
+
+\def\packageexternalfigureobject
+ {\global\setbox\foundexternalfigure\vbox to \naturalfigureheight
+ {\vfill
+ \ifdim\wd\foundexternalfigure=\zeropoint
+ \setextrafiguredriveroptions
+ \insertunscaledfiguredriverdata
+ \else\ifskipexternalfigures
+ \ruledhbox{\backgroundline[\@@efsplitcolor]{\fakebox\foundexternalfigure}}%
+ \else
+ \box\foundexternalfigure
+ \fi\fi}%
+ \wd\foundexternalfigure\naturalfigurewidth
+ \ht\foundexternalfigure\naturalfigureheight}
+
+\def\finishexternalfigure % here we use \figurevariables
+ {\global\setbox\foundexternalfigure\vbox
+ {\forgetall
+ \ifcase\figurestatus
+ \resetsystemmode\v!figure % todo, also: \v!resource
+ \else
+ \setsystemmode \v!figure % todo, also: \v!resource
+ \fi
+ \ifconditional\externalfigureflush
+ \ifconditional\externalfigurelevel % probably background
+ \ifskipexternalfigures
+ % nothing
+ \fakebox\foundexternalfigure
+ \else\ifcase\figurestatus
+ % nothing
+ \else\ifnum\splitexternalfigure=\plustwo\else
+ \the\externalfigurepostprocessors
+ \box\foundexternalfigure
+ \fi\fi\fi
+ \else
+ \iftrialtypesetting \else \feedbackexternalfigure \fi
+ \settrue\externalfigurelevel
+ \ifskipexternalfigures
+ \ifcase\figurestatus
+ \externalfigurereplacement\figurelabel\figurefilename{unknown}%
+ \else
+ \externalfigurereplacement\figurelabel\figurefullname{skipped}%
+ \fi
+ \else\ifcase\figurestatus
+ \externalfigurereplacement\figurelabel\figurefilename{unknown}%
+ \else\ifnum\splitexternalfigure=\plustwo
+ \backgroundline[\@@efsplitcolor]{\fakebox\foundexternalfigure}%
+ \else
+ \the\externalfigurepostprocessors
+ \doifelse\@@efreset\v!yes
+ {\wd\foundexternalfigure\figurewidth
+ \ht\foundexternalfigure\figureheight
+ \dp\foundexternalfigure\zeropoint
+ \box\foundexternalfigure}
+ {\localframed % should also be applied to high res !
+ [\??ef]
+ [\c!offset=\v!overlay,
+ \c!width=\figurewidth,
+ \c!height=\figureheight]
+ {\vfilll
+ \ifnum\splitexternalfigure=\plusone
+ % hm, eigenlijk in dit geval achtergrondkleur
+ \hidesplitcolorfalse % really needed
+ \backgroundline[\@@efsplitcolor]{\box\foundexternalfigure}%
+ \else % = 0, no split mode
+ \box\foundexternalfigure
+ \fi}}%
+ \fi\fi\fi
+ \fi
+ \else
+ % maybe also \the\externalfigurepostprocessors
+ \iftrialtypesetting \else \feedbackexternalfigure \fi
+ \fi}}
+
+\def\insertfiguredriverdata#1#2%
+ {\lowercasestring\wantedfiguretypespec\to\lcwantedfiguretypespec
+ \lowercasestring\wantedfiguremethod \to\lcwantedfiguremethod
+ \edef\@@DriverImageWidth {\the\dimexpr#1\relax}%
+ \edef\@@DriverImageHeight{\the\dimexpr#2\relax}%
+ \let \@@DriverImageFile \wantedfigurefullname
+ \let \@@DriverImageType \lcwantedfiguretypespec
+ \let \@@DriverImageMethod \lcwantedfiguremethod
+ \let \@@DriverImageLabel \wantedfigurelabel
+ \let \@@DriverImagePage \wantedfigurepage
+ \doinsertfile}
+
+\def\insertunscaledfiguredriverdata
+ {\insertfiguredriverdata\naturalfigurewidth\naturalfigureheight}
+
+\def\insertscaledfiguredriverdata
+ {\insertfiguredriverdata\finalscaleboxwidth\finalscaleboxheight}
+
+\ifx\externalfigurereplacement\undefined\let\externalfigurereplacement\gobblethreearguments\fi
+\ifx\externalfigureplaceholder\undefined\let\externalfigureplaceholder\gobblethreearguments\fi
+
+\def\registerexternalfigure % no placement, handy for preprocessing
+ {\dotripleempty\doregisterexternalfigure}
+
+\def\doregisterexternalfigure[#1][#2][#3]%
+ {\bgroup
+ \setfalse\externalfigureflush
+ \externalfigure[#1][#2][#3]% or \doexternalfigure
+ \egroup}
+
+\let\feedbackexternalfigure\relax % \gobblefourarguments
+\let\dowithfigure \relax
+
+%D Conversion stuff:
+
+\newcount\nofconversionfigures
+
+\def\resetwantedconversionvariables
+ {\let\wantedconversionpath \empty % these point to the to be converted graphic
+ \let\wantedconversionname \empty
+ \let\wantedconversiontype \empty
+ \let\wantedconversioncache \empty
+ \let\wantedconversionprefix\empty}
+
+\resetwantedconversionvariables
+
+\def\checkforconvertedfigure
+ {\ifcase\figurestatus
+ \resetwantedconversionvariables
+ \doifsomething\@@efconversion
+ {\global\advance\nofconversionfigures\plusone
+ \doshowfigurestate{n-of-conversions : \number\nofconversionfigures}%
+ \edef\wantedfigureconversion{\@@efconversion}%
+ \edef\wantedconversioncache {\@@efcache}%
+ \edef\wantedconversionprefix{\@@efprefix}%
+ \doshowfigurestate{checking paths : \figurepathlist}%
+ \processcommacommand[\figurepathlist]\dolocatefigureconversionfile
+ \ifcase\figurestatus
+ \doshowfigurestate{remark : no conversion file found}%
+ \else
+ \doshowfigurestate{remark : conversion file found}%
+ \chardef\figurestatus\zerocount
+ \fi
+ \let\wantedconversionname\wantedfigurename
+ \edef\wantedfigurename{\wantedconversionprefix\wantedfigurename}%
+ \ifx\wantedconversioncache\empty
+ \let \wantedfigurepath \wantedconversionpath
+ \else
+ \checkfilename\@@efcache
+ \ifnum\kindoffile=\plusone
+ \let\wantedfigurepath\@@efcache % root related path
+ \else % brrr
+ \edef\wantedfigurepath{\@@efcache,\wantedconversionpath/\@@efcache}% in case of explicit paths, what a mess
+ \fi
+ \fi
+ \let\wantedfiguretype \empty
+ \let\wantedfiguretypelist\figuretypes % hm, why needed
+ \ifx\figurepathlist\empty
+ \let\figurepathlist\wantedfigurepath
+ \else
+ \edef\figurepathlist{\wantedfigurepath,\figurepathlist}%
+ \fi
+ \doshowfigurestate{conversion path : \wantedconversionpath}%
+ \doshowfigurestate{conversion name : \wantedconversionname}}%
+ \doshowfigurestate{new figure path : \wantedfigurepath}%
+ \fi}
+
+\def\dolocatefigureconversionfile#1%
+ {\ifcase\figurestatus
+ \setwantedfigurefullname{#1}\wantedfigurename\wantedfiguretype
+ \doshowfigurestate{locating original : \wantedfigurefullname}%
+ \doiffile\wantedfigurefullname
+ {\def\wantedconversionpath{#1}%
+ \let\wantedconversionname\wantedfigurename
+ \let\wantedconversiontype\wantedfiguretype
+ \chardef\figurestatus\plusfive}%
+ \fi}
+
+\def\setpublicfigureconversionvariables % also prefix, cache
+ {\doifsomething\@@efconversion
+ {\doifmode{\systemmodeprefix\v!first}
+ {\let\figurefilepath\wantedconversionpath
+ \let\figurefilename\wantedconversionname
+ \let\figurefiletype\wantedconversiontype
+ \let\figurefileconversion\wantedfigureconversion
+ \def\figurefullname
+ {\ifx\wantedconversionpath\empty\else\wantedconversionpath/\fi
+ \wantedconversionname
+ \ifx\wantedconversiontype\empty\else.\wantedconversiontype\fi}}}}
+
+%D In \PDF\ one can specify an alternative graphic. This means
+%D that for instance a low resolution graphic can be used for
+%D viewing and a high res one for printing. Because this
+%D feature depends much on the driver, here we only take care
+%D of perparations. It is up to the special driver to handle
+%D the inclusion. The driver routines can change the content of
+%D box \type {\foundexternalfigure} if suitable.
+%D
+%D One complication is for instance that an alternative may
+%D not itself have an alternative, and these kind of situations
+%D are best handled by the driver.
+
+\let\lastfigureobjectname\empty
+
+%D The next macro does not work well with figure bases yet.
+
+\def\calculateexternalscreenfigure[#1][#2][#3][#4][#5][#6]%
+ {\ifx\@@efdisplay\empty\else
+ \doifnot\@@efobject\v!no
+ {\doifobjectssupportedelse
+ {\doifspecialavailableelse\doregisterfigure
+ {\doshowfigurestate{screen alternative : start}%
+ \bgroup
+ \dosetefparameters{#4}{#5}{#6}%
+ \doregisterfigure{FIG}{\lastfigureobjectname}%
+ \let\@@ef@@scherm\@@efdisplay
+ \calculateexternalfigure[#1][\@@ef@@scherm][\@@ef@@scherm][#4,\c!display=][#5][#6]%
+ \doshowfigurestate{screen alternative : stop}%
+ \egroup}
+ {}}
+ {}}%
+ \fi}
+
+\def\getfiguredimensions
+ {\dodoubleempty\dogetfiguredimensions}
+
+\def\dogetfiguredimensions[#1][#2]%
+ {{\let\immediate\relax % very dirty but prevents flushing, will change
+ \setbox0\hbox{\externalfigure[#1][#2,\c!display=,\c!object=\v!no]}}}
+
+% use the next one when the object must be forgotten (xobj
+% nums can migrate to the next object; maybe it should
+% always be done; todo ....
+
+\def\getfiguredimensionsonly
+ {\dodoubleempty\dogetfiguredimensionsonly}
+
+\def\dogetfiguredimensionsonly[#1][#2]%
+ {\dogetfiguredimensions[#1][#2]%
+ \doresetobjects}
+
+\def\doiffigureelse#1%
+ {\getfiguredimensions[#1]% so data is available !
+ \ifdim\analyzedfigurewidth=\zeropoint % todo: \figurestatus
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+%D Size determination.
+%D
+%D An analyzer must set the following dimensions (global macros):
+%D
+%D \starttyping
+%D \analyzedfigurewidth
+%D \analyzedfigureheight
+%D \stoptyping
+%D
+%D And afterwards, when succeeded, call:
+%D
+%D \starttyping
+%D \setanalyzedfiguredimensions{number>=10}
+%D \stoptyping
+%D
+%D Numbers upto 9 are reserved for special purposes:
+%D
+%D \starttabulate
+%D \NC 0 \NC not found \NC \NR
+%D \NC 1 \NC object (will be reused) \NC \NR
+%D \NC 2 \NC found but no dimensions (e.g. special annotation) \NC \NR
+%D \stoptabulate
+
+\let\doanalyzefiguredimensionsfromfile\relax % hook for figuredatabase
+\let\doanalyzefiguredimensionsinternal\relax
+\let\doanalyzefiguredimensionsexternal\relax % hook for rli support (see later)
+\let\doanalyzefiguredimensionsfallback\relax
+
+\def\doanalyzefiguredimensions
+ {\lowercasestring\wantedfiguretypespec\to\lcwantedfiguretypespec
+ \doiffileinsertionsupportedelse\lcwantedfiguretypespec
+ {\doiffileelse\wantedfigurefullname
+ {\doshowfigurestate{analyzing : \wantedfigurefullname}%
+ \doanalyzefiguredimensionsinternal
+ \doanalyzefiguredimensionsexternal
+ \doanalyzefiguredimensionsfallback}
+ {\doshowfigurestate{not found : \wantedfigurefullname}}}
+ {}}
+
+\def\setanalyzedfiguredimensions#1%
+ {\ifdim\analyzedfigurewidth>\zeropoint
+ \ifdim\analyzedfigureheight>\zeropoint
+ \determinedfigurewidth \analyzedfigurewidth
+ \determinedfigureheight\analyzedfigureheight
+ \chardef\figurestatus #1\relax
+ \doshowfigurestate{dimensions :
+ \the\dimexpr\analyzedfigurewidth\relax\space x\space
+ \the\dimexpr\analyzedfigureheight\relax}%
+ \else
+ \determinedfigurewidth \zeropoint
+ \determinedfigureheight\zeropoint
+ \chardef\figurestatus \zerocount
+ \fi
+ \else
+ \determinedfigurewidth \zeropoint
+ \determinedfigureheight\zeropoint
+ \chardef\figurestatus \zerocount
+ \fi}
+
+%D We can remap types. This is to be dealt with in the driver files.
+
+\def\definegraphictypesynonym
+ {\dodoubleargument\dodefinegraphictypesynonym}
+
+\def\dodefinegraphictypesynonym[#1][#2]%
+ {\setvalue{\??ef:\??ex:#1}{#2}}
+
+\def\truegraphictype#1%
+ {\ifcsname\??ef:\??ex:#1\endcsname
+ \expandafter\truegraphictype\csname\??ef:\??ex:#1\endcsname\else#1%
+ \fi}
+
+\definegraphictypesynonym[epdf] [pdf]
+\definegraphictypesynonym[jpeg] [jpg]
+\definegraphictypesynonym[jp2] [jpg]
+\definegraphictypesynonym[jbig] [jb2]
+\definegraphictypesynonym[jbig2][jb2]
+\definegraphictypesynonym[jbg] [jb2]
+
+%D The self method (mostly used) uses the driver.
+
+% todo: when zero width mps, ok
+%
+% analyzer must set the analyzed dimensions
+
+\def\doanalyzefiguredimensionsinternal
+ {\ifcase\figurestatus
+ \lowercasestring\wantedfiguretypespec\to\lcwantedfiguretypespec
+ \let\@@DriverImageFile \wantedfigurefullname
+ \let\@@DriverImagePage \wantedfigurepage
+ \let\@@DriverImageType\lcwantedfiguretypespec
+ % use internal when available, otherwise try driver (\dogetfiguresize)
+ \executeifdefined{dogetfiguresize\@@DriverImageType}\dogetfiguresize
+ \setanalyzedfiguredimensions\!!ten
+ \fi}
+
+%D The tex method.
+
+\def\dogetfiguresizetex
+ {\ifcase\figurestatus
+ \global\setbox\foundexternalfigure\vbox
+ {\insidefloattrue
+ \forgetall
+ \blank[\v!disable]% niet meer weg !
+ \startreadingfile
+ \readfile\wantedfigurefullname \donothing \donothing
+ \stopreadingfile
+ \endgraf
+ \removelastskip}%
+ \global\setbox\foundexternalfigure\hbox
+ {\raise\dp\foundexternalfigure\box\foundexternalfigure}%
+ \xdef\analyzedfigurewidth {\the\wd\foundexternalfigure}%
+ \xdef\analyzedfigureheight{\the\ht\foundexternalfigure}%
+ \fi}
+
+\let\dogetfiguresizetmp \dogetfiguresizetex
+\let\dogetfiguresizebuffer\dogetfiguresizetex
+
+%D The eps, mps and svg files are read directly.
+
+\def\dogetfiguresizeeps
+ {\dogetEPSboundingbox\wantedfigurefullname\!!widtha\!!heighta\!!widthb\!!heightb
+ \xdef\analyzedfigurewidth {\the\!!widthb}%
+ \xdef\analyzedfigureheight{\the\!!heightb}}
+
+\let\dogetfiguresizemps\dogetfiguresizeeps
+
+\def\dogetfiguresizesvg
+ {\doifinset\wantedfiguretypespec\c!svg
+ {\startnointerference
+ \startXMLignore
+ \defineXMLcommand[svg][width=100,height=75]
+ {\doifdimensionelse{\XMLop{width}}
+ {\xdef\analyzedfigurewidth {\the\dimexpr\XMLop{width}\relax}}
+ {\xdef\analyzedfigurewidth {\the\dimexpr\XMLop{width}\onebasepoint\relax}}%
+ \doifdimensionelse{\XMLop{height}}
+ {\xdef\analyzedfigurewidth {\the\dimexpr\XMLop{height}\relax}}
+ {\xdef\analyzedfigurewidth {\the\dimexpr\XMLop{height}\onebasepoint\relax}}%
+ \endinput}%
+ \processXMLfilegrouped\wantedfigurefullname
+ \stopXMLignore
+ \stopnointerference}}
+
+%D Do some checking on the filename.
+
+\newconditional \figurefileisqualified
+
+\def\setfigurepathlist
+ {\let\figurepathlist\empty
+ \expanded{\doifinset{\v!global }{\@@exlocation}}
+ {\let\figurepathlist\@@exdirectory}%
+ \expanded{\doifinset{\v!local }{\@@exlocation}}
+ {\prependtocommalist\f!currentpath\figurepathlist}%
+ \expanded{\doifinset{\v!default}{\@@exlocation}}
+ {\appendtocommalist\defaultfigurepathsignal\figurepathlist}}
+
+% The combined path and qualified path hack is dedicated to Onno Tomson,
+% our partner in fighting inconsistent and faulty image specifications in
+% user files.
+
+\def\analyzefigurefilename#1#2%
+ {\sanitizefilename#1\to\expandedfigurename
+ \expanded{\checkfilename{\expandedfigurename}}%
+ \ifcase\kindoffile
+ \splitfigurefilename
+ \ifcase\splitoffkind
+ \let\wantedfigurepath\empty % no . either
+ \setfigurepathlist
+ \setfalse\figurefileisqualified
+ \else
+ \splitfigurefilename
+ % will become splitoffkind 3 ! ! ! !
+ \setfalse\figurefileisqualified
+ \doifinstring{$$/}{$$\wantedfigurepath}{\settrue\figurefileisqualified}%
+ \doifinstring {:} {\wantedfigurepath}{\settrue\figurefileisqualified}%
+ \ifconditional\figurefileisqualified
+ \let\figurepathlist\wantedfigurepath
+ \let\wantedfigurepath\empty
+ \settrue\figurefileisqualified
+ \else
+ \let\figurepathlist\@@exdirectory
+ \let\oldfigurepathlist\figurepathlist
+ \let\figurepathlist\wantedfigurepath
+ \def\docommand##1{\edef\figurepathlist{\figurepathlist,##1/\wantedfigurepath}}%
+ \processcommacommand[\oldfigurepathlist]\docommand
+ \fi
+ \fi
+ \else % fully qualified
+ \splitfigurefilename
+ \let\wantedfigurepath\empty
+ \settrue\figurefileisqualified
+ \fi
+ \ifx\figurepathlist\empty
+ \let\figurepathlist\defaultfigurepathsignal % will prepend no path
+ \fi
+ \doifelsenothing\wantedfiguretype
+ {\doifparentfileelse\wantedfigurename
+ {\@EA\removefromcommalist\@EA{\jobsuffix }\wantedfiguretypelist
+ \@EA\removefromcommalist\@EA{\jobfilesuffix}\wantedfiguretypelist}
+ {}}
+ {\let\wantedfiguretypelist\empty
+ \let\wantedfiguretypespec\wantedfiguretype}%
+ \edef\wantedfigurelabel{#2}%
+ \doshowfigurestate{type check : \ifx\wantedfiguretypelist\empty forced type \wantedfiguretypespec\else\wantedfiguretypelist\fi}%
+ \doshowfigurestate{file specs : \wantedfigurefull\space [\wantedfigurepath] [\wantedfigurename] [\wantedfiguretype]}%
+ \doshowfigurestate{file type : \ifconditional\figurefileisqualified qualified\else simple\fi}}
+
+\def\setwantedfigurefullname#1#2#3% path name spec
+ {\ifx\wantedfiguremethod\empty
+ % the either explicit or gambled typespec determines the method
+ \edef\wantedfiguretypespec{#3}%
+ \doifelse{#1}\defaultfigurepathsignal
+ {\edef\wantedfigurefullname {#2.\wantedfiguretypespec}}
+ {\edef\wantedfigurefullname{#1/#2.\wantedfiguretypespec}}%
+ \else\ifx\wantedfiguretype\empty %
+ % the typespec (probably the same as the method) determines the suffix
+ \doifelse{#1}\defaultfigurepathsignal
+ {\edef\wantedfigurefullname {#2.\wantedfiguretypespec}}
+ {\edef\wantedfigurefullname{#1/#2.\wantedfiguretypespec}}%
+ \let\wantedfiguretypespec\wantedfiguremethod
+ \else
+ % the given suffix is used
+ \let\wantedfiguretypespec\wantedfiguremethod
+ \doifelse{#1}\defaultfigurepathsignal
+ {\edef\wantedfigurefullname {#2.\wantedfiguretype}}
+ {\edef\wantedfigurefullname{#1/#2.\wantedfiguretype}}%
+ \fi\fi}
+
+\def\splitfigurefilename
+ {\splitfilename\expandedfigurename
+ \let\wantedfigurefull\splitofffull
+ \let\wantedfigurepath\splitoffpath
+ \let\wantedfigurename\splitoffname
+ \let\wantedfigurebase\splitoffbase
+ \let\wantedfiguretype\splitofftype}
+
+\def\analyzefigurefiles
+ {\ifconditional\figurefileisqualified
+ \ifx\wantedfiguretype\empty
+ \doshowfigurestate{locating : unknown type}%
+ \doanalyzeunknownfiguretype
+ \else
+ % this file or none
+ \doshowfigurestate{locating : known type}%
+ \doanalyzequalifiedfigure
+ \fi
+ \else
+ \ifx\wantedfiguretype\empty
+ % locate best fit / check support
+ \doshowfigurestate{locating : best fit}%
+ \doanalyzeunknownfiguretype
+ \else
+ % only check on paths
+ \doshowfigurestate{locating : known types}%
+ \doanalyzeknownfiguretype
+ \fi
+ \fi}
+
+\def\doanalyzequalifiedfigure
+ {\let\wantedfigurefullname\wantedfigurefull
+ \let\wantedfiguretypespec\wantedfiguretype
+ \doshowfigurestate{forced type : \wantedfiguretype}%
+ \doshowfigurestate{identifying : \wantedfigurefullname}%
+ \doanalyzefiguredimensions}
+
+\def\doanalyzeknownfiguretype
+ {\doshowfigurestate{using paths : \figurepathlist}%
+ \doshowfigurestate{known type : \wantedfiguretype}%
+ \doshowfigurestate{identifying : \wantedfigurename}%
+ \let\wantedfiguretypespec\wantedfiguretype
+ \processcommacommand[\figurepathlist]\dodoanalyzeknownfiguretype}
+
+\def\dodoanalyzeknownfiguretype#1% path
+ {\ifcase\figurestatus
+ \setwantedfigurefullname{#1}\wantedfigurename\wantedfiguretype
+ \doanalyzefiguredimensions
+ \fi}
+
+\def\doanalyzeunknownfiguretype
+ {\doshowfigurestate{using paths : \figurepathlist}%
+ \doshowfigurestate{using types : \wantedfiguretypelist}%
+ \doshowfigurestate{identifying : \wantedfigurename}%
+ \processcommacommand[\wantedfiguretypelist]\dodoanalyzeunknownfiguretype}
+
+\def\dodoanalyzeunknownfiguretype#1%
+ {\processcommacommand[\figurepathlist]{\dododoanalyzeunknownfiguretype{#1}}}
+
+\def\dododoanalyzeunknownfiguretype#1#2% type path
+ {\ifcase\figurestatus
+ \setwantedfigurefullname{#2}\wantedfigurename{#1}% path spec
+ \doanalyzefiguredimensions
+ \fi}
+
+%D Some files, take for instance movies, cannot easilly be
+%D parsed on dimensions, that is, not yet. Although the current
+%D mechanism has no problems with this, as long as the user
+%D specified width and height reflect the right aspect ratio.
+%D Nevertheless, when one does not want any scanning done, one
+%D can disable \type{preset}. When no preset is needed, we only
+%D locate the file.
+
+\def\doanalyzefiguredimensionsfallback
+ {\ifcase\figurestatus
+ \doshowfigurestate{warning : assuming adaptive figure}%
+ \xdef\analyzedfigurewidth {\the\dimexpr\@@efwidth +\zeropoint\relax}%
+ \xdef\analyzedfigureheight{\the\dimexpr\@@efheight+\zeropoint\relax}%
+ \setanalyzedfiguredimensions\plustwo
+ \fi}
+
+%D This is \MKII\ only and comes from cont-new (maybe used in a project).
+
+% maybe to be integrated (option=...)
+
+\def\directexternalfigure
+ {\dodoubleempty\dodirectexternalfigure}
+
+\def\dodirectexternalfigure[#1][#2]%
+ {\bgroup
+ \getparameters[\??ef][\c!type=\splitofftype,\c!page=1,#2]%
+ \sanitizefilename#1\to\expandedfigurename
+ \splitfilename\expandedfigurename
+ \let\@@DriverImageWidth \!!zeropoint
+ \let\@@DriverImageHeight \!!zeropoint
+ \let\@@DriverImageFile \splitofffull
+ \let\@@DriverImageType \@@eftype
+ \let\@@DriverImageMethod \@@eftype
+ \let\@@DriverImageLabel \empty
+ \let\@@DriverImagePage \@@efpage
+ \doinsertfile
+ \egroup}
+
+% \directexternalfigure[cow.pdf]
+
+\protect \endinput
diff --git a/tex/context/base/grph-inc.mkiv b/tex/context/base/grph-inc.mkiv
new file mode 100644
index 000000000..16ee1097a
--- /dev/null
+++ b/tex/context/base/grph-inc.mkiv
@@ -0,0 +1,433 @@
+%D \module
+%D [ file=grph-inc, % moved from core-fig
+%D version=2006.08.26, % overhaul of 1997.03.31
+%D title=\CONTEXT\ Graphic Macros,
+%D subtitle=Figure Inclusion,
+%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 Graphic Macros / Figure Inclusion}
+
+%D todo:
+%D
+%D - color conversion
+%D - alternative images
+%D - a few more obscure things
+
+\registerctxluafile{grph-inc}{1.001}
+\registerctxluafile{grph-fil}{1.001}
+\registerctxluafile{grph-u3d}{1.001} % this will change
+\registerctxluafile{grph-swf}{1.001} % this will change
+
+\unprotect
+
+%D The following registers are used (if only to be downward compatible).
+
+\newbox \foundexternalfigure
+\newif \ifskipexternalfigures
+\newtoks \everyexternalfigureresets
+\newtoks \everyexternalfigurechecks
+\newtoks \externalfigurepostprocessors
+
+\def\resetfigurevariables {\the\everyexternalfigureresets}
+\def\checkfigurevariables {\the\everyexternalfigurechecks}
+
+%D Historic feature:
+
+\appendtoks
+ \global\let\externalfigurelog\empty
+\to \everyexternalfigureresets
+
+\let\runutilityfiletrue \relax \let\runutilityfilefalse \relax
+\let\consultutilityfiletrue\relax \let\consultutilityfilefalse\relax
+
+%D You can register additional suffixes with the following command:
+%D
+%D \starttyping
+%D \definegraphictypesynonym[jbig] [jb2]
+%D \definegraphictypesynonym[jbig2][jb2]
+%D \definegraphictypesynonym[jbg] [jb2]
+%D \stoptyping
+
+\unexpanded\def\definegraphictypesynonym
+ {\dodoubleargument\dodefinegraphictypesynonym}
+
+\def\dodefinegraphictypesynonym[#1][#2]%
+ {\ctxlua{figures.registersuffix("#1","#2")}}
+
+%D Additional paths can be installed with the regular setup command. The next
+%D macro picks up the list.
+
+\def\setfigurepathlist
+ {\ctxlua{figures.setpaths("\@@exlocation",\!!bs\@@exdirectory\!!es)}}
+
+%D Variables:
+
+\def\defaultfigurewidth {8\lineheight}
+\def\defaultfigureheight {6\lineheight}
+
+\def\figurestatus {\numexpr\ctxlua{figures.tprint("status","status",0)}\relax} % number: 0 = not found
+\def\figurewidth {\ctxlua{figures.tprint("status","width",0)}sp}
+\def\figureheight {\ctxlua{figures.tprint("status","height",0)}sp}
+\def\figurexscale {\ctxlua{figures.tprint("status","xscale",1)}}
+\def\figureyscale {\ctxlua{figures.tprint("status","yscale",1)}}
+
+\def\figurelabel {\ctxlua{figures.tprint("request","label")}}
+\def\figurefileoriginal {\ctxlua{figures.tprint("request","name")}}
+\def\figurefilepage {\ctxlua{figures.tprint("request","page",1)}}
+\def\figurefileoptions {\ctxlua{figures.tprint("request","options")}}
+\def\figurefileconversion{\ctxlua{figures.tprint("request","conversion")}}
+\def\figurefilecache {\ctxlua{figures.tprint("request","cache")}}
+\def\figurefileprefix {\ctxlua{figures.tprint("request","prefix")}}
+
+\def\figurenaturalwidth {\ctxlua{figures.tprint("used","width", \number\dimexpr\defaultfigurewidth \relax)}sp}
+\def\figurenaturalheight {\ctxlua{figures.tprint("used","height",\number\dimexpr\defaultfigureheight\relax)}sp}
+
+\def\figurefilepath {\ctxlua{tex.sprint(tex.ctxcatcodes,file.dirname (figures.get("used","fullname")))}}
+\def\figurefilename {\ctxlua{tex.sprint(tex.ctxcatcodes,file.nameonly(figures.get("used","fullname")))}}
+\def\figurefiletype {\ctxlua{tex.sprint(tex.ctxcatcodes,file.extname (figures.get("used","fullname")))}}
+\def\figurefullname {\ctxlua{figures.tprint("used","fullname")}}
+\def\noffigurepages {\ctxlua{figures.tprint("used","pages",0)}}
+
+\let\naturalfigurewidth \figurenaturalwidth
+\let\naturalfigureheight \figurenaturalheight
+
+\let\figurescalewidth \figurewidth
+\let\figurescaleheight \figureheight
+\let\figurescalexscale \figurexscale
+\let\figurescaleyscale \figureyscale
+
+\appendtoks
+ \ctxlua { % figures.defaultwidth .. why not dimen
+ figures.setpaths("\@@exlocation","\@@exdirectory") ;
+ figures.defaultwidth = \number\dimexpr\defaultfigurewidth \relax ;
+ figures.defaultheight = \number\dimexpr\defaultfigureheight\relax ;
+ figures.boxnumber = \number\foundexternalfigure ;
+ }%
+\to \everyexternalfigureresets
+
+%D In some situations we need to make sure that the figure related variables
+%D are reset. This is especially important when we are nesting. Is this still
+%D needed in \MKIV.
+
+\def\resetexternalfigures
+ {\let\@@efoption \empty % \let\@@efprefix\empty
+ \let\@@efmaxwidth \empty % \let\@@efcache \empty
+ \let\@@efmaxheight \empty % \let\@@efframe \v!off
+ \let\@@efforegroundcolor\empty
+ \let\@@efcolor \empty
+ \let\@@efconversion \empty
+ \let\@@efbackground \empty}
+
+\appendtoks \resetexternalfigures \to \everyoverlay
+\appendtoks \resetexternalfigures \to \everybeforepagebody % not really needed
+
+\def\resetfigureusersettings
+ {%
+ \let\@@efmethod \empty
+ \let\@@eflabel \empty
+ \let\@@efsize \empty
+ \let\@@efconversion\@@exconversion
+ \let\@@efprefix \@@exprefix
+ \let\@@efcache \@@excache
+ \let\@@efpage \!!zerocount
+ \let\@@efobject \@@exobject
+ \let\@@efdisplay \empty
+ %
+ \let\@@efpreset \v!yes
+ \let\@@efsplit \empty
+ \let\@@efcolor \empty
+ %
+ \let\@@efsymbol \v!no
+ %
+ \let\@@efcontrols \v!no
+ \let\@@efpreview \v!no
+ \let\@@efrepeat \v!no
+ %
+ \let\@@efforegroundcolor\empty
+ %
+ \let\@@efhfactor \empty
+ \let\@@efwfactor \empty
+ \let\@@effactor \empty
+ \let\@@efmaxwidth \@@exmaxwidth
+ \let\@@efmaxheight \@@exmaxheight
+ \let\@@efxscale \empty
+ \let\@@efyscale \empty
+ \let\@@efscale \empty
+ \let\@@efsx \!!plusone
+ \let\@@efsy \!!plusone
+ \let\@@efwidth \empty
+ \let\@@efheight \empty
+ \let\@@eflines \empty
+ \let\@@efgrid \empty}
+
+\resetfigureusersettings
+
+\appendtoks
+ \resetfigureusersettings
+\to \everyexternalfigureresets
+
+\def\checkfigureusersettings
+ {% old features
+ \doif\@@exoption\v!frame
+ {\let\@@efframe\v!on}%
+ \doif\@@exoption\v!empty
+ {\skipexternalfigurestrue
+ \let\@@efframe\v!off}%
+ \doifsomething\@@efwidth {\doifdimensionelse\@@efwidth {\edef\@@efwidth {\the\dimexpr\@@efwidth }}\donothing}%
+ \doifsomething\@@efheight{\doifdimensionelse\@@efheight{\edef\@@efheight{\the\dimexpr\@@efheight}}\donothing}%
+ % fake color in gray bitmaps, assumes that
+ % a transparent color is used
+ \doifsomething\@@efforegroundcolor
+ {\def\@@efbackground{\v!foreground,\v!color}%
+ \def\@@efbackgroundcolor{\@@efforegroundcolor}}}
+
+\appendtoks
+ \checkfigureusersettings
+\to \everyexternalfigurechecks
+
+%D Internal graphics are handled at the \TEX\ end:
+
+\def\doprocesstexlikefigure#1% retrofit into mkii
+ {\global\setbox\foundexternalfigure\vbox\framed
+ [\c!strut=\v!no,\c!align=\v!normal,\c!frame=\v!off,
+ \c!offset=\v!overlay,\c!width=\v!fit,\c!height=\v!fit]
+ {\blank[\v!disable]#1\endgraf\removelastskip}} % disable should stay here!
+
+\def\doprocessmpslikefigure#1% retrofit into mkii
+ {\global\setbox\foundexternalfigure\vbox{\convertMPtoPDF{#1}11}}
+
+\def\docheckfigurebuffer #1{\doprocesstexlikefigure{\getbuffer[#1]}}
+\def\docheckfiguretex #1{\doprocesstexlikefigure{\input#1\relax}}
+\def\docheckfiguremps #1{\doprocessmpslikefigure{#1}}
+\def\docheckfiguremprun #1#2{\doprocesstexlikefigure{\useMPrun{#1}{#2}}}
+
+\def\doscalefigure
+ {\global\setbox\foundexternalfigure\vbox{\doscalebox\??ef{\dowithfigure{\box\foundexternalfigure}}}}
+
+\newconditional\testexternalfigureonly
+
+% \enabletrackers[figures.conversion]
+% \externalfigure[demo.svg]
+% \externalfigure[demo.svg][conversion=png]
+
+\def\calculateexternalfigure[#1][#2][#3][#4][#5][#6]% \cmd label filename parent_id preset current
+ {\dontcomplain
+ \restorecatcodes
+ \forgetall
+ \resetfigurevariables
+ \dosetefparameters{#4}{#5}{#6}%
+ \checkfigurevariables
+% \begingroup
+% \color[\@@efcolor]{\xdef\globcolorattr{\internalspotcolorname}}
+% \endgroup
+ \ctxlua{figures.push {
+ name="#3",
+ label="#2", % todo: \@eflabel
+ page="\@@efpage",
+ size="\@@efsize",
+ object="\@@efobject",
+ prefix="\@@efprefix",
+ cache="\@@efcache",
+ format="\@@efmethod",
+ preset="\@@efprefix",
+ controls="\@@efcontrols",
+ preview="\@@efpreview",
+ display="\@@efdisplay",
+ conversion="\@@efconversion",
+ color="\internalspotcolorparent\@@efcolor", % hack is needed
+ ["repeat"]="\@@efrepeat",
+ width="\@@efwidth", % can be crap
+ height="\@@efheight", % can be crap
+ } }%
+ \ctxlua{figures.identify()}%
+ \ifconditional\testexternalfigureonly
+ \ifcase\figurestatus \else
+ \ctxlua{figures.check()}%
+ \ctxlua{figures.dummy()}%
+ \ctxlua{figures.scale()}%
+ \ctxlua{figures.done()}%
+ \fi
+ \signalexternalfigure
+ \else
+ \ifcase\figurestatus
+ \ctxlua{figures.dummy()}%
+ \ctxlua{figures.scale()}%
+ \else
+ \ctxlua{figures.check()}%
+ \ctxlua{figures.include()}%
+ \ctxlua{figures.scale()}%
+ \fi
+ \ctxlua{figures.done()}%
+ \signalexternalfigure
+ \finishexternalfigure
+ \fi
+ \ctxlua{figures.pop()}}
+
+\def\relocateexternalfigure % easier here than in lua
+ {\global\setbox\foundexternalfigure\vbox to \ht\foundexternalfigure\bgroup
+ \vss
+ \ht\foundexternalfigure\zeropoint
+ \hbox to \wd\foundexternalfigure\bgroup
+ \box\foundexternalfigure
+ \hss
+ \egroup
+ \egroup}
+
+\def\signalexternalfigure % global
+ {\ifcase\figurestatus
+ \global\resetsystemmode\v!figure % todo, also: \v!resource
+ \else
+ \global\setsystemmode \v!figure % todo, also: \v!resource
+ \fi}
+
+\unexpanded\def\startfoundexternalfigure#1#2% ht wd
+ {\global\setbox\foundexternalfigure\vbox to #2\bgroup\vss\hbox to #1\bgroup}
+
+\unexpanded\def\stopfoundexternalfigure
+ {\hss\egroup\egroup}
+
+\def\emptyfoundexternalfigure
+ {\startfoundexternalfigure\defaultfigurewidth\defaultfigureheight
+ \stopfoundexternalfigure}
+
+\def\finishexternalfigure % here we use \figurevariables
+ {\global\setbox\foundexternalfigure\vbox
+ {\ifcase\figurestatus
+ \let\@@efframe\v!on
+ \fi
+ \ifconditional\externalfigureflush
+ \ifconditional\externalfigurelevel % probably background
+ \ifskipexternalfigures
+ % nothing
+ \fakebox\foundexternalfigure
+ \else\ifcase\figurestatus
+ % nothing
+ \else
+ \the\externalfigurepostprocessors
+ \box\foundexternalfigure
+ \fi\fi
+ \else
+ \iftrialtypesetting \else \feedbackexternalfigure \fi
+ \settrue\externalfigurelevel
+ \ifskipexternalfigures
+ \ifcase\figurestatus
+ \externalfigurereplacement\figurelabel\figurefileoriginal{unknown}%
+ \else
+ \externalfigurereplacement\figurelabel\figurefullname{skipped}%
+ \fi
+ \else\ifcase\figurestatus
+ \externalfigurereplacement\figurelabel\figurefileoriginal{unknown}%
+ \else
+ \the\externalfigurepostprocessors
+ \doifelse\@@efreset\v!yes
+ {\wd\foundexternalfigure\figurewidth
+ \ht\foundexternalfigure\figureheight
+ \dp\foundexternalfigure\zeropoint
+ \box\foundexternalfigure}
+ {\localframed % should also be applied to high res !
+ [\??ef]
+ [\c!offset=\v!overlay,
+ \c!width=\figurewidth,
+ \c!height=\figureheight]
+ {\vfilll\box\foundexternalfigure}}%
+ \fi\fi
+ \fi
+ \else
+ % maybe also \the\externalfigurepostprocessors
+ \iftrialtypesetting \else \feedbackexternalfigure \fi
+ \fi}}
+
+\ifx\externalfigurereplacement\undefined\let\externalfigurereplacement\gobblethreearguments\fi
+\ifx\externalfigureplaceholder\undefined\let\externalfigureplaceholder\gobblethreearguments\fi
+
+\let\feedbackexternalfigure\relax % \gobblefourarguments
+\let\dowithfigure \relax
+
+\def\getfiguredimensions
+ {\dodoubleempty\dogetfiguredimensions}
+
+\def\dogetfiguredimensions[#1][#2]%
+ {\startnointerference
+ \settrue\testexternalfigureonly
+ \externalfigure[#1][#2,\c!display=,\c!object=\v!no]%
+ \stopnointerference}
+
+\let\getfiguredimensionsonly\getfiguredimensions
+
+\def\doiffigureelse#1%
+ {\getfiguredimensions[#1]% so data is available !
+ \ifdim\figurewidth=\zeropoint % todo: \figurestatus
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\def\registerexternalfigure % no placement, handy for preprocessing
+ {\dotripleempty\doregisterexternalfigure}
+
+\def\doregisterexternalfigure[#1][#2][#3]%
+ {\startnointerference
+ \testexternalfigureonly
+ \setfalse\externalfigureflush % == test ?
+ \externalfigure[#1][#2][#3]% or \doexternalfigure
+ \externalfigure[#1][#2,\c!display=,\c!object=\v!no]%
+ \stopnointerference}
+
+% figurebases
+
+\def\usefigurebase[#1]%
+ {\ctxlua{figures.bases.use("#1")}}
+
+\protect \endinput
+
+% \startbuffer
+% \definecolor [blue] [c=1,m=.38,y=0,k=.64]
+% \definecolor [yellow] [c=0,m=.28,y=1,k=.06]
+%
+% \definespotcolor [blue-100] [blue] [p=1]
+% \definespotcolor [yellow-100] [yellow] [p=1]
+%
+% \definemultitonecolor [combicolor] [blue=.12,yellow=.28] [c=.1,m=.1,y=.3,k=.1]
+%
+% \definemultitonecolor [combicolor-b] [blue=1] [c=1,m=.38,y=0,k=.64] % force multitone
+% \definemultitonecolor [combicolor-y] [yellow=1] [c=0,m=.28,y=1,k=.06] % force multitone
+%
+% \useexternalfigure[demo-a][mill.png] [object=no,width=.2\textwidth]
+% \useexternalfigure[demo-b][hacker-bw.jpg][object=no,width=.2\textwidth]
+%
+% \startbaselinecorrection \startcombination[4*1]
+% {\externalfigure[demo-a]} {no color}
+% {\externalfigure[demo-a][color=combicolor]} {indexed duotone}
+% {\externalfigure[demo-a][color=combicolor-b]} {spot color}
+% {\externalfigure[demo-a][color=combicolor-y]} {spot color}
+% \stopcombination \stopbaselinecorrection
+%
+% \startbaselinecorrection \startcombination[4*1]
+% {\externalfigure[demo-b]} {no color}
+% {\externalfigure[demo-b][color=combicolor]} {indexed duotone}
+% {\externalfigure[demo-b][color=combicolor-b]} {spot color}
+% {\externalfigure[demo-b][color=combicolor-y]} {spot color}
+% \stopcombination \stopbaselinecorrection
+%
+% \startbaselinecorrection \startcombination[4*1]
+% {\externalfigure[demo-a]} {no color}
+% {\externalfigure[demo-a][color=combicolor]} {indexed duotone}
+% {\externalfigure[demo-a][color=blue-100]} {spot color}
+% {\externalfigure[demo-a][color=yellow-100]} {spot color}
+% \stopcombination \stopbaselinecorrection
+%
+% \startbaselinecorrection \startcombination[4*1]
+% {\externalfigure[demo-b]} {no color}
+% {\externalfigure[demo-b][color=combicolor]} {indexed duotone}
+% {\externalfigure[demo-b][color=blue-100]} {spot color}
+% {\externalfigure[demo-b][color=yellow-100]} {spot color}
+% \stopcombination \stopbaselinecorrection
+% \stopbuffer
+%
+% \getbuffer \typebuffer
diff --git a/tex/context/base/grph-swf.lua b/tex/context/base/grph-swf.lua
new file mode 100644
index 000000000..e55454b52
--- /dev/null
+++ b/tex/context/base/grph-swf.lua
@@ -0,0 +1,43 @@
+if not modules then modules = { } end modules ['grph-swf'] = {
+ version = 1.001,
+ comment = "companion to grph-inc.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local texsprint = tex.sprint
+local ctxcatcodes = tex.ctxcatcodes
+local pdfannotation = nodes.pdfannotation
+
+function figures.checkers.swf(data)
+ local dr, du, ds = data.request, data.used, data.status
+ local width = (dr.width or figures.defaultwidth):todimen()
+ local height = (dr.height or figures.defaultheight):todimen()
+ local foundname = du.fullname
+ dr.width, dr.height = width, height
+ du.width, du.height, du.foundname = width, height, foundname
+ texsprint(ctxcatcodes,format("\\startfoundexternalfigure{%ssp}{%ssp}",width,height))
+ local annot, preview, ref = backends.pdf.helpers.insertswf {
+ foundname = foundname,
+ width = width,
+ height = height,
+ -- factor = number.dimenfactors.bp,
+ -- display = dr.display,
+ -- controls = dr.controls,
+ -- label = dr.label,
+ }
+ -- node.write(pdfannotation(width,-height,0,annot()))
+ texsprint(ctxcatcodes,format("\\pdfannot width %ssp height %ssp {%s}",width,height,annot())) -- brrrr
+--~ if ref then -- wrong ! a direct ref should work
+--~ texsprint(ctxcatcodes,format("\\smash{\\pdfrefximage%s\\relax}",ref)) -- brrrr
+--~ end
+ texsprint(ctxcatcodes,"\\stopfoundexternalfigure")
+ return data
+end
+
+figures.includers.swf = figures.includers.nongeneric
+
+figures.registersuffix("swf","swf")
diff --git a/tex/context/base/grph-trf.mkii b/tex/context/base/grph-trf.mkii
new file mode 100644
index 000000000..3e32395b4
--- /dev/null
+++ b/tex/context/base/grph-trf.mkii
@@ -0,0 +1,579 @@
+%D \module
+%D [ file=grph-fig,
+%D version=2006.08.26, % overhaul/split of 1997.03.31 core-fig
+%D title=\CONTEXT\ Graphic Macros,
+%D subtitle=Transformations,
+%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.
+
+%D It may be that some functionality got lost. If it concerns
+%D defined features, let me know and it will be sorted out.
+
+\writestatus{loading}{ConTeXt Graphic Macros / Transformations}
+
+\unprotect
+
+%D Scaling:
+
+\unexpanded\def\scale{\dodoubleempty\doscalenextbox[\??xy]}
+
+% probably too many dimens / the width calculations can go
+% since we may assume scaling is available (was not true
+% long ago which is why we also calculate the width)
+
+\newdimen\scaleboxwidth
+\newdimen\scaleboxheight
+\newdimen\scaleboxdepth
+
+\newdimen\scaleboxsizex
+\newdimen\scaleboxsizey
+\newdimen\scaleboxoffsetx
+\newdimen\scaleboxoffsety
+
+\newdimen\scaleboxhsize
+\newdimen\scaleboxvsize
+
+% global
+
+\newdimen\scaleboxdimx \let\figwid \scaleboxdimx
+\newdimen\scaleboxdimy \let\fighei \scaleboxdimy
+\newcount\scaleboxscax \let\figxsca\scaleboxscax
+\newcount\scaleboxscay \let\figysca\scaleboxscay
+
+\newdimen\scaleboxoutervsize % we cannot manipulate any global vsize !
+
+\let\finalscaleboxxscale \!!plusone
+\let\finalscaleboxyscale \!!plusone
+\let\finalscaleboxwidth \!!zeropoint
+\let\finalscaleboxheight \!!zeropoint
+\let\finalscaleboxxfactor\!!hundred
+\let\finalscaleboxyfactor\!!hundred
+
+\newconditional\scaleboxdone
+
+\def\doscalenextbox[#1][#2]%
+ {\bgroup
+ \getparameters
+ [#1]
+ [\c!scale=,\c!xscale=,\c!yscale=,\c!width=,\c!height=,\c!lines=,
+ \c!factor=,\c!hfactor=,\c!wfactor=,\c!grid=,\c!sx=1,\c!sy=1,
+ \c!equalwidth=,\c!equalheight=,
+ \c!maxwidth=\scaleparameter\c!width,\c!maxheight=\scaleparameter\c!height,
+ #2]%
+ \dowithnextbox{\dodoscalenextbox{#1}\egroup}\hbox}
+
+\def\doscalebox#1%
+ {\bgroup\dowithnextbox{\dodoscalenextbox{#1}\egroup}\hbox}
+
+\let\currentscaletag\??xy
+
+\def\scaleparameter#1%
+ {\csname\currentscaletag#1\endcsname}
+
+\def\setscaleparameter#1#2%
+ {\setvalue{\currentscaletag#1}{#2}}
+
+\def\dodoscalenextbox#1%
+ {\edef\currentscaletag{#1}%
+ \doif{\scaleparameter\c!depth}\v!no{\setbox\nextbox\hbox{\raise\nextboxdp\box\nextbox}}% new
+ \forgetall
+ \dontshowcomposition
+ \dontcomplain
+ \doscaleboxcalculations
+ \doscaleboxindeed
+ \doscaleboxposition
+ \flushnextbox}
+
+\def\doscaleboxindeed
+ {\ifconditional\scaleboxdone
+ \scaleboxwidth \finalscaleboxxscale\nextboxwd
+ \scaleboxheight\finalscaleboxyscale\nextboxht
+ \scaleboxdepth \finalscaleboxyscale\nextboxdp
+ \setbox\nextbox\hbox
+ {\dostartscaling \finalscaleboxxscale \finalscaleboxyscale
+ \smashedbox\nextbox
+ \dostopscaling}%
+ \nextboxwd\scaleboxwidth
+ \nextboxht\scaleboxheight
+ \nextboxdp\scaleboxdepth
+ \fi}
+
+\def\doscaleboxcalculations
+ {\setfalse\scaleboxdone
+ % initial final value
+ \global\let\finalscaleboxxscale \!!plusone
+ \global\let\finalscaleboxyscale \!!plusone
+ \xdef \finalscaleboxwidth {\the\nextboxwd}%
+ \xdef \finalscaleboxheight{\the\nextboxht}%
+ \global\let\finalscaleboxxfactor\!!hundred
+ \global\let\finalscaleboxyfactor\!!hundred
+ \ifdim\nextboxht>\zeropoint \ifdim\nextboxwd>\zeropoint
+ \edef\scaleboxstampa % slow way [can be combined]
+ {\scaleparameter\c!scale \scaleparameter\c!xscale \scaleparameter\c!yscale
+ \scaleparameter\c!factor\scaleparameter\c!wfactor\scaleparameter\c!hfactor
+ \scaleparameter\c!lines \scaleparameter\c!width \scaleparameter\c!height}%
+ \edef\scaleboxstampb % fast way [just sx/sy]
+ {\scaleparameter\c!sx
+ \scaleparameter\c!sy}%
+ \edef\scaleboxstampc
+ {11}%
+ \ifx\scaleboxstampa\empty
+ \ifx\scaleboxstampb\scaleboxstampc
+ % no scaling, but still check; new, gone again
+% wrong: scaled proportionally as side effect
+% \doifsomething{\scaleparameter\c!maxwidth }{\letvalue{\currentscaletag\c!factor}\v!fit}%
+% \doifsomething{\scaleparameter\c!maxheight}{\letvalue{\currentscaletag\c!factor}\v!fit}%
+ \insidefloattrue % trick
+ \dodoscaleboxcalculations
+ \else
+ \dosetscalboxsxsy
+ \nodoscaleboxcalculations
+ \fi
+ \else
+ \ifx\scaleboxstampb\empty
+ % no need to check further
+ \else
+ \dosetscalboxsxsy
+ \fi
+ \dodoscaleboxcalculations
+ \fi
+ \fi \fi}
+
+\def\dosetscalboxsxsy
+ {\ifdim\scaleparameter\c!sx\onepoint=\onepoint\else
+ \setevalue{\currentscaletag\c!width }{\the\dimexpr\scaleparameter\c!sx\wd\nextbox\relax}%
+ \fi
+ \ifdim\scaleparameter\c!sy\onepoint=\onepoint\else
+ \setevalue{\currentscaletag\c!height}{\the\dimexpr\scaleparameter\c!sy\ht\nextbox\relax}%
+ \fi}
+
+\def\doscaleboxrounding#1.#2\relax{#1}
+
+\def\scaleboxrounding#1%
+ {\@EA\@EA\@EA\doscaleboxrounding\@EA\WITHOUTPT\the\dimexpr#1\points*100+32768sp\relax.\relax}
+
+\def\nodoscaleboxcalculations
+ {\settrue\scaleboxdone
+ \xdef\finalscaleboxwidth {\the\dimexpr\scaleparameter\c!sx\wd\nextbox\relax}%
+ \xdef\finalscaleboxheight {\the\dimexpr\scaleparameter\c!sy\ht\nextbox\relax}%
+ \xdef\finalscaleboxxscale {\scaleparameter\c!sx}%
+ \xdef\finalscaleboxyscale {\scaleparameter\c!sy}%
+ \ifx\finalscaleboxxscale\empty\let\finalscaleboxxscale\!!plusone\fi
+ \ifx\finalscaleboxyscale\empty\let\finalscaleboxyscale\!!plusone\fi
+ \xdef\finalscaleboxxfactor{\scaleboxrounding\finalscaleboxxscale}%
+ \xdef\finalscaleboxyfactor{\scaleboxrounding\finalscaleboxyscale}}
+
+\def\dodoscaleboxcalculations
+ {\settrue\scaleboxdone
+ % initial values
+ \scaleboxoffsetx\zeropoint
+ \scaleboxoffsety\zeropoint
+ \scaleboxsizex \nextboxwd
+ \scaleboxsizey \nextboxht % alleen ht wordt geschaald!
+ % final values
+ \global\scaleboxdimx \zeropoint % see note * (core-fig)
+ \global\scaleboxdimy \zeropoint % see note * (core-fig)
+ \scaleboxscax \plusone % see note * (core-fig)
+ \scaleboxscay \plusone % see note * (core-fig)
+ % preparations
+ \setfalse\scaleboxscalingdone
+ \checkscaleboxsettings
+ % calculators
+ % beware, they operate in sequence, and calculate missing dimensions / messy
+ %setscaleboxbynature % when? needed?
+ \ifconditional\scaleboxscalingdone\else\setscaleboxbyfactor \fi
+ \ifconditional\scaleboxscalingdone\else\setscaleboxbyscale \fi
+ \ifconditional\scaleboxscalingdone\else\setscaleboxbydimension\fi
+ % finalizers / to be done (no longer needed this way, clean up)
+ \convertscaleboxinsertscale\scaleboxhsize\figx\scaleboxscax\scax
+ \convertscaleboxinsertscale\scaleboxvsize\figy\scaleboxscay\scay
+ % used in actual scaling
+ \xdef\finalscaleboxwidth {\the\scaleboxdimx}%
+ \xdef\finalscaleboxheight {\the\scaleboxdimy}%
+ \xdef\finalscaleboxxfactor{\the\scaleboxscax}%
+ \xdef\finalscaleboxyfactor{\the\scaleboxscay}%
+ \xdef\finalscaleboxxscale {\withoutpt\the\dimexpr\scax\points/\plushundred\relax}%
+ \xdef\finalscaleboxyscale {\withoutpt\the\dimexpr\scay\points/\plushundred\relax}}
+
+
+\setvalue{\??xy:\c!grid:\v!yes }{\getnoflines \fighei\setevalue{\currentscaletag\c!height}{\the\noflines\lineheight}}
+\setvalue{\??xy:\c!grid:\v!height }{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight+\strutdepth\relax}}
+\setvalue{\??xy:\c!grid:\v!depth }{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight-\strutdepth\relax}}
+\setvalue{\??xy:\c!grid:\v!halfline}{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight+.5\lineheight\relax}}
+\setvalue{\??xy:\c!grid:\v!fit }{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\noflines\lineheight}}
+\letvalue{\??xy:\c!grid:\empty }\donothing
+
+\def\checkscaleboxsettings
+ {\doifsomething{\scaleparameter\c!maxwidth }% can be defined in itself
+ {\setevalue{\currentscaletag\c!maxwidth }{\the\dimexpr\scaleparameter\c!maxwidth \relax}}%
+ \doifsomething{\scaleparameter\c!maxheight}% can be defined in itself
+ {\setevalue{\currentscaletag\c!maxheight}{\the\dimexpr\scaleparameter\c!maxheight\relax}}%
+ \doifsomething{\scaleparameter\c!lines}
+ {\setevalue{\currentscaletag\c!height}{\the\dimexpr\scaleparameter\c!lines\lineheight\relax}}%
+ \getvalue{\??xy:\c!grid:\scaleparameter\c!grid}}
+
+\def\setscaleboxbynature % where ! ! ! ! !
+ {\doifsomething{\scaleparameter\c!width }{\global\scaleboxdimx\scaleparameter\c!width }%
+ \doifsomething{\scaleparameter\c!height}{\global\scaleboxdimy\scaleparameter\c!height}%
+ \doifsomething{\scaleparameter\c!scale } {\scaleboxscax\scaleparameter\c!scale
+ \scaleboxscay\scaleparameter\c!scale }%
+ \doifsomething{\scaleparameter\c!xscale} {\scaleboxscax\scaleparameter\c!xscale}%
+ \doifsomething{\scaleparameter\c!yscale} {\scaleboxscay\scaleparameter\c!yscale}} % oeps, was x
+
+% \defineexternalfigure[width-6][factor=auto,maxwidth=\textheight,maxheight=\textwidth]
+% \defineexternalfigure[width-7][factor=auto,maxwidth=\textwidth,maxheight=\textheight]
+% \placefigure{none}{\rotate[frame=on,offset=overlay]{\externalfigure[t:/sources/cow.pdf][width-6]}} \page
+% \placefigure{none}{\framed[frame=on,offset=overlay]{\externalfigure[t:/sources/cow.pdf][width-7]}}
+
+\def\setscaleboxbyfactor
+ {\doifinsetelse{\scaleparameter\c!factor}{\v!max,\v!fit,\v!broad,\v!auto}
+ {\doapplyscaleboxsize
+ \ifdim\scaleboxsizex>\scaleboxsizey
+ \docalculatescaleboxnorm \scaleboxdimx\c!factor\c!maxwidth\hsize\scaleboxhsize
+ \docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey
+ \else
+ \docalculatescaleboxnorm \scaleboxdimy\c!factor\c!maxheight\scaleboxoutervsize\scaleboxvsize
+ \docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex
+ \fi
+ \donetrue}
+ {\doifinsetelse{\scaleparameter\c!hfactor}{\v!max,\v!fit,\v!broad,\v!auto}
+ {\doapplyscaleboxsize
+ \docalculatescaleboxnorm \scaleboxdimy\c!hfactor\c!maxheight\scaleboxoutervsize\scaleboxvsize
+ \docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex
+ \donetrue}
+ {\doifinsetelse{\scaleparameter\c!wfactor}{\v!max,\v!fit,\v!broad,\v!auto}
+ {\doapplyscaleboxsize
+ \docalculatescaleboxnorm \scaleboxdimx\c!wfactor\c!maxwidth\hsize\scaleboxhsize
+ \docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey
+ \donetrue}
+ {\docalculatescaleboxnorm\scaleboxdimy\c!factor \c!height \textheight\scaleboxvsize
+ \docalculatescaleboxnorm\scaleboxdimy\c!hfactor\c!height \textheight\scaleboxvsize
+ \docalculatescaleboxnorm\scaleboxdimx\c!wfactor\c!width \hsize \hsize
+ \donefalse}}}%
+ \ifdone
+ \settrue\scaleboxscalingdone
+ \ifdim\scaleboxdimx>\scaleboxhsize
+ \global\scaleboxdimy\zeropoint \global\scaleboxdimx\scaleboxhsize
+ \else\ifdim\scaleboxdimy>\scaleboxvsize
+ \global\scaleboxdimx\zeropoint \global\scaleboxdimy\scaleboxvsize
+ \fi\fi
+ \setscaleboxbydimension
+ \fi}
+
+\def\setscaleboxbyscale
+ {\doifsomething{\scaleparameter\c!scale\scaleparameter\c!xscale\scaleparameter\c!yscale}
+ {\doapplyscaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax\c!xscale
+ \doapplyscaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay\c!yscale
+ \global\scaleboxdimx\zeropoint
+ \global\scaleboxdimy\zeropoint
+ \doifelsenothing{\scaleparameter\c!maxwidth}
+ {\doifsomething{\scaleparameter\c!maxheight}
+ {\ifdim\scaleboxsizey>\scaleparameter\c!maxheight\relax
+ \global\scaleboxdimy\scaleparameter\c!maxheight
+ \fi}}
+ {\ifdim\scaleboxsizex>\scaleparameter\c!maxwidth\relax
+ \global\scaleboxdimx\scaleparameter\c!maxwidth
+ \fi}}}
+
+\def\setscaleboxbydimension
+ {\ifdim\scaleboxdimx>\zeropoint
+ \ifdim\scaleboxdimy>\zeropoint
+ \dosetdimensionscaleboxsize
+ {\docalculatescaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay
+ \docalculatescaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax}%
+ {\docalculatescaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay
+ \docalculatescaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax}%
+ {\docalculatescaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay
+ \docalculatescaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax}%
+ \else
+ \dosetdimensionscaleboxsize
+ {\docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey}%
+ {\docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey}%
+ {\docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey}%
+ \fi
+ \else
+ \ifdim\scaleboxdimy>\zeropoint
+ \dosetdimensionscaleboxsize
+ {\docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex}%
+ {\docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex}%
+ {\docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex}%
+ \else
+ \dosetdimensionscaleboxsize
+ {\doapplyscaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax\c!xscale
+ \doapplyscaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay\c!yscale}%
+ {\docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey}%
+ {\docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex}%
+ \fi
+ \fi}
+
+\def\dosetdimensionscaleboxsize#1#2#3%
+ {#1\relax
+ \doifsomething{\scaleparameter\c!maxwidth}
+ {\ifdim\scaleboxdimx>\scaleparameter\c!maxwidth\relax
+ \global\scaleboxdimx\scaleparameter\c!maxwidth
+ #2\relax
+ \fi}%
+ \doifsomething{\scaleparameter\c!maxheight}
+ {\ifdim\scaleboxdimy>\scaleparameter\c!maxheight\relax
+ \global\scaleboxdimy\scaleparameter\c!maxheight
+ #3\relax
+ \fi}}
+
+\def\docalculatescaleboxnorm#1#2#3#4#5% 2 3 parameters (dodo:speedup)
+ {\processaction
+ [\scaleparameter#2]
+ [ \v!max=>\global#1\dimexpr#4\relax,
+ \v!fit=>\global#1\dimexpr#5\relax,
+ \v!broad=>\global#1\dimexpr#5-4\@@exbodyfont\relax,
+ \v!auto=>\doifsomething{\scaleparameter#3}{\global#1\dimexpr\scaleparameter#3\relax},
+ \s!default=>\doifsomething{\scaleparameter#3}{\global#1\dimexpr\scaleparameter#3\relax},
+ \s!unknown=>\global#1\dimexpr\scaleparameter#2\dimexpr\@@exbodyfont/10\relax\relax]}
+
+\def\docalculatescaleboxscales#1#2#3#4%
+ {\scratchdimen\dimexpr#1/\dimexpr#2/\plusthousand\relax\relax
+ \scaleboxscax\scratchdimen
+ \scaleboxscay\scratchdimen
+ #3\dimexpr\scaleboxscax\dimexpr#4/\plusthousand\relax\relax}
+
+\def\docalculatescaleboxscale#1#2#3%
+ {#3\dimexpr#1/\dimexpr#2/\plusthousand\relax\relax}
+
+\def\doapplyscaleboxscale#1#2#3#4% $4 = parameter / scale can be empty
+ {\ifcase0\scaleparameter#4\relax
+ \ifcase0\scaleparameter\c!scale\relax
+ #3=\plusthousand
+ \else
+ #3=\scaleparameter\c!scale
+ \fi
+ \else
+ #3=\scaleparameter#4%
+ \fi
+ \relax % important ! still ?
+ \global#1\ifnum#3=\plusthousand#2\else\dimexpr#3\dimexpr#2/\plusthousand\relax\relax\fi
+ \relax}
+
+\def\doapplyscaleboxsize
+ {\doifelsenothing{\scaleparameter\c!maxheight}
+ {\scaleboxoutervsize\textheight
+ \ifinner
+ \scaleboxoutervsize \vsize % \textheight =\vsize
+ \scratchdimen\vsize % \scratchdimen=\textheight
+ \else\ifinsidefloat
+ \scaleboxoutervsize \vsize % \textheight =\vsize
+ \scratchdimen\vsize % \scratchdimen=\textheight
+ \else\ifinpagebody
+ \scaleboxoutervsize \vsize % \textheight =\vsize
+ \scratchdimen\vsize % \scratchdimen=\textheight
+ \else % hm, there should be an option to force this
+ \ifdim\pagegoal<\maxdimen
+ \ifdim\pagetotal<\pagegoal
+ \scratchdimen\pagegoal
+ \advance\scratchdimen -\pagetotal
+ \else
+ \scratchdimen\scaleboxoutervsize % \textheight
+ \fi
+ \else
+ \scratchdimen\scaleboxoutervsize % \textheight
+ \fi
+ \fi\fi\fi}
+ {\scratchdimen\scaleparameter\c!maxheight
+ \scaleboxoutervsize\scratchdimen}%
+ \doifelsenothing{\scaleparameter\c!height}
+ {\scaleboxvsize\scratchdimen}
+ {\scaleboxvsize\scaleparameter\c!height}%
+ \doifelsenothing{\scaleparameter\c!width}
+ {\scaleboxhsize\hsize}
+ {\scaleboxhsize\scaleparameter\c!width}}
+
+\def\convertscaleboxinsertscale#1#2#3#4%
+ {\scratchdimen#1\relax
+ \ifnum#3=\plusthousand
+ % == scale 1
+ \else
+ % better 1000 100 10 ranges, evt round 2sp
+ \divide\scratchdimen \plusthousand
+ \multiply\scratchdimen #3\relax
+ \fi
+ \scratchdimen-\scratchdimen % beter hier - dan in driver
+ \edef#2{\the\scratchdimen}%
+ \scratchcounter#3\relax
+ \ifnum\scratchcounter>\plustenthousand
+ \divide\scratchcounter\!!ten \scratchdimen\the\scratchcounter\points
+ \else
+ \scratchdimen\the\scratchcounter\points \divide\scratchdimen\!!ten
+ \fi
+ \edef#4{\withoutpt\the\scratchdimen}}
+
+% \startcombination
+% {\externalfigure[cow.pdf] [frame=on,height=3cm,equalwidth=6cm]} {}
+% {\externalfigure[mill.png][frame=on,height=3cm,equalwidth=6cm]} {}
+% \stopcombination
+
+\def\doscaleboxposition
+ {\doifsomething{\scaleparameter\c!equalwidth}
+ {\scratchdimen\scaleparameter\c!equalwidth\relax
+ \ifdim\wd\nextbox<\scratchdimen
+ \setbox\nextbox\hbox to \scratchdimen{\hss\box\nextbox\hss}%
+ \fi}%
+ \doifsomething{\scaleparameter\c!equalheight}
+ {\scratchdimen\scaleparameter\c!equalheight\relax
+ \ifdim\ht\nextbox<\scratchdimen
+ \setbox\nextbox\vbox to \scratchdimen{\vss\box\nextbox\vss}%
+ \fi}}
+
+%D \macros
+%D {clip, setupclipping}
+%D
+%D Although related to figures, clipping can be applied to
+%D arbitrary content. We can use \METAPOST\ to provide a non
+%D rectangular clipping path.
+%D
+%D \starttyping
+%D \startMPclip{fun}
+%D clip currentpicture to fullcircle
+%D shifted (.5,.5) xscaled \width yscaled \height ;
+%D \stopMPclip
+%D \stoptyping
+%D
+%D We get a rectangular piece of the figure when we say:
+%D
+%D \starttyping
+%D \clip[x=2,y=1]{\externalfigure[photo]}
+%D \stoptyping
+%D
+%D When we want to clip to the oval we defined a few lines ago,
+%D we say:
+%D
+%D \starttyping
+%D \clip[nx=1,ny=1,x=1,y=1,mp=fun]{\externalfigure[photo]}
+%D \stoptyping
+%D
+%D The general characteristics of clipping can be set up with
+%D
+%D \showsetup{setupclipping}
+
+\def\setupclipping
+ {\dodoubleargument\getparameters[\??cp]}
+
+\def\clip
+ {\dosingleempty\doclip}
+
+\def\doclip[#1]% nb top->bottom left->right
+ {\bgroup
+ \getparameters[\??cp][#1]%
+ \doifelse\@@cpstate\v!start\dodoclip{\egroup\hbox}}
+
+\def\dodoclip
+ {\dowithnextbox
+ {\ifdim\@@cpwidth>\zeropoint
+ \!!dimena\@@cpwidth
+ \!!dimenc\@@cphoffset
+ \else
+ \!!dimena\nextboxwd
+ \divide\!!dimena \@@cpnx
+ \!!dimenc\@@cpx\!!dimena
+ \advance\!!dimenc -\!!dimena
+ \!!dimena\@@cpsx\!!dimena
+ \fi
+ \relax % sure
+ \ifdim\@@cpheight>\zeropoint
+ \!!dimenb\@@cpheight
+ \!!dimend\nextboxht
+ \advance\!!dimend -\@@cpvoffset
+ \advance\!!dimend -\!!dimenb
+ \else
+ \!!dimenb\nextboxht
+ \divide\!!dimenb \@@cpny
+ \!!dimend-\@@cpy\!!dimenb
+ \advance\!!dimend -\@@cpsy\!!dimenb
+ \advance\!!dimend \!!dimenb
+ \!!dimenb\@@cpsy\!!dimenb
+ \advance\!!dimend \nextboxht % dimend !
+ \fi
+ \setbox\nextbox\hbox % old
+ {\advance\!!dimenc -\@@cpleftoffset % new !
+ \advance\!!dimend -\@@cpbottomoffset % new ! % - added
+ \hskip-\!!dimenc\lower\!!dimend\flushnextbox}% old
+ \nextboxwd\zeropoint
+ \nextboxht\zeropoint
+ \nextboxdp\zeropoint
+ \setbox\nextbox\hbox
+ {\advance\!!dimena \@@cpleftoffset % new !
+ \advance\!!dimena \@@cprightoffset % new !
+ \advance\!!dimenb \@@cpbottomoffset % new !
+ \advance\!!dimenb \@@cptopoffset % new !
+ \dostartclipping\@@cpmp\!!dimena\!!dimenb % old
+ \flushnextbox
+ \dostopclipping}%
+ \setbox\nextbox\hbox % new !
+ {\!!dimena-\@@cpleftoffset % new !
+ \!!dimenb \@@cpbottomoffset % new ! % - removed
+ \hskip\!!dimena\lower\!!dimenb\flushnextbox}% new !
+ \nextboxwd\!!dimena
+ \nextboxht\!!dimenb
+ \nextboxdp\zeropoint
+ \flushnextbox
+ \egroup}%
+ \hbox}
+
+\setupclipping
+ [\c!state=\v!start,
+ \c!n=1, % was 2
+ \c!nx=\@@cpn,\c!x=1,\c!sx=1,
+ \c!ny=\@@cpn,\c!y=1,\c!sy=1,
+ \c!width=\!!zeropoint,
+ \c!height=\!!zeropoint,
+ \c!hoffset=\!!zeropoint,
+ \c!voffset=\!!zeropoint,
+ \c!offset=\zeropoint,
+ \c!leftoffset=\@@cpoffset, % \zeropoint,
+ \c!rightoffset=\@@cpoffset, % \zeropoint,
+ \c!topoffset=\@@cpoffset, % \zeropoint,
+ \c!bottomoffset=\@@cpoffset,% \zeropoint,
+ \c!mp=]
+
+%D \startbuffer
+%D \startuseMPgraphic{test}
+%D path p ; p := fullcircle scaled 4cm ;
+%D draw p withpen pencircle scaled 1cm ;
+%D setbounds currentpicture to boundingbox p ;
+%D \stopuseMPgraphic
+%D
+%D \hbox to \hsize \bgroup
+%D \hss
+%D \ruledhbox{\useMPgraphic{test}}%
+%D \hss
+%D \ruledhbox{\clip{\useMPgraphic{test}}}%
+%D \hss
+%D \egroup
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D Mirroring.
+
+\def\domirrorbox % \hbox/\vbox/\vtop
+ {\bgroup
+ \dowithnextbox
+ {\dontshowcomposition
+ \scratchdimen\nextboxwd
+ % better use an hbox (if no \forgetall, leftskip etc may creep in)
+ %\setbox\nextbox\vbox{\forgetall\dostartmirroring\hskip-\nextboxwd\flushnextbox\dostopmirroring}%
+ \setbox\nextbox\hbox{\dostartmirroring\hskip-\nextboxwd\flushnextbox\dostopmirroring}%
+ \nextboxwd\scratchdimen
+ \flushnextbox
+ \egroup}}
+
+\unexpanded\def\mirror
+ {\domirrorbox\hbox}
+
+% \setbox0=\hbox{gans}
+% \ruledhbox{\copy0 \schaal[sx=2,sy=2]{\copy0}}
+% \mirror{\ruledhbox{\copy0 \schaal{\box0}}}
+
+\protect \endinput
diff --git a/tex/context/base/grph-trf.mkiv b/tex/context/base/grph-trf.mkiv
new file mode 100644
index 000000000..9924a68e8
--- /dev/null
+++ b/tex/context/base/grph-trf.mkiv
@@ -0,0 +1,580 @@
+%D \module
+%D [ file=grph-fig,
+%D version=2006.08.26, % overhaul/split of 1997.03.31 core-fig
+%D title=\CONTEXT\ Graphic Macros,
+%D subtitle=Transformations,
+%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.
+
+%D It may be that some functionality got lost. If it concerns
+%D defined features, let me know and it will be sorted out.
+
+%D We will move the calculations to lua.
+
+\writestatus{loading}{ConTeXt Graphic Macros / Transformations}
+
+\unprotect
+
+%D Scaling:
+
+\unexpanded\def\scale{\dodoubleempty\doscalenextbox[\??xy]}
+
+% probably too many dimens / the width calculations can go
+% since we may assume scaling is available (was not true
+% long ago which is why we also calculate the width)
+
+\newdimen\scaleboxwidth
+\newdimen\scaleboxheight
+\newdimen\scaleboxdepth
+
+\newdimen\scaleboxsizex
+\newdimen\scaleboxsizey
+\newdimen\scaleboxoffsetx
+\newdimen\scaleboxoffsety
+
+\newdimen\scaleboxhsize
+\newdimen\scaleboxvsize
+
+% global
+
+\newdimen\scaleboxdimx \let\figwid \scaleboxdimx
+\newdimen\scaleboxdimy \let\fighei \scaleboxdimy
+\newcount\scaleboxscax \let\figxsca\scaleboxscax
+\newcount\scaleboxscay \let\figysca\scaleboxscay
+
+\newdimen\scaleboxoutervsize % we cannot manipulate any global vsize !
+
+\let\finalscaleboxxscale \!!plusone
+\let\finalscaleboxyscale \!!plusone
+\let\finalscaleboxwidth \!!zeropoint
+\let\finalscaleboxheight \!!zeropoint
+\let\finalscaleboxxfactor\!!hundred
+\let\finalscaleboxyfactor\!!hundred
+
+\newconditional\scaleboxdone
+
+\def\doscalenextbox[#1][#2]%
+ {\bgroup
+ \getparameters
+ [#1]
+ [\c!scale=,\c!xscale=,\c!yscale=,\c!width=,\c!height=,\c!lines=,
+ \c!factor=,\c!hfactor=,\c!wfactor=,\c!grid=,\c!sx=1,\c!sy=1,
+ \c!equalwidth=,\c!equalheight=,
+ \c!maxwidth=\scaleparameter\c!width,\c!maxheight=\scaleparameter\c!height,
+ #2]%
+ \dowithnextbox{\dodoscalenextbox{#1}\egroup}\hbox}
+
+\def\doscalebox#1%
+ {\bgroup\dowithnextbox{\dodoscalenextbox{#1}\egroup}\hbox}
+
+\let\currentscaletag\??xy
+
+\def\scaleparameter#1%
+ {\csname\currentscaletag#1\endcsname}
+
+\def\setscaleparameter#1#2%
+ {\setvalue{\currentscaletag#1}{#2}}
+
+\def\dodoscalenextbox#1%
+ {\edef\currentscaletag{#1}%
+ \doif{\scaleparameter\c!depth}\v!no{\setbox\nextbox\hbox{\raise\nextboxdp\box\nextbox}}% new
+ \forgetall
+ \dontshowcomposition
+ \dontcomplain
+ \doscaleboxcalculations
+ \doscaleboxindeed
+ \doscaleboxposition
+ \flushnextbox}
+
+\def\doscaleboxindeed
+ {\ifconditional\scaleboxdone
+ \scaleboxwidth \finalscaleboxxscale\nextboxwd
+ \scaleboxheight\finalscaleboxyscale\nextboxht
+ \scaleboxdepth \finalscaleboxyscale\nextboxdp
+ \setbox\nextbox\hbox
+ {\dostartscaling \finalscaleboxxscale \finalscaleboxyscale
+ \smashedbox\nextbox
+ \dostopscaling}%
+ \nextboxwd\scaleboxwidth
+ \nextboxht\scaleboxheight
+ \nextboxdp\scaleboxdepth
+ \fi}
+
+\def\doscaleboxcalculations
+ {\setfalse\scaleboxdone
+ % initial final value
+ \global\let\finalscaleboxxscale \!!plusone
+ \global\let\finalscaleboxyscale \!!plusone
+ \xdef \finalscaleboxwidth {\the\nextboxwd}%
+ \xdef \finalscaleboxheight{\the\nextboxht}%
+ \global\let\finalscaleboxxfactor\!!hundred
+ \global\let\finalscaleboxyfactor\!!hundred
+ \ifdim\nextboxht>\zeropoint \ifdim\nextboxwd>\zeropoint
+ % hm, still useful? better in lua anyway
+ \edef\scaleboxstampa % slow way [can be combined]
+ {\scaleparameter\c!scale \scaleparameter\c!xscale \scaleparameter\c!yscale
+ \scaleparameter\c!factor\scaleparameter\c!wfactor\scaleparameter\c!hfactor
+ \scaleparameter\c!lines \scaleparameter\c!width \scaleparameter\c!height}%
+ \edef\scaleboxstampb % fast way [just sx/sy]
+ {\scaleparameter\c!sx
+ \scaleparameter\c!sy}%
+ \edef\scaleboxstampc
+ {11}%
+ \ifx\scaleboxstampa\empty
+ \ifx\scaleboxstampb\scaleboxstampc
+ % no scaling, but still check; new, gone again
+% wrong: scaled proportionally as side effect
+% \doifsomething{\scaleparameter\c!maxwidth }{\letvalue{\currentscaletag\c!factor}\v!fit}%
+% \doifsomething{\scaleparameter\c!maxheight}{\letvalue{\currentscaletag\c!factor}\v!fit}%
+ \insidefloattrue % trick
+ \dodoscaleboxcalculations
+ \else
+ \dosetscalboxsxsy
+ \nodoscaleboxcalculations
+ \fi
+ \else
+ \ifx\scaleboxstampb\empty
+ % no need to check further
+ \else
+ \dosetscalboxsxsy
+ \fi
+ \dodoscaleboxcalculations
+ \fi
+ \fi \fi}
+
+\def\dosetscalboxsxsy
+ {\ifdim\scaleparameter\c!sx\onepoint=\onepoint\else
+ \setevalue{\currentscaletag\c!width }{\the\dimexpr\scaleparameter\c!sx\wd\nextbox\relax}%
+ \fi
+ \ifdim\scaleparameter\c!sy\onepoint=\onepoint\else
+ \setevalue{\currentscaletag\c!height}{\the\dimexpr\scaleparameter\c!sy\ht\nextbox\relax}%
+ \fi}
+
+\def\doscaleboxrounding#1.#2\relax{#1}
+
+\def\scaleboxrounding#1%
+ {\@EA\@EA\@EA\doscaleboxrounding\@EA\WITHOUTPT\the\dimexpr#1\points*100+32768sp\relax.\relax}
+
+\def\nodoscaleboxcalculations
+ {\settrue\scaleboxdone
+ \xdef\finalscaleboxwidth {\the\dimexpr\scaleparameter\c!sx\wd\nextbox\relax}%
+ \xdef\finalscaleboxheight {\the\dimexpr\scaleparameter\c!sy\ht\nextbox\relax}%
+ \xdef\finalscaleboxxscale {\scaleparameter\c!sx}%
+ \xdef\finalscaleboxyscale {\scaleparameter\c!sy}%
+ \ifx\finalscaleboxxscale\empty\let\finalscaleboxxscale\!!plusone\fi
+ \ifx\finalscaleboxyscale\empty\let\finalscaleboxyscale\!!plusone\fi
+ \xdef\finalscaleboxxfactor{\scaleboxrounding\finalscaleboxxscale}%
+ \xdef\finalscaleboxyfactor{\scaleboxrounding\finalscaleboxyscale}}
+
+\def\dodoscaleboxcalculations
+ {\settrue\scaleboxdone
+ % initial values
+ \scaleboxoffsetx\zeropoint
+ \scaleboxoffsety\zeropoint
+ \scaleboxsizex \nextboxwd
+ \scaleboxsizey \nextboxht % alleen ht wordt geschaald!
+ % final values
+ \global\scaleboxdimx \zeropoint % see note * (core-fig)
+ \global\scaleboxdimy \zeropoint % see note * (core-fig)
+ \scaleboxscax \plusone % see note * (core-fig)
+ \scaleboxscay \plusone % see note * (core-fig)
+ % preparations
+ \setfalse\scaleboxscalingdone
+ \checkscaleboxsettings
+ % calculators
+ % beware, they operate in sequence, and calculate missing dimensions / messy
+ %setscaleboxbynature % when? needed?
+ \ifconditional\scaleboxscalingdone\else\setscaleboxbyfactor \fi
+ \ifconditional\scaleboxscalingdone\else\setscaleboxbyscale \fi
+ \ifconditional\scaleboxscalingdone\else\setscaleboxbydimension\fi
+ % finalizers / to be done (no longer needed this way, clean up)
+ \convertscaleboxinsertscale\scaleboxhsize\figx\scaleboxscax\scax
+ \convertscaleboxinsertscale\scaleboxvsize\figy\scaleboxscay\scay
+ % used in actual scaling
+ \xdef\finalscaleboxwidth {\the\scaleboxdimx}%
+ \xdef\finalscaleboxheight {\the\scaleboxdimy}%
+ \xdef\finalscaleboxxfactor{\the\scaleboxscax}%
+ \xdef\finalscaleboxyfactor{\the\scaleboxscay}%
+ \xdef\finalscaleboxxscale {\withoutpt\the\dimexpr\scax\points/\plushundred\relax}%
+ \xdef\finalscaleboxyscale {\withoutpt\the\dimexpr\scay\points/\plushundred\relax}}
+
+\setvalue{\??xy:\c!grid:\v!yes }{\getnoflines \fighei\setevalue{\currentscaletag\c!height}{\the\noflines\lineheight}}
+\setvalue{\??xy:\c!grid:\v!height }{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight+\strutdepth\relax}}
+\setvalue{\??xy:\c!grid:\v!depth }{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight-\strutdepth\relax}}
+\setvalue{\??xy:\c!grid:\v!halfline}{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight+.5\lineheight\relax}}
+\setvalue{\??xy:\c!grid:\v!fit }{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\noflines\lineheight}}
+\letvalue{\??xy:\c!grid:\empty }\donothing
+
+\def\checkscaleboxsettings
+ {\doifsomething{\scaleparameter\c!maxwidth }% can be defined in itself
+ {\setevalue{\currentscaletag\c!maxwidth }{\the\dimexpr\scaleparameter\c!maxwidth \relax}}%
+ \doifsomething{\scaleparameter\c!maxheight}% can be defined in itself
+ {\setevalue{\currentscaletag\c!maxheight}{\the\dimexpr\scaleparameter\c!maxheight\relax}}%
+ \doifsomething{\scaleparameter\c!lines}
+ {\setevalue{\currentscaletag\c!height}{\the\dimexpr\scaleparameter\c!lines\lineheight\relax}}%
+ \getvalue{\??xy:\c!grid:\scaleparameter\c!grid}}
+
+\def\setscaleboxbynature % where ! ! ! ! !
+ {\doifsomething{\scaleparameter\c!width }{\global\scaleboxdimx\scaleparameter\c!width }%
+ \doifsomething{\scaleparameter\c!height}{\global\scaleboxdimy\scaleparameter\c!height}%
+ \doifsomething{\scaleparameter\c!scale } {\scaleboxscax\scaleparameter\c!scale
+ \scaleboxscay\scaleparameter\c!scale }%
+ \doifsomething{\scaleparameter\c!xscale} {\scaleboxscax\scaleparameter\c!xscale}%
+ \doifsomething{\scaleparameter\c!yscale} {\scaleboxscay\scaleparameter\c!yscale}} % oeps, was x
+
+% \defineexternalfigure[width-6][factor=auto,maxwidth=\textheight,maxheight=\textwidth]
+% \defineexternalfigure[width-7][factor=auto,maxwidth=\textwidth,maxheight=\textheight]
+% \placefigure{none}{\rotate[frame=on,offset=overlay]{\externalfigure[t:/sources/cow.pdf][width-6]}} \page
+% \placefigure{none}{\framed[frame=on,offset=overlay]{\externalfigure[t:/sources/cow.pdf][width-7]}}
+
+\def\setscaleboxbyfactor
+ {\doifinsetelse{\scaleparameter\c!factor}{\v!max,\v!fit,\v!broad,\v!auto}
+ {\doapplyscaleboxsize
+ \ifdim\scaleboxsizex>\scaleboxsizey
+ \docalculatescaleboxnorm \scaleboxdimx\c!factor\c!maxwidth\hsize\scaleboxhsize
+ \docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey
+ \else
+ \docalculatescaleboxnorm \scaleboxdimy\c!factor\c!maxheight\scaleboxoutervsize\scaleboxvsize
+ \docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex
+ \fi
+ \donetrue}
+ {\doifinsetelse{\scaleparameter\c!hfactor}{\v!max,\v!fit,\v!broad,\v!auto}
+ {\doapplyscaleboxsize
+ \docalculatescaleboxnorm \scaleboxdimy\c!hfactor\c!maxheight\scaleboxoutervsize\scaleboxvsize
+ \docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex
+ \donetrue}
+ {\doifinsetelse{\scaleparameter\c!wfactor}{\v!max,\v!fit,\v!broad,\v!auto}
+ {\doapplyscaleboxsize
+ \docalculatescaleboxnorm \scaleboxdimx\c!wfactor\c!maxwidth\hsize\scaleboxhsize
+ \docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey
+ \donetrue}
+ {\docalculatescaleboxnorm\scaleboxdimy\c!factor \c!height \textheight\scaleboxvsize
+ \docalculatescaleboxnorm\scaleboxdimy\c!hfactor\c!height \textheight\scaleboxvsize
+ \docalculatescaleboxnorm\scaleboxdimx\c!wfactor\c!width \hsize \hsize
+ \donefalse}}}%
+ \ifdone
+ \settrue\scaleboxscalingdone
+ \ifdim\scaleboxdimx>\scaleboxhsize
+ \global\scaleboxdimy\zeropoint \global\scaleboxdimx\scaleboxhsize
+ \else\ifdim\scaleboxdimy>\scaleboxvsize
+ \global\scaleboxdimx\zeropoint \global\scaleboxdimy\scaleboxvsize
+ \fi\fi
+ \setscaleboxbydimension
+ \fi}
+
+\def\setscaleboxbyscale
+ {\doifsomething{\scaleparameter\c!scale\scaleparameter\c!xscale\scaleparameter\c!yscale}
+ {\doapplyscaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax\c!xscale
+ \doapplyscaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay\c!yscale
+ \global\scaleboxdimx\zeropoint
+ \global\scaleboxdimy\zeropoint
+ \doifelsenothing{\scaleparameter\c!maxwidth}
+ {\doifsomething{\scaleparameter\c!maxheight}
+ {\ifdim\scaleboxsizey>\scaleparameter\c!maxheight\relax
+ \global\scaleboxdimy\scaleparameter\c!maxheight
+ \fi}}
+ {\ifdim\scaleboxsizex>\scaleparameter\c!maxwidth\relax
+ \global\scaleboxdimx\scaleparameter\c!maxwidth
+ \fi}}}
+
+\def\setscaleboxbydimension
+ {\ifdim\scaleboxdimx>\zeropoint
+ \ifdim\scaleboxdimy>\zeropoint
+ \dosetdimensionscaleboxsize
+ {\docalculatescaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay
+ \docalculatescaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax}%
+ {\docalculatescaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay
+ \docalculatescaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax}%
+ {\docalculatescaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay
+ \docalculatescaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax}%
+ \else
+ \dosetdimensionscaleboxsize
+ {\docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey}%
+ {\docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey}%
+ {\docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey}%
+ \fi
+ \else
+ \ifdim\scaleboxdimy>\zeropoint
+ \dosetdimensionscaleboxsize
+ {\docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex}%
+ {\docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex}%
+ {\docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex}%
+ \else
+ \dosetdimensionscaleboxsize
+ {\doapplyscaleboxscale\scaleboxdimx\scaleboxsizex\scaleboxscax\c!xscale
+ \doapplyscaleboxscale\scaleboxdimy\scaleboxsizey\scaleboxscay\c!yscale}%
+ {\docalculatescaleboxscales\scaleboxdimx\scaleboxsizex\scaleboxdimy\scaleboxsizey}%
+ {\docalculatescaleboxscales\scaleboxdimy\scaleboxsizey\scaleboxdimx\scaleboxsizex}%
+ \fi
+ \fi}
+
+\def\dosetdimensionscaleboxsize#1#2#3%
+ {#1\relax
+ \doifsomething{\scaleparameter\c!maxwidth}
+ {\ifdim\scaleboxdimx>\scaleparameter\c!maxwidth\relax
+ \global\scaleboxdimx\scaleparameter\c!maxwidth
+ #2\relax
+ \fi}%
+ \doifsomething{\scaleparameter\c!maxheight}
+ {\ifdim\scaleboxdimy>\scaleparameter\c!maxheight\relax
+ \global\scaleboxdimy\scaleparameter\c!maxheight
+ #3\relax
+ \fi}}
+
+\def\docalculatescaleboxnorm#1#2#3#4#5% 2 3 parameters (dodo:speedup)
+ {\processaction
+ [\scaleparameter#2]
+ [ \v!max=>\global#1\dimexpr#4\relax,
+ \v!fit=>\global#1\dimexpr#5\relax,
+ \v!broad=>\global#1\dimexpr#5-4\@@exbodyfont\relax,
+ \v!auto=>\doifsomething{\scaleparameter#3}{\global#1\dimexpr\scaleparameter#3\relax},
+ \s!default=>\doifsomething{\scaleparameter#3}{\global#1\dimexpr\scaleparameter#3\relax},
+ \s!unknown=>\global#1\dimexpr\scaleparameter#2\dimexpr\@@exbodyfont/10\relax\relax]}
+
+\def\docalculatescaleboxscales#1#2#3#4%
+ {\scratchdimen\dimexpr#1/\dimexpr#2/\plusthousand\relax\relax
+ \scaleboxscax\scratchdimen
+ \scaleboxscay\scratchdimen
+ #3\dimexpr\scaleboxscax\dimexpr#4/\plusthousand\relax\relax}
+
+\def\docalculatescaleboxscale#1#2#3%
+ {#3\dimexpr#1/\dimexpr#2/\plusthousand\relax\relax}
+
+\def\doapplyscaleboxscale#1#2#3#4% $4 = parameter / scale can be empty
+ {\ifcase0\scaleparameter#4\relax
+ \ifcase0\scaleparameter\c!scale\relax
+ #3=\plusthousand
+ \else
+ #3=\scaleparameter\c!scale
+ \fi
+ \else
+ #3=\scaleparameter#4%
+ \fi
+ \relax % important ! still ?
+ \global#1\ifnum#3=\plusthousand#2\else\dimexpr#3\dimexpr#2/\plusthousand\relax\relax\fi
+ \relax}
+
+\def\doapplyscaleboxsize
+ {\doifelsenothing{\scaleparameter\c!maxheight}
+ {\scaleboxoutervsize\textheight
+ \ifinner
+ \scaleboxoutervsize \vsize % \textheight =\vsize
+ \scratchdimen\vsize % \scratchdimen=\textheight
+ \else\ifinsidefloat
+ \scaleboxoutervsize \vsize % \textheight =\vsize
+ \scratchdimen\vsize % \scratchdimen=\textheight
+ \else\ifinpagebody
+ \scaleboxoutervsize \vsize % \textheight =\vsize
+ \scratchdimen\vsize % \scratchdimen=\textheight
+ \else % hm, there should be an option to force this
+ \ifdim\pagegoal<\maxdimen
+ \ifdim\pagetotal<\pagegoal
+ \scratchdimen\dimexpr\pagegoal-\pagetotal\relax
+ \else
+ \scratchdimen\scaleboxoutervsize % \textheight
+ \fi
+ \else
+ \scratchdimen\scaleboxoutervsize % \textheight
+ \fi
+ \fi\fi\fi}
+ {\scratchdimen\scaleparameter\c!maxheight
+ \scaleboxoutervsize\scratchdimen}%
+ \doifelsenothing{\scaleparameter\c!height}
+ {\scaleboxvsize\scratchdimen}
+ {\scaleboxvsize\scaleparameter\c!height}%
+ \doifelsenothing{\scaleparameter\c!width}
+ {\scaleboxhsize\hsize}
+ {\scaleboxhsize\scaleparameter\c!width}}
+
+\def\convertscaleboxinsertscale#1#2#3#4%
+ {\scratchdimen#1\relax
+ \ifnum#3=\plusthousand
+ % == scale 1
+ \else
+ % better 1000 100 10 ranges, evt round 2sp
+ \divide\scratchdimen \plusthousand
+ \multiply\scratchdimen #3\relax
+ \fi
+ \scratchdimen-\scratchdimen % beter hier - dan in driver
+ \edef#2{\the\scratchdimen}%
+ \scratchcounter#3\relax
+ \ifnum\scratchcounter>\plustenthousand
+ \divide\scratchcounter\!!ten \scratchdimen\the\scratchcounter\points
+ \else
+ \scratchdimen\the\scratchcounter\points \divide\scratchdimen\!!ten
+ \fi
+ \edef#4{\withoutpt\the\scratchdimen}}
+
+% \startcombination
+% {\externalfigure[cow.pdf] [frame=on,height=3cm,equalwidth=6cm]} {}
+% {\externalfigure[mill.png][frame=on,height=3cm,equalwidth=6cm]} {}
+% \stopcombination
+
+\def\doscaleboxposition
+ {\doifsomething{\scaleparameter\c!equalwidth}
+ {\scratchdimen\scaleparameter\c!equalwidth\relax
+ \ifdim\wd\nextbox<\scratchdimen
+ \setbox\nextbox\hbox to \scratchdimen{\hss\box\nextbox\hss}%
+ \fi}%
+ \doifsomething{\scaleparameter\c!equalheight}
+ {\scratchdimen\scaleparameter\c!equalheight\relax
+ \ifdim\ht\nextbox<\scratchdimen
+ \setbox\nextbox\vbox to \scratchdimen{\vss\box\nextbox\vss}%
+ \fi}}
+
+%D \macros
+%D {clip, setupclipping}
+%D
+%D Although related to figures, clipping can be applied to
+%D arbitrary content. We can use \METAPOST\ to provide a non
+%D rectangular clipping path.
+%D
+%D \starttyping
+%D \startMPclip{fun}
+%D clip currentpicture to fullcircle
+%D shifted (.5,.5) xscaled \width yscaled \height ;
+%D \stopMPclip
+%D \stoptyping
+%D
+%D We get a rectangular piece of the figure when we say:
+%D
+%D \starttyping
+%D \clip[x=2,y=1]{\externalfigure[photo]}
+%D \stoptyping
+%D
+%D When we want to clip to the oval we defined a few lines ago,
+%D we say:
+%D
+%D \starttyping
+%D \clip[nx=1,ny=1,x=1,y=1,mp=fun]{\externalfigure[photo]}
+%D \stoptyping
+%D
+%D The general characteristics of clipping can be set up with
+%D
+%D \showsetup{setupclipping}
+
+\unexpanded\def\setupclipping
+ {\dodoubleargument\getparameters[\??cp]}
+
+\def\clip
+ {\dosingleempty\doclip}
+
+\def\doclip[#1]% nb top->bottom left->right
+ {\bgroup
+ \getparameters[\??cp][#1]%
+ \doifelse\@@cpstate\v!start\dodoclip{\egroup\hbox}}
+
+\def\dodoclip
+ {\dowithnextbox
+ {\ifdim\@@cpwidth>\zeropoint
+ \!!dimena\@@cpwidth
+ \!!dimenc\@@cphoffset
+ \else
+ \!!dimena\nextboxwd
+ \divide\!!dimena \@@cpnx
+ \!!dimenc\@@cpx\!!dimena
+ \advance\!!dimenc -\!!dimena
+ \!!dimena\@@cpsx\!!dimena
+ \fi
+ \relax % sure
+ \ifdim\@@cpheight>\zeropoint
+ \!!dimenb\@@cpheight
+ \!!dimend\nextboxht
+ \advance\!!dimend -\@@cpvoffset
+ \advance\!!dimend -\!!dimenb
+ \else
+ \!!dimenb\nextboxht
+ \divide\!!dimenb \@@cpny
+ \!!dimend-\@@cpy\!!dimenb
+ \advance\!!dimend -\@@cpsy\!!dimenb
+ \advance\!!dimend \!!dimenb
+ \!!dimenb\@@cpsy\!!dimenb
+ \advance\!!dimend \nextboxht % dimend !
+ \fi
+ \setbox\nextbox\hbox % old
+ {\advance\!!dimenc -\@@cpleftoffset % new !
+ \advance\!!dimend -\@@cpbottomoffset % new ! % - added
+ \hskip-\!!dimenc\lower\!!dimend\flushnextbox}% old
+ \nextboxwd\zeropoint
+ \nextboxht\zeropoint
+ \nextboxdp\zeropoint
+ \setbox\nextbox\hbox
+ {\advance\!!dimena \@@cpleftoffset % new !
+ \advance\!!dimena \@@cprightoffset % new !
+ \advance\!!dimenb \@@cpbottomoffset % new !
+ \advance\!!dimenb \@@cptopoffset % new !
+ \dostartclipping\@@cpmp\!!dimena\!!dimenb % old
+ \flushnextbox
+ \dostopclipping}%
+ \setbox\nextbox\hbox % new !
+ {\!!dimena-\@@cpleftoffset % new !
+ \!!dimenb \@@cpbottomoffset % new ! % - removed
+ \hskip\!!dimena\lower\!!dimenb\flushnextbox}% new !
+ \nextboxwd\!!dimena
+ \nextboxht\!!dimenb
+ \nextboxdp\zeropoint
+ \flushnextbox
+ \egroup}%
+ \hbox}
+
+\setupclipping
+ [\c!state=\v!start,
+ \c!n=1, % was 2
+ \c!nx=\@@cpn,\c!x=1,\c!sx=1,
+ \c!ny=\@@cpn,\c!y=1,\c!sy=1,
+ \c!width=\!!zeropoint,
+ \c!height=\!!zeropoint,
+ \c!hoffset=\!!zeropoint,
+ \c!voffset=\!!zeropoint,
+ \c!offset=\zeropoint,
+ \c!leftoffset=\@@cpoffset, % \zeropoint,
+ \c!rightoffset=\@@cpoffset, % \zeropoint,
+ \c!topoffset=\@@cpoffset, % \zeropoint,
+ \c!bottomoffset=\@@cpoffset,% \zeropoint,
+ \c!mp=]
+
+%D \startbuffer
+%D \startuseMPgraphic{test}
+%D path p ; p := fullcircle scaled 4cm ;
+%D draw p withpen pencircle scaled 1cm ;
+%D setbounds currentpicture to boundingbox p ;
+%D \stopuseMPgraphic
+%D
+%D \hbox to \hsize \bgroup
+%D \hss
+%D \ruledhbox{\useMPgraphic{test}}%
+%D \hss
+%D \ruledhbox{\clip{\useMPgraphic{test}}}%
+%D \hss
+%D \egroup
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D Mirroring.
+
+\def\domirrorbox % \hbox/\vbox/\vtop
+ {\bgroup
+ \dowithnextbox
+ {\dontshowcomposition
+ \scratchdimen\nextboxwd
+ % better use an hbox (if no \forgetall, leftskip etc may creep in)
+ %\setbox\nextbox\vbox{\forgetall\dostartmirroring\hskip-\nextboxwd\flushnextbox\dostopmirroring}%
+ \setbox\nextbox\hbox{\dostartmirroring\hskip-\nextboxwd\flushnextbox\dostopmirroring}%
+ \nextboxwd\scratchdimen
+ \flushnextbox
+ \egroup}}
+
+\unexpanded\def\mirror
+ {\domirrorbox\hbox}
+
+% \setbox0=\hbox{gans}
+% \ruledhbox{\copy0 \schaal[sx=2,sy=2]{\copy0}}
+% \mirror{\ruledhbox{\copy0 \schaal{\box0}}}
+
+\protect \endinput
diff --git a/tex/context/base/grph-u3d.lua b/tex/context/base/grph-u3d.lua
new file mode 100644
index 000000000..f3bf17631
--- /dev/null
+++ b/tex/context/base/grph-u3d.lua
@@ -0,0 +1,49 @@
+if not modules then modules = { } end modules ['grph-u3d'] = {
+ version = 1.001,
+ comment = "companion to grph-inc.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- see lpdf-u3d.lua for comment
+
+local trace_inclusion = false trackers.register("figures.inclusion", function(v) trace_inclusion = v end)
+
+local pdfannotation = nodes.pdfannotation
+local todimen = string.todimen
+
+-- maybe todo: backends.codeinjections.insertu3d
+
+function figures.checkers.u3d(data)
+ local dr, du, ds = data.request, data.used, data.status
+ local width = todimen(dr.width or figures.defaultwidth)
+ local height = todimen(dr.height or figures.defaultheight)
+ local foundname = du.fullname
+ dr.width, dr.height = width, height
+ du.width, du.height, du.foundname = width, height, foundname
+ if trace_inclusion then
+ logs.report("figures","including u3d '%s': width %s, height %s",foundname,width,height)
+ end
+ context.startfoundexternalfigure(width .. "sp",height .. "sp")
+ context(function()
+ local annotation, preview, ref = backends.pdf.helpers.insert3d {
+ foundname = foundname,
+ width = width,
+ height = height,
+ factor = number.dimenfactors.bp,
+ display = dr.display,
+ controls = dr.controls,
+ label = dr.label,
+ }
+--~ print(annotation, preview, ref)
+ node.write(pdfannotation(width,height,0,annotation()))
+ end)
+ context.stopfoundexternalfigure()
+ return data
+end
+
+figures.includers.u3d = figures.includers.nongeneric
+
+figures.registersuffix("u3d","u3d")
+figures.registersuffix("prc","u3d")
diff --git a/tex/context/base/hand-def.mkii b/tex/context/base/hand-def.mkii
new file mode 100644
index 000000000..0a19ce270
--- /dev/null
+++ b/tex/context/base/hand-def.mkii
@@ -0,0 +1,577 @@
+%D \module
+%D [ file=hand-def, % was enco-pro
+%D version=2000.29.09,
+%D title=\CONTEXT\ Handling Macros,
+%D subtitle=Default Protruding Factors,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is an experimental definition file. The protruding
+%D values we use here are those found from \THANH's thesis.
+
+\startfonthandling [pure]
+
+ \defineprotrudefactor , 0 1
+ \defineprotrudefactor . 0 1
+ \defineprotrudefactor : 0 1
+ \defineprotrudefactor ; 0 1
+ \defineprotrudefactor - 0 1
+
+ \defineprotrudefactor hyphen 0 1
+ \defineprotrudefactor endash 0 .5
+ \defineprotrudefactor emdash 0 .33 % .5
+
+\stopfonthandling
+
+\startfonthandling [punctuation]
+
+ \defineprotrudefactor ! 0 .2
+ \defineprotrudefactor ' 0 .7
+ \defineprotrudefactor ` .7 0
+ \defineprotrudefactor ( .05 0
+ \defineprotrudefactor ) 0 .05
+ \defineprotrudefactor [ .05 0
+ \defineprotrudefactor ] 0 .05
+ \defineprotrudefactor , 0 .7
+ \defineprotrudefactor - 0 .7
+ \defineprotrudefactor . 0 .7
+ \defineprotrudefactor : 0 .5
+ \defineprotrudefactor ; 0 .5
+
+ \defineprotrudefactor rightupperninequote 0 .5
+ \defineprotrudefactor leftupperninequote .5 0
+ \defineprotrudefactor endash 0 .3
+ \defineprotrudefactor emdash 0 .2
+
+ \defineprotrudefactor hyphen 0 .7
+
+\stopfonthandling
+
+\startfonthandling [alpha]
+
+ \defineprotrudefactor A .05 .05
+ \defineprotrudefactor F 0 .05
+ \defineprotrudefactor J .05 0
+ \defineprotrudefactor K 0 .05
+ \defineprotrudefactor L 0 .05
+ \defineprotrudefactor T .05 .05
+ \defineprotrudefactor V .05 .05
+ \defineprotrudefactor W .05 .05
+ \defineprotrudefactor X .05 .05
+ \defineprotrudefactor Y .05 .05
+
+ \defineprotrudefactor k 0 .05
+ \defineprotrudefactor r 0 .05
+ \defineprotrudefactor t 0 .05
+ \defineprotrudefactor v .05 .05
+ \defineprotrudefactor w .05 .05
+ \defineprotrudefactor x .05 .05
+ \defineprotrudefactor y .05 .05
+
+\stopfonthandling
+
+% ogoneks may need another treatment
+
+\startfonthandling [extended]
+
+ \inherithandling Acircumflex A
+ \inherithandling acircumflex a
+ \inherithandling Ccircumflex C
+ \inherithandling ccircumflex c
+ \inherithandling Ecircumflex E
+ \inherithandling ecircumflex e
+ \inherithandling Gcircumflex G
+ \inherithandling gcircumflex g
+ \inherithandling Hcircumflex H
+ \inherithandling hcircumflex h
+ \inherithandling Icircumflex I
+ \inherithandling icircumflex i
+ \inherithandling Jcircumflex J
+ \inherithandling jcircumflex j
+ \inherithandling Ocircumflex O
+ \inherithandling ocircumflex o
+ \inherithandling Scircumflex S
+ \inherithandling scircumflex s
+ \inherithandling Ucircumflex U
+ \inherithandling ucircumflex u
+ \inherithandling Wcircumflex W
+ \inherithandling wcircumflex w
+ \inherithandling Ycircumflex Y
+ \inherithandling ycircumflex y
+
+ \inherithandling Agrave A
+ \inherithandling agrave a
+ \inherithandling Egrave E
+ \inherithandling egrave e
+ \inherithandling Igrave I
+ \inherithandling igrave i
+ \inherithandling Ograve O
+ \inherithandling ograve o
+ \inherithandling Ugrave U
+ \inherithandling ugrave u
+ \inherithandling Ygrave Y
+ \inherithandling ygrave y
+
+ \inherithandling Atilde A
+ \inherithandling atilde a
+ \inherithandling Itilde I
+ \inherithandling itilde i
+ \inherithandling Ntilde N
+ \inherithandling ntilde n
+ \inherithandling Otilde O
+ \inherithandling otilde o
+ \inherithandling Utilde U
+ \inherithandling utilde u
+
+ \inherithandling Adiaeresis A
+ \inherithandling adiaeresis a
+ \inherithandling Ediaeresis E
+ \inherithandling ediaeresis e
+ \inherithandling Idiaeresis I
+ \inherithandling idiaeresis i
+ \inherithandling Odiaeresis O
+ \inherithandling odiaeresis o
+ \inherithandling Udiaeresis U
+ \inherithandling udiaeresis u
+ \inherithandling Ydiaeresis Y
+ \inherithandling ydiaeresis y
+
+ \inherithandling Aacute A
+ \inherithandling aacute a
+ \inherithandling Cacute C
+ \inherithandling cacute c
+ \inherithandling Eacute E
+ \inherithandling eacute e
+ \inherithandling Iacute I
+ \inherithandling iacute i
+ \inherithandling Lacute L
+ \inherithandling lacute l
+ \inherithandling Nacute N
+ \inherithandling nacute n
+ \inherithandling Oacute O
+ \inherithandling oacute o
+ \inherithandling Racute R
+ \inherithandling racute r
+ \inherithandling Sacute s
+ \inherithandling sacute s
+ \inherithandling Uacute U
+ \inherithandling uacute u
+ \inherithandling Yacute Y
+ \inherithandling yacute y
+ \inherithandling Zacute Z
+ \inherithandling zacute z
+
+ \inherithandling Dstroke D
+ \inherithandling dstroke d
+ \inherithandling Hstroke H
+ \inherithandling hstroke h
+ \inherithandling Tstroke T
+ \inherithandling tstroke t
+
+ \inherithandling Cdotaccent C
+ \inherithandling cdotaccent c
+ \inherithandling Edotaccent E
+ \inherithandling edotaccent e
+ \inherithandling Gdotaccent G
+ \inherithandling gdotaccent g
+ \inherithandling Idotaccent I
+ \inherithandling idotaccent i
+ \inherithandling Zdotaccent Z
+ \inherithandling zdotaccent z
+
+ \inherithandling Amacron A
+ \inherithandling amacron a
+ \inherithandling Emacron E
+ \inherithandling emacron e
+ \inherithandling Imacron I
+ \inherithandling imacron i
+ \inherithandling Omacron O
+ \inherithandling omacron o
+ \inherithandling Umacron U
+ \inherithandling umacron u
+
+ \inherithandling Ccedilla C
+ \inherithandling ccedilla c
+ \inherithandling Kcedilla K
+ \inherithandling kcedilla k
+ \inherithandling Lcedilla L
+ \inherithandling lcedilla l
+ \inherithandling Ncedilla N
+ \inherithandling ncedilla n
+ \inherithandling Rcedilla R
+ \inherithandling rcedilla r
+ \inherithandling Scedilla S
+ \inherithandling scedilla s
+ \inherithandling Tcedilla T
+ \inherithandling tcedilla t
+
+ \inherithandling Ohungarumlaut O
+ \inherithandling ohungarumlaut o
+ \inherithandling Uhungarumlaut U
+ \inherithandling uhungarumlaut u
+
+ \inherithandling Aogonek A
+ \inherithandling aogonek a
+ \inherithandling Eogonek E
+ \inherithandling eogonek e
+ \inherithandling Iogonek I
+ \inherithandling iogonek i
+ \inherithandling Uogonek U
+ \inherithandling uogonek u
+
+ \inherithandling Aring A
+ \inherithandling aring a
+ \inherithandling Uring U
+ \inherithandling uring u
+
+ \inherithandling Abreve A
+ \inherithandling abreve a
+ \inherithandling Ebreve E
+ \inherithandling ebreve e
+ \inherithandling Gbreve G
+ \inherithandling gbreve g
+ \inherithandling Ibreve I
+ \inherithandling ibreve i
+ \inherithandling Obreve O
+ \inherithandling obreve o
+ \inherithandling Ubreve U
+ \inherithandling ubreve u
+
+ \inherithandling Ccaron C
+ \inherithandling ccaron c
+ \inherithandling Dcaron D
+ \inherithandling dcaron d
+ \inherithandling Ecaron E
+ \inherithandling ecaron e
+ \inherithandling Lcaron L
+ \inherithandling lcaron l
+ \inherithandling Ncaron N
+ \inherithandling ncaron n
+ \inherithandling Rcaron R
+ \inherithandling rcaron r
+ \inherithandling Scaron S
+ \inherithandling scaron s
+ \inherithandling Tcaron T
+ \inherithandling tcaron t
+ \inherithandling Ycaron Y
+ \inherithandling ycaron y
+ \inherithandling Zcaron Z
+ \inherithandling zcaron z
+
+ \inherithandling AEligature E
+ \inherithandling aeligature e
+ \inherithandling Lstroke I
+ \inherithandling lstroke o
+ \inherithandling Ostroke O
+ \inherithandling ostroke o
+ \inherithandling OEligature O
+ \inherithandling oeligature o
+
+ \inherithandling Ssharp S
+ \inherithandling ssharp s
+ \inherithandling IJligature J
+ \inherithandling ijligature j
+
+ \inherithandling aumlaut a
+ \inherithandling eumlaut e
+ \inherithandling iumlaut i
+ \inherithandling oumlaut o
+ \inherithandling uumlaut u
+
+ \inherithandling Aumlaut A
+ \inherithandling Eumlaut E
+ \inherithandling Iumlaut I
+ \inherithandling Oumlaut O
+ \inherithandling Uumlaut U
+
+ \inherithandling Lslash L
+ \inherithandling lslash l
+ \inherithandling Dslash D
+ \inherithandling dslash d
+ \inherithandling Oslash O
+ \inherithandling oslash o
+
+ \inherithandling Eszett S
+ \inherithandling eszett s
+
+ \inherithandling Thorn P
+ \inherithandling thorn p
+
+ % vietnamese
+
+ \inherithandling Ahook A
+ \inherithandling ahook a
+ \inherithandling Ehook E
+ \inherithandling ehook e
+ \inherithandling Ihook I
+ \inherithandling ihook i
+ \inherithandling Ohook O
+ \inherithandling ohook o
+ \inherithandling Uhook U
+ \inherithandling uhook u
+ \inherithandling Yhook Y
+ \inherithandling yhook y
+
+ \inherithandling Acircumflexgrave A
+ \inherithandling Acircumflexacute A
+ \inherithandling Acircumflextilde A
+ \inherithandling Acircumflexhook A
+ \inherithandling acircumflexgrave a
+ \inherithandling acircumflexacute a
+ \inherithandling acircumflextilde a
+ \inherithandling acircumflexhook a
+ \inherithandling Ecircumflexgrave E
+ \inherithandling Ecircumflexacute E
+ \inherithandling Ecircumflextilde E
+ \inherithandling Ecircumflexhook E
+ \inherithandling ecircumflexgrave e
+ \inherithandling ecircumflexacute e
+ \inherithandling ecircumflextilde e
+ \inherithandling ecircumflexhook e
+ \inherithandling Ocircumflexgrave O
+ \inherithandling Ocircumflexacute O
+ \inherithandling Ocircumflextilde O
+ \inherithandling Ocircumflexhook O
+ \inherithandling ocircumflexgrave o
+ \inherithandling ocircumflexacute o
+ \inherithandling ocircumflextilde o
+ \inherithandling ocircumflexhook o
+
+ \inherithandling Abrevegrave A
+ \inherithandling Abreveacute A
+ \inherithandling Abrevetilde A
+ \inherithandling Abrevehook A
+ \inherithandling abrevegrave a
+ \inherithandling abreveacute a
+ \inherithandling abrevetilde a
+ \inherithandling abrevehook a
+
+ \inherithandling Adotbelow A
+ \inherithandling adotbelow a
+ \inherithandling Edotbelow E
+ \inherithandling edotbelow e
+ \inherithandling Idotbelow I
+ \inherithandling idotbelow i
+ \inherithandling Odotbelow O
+ \inherithandling odotbelow o
+ \inherithandling Udotbelow U
+ \inherithandling udotbelow u
+ \inherithandling Ydotbelow Y
+ \inherithandling ydotbelow y
+
+ \inherithandling Ohorndotbelow O
+ \inherithandling ohorndotbelow o
+ \inherithandling Uhorndotbelow U
+ \inherithandling uhorndotbelow u
+
+ \inherithandling Acircumflexdotbelow A
+ \inherithandling acircumflexdotbelow a
+ \inherithandling Ecircumflexdotbelow E
+ \inherithandling ecircumflexdotbelow e
+ \inherithandling Ocircumflexdotbelow O
+ \inherithandling ocircumflexdotbelow o
+
+ \inherithandling Abrevedotbelow A
+ \inherithandling abrevedotbelow a
+
+ \inherithandling Ohorn O
+ \inherithandling Ohorngrave O
+ \inherithandling Ohornacute O
+ \inherithandling Ohorntilde O
+ \inherithandling Ohornhook O
+ \inherithandling ohorn o
+ \inherithandling ohorngrave o
+ \inherithandling ohornacute o
+ \inherithandling ohorntilde o
+ \inherithandling ohornhook o
+ \inherithandling Uhorn U
+ \inherithandling Uhorngrave U
+ \inherithandling Uhornacute U
+ \inherithandling Uhorntilde U
+ \inherithandling Uhornhook U
+ \inherithandling uhorn u
+ \inherithandling uhorngrave u
+ \inherithandling uhornacute u
+ \inherithandling uhorntilde u
+ \inherithandling uhornhook u
+
+ \inherithandling Ytilde Y
+ \inherithandling ytilde y
+ \inherithandling Etilde E
+ \inherithandling etilde e
+
+\stopfonthandling
+
+\startfonthandling [hz]
+
+ \defineadjustfactor A .5
+ \defineadjustfactor B .7
+ \defineadjustfactor C .7
+ \defineadjustfactor D .5
+ \defineadjustfactor E .7
+ \defineadjustfactor F .7
+ \defineadjustfactor G .5
+ \defineadjustfactor H .7
+ \defineadjustfactor K .7
+ \defineadjustfactor M .7
+ \defineadjustfactor N .7
+ \defineadjustfactor O .5
+ \defineadjustfactor P .7
+ \defineadjustfactor Q .5
+ \defineadjustfactor R .7
+ \defineadjustfactor S .7
+ \defineadjustfactor U .7
+ \defineadjustfactor W .7
+ \defineadjustfactor Z .7
+
+ \defineadjustfactor a .7
+ \defineadjustfactor b .7
+ \defineadjustfactor c .7
+ \defineadjustfactor d .7
+ \defineadjustfactor e .7
+ \defineadjustfactor g .7
+ \defineadjustfactor h .7
+ \defineadjustfactor k .7
+ \defineadjustfactor m .7
+ \defineadjustfactor n .7
+ \defineadjustfactor o .7
+ \defineadjustfactor p .7
+ \defineadjustfactor q .7
+ \defineadjustfactor s .7
+ \defineadjustfactor u .7
+ \defineadjustfactor w .7
+ \defineadjustfactor z .7
+
+ \defineadjustfactor 2 .7
+ \defineadjustfactor 3 .7
+ \defineadjustfactor 6 .7
+ \defineadjustfactor 8 .7
+ \defineadjustfactor 9 .7
+
+% \defineadjustfactor hyphen ?
+% \defineadjustfactor endash ?
+% \defineadjustfactor emdash ?
+
+\stopfonthandling
+
+% no ligs other than fi fl etc, no --- and ''
+
+\startfonthandling[noligs]
+
+ \settagcode - {\notagcode}
+ \settagcode ' {\notagcode}
+ \settagcode ` {\notagcode}
+ \settagcode ? {\notagcode}
+ \settagcode ! {\notagcode}
+
+\stopfonthandling
+
+% \startfonthandling[noligs]
+% \dostepwiserecurse{0}{255}{1}{\expanded{\settagcode \recurselevel\space\notagcode\space}}
+% \stopfonthandling
+
+% \definefonthandling [noligs] [noligs] [type=tag]
+ % \setupfontsynonym[Serif][handling=noligs]
+% \definefont[test][Serif at 12.34pt]
+%
+% {``fi--ffl---ffi'' \test ``fi--ffl---ffi''}
+
+\unprotect
+
+% beware: extended extends the preceding vector (both protruding and
+% adjusting) but as long as the normal ascii characters are not set
+% beforehand, they default to normal
+
+% protruding variants -- slanted/italic is yet incomplete
+
+\definefonthandling [pure] [pure] [\c!type=\v!hanging]
+\definefonthandling [purebold] [pure] [\c!type=\v!hanging]
+\definefonthandling [pureslanted] [pure] [\c!type=\v!hanging,\c!right=1.5]
+\definefonthandling [pureitalic] [pure] [\c!type=\v!hanging,\c!right=1.5]
+\definefonthandling [pureboldslanted] [pure] [\c!type=\v!hanging,\c!right=1.5]
+\definefonthandling [purebolditalic] [pure] [\c!type=\v!hanging,\c!right=1.5]
+
+\definefonthandling [normal] [punctuation,alpha,extended] [\c!type=\v!hanging]
+\definefonthandling [normalbold] [punctuation,alpha,extended] [\c!type=\v!hanging]
+\definefonthandling [normalslanted] [punctuation,alpha,extended] [\c!type=\v!hanging,\c!right=1.5]
+\definefonthandling [normalitalic] [punctuation,alpha,extended] [\c!type=\v!hanging,\c!right=1.5]
+\definefonthandling [normalboldslanted] [punctuation,alpha,extended] [\c!type=\v!hanging,\c!right=1.5]
+\definefonthandling [normalbolditalic] [punctuation,alpha,extended] [\c!type=\v!hanging,\c!right=1.5]
+
+% for old times sake
+
+\definefonthandling [bold] [punctuation,alpha,extended] [\c!type=\v!hanging]
+\definefonthandling [slanted] [punctuation,alpha,extended] [\c!type=\v!hanging,\c!right=1.5]
+\definefonthandling [italic] [punctuation,alpha,extended] [\c!type=\v!hanging,\c!right=1.5]
+\definefonthandling [boldslanted] [punctuation,alpha,extended] [\c!type=\v!hanging,\c!right=1.5]
+\definefonthandling [bolditalic] [punctuation,alpha,extended] [\c!type=\v!hanging,\c!right=1.5]
+
+% hz variants
+
+\definefonthandling [hz] [hz,extended] [\c!type=\v!hz] % min=20 max=20 step=5
+
+% combined variants
+
+\definefonthandling [quality] [hz,pure]
+\definefonthandling [highquality] [hz,normal]
+
+% noligs (xml) : \definefonthandling [default] [noligs]
+
+\definefonthandling [noligs] [noligs] [\c!type=tag]
+
+% experimental values !
+%
+% \definefontsynonym[myfont][Serif][handling=prespacing]
+% \definefont[whatever][myfont sa 1]
+% \setupalign[spacing]
+%
+% \whatever look at this: we now have a proper spacing feature and, hurray,
+% get rid of active punctuation!
+
+\startfonthandling [flexspacing]
+
+ \definespacefactor : 0 1.25 .25 .25
+
+ \definespacefactor , 0 1 .25 .25
+ \inheritspacefactor ; ,
+
+ \definespacefactor . 0 1.5 .25 .25
+ \inheritspacefactor ! .
+ \inheritspacefactor ? .
+
+\stopfonthandling
+
+\definefonthandling[flexspacing][flexspacing][\c!type=\v!spacing]
+
+\startfonthandling [prespacing] % better name needed
+
+ \definespacefactor : .25 .25 0 0
+ \inheritspacefactor ; :
+ \inheritspacefactor ! :
+ \inheritspacefactor ? :
+
+\stopfonthandling
+
+\definefonthandling[prespacing][prespacing][\c!type=\v!spacing] % factor=.5
+
+% A special case of guillemots, beware: when used ungrouped,
+% it overloads all successive (current) encoding vector
+% instances! Will be obsolete soon.
+
+\startfonthandling [glm]
+
+ \overloadcharacter guilsingleleft {\defaultcharacter\guilsingleleft }
+ \overloadcharacter guilsingleright {\defaultcharacter\guilsingleright}
+ \overloadcharacter leftguillemot {\defaultcharacter\leftguillemot }
+ \overloadcharacter rightguillemot {\defaultcharacter\rightguillemot }
+
+\stopfonthandling
+
+\definefonthandling [glm] [glm]
+
+\protect \endinput
diff --git a/tex/context/base/hand-ini.mkii b/tex/context/base/hand-ini.mkii
new file mode 100644
index 000000000..ac8a94696
--- /dev/null
+++ b/tex/context/base/hand-ini.mkii
@@ -0,0 +1,483 @@
+%D \module
+%D [ file=hand-ini, % moved from enco-ini / pro
+%D version=2000.12.27, % 1998.12.03,
+%D title=\CONTEXT\ Handling Macros,
+%D subtitle=Initialization,
+%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.
+
+%D {\em This module is experimental and implements font
+%D specific features, like hanging punctuation.}
+
+\unprotect
+
+\newif\iftracefonthandling % \tracefonthandlingtrue
+
+\newif\ifskiphandlingdef \skiphandlingdeffalse
+
+\newtoks\everyenablefonthandling
+
+% much in common with hz/protruding defs
+% todo: fix others
+
+\def\dosetsomehandling#1#2#3 #4 % no define since directly set
+ {\ifskiphandlingdef \else
+ \doifnumberelse{\string#2}
+ {#1{#2#3}{#4}}
+ {\doifelsenothing{#3}
+ {#1{`#2}{#4}}
+ {\let\char\empty
+ \doifnumberelse{\csname#2#3\endcsname}{#1{\csname#2#3\endcsname}{#4}}\donothing
+ \let\char\normalchar}}%
+ \fi}
+
+\def\dosetpairhandling#1#2#3 #4 #5 % no define since directly set
+ {\ifskiphandlingdef \else
+ \doifnumberelse{\string#2}
+ {#1{#2#3}{#4}{#5}}
+ {\doifelsenothing{#3}
+ {#1{`#2}{#4}{#5}}
+ {\let\char\empty
+ \doifnumberelse{\csname#2#3\endcsname}{#1{\csname#2#3\endcsname}{#4}{#5}}\donothing
+ \let\char\normalchar}}%
+ \fi}
+
+\def\dosetquartethandling#1#2#3 #4 #5 #6 #7 % no define since directly set
+ {\ifskiphandlingdef \else
+ \doifnumberelse{\string#2}
+ {#1{#2#3}{#4}{#5}{#6}{#7}}
+ {\doifelsenothing{#3}
+ {#1{`#2}{#4}{#5}{#6}{#7}}
+ {\let\char\empty
+ \doifnumberelse{\csname#2#3\endcsname}{#1{\csname#2#3\endcsname}{#4}{#5}{#6}{#7}}\donothing
+ \let\char\normalchar}}%
+ \fi}
+
+\def\doinhsomehandling#1#2#3 #4 % to be checked
+ {\ifskiphandlingdef \else
+ \if#3\relax\relax
+ #1{`#2}{`#4}%
+ \else
+ \let\char\empty
+ \doifnumberelse{\csname#2#3\endcsname}{#1{\csname#2#3\endcsname}{`#4}}\donothing
+ \let\char\normalchar
+ \fi
+ \fi}
+
+% adjustspacing
+
+\newdimen\adjustdimen \let\handledfont\font
+
+\ifx\undefined\pdfadjustspacing % we don't use pdftex
+
+ \let\enableadjusting \relax
+ \let\disableadjusting \relax
+ \let\setadjusting \gobbletwoarguments
+
+ \def\defineadjustfactor #1 #2 {}
+ \def\inheritadjustfactor #1 #2 {}
+
+ \let\setfontadjusting \gobbleoneargument
+
+\else
+
+ \def\enableadjusting {\pdfadjustspacing\plustwo}
+ \def\disableadjusting {\pdfadjustspacing\zerocount}
+
+ \appendtoks \disableadjusting \to \everyforgetall % Here or not here?
+
+ \def\dododefineadjustfactor#1#2%
+ {\efcode\handledfont#1\dimexpr#2\onepoint*\plusthousand/\maxcard\relax}
+
+ \def\dodoinheritadjustfactor#1#2%
+ {\efcode\handledfont#1\efcode\handledfont#2\relax}
+
+ \def\defineadjustfactor#1 #2 %
+ {\setfonttoks
+ \let\inherithandling\inheritadjustfactor
+ \appendtoks\dosetsomehandling\dododefineadjustfactor#1 #2 \to\fonttoks}
+
+ \def\inheritadjustfactor#1 #2 %
+ {\setfonttoks
+ \appendtoks\doinhsomehandling\dodoinheritadjustfactor#1 #2 \to\fonttoks}
+
+ \ifnum\pdftexversion<120
+ \let\@@pdfexpandbonus\plusthousand
+ \else
+ \def\@@pdfexpandbonus{autoexpand}%
+ \fi
+
+ \def\setfontadjusting#1%
+ {\doifvalue{\@fha@\@fha@#1\c!type}\v!hz{\dosetfontadjusting{#1}}}
+
+ \def\dosetfontadjusting#1%
+ {\iftracefonthandling\showfontadjusting{#1}\fi
+ \pdffontexpand\handledfont
+ \csname\@fha@\@fha@#1\c!max \endcsname\space
+ \csname\@fha@\@fha@#1\c!min \endcsname\space
+ \csname\@fha@\@fha@#1\c!step\endcsname\space
+ \@@pdfexpandbonus\relax}
+
+ \def\showfontadjusting#1%
+ {\writestatus\m!handlings{[adjust]\space#1\space
+ \csname\@fha@\@fha@#1\c!max \endcsname/%
+ \csname\@fha@\@fha@#1\c!min \endcsname/%
+ \csname\@fha@\@fha@#1\c!step\endcsname\space
+ \fontname\handledfont}}
+\fi
+
+\ifx\setfontadjusting\gobbleoneargument \else
+ \appendtoks
+ \setfontadjusting\askedfonthandling
+ \to \everyenablefonthandling
+\fi
+
+% protruding
+
+\newif\ifembasedprotruding \embasedprotrudingfalse
+
+\newdimen\lproddimen \newdimen\rproddimen \let\handledfont\font
+
+\ifx\undefined\pdfprotrudechars % we don't use pdftex
+
+ \let\enableprotruding \relax
+ \let\disableprotruding \relax
+ \let\setprotrudingfactor \gobbleoneargument
+
+ \def\defineprotrudefactor #1 #2 #3 {}
+ \def\inheritprotrudefactor #1 #2 {}
+
+\else
+
+ \def\enableprotruding {\pdfprotrudechars\plustwo}
+ \def\disableprotruding{\pdfprotrudechars\zerocount}
+
+ \appendtoks \disableprotruding \to \everyforgetall % Here or not here?
+
+ \lproddimen1000\onepoint \divide\lproddimen\maxcard
+ \rproddimen1000\onepoint \divide\rproddimen\maxcard
+
+ \def\setprotrudingfactor#1%
+ {\doifvalue{\@fha@\@fha@#1\c!type}\v!hanging{\dosetprotrudingfactor{#1}}}
+
+ \def\dosetprotrudingfactor#1% no \onepoint instead of pt
+ {\lproddimen\dimexpr\csname\@fha@\@fha@#1\c!left \endcsname\onepoint*\plusthousand/\maxcard\relax
+ \rproddimen\dimexpr\csname\@fha@\@fha@#1\c!right\endcsname\onepoint*\plusthousand/\maxcard\relax
+ \iftracefonthandling\showprotrudingfactor{#1}\fi}
+
+ \def\showprotrudingfactor#1%
+ {\writestatus\m!handlings{[protrude]\space#1\space
+ \csname\@fha@\@fha@#1\c!left \endcsname\space
+ \csname\@fha@\@fha@#1\c!right\endcsname\space
+ \fontname\handledfont}}
+
+ % division before multiplication, else overflow with "sa>5"
+
+ \newdimen\protrudethreshold \protrudethreshold=36pt
+
+ \def\dododefineprotrudefactor#1#2#3%
+ {\lpcode\handledfont#1\dimexpr#2\lproddimen
+ \ifembasedprotruding \else
+ \ifdim\emwidth>\protrudethreshold
+ /\emwidth*\fontcharwd\handledfont#1%
+ \else
+ *\fontcharwd\handledfont#1/\emwidth
+ \fi
+ \fi
+ \relax
+ \rpcode\handledfont#1\dimexpr#3\rproddimen
+ \ifembasedprotruding \else
+ \ifdim\emwidth>\protrudethreshold
+ /\emwidth*\fontcharwd\handledfont#1%
+ \else
+ *\fontcharwd\handledfont#1/\emwidth
+ \fi
+ \fi
+ \relax}
+
+ \def\dodoinheritprotrudefactor#1#2%
+ {\lpcode\handledfont#1\lpcode\handledfont#2\relax
+ \rpcode\handledfont#1\rpcode\handledfont#2\relax}
+
+ \def\defineprotrudefactor#1 #2 #3 %
+ {\setfonttoks
+ \let\inherithandling\inheritprotrudefactor
+ \appendtoks\dosetpairhandling\dododefineprotrudefactor#1 #2 #3 \to\fonttoks}
+
+ \def\inheritprotrudefactor#1 #2 %
+ {\setfonttoks
+ \appendtoks\doinhsomehandling\dodoinheritprotrudefactor#1 #2 \to\fonttoks}
+
+\fi
+
+\ifx\setprotrudingfactor\gobbleoneargument \else
+ \appendtoks
+ \setprotrudingfactor\askedfonthandling
+ \to \everyenablefonthandling
+\fi
+
+% Basic support for a new pdftex feature: space factors
+%
+% \knbccode -- kern before char code
+% \knbscode -- kern before space code
+% \stbscode -- stretch before space code
+% \shbscode -- shrink before space code
+%
+% Setting \knsbcode\font`\.=200 means that if a period sits before
+% a interword space (glue), then the interword glue will be increased
+% by an amount of 1em*200/1000, i.e. the value is given in thousandths
+% of an em. (HTT)
+
+\newdimen\spfacdimen
+
+\ifx\undefined\pdfadjustinterwordglue % we don't use pdftex
+
+ \let\enablespacehandling \relax
+ \let\disablespacehandling \relax
+ \let\enablekernhandling \relax
+ \let\disablekernhandling \relax
+
+ \let\setspacehandling \gobbleoneargument
+
+ \def\definespacefactor #1 #2 #3 #4 #5 {}
+ \def\inheritspacefactor #1 #2 {}
+
+\else
+
+ \def\enablespacehandling {\pdfadjustinterwordglue\plusone }
+ \def\disablespacehandling{\pdfadjustinterwordglue\minusone}
+ \def\enablekernhandling {\pdfprependkern \plusone }
+ \def\disablekernhandling {\pdfprependkern \minusone}
+
+ \appendtoks \disablespacehandling \to \everyforgetall % Here or not here?
+
+ \def\dosetspacehandling#1%
+ {\spfacdimen\csname\@fha@\@fha@#1\c!factor\endcsname\s!pt
+ \multiply\spfacdimen\plusthousand\divide\spfacdimen\maxcard\relax}
+
+ \def\setspacehandling#1%
+ {\doifvalue{\@fha@\@fha@#1\c!type}\v!spacing{\dosetspacehandling{#1}}}
+
+ \def\dododefinespacefactor#1#2#3#4#5%
+ {\sfcode#1\plusthousand
+ \knbccode\handledfont#1\dimexpr#2\spfacdimen\relax
+ \knbscode\handledfont#1\dimexpr#3\spfacdimen\relax
+ \stbscode\handledfont#1\dimexpr#4\spfacdimen\relax
+ \shbscode\handledfont#1\dimexpr#5\spfacdimen\relax}
+
+ \def\dodoinheritspacefactor#1#2%
+ {\sfcode#1\plusthousand
+ \knbccode\handledfont#1\knbccode\handledfont#2\relax
+ \knbscode\handledfont#1\knbscode\handledfont#2\relax
+ \stbscode\handledfont#1\stbscode\handledfont#2\relax
+ \shbscode\handledfont#1\shbscode\handledfont#2\relax}
+
+ \def\definespacefactor#1 #2 #3 #4 #5 %
+ {\setfonttoks
+ \let\inherithandling\inheritspacefactor
+ \appendtoks\dosetquartethandling\dododefinespacefactor#1 #2 #3 #4 #5 \to\fonttoks}
+
+ \def\inheritspacefactor#1 #2 %
+ {\setfonttoks
+ \appendtoks\doinhsomehandling\dodoinheritspacefactor#1 #2 \to\fonttoks}
+
+\fi
+
+\ifx\setspacehandling\gobbleoneargument \else
+ \appendtoks
+ \setspacehandling\askedfonthandling
+ \to \everyenablefonthandling
+\fi
+
+% font attributes
+
+\let\notagcode\minusone
+
+\ifx\tagcode\undefined
+
+ \def\settagcode #1 #2 {}
+
+\else
+
+ \def\dodosettagcode#1#2%
+ {\tagcode\handledfont#1 #2\relax}
+
+ \def\settagcode#1 #2 %
+ {\setfonttoks
+ \appendtoks\dosetsomehandling\dodosettagcode#1 #2 \to\fonttoks}
+
+\fi
+
+% hook into font mechanism
+
+\let\fonthandling\empty
+
+\def\startfonthandling[#1]%
+ {\def\fonthandling{#1}%
+ \ifcsname\@fha@\fonthandling\endcsname\else
+ \expandafter\newtoks\csname\@fha@\fonthandling\endcsname
+ \fi
+ \setfonttoks}
+
+\def\stopfonthandling
+ {\let\fonthandling\empty}
+
+\def\setfonttoks
+ {\@EA\let\@EA\fonttoks\csname\@fha@\fonthandling\endcsname}
+
+\def\definefonthandling
+ {\dotripleempty\dodefinefonthandling}
+
+\def\dodefinefonthandling[#1][#2][#3]%
+ {\ifthirdargument
+ \setvalue{\@fha@\@fha@#1}{#2}%
+ \getparameters
+ [\@fha@\@fha@#1]
+ [\c!type=\v!hanging,%
+ \c!left=1,\c!right=1,%
+ \c!min=20,\c!max=20,\c!step=5,%
+ \c!factor=1,%
+ #3]%
+ \else
+ \setvalue{\@fha@\@fha@\@fha@#1}{#2}%
+ \fi}
+
+\def\setupfonthandling
+ {\dodoubleempty\dosetupfonthandling}
+
+\def\dosetupfonthandling[#1][#2]%
+ {\getparameters[\@fha@\@fha@#1][#2]}
+
+\def\enablehandling
+ {\dodoubleempty\doenablehandling}
+
+\def\doenablehandling[#1][#2]% handling / symbolic fontname
+ {\fastenablehandling{#1}{#2}} % for the moment the same as:
+
+\def\fastenablehandling#1#2% also gets #2 passed
+ {\edef\askedfonthandling{#1}%
+ \edef\filoffonthandling{#2}%
+ \ifcsname\@fha@\@fha@\@fha@\askedfonthandling\endcsname
+ \@EA\redofastenablehandling
+ \else\ifcsname\@fha@\@fha@\askedfonthandling\endcsname
+ \@EAEAEA\dofastenablehandling
+ \else
+ \@EAEAEA\nofastenablehandling
+ \fi\fi}
+
+\def\xfastenablehandling#1%
+ {\edef\askedfonthandling{#1}%
+ \ifcsname\@fha@\@fha@\askedfonthandling\endcsname
+ \@EA\dofastenablehandling
+ \else
+ \@EA\nofastenablehandling
+ \fi}
+
+\def\redofastenablehandling
+ {\startdirectcharacters
+ \edef\fonthandling{\csname\@fha@\@fha@\@fha@\askedfonthandling\endcsname}%
+ \rawprocesscommacommand[\fonthandling]\xfastenablehandling
+ \stopdirectcharacters}
+
+\def\dofastenablehandling
+ {\startdirectcharacters
+ \the\everyenablefonthandling
+ \edef\fonthandling{\csname\@fha@\@fha@\askedfonthandling\endcsname}%
+ \checkfonthandling\filoffonthandling
+ \rawprocesscommacommand[\fonthandling]\dodoenablehandling
+ \registerfonthandling\filoffonthandling
+ \stopdirectcharacters}
+
+\def\nofastenablehandling
+ {\the\everyenablefonthandling
+ \let\fonthandling\askedfonthandling
+ \dodoenablehandling\fonthandling}
+
+\def\dodoenablehandling#1%
+ {\ifcsname\@fha@#1\endcsname
+ \the\csname\@fha@#1\endcsname
+ \fi}
+
+%D We must not use \type {\purefontname} here (was a bug)!
+
+% not robust as long as tex reuses definitions internally
+%
+% \def\checkfonthandling#1% we need a fast compare
+% {\doifelsevalue{#1\s!handling\c!file}{\fontname\font}
+% \skiphandlingdeftrue\skiphandlingdeffalse}
+%
+% \def\registerfonthandling#1%
+% {\@EA\xdef\csname#1\s!handling\c!file\endcsname{\fontname\font}}
+
+\def\checkfonthandling #1{\skiphandlingdeffalse}
+\let\registerfonthandling \gobbleoneargument
+
+%D This one makes live easier (less definitions):
+
+\def\inherithandling #1 #2 %
+ {\inheritprotrudefactor #1 #2 %
+ \inheritadjustfactor #1 #2 }
+
+%D \macros
+%D {usehandling}
+%D
+%D Handling definitions are collected in dedicated files and
+%D loaded only once:
+%D
+%D % \showsetup{usehandling}
+
+\def\dousehandling#1% is the same as encoding
+ {\doifundefined{\c!file\f!handlingprefix#1}%
+ {\letvalueempty{\c!file\f!handlingprefix#1}%
+ \makeshortfilename[\truefilename{\f!handlingprefix#1}]%
+ \startreadingfile
+ \readsysfile{\shortfilename.mkii}
+ {\showmessage\m!handlings2{#1}}
+ {\showmessage\m!handlings3{#1}}%
+ \stopreadingfile}}
+
+\def\usehandling[#1]%
+ {\processcommalist[#1]\dousehandling}
+
+%D New:
+
+\def\overloadcharacter#1 #2 %
+ {\setfonttoks
+ \doifnumberelse{\string#2}
+ {\appendtoks\dooverloadcharacter{#1}{\char#2 }\to\fonttoks}
+ {\appendtoks\dooverloadcharacter{#1}{#2}\to\fonttoks}}
+
+\def\dooverloadcharacter#1%
+ {\setvalue{\characterencoding\string#1}}
+
+%D Let's now see if this macro works:
+
+% \setupfonthandling
+% [\s!default]
+% [\c!links=1,\c!rechts=1,\c!min=20,\c!max=20,\c!stap=5]
+
+% Beware of fonttoks:
+%
+% \startfonthandling[morespacing]
+% \appendtoks
+% \fontdimen2\handledfont=.50em
+% \fontdimen3\handledfont=.25em
+% \fontdimen4\handledfont=.25em
+% \to \fonttoks
+% \stopfonthandling
+%
+% \definefonthandling [morespacing] [morespacing]
+%
+% \definefontsynonym[xtexnansi-lmr7][texnansi-lmr7][handling=morespacing]
+% \definefont[crap][texnansi-lmr7]
+%
+% \crap \the\fontdimen2\font, \the\fontdimen3\font, \the\fontdimen4\font
+
+\usehandling [def]
+
+\protect \endinput
diff --git a/tex/context/base/hand-ini.mkiv b/tex/context/base/hand-ini.mkiv
new file mode 100644
index 000000000..0285b10cb
--- /dev/null
+++ b/tex/context/base/hand-ini.mkiv
@@ -0,0 +1,74 @@
+%D \module
+%D [ file=hand-ini,
+%D version=2008.02.12,
+%D title=\CONTEXT\ Handling Macros,
+%D subtitle=Initialization,
+%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.
+
+%D Handling is implemented differently in \MKIV. Maybe I'll cook up
+%D some compatibility hack.
+
+% \definefontfeature[demo][default][mode=node,expansion=quality]
+% \definefontfeature[demo][default][mode=node,protrusion=pure]
+
+% experimental setup:
+%
+% \showframe \setupalign[hanging] \enabletrackers[fonts.protrusion]
+%
+% \definefontfeature[default] [default][mode=node,script=latn]
+% %definefontfeature[whatever][default][mode=node,lfbd=yes,rtbd=yes,script=latn]
+% \definefontfeature[whatever][default][mode=node,protrusion=quality]
+% \definefontfeature[whocares][default][mode=node,protrusion=yes,opbd=yes,script=latn] % left|right|yes
+%
+% \definedfont[fxlbi.otf*default] \input tufte 0123456789 \par \dorecurse{15}{1 2 3 4 5 6 7 8 9 0 } \par
+% \definedfont[fxlbi.otf*whatever] \input tufte 0123456789 \par \dorecurse{15}{1 2 3 4 5 6 7 8 9 0 } \par
+% \definedfont[fxlbi.otf*whocares] \input tufte 0123456789 \par \dorecurse{15}{1 2 3 4 5 6 7 8 9 0 } \par
+%
+% %definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn,featurefile=texgyrepagella-regularxx.fea]
+% \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn]
+%
+% \definedfont[texgyrepagella-regularxx.otf*whocares] \input tufte
+
+\unprotect
+
+%D New stuff.
+
+\unexpanded\def\setupfontexpansion {\dodoubleargument\dosetupfontexpansion }
+\unexpanded\def\setupfontprotrusion{\dodoubleargument\dosetupfontprotrusion}
+
+\def\dosetupfontexpansion [#1][#2]{\ctxlua{commands.setupfontexpansion ("#1","#2")}}
+\def\dosetupfontprotrusion[#1][#2]{\ctxlua{commands.setupfontprotrusion("#1","#2")}}
+
+% \setupfontprotrusion[quality-upright][vector=quality]
+% \setupfontprotrusion[quality-slanted][vector=quality,right=1.5]
+
+%D Old stuff.
+
+\def\fonthandlingerror{\writestatus\m!fonts{font handling is replaced by features in mkiv}}
+
+\def\enableadjusting {\pdfadjustspacing\plustwo } \let\enableexpansion \enableadjusting
+\def\disableadjusting {\pdfadjustspacing\zerocount} \let\disableexpansion\disableadjusting
+\def\enableprotruding {\pdfprotrudechars\plustwo }
+\def\disableprotruding{\pdfprotrudechars\zerocount}
+
+\appendtoks \disableadjusting \to \everyforgetall % Here or not here?
+\appendtoks \disableprotruding \to \everyforgetall % Here or not here?
+
+\unexpanded\def\startfonthandling #1{\fonthandlingerror\fonthandlingerror\gobbleuntil\stopfonthandling} % can't happen
+\unexpanded\def\definefonthandling {\dotripleempty\dodefinefonthandling}
+\unexpanded\def\setupfonthandling {\dodoubleempty\dosetupfonthandling }
+\def\dodefinefonthandling[#1][#2][#3]{\fonthandlingerror}
+\def\dosetupfonthandling [#1][#2]{\fonthandlingerror}
+\def\usehandling [#1]{\fonthandlingerror}
+
+%D Just to be sure, maybe users use it:
+
+\let\fonthandling\empty
+
+\protect \endinput
diff --git a/tex/context/base/java-ans.tex b/tex/context/base/java-ans.tex
new file mode 100644
index 000000000..636c894f9
--- /dev/null
+++ b/tex/context/base/java-ans.tex
@@ -0,0 +1,28 @@
+%D \module
+%D [ file=java-ans,
+%D version=1998.06.01,
+%D title=\CONTEXT\ JavaScript Macros,
+%D subtitle=Answer Analization,
+%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.
+
+\startJSpreamble{Do_Check_Answer} used later
+
+ function Do_Check_Answer (field, value)
+ { if (event.value.toLowerCase()==value.toLowerCase())
+ { event.target.hidden = true }
+ % { event.target.display = display.hidden }
+ return("\040") } // funny, "" does not work
+
+\stopJSpreamble
+
+\startJScode{Check_Answer} uses {Do_Check_Answer}
+ event.value = Do_Check_Answer(JS_S_1, JS_S_2) ;
+\stopJScode
+
+\endinput
diff --git a/tex/context/base/java-exa.tex b/tex/context/base/java-exa.tex
new file mode 100644
index 000000000..f40f70f84
--- /dev/null
+++ b/tex/context/base/java-exa.tex
@@ -0,0 +1,395 @@
+%D \module
+%D [ file=java-exa,
+%D version=2002.??.??,
+%D title=\CONTEXT\ JavaScript Macros,
+%D subtitle=Example 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.
+
+% XFDF versus HTML
+% localhost versus remote versus set
+
+% filename | filename-nr => name
+% fakename | fakename-nr => file upload, unless localhost
+%
+% we erase the list because otherwise we end up in browser remembering
+% problems; also, it is not possible to set upload fields 'manually'
+
+\startJSpreamble request_1 used now
+
+ var example_method = "HTML" ;
+ var example_host = "" ;
+ var example_port = "" ;
+ var example_url = "" ;
+ var example_file = "" ;
+
+ var example_log = true ; % false
+
+ function stripped_exa_value( name ) {
+ f = this.getField(name) ;
+ if (f) {
+ str = f.value ;
+ if (str.indexOf(name+'-')==0) {
+ str = str.substr(name.length+1) ;
+ }
+ return str ;
+ } else {
+ return "" ;
+ }
+ }
+
+ function identify_example_url ( ) {
+ if (example_log) {
+ console.clear ;
+ console.println("base url: "+this.baseURL) ;
+ console.println("this url: "+this.URL) ;
+ }
+ if (this.baseURL != "") {
+ example_url = this.baseURL ;
+ } else {
+ if (this.URL != "") {
+ example_url = this.URL
+ }
+ }
+ if (example_url.indexOf("file://")>=0) {
+ example_url = "" ;
+ }
+ str = stripped_exa_value("examplehost") ;
+ if (str != "auto") {
+ example_host = str ;
+ if (str == "localhost") {
+ example_port = "8061"
+ }
+ }
+ str = stripped_exa_value("exampleport") ;
+ if (str != "auto") {
+ example_port = str ;
+ }
+ if (example_log) {
+ console.println("example_url: "+example_url) ;
+ console.println("example_host: "+example_host) ;
+ console.println("example_port: "+example_port) ;
+ }
+ }
+
+ function check_example_url ( url ) {
+ if (url.indexOf("file://")>=0) {
+ url = "http://localhost:8061" ;
+ console.println("file url replaced by: "+url) ;
+ } else {
+ if (url.indexOf("://")<0) {
+ url = "http://" + url ;
+ }
+ if (example_log) {
+ console.println("url before check: "+url) ;
+ }
+% url = url.replace(/(http:\\\/\\\/.+)(\\\/.*$)/, "$1") ;
+ url = url.replace(/(https*:\\\/\\\/.+?)(\\\/.*$)/, "$1/exarequest") ;
+ if (example_log) {
+ console.println("url after check: "+url) ;
+ }
+ }
+ return url ;
+ }
+
+ function set_example_xfdf ( method ) {
+ example_method = method ;
+ }
+
+ function set_example_file ( file ) {
+ example_method = file ;
+ }
+
+ function set_example_host ( host ) {
+ example_host = host ;
+ }
+
+ function set_example_port ( port ) {
+ example_host = host ;
+ }
+
+ function do_erase_example_file(tag) {
+ f = this.getField(tag) ;
+ if (f) {
+ f.value = "" ;
+ }
+ }
+
+ function do_erase_example_list(tag) {
+ for (i=1;i<=100;i++) {
+ f = this.getField(tag+"-"+i) ;
+ if (f) {
+ f.value = "" ;
+ } else {
+ return
+ }
+ }
+ }
+
+ function do_submit_example_url ( url ) {
+ if ((example_method == "XFDF" ) || (url.indexOf("localhost")>=0)) {
+ do_erase_example_file("fakename") ;
+ do_erase_example_list("fakename") ;
+ }
+ url = check_example_url(url) ;
+ if (example_log) {
+ console.println("submitting form to "+url+" using method "+example_method) ;
+ }
+ if (example_file != "") {
+ url = url + "/" + example_file ;
+ }
+ % we need the bFDF for acrobat 5
+ this.submitForm({cURL : url, bFDF : false, cSubmitAs : example_method}) ;
+ }
+
+ function submit_example_form ( ) {
+ identify_example_url() ;
+ if (example_host != "") {
+ if (example_port != "") {
+ do_submit_example_url(example_host+":"+example_port) ;
+ } else {
+ do_submit_example_url(example_host) ;
+ }
+ } else {
+ if (example_url != "") {
+ do_submit_example_url(example_url) ;
+ } else {
+ if (example_port != "") {
+ do_submit_example_url("localhost"+":"+example_port) ;
+ } else {
+ do_submit_example_url("localhost:8061") ; % local exampler
+ }
+ }
+ }
+ resetfilename () ;
+ }
+
+ function submit_form ( host, port) {
+ set_example_host(host) ;
+ set_example_post(post) ;
+ submit_example_form ;
+ }
+
+\stopJSpreamble
+
+\startJSpreamble request_2 used now
+
+ var exa_command = "" ;
+ var exa_option = "" ;
+ var exa_filename = "" ;
+ var exa_filelist = "" ;
+ var exa_registered = "" ;
+
+ function set_request (command,option) {
+ exa_command = command ;
+ if (exa_command == "") {
+ exa_option = option ;
+ } else { if (option == "") {
+ exa_option = "" ;
+ } else { if (option.indexOf("--")<0) {
+ exa_option = "--action=" + option ;
+ } else {
+ exa_option = option ;
+ } } }
+ }
+
+ function assemble_request ( ) {
+ v = this.getField('filename') ;
+ if (v) {
+ exa_filename = v.value ;
+ }
+ v = this.getField('filelist') ;
+ if (v) {
+ exa_filelist = v.value ;
+ }
+% exa_filename = exa_filename.replace(/\\\\/g,'/') ;
+% exa_filelist = exa_filelist.replace(/\\\\/g,'/') ;
+ str = "\\n" ;
+ str = str+"" ;
+ if (exa_filelist == "") {
+ exa_filelist = exa_registered ;
+ } else { if (exa_registered != "") {
+ exa_filelist = exa_filelist + "\\n" + exa_registered ;
+ } }
+ if (exa_command != "") {
+ str = str+""+exa_command+"" ;
+ }
+ if (exa_option != "") {
+ str = str+""+exa_option+"" ;
+ }
+ if (exa_filename != "") {
+ str = str+""+exa_filename+"" ;
+ }
+ var fls = "" ;
+ if (exa_filelist != "") {
+ % old method, soon obsolete
+ lst = exa_filelist.split(/\\s/) ;
+ for (i=0;i"+lst[i]+"" ;
+ }
+ } else { if (exa_multiple) {
+ for (i=1;i<=100;i++) {
+ % console.println("file field "+i) ;
+ f = this.getField("filename-"+ i) ;
+% if (f) { if (f.value != "") {
+% if (g) { if (g.value == "") {
+% fls = fls+""+f.value+"" ;
+% } else {
+% fls = fls+""+f.value+"" ;
+% } } else {
+% fls = fls+""+f.value+"" ;
+% }
+% } }
+ if (f) { if (f.value != "") {
+ fls = fls + "" ;
+ } else {
+ % console.println("b") ;
+ fls = fls + " label='" + g.value + "'>" ;
+ } } else {
+ % console.println("c") ;
+ fls = fls + ">" ;
+ }
+ fls = fls + f.value + "" ;
+ } }
+ }
+ } }
+ if (fls != "") {
+ str = str + "" + fls + "" ;
+ }
+ str = str + "" ;
+ v = this.getField('exa:request') ;
+ if (v) {
+ v.value = str ;
+ }
+ }
+
+\stopJSpreamble
+
+\startJSpreamble request_3 used now
+
+ var exa_multiple = false ;
+
+ function setfilename ( suffixes ) {
+ if (event.targetName) {
+ var name = event.targetName ;
+ var fake = name.replace(/filename/,"fakename") ;
+ } else {
+ var name = 'filename' ;
+ var fake = 'fakename' ;
+ }
+ f = this.getField(fake) ;
+ if (f) {
+ f.browseForFileToSubmit() ;
+ if ((suffixes != "") && (f.value != "")) {
+ %
+ s = suffixes.replace(/,/g,"|") ;
+ r = new RegExp() ;
+ s = "\\\\.(" + s + ")$" ;
+ r.compile(s, "i") ;
+ if (f.value.search(r)<=0) {
+ f.value = "" ;
+ app.alert('This filetype is not permitted.') ;
+ %
+ % lst = suffixes.split(/,/) ;
+ % ok = false ;
+ % for (i=0;i=0) {
+% f.value = "" ;
+% }
+% }
+ }
+ this.dirty = false ;
+ }
+
+ function addfilename () {
+ if (exa_multiple) {
+ h = this.getField("filelist") ;
+ g = this.getField("filename") ;
+ if ((g) && (h)) {
+ str = g.value ;
+ if (h.value == "") {
+ h.value = str ;
+ } else {
+ h.value = h.value + "\\n" + str ;
+ }
+ g.value = "" ;
+ this.value = "" ;
+ }
+ }
+ this.dirty = false ;
+ }
+
+ % this only works with client that assembles request
+
+ function registerfilename (str) {
+ if (str!="") {
+ h = this.getField("filelist") ;
+ if (h) {
+ if (h.value != "") {
+ h.value = h.value + "\\n" ;
+ }
+ h.value = h.value + str ;
+ } else {
+ if (exa_registered != "") {
+ exa_registered = exa_registered + "\\n" ;
+ }
+ exa_registered = exa_registered + str ;
+ }
+ }
+ console.show ;
+ console.println('registered files') ;
+ console.println("file: "+str) ;
+ console.println("list: "+exa_registered) ;
+ this.dirty = false ;
+ }
+
+ function checkfilename () {
+ }
+
+ function getfilename ( suffixes ) {
+ setfilename(suffixes) ;
+ checkfilename() ;
+ addfilename() ;
+ }
+
+ function resetfilename () {
+ do_erase_example_file("fakename") ;
+ do_erase_example_file("filename") ;
+ do_erase_example_file("filelist") ;
+ do_erase_example_list("filename") ;
+ do_erase_example_list("fakename") ;
+ }
+
+\stopJSpreamble
+
+\endinput
diff --git a/tex/context/base/java-fil.tex b/tex/context/base/java-fil.tex
new file mode 100644
index 000000000..4d79a2ace
--- /dev/null
+++ b/tex/context/base/java-fil.tex
@@ -0,0 +1,48 @@
+%D \module
+%D [ file=java-fil,
+%D version=1998.06.01,
+%D title=\CONTEXT\ JavaScript Macros,
+%D subtitle=Filing and Printing,
+%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.
+
+\startJSpreamble Auxiliary used now
+
+ function DocumentFileName ()
+ { var Paths = this.path.split("/") ;
+ Paths = Paths[Paths.length-1].split(".") ;
+ return(Paths[0]) }
+
+ function Print_Page_Range(From, To) % gaat mis, nog geen args mogelijk
+ { if ((Number(From)>0)&&(Number(To)>=Number(From)))
+ { var myFrom = Number(From)-1 ;
+ var myTo = Number(To)-1 ;
+ this.print(false,myFrom,myTo,true) } }
+
+ function Print_This_Page ()
+ { this.print(false,this.pageNum,this.pageNum,true) }
+
+\stopJSpreamble
+
+\definereference
+ [PrintSubPaginas]
+ [JS(Print_Page_Range{\firstsubpage,\lastsubpage})]
+
+\definereference
+ [PrintSubPages]
+ [JS(Print_Page_Range{\firstsubpage,\lastsubpage})]
+
+\definereference
+ [PrintDezePagina]
+ [JS(Print_This_Page)]
+
+\definereference
+ [PrintThisPage]
+ [JS(Print_This_Page)]
+
+\endinput
diff --git a/tex/context/base/java-fld.tex b/tex/context/base/java-fld.tex
new file mode 100644
index 000000000..3c24b7e02
--- /dev/null
+++ b/tex/context/base/java-fld.tex
@@ -0,0 +1,282 @@
+%D \module
+%D [ file=java-fld,
+%D version=1998.05.20,
+%D title=\CONTEXT\ JavaScript Macros,
+%D subtitle=Field 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.
+
+% will be simplified, since we now parse functions
+
+% nu nog alles geladen, moet dus anders
+
+\startJSpreamble {Sanitize_TeX_Input} used later
+
+ function Sanitized_TeX_String (value)
+ { var v = value ;
+ v = v.replace( /\\\\oe/g,"\\234") ;
+ v = v.replace( /\\\\<>/g,"\\273") ;
+ v = v.replace( /\\\\`A/g,"\\300") ;
+ v = v.replace( /\\\\'A/g,"\\301") ;
+ v = v.replace( /\\\\^A/g,"\\302") ;
+ v = v.replace( /\\\\~A/g,"\\303") ;
+ v = v.replace( /\\\\"A/g,"\\304") ;
+ v = v.replace( /\\\\oA/g,"\\305") ;
+ v = v.replace( /\\\\AE/g,"\\306") ;
+ v = v.replace( /\\\\,C/g,"\\307") ;
+ v = v.replace( /\\\\`E/g,"\\310") ;
+ v = v.replace( /\\\\'E/g,"\\311") ;
+ v = v.replace( /\\\\^E/g,"\\312") ;
+ v = v.replace( /\\\\"E/g,"\\313") ;
+ v = v.replace( /\\\\`I/g,"\\314") ;
+ v = v.replace( /\\\\'I/g,"\\315") ;
+ v = v.replace( /\\\\^I/g,"\\316") ;
+ v = v.replace( /\\\\"I/g,"\\317") ;
+ v = v.replace( /\\\\~N/g,"\\321") ;
+ v = v.replace( /\\\\`O/g,"\\322") ;
+ v = v.replace( /\\\\'O/g,"\\323") ;
+ v = v.replace( /\\\\^O/g,"\\324") ;
+ v = v.replace( /\\\\~O/g,"\\325") ;
+ v = v.replace( /\\\\"O/g,"\\326") ;
+ v = v.replace( /\\\\`U/g,"\\331") ;
+ v = v.replace( /\\\\'U/g,"\\332") ;
+ v = v.replace( /\\\\^U/g,"\\333") ;
+ v = v.replace( /\\\\"U/g,"\\334") ;
+ v = v.replace( /\\\\'Y/g,"\\335") ;
+ v = v.replace( /\\\\ss/g,"\\337") ;
+ v = v.replace( /\\\\`a/g,"\\340") ;
+ v = v.replace( /\\\\'a/g,"\\341") ;
+ v = v.replace( /\\\\^a/g,"\\342") ;
+ v = v.replace( /\\\\~a/g,"\\343") ;
+ v = v.replace( /\\\\"a/g,"\\344") ;
+ v = v.replace( /\\\\oa/g,"\\345") ;
+ v = v.replace( /\\\\ae/g,"\\346") ;
+ v = v.replace( /\\\\,c/g,"\\347") ;
+ v = v.replace( /\\\\`e/g,"\\350") ;
+ v = v.replace( /\\\\'e/g,"\\351") ;
+ v = v.replace( /\\\\^e/g,"\\352") ;
+ v = v.replace( /\\\\"e/g,"\\353") ;
+ v = v.replace( /\\\\`i/g,"\\354") ;
+ v = v.replace( /\\\\'i/g,"\\355") ;
+ v = v.replace( /\\\\^i/g,"\\356") ;
+ v = v.replace( /\\\\"i/g,"\\357") ;
+ v = v.replace( /\\\\~n/g,"\\361") ;
+ v = v.replace( /\\\\`o/g,"\\362") ;
+ v = v.replace( /\\\\'o/g,"\\363") ;
+ v = v.replace( /\\\\^o/g,"\\364") ;
+ v = v.replace( /\\\\~o/g,"\\365") ;
+ v = v.replace( /\\\\"o/g,"\\366") ;
+ v = v.replace( /\\\\`u/g,"\\371") ;
+ v = v.replace( /\\\\'u/g,"\\372") ;
+ v = v.replace( /\\\\^u/g,"\\373") ;
+ v = v.replace( /\\\\"u/g,"\\374") ;
+ v = v.replace( /\\\\'y/g,"\\375") ;
+ v = v.replace( /\\\\"y/g,"\\377") ;
+ return(v) }
+
+ var TeX_Key_Mode = 0 ;
+
+ function Initialize_TeX_Keystroke ()
+ { TeX_Key_Char = "" ;
+ TeX_Key_Mode = 0 }
+
+ function Sanitized_TeX_Keystroke (change)
+ { if (change=="\\\\")
+ { TeX_Key_Mode = 1 ;
+ return("") }
+ else if (TeX_Key_Mode==1)
+ { TeX_Key_Mode = 2 ;
+ TeX_Key_Char = change ;
+ return("") }
+ else if (TeX_Key_Mode==2)
+ { TeX_Key_Mode = 0 ;
+ TeX_Key_Char = "\\\\"+TeX_Key_Char+change ;
+ return(Sanitized_TeX_String(TeX_Key_Char)) }
+ else
+ { TeX_Key_Mode = 0 ;
+ return(change) } }
+
+\stopJSpreamble
+
+\startJScode {Initialize_TeX_Key} uses {Sanitize_TeX_Input}
+ Initialize_TeX_Keystroke() ;
+\stopJScode
+
+\startJScode {Convert_TeX_Key} uses {Sanitize_TeX_Input}
+ if (!event.willCommit)
+ { event.change = Sanitized_TeX_Keystroke(event.change) }
+\stopJScode
+
+\startJScode{Convert_TeX_String} uses {Sanitize_TeX_Input}
+ event.value = Sanitized_TeX_String(event.value) ;
+\stopJScode
+
+\startJSpreamble fields_1 used now
+
+var visible_field = new Array() ;
+var visible_fields = 0 ;
+
+function PresetFields ( )
+ { this.syncAnnotScan() }
+
+function Preset_Fields ( )
+ { this.syncAnnotScan() }
+
+function Hide_When_Down ( )
+ { event.target.hidden = true }
+
+function Hide_Field ( Name )
+ { var v = this.getField(Name) ;
+ if (v)
+ { v.hidden = true ;
+ v.readonly = true ;
+ this.dirty = false } }
+
+function Do_Vide_Field ( Name, Closable )
+ { var v = this.getField(Name) ;
+ if (v)
+ { ++visible_fields ;
+ visible_field[visible_fields] = Name ;
+ v.hidden = false ;
+ if (Closable)
+ { v.readonly = false ;
+ v.value = "On" }
+ this.dirty = false } }
+
+function Vide_Field ( Name )
+ { Do_Vide_Field(Name,false) }
+
+function Vide_Hide_Field ( Name )
+ { Do_Vide_Field(Name,true) }
+
+function Hide_Fields ()
+ { while (visible_fields>0)
+ { Hide_Field(visible_field[visible_fields]) ;
+ --visible_fields } }
+
+function Vide_Fields ( Name )
+ { Hide_Fields () ;
+ Vide_Field ( Name) }
+
+function Vide_Hide_Fields ( Name )
+ { Hide_Fields () ;
+ Vide_Hide_Field ( Name) }
+
+function Toggle_Hide ( Name )
+ { var v = this.getField(Name) ;
+ if (v)
+ { v.hidden = !v.hidden ;
+ this.dirty = false } }
+
+function Field_On ( Name )
+ { v = this.getField(Name) ;
+ if (v) { v.value = "On" ; this.dirty = false } }
+
+function Field_Off ( Name )
+ { var v = this.getField(Name) ;
+ if (v) { v.value = "Off" ; this.dirty = false } }
+
+function Toggle_Value ( Name )
+ { var v = this.getField(Name) ;
+ if (v)
+ { if (v.value=="On")
+ { v.value = "Off" }
+ else
+ { v.value = "On" } }
+ this.dirty = false }
+
+function Toggle_Read ( Name )
+ { var v = this.getField(Name);
+ if (v) { v.readonly = !v.readonly } }
+
+function Flip_Fields ( Name )
+ { var Names = Name.split(",") ;
+ for (var i=0;i0) && (JS_R_1!=""))
+%D { gotoNamedDest(JS_R_1) };
+%D \stopJScode
+%D \stoptyping
+%D
+%D Such a piece of code is closely related to the interpreter
+%D used. Watch the last two lines, here the script adapts
+%D itself to the presence of a reference.
+%D
+%D While
+%D
+%D \starttyping
+%D \startJScode{name}
+%D name = 4 ;
+%D \stopJScode
+%D \stoptyping
+%D
+%D assumes uses no preamble or presumes that the preamble is
+%D always loaded, the next definition also tells \CONTEXT\ to
+%D actually include the preamble needed.
+%D
+%D \starttyping
+%D \startJScode{uses} uses {later}
+%D uses = 6 ;
+%D \stopJScode
+%D \stoptyping
+
+\long\def\startJScode#1 #2
+ {\doifelse{#2}{uses}
+ {\dostartJScodeA{#1}}
+ {\dostartJScodeB{#1} #2 }}
+
+\long\def\dostartJScodeA#1#2 #3\stopJScode
+ {\long\setgvalue{\r!java#1}{\do{#2}{#3}}}
+
+\long\def\dostartJScodeB#1#2\stopJScode
+ {\long\setgvalue{\r!java#1}{\do{}{#2}}}
+
+\let\stopJScode\relax
+
+%D \macros
+%D {presetJScode}
+%D
+%D The code can be retrieved by saying
+%D
+%D \starttyping
+%D \presetJScode{SomeScript}{template}
+%D \stoptyping
+%D
+%D Such a template is a comma separated list, where
+%D individual entries can optionally be transformed by
+%D \type{R{}} and \type{V{}}.
+%D
+%D After this call, the code is available in \type{\JScode}.
+
+\newif\ifdirectJScode
+
+\def\presetJScode#1#2% #1=operation #2=arguments
+ {\setverbosecscharacters
+ \def\par{\delcharacter}% was: { }
+ \scratchcounter\zerocount
+ \globallet\JScode\empty
+ \def\do##1##2%
+ {\doifelse{##2}{!}\directJScodetrue\directJScodefalse}%
+ \getvalue{\r!java#1}%
+ \edef\!!stringa{#2}%
+ \ifx\!!stringa\empty \else
+ \processcommacommand[\!!stringa]\dopresetJSvariables
+ \fi
+ \def\docommand##1%
+ {\doifundefinedelse{\r!java\r!java##1}
+ {\showmessage\m!javascript2{##1}}
+ {\useJSpreamblenow{##1}}}%
+% {\doglobal\increment\currentJSpreamble
+% \doglobal\addtocommalist{##1}\allJSpreambles}}%
+ \def\do##1##2%
+ {\xdef\JScode{\ifdirectJScode#1(\JScode)\else\JScode##2\fi}%
+ %\xdef\JScode{JS\string_N=\the\scratchcounter;\JScode}%
+ \processcommalist[##1]\docommand}%
+ \getvalue{\r!java#1}}
+
+\def\dopresetJSvariables#1%
+ {\advance\scratchcounter \plusone
+ \donefalse
+ \dodopresetJSvariables#1\end}%
+
+\def\dodopresetJSvariables
+ {\doifnextcharelse R\dodopresetJSrefvariables
+ {\doifnextcharelse V\dodopresetJSvervariables
+ {\doifnextcharelse S\dodopresetJSstrvariables
+ \dodopresetJSrawvariables}}}
+
+\def\dodopresetJSrefvariables R#1\end
+ {\doifreferencefoundelse{#1}
+ {\donetrue \dododopresetJSvariables R{\referenceprefix#1}%
+ \donefalse\dododopresetJSvariables P{\currentrealreference}}
+ {\unknownreference{#1}}%
+ \ifminimalizeJScode \else
+ \donetrue\dododopresetJSvariables S{#1}%
+ \fi}
+
+\def\dodopresetJSvervariables V#1\end
+ {\donefalse\dododopresetJSvariables V{#1}%
+ \ifminimalizeJScode \else
+ \donetrue\dododopresetJSvariables S{#1}%
+ \fi}
+
+\def\dodopresetJSstrvariables S#1\end
+ {\donetrue\dododopresetJSvariables S{#1}}
+
+\def\dodopresetJSrawvariables #1\end
+ {\donetrue\dododopresetJSvariables S{#1}}
+
+\def\JSprefix#1%
+ {JS\string_#1\string_\the\scratchcounter}
+
+\def\dododopresetJSvariables#1#2%
+ {\iftraceJScode
+ \writestatus{JavaScript}{\JSprefix#1=#2}
+ \xdef\JScode{\JScode console.println("\JSprefix#1=#2"); }%
+ \fi
+ \ifdirectJScode
+ \xdef\JScode{\ifx\JScode\empty\else\JScode,\fi\ifdone"#2"\else#2\fi}%
+ \else
+ \xdef\JScode{\JScode\JSprefix#1=\ifdone"#2"\else#2\fi; }%
+ \fi}
+
+%D \macros
+%D {startJSpreamble, flushJSpreamble}
+%D
+%D One can define insert \JAVASCRIPT\ code at the document level
+%D by using:
+%D
+%D \starttyping
+%D \startJSpreamble{oeps}
+%D oeps = 1 ;
+%D \stopJSpreamble
+%D \stoptyping
+%D
+%D which is the same as:
+%D
+%D \starttyping
+%D \startJSpreamble{now} used now
+%D now = 2 ;
+%D \stopJSpreamble
+%D \stoptyping
+%D
+%D while the next definition is only included when actually
+%D used.
+%D
+%D \starttyping
+%D \startJSpreamble{later} used later
+%D later = 3 ;
+%D \stopJSpreamble
+%D \stoptyping
+%D
+%D This command may be used more that once, but always before
+%D the first page is shipped out.
+
+\newif\ifoneJSpreamble \oneJSpreamblefalse
+
+\let\allJSpreambles\empty
+\newcounter\nofJSpreambles
+\newcounter\currentJSpreamble
+
+\long\def\startJSpreamble#1 #2 %
+ {\bgroup % we need to restore the catcodes
+ \restoreendofline % just in case it happens while reading lists
+ \doifelse{#2}{used}
+ {\dostartJSpreamble#1 }
+ {\dostartJSpreamble#1 now #2 }}
+
+\long\def\dostartJSpreamble#1 #2 %
+ {\processaction
+ [#2]
+ [ later=>\chardef\JSstatus\zerocount,%
+ now=>\chardef\JSstatus\plusone ,%
+ \s!default=>\chardef\JSstatus\plustwo ,%
+ \s!unknown=>\chardef\JSstatus\plustwo ]%
+ \ifaddJSlinebreaks
+ \obeylines \let\obeyedline \normalpar
+ \obeyspaces \let\obeyedspace\normalspace
+ \fi
+ \dodostartJSpreamble{#1}}
+
+\long\def\dodostartJSpreamble#1#2\stopJSpreamble
+ {\presetJSfunctions #2function ()\end
+ \long\setgvalue{\r!java\r!java#1}{#2}%
+ \ifcase\JSstatus \else
+ \useJSpreamblenow{#1}%
+ \fi
+ \egroup}
+
+%D \macros
+%D {setJSpreamble, addtoJSpreamble}
+%D
+%D In addition to the previous preamble definitions, we can
+%D set a preamble \quote {in||line} and add tokens to a
+%D preamble.
+
+\def\setJSpreamble#1#2%
+ {\doifundefined{\r!java\r!java#1}
+ {\setgvalue{\r!java\r!java#1}{#2;}%
+ \doglobal\increment\currentJSpreamble
+ \doglobal\addtocommalist{#1}\allJSpreambles}}
+
+\def\addtoJSpreamble#1#2%
+ {\doifdefinedelse{\r!java\r!java#1}
+ {\edef\!!stringa{\r!java\r!java#1}%
+ \edef\!!stringb{\csname\!!stringa\endcsname}%
+ \@EA\setgvalue\@EA\!!stringa\@EA{\!!stringb #2;}}
+ {\setJSpreamble{#1}{#2}}}
+
+%D \macros
+%D {useJSpreamblenow}
+%D
+%D The next macro can be used to force inclusion of postponed
+%D \JAVASCRIPT\ preambles.
+
+\def\useJSpreamblenow#1%
+ {\doglobal\increment\currentJSpreamble
+ \doglobal\addtocommalist{#1}\allJSpreambles}
+
+%D Because we want to check for valid calls, we preload the
+%D functions. This means that we can call them directly as
+%D well as indirectly when defined by \type {\startJScode} etc.
+
+% \long\def\presetJSfunctions#1function #2(#3)%
+% {\doifelsenothing{#2}
+% {\long\def\presetJSfunctions##1\end{}}
+% {\stripspaces\from#2\to\ascii
+% \doifundefined{\r!java\ascii}{\setgvalue{\r!java\ascii}{\do{}{!}}}}%
+% \presetJSfunctions}
+
+\long\def\presetJSfunctions#1function#2(#3)%
+ {\doifelse{#2}\space
+ {\long\def\presetJSfunctions##1\end{}}
+ {\stripspaces\from#2\to\ascii
+ \doifundefined{\r!java\ascii}{\setgvalue{\r!java\ascii}{\do{}{!}}}}%
+ \presetJSfunctions}
+
+\def\getJSpreamble#1%
+ {\getvalue{\r!java\r!java#1}}
+
+\def\presetJSpreamble
+ {\ifx\allJSpreambles\empty\else
+ \bgroup
+ \setverbosecscharacters
+ \obeyspaces \let\obeyedspace\normalspace
+ \def\par{\delcharacter}% was: { }
+ \globallet\JSpreamble\empty
+ \def\@@collectedJSpreamble{\r!java\r!java collected}%
+ \letvalue{\@@collectedJSpreamble}=\empty
+ \def\docommand##1%
+ {\xdef\JScode{\getvalue{\r!java\r!java##1}}%
+ \ifoneJSpreamble % \global\letcdcsname
+ \@EA\setxvalue\@EA\@@collectedJSpreamble\@EA
+ {\csname\@@collectedJSpreamble\endcsname\JScode}%
+ \else
+ \setxvalue{\r!java\r!java##1}{\JScode}%
+ \fi}%
+ \processcommacommand[\allJSpreambles]\docommand
+ \ifoneJSpreamble
+ \gdef\allJSpreambles{collected}%
+ \fi
+ \globallet\presetJSpreamble\relax
+ \egroup
+ \fi}
+
+\def\flushJSpreamble
+ {\iflocation\ifx\allJSpreambles\empty\else
+ \ifcase\nofJSpreambles\else\ifnum\nofJSpreambles=\currentJSpreamble
+ \bgroup
+ \presetJSpreamble
+ \expanded{\doflushJSpreamble{\allJSpreambles}}%
+ \globallet\flushJSpreamble\relax
+ \globallet\allJSpreambles\empty
+ \egroup
+ \fi\fi
+ \fi\fi}
+
+\def\finalflushJSpreamble
+ {\iflocation
+ \flushJSpreamble
+ \ifcase\currentJSpreamble\relax\else
+ \savecurrentvalue\nofJSpreambles\currentJSpreamble
+ \globallet\currentJSpreamble\nofJSpreambles
+ \fi
+ \fi}
+
+\prependtoks \flushJSpreamble \to \everyshipout
+\prependtoks \finalflushJSpreamble \to \everylastshipout
+
+%D \macros
+%D {doPSsanitizeJScode}
+%D
+%D Before the code can be passed to the (\POSTSCRIPT\ or \PDF)
+%D output file, some precautions must be made concerning the
+%D use of \type{(} and~\type{)}. Here we use a beautiful
+%D \type{\aftergroup} trick I discovered in the \TABLE\ format.
+
+\def\doPSsanitizeJScode#1\to#2%
+ {\begingroup
+ \scratchcounter\zerocount % \aftergroup counter
+ \aftergroup\xdef
+ \aftergroup#2%
+ \aftergroup{%
+ \expanded{\defconvertedargument\noexpand\JScode{#1}}%
+ \expandafter\handletokens\JScode\with\dodoPSsanitizeJScode
+ \aftergroup}%
+ \endgroup
+ \iftraceJScode
+ \writestatus{JS trace}{#2}%
+ \fi}
+
+%D I started with:
+%D
+%D \starttyping
+%D \def\dodoPSsanitizeJScode#1%
+%D {\aftergroup\string
+%D \if#1(%
+%D \expandafter\aftergroup\csname#1\endcsname
+%D \else\if#1)%
+%D \expandafter\aftergroup\csname#1\endcsname
+%D \else\if#1;%
+%D \aftergroup;\aftergroup\string\expandafter\aftergroup\
+%D \else
+%D \expandafter\aftergroup#1%
+%D \fi\fi\fi
+%D \advance\scratchcounter by 1
+%D \ifnum\scratchcounter=500
+%D \expandafter\dododoPSsanitizeJScode
+%D \fi}
+%D \stoptyping
+%D
+%D For pretty printing purposes, we need some way to signal
+%D \TEX\ macros. Therefore we introduce a special keyword
+%D \type{TEX}. When followed by a space, this keyword is
+%D ignored, that is, filtered from the stream. Now we have:
+
+\chardef\JSisTEX \zerocount
+\chardef\JScomment\zerocount
+
+\newif\ifaddJSlinebreaks \addJSlinebreakstrue
+
+\def\flushJSisTEX
+ {\ifcase\JSisTEX
+ \or \aftergroup T%
+ \or \aftergroup T\aftergroup E%
+ \or \aftergroup T\aftergroup E\aftergroup X%
+ \fi
+ \chardef\JSisTEX\zerocount}
+
+% \def\doJSlinebreak
+% {\ifaddJSlinebreaks
+% \aftergroup\string\aftergroup\n%
+% \fi}
+%
+% \def\dodoPSsanitizeJScode#1% % input stack>500 & TEX check
+% {\if#1/%
+% \ifnum\JScomment=0
+% \chardef\JScomment\plusone
+% \else\ifnum\JScomment=1
+% \chardef\JScomment\plustwo
+% \fi\fi
+% \else
+% \ifnum\JScomment=1
+% \aftergroup/%
+% \chardef\JScomment\zerocount
+% \fi
+% \ifnum\JScomment=2
+% \if#1\delcharacter
+% \chardef\JScomment\zerocount
+% \fi
+% \else
+% \if#1\delcharacter
+% \flushJSisTEX\doJSlinebreak
+% \else\if#1(%
+% \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname
+% \else\if#1)%
+% \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname
+% \else\if#1;%
+% \flushJSisTEX\aftergroup;\doJSlinebreak
+% \else\if#1T%
+% \ifnum\JSisTEX=0 \chardef\JSisTEX\plusone \else\flushJSisTEX\aftergroup T\fi
+% \else\if#1E%
+% \ifnum\JSisTEX=1 \chardef\JSisTEX\plustwo \else\flushJSisTEX\aftergroup E\fi
+% \else\if#1X%
+% \ifnum\JSisTEX=2 \chardef\JSisTEX\plusthree \else\flushJSisTEX\aftergroup X\fi
+% \else\if#1\normalspace
+% \ifnum\JSisTEX=3 \chardef\JSisTEX\zerocount \else\flushJSisTEX\aftergroup#1\fi
+% \else
+% \flushJSisTEX\aftergroup\string\expandafter\aftergroup#1%
+% \fi\fi\fi\fi\fi\fi\fi\fi
+% \fi
+% \fi
+% \dododoPSsanitizeJScode}
+
+% todo: "http:\\" -> simple. maar wel \" afvangen
+%
+% use new pdftex escape mechanism or make fully expandable version, not used that often btw
+
+\chardef\JSstring\zerocount
+
+\def\doJSlinebreak
+ {\chardef\JScomment\zerocount
+ \chardef\JSstring\zerocount
+ \ifaddJSlinebreaks
+ \aftergroup\string\aftergroup\n%
+ \fi}
+
+\def\dodoPSsanitizeJScode#1% % input stack>500 & TEX check
+ {\if#1/%
+ \ifnum\JSstring=0
+ \ifnum\JScomment=0
+ \chardef\JScomment\plusone
+ \else\ifnum\JScomment=1
+ \chardef\JScomment\plustwo
+ \fi\fi
+ \else
+ \aftergroup/%
+ \fi
+ \else
+ \ifnum\JScomment=1
+ \aftergroup/%
+ \chardef\JScomment\zerocount
+ \fi
+ % is the delchar trick still needed?
+ \ifnum\JScomment=2
+ \ifnum`#1=13 % brrr
+ \doJSlinebreak
+ \else\if#1\par
+ \doJSlinebreak
+ \else\if#1\delcharacter
+ \doJSlinebreak
+ \fi\fi\fi
+ \else
+ \ifnum`#1=13 % brrr
+ \flushJSisTEX\doJSlinebreak
+ \else\if#1\par
+ \flushJSisTEX\doJSlinebreak
+ \else\if#1\delcharacter
+ \flushJSisTEX\doJSlinebreak
+ \else\if#1(%
+ \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname
+ \else\if#1)%
+ \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname
+ %\else\if#1;%
+ % \flushJSisTEX\aftergroup;\doJSlinebreak
+ \else\if#1T%
+ \ifnum\JSisTEX=0 \chardef\JSisTEX\plusone \else\flushJSisTEX\aftergroup T\fi
+ \else\if#1E%
+ \ifnum\JSisTEX=1 \chardef\JSisTEX\plustwo \else\flushJSisTEX\aftergroup E\fi
+ \else\if#1X%
+ \ifnum\JSisTEX=2 \chardef\JSisTEX\plusthree \else\flushJSisTEX\aftergroup X\fi
+ \else\if#1\normalspace
+ \ifnum\JSisTEX=3 \chardef\JSisTEX\zerocount \else\flushJSisTEX\aftergroup#1\fi
+ \else
+ % todo: "test\"test"
+ \if#1"%
+ \ifcase\JSstring
+ \chardef\JSstring\plusone
+ \else
+ \chardef\JSstring\zerocount
+ \fi
+ \fi
+ \flushJSisTEX\aftergroup\string\expandafter\aftergroup#1%
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi % \fi
+ \fi
+ \fi
+ \dododoPSsanitizeJScode}
+
+%D Close reading learns that one line comments (\type{// ...})
+%D are removed from the stream. This permits switching in
+%D pretty printing \JAVASCRIPT\ sources as well as saves
+%D some bytes.
+
+%D The magic 500 in the next hack prevents the input stack from
+%D overflowing when large scripts are sanitized.
+
+\def\dododoPSsanitizeJScode
+ {\ifcase\JSisTEX\ifcase\JScomment
+ \advance\scratchcounter \plusone
+ \fi\fi
+ \ifnum\scratchcounter=500
+ \expandafter\dodododoPSsanitizeJScode
+ \fi}
+
+\def\dodododoPSsanitizeJScode
+ {\let\next={%
+ \aftergroup}%
+ \endgroup
+ \begingroup
+ \aftergroup\xdef
+ \aftergroup\sanitizedJScode
+ \aftergroup{%
+ \aftergroup\sanitizedJScode
+ \let\next=}}
+
+%D The macro \type{\doPSsanitizeJScode} converts its argument
+%D into the macro \type{\sanitizedJScode}, thereby prefixing
+%D each \type{(} and \type{)} by a slash.
+
+%D Hooking this mechanism into the general \CONTEXT\ reference
+%D mechanism does not take much effort:
+
+\definespecialtest{JS}%
+ {\doifdefinedelse{\r!java\currentreferenceoperation}}
+
+\definespeciallocation{JS}#1#2%
+ {\iflocation
+ \bgroup
+ \bgroup
+ \presetJScode
+ \currentreferenceoperation
+ \currentreferencearguments
+ \egroup
+ \dohandlegoto
+ {#2}%
+ {\dostartgotoJS\buttonwidth\buttonheight\JScode}%
+ {\dostopgotoJS}%
+ \egroup
+ \else
+ {#2}%
+ \fi}
+
+%D \macros
+%D {useJSscripts}
+%D
+%D In due time, users will build their collections of scripts,
+%D which can be used (loaded) when applicable. Although not all
+%D public, we will provide some general purpose scripts,
+%D collected in files with names like \type{java-...}. One can
+%D load these scripts with \type{\useJSscripts}, like:
+%D
+%D \starttyping
+%D \useJSscripts[fld]
+%D \stoptyping
+%D
+%D The not so complicated implementation of this macro is:
+
+\def\dodouseJSscripts#1%
+ {\doifelse{#1}\v!reset
+ {\let\allJSpreambles\empty}
+ {\doifundefined{\c!file\f!javascriptprefix#1}
+ {\startnointerference
+ \letgvalueempty{\c!file\f!javascriptprefix#1}%
+ \makeshortfilename[\f!javascriptprefix#1]%
+ \startreadingfile
+ \readsysfile\shortfilename{\showmessage\m!javascript1{#1}}\donothing
+ \stopreadingfile
+ \stopnointerference}}}
+
+\def\douseJSscripts[#1][#2]%
+ {\processcommalist[#1]\dodouseJSscripts
+ \processcommalist[#2]\useJSpreamblenow}
+
+\def\useJSscripts
+ {\dodoubleempty\douseJSscripts}
+
+\protect \endinput
diff --git a/tex/context/base/java-ini.mkiv b/tex/context/base/java-ini.mkiv
new file mode 100644
index 000000000..6536ced48
--- /dev/null
+++ b/tex/context/base/java-ini.mkiv
@@ -0,0 +1,164 @@
+%D \module
+%D [ file=java-ini,
+%D version=1998.01.30,
+%D title=\CONTEXT\ JavaScript Macros,
+%D subtitle=Initialization,
+%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 JavaScript Macros / Initialization}
+
+\registerctxluafile{java-ini}{1.001}
+
+\unprotect
+
+%D \macros
+%D {JS*}
+%D
+%D Because \JAVASCRIPT's are activated by the user, for
+%D instance by activating on a button, their support is closely
+%D related to the referencing mechanism. Integration takes
+%D place by
+%D
+%D \starttyping
+%D \goto{calculate total}[Sum()]
+%D \stoptyping
+%D
+%D The \type{()} classify this as a script. If they are absent,
+%D the keyword is treated as a normal reference.
+%D
+%D One can pass arguments to such a script by saying:
+%D
+%D \starttyping
+%D \goto{calculate total}[Sum(1.5,2.3)]
+%D \stoptyping
+
+
+%D \macros
+%D {startJScode}
+%D
+%D A piece of \JAVASCRIPT\ code is defined by saying:
+%D
+%D \starttyping
+%D \startJScode{name}
+%D name = 4 ;
+%D \stopJScode
+%D \stoptyping
+%D
+%D This assumes uses no preamble or presumes that the preamble is
+%D always loaded, the next definition also tells \CONTEXT\ to
+%D actually include the preamble needed.
+%D
+%D \starttyping
+%D \startJScode{uses} uses {later}
+%D uses = 6 ;
+%D \stopJScode
+%D \stoptyping
+%D
+%D \macros
+%D {startJSpreamble}
+%D
+%D One can define insert \JAVASCRIPT\ code at the document level
+%D by using:
+%D
+%D \starttyping
+%D \startJSpreamble{oeps}
+%D oeps = 1 ;
+%D \stopJSpreamble
+%D \stoptyping
+%D
+%D which is the same as:
+%D
+%D \starttyping
+%D \startJSpreamble{now} used now
+%D now = 2 ;
+%D \stopJSpreamble
+%D \stoptyping
+%D
+%D while the next definition is only included when actually
+%D used.
+%D
+%D \starttyping
+%D \startJSpreamble{later} used later
+%D later = 3 ;
+%D \stopJSpreamble
+%D \stoptyping
+%D
+%D This command may be used more that once, but always before
+%D the first page is shipped out.
+%D
+%D \macros
+%D {setJSpreamble, addtoJSpreamble}
+%D
+%D In addition to the previous preamble definitions, we can
+%D set a preamble \quote {in||line} and add tokens to a
+%D preamble.
+%D
+%D \macros
+%D {useJSpreamblenow}
+%D
+%D This macro can be used to force inclusion of postponed
+%D \JAVASCRIPT\ preambles.
+
+\unexpanded\def\startJScode
+ {\begingroup\obeylualines\obeyluatokens\dostartJScode}
+
+\long\def\dostartJScode#1\stopJScode
+ {\normalexpanded{\endgroup\ctxlua{javascripts.storecode(\!!bs#1\!!es)}}}
+
+\let\stopJScode\relax
+
+\unexpanded\def\startJSpreamble
+ {\begingroup\obeylualines\obeyluatokens\dostartJSpreamble}
+
+\long\def\dostartJSpreamble#1\stopJSpreamble
+ {\normalexpanded{\endgroup\ctxlua{javascripts.storepreamble(\!!bs#1\!!es)}}}
+
+\let\stopJSpreamble\relax
+
+\def\setJSpreamble #1#2{\ctxlua{javascripts.storepreamble ("#1",\!!bs#2\!!es)}}
+\def\addtoJSpreamble #1#2{\ctxlua{javascripts.addtopreamble ("#1",\!!bs#2\!!es)}}
+\def\useJSpreamblenow #1{\ctxlua{javascripts.usepreamblenow("#1")}}
+\def\finalflushJSpreamble{\iflocation\ctxlua{javascripts.flushpreambles()}\fi}
+
+%D \macros
+%D {useJSscripts}
+%D
+%D In due time, users will build their collections of scripts,
+%D which can be used (loaded) when applicable. Although not all
+%D public, we will provide some general purpose scripts,
+%D collected in files with names like \type{java-...}. One can
+%D load these scripts with \type{\useJSscripts}, like:
+%D
+%D \starttyping
+%D \useJSscripts[fld]
+%D \stoptyping
+%D
+%D The not so complicated implementation of this macro is:
+
+\def\dodouseJSscripts#1%
+ {\doifelse{#1}\v!reset
+ {\let\allJSpreambles\empty}
+ {\ifcsname\c!file\f!javascriptprefix#1\endcsname \else
+ \startnointerference
+ \letgvalueempty{\c!file\f!javascriptprefix#1}%
+ \makeshortfilename[\f!javascriptprefix#1]%
+ \startreadingfile
+ \readsysfile\shortfilename{\showmessage\m!javascript1{#1}}\donothing
+ \stopreadingfile
+ \stopnointerference
+ \fi}}
+
+\def\douseJSscripts[#1][#2]%
+ {\processcommalist[#1]\dodouseJSscripts
+ \processcommalist[#2]\useJSpreamblenow}
+
+\def\useJSscripts
+ {\dodoubleempty\douseJSscripts}
+
+\protect \endinput
diff --git a/tex/context/base/java-stp.tex b/tex/context/base/java-stp.tex
new file mode 100644
index 000000000..df4fbcc2f
--- /dev/null
+++ b/tex/context/base/java-stp.tex
@@ -0,0 +1,121 @@
+%D \module
+%D [ file=java-stp,
+%D version=2004.03.15,
+%D title=\CONTEXT\ JavaScript Macros,
+%D subtitle=Stepping,
+%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.
+
+% we define ocglist global, otherwise we quickly run into a memory hog (even
+% out of memory in a 512 Meg machine)
+
+% we cannot use doc_visited[this.pageNum] instead of doc_currentstep because
+% of some funny side effect (i.e. dup or so)
+
+\startJSpreamble Steps used now
+
+ var doc_ocglist = this.getOCGs() ;
+ var doc_stepname = "step" ;
+ var doc_currentstep = 0 ;
+ var doc_maxstep = 50 ;
+ var doc_visited = new Array() ;
+ var doc_busy = new Array() ;
+
+ function SetupStepper ( layername, laststep ) {
+ doc_stepname = layername ;
+ doc_maxstep = laststep ;
+ for (var i=0; i<=this.numPages; i++) {
+ doc_visited[i] = 0 ;
+ doc_busy[i] = 0 ;
+ }
+ }
+
+ for (var i=0; i<=this.numPages; i++) {
+ doc_visited[i] = 0 ;
+ doc_busy[i] = 0 ;
+ }
+
+ function GetOCG ( name ) {
+ for (var i=0; i < doc_ocglist.length; i++) {
+ if (doc_ocglist[i].name == name) {
+ return doc_ocglist[i] ;
+ }
+ }
+ return null ;
+ }
+
+ function CheckBusy ( ) {
+ var ocg = GetOCG("step:busy") ;
+ if (ocg != null) {
+ if (doc_visited[this.pageNum]==0) {
+ ocg.state = true ;
+ } else {
+ if (doc_visited[this.pageNum]Internally work with scaled point, which are
+represented by integers. However, in practice, at east at the
+ end we work with more generic units like points (pt). Going
+from scaled points (numbers) to one of those units can be
+done by using the conversion factors collected in the following
+table.
+--ldx]]--
+
+local format, match, gsub, type, setmetatable = string.format, string.match, string.gsub, type, setmetatable
+local P, S, R, Cc, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.Cc, lpeg.match
+
+number = number or { }
+
+number.tonumberf = function(n) return match(format("%.20f",n),"(.-0?)0*$") end -- one zero too much but alas
+number.tonumberg = function(n) return format("%.20g",n) end
+
+local dimenfactors = {
+ ["pt"] = 1/65536,
+ ["in"] = ( 100/ 7227)/65536,
+ ["cm"] = ( 254/ 7227)/65536,
+ ["mm"] = ( 2540/ 7227)/65536,
+ ["sp"] = 1, -- 65536 sp in 1pt
+ ["bp"] = ( 7200/ 7227)/65536,
+ ["pc"] = ( 1/ 12)/65536,
+ ["dd"] = ( 1157/ 1238)/65536,
+ ["cc"] = ( 1157/14856)/65536,
+ ["nd"] = (20320/21681)/65536,
+ ["nc"] = ( 5080/65043)/65536
+}
+
+--~ print(table.serialize(dimenfactors))
+--~
+--~ %.99g:
+--~
+--~ t={
+--~ ["bp"]=1.5201782378580324e-005,
+--~ ["cc"]=1.1883696112892098e-006,
+--~ ["cm"]=5.3628510057769479e-007,
+--~ ["dd"]=1.4260435335470516e-005,
+--~ ["em"]=0.000152587890625,
+--~ ["ex"]=6.103515625e-005,
+--~ ["in"]=2.1113586636917117e-007,
+--~ ["mm"]=5.3628510057769473e-008,
+--~ ["nc"]=1.1917446679504327e-006,
+--~ ["nd"]=1.4300936015405194e-005,
+--~ ["pc"]=1.2715657552083333e-006,
+--~ ["pt"]=1.52587890625e-005,
+--~ ["sp"]=1,
+--~ }
+--~
+--~ patched %s and tonumber
+--~
+--~ t={
+--~ ["bp"]=0.00001520178238,
+--~ ["cc"]=0.00000118836961,
+--~ ["cm"]=0.0000005362851,
+--~ ["dd"]=0.00001426043534,
+--~ ["em"]=0.00015258789063,
+--~ ["ex"]=0.00006103515625,
+--~ ["in"]=0.00000021113587,
+--~ ["mm"]=0.00000005362851,
+--~ ["nc"]=0.00000119174467,
+--~ ["nd"]=0.00001430093602,
+--~ ["pc"]=0.00000127156576,
+--~ ["pt"]=0.00001525878906,
+--~ ["sp"]=1,
+--~ }
+
+--[[ldx--
+
A conversion function that takes a number, unit (string) and optional
+format (string) is implemented using this table.
+--ldx]]--
+
+-- was:
+
+local function todimen(n,unit,fmt)
+ if type(n) == 'string' then
+ return n
+ else
+ unit = unit or 'pt'
+ return format(fmt or "%s%s",n*dimenfactors[unit],unit)
+ -- if fmt then
+ -- return format(fmt,n*dimenfactors[unit],unit)
+ -- else
+ -- return match(format("%.20f",n*dimenfactors[unit]),"(.-0?)0*$") .. unit
+ -- end
+ end
+end
+
+--[[ldx--
+
We collect a bunch of converters in the number namespace.
+--ldx]]--
+
+number.maxdimen = 1073741823
+number.todimen = todimen
+number.dimenfactors = dimenfactors
+
+function number.topoints (n) return todimen(n,"pt") end
+function number.toinches (n) return todimen(n,"in") end
+function number.tocentimeters (n) return todimen(n,"cm") end
+function number.tomillimeters (n) return todimen(n,"mm") end
+function number.toscaledpoints(n) return todimen(n,"sp") end
+function number.toscaledpoints(n) return n .. "sp" end
+function number.tobasepoints (n) return todimen(n,"bp") end
+function number.topicas (n) return todimen(n "pc") end
+function number.todidots (n) return todimen(n,"dd") end
+function number.tociceros (n) return todimen(n,"cc") end
+function number.tonewdidots (n) return todimen(n,"nd") end
+function number.tonewciceros (n) return todimen(n,"nc") end
+
+--[[ldx--
+
More interesting it to implement a (sort of) dimen datatype, one
+that permits calculations too. First we define a function that
+converts a string to scaledpoints. We use . We capture
+a number and optionally a unit. When no unit is given a constant
+capture takes place.
We use a metatable to intercept errors. When no key is found in
+the table with factors, the metatable will be consulted for an
+alternative index function.
The main (and globally) visible representation of a dimen is defined next: it is
+a one-element table. The unit that is returned from the match is normally a number
+(one of the previously defined factors) but we also accept functions. Later we will
+see why.
+--ldx]]--
+
+function dimen(a)
+ if a then
+ local ta= type(a)
+ if ta == "string" then
+ local value, unit = lpegmatch(pattern,a)
+ if type(unit) == "function" then
+ k = value/unit()
+ else
+ k = value/unit
+ end
+ a = k
+ elseif ta == "table" then
+ a = a[1]
+ end
+ return setmetatable({ a }, dimensions)
+ else
+ return setmetatable({ 0 }, dimensions)
+ end
+end
+
+--[[ldx--
+
This function return a small hash with a metatable attached. It is
+through this metatable that we can do the calculations. We could have
+shared some of the code but for reasons of speed we don't.
+--ldx]]--
+
+function dimensions.__add(a, b)
+ local ta, tb = type(a), type(b)
+ if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end
+ if tb == "string" then b = b:todimen() elseif tb == "table" then b = b[1] end
+ return setmetatable({ a + b }, dimensions)
+end
+
+function dimensions.__sub(a, b)
+ local ta, tb = type(a), type(b)
+ if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end
+ if tb == "string" then b = b:todimen() elseif tb == "table" then b = b[1] end
+ return setmetatable({ a - b }, dimensions)
+end
+
+function dimensions.__mul(a, b)
+ local ta, tb = type(a), type(b)
+ if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end
+ if tb == "string" then b = b:todimen() elseif tb == "table" then b = b[1] end
+ return setmetatable({ a * b }, dimensions)
+end
+
+function dimensions.__div(a, b)
+ local ta, tb = type(a), type(b)
+ if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end
+ if tb == "string" then b = b:todimen() elseif tb == "table" then b = b[1] end
+ return setmetatable({ a / b }, dimensions)
+end
+
+function dimensions.__unm(a)
+ local ta = type(a)
+ if ta == "string" then a = a:todimen() elseif ta == "table" then a = a[1] end
+ return setmetatable({ - a }, dimensions)
+end
+
+--[[ldx--
+
It makes no sense to implement the power and modulo function but
+the next two do make sense because they permits is code like:
+
+
+local a, b = dimen "10pt", dimen "11pt"
+...
+if a > b then
+ ...
+end
+
+--ldx]]--
+
+-- makes no sense: dimensions.__pow and dimensions.__mod
+
+function dimensions.__lt(a, b)
+ return a[1] < b[1]
+end
+
+function dimensions.__eq(a, b)
+ return a[1] == b[1]
+end
+
+--[[ldx--
+
We also need to provide a function for conversion to string (so that
+we can print dimensions). We print them as points, just like .
Since it does not take much code, we also provide a way to access
+a few accessors
+
+
+print(dimen().pt)
+print(dimen().sp)
+
+--ldx]]--
+
+function dimensions.__index(tab,key)
+ local d = dimenfactors[key]
+ if not d then
+ error("illegal property of dimen: " .. key)
+ d = 1
+ end
+ return 1/d
+end
+
+--[[ldx--
+
In the converter from string to dimension we support functions as
+factors. This is because in we have a few more units:
+ex and em. These are not constant factors but
+depend on the current font. They are not defined by default, but need
+an explicit function call. This is because at the moment that this code
+is loaded, the relevant tables that hold the functions needed may not
+yet be available.
+--ldx]]--
+
+function dimensions.texify() -- todo: %
+ local fti, fc = fonts and fonts.ids and fonts.ids, font and font.current
+ if fti and fc then
+ dimenfactors["ex"] = function() return fti[fc()].ex_height end
+ dimenfactors["em"] = function() return fti[fc()].quad end
+ else
+ dimenfactors["ex"] = 1/65536* 4 -- 4pt
+ dimenfactors["em"] = 1/65536*10 -- 10pt
+ end
+end
+
+--[[ldx--
+
In order to set the defaults we call this function now. At some point
+the macro package needs to make sure the function is called again.
+--ldx]]--
+
+dimensions.texify()
+
+--[[ldx--
+
The previous code is rather efficient (also thanks to ) but we
+can speed it up by caching converted dimensions. On my machine (2008) the following
+loop takes about 25.5 seconds.
When we cache converted strings this becomes 16.3 seconds. In order not
+to waste too much memory on it, we tag the values of the cache as being
+week which mean that the garbage collector will collect them in a next
+sweep. This means that in most cases the speed up is mostly affecting the
+current couple of calculations and as such the speed penalty is small.
+
+
We redefine two previous defined functions that can benefit from
+this:
+--ldx]]--
+
+local known = { } setmetatable(known, { __mode = "v" })
+
+function dimen(a)
+ if a then
+ local ta= type(a)
+ if ta == "string" then
+ local k = known[a]
+ if k then
+ a = k
+ else
+ local value, unit = lpegmatch(dimenpair,a)
+ if type(unit) == "function" then
+ k = value/unit()
+ else
+ k = value/unit
+ end
+ known[a] = k
+ a = k
+ end
+ elseif ta == "table" then
+ a = a[1]
+ end
+ return setmetatable({ a }, dimensions)
+ else
+ return setmetatable({ 0 }, dimensions)
+ end
+end
+
+function string:todimen()
+ if type(self) == "number" then
+ return self
+ else
+ local k = known[self]
+ if not k then
+ local value, unit = lpegmatch(dimenpair,self)
+ if value and unit then
+ k = value/unit
+ else
+ k = 0
+ end
+ -- print(self,value,unit)
+ known[self] = k
+ end
+ return k
+ end
+end
+
+function number.toscaled(d)
+ return format("0.5f",d/2^16)
+end
+
+--[[ldx--
+
In a similar fashion we can define a glue datatype. In that case we
+probably use a hash instead of a one-element table.
+--ldx]]--
+
+--[[ldx--
+
Goodie:s
+--ldx]]--
+
+function number.percent(n) -- will be cleaned up once luatex 0.30 is out
+ local hsize = tex.hsize
+ if type(hsize) == "string" then
+ hsize = hsize:todimen()
+ end
+ return (n/100) * hsize
+end
+
+number["%"] = number.percent
diff --git a/tex/context/base/l-dir.lua b/tex/context/base/l-dir.lua
new file mode 100644
index 000000000..2643f538b
--- /dev/null
+++ b/tex/context/base/l-dir.lua
@@ -0,0 +1,363 @@
+if not modules then modules = { } end modules ['l-dir'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- dir.expand_name will be merged with cleanpath and collapsepath
+
+local type = type
+local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
+local lpegmatch = lpeg.match
+
+dir = dir or { }
+
+-- handy
+
+function dir.current()
+ return (gsub(lfs.currentdir(),"\\","/"))
+end
+
+-- optimizing for no string.find (*) does not save time
+
+local attributes = lfs.attributes
+local walkdir = lfs.dir
+
+local function glob_pattern(path,patt,recurse,action)
+ local ok, scanner
+ if path == "/" then
+ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+ else
+ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+ end
+ if ok and type(scanner) == "function" then
+ if not find(path,"/$") then path = path .. '/' end
+ for name in scanner do
+ local full = path .. name
+ local mode = attributes(full,'mode')
+ if mode == 'file' then
+ if find(full,patt) then
+ action(full)
+ end
+ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+ glob_pattern(full,patt,recurse,action)
+ end
+ end
+ end
+end
+
+dir.glob_pattern = glob_pattern
+
+local function collect_pattern(path,patt,recurse,result)
+ local ok, scanner
+ result = result or { }
+ if path == "/" then
+ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+ else
+ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+ end
+ if ok and type(scanner) == "function" then
+ if not find(path,"/$") then path = path .. '/' end
+ for name in scanner do
+ local full = path .. name
+ local attr = attributes(full)
+ local mode = attr.mode
+ if mode == 'file' then
+ if find(full,patt) then
+ result[name] = attr
+ end
+ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+ attr.list = collect_pattern(full,patt,recurse)
+ result[name] = attr
+ end
+ end
+ end
+ return result
+end
+
+dir.collect_pattern = collect_pattern
+
+local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
+
+local pattern = Ct {
+ [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
+ [2] = C(((1-S("*?/"))^0 * P("/"))^0),
+ [3] = C(P(1)^0)
+}
+
+local filter = Cs ( (
+ P("**") / ".*" +
+ P("*") / "[^/]*" +
+ P("?") / "[^/]" +
+ P(".") / "%%." +
+ P("+") / "%%+" +
+ P("-") / "%%-" +
+ P(1)
+)^0 )
+
+local function glob(str,t)
+ if type(t) == "function" then
+ if type(str) == "table" then
+ for s=1,#str do
+ glob(str[s],t)
+ end
+ elseif lfs.isfile(str) then
+ t(str)
+ else
+ local split = lpegmatch(pattern,str)
+ if split then
+ local root, path, base = split[1], split[2], split[3]
+ local recurse = find(base,"%*%*")
+ local start = root .. path
+ local result = lpegmatch(filter,start .. base)
+ glob_pattern(start,result,recurse,t)
+ end
+ end
+ else
+ if type(str) == "table" then
+ local t = t or { }
+ for s=1,#str do
+ glob(str[s],t)
+ end
+ return t
+ elseif lfs.isfile(str) then
+ local t = t or { }
+ t[#t+1] = str
+ return t
+ else
+ local split = lpegmatch(pattern,str)
+ if split then
+ local t = t or { }
+ local action = action or function(name) t[#t+1] = name end
+ local root, path, base = split[1], split[2], split[3]
+ local recurse = find(base,"%*%*")
+ local start = root .. path
+ local result = lpegmatch(filter,start .. base)
+ glob_pattern(start,result,recurse,action)
+ return t
+ else
+ return { }
+ end
+ end
+ end
+end
+
+dir.glob = glob
+
+--~ list = dir.glob("**/*.tif")
+--~ list = dir.glob("/**/*.tif")
+--~ list = dir.glob("./**/*.tif")
+--~ list = dir.glob("oeps/**/*.tif")
+--~ list = dir.glob("/oeps/**/*.tif")
+
+local function globfiles(path,recurse,func,files) -- func == pattern or function
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return find(name,s) end
+ end
+ files = files or { }
+ for name in walkdir(path) do
+ if find(name,"^%.") then
+ --- skip
+ else
+ local mode = attributes(name,'mode')
+ if mode == "directory" then
+ if recurse then
+ globfiles(path .. "/" .. name,recurse,func,files)
+ end
+ elseif mode == "file" then
+ if func then
+ if func(name) then
+ files[#files+1] = path .. "/" .. name
+ end
+ else
+ files[#files+1] = path .. "/" .. name
+ end
+ end
+ end
+ end
+ return files
+end
+
+dir.globfiles = globfiles
+
+-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
+-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
+-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
+-- t = dir.glob("f:/minimal/tex/**/*")
+-- print(dir.ls("f:/minimal/tex/**/*"))
+-- print(dir.ls("*.tex"))
+
+function dir.ls(pattern)
+ return table.concat(glob(pattern),"\n")
+end
+
+--~ mkdirs("temp")
+--~ mkdirs("a/b/c")
+--~ mkdirs(".","/a/b/c")
+--~ mkdirs("a","b","c")
+
+local make_indeed = true -- false
+
+if string.find(os.getenv("PATH"),";") then -- os.type == "windows"
+
+ function dir.mkdirs(...)
+ local str, pth, t = "", "", { ... }
+ for i=1,#t do
+ local s = t[i]
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ local first, middle, last
+ local drive = false
+ first, middle, last = match(str,"^(//)(//*)(.*)$")
+ if first then
+ -- empty network path == local path
+ else
+ first, last = match(str,"^(//)/*(.-)$")
+ if first then
+ middle, last = match(str,"([^/]+)/+(.-)$")
+ if middle then
+ pth = "//" .. middle
+ else
+ pth = "//" .. last
+ last = ""
+ end
+ else
+ first, middle, last = match(str,"^([a-zA-Z]:)(/*)(.-)$")
+ if first then
+ pth, drive = first .. middle, true
+ else
+ middle, last = match(str,"^(/*)(.-)$")
+ if not middle then
+ last = str
+ end
+ end
+ end
+ end
+ for s in gmatch(last,"[^/]+") do
+ if pth == "" then
+ pth = s
+ elseif drive then
+ pth, drive = pth .. s, false
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("a:"))
+--~ print(dir.mkdirs("a:/b/c"))
+--~ print(dir.mkdirs("a:b/c"))
+--~ print(dir.mkdirs("a:/bbb/c"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str) -- will be merged with cleanpath and collapsepath
+ local first, nothing, last = match(str,"^(//)(//*)(.*)$")
+ if first then
+ first = dir.current() .. "/"
+ end
+ if not first then
+ first, last = match(str,"^(//)/*(.*)$")
+ end
+ if not first then
+ first, last = match(str,"^([a-zA-Z]:)(.*)$")
+ if first and not find(last,"^/") then
+ local d = lfs.currentdir()
+ if lfs.chdir(first) then
+ first = dir.current()
+ end
+ lfs.chdir(d)
+ end
+ end
+ if not first then
+ first, last = dir.current(), str
+ end
+ last = gsub(last,"//","/")
+ last = gsub(last,"/%./","/")
+ last = gsub(last,"^/*","")
+ first = gsub(first,"/*$","")
+ if last == "" then
+ return first
+ else
+ return first .. "/" .. last
+ end
+ end
+
+else
+
+ function dir.mkdirs(...)
+ local str, pth, t = "", "", { ... }
+ for i=1,#t do
+ local s = t[i]
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ str = gsub(str,"/+","/")
+ if find(str,"^/") then
+ pth = "/"
+ for s in gmatch(str,"[^/]+") do
+ local first = (pth == "/")
+ if first then
+ pth = pth .. s
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not first and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ else
+ pth = "."
+ for s in gmatch(str,"[^/]+") do
+ pth = pth .. "/" .. s
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str) -- will be merged with cleanpath and collapsepath
+ if not find(str,"^/") then
+ str = lfs.currentdir() .. "/" .. str
+ end
+ str = gsub(str,"//","/")
+ str = gsub(str,"/%./","/")
+ return str
+ end
+
+end
+
+dir.makedirs = dir.mkdirs
diff --git a/tex/context/base/l-file.lua b/tex/context/base/l-file.lua
new file mode 100644
index 000000000..2bfc07090
--- /dev/null
+++ b/tex/context/base/l-file.lua
@@ -0,0 +1,314 @@
+if not modules then modules = { } end modules ['l-file'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- needs a cleanup
+
+file = file or { }
+
+local concat = table.concat
+local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char
+local lpegmatch = lpeg.match
+
+function file.removesuffix(filename)
+ return (gsub(filename,"%.[%a%d]+$",""))
+end
+
+function file.addsuffix(filename, suffix)
+ if not suffix or suffix == "" then
+ return filename
+ elseif not find(filename,"%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return filename
+ end
+end
+
+function file.replacesuffix(filename, suffix)
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
+end
+
+function file.dirname(name,default)
+ return match(name,"^(.+)[/\\].-$") or (default or "")
+end
+
+function file.basename(name)
+ return match(name,"^.+[/\\](.-)$") or name
+end
+
+function file.nameonly(name)
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
+end
+
+function file.extname(name,default)
+ return match(name,"^.+%.([^/\\]-)$") or default or ""
+end
+
+file.suffix = file.extname
+
+--~ function file.join(...)
+--~ local pth = concat({...},"/")
+--~ pth = gsub(pth,"\\","/")
+--~ local a, b = match(pth,"^(.*://)(.*)$")
+--~ if a and b then
+--~ return a .. gsub(b,"//+","/")
+--~ end
+--~ a, b = match(pth,"^(//)(.*)$")
+--~ if a and b then
+--~ return a .. gsub(b,"//+","/")
+--~ end
+--~ return (gsub(pth,"//+","/"))
+--~ end
+
+local trick_1 = char(1)
+local trick_2 = "^" .. trick_1 .. "/+"
+
+function file.join(...)
+ local lst = { ... }
+ local a, b = lst[1], lst[2]
+ if a == "" then
+ lst[1] = trick_1
+ elseif b and find(a,"^/+$") and find(b,"^/") then
+ lst[1] = ""
+ lst[2] = gsub(b,"^/+","")
+ end
+ local pth = concat(lst,"/")
+ pth = gsub(pth,"\\","/")
+ local a, b = match(pth,"^(.*://)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ a, b = match(pth,"^(//)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ pth = gsub(pth,trick_2,"")
+ return (gsub(pth,"//+","/"))
+end
+
+--~ print(file.join("//","/y"))
+--~ print(file.join("/","/y"))
+--~ print(file.join("","/y"))
+--~ print(file.join("/x/","/y"))
+--~ print(file.join("x/","/y"))
+--~ print(file.join("http://","/y"))
+--~ print(file.join("http://a","/y"))
+--~ print(file.join("http:///a","/y"))
+--~ print(file.join("//nas-1","/y"))
+
+function file.iswritable(name)
+ local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,"."))
+ return a and sub(a.permissions,2,2) == "w"
+end
+
+function file.isreadable(name)
+ local a = lfs.attributes(name)
+ return a and sub(a.permissions,1,1) == "r"
+end
+
+file.is_readable = file.isreadable
+file.is_writable = file.iswritable
+
+-- todo: lpeg
+
+--~ function file.split_path(str)
+--~ local t = { }
+--~ str = gsub(str,"\\", "/")
+--~ str = gsub(str,"(%a):([;/])", "%1\001%2")
+--~ for name in gmatch(str,"([^;:]+)") do
+--~ if name ~= "" then
+--~ t[#t+1] = gsub(name,"\001",":")
+--~ end
+--~ end
+--~ return t
+--~ end
+
+local checkedsplit = string.checkedsplit
+
+function file.split_path(str,separator)
+ str = gsub(str,"\\","/")
+ return checkedsplit(str,separator or io.pathseparator)
+end
+
+function file.join_path(tab)
+ return concat(tab,io.pathseparator) -- can have trailing //
+end
+
+-- we can hash them weakly
+
+function file.collapse_path(str)
+ str = gsub(str,"\\","/")
+ if find(str,"/") then
+ str = gsub(str,"^%./",(gsub(lfs.currentdir(),"\\","/")) .. "/") -- ./xx in qualified
+ str = gsub(str,"/%./","/")
+ local n, m = 1, 1
+ while n > 0 or m > 0 do
+ str, n = gsub(str,"[^/%.]+/%.%.$","")
+ str, m = gsub(str,"[^/%.]+/%.%./","")
+ end
+ str = gsub(str,"([^/])/$","%1")
+ -- str = gsub(str,"^%./","") -- ./xx in qualified
+ str = gsub(str,"/%.$","")
+ end
+ if str == "" then str = "." end
+ return str
+end
+
+--~ print(file.collapse_path("/a"))
+--~ print(file.collapse_path("a/./b/.."))
+--~ print(file.collapse_path("a/aa/../b/bb"))
+--~ print(file.collapse_path("a/../.."))
+--~ print(file.collapse_path("a/.././././b/.."))
+--~ print(file.collapse_path("a/./././b/.."))
+--~ print(file.collapse_path("a/b/c/../.."))
+
+function file.robustname(str)
+ return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
+end
+
+file.readdata = io.loaddata
+file.savedata = io.savedata
+
+function file.copy(oldname,newname)
+ file.savedata(newname,io.loaddata(oldname))
+end
+
+-- lpeg variants, slightly faster, not always
+
+--~ local period = lpeg.P(".")
+--~ local slashes = lpeg.S("\\/")
+--~ local noperiod = 1-period
+--~ local noslashes = 1-slashes
+--~ local name = noperiod^1
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1
+
+--~ function file.extname(name)
+--~ return lpegmatch(pattern,name) or ""
+--~ end
+
+--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
+
+--~ function file.removesuffix(name)
+--~ return lpegmatch(pattern,name)
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
+
+--~ function file.basename(name)
+--~ return lpegmatch(pattern,name) or name
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
+
+--~ function file.dirname(name)
+--~ local p = lpegmatch(pattern,name)
+--~ if p then
+--~ return sub(name,1,p-2)
+--~ else
+--~ return ""
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.addsuffix(name, suffix)
+--~ local p = lpegmatch(pattern,name)
+--~ if p then
+--~ return name
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.replacesuffix(name,suffix)
+--~ local p = lpegmatch(pattern,name)
+--~ if p then
+--~ return sub(name,1,p-2) .. "." .. suffix
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1
+
+--~ function file.nameonly(name)
+--~ local a, b = lpegmatch(pattern,name)
+--~ if b then
+--~ return sub(name,a,b-2)
+--~ elseif a then
+--~ return sub(name,a)
+--~ else
+--~ return name
+--~ end
+--~ end
+
+--~ local test = file.extname
+--~ local test = file.basename
+--~ local test = file.dirname
+--~ local test = file.addsuffix
+--~ local test = file.replacesuffix
+--~ local test = file.nameonly
+
+--~ print(1,test("./a/b/c/abd.def.xxx","!!!"))
+--~ print(2,test("./../b/c/abd.def.xxx","!!!"))
+--~ print(3,test("a/b/c/abd.def.xxx","!!!"))
+--~ print(4,test("a/b/c/def.xxx","!!!"))
+--~ print(5,test("a/b/c/def","!!!"))
+--~ print(6,test("def","!!!"))
+--~ print(7,test("def.xxx","!!!"))
+
+--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+
+-- also rewrite previous
+
+local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
+local separator = lpeg.P("://")
+
+local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
+local rootbased = lpeg.P("/") + letter*lpeg.P(":")
+
+-- ./name ../name /name c: :// name/name
+
+function file.is_qualified_path(filename)
+ return lpegmatch(qualified,filename) ~= nil
+end
+
+function file.is_rootbased_path(filename)
+ return lpegmatch(rootbased,filename) ~= nil
+end
+
+local slash = lpeg.S("\\/")
+local period = lpeg.P(".")
+local drive = lpeg.C(lpeg.R("az","AZ")) * lpeg.P(":")
+local path = lpeg.C(((1-slash)^0 * slash)^0)
+local suffix = period * lpeg.C(lpeg.P(1-period)^0 * lpeg.P(-1))
+local base = lpeg.C((1-suffix)^0)
+
+local pattern = (drive + lpeg.Cc("")) * (path + lpeg.Cc("")) * (base + lpeg.Cc("")) * (suffix + lpeg.Cc(""))
+
+function file.splitname(str) -- returns drive, path, base, suffix
+ return lpegmatch(pattern,str)
+end
+
+-- function test(t) for k, v in next, t do print(v, "=>", file.splitname(v)) end end
+--
+-- test { "c:", "c:/aa", "c:/aa/bb", "c:/aa/bb/cc", "c:/aa/bb/cc.dd", "c:/aa/bb/cc.dd.ee" }
+-- test { "c:", "c:aa", "c:aa/bb", "c:aa/bb/cc", "c:aa/bb/cc.dd", "c:aa/bb/cc.dd.ee" }
+-- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
+-- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
+
+--~ -- todo:
+--~
+--~ if os.type == "windows" then
+--~ local currentdir = lfs.currentdir
+--~ function lfs.currentdir()
+--~ return (gsub(currentdir(),"\\","/"))
+--~ end
+--~ end
diff --git a/tex/context/base/l-io.lua b/tex/context/base/l-io.lua
new file mode 100644
index 000000000..66e279309
--- /dev/null
+++ b/tex/context/base/l-io.lua
@@ -0,0 +1,187 @@
+if not modules then modules = { } end modules ['l-io'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local byte, find, gsub = string.byte, string.find, string.gsub
+
+if string.find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator = "\\", ";"
+else
+ io.fileseparator, io.pathseparator = "/" , ":"
+end
+
+function io.loaddata(filename,textmode)
+ local f = io.open(filename,(textmode and 'r') or 'rb')
+ if f then
+ -- collectgarbage("step") -- sometimes makes a big difference in mem consumption
+ local data = f:read('*all')
+ -- garbagecollector.check(data)
+ f:close()
+ return data
+ else
+ return nil
+ end
+end
+
+function io.savedata(filename,data,joiner)
+ local f = io.open(filename,"wb")
+ if f then
+ if type(data) == "table" then
+ f:write(table.join(data,joiner or ""))
+ elseif type(data) == "function" then
+ data(f)
+ else
+ f:write(data or "")
+ end
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+function io.exists(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return false
+ else
+ assert(f:close())
+ return true
+ end
+end
+
+function io.size(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return 0
+ else
+ local s = f:seek("end")
+ assert(f:close())
+ return s
+ end
+end
+
+function io.noflines(f)
+ local n = 0
+ for _ in f:lines() do
+ n = n + 1
+ end
+ f:seek('set',0)
+ return n
+end
+
+local nextchar = {
+ [ 4] = function(f)
+ return f:read(1,1,1,1)
+ end,
+ [ 2] = function(f)
+ return f:read(1,1)
+ end,
+ [ 1] = function(f)
+ return f:read(1)
+ end,
+ [-2] = function(f)
+ local a, b = f:read(1,1)
+ return b, a
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ return d, c, b, a
+ end
+}
+
+function io.characters(f,n)
+ if f then
+ return nextchar[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+local nextbyte = {
+ [4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(a), byte(b), byte(c), byte(d)
+ else
+ return nil, nil, nil, nil
+ end
+ end,
+ [2] = function(f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(a), byte(b)
+ else
+ return nil, nil
+ end
+ end,
+ [1] = function (f)
+ local a = f:read(1)
+ if a then
+ return byte(a)
+ else
+ return nil
+ end
+ end,
+ [-2] = function (f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(b), byte(a)
+ else
+ return nil, nil
+ end
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(d), byte(c), byte(b), byte(a)
+ else
+ return nil, nil, nil, nil
+ end
+ end
+}
+
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+function io.ask(question,default,options)
+ while true do
+ io.write(question)
+ if options then
+ io.write(string.format(" [%s]",table.concat(options,"|")))
+ end
+ if default then
+ io.write(string.format(" [%s]",default))
+ end
+ io.write(string.format(" "))
+ local answer = io.read()
+ answer = gsub(answer,"^%s*(.*)%s*$","%1")
+ if answer == "" and default then
+ return default
+ elseif not options then
+ return answer
+ else
+ for k=1,#options do
+ if options[k] == answer then
+ return answer
+ end
+ end
+ local pattern = "^" .. answer
+ for k=1,#options do
+ local v = options[k]
+ if find(v,pattern) then
+ return v
+ end
+ end
+ end
+ end
+end
diff --git a/tex/context/base/l-lpeg.lua b/tex/context/base/l-lpeg.lua
new file mode 100644
index 000000000..b107a8e64
--- /dev/null
+++ b/tex/context/base/l-lpeg.lua
@@ -0,0 +1,165 @@
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local lpeg = require("lpeg")
+
+lpeg.patterns = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
+
+local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
+local match = lpeg.match
+
+local digit, sign = R('09'), S('+-')
+local cr, lf, crlf = P("\r"), P("\n"), P("\r\n")
+local utf8byte = R("\128\191")
+
+patterns.utf8byte = utf8byte
+patterns.utf8one = R("\000\127")
+patterns.utf8two = R("\194\223") * utf8byte
+patterns.utf8three = R("\224\239") * utf8byte * utf8byte
+patterns.utf8four = R("\240\244") * utf8byte * utf8byte * utf8byte
+
+patterns.digit = digit
+patterns.sign = sign
+patterns.cardinal = sign^0 * digit^1
+patterns.integer = sign^0 * digit^1
+patterns.float = sign^0 * digit^0 * P('.') * digit^1
+patterns.number = patterns.float + patterns.integer
+patterns.oct = P("0") * R("07")^1
+patterns.octal = patterns.oct
+patterns.HEX = P("0x") * R("09","AF")^1
+patterns.hex = P("0x") * R("09","af")^1
+patterns.hexadecimal = P("0x") * R("09","AF","af")^1
+patterns.lowercase = R("az")
+patterns.uppercase = R("AZ")
+patterns.letter = patterns.lowercase + patterns.uppercase
+patterns.space = S(" ")
+patterns.eol = S("\n\r")
+patterns.spacer = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline = crlf + cr + lf
+patterns.nonspace = 1 - patterns.space
+patterns.nonspacer = 1 - patterns.spacer
+patterns.whitespace = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.utf8 = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+patterns.utfbom = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
+
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return P { P(pattern) + 1 * V(1) } -- why so complex?
+end
+
+function lpeg.splitter(pattern, action)
+ return (((1-P(pattern))^1)/action+1)^0
+end
+
+local spacing = patterns.spacer^0 * patterns.newline -- sort of strip
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
+local content = (empty + nonempty)^1
+
+local capture = Ct(content^0)
+
+function string:splitlines()
+ return match(capture,self)
+end
+
+patterns.textline = content
+
+--~ local p = lpeg.splitat("->",false) print(match(p,"oeps->what->more")) -- oeps what more
+--~ local p = lpeg.splitat("->",true) print(match(p,"oeps->what->more")) -- oeps what->more
+--~ local p = lpeg.splitat("->",false) print(match(p,"oeps")) -- oeps
+--~ local p = lpeg.splitat("->",true) print(match(p,"oeps")) -- oeps
+
+local splitters_s, splitters_m = { }, { }
+
+local function splitat(separator,single)
+ local splitter = (single and splitters_s[separator]) or splitters_m[separator]
+ if not splitter then
+ separator = P(separator)
+ if single then
+ local other, any = C((1 - separator)^0), P(1)
+ splitter = other * (separator * C(any^0) + "") -- ?
+ splitters_s[separator] = splitter
+ else
+ local other = C((1 - separator)^0)
+ splitter = other * (separator * other)^0
+ splitters_m[separator] = splitter
+ end
+ end
+ return splitter
+end
+
+lpeg.splitat = splitat
+
+local cache = { }
+
+function lpeg.split(separator,str)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return match(c,str)
+end
+
+function string:split(separator)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return match(c,self)
+end
+
+lpeg.splitters = cache
+
+local cache = { }
+
+function lpeg.checkedsplit(separator,str)
+ local c = cache[separator]
+ if not c then
+ separator = P(separator)
+ local other = C((1 - separator)^0)
+ c = Ct(separator^0 * other * (separator^1 * other)^0)
+ cache[separator] = c
+ end
+ return match(c,str)
+end
+
+function string:checkedsplit(separator)
+ local c = cache[separator]
+ if not c then
+ separator = P(separator)
+ local other = C((1 - separator)^0)
+ c = Ct(separator^0 * other * (separator^1 * other)^0)
+ cache[separator] = c
+ end
+ return match(c,self)
+end
+
+--~ function lpeg.append(list,pp)
+--~ local p = pp
+--~ for l=1,#list do
+--~ if p then
+--~ p = p + P(list[l])
+--~ else
+--~ p = P(list[l])
+--~ end
+--~ end
+--~ return p
+--~ end
+
+--~ from roberto's site:
+
+local f1 = string.byte
+
+local function f2(s) local c1, c2 = f1(s,1,2) return c1 * 64 + c2 - 12416 end
+local function f3(s) local c1, c2, c3 = f1(s,1,3) return (c1 * 64 + c2) * 64 + c3 - 925824 end
+local function f4(s) local c1, c2, c3, c4 = f1(s,1,4) return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 end
+
+patterns.utf8byte = patterns.utf8one/f1 + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4
diff --git a/tex/context/base/l-math.lua b/tex/context/base/l-math.lua
new file mode 100644
index 000000000..fc8db4721
--- /dev/null
+++ b/tex/context/base/l-math.lua
@@ -0,0 +1,41 @@
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
+
+if not math.round then
+ function math.round(x)
+ return floor(x + 0.5)
+ end
+end
+
+if not math.div then
+ function math.div(n,m)
+ return floor(n/m)
+ end
+end
+
+if not math.mod then
+ function math.mod(n,m)
+ return n % m
+ end
+end
+
+local pipi = 2*math.pi/360
+
+function math.sind(d)
+ return sin(d*pipi)
+end
+
+function math.cosd(d)
+ return cos(d*pipi)
+end
+
+function math.tand(d)
+ return tan(d*pipi)
+end
diff --git a/tex/context/base/l-md5.lua b/tex/context/base/l-md5.lua
new file mode 100644
index 000000000..27955ef9b
--- /dev/null
+++ b/tex/context/base/l-md5.lua
@@ -0,0 +1,72 @@
+if not modules then modules = { } end modules ['l-md5'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This also provides file checksums and checkers.
+
+local gsub, format, byte = string.gsub, string.format, string.byte
+
+local function convert(str,fmt)
+ return (gsub(md5.sum(str),".",function(chr) return format(fmt,byte(chr)) end))
+end
+
+if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
+if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
+if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
+
+--~ if not md5.HEX then
+--~ local function remap(chr) return format("%02X",byte(chr)) end
+--~ function md5.HEX(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.hex then
+--~ local function remap(chr) return format("%02x",byte(chr)) end
+--~ function md5.hex(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.dec then
+--~ local function remap(chr) return format("%03i",byte(chr)) end
+--~ function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+
+file.needs_updating_threshold = 1
+
+function file.needs_updating(oldname,newname) -- size modification access change
+ local oldtime = lfs.attributes(oldname, modification)
+ local newtime = lfs.attributes(newname, modification)
+ if newtime >= oldtime then
+ return false
+ elseif oldtime - newtime < file.needs_updating_threshold then
+ return false
+ else
+ return true
+ end
+end
+
+function file.checksum(name)
+ if md5 then
+ local data = io.loaddata(name)
+ if data then
+ return md5.HEX(data)
+ end
+ end
+ return nil
+end
+
+function file.loadchecksum(name)
+ if md5 then
+ local data = io.loaddata(name .. ".md5")
+ return data and (gsub(data,"%s",""))
+ end
+ return nil
+end
+
+function file.savechecksum(name, checksum)
+ if not checksum then checksum = file.checksum(name) end
+ if checksum then
+ io.savedata(name .. ".md5",checksum)
+ return checksum
+ end
+ return nil
+end
diff --git a/tex/context/base/l-number.lua b/tex/context/base/l-number.lua
new file mode 100644
index 000000000..a1249f055
--- /dev/null
+++ b/tex/context/base/l-number.lua
@@ -0,0 +1,58 @@
+if not modules then modules = { } end modules ['l-number'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local tostring = tostring
+local format, floor, insert, match = string.format, math.floor, table.insert, string.match
+local lpegmatch = lpeg.match
+
+number = number or { }
+
+-- a,b,c,d,e,f = number.toset(100101)
+
+function number.toset(n)
+ return match(tostring(n),"(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
+end
+
+function number.toevenhex(n)
+ local s = format("%X",n)
+ if #s % 2 == 0 then
+ return s
+ else
+ return "0" .. s
+ end
+end
+
+-- the lpeg way is slower on 8 digits, but faster on 4 digits, some 7.5%
+-- on
+--
+-- for i=1,1000000 do
+-- local a,b,c,d,e,f,g,h = number.toset(12345678)
+-- local a,b,c,d = number.toset(1234)
+-- local a,b,c = number.toset(123)
+-- end
+--
+-- of course dedicated "(.)(.)(.)(.)" matches are even faster
+
+local one = lpeg.C(1-lpeg.S(''))^1
+
+function number.toset(n)
+ return lpegmatch(one,tostring(n))
+end
+
+function number.bits(n,zero)
+ local t, i = { }, (zero and 0) or 1
+ while n > 0 do
+ local m = n % 2
+ if m > 0 then
+ insert(t,1,i)
+ end
+ n = floor(n/2)
+ i = i + 1
+ end
+ return t
+end
diff --git a/tex/context/base/l-os.lua b/tex/context/base/l-os.lua
new file mode 100644
index 000000000..fba2cd317
--- /dev/null
+++ b/tex/context/base/l-os.lua
@@ -0,0 +1,301 @@
+if not modules then modules = { } end modules ['l-os'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- maybe build io.flush in os.execute
+
+local find, format, gsub = string.find, string.format, string.gsub
+local random, ceil = math.random, math.ceil
+
+local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
+
+function os.execute(...) ioflush() return execute(...) end
+function os.spawn (...) ioflush() return spawn (...) end
+function os.exec (...) ioflush() return exec (...) end
+
+function os.resultof(command)
+ ioflush() -- else messed up logging
+ local handle = io.popen(command,"r")
+ if not handle then
+ -- print("unknown command '".. command .. "' in os.resultof")
+ return ""
+ else
+ return handle:read("*all") or ""
+ end
+end
+
+--~ os.type : windows | unix (new, we already guessed os.platform)
+--~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
+--~ os.platform : extended os.name with architecture
+
+if not io.fileseparator then
+ if find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "mswin"
+ else
+ io.fileseparator, io.pathseparator, os.type = "/" , ":", os.type or "unix"
+ end
+end
+
+os.type = os.type or (io.pathseparator == ";" and "windows") or "unix"
+os.name = os.name or (os.type == "windows" and "mswin" ) or "linux"
+
+if os.type == "windows" then
+ os.libsuffix, os.binsuffix = 'dll', 'exe'
+else
+ os.libsuffix, os.binsuffix = 'so', ''
+end
+
+function os.launch(str)
+ if os.type == "windows" then
+ os.execute("start " .. str) -- os.spawn ?
+ else
+ os.execute(str .. " &") -- os.spawn ?
+ end
+end
+
+if not os.times then
+ -- utime = user time
+ -- stime = system time
+ -- cutime = children user time
+ -- cstime = children system time
+ function os.times()
+ return {
+ utime = os.gettimeofday(), -- user
+ stime = 0, -- system
+ cutime = 0, -- children user
+ cstime = 0, -- children system
+ }
+ end
+end
+
+os.gettimeofday = os.gettimeofday or os.clock
+
+local startuptime = os.gettimeofday()
+
+function os.runtime()
+ return os.gettimeofday() - startuptime
+end
+
+--~ print(os.gettimeofday()-os.time())
+--~ os.sleep(1.234)
+--~ print (">>",os.runtime())
+--~ print(os.date("%H:%M:%S",os.gettimeofday()))
+--~ print(os.date("%H:%M:%S",os.time()))
+
+-- no need for function anymore as we have more clever code and helpers now
+-- this metatable trickery might as well disappear
+
+os.resolvers = os.resolvers or { }
+
+local resolvers = os.resolvers
+
+local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end } -- maybe nil
+local osix = osmt.__index
+
+osmt.__index = function(t,k)
+ return (resolvers[k] or osix)(t,k)
+end
+
+setmetatable(os,osmt)
+
+if not os.setenv then
+
+ -- we still store them but they won't be seen in
+ -- child processes although we might pass them some day
+ -- using command concatination
+
+ local env, getenv = { }, os.getenv
+
+ function os.setenv(k,v)
+ env[k] = v
+ end
+
+ function os.getenv(k)
+ return env[k] or getenv(k)
+ end
+
+end
+
+-- we can use HOSTTYPE on some platforms
+
+local name, platform = os.name or "linux", os.getenv("MTX_PLATFORM") or ""
+
+local function guess()
+ local architecture = os.resultof("uname -m") or ""
+ if architecture ~= "" then
+ return architecture
+ end
+ architecture = os.getenv("HOSTTYPE") or ""
+ if architecture ~= "" then
+ return architecture
+ end
+ return os.resultof("echo $HOSTTYPE") or ""
+end
+
+if platform ~= "" then
+
+ os.platform = platform
+
+elseif os.type == "windows" then
+
+ -- we could set the variable directly, no function needed here
+
+ function os.resolvers.platform(t,k)
+ local platform, architecture = "", os.getenv("PROCESSOR_ARCHITECTURE") or ""
+ if find(architecture,"AMD64") then
+ platform = "mswin-64"
+ else
+ platform = "mswin"
+ end
+ os.setenv("MTX_PLATFORM",platform)
+ os.platform = platform
+ return platform
+ end
+
+elseif name == "linux" then
+
+ function os.resolvers.platform(t,k)
+ -- we sometims have HOSTTYPE set so let's check that first
+ local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
+ if find(architecture,"x86_64") then
+ platform = "linux-64"
+ elseif find(architecture,"ppc") then
+ platform = "linux-ppc"
+ else
+ platform = "linux"
+ end
+ os.setenv("MTX_PLATFORM",platform)
+ os.platform = platform
+ return platform
+ end
+
+elseif name == "macosx" then
+
+ --[[
+ Identifying the architecture of OSX is quite a mess and this
+ is the best we can come up with. For some reason $HOSTTYPE is
+ a kind of pseudo environment variable, not known to the current
+ environment. And yes, uname cannot be trusted either, so there
+ is a change that you end up with a 32 bit run on a 64 bit system.
+ Also, some proper 64 bit intel macs are too cheap (low-end) and
+ therefore not permitted to run the 64 bit kernel.
+ ]]--
+
+ function os.resolvers.platform(t,k)
+ -- local platform, architecture = "", os.getenv("HOSTTYPE") or ""
+ -- if architecture == "" then
+ -- architecture = os.resultof("echo $HOSTTYPE") or ""
+ -- end
+ local platform, architecture = "", os.resultof("echo $HOSTTYPE") or ""
+ if architecture == "" then
+ -- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n")
+ platform = "osx-intel"
+ elseif find(architecture,"i386") then
+ platform = "osx-intel"
+ elseif find(architecture,"x86_64") then
+ platform = "osx-64"
+ else
+ platform = "osx-ppc"
+ end
+ os.setenv("MTX_PLATFORM",platform)
+ os.platform = platform
+ return platform
+ end
+
+elseif name == "sunos" then
+
+ function os.resolvers.platform(t,k)
+ local platform, architecture = "", os.resultof("uname -m") or ""
+ if find(architecture,"sparc") then
+ platform = "solaris-sparc"
+ else -- if architecture == 'i86pc'
+ platform = "solaris-intel"
+ end
+ os.setenv("MTX_PLATFORM",platform)
+ os.platform = platform
+ return platform
+ end
+
+elseif name == "freebsd" then
+
+ function os.resolvers.platform(t,k)
+ local platform, architecture = "", os.resultof("uname -m") or ""
+ if find(architecture,"amd64") then
+ platform = "freebsd-amd64"
+ else
+ platform = "freebsd"
+ end
+ os.setenv("MTX_PLATFORM",platform)
+ os.platform = platform
+ return platform
+ end
+
+elseif name == "kfreebsd" then
+
+ function os.resolvers.platform(t,k)
+ -- we sometims have HOSTTYPE set so let's check that first
+ local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
+ if find(architecture,"x86_64") then
+ platform = "kfreebsd-64"
+ else
+ platform = "kfreebsd-i386"
+ end
+ os.setenv("MTX_PLATFORM",platform)
+ os.platform = platform
+ return platform
+ end
+
+else
+
+ -- platform = "linux"
+ -- os.setenv("MTX_PLATFORM",platform)
+ -- os.platform = platform
+
+ function os.resolvers.platform(t,k)
+ local platform = "linux"
+ os.setenv("MTX_PLATFORM",platform)
+ os.platform = platform
+ return platform
+ end
+
+end
+
+-- beware, we set the randomseed
+
+-- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the
+-- version number as well as two reserved bits. All other bits are set using a random or pseudorandom
+-- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal
+-- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479.
+--
+-- as we don't call this function too often there is not so much risk on repetition
+
+local t = { 8, 9, "a", "b" }
+
+function os.uuid()
+ return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x",
+ random(0xFFFF),random(0xFFFF),
+ random(0x0FFF),
+ t[ceil(random(4))] or 8,random(0x0FFF),
+ random(0xFFFF),
+ random(0xFFFF),random(0xFFFF),random(0xFFFF)
+ )
+end
+
+local d
+
+function os.timezone(delta)
+ d = d or tonumber(tonumber(os.date("%H")-os.date("!%H")))
+ if delta then
+ if d > 0 then
+ return format("+%02i:00",d)
+ else
+ return format("-%02i:00",-d)
+ end
+ else
+ return 1
+ end
+end
diff --git a/tex/context/base/l-pdfview.lua b/tex/context/base/l-pdfview.lua
new file mode 100644
index 000000000..627477ee8
--- /dev/null
+++ b/tex/context/base/l-pdfview.lua
@@ -0,0 +1,95 @@
+if not modules then modules = { } end modules ['l-pdfview'] = {
+ version = 1.001,
+ comment = "companion to mtx-context.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, getenv = string.format, os.getenv
+
+pdfview = pdfview or { }
+
+local opencalls = {
+ ['default'] = "pdfopen --file", -- "pdfopen --back --file"
+ ['xpdf'] = "xpdfopen",
+}
+
+local closecalls= {
+ ['default'] = "pdfclose --file",
+ ['xpdf'] = nil,
+}
+
+local allcalls = {
+ ['default'] = "pdfclose --all",
+ ['xpdf'] = nil,
+}
+
+if os.type == "windows" then
+ opencalls['okular'] = 'start "test" "c:/program files/kde/bin/okular.exe" --unique' -- todo: get focus
+else
+ opencalls['okular'] = 'okular --unique'
+end
+
+pdfview.METHOD = "MTX_PDFVIEW_METHOD"
+pdfview.method = getenv(pdfview.METHOD) or 'default'
+pdfview.method = (opencalls[pdfview.method] and pdfview.method) or 'default'
+
+function pdfview.methods()
+ return table.concat(table.sortedkeys(opencalls), " ")
+end
+
+function pdfview.status()
+ return format("pdfview methods: %s, current method: %s, MTX_PDFVIEW_METHOD=%s",pdfview.methods(),pdfview.method,getenv(pdfview.METHOD) or "")
+end
+
+local openedfiles = { }
+
+local function fullname(name)
+ return file.addsuffix(name,"pdf")
+end
+
+function pdfview.open(...)
+ local opencall = opencalls[pdfview.method]
+ if opencall then
+ local t = { ... }
+ for i=1,#t do
+ local name = fullname(t[i])
+ if io.exists(name) then
+ os.execute(format('%s "%s" 2>&1', opencall, name))
+ openedfiles[name] = true
+ end
+ end
+ end
+end
+
+function pdfview.close(...)
+ local closecall = closecalls[pdfview.method]
+ if closecall then
+ local t = { ... }
+ for i=1,#t do
+ local name = fullname(t[i])
+ if openedfiles[name] then
+ os.execute(format('%s "%s" 2>&1', closecall, name))
+ openedfiles[name] = nil
+ else
+ pdfview.closeall()
+ break
+ end
+ end
+ end
+end
+
+function pdfview.closeall()
+ local allcall = allcalls[pdfview.method]
+ if allcall then
+ os.execute(format('%s 2>&1', allcall))
+ end
+ openedfiles = { }
+end
+
+--~ pdfview.open("t:/document/show-exa.pdf")
+--~ os.sleep(3)
+--~ pdfview.close("t:/document/show-exa.pdf")
+
+return pdfview
diff --git a/tex/context/base/l-set.lua b/tex/context/base/l-set.lua
new file mode 100644
index 000000000..f844d0b40
--- /dev/null
+++ b/tex/context/base/l-set.lua
@@ -0,0 +1,84 @@
+if not modules then modules = { } end modules ['l-set'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+set = set or { }
+
+local nums = { }
+local tabs = { }
+local concat = table.concat
+local next, type = next, type
+
+set.create = table.tohash
+
+function set.tonumber(t)
+ if next(t) then
+ local s = ""
+ -- we could save mem by sorting, but it slows down
+ for k, v in next, t do
+ if v then
+ -- why bother about the leading space
+ s = s .. " " .. k
+ end
+ end
+ local n = nums[s]
+ if not n then
+ n = #tabs + 1
+ tabs[n] = t
+ nums[s] = n
+ end
+ return n
+ else
+ return 0
+ end
+end
+
+function set.totable(n)
+ if n == 0 then
+ return { }
+ else
+ return tabs[n] or { }
+ end
+end
+
+function set.tolist(n)
+ if n == 0 or not tabs[n] then
+ return ""
+ else
+ local t = { }
+ for k, v in next, tabs[n] do
+ if v then
+ t[#t+1] = k
+ end
+ end
+ return concat(t," ")
+ end
+end
+
+function set.contains(n,s)
+ if type(n) == "table" then
+ return n[s]
+ elseif n == 0 then
+ return false
+ else
+ local t = tabs[n]
+ return t and t[s]
+ end
+end
+
+--~ local c = set.create{'aap','noot','mies'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ local c = set.create{'zus','wim','jet'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ print(t['jet'])
+--~ print(set.contains(t,'jet'))
+--~ print(set.contains(t,'aap'))
+
diff --git a/tex/context/base/l-string.lua b/tex/context/base/l-string.lua
new file mode 100644
index 000000000..9856d5212
--- /dev/null
+++ b/tex/context/base/l-string.lua
@@ -0,0 +1,288 @@
+if not modules then modules = { } end modules ['l-string'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local sub, gsub, find, match, gmatch, format, char, byte, rep, lower = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower
+local lpegmatch = lpeg.match
+
+-- some functions may disappear as they are not used anywhere
+
+if not string.split then
+
+ -- this will be overloaded by a faster lpeg variant
+
+ function string:split(pattern)
+ if #self > 0 then
+ local t = { }
+ for s in gmatch(self..pattern,"(.-)"..pattern) do
+ t[#t+1] = s
+ end
+ return t
+ else
+ return { }
+ end
+ end
+
+end
+
+local chr_to_esc = {
+ ["%"] = "%%",
+ ["."] = "%.",
+ ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
+ ["^"] = "%^", ["$"] = "%$",
+ ["["] = "%[", ["]"] = "%]",
+ ["("] = "%(", [")"] = "%)",
+ ["{"] = "%{", ["}"] = "%}"
+}
+
+string.chr_to_esc = chr_to_esc
+
+function string:esc() -- variant 2
+ return (gsub(self,"(.)",chr_to_esc))
+end
+
+function string:unquote()
+ return (gsub(self,"^([\"\'])(.*)%1$","%2"))
+end
+
+--~ function string:unquote()
+--~ if find(self,"^[\'\"]") then
+--~ return sub(self,2,-2)
+--~ else
+--~ return self
+--~ end
+--~ end
+
+function string:quote() -- we could use format("%q")
+ return format("%q",self)
+end
+
+function string:count(pattern) -- variant 3
+ local n = 0
+ for _ in gmatch(self,pattern) do
+ n = n + 1
+ end
+ return n
+end
+
+function string:limit(n,sentinel)
+ if #self > n then
+ sentinel = sentinel or " ..."
+ return sub(self,1,(n-#sentinel)) .. sentinel
+ else
+ return self
+ end
+end
+
+--~ function string:strip() -- the .- is quite efficient
+--~ -- return match(self,"^%s*(.-)%s*$") or ""
+--~ -- return match(self,'^%s*(.*%S)') or '' -- posted on lua list
+--~ return find(s,'^%s*$') and '' or match(s,'^%s*(.*%S)')
+--~ end
+
+do -- roberto's variant:
+ local space = lpeg.S(" \t\v\n")
+ local nospace = 1 - space
+ local stripper = space^0 * lpeg.C((space^0 * nospace^1)^0)
+ function string.strip(str)
+ return lpegmatch(stripper,str) or ""
+ end
+end
+
+function string:is_empty()
+ return not find(self,"%S")
+end
+
+function string:enhance(pattern,action)
+ local ok, n = true, 0
+ while ok do
+ ok = false
+ self = gsub(self,pattern, function(...)
+ ok, n = true, n + 1
+ return action(...)
+ end)
+ end
+ return self, n
+end
+
+local chr_to_hex, hex_to_chr = { }, { }
+
+for i=0,255 do
+ local c, h = char(i), format("%02X",i)
+ chr_to_hex[c], hex_to_chr[h] = h, c
+end
+
+function string:to_hex()
+ return (gsub(self or "","(.)",chr_to_hex))
+end
+
+function string:from_hex()
+ return (gsub(self or "","(..)",hex_to_chr))
+end
+
+if not string.characters then
+
+ local function nextchar(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, sub(str,index,index)
+ end
+ function string:characters()
+ return nextchar, self, 0
+ end
+ local function nextbyte(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, byte(sub(str,index,index))
+ end
+ function string:bytes()
+ return nextbyte, self, 0
+ end
+
+end
+
+-- we can use format for this (neg n)
+
+function string:rpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self .. rep(chr or " ",m)
+ else
+ return self
+ end
+end
+
+function string:lpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return rep(chr or " ",m) .. self
+ else
+ return self
+ end
+end
+
+string.padd = string.rpadd
+
+function is_number(str) -- tonumber
+ return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1
+end
+
+--~ print(is_number("1"))
+--~ print(is_number("1.1"))
+--~ print(is_number(".1"))
+--~ print(is_number("-0.1"))
+--~ print(is_number("+0.1"))
+--~ print(is_number("-.1"))
+--~ print(is_number("+.1"))
+
+function string:split_settings() -- no {} handling, see l-aux for lpeg variant
+ if find(self,"=") then
+ local t = { }
+ for k,v in gmatch(self,"(%a+)=([^%,]*)") do
+ t[k] = v
+ end
+ return t
+ else
+ return nil
+ end
+end
+
+local patterns_escapes = {
+ ["-"] = "%-",
+ ["."] = "%.",
+ ["+"] = "%+",
+ ["*"] = "%*",
+ ["%"] = "%%",
+ ["("] = "%)",
+ [")"] = "%)",
+ ["["] = "%[",
+ ["]"] = "%]",
+}
+
+function string:pattesc()
+ return (gsub(self,".",patterns_escapes))
+end
+
+local simple_escapes = {
+ ["-"] = "%-",
+ ["."] = "%.",
+ ["?"] = ".",
+ ["*"] = ".*",
+}
+
+function string:simpleesc()
+ return (gsub(self,".",simple_escapes))
+end
+
+function string:tohash()
+ local t = { }
+ for s in gmatch(self,"([^, ]+)") do -- lpeg
+ t[s] = true
+ end
+ return t
+end
+
+local pattern = lpeg.Ct(lpeg.C(1)^0)
+
+function string:totable()
+ return lpegmatch(pattern,self)
+end
+
+--~ local t = {
+--~ "1234567123456712345671234567",
+--~ "a\tb\tc",
+--~ "aa\tbb\tcc",
+--~ "aaa\tbbb\tccc",
+--~ "aaaa\tbbbb\tcccc",
+--~ "aaaaa\tbbbbb\tccccc",
+--~ "aaaaaa\tbbbbbb\tcccccc",
+--~ }
+--~ for k,v do
+--~ print(string.tabtospace(t[k]))
+--~ end
+
+function string.tabtospace(str,tab)
+ -- we don't handle embedded newlines
+ while true do
+ local s = find(str,"\t")
+ if s then
+ if not tab then tab = 7 end -- only when found
+ local d = tab-(s-1) % tab
+ if d > 0 then
+ str = gsub(str,"\t",rep(" ",d),1)
+ else
+ str = gsub(str,"\t","",1)
+ end
+ else
+ break
+ end
+ end
+ return str
+end
+
+function string:compactlong() -- strips newlines and leading spaces
+ self = gsub(self,"[\n\r]+ *","")
+ self = gsub(self,"^ *","")
+ return self
+end
+
+function string:striplong() -- strips newlines and leading spaces
+ self = gsub(self,"^%s*","")
+ self = gsub(self,"[\n\r]+ *","\n")
+ return self
+end
+
+function string:topattern(lowercase,strict)
+ if lowercase then
+ self = lower(self)
+ end
+ self = gsub(self,".",simple_escapes)
+ if self == "" then
+ self = ".*"
+ elseif strict then
+ self = "^" .. self .. "$"
+ end
+ return self
+end
diff --git a/tex/context/base/l-table.lua b/tex/context/base/l-table.lua
new file mode 100644
index 000000000..ee395d0f1
--- /dev/null
+++ b/tex/context/base/l-table.lua
@@ -0,0 +1,910 @@
+if not modules then modules = { } end modules ['l-table'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+table.join = table.concat
+
+local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
+local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match
+local getmetatable, setmetatable = getmetatable, setmetatable
+local type, next, tostring, tonumber, ipairs = type, next, tostring, tonumber, ipairs
+
+-- Starting with version 5.2 Lua no longer provide ipairs, which makes
+-- sense. As we already used the for loop and # in most places the
+-- impact on ConTeXt was not that large; the remaining ipairs already
+-- have been replaced. In a similar fashio we also hardly used pairs.
+--
+-- Just in case, we provide the fallbacks as discussed in Programming
+-- in Lua (http://www.lua.org/pil/7.3.html):
+
+if not ipairs then
+
+ -- for k, v in ipairs(t) do ... end
+ -- for k=1,#t do local v = t[k] ... end
+
+ local function iterate(a,i)
+ i = i + 1
+ local v = a[i]
+ if v ~= nil then
+ return i, v --, nil
+ end
+ end
+
+ function ipairs(a)
+ return iterate, a, 0
+ end
+
+end
+
+if not pairs then
+
+ -- for k, v in pairs(t) do ... end
+ -- for k, v in next, t do ... end
+
+ function pairs(t)
+ return next, t -- , nil
+ end
+
+end
+
+-- Also, unpack has been moved to the table table, and for compatiility
+-- reasons we provide both now.
+
+if not table.unpack then
+ table.unpack = _G.unpack
+elseif not unpack then
+ _G.unpack = table.unpack
+end
+
+-- extra functions, some might go (when not used)
+
+function table.strip(tab)
+ local lst = { }
+ for i=1,#tab do
+ local s = gsub(tab[i],"^%s*(.-)%s*$","%1")
+ if s == "" then
+ -- skip this one
+ else
+ lst[#lst+1] = s
+ end
+ end
+ return lst
+end
+
+function table.keys(t)
+ local k = { }
+ for key, _ in next, t do
+ k[#k+1] = key
+ end
+ return k
+end
+
+local function compare(a,b)
+ return (tostring(a) < tostring(b))
+end
+
+local function sortedkeys(tab)
+ local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ if kind == 3 then
+ -- no further check
+ else
+ local tkey = type(key)
+ if tkey == "string" then
+ -- if kind == 2 then kind = 3 else kind = 1 end
+ kind = (kind == 2 and 3) or 1
+ elseif tkey == "number" then
+ -- if kind == 1 then kind = 3 else kind = 2 end
+ kind = (kind == 1 and 3) or 2
+ else
+ kind = 3
+ end
+ end
+ end
+ if kind == 0 or kind == 3 then
+ sort(srt,compare)
+ else
+ sort(srt)
+ end
+ return srt
+end
+
+local function sortedhashkeys(tab) -- fast one
+ local srt = { }
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ end
+ sort(srt)
+ return srt
+end
+
+table.sortedkeys = sortedkeys
+table.sortedhashkeys = sortedhashkeys
+
+function table.sortedhash(t)
+ local s = sortedhashkeys(t) -- maybe just sortedkeys
+ local n = 0
+ local function kv(s)
+ n = n + 1
+ local k = s[n]
+ return k, t[k]
+ end
+ return kv, s
+end
+
+table.sortedpairs = table.sortedhash
+
+function table.append(t, list)
+ for _,v in next, list do
+ insert(t,v)
+ end
+end
+
+function table.prepend(t, list)
+ for k,v in next, list do
+ insert(t,k,v)
+ end
+end
+
+function table.merge(t, ...) -- first one is target
+ t = t or {}
+ local lst = {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ t[k] = v
+ end
+ end
+ return t
+end
+
+function table.merged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ tmp[k] = v
+ end
+ end
+ return tmp
+end
+
+function table.imerge(t, ...)
+ local lst = {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ t[#t+1] = nst[j]
+ end
+ end
+ return t
+end
+
+function table.imerged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ tmp[#tmp+1] = nst[j]
+ end
+ end
+ return tmp
+end
+
+local function fastcopy(old) -- fast one
+ if old then
+ local new = { }
+ for k,v in next, old do
+ if type(v) == "table" then
+ new[k] = fastcopy(v) -- was just table.copy
+ else
+ new[k] = v
+ end
+ end
+ -- optional second arg
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+local function copy(t, tables) -- taken from lua wiki, slightly adapted
+ tables = tables or { }
+ local tcopy = {}
+ if not tables[t] then
+ tables[t] = tcopy
+ end
+ for i,v in next, t do -- brrr, what happens with sparse indexed
+ if type(i) == "table" then
+ if tables[i] then
+ i = tables[i]
+ else
+ i = copy(i, tables)
+ end
+ end
+ if type(v) ~= "table" then
+ tcopy[i] = v
+ elseif tables[v] then
+ tcopy[i] = tables[v]
+ else
+ tcopy[i] = copy(v, tables)
+ end
+ end
+ local mt = getmetatable(t)
+ if mt then
+ setmetatable(tcopy,mt)
+ end
+ return tcopy
+end
+
+table.fastcopy = fastcopy
+table.copy = copy
+
+-- roughly: copy-loop : unpack : sub == 0.9 : 0.4 : 0.45 (so in critical apps, use unpack)
+
+function table.sub(t,i,j)
+ return { unpack(t,i,j) }
+end
+
+function table.replace(a,b)
+ for k,v in next, b do
+ a[k] = v
+ end
+end
+
+-- slower than #t on indexed tables (#t only returns the size of the numerically indexed slice)
+
+function table.is_empty(t) -- obolete, use inline code instead
+ return not t or not next(t)
+end
+
+function table.one_entry(t) -- obolete, use inline code instead
+ local n = next(t)
+ return n and not next(t,n)
+end
+
+--~ function table.starts_at(t) -- obsolete, not nice anyway
+--~ return ipairs(t,1)(t,0)
+--~ end
+
+function table.tohash(t,value)
+ local h = { }
+ if t then
+ if value == nil then value = true end
+ for _, v in next, t do -- no ipairs here
+ h[v] = value
+ end
+ end
+ return h
+end
+
+function table.fromhash(t)
+ local h = { }
+ for k, v in next, t do -- no ipairs here
+ if v then h[#h+1] = k end
+ end
+ return h
+end
+
+--~ print(table.serialize(t), "\n")
+--~ print(table.serialize(t,"name"), "\n")
+--~ print(table.serialize(t,false), "\n")
+--~ print(table.serialize(t,true), "\n")
+--~ print(table.serialize(t,"name",true), "\n")
+--~ print(table.serialize(t,"name",true,true), "\n")
+
+table.serialize_functions = true
+table.serialize_compact = true
+table.serialize_inline = true
+
+local noquotes, hexify, handle, reduce, compact, inline, functions
+
+local reserved = table.tohash { -- intercept a language flaw, no reserved words as key
+ 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
+ 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
+}
+
+local function simple_table(t)
+ if #t > 0 then
+ local n = 0
+ for _,v in next, t do
+ n = n + 1
+ end
+ if n == #t then
+ local tt = { }
+ for i=1,#t do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "number" then
+ if hexify then
+ tt[#tt+1] = format("0x%04X",v)
+ else
+ tt[#tt+1] = tostring(v) -- tostring not needed
+ end
+ elseif tv == "boolean" then
+ tt[#tt+1] = tostring(v)
+ elseif tv == "string" then
+ tt[#tt+1] = format("%q",v)
+ else
+ tt = nil
+ break
+ end
+ end
+ return tt
+ end
+ end
+ return nil
+end
+
+-- Because this is a core function of mkiv I moved some function calls
+-- inline.
+--
+-- twice as fast in a test:
+--
+-- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) )
+
+-- problem: there no good number_to_string converter with the best resolution
+
+local function do_serialize(root,name,depth,level,indexed)
+ if level > 0 then
+ depth = depth .. " "
+ if indexed then
+ handle(format("%s{",depth))
+ elseif name then
+ --~ handle(format("%s%s={",depth,key(name)))
+ if type(name) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s[0x%04X]={",depth,name))
+ else
+ handle(format("%s[%s]={",depth,name))
+ end
+ elseif noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then
+ handle(format("%s%s={",depth,name))
+ else
+ handle(format("%s[%q]={",depth,name))
+ end
+ else
+ handle(format("%s{",depth))
+ end
+ end
+ -- we could check for k (index) being number (cardinal)
+ if root and next(root) then
+ local first, last = nil, 0 -- #root cannot be trusted here (will be ok in 5.2 when ipairs is gone)
+ if compact then
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
+ if not first then first = k end
+ last = last + 1
+ end
+ end
+ local sk = sortedkeys(root)
+ for i=1,#sk do
+ local k = sk[i]
+ local v = root[k]
+ --~ if v == root then
+ -- circular
+ --~ else
+ local t = type(v)
+ if compact and first and type(k) == "number" and k >= first and k <= last then
+ if t == "number" then
+ if hexify then
+ handle(format("%s 0x%04X,",depth,v))
+ else
+ handle(format("%s %s,",depth,v)) -- %.99g
+ end
+ elseif t == "string" then
+ if reduce and tonumber(v) then
+ handle(format("%s %s,",depth,v))
+ else
+ handle(format("%s %q,",depth,v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(format("%s {},",depth))
+ elseif inline then -- and #t > 0
+ local st = simple_table(v)
+ if st then
+ handle(format("%s { %s },",depth,concat(st,", ")))
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ elseif t == "boolean" then
+ handle(format("%s %s,",depth,tostring(v)))
+ elseif t == "function" then
+ if functions then
+ handle(format('%s loadstring(%q),',depth,dump(v)))
+ else
+ handle(format('%s "function",',depth))
+ end
+ else
+ handle(format("%s %q,",depth,tostring(v)))
+ end
+ elseif k == "__p__" then -- parent
+ if false then
+ handle(format("%s __p__=nil,",depth))
+ end
+ elseif t == "number" then
+ --~ if hexify then
+ --~ handle(format("%s %s=0x%04X,",depth,key(k),v))
+ --~ else
+ --~ handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g
+ --~ end
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ if hexify then
+ handle(format("%s %s=0x%04X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v)) -- %.99g
+ end
+ else
+ if hexify then
+ handle(format("%s [%q]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g
+ end
+ end
+ elseif t == "string" then
+ if reduce and tonumber(v) then
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
+ end
+ elseif t == "table" then
+ if not next(v) then
+ --~ handle(format("%s %s={},",depth,key(k)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ --~ handle(format("%s %s={ %s },",depth,key(k),concat(st,", ")))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ elseif t == "boolean" then
+ --~ handle(format("%s %s=%s,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%s,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%s,",depth,k,tostring(v)))
+ end
+ elseif t == "function" then
+ if functions then
+ --~ handle(format('%s %s=loadstring(%q),',depth,key(k),dump(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ end
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%q,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
+ end
+ end
+ --~ end
+ end
+ end
+ if level > 0 then
+ handle(format("%s},",depth))
+ end
+end
+
+-- replacing handle by a direct t[#t+1] = ... (plus test) is not much
+-- faster (0.03 on 1.00 for zapfino.tma)
+
+local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
+ noquotes = _noquotes
+ hexify = _hexify
+ handle = _handle or print
+ reduce = _reduce or false
+ compact = table.serialize_compact
+ inline = compact and table.serialize_inline
+ functions = table.serialize_functions
+ local tname = type(name)
+ if tname == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif tname == "number" then
+ if hexify then
+ handle(format("[0x%04X]={",name))
+ else
+ handle("[" .. name .. "]={")
+ end
+ elseif tname == "boolean" then
+ if name then
+ handle("return {")
+ else
+ handle("{")
+ end
+ else
+ handle("t={")
+ end
+ if root and next(root) then
+ do_serialize(root,name,"",0,indexed)
+ end
+ handle("}")
+end
+
+--~ name:
+--~
+--~ true : return { }
+--~ false : { }
+--~ nil : t = { }
+--~ string : string = { }
+--~ 'return' : return { }
+--~ number : [number] = { }
+
+function table.serialize(root,name,reduce,noquotes,hexify)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ return concat(t,"\n")
+end
+
+function table.tohandle(handle,root,name,reduce,noquotes,hexify)
+ serialize(root,name,handle,reduce,noquotes,hexify)
+end
+
+-- sometimes tables are real use (zapfino extra pro is some 85M) in which
+-- case a stepwise serialization is nice; actually, we could consider:
+--
+-- for line in table.serializer(root,name,reduce,noquotes) do
+-- ...(line)
+-- end
+--
+-- so this is on the todo list
+
+table.tofile_maxtab = 2*1024
+
+function table.tofile(filename,root,name,reduce,noquotes,hexify)
+ local f = io.open(filename,'w')
+ if f then
+ local maxtab = table.tofile_maxtab
+ if maxtab > 1 then
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ if #t > maxtab then
+ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+ t = { }
+ end
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ f:write(concat(t,"\n"),"\n")
+ else
+ local function flush(s)
+ f:write(s,"\n")
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ end
+ f:close()
+ end
+end
+
+local function flatten(t,f,complete) -- is this used? meybe a variant with next, ...
+ for i=1,#t do
+ local v = t[i]
+ if type(v) == "table" then
+ if complete or type(v[1]) == "table" then
+ flatten(v,f,complete)
+ else
+ f[#f+1] = v
+ end
+ else
+ f[#f+1] = v
+ end
+ end
+end
+
+function table.flatten(t)
+ local f = { }
+ flatten(t,f,true)
+ return f
+end
+
+function table.unnest(t) -- bad name
+ local f = { }
+ flatten(t,f,false)
+ return f
+end
+
+table.flatten_one_level = table.unnest
+
+-- a better one:
+
+local function flattened(t,f)
+ if not f then
+ f = { }
+ end
+ for k, v in next, t do
+ if type(v) == "table" then
+ flattened(v,f)
+ else
+ f[k] = v
+ end
+ end
+ return f
+end
+
+table.flattened = flattened
+
+-- the next three may disappear
+
+function table.remove_value(t,value) -- todo: n
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ remove(t,i)
+ -- remove all, so no: return
+ end
+ end
+ end
+end
+
+function table.insert_before_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i,str)
+ return
+ end
+ end
+ end
+ insert(t,1,str)
+ elseif value then
+ insert(t,1,value)
+ end
+end
+
+function table.insert_after_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i+1,str)
+ return
+ end
+ end
+ end
+ t[#t+1] = str
+ elseif value then
+ t[#t+1] = value
+ end
+end
+
+local function are_equal(a,b,n,m) -- indexed
+ if a and b and #a == #b then
+ n = n or 1
+ m = m or #a
+ for i=n,m do
+ local ai, bi = a[i], b[i]
+ if ai==bi then
+ -- same
+ elseif type(ai)=="table" and type(bi)=="table" then
+ if not are_equal(ai,bi) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+ else
+ return false
+ end
+end
+
+local function identical(a,b) -- assumes same structure
+ for ka, va in next, a do
+ local vb = b[k]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+end
+
+table.are_equal = are_equal
+table.identical = identical
+
+-- maybe also make a combined one
+
+function table.compact(t)
+ if t then
+ for k,v in next, t do
+ if not next(v) then
+ t[k] = nil
+ end
+ end
+ end
+end
+
+function table.contains(t, v)
+ if t then
+ for i=1, #t do
+ if t[i] == v then
+ return i
+ end
+ end
+ end
+ return false
+end
+
+function table.count(t)
+ local n, e = 0, next(t)
+ while e do
+ n, e = n + 1, next(t,e)
+ end
+ return n
+end
+
+function table.swapped(t)
+ local s = { }
+ for k, v in next, t do
+ s[v] = k
+ end
+ return s
+end
+
+--~ function table.are_equal(a,b)
+--~ return table.serialize(a) == table.serialize(b)
+--~ end
+
+function table.clone(t,p) -- t is optional or nil or table
+ if not p then
+ t, p = { }, t or { }
+ elseif not t then
+ t = { }
+ end
+ setmetatable(t, { __index = function(_,key) return p[key] end }) -- why not __index = p ?
+ return t
+end
+
+function table.hexed(t,seperator)
+ local tt = { }
+ for i=1,#t do tt[i] = format("0x%04X",t[i]) end
+ return concat(tt,seperator or " ")
+end
+
+function table.reverse_hash(h)
+ local r = { }
+ for k,v in next, h do
+ r[v] = lower(gsub(k," ",""))
+ end
+ return r
+end
+
+function table.reverse(t)
+ local tt = { }
+ if #t > 0 then
+ for i=#t,1,-1 do
+ tt[#tt+1] = t[i]
+ end
+ end
+ return tt
+end
+
+function table.insert_before_value(t,value,extra)
+ for i=1,#t do
+ if t[i] == extra then
+ remove(t,i)
+ end
+ end
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i,extra)
+ return
+ end
+ end
+ insert(t,1,extra)
+end
+
+function table.insert_after_value(t,value,extra)
+ for i=1,#t do
+ if t[i] == extra then
+ remove(t,i)
+ end
+ end
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i+1,extra)
+ return
+ end
+ end
+ insert(t,#t+1,extra)
+end
+
diff --git a/tex/context/base/l-unicode.lua b/tex/context/base/l-unicode.lua
new file mode 100644
index 000000000..0c5a60142
--- /dev/null
+++ b/tex/context/base/l-unicode.lua
@@ -0,0 +1,199 @@
+if not modules then modules = { } end modules ['l-unicode'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if not unicode then
+
+ unicode = { utf8 = { } }
+
+ local floor, char = math.floor, string.char
+
+ function unicode.utf8.utfchar(n)
+ if n < 0x80 then
+ return char(n)
+ elseif n < 0x800 then
+ return char(0xC0 + floor(n/0x40)) .. char(0x80 + (n % 0x40))
+ elseif n < 0x10000 then
+ return char(0xE0 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
+ elseif n < 0x40000 then
+ return char(0xF0 + floor(n/0x40000)) .. char(0x80 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
+ else -- wrong:
+ -- return char(0xF1 + floor(n/0x1000000)) .. char(0x80 + floor(n/0x40000)) .. char(0x80 + floor(n/0x1000)) .. char(0x80 + (floor(n/0x40) % 0x40)) .. char(0x80 + (n % 0x40))
+ return "?"
+ end
+ end
+
+end
+
+utf = utf or unicode.utf8
+
+local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub
+local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs
+
+-- 0 EF BB BF UTF-8
+-- 1 FF FE UTF-16-little-endian
+-- 2 FE FF UTF-16-big-endian
+-- 3 FF FE 00 00 UTF-32-little-endian
+-- 4 00 00 FE FF UTF-32-big-endian
+
+unicode.utfname = {
+ [0] = 'utf-8',
+ [1] = 'utf-16-le',
+ [2] = 'utf-16-be',
+ [3] = 'utf-32-le',
+ [4] = 'utf-32-be'
+}
+
+-- \000 fails in <= 5.0 but is valid in >=5.1 where %z is depricated
+
+function unicode.utftype(f)
+ local str = f:read(4)
+ if not str then
+ f:seek('set')
+ return 0
+ -- elseif find(str,"^%z%z\254\255") then -- depricated
+ -- elseif find(str,"^\000\000\254\255") then -- not permitted and bugged
+ elseif find(str,"\000\000\254\255",1,true) then -- seems to work okay (TH)
+ return 4
+ -- elseif find(str,"^\255\254%z%z") then -- depricated
+ -- elseif find(str,"^\255\254\000\000") then -- not permitted and bugged
+ elseif find(str,"\255\254\000\000",1,true) then -- seems to work okay (TH)
+ return 3
+ elseif find(str,"^\254\255") then
+ f:seek('set',2)
+ return 2
+ elseif find(str,"^\255\254") then
+ f:seek('set',2)
+ return 1
+ elseif find(str,"^\239\187\191") then
+ f:seek('set',3)
+ return 0
+ else
+ f:seek('set')
+ return 0
+ end
+end
+
+function unicode.utf16_to_utf8(str, endian) -- maybe a gsub is faster or an lpeg
+ local result, tmp, n, m, p = { }, { }, 0, 0, 0
+ -- lf | cr | crlf / (cr:13, lf:10)
+ local function doit()
+ if n == 10 then
+ if p ~= 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = 0
+ end
+ elseif n == 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = n
+ else
+ tmp[#tmp+1] = utfchar(n)
+ p = 0
+ end
+ end
+ for l,r in bytepairs(str) do
+ if r then
+ if endian then
+ n = l*256 + r
+ else
+ n = r*256 + l
+ end
+ if m > 0 then
+ n = (m-0xD800)*0x400 + (n-0xDC00) + 0x10000
+ m = 0
+ doit()
+ elseif n >= 0xD800 and n <= 0xDBFF then
+ m = n
+ else
+ doit()
+ end
+ end
+ end
+ if #tmp > 0 then
+ result[#result+1] = concat(tmp)
+ end
+ return result
+end
+
+function unicode.utf32_to_utf8(str, endian)
+ local result = { }
+ local tmp, n, m, p = { }, 0, -1, 0
+ -- lf | cr | crlf / (cr:13, lf:10)
+ local function doit()
+ if n == 10 then
+ if p ~= 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = 0
+ end
+ elseif n == 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = n
+ else
+ tmp[#tmp+1] = utfchar(n)
+ p = 0
+ end
+ end
+ for a,b in bytepairs(str) do
+ if a and b then
+ if m < 0 then
+ if endian then
+ m = a*256*256*256 + b*256*256
+ else
+ m = b*256 + a
+ end
+ else
+ if endian then
+ n = m + a*256 + b
+ else
+ n = m + b*256*256*256 + a*256*256
+ end
+ m = -1
+ doit()
+ end
+ else
+ break
+ end
+ end
+ if #tmp > 0 then
+ result[#result+1] = concat(tmp)
+ end
+ return result
+end
+
+local function little(c)
+ local b = byte(c) -- b = c:byte()
+ if b < 0x10000 then
+ return char(b%256,b/256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1%256,b1/256,b2%256,b2/256)
+ end
+end
+
+local function big(c)
+ local b = byte(c)
+ if b < 0x10000 then
+ return char(b/256,b%256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1/256,b1%256,b2/256,b2%256)
+ end
+end
+
+function unicode.utf8_to_utf16(str,littleendian)
+ if littleendian then
+ return char(255,254) .. utfgsub(str,".",little)
+ else
+ return char(254,255) .. utfgsub(str,".",big)
+ end
+end
diff --git a/tex/context/base/l-url.lua b/tex/context/base/l-url.lua
new file mode 100644
index 000000000..e3e6f8130
--- /dev/null
+++ b/tex/context/base/l-url.lua
@@ -0,0 +1,134 @@
+if not modules then modules = { } end modules ['l-url'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local char, gmatch, gsub = string.char, string.gmatch, string.gsub
+local tonumber, type = tonumber, type
+local lpegmatch = lpeg.match
+
+-- from the spec (on the web):
+--
+-- foo://example.com:8042/over/there?name=ferret#nose
+-- \_/ \______________/\_________/ \_________/ \__/
+-- | | | | |
+-- scheme authority path query fragment
+-- | _____________________|__
+-- / \ / \
+-- urn:example:animal:ferret:nose
+
+url = url or { }
+
+local function tochar(s)
+ return char(tonumber(s,16))
+end
+
+local colon, qmark, hash, slash, percent, endofstring = lpeg.P(":"), lpeg.P("?"), lpeg.P("#"), lpeg.P("/"), lpeg.P("%"), lpeg.P(-1)
+
+local hexdigit = lpeg.R("09","AF","af")
+local plus = lpeg.P("+")
+local escaped = (plus / " ") + (percent * lpeg.C(hexdigit * hexdigit) / tochar)
+
+-- we assume schemes with more than 1 character (in order to avoid problems with windows disks)
+
+local scheme = lpeg.Cs((escaped+(1-colon-slash-qmark-hash))^2) * colon + lpeg.Cc("")
+local authority = slash * slash * lpeg.Cs((escaped+(1- slash-qmark-hash))^0) + lpeg.Cc("")
+local path = slash * lpeg.Cs((escaped+(1- qmark-hash))^0) + lpeg.Cc("")
+local query = qmark * lpeg.Cs((escaped+(1- hash))^0) + lpeg.Cc("")
+local fragment = hash * lpeg.Cs((escaped+(1- endofstring))^0) + lpeg.Cc("")
+
+local parser = lpeg.Ct(scheme * authority * path * query * fragment)
+
+-- todo: reconsider Ct as we can as well have five return values (saves a table)
+-- so we can have two parsers, one with and one without
+
+function url.split(str)
+ return (type(str) == "string" and lpegmatch(parser,str)) or str
+end
+
+-- todo: cache them
+
+function url.hashed(str)
+ local s = url.split(str)
+ local somescheme = s[1] ~= ""
+ return {
+ scheme = (somescheme and s[1]) or "file",
+ authority = s[2],
+ path = s[3],
+ query = s[4],
+ fragment = s[5],
+ original = str,
+ noscheme = not somescheme,
+ }
+end
+
+function url.hasscheme(str)
+ return url.split(str)[1] ~= ""
+end
+
+function url.addscheme(str,scheme)
+ return (url.hasscheme(str) and str) or ((scheme or "file:///") .. str)
+end
+
+function url.construct(hash)
+ local fullurl = hash.sheme .. "://".. hash.authority .. hash.path
+ if hash.query then
+ fullurl = fullurl .. "?".. hash.query
+ end
+ if hash.fragment then
+ fullurl = fullurl .. "?".. hash.fragment
+ end
+ return fullurl
+end
+
+function url.filename(filename)
+ local t = url.hashed(filename)
+ return (t.scheme == "file" and (gsub(t.path,"^/([a-zA-Z])([:|])/)","%1:"))) or filename
+end
+
+function url.query(str)
+ if type(str) == "string" then
+ local t = { }
+ for k, v in gmatch(str,"([^&=]*)=([^&=]*)") do
+ t[k] = v
+ end
+ return t
+ else
+ return str
+ end
+end
+
+--~ print(url.filename("file:///c:/oeps.txt"))
+--~ print(url.filename("c:/oeps.txt"))
+--~ print(url.filename("file:///oeps.txt"))
+--~ print(url.filename("file:///etc/test.txt"))
+--~ print(url.filename("/oeps.txt"))
+
+--~ from the spec on the web (sort of):
+--~
+--~ function test(str)
+--~ print(table.serialize(url.hashed(str)))
+--~ end
+--~
+--~ test("%56pass%20words")
+--~ test("file:///c:/oeps.txt")
+--~ test("file:///c|/oeps.txt")
+--~ test("file:///etc/oeps.txt")
+--~ test("file://./etc/oeps.txt")
+--~ test("file:////etc/oeps.txt")
+--~ test("ftp://ftp.is.co.za/rfc/rfc1808.txt")
+--~ test("http://www.ietf.org/rfc/rfc2396.txt")
+--~ test("ldap://[2001:db8::7]/c=GB?objectClass?one#what")
+--~ test("mailto:John.Doe@example.com")
+--~ test("news:comp.infosystems.www.servers.unix")
+--~ test("tel:+1-816-555-1212")
+--~ test("telnet://192.0.2.16:80/")
+--~ test("urn:oasis:names:specification:docbook:dtd:xml:4.1.2")
+--~ test("/etc/passwords")
+--~ test("http://www.pragma-ade.com/spaced%20name")
+
+--~ test("zip:///oeps/oeps.zip#bla/bla.tex")
+--~ test("zip:///oeps/oeps.zip?bla/bla.tex")
diff --git a/tex/context/base/l-utils.lua b/tex/context/base/l-utils.lua
new file mode 100644
index 000000000..ebc27b8cf
--- /dev/null
+++ b/tex/context/base/l-utils.lua
@@ -0,0 +1,176 @@
+if not modules then modules = { } end modules ['l-utils'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- hm, quite unreadable
+
+local gsub = string.gsub
+local concat = table.concat
+local type, next = type, next
+
+if not utils then utils = { } end
+if not utils.merger then utils.merger = { } end
+if not utils.lua then utils.lua = { } end
+
+utils.merger.m_begin = "begin library merge"
+utils.merger.m_end = "end library merge"
+utils.merger.pattern =
+ "%c+" ..
+ "%-%-%s+" .. utils.merger.m_begin ..
+ "%c+(.-)%c+" ..
+ "%-%-%s+" .. utils.merger.m_end ..
+ "%c+"
+
+function utils.merger._self_fake_()
+ return
+ "-- " .. "created merged file" .. "\n\n" ..
+ "-- " .. utils.merger.m_begin .. "\n\n" ..
+ "-- " .. utils.merger.m_end .. "\n\n"
+end
+
+function utils.report(...)
+ print(...)
+end
+
+utils.merger.strip_comment = true
+
+function utils.merger._self_load_(name)
+ local f, data = io.open(name), ""
+ if f then
+ utils.report("reading merge from %s",name)
+ data = f:read("*all")
+ f:close()
+ else
+ utils.report("unknown file to merge %s",name)
+ end
+ if data and utils.merger.strip_comment then
+ -- saves some 20K
+ data = gsub(data,"%-%-~[^\n\r]*[\r\n]", "")
+ end
+ return data or ""
+end
+
+function utils.merger._self_save_(name, data)
+ if data ~= "" then
+ local f = io.open(name,'w')
+ if f then
+ utils.report("saving merge from %s",name)
+ f:write(data)
+ f:close()
+ end
+ end
+end
+
+function utils.merger._self_swap_(data,code)
+ if data ~= "" then
+ return (gsub(data,utils.merger.pattern, function(s)
+ return "\n\n" .. "-- "..utils.merger.m_begin .. "\n" .. code .. "\n" .. "-- "..utils.merger.m_end .. "\n\n"
+ end, 1))
+ else
+ return ""
+ end
+end
+
+--~ stripper:
+--~
+--~ data = gsub(data,"%-%-~[^\n]*\n","")
+--~ data = gsub(data,"\n\n+","\n")
+
+function utils.merger._self_libs_(libs,list)
+ local result, f, frozen = { }, nil, false
+ result[#result+1] = "\n"
+ if type(libs) == 'string' then libs = { libs } end
+ if type(list) == 'string' then list = { list } end
+ local foundpath = nil
+ for i=1,#libs do
+ local lib = libs[i]
+ for j=1,#list do
+ local pth = gsub(list[j],"\\","/") -- file.clean_path
+ utils.report("checking library path %s",pth)
+ local name = pth .. "/" .. lib
+ if lfs.isfile(name) then
+ foundpath = pth
+ end
+ end
+ if foundpath then break end
+ end
+ if foundpath then
+ utils.report("using library path %s",foundpath)
+ local right, wrong = { }, { }
+ for i=1,#libs do
+ local lib = libs[i]
+ local fullname = foundpath .. "/" .. lib
+ if lfs.isfile(fullname) then
+ -- right[#right+1] = lib
+ utils.report("merging library %s",fullname)
+ result[#result+1] = "do -- create closure to overcome 200 locals limit"
+ result[#result+1] = io.loaddata(fullname,true)
+ result[#result+1] = "end -- of closure"
+ else
+ -- wrong[#wrong+1] = lib
+ utils.report("no library %s",fullname)
+ end
+ end
+ if #right > 0 then
+ utils.report("merged libraries: %s",concat(right," "))
+ end
+ if #wrong > 0 then
+ utils.report("skipped libraries: %s",concat(wrong," "))
+ end
+ else
+ utils.report("no valid library path found")
+ end
+ return concat(result, "\n\n")
+end
+
+function utils.merger.selfcreate(libs,list,target)
+ if target then
+ utils.merger._self_save_(
+ target,
+ utils.merger._self_swap_(
+ utils.merger._self_fake_(),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+ end
+end
+
+function utils.merger.selfmerge(name,libs,list,target)
+ utils.merger._self_save_(
+ target or name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+end
+
+function utils.merger.selfclean(name)
+ utils.merger._self_save_(
+ name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ ""
+ )
+ )
+end
+
+function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true
+ -- utils.report("compiling",luafile,"into",lucfile)
+ os.remove(lucfile)
+ local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
+ if strip ~= false then
+ command = "-s " .. command
+ end
+ local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0)
+ if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
+ -- utils.report("removing",luafile)
+ os.remove(luafile)
+ end
+ return done
+end
+
diff --git a/tex/context/base/l-xml.lua b/tex/context/base/l-xml.lua
new file mode 100644
index 000000000..14e97337b
--- /dev/null
+++ b/tex/context/base/l-xml.lua
@@ -0,0 +1,23 @@
+if not modules then modules = { } end modules ['l-xml'] = {
+ version = 1.001,
+ comment = "this module is replaced by the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- We asume that the helper modules l-*.lua are loaded
+-- already. But anyway if you use mtxrun to run your script
+-- all is taken care of.
+
+if not trackers then
+ require('trac-tra')
+end
+
+if not xml then
+ require('lxml-tab')
+ require('lxml-lpt')
+ require('lxml-mis')
+ require('lxml-aux')
+ require('lxml-xml')
+end
diff --git a/tex/context/base/lang-all.xml b/tex/context/base/lang-all.xml
new file mode 100644
index 000000000..503cb0ae5
--- /dev/null
+++ b/tex/context/base/lang-all.xml
@@ -0,0 +1,376 @@
+
+
+
+
+
+
+
+ bahyph.tex
+ TeX hyphenation patterns for the Basque language
+
+ 1991
+ Julio Sanchez (jsanchez@gmv.es)
+ These patterns have been derived from "On Word Division in Spanish"
+ Jos'e A. Ma~nas
+
+
+ 1997
+ Juan M. Aguirregabiria (wtpagagj@lg.ehu.es)
+ Adaption to TeX based on shyphen.sh
+
+
+
+
+ cahyph.tex
+ TeX hyphenation patterns for the Catalan language
+ Version 1.11
+
+ 1991-1995
+ Gon\c{c}al Badenes,Francina Turon
+
+
+ 1991-2003
+ Gon\c{c}al Badenes
+
+
+
+
+ cyhyph.tex
+ TeX hyphenation patterns for the Welsh Language
+ v3,GNU General Public License
+
+ 1996
+ Yannis Haralambous
+ Inputs cathyph.tex, patterns in EC/DC encoding
+
+
+
+
+ czhyphen.tex
+ TeX hyphenation patterns for the Czech language
+
+ 1991
+ Karel Horak
+ List of exceptions
+
+
+ 1995
+ Pavel Sevecek (\v{S}eve\v{c}ek) (pavel@lingea.cz)
+ Macros, adaption for TeX 2
+
+
+
+
+
+ dkspecial.tex dkcommon.tex
+ TeX hyphenation patterns for the Danish language
+
+
+
+
+ dehyphn.tex
+ TeX hyphenation patterns for the German language (new orthography)
+
+ 1988, 1991
+ Rechenzentrum der Ruhr-Universitaet Bochum
+ German hyphen patterns
+
+
+ 1993, 1994, 1999
+ Bernd Raichle/DANTE e.V.
+ Macros, adaption for TeX 2
+
+
+ 1998-2001
+ Walter Schmidt
+ Adaption to new German orthography
+
+
+
+
+ dehypht.tex
+ TeX hyphenation patterns for the German language (traditional orthography)
+
+ 1988, 1991
+ Rechenzentrum der Ruhr-Universitaet Bochum
+ German hyphen patterns
+
+
+ 1993, 1994, 1999
+ Bernd Raichle/DANTE e.V.
+ Macros, adaption for TeX 2
+
+
+
+
+ hyphen.tex
+ Plain TeX hyphenation patterns for the English language (US)
+ [NOT TO BE CHANGED IN ANY WAY!]
+
+
+
+
+ eshyph.tex
+ TeX hyphenation patterns for the Spanish language
+
+ 1993
+ Francesc Carmona (franc@porthos.bio.ub.es)
+
+
+
+
+ fihyph.tex
+ TeX hyphenation patterns for the Finnish language
+
+ 1986
+ Kauko Saarinen
+ First release
+
+
+ 1988
+ Fred Karlsson
+ Completely rewritten patterns
+
+
+ 1989
+ Fred Karlsson
+ Some vowel tripples added
+
+
+ 1995
+ Thomas Esser
+ Added \uccode and \lccode
+
+
+
+
+ frhyph.tex
+ TeX hyphenation patterns for the French language
+ V2.11
+
+ Jacques Desarmenien, Norman Buckle, Michael Ferguson, Justin Bur, Daniel Flipo and Bernard Gaulle
+
+
+ 1996
+ Bernd Raichle/DANTE e.V.
+ Adaption for TeX 3.x and MLTeX 3.x (2.x)
+
+
+
+
+ hrhyph.tex
+ TeX hyphenation patterns for the Croatian language
+
+ 1994, 1996
+ Marinovi\'c Igor (migor@student.math.hr)
+
+
+
+
+ huhyphn.tex
+ TeX hyphenation patterns for the Hungarian language
+
+
+
+ ishyph.tex
+ Plain TeX hyphenation patterns for the Icelandic language
+ [NOT TO BE CHANGED IN ANY WAY!]
+
+ 1987
+ Jorgen Pind
+
+
+
+
+ ithyph.tex
+ TeX hyphenation patterns for the Italian language
+ v4.8d
+
+ 1998, 2001
+ Claudio Beccari
+
+
+ 1993, 1994, 1999
+ Bernd Raichle/DANTE e.V.
+ Macros, adaption for TeX 2
+
+
+
+
+ lahyph.tex
+ TeX hyphenation patterns for the Latin language
+ v3.0b
+
+ 1999-2001
+ Claudio Beccari
+
+
+ 1993, 1994, 1998, 1999
+ Bernd Raichle/DANTE e.V.
+ Macro code in 'dehypht.tex'
+
+
+
+
+ nehyph96.tex
+ TeX hyphenation patterns for the Dutch language
+
+ 1996
+ Piet Tutelaers (P.T.H.Tutelaers@tue.nl)
+ 8-bit hyphenation patterns for TeX based upon the new Dutch
+ spelling, officially since 1 August 1996. These patterns follow
+ the new hyphenation rules in the `Woordenlijst Nederlandse
+ Taal, SDU Uitgevers, Den Haag 1995' (the so called `Groene
+ Boekje') described in section 5.2 (Het afbreekteken)
+
+
+
+
+
+
+ nohyph.tex
+ TeX hyphenation patterns for the Norwegian language
+
+ 2005
+ Rune Kleveland with patches from Ole Michael Selberg
+ nohyphbx.tex
+
+
+ 200+
+ Rune Kleveland
+ nohyphb.tex
+
+
+ 199+
+ Dag Langmyhr and student
+ nohyph2.tex
+
+
+ 199+
+ Ivar Aavatsmark and others
+ nohyph.tex sometimes named nohyph1.tex
+
+
+ 1992,1993
+ Ivar Aavatsmark
+ nohyphen.tex based on danhyph.tex
+
+
+ 1994
+ Preben Randhol, Jon Martin Solaas
+
+
+ 1995
+ Thomas Esser (te@dbs.uni-hannover.de)
+ Make patterns work with non-T1 encoding
+
+
+
+
+ plhyph.tex
+ TeX hyphenation patterns for the Polish language
+
+
+
+
+ pthyph.tex
+ TeX hyphenation patterns for the Portuguese language
+
+
+
+
+ rohyph.tex
+ TeX hyphenation patterns for the Romanian language
+
+
+
+
+ skhyphen.tex skhyphen.ex
+ TeX hyphenation patterns for the Slovakian language
+
+ 1992
+ Jana Chlebikova
+
+
+ 1991
+ Karel Horak
+ List of exceptions
+
+
+
+
+ sihyph.tex
+ TeX hyphenation patterns for the Slovenian language
+
+ 1990
+ TeXCeX (SLO),TeXCeH Norbert Schwarz
+
+
+ 1994
+ Leon "Zlajpah (leon.zlajpah@ijs.si)
+ Use of code page 852 in patterns
+
+
+ 1995,1997
+ Leon "Zlajpah (leon.zlajpah@ijs.si)
+ Adaptaion of Slovenian hyphenation pattens, macros
+
+
+
+
+ svhyph.tex
+ TeX hyphenation patterns for the Swedish language
+
+ 1991,1994
+ Jan Michael Rynning
+
+
+
+
+ tkhyph.tex
+ TeX hyphenation patterns for the modern Turkish language
+
+ 1996
+ Yannis Haralambous
+ A mechanically generated Turkish Hyphenation table for TeX,
+ using the University of Washington diacritical coding
+ developed by P. A. MacKay for the Ottoman Texts Project
+
+
+
+
+ ukhyphen.tex
+ TeX hyphenation patterns for the English language (UK)
+
+
+
+
+ Vietnamese needs no patterns.
+
+
+
+ grahyph4.tex
+ TeX hyphenation patterns for the ancient Greek language
+
+ 2004
+ Dimitrios Filippou
+ These hyphenation patterns are explained in "ancient.pdf".
+ Hyphenation examples are given in the file "anc-test.pdf".
+ Some doubtful patterns are marked by three question marks "???".
+
+
+
+
diff --git a/tex/context/base/lang-alt.tex b/tex/context/base/lang-alt.tex
new file mode 100644
index 000000000..f65acbda3
--- /dev/null
+++ b/tex/context/base/lang-alt.tex
@@ -0,0 +1,152 @@
+%D \module
+%D [ file=lang-alt,
+%D version=1997.09.03,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Altaic Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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 Language Macros / Altaic Languages}
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+
+% Uigur, Uzbek
+% Azeri/Azerbaijani, Chuvash, Turkish, Turkmen
+% Kazakh, Kazar, Kireghiz, Noghay, Talar
+% Buryat, Kalmuck, Khalkha
+%
+% Turkmen translation by Nazar Annagurban 18. March 2010
+
+\unprotect
+
+\installlanguage
+ [\s!tr]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day}]
+
+\installlanguage
+ [\s!tk]
+ [\c!spacing=\v!broad,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day}
+ \s!patterns=\s!tk,
+ \s!lefthyphenmin=1,
+ \s!righthyphenmin=2]
+
+\installlanguage [turkish] [\s!tr]
+\installlanguage [turkmen] [\s!tk]
+
+\setupheadtext [\s!tr] [\v!content=Fihrist]
+\setupheadtext [\s!tk] [\v!content=Mazmuny]
+\setupheadtext [\s!tr] [\v!tables=Tablolar]
+\setupheadtext [\s!tk] [\v!tables=Tablisalar]
+\setupheadtext [\s!tr] [\v!figures=\Scedilla ekiller]
+\setupheadtext [\s!tk] [\v!figures=Suratlar]
+\setupheadtext [\s!tr] [\v!graphics=Grafikler]
+\setupheadtext [\s!tk] [\v!graphics=Grafikler]
+\setupheadtext [\s!tr] [\v!intermezzi=...]
+\setupheadtext [\s!tk] [\v!intermezzi=Arakesmeler]
+\setupheadtext [\s!tr] [\v!index=\Idotaccent ndex]
+\setupheadtext [\s!tk] [\v!index=Indeks]
+\setupheadtext [\s!tr] [\v!abbreviations=K\dotlessi saltmalar]
+\setupheadtext [\s!tk] [\v!abbreviations=Gysgaltmalar]
+\setupheadtext [\s!tr] [\v!logos=Logolar]
+\setupheadtext [\s!tk] [\v!logos=Logolar]
+\setupheadtext [\s!tr] [\v!units=Birimler]
+\setupheadtext [\s!tk] [\v!units=Birlikler]
+
+\setuplabeltext [\s!tr] [\v!table=Tablo ]
+\setuplabeltext [\s!tk] [\v!table=Tablisa]
+\setuplabeltext [\s!tr] [\v!figure=\Scedilla ekil ]
+\setuplabeltext [\s!tk] [\v!figure=Surat]
+\setuplabeltext [\s!tr] [\v!intermezzo=... ]
+\setuplabeltext [\s!tk] [\v!intermezzo=Arakesme]
+\setuplabeltext [\s!tr] [\v!graphic=Grafik]
+\setuplabeltext [\s!tk] [\v!graphic=Grafik]
+\setuplabeltext [\s!tr] [\v!chapter=]
+\setuplabeltext [\s!tk] [\v!chapter=Bap]
+\setuplabeltext [\s!tr] [\v!section=]
+\setuplabeltext [\s!tk] [\v!section=]
+\setuplabeltext [\s!tr] [\v!subsection=]
+\setuplabeltext [\s!tk] [\v!subsection=]
+\setuplabeltext [\s!tr] [\v!subsubsection=]
+\setuplabeltext [\s!tr] [\v!subsubsubsection=]
+\setuplabeltext [\s!tk] [\v!subsubsubsection=]
+\setuplabeltext [\s!tr] [\v!appendix=]
+\setuplabeltext [\s!tk] [\v!appendix=Go\scedilla ma\ccedilla a]
+\setuplabeltext [\s!tr] [\v!part=Cilt ]
+\setuplabeltext [\s!tk] [\v!part=B\odiaeresis l\udiaeresis m]
+\setuplabeltext [\s!tr] [\v!line=sat\dotlessi r ]
+\setuplabeltext [\s!tk] [\v!line=setir]
+\setuplabeltext [\s!tr] [\v!lines=sat\dotlessi rlar ]
+\setuplabeltext [\s!tk] [\v!lines=setirler]
+
+\setuplabeltext [\s!tk] [\v!january=\yacute anwar]
+\setuplabeltext [\s!tk] [\v!february=fewral]
+\setuplabeltext [\s!tk] [\v!march=mart]
+\setuplabeltext [\s!tk] [\v!april=aprel]
+\setuplabeltext [\s!tk] [\v!may=ma\yacute]
+\setuplabeltext [\s!tk] [\v!june=i\yacute un]
+\setuplabeltext [\s!tk] [\v!july=i\yacute ul]
+\setuplabeltext [\s!tk] [\v!august=awgust]
+\setuplabeltext [\s!tk] [\v!september=sent\yacute abr]
+\setuplabeltext [\s!tk] [\v!october=okt\yacute abr]
+\setuplabeltext [\s!tk] [\v!november=no\yacute abr]
+\setuplabeltext [\s!tk] [\v!december=dekabr]
+
+\setuplabeltext [\s!tr] [\v!january=ocak]
+\setuplabeltext [\s!tr] [\v!february=\Scedilla ubat]
+\setuplabeltext [\s!tr] [\v!march=mart]
+\setuplabeltext [\s!tr] [\v!april=nisan]
+\setuplabeltext [\s!tr] [\v!may=may\dotlessi s]
+\setuplabeltext [\s!tr] [\v!june=haziran]
+\setuplabeltext [\s!tr] [\v!july=temmuz]
+\setuplabeltext [\s!tr] [\v!august=a\gbreve ustos]
+\setuplabeltext [\s!tr] [\v!september=eyl\udiaeresis l]
+\setuplabeltext [\s!tr] [\v!october=ekim]
+\setuplabeltext [\s!tr] [\v!november=kas\dotlessi m]
+\setuplabeltext [\s!tr] [\v!december=aral\dotlessi k]
+
+\setuplabeltext [\s!tr] [\v!sunday=pazar]
+\setuplabeltext [\s!tr] [\v!monday=pazartesi]
+\setuplabeltext [\s!tr] [\v!tuesday=sal\dotlessi]
+\setuplabeltext [\s!tr] [\v!wednesday=\ccedilla ar\scedilla amba]
+\setuplabeltext [\s!tr] [\v!thursday=per\scedilla embe]
+\setuplabeltext [\s!tr] [\v!friday=cuma]
+\setuplabeltext [\s!tr] [\v!saturday=cumartesi]
+
+\setuplabeltext [\s!tk] [\v!sunday=dyn\ccedilla\ g\udiaeresis n]
+\setuplabeltext [\s!tk] [\v!monday=birinji g\udiaeresis n]
+\setuplabeltext [\s!tk] [\v!tuesday=ikinji g\udiaeresis n]
+\setuplabeltext [\s!tk] [\v!wednesday=\udiaeresis\ccedilla\udiaeresis nji]
+\setuplabeltext [\s!tk] [\v!thursday=d\odiaeresis rd\udiaeresis nji g\udiaeresis n]
+\setuplabeltext [\s!tk] [\v!friday=b\adiaeresis\scedilla inji g\udiaeresis n]
+\setuplabeltext [\s!tk] [\v!saturday=altynjy g\udiaeresis n]
+
+%D \ShowAllLanguageValues [\s!tr] [turkish] {Turkish} {delight} % turks fruit
+
+\protect \endinput
diff --git a/tex/context/base/lang-ana.tex b/tex/context/base/lang-ana.tex
new file mode 100644
index 000000000..c108655c4
--- /dev/null
+++ b/tex/context/base/lang-ana.tex
@@ -0,0 +1,24 @@
+%D \module
+%D [ file=lang-ana,
+%D version=1997.09.03,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Anatolian Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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 Language Macros / Anatolian Languages}
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+
+\unprotect
+
+\protect \endinput
diff --git a/tex/context/base/lang-ara.mkiv b/tex/context/base/lang-ara.mkiv
new file mode 100644
index 000000000..3c4d3c522
--- /dev/null
+++ b/tex/context/base/lang-ara.mkiv
@@ -0,0 +1,150 @@
+%D \module
+%D [ file=lang-ara,
+%D version=2008.06.20,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Arabic Languages,
+%D author=Khaled Hosny,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%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 Language Macros / Arabic Languages}
+
+\unprotect
+
+\definesystemconstant {arabic}
+\definesystemvariable {ar}
+
+\installlanguage
+ [\s!ar]
+ [\c!spacing=\v!broad,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!day,\ ,\v!month,{،\ },\v!year}]
+
+\installlanguage [\s!arabic] [\s!ar]
+
+% Just aliases to "ar" for now
+
+\installlanguage[\s!ar-ae][\c!default=\s!ar] % U.A.E.
+\installlanguage[\s!ar-bh][\c!default=\s!ar] % Bahrain
+\installlanguage[\s!ar-eg][\c!default=\s!ar] % Egypt
+\installlanguage[\s!ar-in][\c!default=\s!ar] % India?
+\installlanguage[\s!ar-kw][\c!default=\s!ar] % Kuwait
+\installlanguage[\s!ar-ly][\c!default=\s!ar] % Libya
+\installlanguage[\s!ar-om][\c!default=\s!ar] % Oman
+\installlanguage[\s!ar-qa][\c!default=\s!ar] % Qatar
+\installlanguage[\s!ar-sa][\c!default=\s!ar] % Saudi Arabia
+\installlanguage[\s!ar-sd][\c!default=\s!ar] % Sudan
+\installlanguage[\s!ar-tn][\c!default=\s!ar] % Tunisia
+\installlanguage[\s!ar-ye][\c!default=\s!ar] % Yemen
+
+% Syriac months
+
+\installlanguage[\s!ar-sy][\c!default=\s!ar] % Syria
+\installlanguage[\s!ar-iq][\c!default=\s!ar-sy] % Iraq
+\installlanguage[\s!ar-jo][\c!default=\s!ar-sy] % Jordan
+\installlanguage[\s!ar-lb][\c!default=\s!ar-sy] % Lebanon
+
+% Maghribi months
+
+\installlanguage[\s!ar-dz][\c!default=\s!ar] % Algeria
+\installlanguage[\s!ar-ma][\c!default=\s!ar] % Morocco
+
+\setupheadtext [\s!ar] [\v!content=المحتويات]
+\setupheadtext [\s!ar] [\v!tables=الجداول]
+\setupheadtext [\s!ar] [\v!figures=الأشكال]
+\setupheadtext [\s!ar] [\v!graphics=الرسوم]
+\setupheadtext [\s!ar] [\v!intermezzi=فسح]
+\setupheadtext [\s!ar] [\v!index=الفهرس]
+\setupheadtext [\s!ar] [\v!abbreviations=الاختصارات]
+\setupheadtext [\s!ar] [\v!logos=الشعارات]
+\setupheadtext [\s!ar] [\v!units=الوحدات]
+\setuplabeltext [\s!ar] [\v!table=جدول ]
+\setuplabeltext [\s!ar] [\v!figure=شكل ]
+\setuplabeltext [\s!ar] [\v!intermezzo=فسحة ]
+\setuplabeltext [\s!ar] [\v!graphic=رسم ]
+
+%D We don't set these here. One can do that in a style.
+
+\setuplabeltext [\s!ar] [\v!chapter=] % باب
+\setuplabeltext [\s!ar] [\v!section=] % فصل or قسم
+\setuplabeltext [\s!ar] [\v!subsection=] % فصل أدنى
+\setuplabeltext [\s!ar] [\v!subsubsection=] % فصل أ دنى أدنى
+\setuplabeltext [\s!ar] [\v!subsubsubsection=] % فصل أدنى أدنى أدنى
+\setuplabeltext [\s!ar] [\v!appendix=] % ملحق
+\setuplabeltext [\s!ar] [\v!part=جزء ]
+\setuplabeltext [\s!ar] [\v!line=سطر ]
+\setuplabeltext [\s!ar] [\v!lines=السطور ]
+
+\setuplabeltext [\s!ar] [\v!january=يناير]
+\setuplabeltext [\s!ar] [\v!february=فبراير]
+\setuplabeltext [\s!ar] [\v!march=مارس]
+\setuplabeltext [\s!ar] [\v!april=أبريل]
+\setuplabeltext [\s!ar] [\v!may=مايو]
+\setuplabeltext [\s!ar] [\v!june=يونيو]
+\setuplabeltext [\s!ar] [\v!july=يوليو]
+\setuplabeltext [\s!ar] [\v!august=أغسطس]
+\setuplabeltext [\s!ar] [\v!september=سبتمبر]
+\setuplabeltext [\s!ar] [\v!october=أكتوبر]
+\setuplabeltext [\s!ar] [\v!november=نوفمبر]
+\setuplabeltext [\s!ar] [\v!december=ديسمبر]
+
+\setuplabeltext [\s!ar-sy] [\v!january=كانون الثاني]
+\setuplabeltext [\s!ar-sy] [\v!february=شباط]
+\setuplabeltext [\s!ar-sy] [\v!march=آذار]
+\setuplabeltext [\s!ar-sy] [\v!april=نيسان]
+\setuplabeltext [\s!ar-sy] [\v!may=أيار]
+\setuplabeltext [\s!ar-sy] [\v!june=حزيران]
+\setuplabeltext [\s!ar-sy] [\v!july=تموز]
+\setuplabeltext [\s!ar-sy] [\v!august=آب]
+\setuplabeltext [\s!ar-sy] [\v!september=أيلول]
+\setuplabeltext [\s!ar-sy] [\v!october=تشرين الأول]
+\setuplabeltext [\s!ar-sy] [\v!november=تشرين الثاني]
+\setuplabeltext [\s!ar-sy] [\v!december=كانون الأول]
+
+\setuplabeltext [\s!ar-ma] [\v!may=ماي]
+\setuplabeltext [\s!ar-ma] [\v!july=يوليوز]
+\setuplabeltext [\s!ar-ma] [\v!august=غشت]
+\setuplabeltext [\s!ar-ma] [\v!september=شتنبر]
+\setuplabeltext [\s!ar-ma] [\v!november=نونبر]
+\setuplabeltext [\s!ar-ma] [\v!december=دجنبر]
+
+\setuplabeltext [\s!ar-dz] [\v!january=جانفي]
+\setuplabeltext [\s!ar-dz] [\v!february=فيفري]
+\setuplabeltext [\s!ar-dz] [\v!april=أفريل]
+\setuplabeltext [\s!ar-dz] [\v!may=ماي]
+\setuplabeltext [\s!ar-dz] [\v!june=جوان]
+\setuplabeltext [\s!ar-dz] [\v!july=جويلة]
+\setuplabeltext [\s!ar-dz] [\v!august=أوت]
+
+\setuplabeltext [\s!ar] [\v!sunday=الأحد]
+\setuplabeltext [\s!ar] [\v!monday=الاثنين]
+\setuplabeltext [\s!ar] [\v!tuesday=الثلاثاء]
+\setuplabeltext [\s!ar] [\v!wednesday=الأربعاء]
+\setuplabeltext [\s!ar] [\v!thursday=الخميس]
+\setuplabeltext [\s!ar] [\v!friday=الجمعة]
+\setuplabeltext [\s!ar] [\v!saturday=السبت]
+
+%D Rather new ...
+
+\setuplabeltext [\s!ar] [\v!page=صفحة ]
+\setuplabeltext [\s!ar] [\v!atpage=في صفحة ]
+\setuplabeltext [\s!ar] [\v!hencefore=كما وضحنا سابقا]
+\setuplabeltext [\s!ar] [\v!hereafter=كما نوضح لاحقا]
+\setuplabeltext [\s!ar] [\v!see=انظر ]
+
+%D ... and to be completed!
+
+%D \ShowAllLanguageValues [\s!ar] [arabic] {Arabic} {horn} % engelse humor
+
+\protect \endinput
diff --git a/tex/context/base/lang-art.tex b/tex/context/base/lang-art.tex
new file mode 100644
index 000000000..e8be91630
--- /dev/null
+++ b/tex/context/base/lang-art.tex
@@ -0,0 +1,26 @@
+%D \module
+%D [ file=lang--art,
+%D version=1997.09.03,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Artificial Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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 Language Macros / Artificial Languages}
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+
+% Esperanto
+
+\unprotect
+
+\protect \endinput
diff --git a/tex/context/base/lang-bal.tex b/tex/context/base/lang-bal.tex
new file mode 100644
index 000000000..394e9d93c
--- /dev/null
+++ b/tex/context/base/lang-bal.tex
@@ -0,0 +1,118 @@
+%D \module
+%D [ file=lang-bal,
+%D version=2010.01.21,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Baltic Languages,
+%D author=Marius Aleknevičius,
+%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 Language Macros / Baltic Languages}
+
+%D The framework of this module is set up by Hans Hagen while
+%D all the translations were done by Marius Aleknevičius. If
+%D you have suggestions, don't hesitate to send us an email.
+
+%D This file is in \UTF\ encoding and is meant for \MKIV.
+
+% Lettish/Latvian, Lietuvių/Lithuanian
+
+\unprotect
+
+\installlanguage
+ [\s!lt]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\lowerleftdoubleninequote,
+ \c!rightquote=\upperrightdoublesixquote,
+ \c!leftquotation=\lowerleftdoubleninequote,
+ \c!rightquotation=\upperrightdoublesixquote,
+ \c!date={\v!year,~m.,\ ,\v!month,\ ,\v!day,~d.},
+ \s!patterns=\s!lt,
+ \s!encoding=l7x,
+ \s!mapping=l7x,
+ \s!lefthyphenmin=2,
+ \s!righthyphenmin=2]
+
+\installlanguage [lithuanian] [\s!lt]
+
+\setupheadtext [\s!lt] [\v!content=Turinys]
+\setupheadtext [\s!lt] [\v!tables=Lentelės]
+\setupheadtext [\s!lt] [\v!figures=Iliustracijos]
+\setupheadtext [\s!lt] [\v!graphics=Graphics] % TODO what is the difference between the "graphics" and the "figures"?
+\setupheadtext [\s!lt] [\v!intermezzi=Intermezzos] % TODO what is the "intermezzi"?
+\setupheadtext [\s!lt] [\v!index=Rodyklė]
+\setupheadtext [\s!lt] [\v!abbreviations=Santrumpos]
+\setupheadtext [\s!lt] [\v!logos=Logos] % TODO where it is used?
+\setupheadtext [\s!lt] [\v!units=Units] % TODO where it is used?
+\setupheadtext [\s!lt] [pubs=Literatūra]
+
+\setuplabeltext [\s!lt] [\v!table={, lentelė.}]
+\setuplabeltext [\s!lt] [\v!figure={, pav.}]
+\setuplabeltext [\s!lt] [\v!intermezzo=Intermezzo ] % TODO
+\setuplabeltext [\s!lt] [\v!graphic=Graphic ] % TODO
+
+%\startlanguagespecifics[\s!lt]
+% \setupheads[\c!sectionstopper=.] %TODO how do I set dots after section numbers?
+%\stoplanguagespecifics
+
+\setuplabeltext [\s!lt] [\v!chapter=] % Chapter
+\setuplabeltext [\s!lt] [\v!section=]
+\setuplabeltext [\s!lt] [\v!subsection=]
+\setuplabeltext [\s!lt] [\v!subsubsection=]
+\setuplabeltext [\s!lt] [\v!subsubsubsection=]
+\setuplabeltext [\s!lt] [\v!appendix=] % Appendix
+\setuplabeltext [\s!lt] [\v!part={, dalis}]
+\setuplabeltext [\s!lt] [\v!line=line ] % TODO where it is used?
+\setuplabeltext [\s!lt] [\v!lines=lines ] % TODO where it is used?
+
+\setuplabeltext [\s!lt] [\v!january=sausio]
+\setuplabeltext [\s!lt] [\v!february=vasario]
+\setuplabeltext [\s!lt] [\v!march=kovo]
+\setuplabeltext [\s!lt] [\v!april=balandžio]
+\setuplabeltext [\s!lt] [\v!may=gegužės]
+\setuplabeltext [\s!lt] [\v!june=birželio]
+\setuplabeltext [\s!lt] [\v!july=liepos]
+\setuplabeltext [\s!lt] [\v!august=rugpjūčio]
+\setuplabeltext [\s!lt] [\v!september=rugsėjo]
+\setuplabeltext [\s!lt] [\v!october=spalio]
+\setuplabeltext [\s!lt] [\v!november=lapkričio]
+\setuplabeltext [\s!lt] [\v!december=gruodžio]
+
+\setuplabeltext [\s!lt] [\v!sunday=sekmadienis]
+\setuplabeltext [\s!lt] [\v!monday=pirmadienis]
+\setuplabeltext [\s!lt] [\v!tuesday=antradienis]
+\setuplabeltext [\s!lt] [\v!wednesday=trečiadienis]
+\setuplabeltext [\s!lt] [\v!thursday=ketvirtadienis]
+\setuplabeltext [\s!lt] [\v!friday=penktadienis]
+\setuplabeltext [\s!lt] [\v!saturday=šeštadienis]
+
+\setuplabeltext [\s!lt] [\v!page=puslapis ] % TODO how to test?
+\setuplabeltext [\s!lt] [\v!atpage=puslapyje ] % TODO how to test?
+\setuplabeltext [\s!lt] [\v!hencefore=kaip parodyta aukščiau] % TODO how to test?
+\setuplabeltext [\s!lt] [\v!hereafter=kaip parodyta žemiau] % TODO how to test?
+\setuplabeltext [\s!lt] [\v!see=žiūrėti ] % TODO how to test?
+
+\setuplabeltext [\s!lt] [\v!january :\s!mnem=jan] % I think, there is no abbreviated versions of months in lithuanian
+\setuplabeltext [\s!lt] [\v!february :\s!mnem=feb]
+\setuplabeltext [\s!lt] [\v!march :\s!mnem=mar]
+\setuplabeltext [\s!lt] [\v!april :\s!mnem=apr]
+\setuplabeltext [\s!lt] [\v!may :\s!mnem=may]
+\setuplabeltext [\s!lt] [\v!june :\s!mnem=jun]
+\setuplabeltext [\s!lt] [\v!july :\s!mnem=jul]
+\setuplabeltext [\s!lt] [\v!august :\s!mnem=aug]
+\setuplabeltext [\s!lt] [\v!september:\s!mnem=sep]
+\setuplabeltext [\s!lt] [\v!october :\s!mnem=oct]
+\setuplabeltext [\s!lt] [\v!november :\s!mnem=nov]
+\setuplabeltext [\s!lt] [\v!december :\s!mnem=dec]
+
+%D \ShowAllLanguageValues [\s!lt] [lithuanian] {Lithuanian} {doll} % What does this mean? Do I need it?
+
+\protect \endinput
diff --git a/tex/context/base/lang-cel.tex b/tex/context/base/lang-cel.tex
new file mode 100644
index 000000000..4d93957f1
--- /dev/null
+++ b/tex/context/base/lang-cel.tex
@@ -0,0 +1,26 @@
+%D \module
+%D [ file=lang-cel,
+%D version=1997.09.03,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Celtic Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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 Language Macros / Celtic Languages}
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+
+% Breton, Welsh, Irish, Manx, Scottish Gaelic
+
+\unprotect
+
+\protect \endinput
diff --git a/tex/context/base/lang-chi.mkii b/tex/context/base/lang-chi.mkii
new file mode 100644
index 000000000..278e10745
--- /dev/null
+++ b/tex/context/base/lang-chi.mkii
@@ -0,0 +1,305 @@
+%D \module
+%D [ file=lang-chi,
+%D version=2002.06.25, % 1998.10.10,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Chinese,
+%D author={Hans Hagen \& Wang Lei},
+%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 Language Macros / Chinese}
+
+%D This module is coded using the \UNICODE\ support built in
+%D \CONTEXT. Therefore, \type {\uchar} is used instead of latin
+%D characters.
+
+\unprotect
+
+\definesystemconstant {chinese} \definesystemconstant {cn}
+
+\installlanguage
+ [\s!cn]
+ [\c!leftsentence=\cnencoding\cnleftsentence,
+ \c!rightsentence=\cnencoding\cnrightsentence,
+ \c!leftsubsentence=\cnencoding\cnleftsubsentence,
+ \c!rightsubsentence=\cnencoding\cnrightsubsentence,
+ \c!leftquote=\cnencoding\cnupperleftsinglequote,
+ \c!rightquote=\cnencoding\cnupperrightsinglequote,
+ \c!leftquotation=\cnencoding\cnupperleftdoublequote,
+ \c!rightquotation=\cnencoding\cnupperrightdoublequote,
+ \c!date={\v!year,\cnyear,\ ,\v!month,\v!day,\cnday}]
+
+\setupheadtext [\s!cn] [\v!content={\cnencoding\cnencodedcontents}]
+\setupheadtext [\s!cn] [\v!tables={\cnencoding\cnencodedtables}]
+\setupheadtext [\s!cn] [\v!figures={\cnencoding\cnencodedfigures}]
+\setupheadtext [\s!cn] [\v!graphics={\cnencoding\cnencodedgraphics}]% RG & XJF
+\setupheadtext [\s!cn] [\v!intermezzi={\cnencoding\cnencodedintermezzo}]% RG & XJF
+\setupheadtext [\s!cn] [\v!index={\cnencoding\cnencodedindex}]
+\setupheadtext [\s!cn] [\v!abbreviations={\cnencoding\cnencodedabbreviations}]
+\setupheadtext [\s!cn] [\v!logos={\cnencoding\cnencodedlogos}]
+\setupheadtext [\s!cn] [\v!units={\cnencoding\cnencodedunits}]
+
+\setuplabeltext [\s!cn] [\v!table={\cnencoding\cnencodedtable}]
+\setuplabeltext [\s!cn] [\v!figure={\cnencoding\cnencodedfigure}]
+\setuplabeltext [\s!cn] [\v!intermezzo={\cnencoding\cnencodedintermezzo}]% RG & XJF
+\setuplabeltext [\s!cn] [\v!graphic={\cnencoding\cnencodedillustration}]% RG & XJF
+\setuplabeltext [\s!cn] [\v!appendix={\cnencoding\cnencodedappendix}]% RG
+\setuplabeltext [\s!cn] [\v!part={\cnencoding\cnencodedintro,\cnencoding\cnencodedpart}]
+\setuplabeltext [\s!cn] [\v!chapter={\cnencoding\cnencodedintro,\cnencoding\cnencodedchapter}]
+\setuplabeltext [\s!cn] [\v!section={\cnencoding\cnencodedintro,\cnencoding\cnencodedsection}]
+\setuplabeltext [\s!cn] [\v!line={\cnencoding\cnencodedline}]% RG & XJF
+\setuplabeltext [\s!cn] [\v!lines={\cnencoding\cnencodedline}]% RG & XJF
+
+\setuplabeltext [\s!cn] [\v!subsection=]
+\setuplabeltext [\s!cn] [\v!subsubsection=]
+\setuplabeltext [\s!cn] [\v!subsubsubsection=]
+
+%D From this definition one can deduce that language, input
+%D encoding, font encoding, and glyph meaning form a pretty
+%D complex four dimensional space.
+
+\startlanguagespecifics[\s!cn]
+
+\setuplabeltext [\s!cn] [\v!january=\cnencoding\cnencodedjanuary ]
+\setuplabeltext [\s!cn] [\v!february=\cnencoding\cnencodedfebrary ]
+\setuplabeltext [\s!cn] [\v!march=\cnencoding\cnencodedmarch ]
+\setuplabeltext [\s!cn] [\v!april=\cnencoding\cnencodedapril ]
+\setuplabeltext [\s!cn] [\v!may=\cnencoding\cnencodedmay ]
+\setuplabeltext [\s!cn] [\v!june=\cnencoding\cnencodedjune ]
+\setuplabeltext [\s!cn] [\v!july=\cnencoding\cnencodedjuly ]
+\setuplabeltext [\s!cn] [\v!august=\cnencoding\cnencodedaugust ]
+\setuplabeltext [\s!cn] [\v!september=\cnencoding\cnencodedseptember]
+\setuplabeltext [\s!cn] [\v!october=\cnencoding\cnencodedoctober ]
+\setuplabeltext [\s!cn] [\v!november=\cnencoding\cnencodednovember ]
+\setuplabeltext [\s!cn] [\v!december=\cnencoding\cnencodeddecember ]
+
+\setuplabeltext [\s!cn] [\v!sunday=\cnencoding\cnencodedsunday ]
+\setuplabeltext [\s!cn] [\v!monday=\cnencoding\cnencodedmonday ]
+\setuplabeltext [\s!cn] [\v!tuesday=\cnencoding\cnencodedtuesday ]
+\setuplabeltext [\s!cn] [\v!wednesday=\cnencoding\cnencodedwednesday]
+\setuplabeltext [\s!cn] [\v!thursday=\cnencoding\cnencodedthursday ]
+\setuplabeltext [\s!cn] [\v!friday=\cnencoding\cnencodedfriday ]
+\setuplabeltext [\s!cn] [\v!saturday=\cnencoding\cnencodedsaturday ]
+
+\stoplanguagespecifics
+
+%D One can specify a split labeltext, as demonstrated in
+%D the definition of the \type {part} label. Unfortunately
+%D the glyphs of both part depend on the encoding. Therefore,
+%D we have an encoding section here.
+
+\unexpanded\def\cnencoding{\enableencoding[\chineseencoding]} % ugly and temporary
+
+\startencoding[cjk-uni]
+ \definecommand cnleftsentence {\uchar{32}{20}\uchar{32}{20}}
+ \definecommand cnrightsentence {\uchar{32}{20}\uchar{32}{20}}
+ \definecommand cnleftsubsentence {\uchar{32}{20}\uchar{32}{20}}
+ \definecommand cnrightsubsentence {\uchar{32}{20}\uchar{32}{20}}
+ \definecommand cnupperleftsinglequote {\uchar{32}{24}}
+ \definecommand cnupperrightsinglequote {\uchar{32}{25}}
+ \definecommand cnupperleftdoublequote {\uchar{32}{28}}
+ \definecommand cnupperrightdoublequote {\uchar{32}{29}}
+ \definecommand cnupperleftsinglequote-v {\uchar{48}{12}}
+ \definecommand cnupperrightsinglequote-v {\uchar{48}{13}}
+ \definecommand cnupperleftdoublequote-v {\uchar{48}{14}}
+ \definecommand cnupperrightdoublequote-v {\uchar{48}{15}}
+ \definecommand cnencodedcontents {\uchar{118}{238}\uchar{95}{85}}
+ \definecommand cnencodedtables {\uchar{136}{104}\uchar{104}{60}}
+ \definecommand cnencodedfigures {\uchar{86}{254}\uchar{95}{98}}
+ \definecommand cnencodedindex {\uchar{125}{34}\uchar{95}{21}}
+ \definecommand cnencodedabbreviations {\uchar{127}{41}\uchar{117}{101}\uchar{139}{237}}
+ \definecommand cnencodedlogos {\uchar{95}{189}\uchar{141}{44}}
+ \definecommand cnencodedunits {\uchar{139}{161}\uchar{145}{207}\uchar{83}{85}\uchar{79}{77}}
+ \definecommand cnencodedtable {\uchar{136}{104}}
+ \definecommand cnencodedfigure {\uchar{86}{254}}
+ \definecommand cnencodedintro {\uchar{123}{44}}
+ \definecommand cnencodedpart {\uchar{144}{232}\uchar{82}{6}}
+ \definecommand cnencodedchapter {\uchar{122}{224}}
+ \definecommand cnencodedsection {\uchar{130}{130}}
+ \definecommand cnencodedjanuary {\uchar{78}{0}\uchar{103}{8}}
+ \definecommand cnencodedfebrary {\uchar{78}{140}\uchar{103}{8}}
+ \definecommand cnencodedmarch {\uchar{78}{9}\uchar{103}{8}}
+ \definecommand cnencodedapril {\uchar{86}{219}\uchar{103}{8}}
+ \definecommand cnencodedmay {\uchar{78}{148}\uchar{103}{8}}
+ \definecommand cnencodedjune {\uchar{81}{109}\uchar{103}{8}}
+ \definecommand cnencodedjuly {\uchar{78}{3}\uchar{103}{8}}
+ \definecommand cnencodedaugust {\uchar{81}{107}\uchar{103}{8}}
+ \definecommand cnencodedseptember {\uchar{78}{93}\uchar{103}{8}}
+ \definecommand cnencodedoctober {\uchar{83}{65}\uchar{103}{8}}
+ \definecommand cnencodednovember {\uchar{83}{65}\uchar{78}{0}\uchar{103}{8}}
+ \definecommand cnencodeddecember {\uchar{83}{65}\uchar{78}{140}\uchar{103}{8}}
+ \definecommand cnencodedsunday {\uchar{102}{31}\uchar{103}{31}\uchar{101}{229}}
+ \definecommand cnencodedmonday {\uchar{102}{31}\uchar{103}{31}\uchar{78}{0}}
+ \definecommand cnencodedtuesday {\uchar{102}{31}\uchar{103}{31}\uchar{78}{140}}
+ \definecommand cnencodedwednesday {\uchar{102}{31}\uchar{103}{31}\uchar{78}{9}}
+ \definecommand cnencodedthursday {\uchar{102}{31}\uchar{103}{31}\uchar{86}{219}}
+ \definecommand cnencodedfriday {\uchar{102}{31}\uchar{103}{31}\uchar{78}{148}}
+ \definecommand cnencodedsaturday {\uchar{102}{31}\uchar{103}{31}\uchar{81}{109}}
+ % RG & XJF
+ \definecommand cnencodedgraphics {\uchar{86}{254}}
+ \definecommand cnencodedintermezzo {\uchar{210}{99}\uchar{242}{102}}
+ \definecommand cnencodedillustration {\uchar{99}{210}\uchar{86}{254}}
+ \definecommand cnencodedappendix {\uchar{150}{68}\uchar{95}{85}}
+ \definecommand cnencodedline {\uchar{136}{76}}
+ % Tobias Burnus & XJF
+ \definecommand cnyear {\uchar{94}{116}}
+ \definecommand cnmonth {\uchar{103}{8}}
+ \definecommand cnday {\uchar{101}{229}}
+\stopencoding
+
+\startencoding[gbk]
+ \definecommand cnleftsentence {\uchar{161}{170}\uchar{161}{170}}
+ \definecommand cnrightsentence {\uchar{161}{170}\uchar{161}{170}}
+ \definecommand cnleftsubsentence {\uchar{161}{170}\uchar{161}{170}}
+ \definecommand cnrightsubsentence {\uchar{161}{170}\uchar{161}{170}}
+ \definecommand cnupperleftsinglequote {\uchar{161}{174}}
+ \definecommand cnupperrightsinglequote {\uchar{161}{175}}
+ \definecommand cnupperleftdoublequote {\uchar{161}{176}}
+ \definecommand cnupperrightdoublequote {\uchar{161}{177}}
+ \definecommand cnupperleftsinglequote-v {\uchar{161}{184}}
+ \definecommand cnupperrightsinglequote-v {\uchar{161}{185}}
+ \definecommand cnupperleftdoublequote-v {\uchar{161}{186}}
+ \definecommand cnupperrightdoublequote-v {\uchar{161}{187}}
+ \definecommand cnencodedcontents {\uchar{196}{191}\uchar{194}{188}}
+ \definecommand cnencodedtables {\uchar{177}{237}\uchar{184}{241}}
+ \definecommand cnencodedfigures {\uchar{205}{188}\uchar{208}{206}}
+ \definecommand cnencodedindex {\uchar{203}{247}\uchar{210}{253}}
+ \definecommand cnencodedabbreviations {\uchar{203}{245}\uchar{194}{212}\uchar{211}{239}}
+ \definecommand cnencodedlogos {\uchar{187}{213}\uchar{177}{225}}
+ \definecommand cnencodedunits {\uchar{188}{198}\uchar{193}{191}\uchar{181}{165}\uchar{206}{187}}
+ \definecommand cnencodedtable {\uchar{177}{237}}
+ \definecommand cnencodedfigure {\uchar{205}{188}}
+ \definecommand cnencodedintro {\uchar{181}{218}}
+ \definecommand cnencodedpart {\uchar{178}{191}\uchar{183}{214}}
+ \definecommand cnencodedchapter {\uchar{213}{194}}
+ \definecommand cnencodedsection {\uchar{189}{218}}
+ \definecommand cnencodedjanuary {\uchar{210}{187}\uchar{212}{194}}
+ \definecommand cnencodedfebrary {\uchar{182}{254}\uchar{212}{194}}
+ \definecommand cnencodedmarch {\uchar{200}{253}\uchar{212}{194}}
+ \definecommand cnencodedapril {\uchar{203}{196}\uchar{212}{194}}
+ \definecommand cnencodedmay {\uchar{206}{229}\uchar{212}{194}}
+ \definecommand cnencodedjune {\uchar{193}{249}\uchar{212}{194}}
+ \definecommand cnencodedjuly {\uchar{198}{223}\uchar{212}{194}}
+ \definecommand cnencodedaugust {\uchar{176}{203}\uchar{212}{194}}
+ \definecommand cnencodedseptember {\uchar{190}{197}\uchar{212}{194}}
+ \definecommand cnencodedoctober {\uchar{202}{174}\uchar{212}{194}}
+ \definecommand cnencodednovember {\uchar{202}{174}\uchar{210}{187}\uchar{212}{194}}
+ \definecommand cnencodeddecember {\uchar{202}{174}\uchar{182}{254}\uchar{212}{194}}
+ \definecommand cnencodedsunday {\uchar{208}{199}\uchar{198}{218}\uchar{200}{213}}
+ \definecommand cnencodedmonday {\uchar{208}{199}\uchar{198}{218}\uchar{210}{187}}
+ \definecommand cnencodedtuesday {\uchar{208}{199}\uchar{198}{218}\uchar{182}{254}}
+ \definecommand cnencodedwednesday {\uchar{208}{199}\uchar{198}{218}\uchar{200}{253}}
+ \definecommand cnencodedthursday {\uchar{208}{199}\uchar{198}{218}\uchar{203}{196}}
+ \definecommand cnencodedfriday {\uchar{208}{199}\uchar{198}{218}\uchar{206}{229}}
+ \definecommand cnencodedsaturday {\uchar{208}{199}\uchar{198}{218}\uchar{193}{249}}
+ % RG & XJF
+ \definecommand cnencodedgraphics {\uchar{205}{188}}
+ \definecommand cnencodedintermezzo {\uchar{178}{229}\uchar{199}{250}}
+ \definecommand cnencodedillustration {\uchar{178}{229}\uchar{205}{188}}
+ \definecommand cnencodedappendix {\uchar{184}{189}\uchar{194}{188}}
+ \definecommand cnencodedline {\uchar{208}{208}}
+ % Tobias Burnus & XJF
+ \definecommand cnyear {\uchar{196}{234}}
+ \definecommand cnmonth {\uchar{212}{194}}
+ \definecommand cnday {\uchar{200}{213}}
+\stopencoding
+
+\startencoding[big5]
+ \definecommand cnleftsentence {\uchar{162}{119}\uchar{162}{119}}
+ \definecommand cnrightsentence {\uchar{162}{119}\uchar{162}{119}}
+ \definecommand cnleftsubsentence {\uchar{162}{119}\uchar{162}{119}}
+ \definecommand cnrightsubsentence {\uchar{162}{119}\uchar{162}{119}}
+ \definecommand cnupperleftsinglequote {\uchar{161}{165}}
+ \definecommand cnupperrightsinglequote {\uchar{161}{166}}
+ \definecommand cnupperleftdoublequote {\uchar{161}{167}}
+ \definecommand cnupperrightdoublequote {\uchar{161}{168}}
+ \definecommand cnupperleftsinglequote-v {\uchar{161}{117}}
+ \definecommand cnupperrightsinglequote-v {\uchar{161}{118}}
+ \definecommand cnupperleftdoublequote-v {\uchar{161}{121}}
+ \definecommand cnupperrightdoublequote-v {\uchar{161}{122}}
+ \definecommand cnencodecontents {\uchar{165}{216}\uchar{191}{253}}
+ \definecommand cnencodetables {\uchar{170}{237}\uchar{174}{230}}
+ \definecommand cnencodefigures {\uchar{185}{207}\uchar{167}{206}}
+ \definecommand cnencodeindex {\uchar{175}{193}\uchar{174}{222}}
+ \definecommand cnencodeabbreviations {\uchar{191}{89}\uchar{178}{164}\uchar{187}{121}}
+ \definecommand cnencodelogos {\uchar{192}{178}\uchar{188}{208}}
+ \definecommand cnencodeunits {\uchar{173}{112}\uchar{182}{113}\uchar{179}{230}\uchar{166}{236}}
+ \definecommand cnencodetable {\uchar{170}{237}}
+ \definecommand cnencodefigure {\uchar{185}{207}}
+ \definecommand cnencodedintro {\uchar{178}{196}}
+ \definecommand cnencodedpart {\uchar{179}{161}\uchar{164}{192}}
+ \definecommand cnencodedchapter {\uchar{179}{185}}
+ \definecommand cnencodedsection {\uchar{184} {96}}
+ \definecommand cnencodedjanuary {\uchar{164} {64}\uchar{164}{235}}
+ \definecommand cnencodedfebrary {\uchar{164} {71}\uchar{164}{235}}
+ \definecommand cnencodedmarch {\uchar{164} {84}\uchar{164}{235}}
+ \definecommand cnencodedapril {\uchar{165}{124}\uchar{164}{235}}
+ \definecommand cnencodedmay {\uchar{164}{173}\uchar{164}{235}}
+ \definecommand cnencodedjune {\uchar{164}{187}\uchar{164}{235}}
+ \definecommand cnencodedjuly {\uchar{164} {67}\uchar{164}{235}}
+ \definecommand cnencodedaugust {\uchar{164} {75}\uchar{164}{235}}
+ \definecommand cnencodedseptember {\uchar{164} {69}\uchar{164}{235}}
+ \definecommand cnencodedoctober {\uchar{164} {81}\uchar{164}{235}}
+ \definecommand cnencodednovember {\uchar{164} {81}\uchar{164} {64}\uchar{164}{235}}
+ \definecommand cnencodeddecember {\uchar{164} {81}\uchar{164} {71}\uchar{164}{235}}
+ \definecommand cnencodedsunday {\uchar{172} {80}\uchar{180}{193}\uchar{164}{233}}
+ \definecommand cnencodedmonday {\uchar{172} {80}\uchar{180}{193}\uchar{164} {64}}
+ \definecommand cnencodedtuesday {\uchar{172} {80}\uchar{180}{193}\uchar{164} {71}}
+ \definecommand cnencodedwednesday {\uchar{172} {80}\uchar{180}{193}\uchar{164} {84}}
+ \definecommand cnencodedthursday {\uchar{172} {80}\uchar{180}{193}\uchar{165}{124}}
+ \definecommand cnencodedfriday {\uchar{172} {80}\uchar{180}{193}\uchar{164}{173}}
+ \definecommand cnencodedsaturday {\uchar{172} {80}\uchar{180}{193}\uchar{164}{187}}
+ % Tobias Burnus &\XJF
+ \definecommand cnyear {\uchar{166}{126}}
+ \definecommand cnmonth {\uchar{164}{235}}
+ \definecommand cnday {\uchar{164}{233}}
+
+% Traditional Chinese characters (only where they differ to the
+% simplified ones) for lang-chi.tex and font-chi.tex.
+
+% \startencoding[cjk-uni]
+% \defineudigit 10000 132 44
+% \defineudigit 100000000 81 4
+
+% \definecommand cnencodedsection {\uchar{123}{192}}
+% \definecommand cnencodedfigure {\uchar{87}{22}}
+% \definecommand cnencodedunits {\uchar{138}{8}\uchar{145}{207}\uchar{85}{174}\uchar{79}{77}}
+% \definecommand cnencodedlogos {\uchar{95}{189}\uchar{140}{182}}
+% \definecommand cnencodedabbreviations {\uchar{126}{46}\uchar{117}{101}\uchar{138}{158}}
+% \definecommand cnencodedfigures {\uchar{87}{22}\uchar{95}{98}}
+% \definecommand cnencodedcontents {\uchar{118}{238}\uchar{147}{4}}
+% \stopencoding
+
+% \startencoding[gbk]
+% \defineudigit 10000 200 102
+% \defineudigit 100000000 131 124
+
+% \definecommand cnencodedsection {\uchar{185}{157}}
+% \definecommand cnencodedfigure {\uchar{136}{68}}
+% \definecommand cnencodedunits {\uchar{211}{139}\uchar{193}{191}\uchar{134}{206}\uchar{206}{187}}
+% \definecommand cnencodedlogos {\uchar{187}{213}\uchar{217}{72}
+% \definecommand cnencodedabbreviations {\uchar{191}{115}\uchar{194}{212}\uchar{213}{90}}
+% \definecommand cnencodedfigures {\uchar{136}{68}\uchar{208}{206}}
+% \definecommand cnencodedcontents {\uchar{196}{191}\uchar{228}{155}}
+% \stopencoding
+
+% \startencoding[big5]
+% \defineudigit 10000 184 85
+% \defineudigit 100000000 187 245
+
+% \definecommand cnencodedsection {\uchar{184}{96}}
+% \definecommand cnencodedfigure {\uchar{185}{207}}
+% \definecommand cnencodedunits {\uchar{173}{112}\uchar{182}{113}\uchar{179}{230}\uchar{166}{236}}
+% \definecommand cnencodedlogos {\uchar{192}{178}\uchar{182}{83}}
+% \definecommand cnencodedabbreviations {\uchar{193}{89}\uchar{178}{164}\uchar{187}{121}}
+% \definecommand cnencodedfigures {\uchar{185}{207}\uchar{167}{206}}
+% \definecommand cnencodedcontents {\uchar{165}{216}\uchar{191}{253}}
+% \stopencoding
+
+\stopencoding
+
+\protect \endinput
diff --git a/tex/context/base/lang-cjk.mkiv b/tex/context/base/lang-cjk.mkiv
new file mode 100644
index 000000000..5f736d4a1
--- /dev/null
+++ b/tex/context/base/lang-cjk.mkiv
@@ -0,0 +1,328 @@
+%D \module
+%D [ file=lang-chi,
+%D version=2009.03.02,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Chinese,
+%D author={Hans Hagen \& Wang Lei},
+%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.
+
+%D Derived from \MKII\ files.
+
+\writestatus{loading}{ConTeXt Language Macros / CJK}
+
+\definesystemconstant {chinese} \definesystemconstant {cn}
+\definesystemconstant {japanese} \definesystemconstant {ja}
+\definesystemconstant {korean} \definesystemconstant {kr}
+
+\unprotect
+
+% Chinese
+
+\installlanguage
+ [\s!cn]
+ [\c!leftsentence=——,
+ \c!rightsentence=——,
+ \c!leftsubsentence=——,
+ \c!rightsubsentence=——,
+ \c!leftquote=‘,
+ \c!rightquote=’,
+ \c!leftquotation=“,
+ \c!rightquotation=”,
+ \c!date={\v!year,年,\ ,\v!month,\v!day,日}]
+
+\setupheadtext [\s!cn] [\v!content=目录]
+\setupheadtext [\s!cn] [\v!tables=表格]
+\setupheadtext [\s!cn] [\v!figures=图形]
+\setupheadtext [\s!cn] [\v!graphics=图]
+\setupheadtext [\s!cn] [\v!intermezzi=퉣]
+\setupheadtext [\s!cn] [\v!index=索引]
+\setupheadtext [\s!cn] [\v!abbreviations=缩略语]
+\setupheadtext [\s!cn] [\v!logos=徽贬]
+\setupheadtext [\s!cn] [\v!units=计量单位]
+
+\setuplabeltext [\s!cn] [\v!table=表]
+\setuplabeltext [\s!cn] [\v!figure=图]
+\setuplabeltext [\s!cn] [\v!intermezzo=퉣]
+\setuplabeltext [\s!cn] [\v!graphic=插图]
+\setuplabeltext [\s!cn] [\v!appendix=附录]
+\setuplabeltext [\s!cn] [\v!part={第,部分}]
+\setuplabeltext [\s!cn] [\v!chapter={第,章}]
+\setuplabeltext [\s!cn] [\v!section={第,节}]
+\setuplabeltext [\s!cn] [\v!line=行]
+\setuplabeltext [\s!cn] [\v!lines=行]
+
+\setuplabeltext [\s!cn] [\v!subsection=]
+\setuplabeltext [\s!cn] [\v!subsubsection=]
+\setuplabeltext [\s!cn] [\v!subsubsubsection=]
+
+\setuplabeltext [\s!cn] [\v!january=一月]
+\setuplabeltext [\s!cn] [\v!february=二月]
+\setuplabeltext [\s!cn] [\v!march=三月]
+\setuplabeltext [\s!cn] [\v!april=四月]
+\setuplabeltext [\s!cn] [\v!may=五月]
+\setuplabeltext [\s!cn] [\v!june=六月]
+\setuplabeltext [\s!cn] [\v!july=七月]
+\setuplabeltext [\s!cn] [\v!august=八月]
+\setuplabeltext [\s!cn] [\v!september=九月]
+\setuplabeltext [\s!cn] [\v!october=十月]
+\setuplabeltext [\s!cn] [\v!november=十一月]
+\setuplabeltext [\s!cn] [\v!december=十二月]
+
+\setuplabeltext [\s!cn] [\v!sunday=星期日]
+\setuplabeltext [\s!cn] [\v!monday=星期一]
+\setuplabeltext [\s!cn] [\v!tuesday=星期二]
+\setuplabeltext [\s!cn] [\v!wednesday=星期三]
+\setuplabeltext [\s!cn] [\v!thursday=星期四]
+\setuplabeltext [\s!cn] [\v!friday=星期五]
+\setuplabeltext [\s!cn] [\v!saturday=星期六]
+
+%D Japanese
+
+\installlanguage
+ [\s!ja]
+ [\c!leftsentence=——,
+ \c!rightsentence=——,
+ \c!leftsubsentence=——,
+ \c!rightsubsentence=——,
+ \c!leftquote=‘,
+ \c!rightquote=’,
+ \c!leftquotation=「,
+ \c!rightquotation=」,
+ \c!date={西暦,\v!year,年,\v!month,月,\v!day,日}]
+
+\setupheadtext [\s!ja] [\v!content=目次]
+\setupheadtext [\s!ja] [\v!tables=机]
+\setupheadtext [\s!ja] [\v!figures=図]
+\setupheadtext [\s!ja] [\v!graphics=グラフ]
+\setupheadtext [\s!ja] [\v!intermezzi=間奏曲]
+\setupheadtext [\s!ja] [\v!index=目次]
+\setupheadtext [\s!ja] [\v!abbreviations=略語]
+\setupheadtext [\s!ja] [\v!logos=理性]
+\setupheadtext [\s!ja] [\v!units=ユニッツ]
+
+\setuplabeltext [\s!ja] [\v!table=表]
+\setuplabeltext [\s!ja] [\v!figure=図]
+\setuplabeltext [\s!ja] [\v!intermezzo=間奏曲]
+\setuplabeltext [\s!ja] [\v!graphic=イラスト]
+\setuplabeltext [\s!ja] [\v!appendix=付録]
+\setuplabeltext [\s!ja] [\v!part={第,パート}]
+\setuplabeltext [\s!ja] [\v!chapter={第,章}]
+\setuplabeltext [\s!ja] [\v!section={第,項}]
+\setuplabeltext [\s!ja] [\v!line=線]
+\setuplabeltext [\s!ja] [\v!lines=線]
+
+\setuplabeltext [\s!ja] [\v!subsection=]
+\setuplabeltext [\s!ja] [\v!subsubsection=]
+\setuplabeltext [\s!ja] [\v!subsubsubsection=]
+
+\setuplabeltext [\s!ja] [\v!january=1]
+\setuplabeltext [\s!ja] [\v!february=2]
+\setuplabeltext [\s!ja] [\v!march=3]
+\setuplabeltext [\s!ja] [\v!april=4]
+\setuplabeltext [\s!ja] [\v!may=5]
+\setuplabeltext [\s!ja] [\v!june=6]
+\setuplabeltext [\s!ja] [\v!july=7]
+\setuplabeltext [\s!ja] [\v!august=8]
+\setuplabeltext [\s!ja] [\v!september=9]
+\setuplabeltext [\s!ja] [\v!october=10]
+\setuplabeltext [\s!ja] [\v!november=11]
+\setuplabeltext [\s!ja] [\v!december=12]
+
+\setuplabeltext [\s!ja] [\v!monday=月曜日]
+\setuplabeltext [\s!ja] [\v!tuesday=火曜日]
+\setuplabeltext [\s!ja] [\v!wednesday=水曜日]
+\setuplabeltext [\s!ja] [\v!thursday=木曜日]
+\setuplabeltext [\s!ja] [\v!friday=金曜日]
+\setuplabeltext [\s!ja] [\v!saturday=土曜日]
+\setuplabeltext [\s!ja] [\v!sunday=日曜日]
+
+%D Korean
+
+% todo
+
+\protect \endinput
+
+cn={
+ ["abbreviations"]="缩略语",
+ ["appendix"]="附录",
+ ["april"]="四月",
+ ["august"]="八月",
+ ["chapter"]="章",
+ ["contents"]="目录",
+ ["day"]="日",
+ ["december"]="十二月",
+ ["febrary"]="二月",
+ ["figure"]="图",
+ ["figures"]="图形",
+ ["friday"]="星期五",
+ ["graphics"]="图",
+ ["illustration"]="插图",
+ ["index"]="索引",
+ ["intermezzo"]="퉣",
+ ["intro"]="第",
+ ["january"]="一月",
+ ["july"]="七月",
+ ["june"]="六月",
+ ["leftsentence"]="——",
+ ["leftsubsentence"]="——",
+ ["line"]="行",
+ ["logos"]="徽贬",
+ ["march"]="三月",
+ ["may"]="五月",
+ ["monday"]="星期一",
+ ["month"]="月",
+ ["november"]="十一月",
+ ["october"]="十月",
+ ["part"]="部分",
+ ["rightsentence"]="——",
+ ["rightsubsentence"]="——",
+ ["saturday"]="星期六",
+ ["section"]="节",
+ ["september"]="九月",
+ ["sunday"]="星期日",
+ ["table"]="表",
+ ["tables"]="表格",
+ ["thursday"]="星期四",
+ ["tuesday"]="星期二",
+ ["units"]="计量单位",
+ ["upperleftdoublequote"]="“",
+ ["upperleftdoublequote-v"]="『",
+ ["upperleftsinglequote"]="‘",
+ ["upperleftsinglequote-v"]="「",
+ ["upperrightdoublequote"]="”",
+ ["upperrightdoublequote-v"]="』",
+ ["upperrightsinglequote"]="’",
+ ["upperrightsinglequote-v"]="」",
+ ["wednesday"]="星期三",
+ ["year"]="年",
+}
+
+ja={
+ ["abbreviations"]="略語",
+ ["abstract"]="概要",
+ ["and"]="、",
+ ["answer"]="答:",
+ ["appendix"]="付録",
+ ["april"]="四月",
+ ["article"]="項目",
+ ["august"]="八月",
+ ["bibliography"]="参考文献",
+ ["book"]="ブック",
+ ["bridgehead"]="項",
+ ["bullet"]="●",
+ ["by"]=":",
+ ["caution"]="注意",
+ ["chapter"]="章",
+ ["christiandate"]="西暦",
+ ["colophon"]="奥付",
+ ["copyright"]="製作著作",
+ ["day"]="日",
+ ["december"]="十二月",
+ ["dedication"]="謝辞",
+ ["edited"]="編者",
+ ["editedby"]="編者:",
+ ["edition"]="編集",
+ ["endquote"]="」",
+ ["equation"]="式",
+ ["example"]="例",
+ ["february"]="二月",
+ ["figure"]="図",
+ ["figures"]="図",
+ ["friday"]="土曜日",
+ ["glossary"]="用語集",
+ ["glosssee"]="参照",
+ ["glossseealso"]="参照",
+ ["graphics"]="グラフ",
+ ["illustration"]="イラスト",
+ ["important"]="重要項目",
+ ["index"]="目次",
+ ["indexsymbols"]="シンボル",
+ ["intermezzo"]="間奏曲",
+ ["intermezzos"]="間奏曲",
+ ["intro"]="第",
+ ["january"]="一月",
+ ["july"]="七月",
+ ["june"]="六月",
+ ["leftsentence"]="——",
+ ["leftsubsentence"]="——",
+ ["line"]="線",
+ ["lines"]="線",
+ ["listofequations"]="式目次",
+ ["listofexamples"]="例目次",
+ ["listoffigures"]="図目次",
+ ["listoftables"]="表目次",
+ ["listofunknown"]="不明目次",
+ ["logos"]="理性",
+ ["march"]="三月",
+ ["may"]="五月",
+ ["monday"]="火曜日",
+ ["month"]="月",
+ ["msgaud"]="対象者",
+ ["msglevel"]="レベル",
+ ["msgorig"]="発信元",
+ ["navhome"]="ホーム",
+ ["navnext"]="次のページ",
+ ["navnextsibling"]="早送り",
+ ["navprev"]="前のページ",
+ ["navprevsibling"]="巻戻し",
+ ["navup"]="上に戻る",
+ ["nestedendquote"]="』",
+ ["nestedstartquote"]="『",
+ ["nonexistantelement"]="要素が存在しません",
+ ["note"]="注意",
+ ["notes"]="注意",
+ ["november"]="十一月",
+ ["october"]="十月",
+ ["pages"]="偧献",
+ ["part"]="パート",
+ ["preface"]="序文",
+ ["procedure"]="手順",
+ ["procedureformal"]="手順",
+ ["productionset"]="プロダクション",
+ ["productionsetformal"]="プロダクション",
+ ["published"]="発行",
+ ["qandadiv"]="問:、答:",
+ ["qandaentry"]="問:",
+ ["question"]="問:",
+ ["reference"]="参照",
+ ["refname"]="名前",
+ ["refsection"]="項",
+ ["refsynopsisdiv"]="概要",
+ ["revhistory"]="改訂履歴",
+ ["revision"]="改訂",
+ ["rightsentence"]="——",
+ ["rightsubsentence"]="——",
+ ["saturday"]="日曜日",
+ ["section"]="項",
+ ["see"]="参照",
+ ["seealso"]="参照",
+ ["separator"]="、",
+ ["september"]="九月",
+ ["set"]="設定",
+ ["setindex"]="目次設定",
+ ["sidebar"]="サイドバー",
+ ["simplesect"]="項",
+ ["singleendquote"]="’",
+ ["singlestartquote"]="‘",
+ ["startquote"]="「",
+ ["step"]="ステップ",
+ ["sunday"]="月曜日",
+ ["table"]="表",
+ ["tablenotes"]="注意",
+ ["tableofcontents"]="目次",
+ ["tables"]="机",
+ ["thursday"]="金曜日",
+ ["tip"]="ティップ",
+ ["tuesday"]="水曜日",
+ ["unexpectedelementname"]="不明な要素名",
+ ["units"]="ユニッツ",
+ ["unsupported"]="サポートしません",
+ ["warning"]="警告",
+ ["wednesday"]="木曜日",
+ ["year"]="年",
+}
diff --git a/tex/context/base/lang-ctx.mkii b/tex/context/base/lang-ctx.mkii
new file mode 100644
index 000000000..09f28dda1
--- /dev/null
+++ b/tex/context/base/lang-ctx.mkii
@@ -0,0 +1,53 @@
+%D \module
+%D [ file=lang-ctx,
+%D version=2005.02.12,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Generic Patterns,
+%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 Language Macros / Generic Patterns}
+
+\unprotect
+
+%D The \CONTEXT\ specific patterns are more generic and
+%D are more or less encoding independent. They are generated
+%D from the ones shipped with distributions using:
+%D
+%D \starttyping
+%D ctxtools --pattern --all
+%D \stoptyping
+
+%D In order to get 8 bit characters hyphenated, we need to load
+%D patterns under the right circumstances. In some countries, more
+%D than one font encoding is in use. I can add more defaults here
+%D if users let me know what encoding they use.
+
+% \installlanguage [\s!nl] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!fr] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!de] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!it] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!pt] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!hr] [\s!mapping=ec,\s!encoding=ec] % no il2, misses cacute characters
+% \installlanguage [\s!pl] [\s!mapping={pl0,ec,qx},\s!encoding={pl0,ec,qx}] % pl0 may go
+% \installlanguage [\s!cs] [\s!mapping={il2,ec},\s!encoding={il2,ec}] % il2 may go
+% \installlanguage [\s!sk] [\s!mapping={il2,ec},\s!encoding={il2,ec}] % il2 may go
+% \installlanguage [\s!sl] [\s!mapping=ec,\s!encoding=ec] % il2 has gone
+% \installlanguage [\s!vi] [\s!mapping=t5,\s!encoding=t5]
+% \installlanguage [\s!ru] [\s!mapping=t2a,\s!encoding=t2a]
+
+% beware, don't use \setuplanguage here
+
+% \installlanguage[\s!gb][\s!lefthyphenmin=3,\s!righthyphenmin=3] % patterns can only handle this
+% \installlanguage[\s!us][\s!lefthyphenmin=2,\s!righthyphenmin=3] % patterns can only handle this
+
+% greek
+
+% \installlanguage[\s!agr][\s!mapping=\s!agr,\s!encoding=\s!agr]
+
+\protect \endinput
diff --git a/tex/context/base/lang-cyr.tex b/tex/context/base/lang-cyr.tex
new file mode 100644
index 000000000..470402bb1
--- /dev/null
+++ b/tex/context/base/lang-cyr.tex
@@ -0,0 +1,371 @@
+%D \module
+%D [ file=lang-cyr,
+%D version=2003.01.24,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Cyrillic Languages,
+%D author=see below,
+%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 Language Macros / Cyrillic Languages}
+
+%D The cyrillic languages always use a dedicated input regime.
+%D Therefore we define the labels using symbolic names.
+%D Support for cyrillic is initiated by Olga Briginets who
+%D also layed the base for the language, encoding and font
+%D definition. Later Alexander Bokovoy and Victor Figurnov
+%D improved things. I (Hans Hagen) mainly cleaned things up
+%D a bit.
+
+\unprotect
+
+\installlanguage
+ [\s!ru]
+ [\s!lefthyphenmin=2,
+ \s!righthyphenmin=2,
+ \c!spacing=\v!packed,
+ \c!leftsentence=\leftguillemot,
+ \c!rightsentence=\rightguillemot,
+ \c!leftsubsentence=\lowerleftdoubleninequote,
+ \c!rightsubsentence=\upperrightdoubleninequote,
+ \c!leftquote=\lowerleftdoubleninequote,
+ \c!rightquote=\upperrightdoubleninequote,
+ \c!leftquotation=\leftguillemot,
+ \c!rightquotation=\rightguillemot,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year},
+ \s!mapping=t2a,
+ \s!encoding=t2a]
+
+\installlanguage
+ [\s!ua]
+ [\s!lefthyphenmin=2,
+ \s!righthyphenmin=2,
+ \c!spacing=\v!packed,
+ \c!leftsentence=\leftguillemot,
+ \c!rightsentence=\rightguillemot,
+ \c!leftsubsentence=\lowerleftdoubleninequote,
+ \c!rightsubsentence=\upperrightdoubleninequote,
+ \c!leftquote=\lowerleftdoubleninequote,
+ \c!rightquote=\upperrightdoubleninequote,
+ \c!leftquotation=\leftguillemot,
+ \c!rightquotation=\rightguillemot,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year},
+ \s!patterns=\s!uk,
+ \s!mapping=t2a,
+ \s!encoding=t2a]
+
+\installlanguage [russian] [\s!ru]
+\installlanguage [ukrainian] [\s!ua]
+
+%D Labels and header texts.
+
+\setupheadtext [\s!ru] [ \v!content=\cyrillicS \cyrillico \cyrillicd
+ \cyrillice \cyrillicr \cyrilliczh
+ \cyrillica \cyrillicn \cyrillici
+ \cyrillice]
+\setupheadtext [\s!ua] [\v!content=\cyrillicZ \cyrillicm \cyrillicii
+ \cyrillics \cyrillict]
+
+\setupheadtext [\s!ru] [\v!tables=\cyrillicS \cyrillicp \cyrillici
+ \cyrillics \cyrillico \cyrillick
+ \space \cyrillict \cyrillica
+ \cyrillicb \cyrillicl \cyrillici
+ \cyrillicc]
+\setupheadtext [\s!ua] [\v!tables=\cyrillicP \cyrillice \cyrillicr
+ \cyrillice \cyrillicl \cyrillicii
+ \cyrillick \space \cyrillict
+ \cyrillica \cyrillicb \cyrillicl
+ \cyrillici \cyrillicc \cyrillicsftsn]
+
+\setupheadtext [\s!ru] [\v!figures=\cyrillicS \cyrillicp \cyrillici
+ \cyrillics \cyrillico \cyrillick
+ \space \cyrillici \cyrillicl
+ \cyrillicl \cyrillicyu\cyrillics
+ \cyrillict \cyrillicr \cyrillica
+ \cyrillicc \cyrillici \cyrillicishrt]
+\setupheadtext [\s!ua] [\v!figures=\cyrillicP \cyrillice \cyrillicr
+ \cyrillice \cyrillicl \cyrillicii
+ \cyrillick \space \cyrillicii
+ \cyrillicl \cyrillicyu\cyrillics
+ \cyrillict \cyrillicr \cyrillica
+ \cyrillicc \cyrillicii\cyrillicishrt]
+
+\setupheadtext [\s!ru] [\v!graphics=\cyrillicS \cyrillicp \cyrillici
+ \cyrillics \cyrillico \cyrillick
+ \space \cyrillicg \cyrillicr
+ \cyrillica \cyrillicf \cyrillici
+ \cyrillick \cyrillico \cyrillicv]
+\setupheadtext [\s!ua] [\v!graphics=\cyrillicP \cyrillice \cyrillicr
+ \cyrillice \cyrillicl \cyrillicii
+ \cyrillick \space \cyrillicg
+ \cyrillicr \cyrillica \cyrillicf
+ \cyrillicii\cyrillick \cyrillico
+ \cyrillicv]
+
+\setupheadtext [\s!ru] [\v!intermezzi=\cyrillicS \cyrillicp \cyrillici
+ \cyrillics \cyrillico \cyrillick
+ \space \cyrillicv \cyrillics
+ \cyrillict \cyrillica \cyrillicv
+ \cyrillico \cyrillick]
+\setupheadtext [\s!ua] [\v!intermezzi=\cyrillicP \cyrillice \cyrillicr
+ \cyrillice \cyrillicl \cyrillicii
+ \cyrillick \space \cyrillicv
+ \cyrillics \cyrillict \cyrillica
+ \cyrillicv \cyrillico \cyrillick]
+
+\setupheadtext [\s!ru] [\v!index=\cyrillicA \cyrillicl \cyrillicf
+ \cyrillica \cyrillicv \cyrillici
+ \cyrillict \cyrillicn \cyrillicery
+ \cyrillicishrt \space \cyrillicu
+ \cyrillick \cyrillica \cyrillicz
+ \cyrillica \cyrillict \cyrillice
+ \cyrillicl \cyrillicsftsn]
+\setupheadtext [\s!ua] [\v!index=\cyrillicP \cyrillico \cyrillick
+ \cyrillica \cyrilliczh\cyrillicch
+ \cyrillici \cyrillick]
+
+\setupheadtext [\s!ru] [\v!abbreviations=\cyrillicS \cyrillicp \cyrillici
+ \cyrillics \cyrillico \cyrillick
+ \space \cyrillics \cyrillico
+ \cyrillick \cyrillicr \cyrillica
+ \cyrillicshch \cyrillice
+ \cyrillicn
+ \cyrillici \cyrillicishrt]
+\setupheadtext [\s!ua] [\v!abbreviations=\cyrillicP \cyrillice \cyrillicr
+ \cyrillice \cyrillicl \cyrillicii
+ \cyrillick \space \cyrillics
+ \cyrillick \cyrillico \cyrillicr
+ \cyrillico \cyrillicch\cyrillice
+ \cyrillicn \cyrillicsftsn]
+
+\setupheadtext [\s!ru] [\v!logos=\cyrillicL \cyrillico \cyrillicg
+ \cyrillico \cyrillict \cyrillici
+ \cyrillicp \cyrillicery]
+\setupheadtext [\s!ua] [\v!logos=\cyrillicL \cyrillico \cyrillicg
+ \cyrillico \cyrillict \cyrillici
+ \cyrillicp \cyrillici]
+
+\setupheadtext [\s!ru] [\v!units=\cyrillicE \cyrillicd \cyrillici
+ \cyrillicn \cyrillici \cyrillicc
+ \cyrillicery \space \cyrillici
+ \cyrillicz \cyrillicm \cyrillice
+ \cyrillicr \cyrillice \cyrillicn
+ \cyrillici \cyrillicya]
+\setupheadtext [\s!ua] [\v!units=\cyrillicO \cyrillicd \cyrillici
+ \cyrillicn \cyrillici \cyrillicc
+ \cyrillicii\space \cyrillicv
+ \cyrillici \cyrillicm \cyrillicii
+ \cyrillicr \cyrillicu]
+
+\setuplabeltext [\s!ru] [\v!table=\cyrillicT \cyrillica \cyrillicb
+ \cyrillicl \cyrillici \cyrillicc
+ \cyrillica \space]
+\setuplabeltext [\s!ua] [\v!table=\cyrillicT \cyrillica \cyrillicb
+ \cyrillicl \cyrillici \cyrillicc
+ \cyrillicya\space]
+
+\setuplabeltext [\s!ru] [\v!figure=\cyrillicR \cyrillici \cyrillics
+ \cyrillicu \cyrillicn \cyrillico
+ \cyrillick \space]
+\setuplabeltext [\s!ua] [\v!figure=\cyrillicM \cyrillica \cyrillicl
+ \cyrillicyu\cyrillicn \cyrillico
+ \cyrillick \space]
+
+\setuplabeltext [\s!ru] [\v!intermezzo=\cyrillicV \cyrillics \cyrillict
+ \cyrillica \cyrillicv \cyrillick
+ \cyrillica \space]
+\setuplabeltext [\s!ua] [\v!intermezzo=\cyrillicV \cyrillics \cyrillict
+ \cyrillica \cyrillicv \cyrillick
+ \cyrillica \space]
+
+\setuplabeltext [\s!ru] [\v!graphic=\cyrillicG \cyrillicr \cyrillica
+ \cyrillicf \cyrillici \cyrillick
+ \space]
+\setuplabeltext [\s!ua] [\v!graphic=\cyrillicG \cyrillicr \cyrillica
+ \cyrillicf \cyrillici \cyrillick
+ \space]
+
+\setuplabeltext [\s!ru] [\v!chapter=]
+\setuplabeltext [\s!ua] [\v!chapter=]
+
+\setuplabeltext [\s!ru] [\v!section=]
+\setuplabeltext [\s!ua] [\v!section=]
+
+\setuplabeltext [\s!ru] [\v!subsection=]
+\setuplabeltext [\s!ua] [\v!subsection=]
+
+\setuplabeltext [\s!ru] [\v!subsubsection=]
+\setuplabeltext [\s!ua] [\v!subsubsection=]
+
+\setuplabeltext [\s!ru] [\v!subsubsubsection=]
+\setuplabeltext [\s!ua] [\v!subsubsubsection=]
+
+\setuplabeltext [\s!ru] [\v!appendix=]
+\setuplabeltext [\s!ua] [\v!appendix=]
+
+\setuplabeltext [\s!ru] [\v!part=\cyrillicCH\cyrillica \cyrillics
+ \cyrillict \cyrillicsftsn
+ \space]
+\setuplabeltext [\s!ua] [\v!part=\cyrillicCH\cyrillica \cyrillics
+ \cyrillict \cyrillici \cyrillicn
+ \cyrillica \space]
+
+\setuplabeltext [\s!ru] [\v!line=\cyrillics \cyrillict \cyrillicr
+ \cyrillico \cyrillick \cyrillica
+ \space]
+\setuplabeltext [\s!ua] [\v!line=\cyrillicr \cyrillicya\cyrillicd
+ \cyrillico \cyrillick \space]
+
+\setuplabeltext [\s!ru] [\v!lines=\cyrillics \cyrillict \cyrillicr
+ \cyrillico \cyrillick \cyrillici
+ \space]
+\setuplabeltext [\s!ua] [\v!lines=\cyrillicr \cyrillicya\cyrillicd
+ \cyrillick \cyrillici \space]
+
+\setuplabeltext [\s!ru] [\v!page=\cyrillics \cyrillict \cyrillicr
+ \cyrillica \cyrillicn \cyrillici
+ \cyrillicc \cyrillica \space]
+\setuplabeltext [\s!ua] [\v!page=\cyrillics \cyrillict \cyrillico
+ \cyrillicr \cyrillicii\cyrillicn
+ \cyrillick \cyrillica \space ]
+
+\setuplabeltext [\s!ru] [\v!atpage=\cyrillicn \cyrillica \space
+ \cyrillics \cyrillict \cyrillicr
+ \cyrillica \cyrillicn \cyrillici
+ \cyrillicc \cyrillice \space]
+\setuplabeltext [\s!ua] [\v!atpage=\cyrillicn \cyrillica \space
+ \cyrillics \cyrillict \cyrillico
+ \cyrillicr \cyrillicii\cyrillicn
+ \cyrillicc \cyrillicii\space ]
+
+\setuplabeltext [\s!ru] [\v!hencefore=\cyrillics \cyrillicm.\space
+ \cyrillicv \cyrillicery \cyrillicsh
+ \cyrillice]
+\setuplabeltext [\s!ua] [\v!hencefore=\cyrillicya\cyrillick \space
+ \cyrillicp \cyrillico \cyrillick
+ \cyrillica \cyrillicz \cyrillica
+ \cyrillicn \cyrillico \space
+ \cyrillicv \cyrillici \cyrillicshch
+ \cyrillice]
+
+\setuplabeltext [\s!ru] [\v!hereafter=\cyrillics \cyrillicm.\space
+ \cyrillicn \cyrillici \cyrilliczh
+ \cyrillice]
+\setuplabeltext [\s!ua] [\v!hereafter=\cyrillicya\cyrillick \space
+ \cyrillicp \cyrillico \cyrillick
+ \cyrillica \cyrillicz \cyrillica
+ \cyrillicn \cyrillico \space
+ \cyrillicn \cyrillici \cyrilliczh
+ \cyrillicch\cyrillice]
+
+\setuplabeltext [\s!ru] [\v!see=\cyrillics \cyrillicm.\space]
+\setuplabeltext [\s!ua] [\v!see=\cyrillicd \cyrillici
+ \cyrillicv.\space ]
+
+\setuplabeltext [\s!ru] [\v!january=\cyrillicya\cyrillicn \cyrillicv
+ \cyrillica \cyrillicr \cyrillicya]
+\setuplabeltext [\s!ru] [\v!february=\cyrillicf \cyrillice \cyrillicv
+ \cyrillicr \cyrillica \cyrillicl
+ \cyrillicya]
+\setuplabeltext [\s!ru] [\v!march=\cyrillicm \cyrillica \cyrillicr
+ \cyrillict \cyrillica]
+\setuplabeltext [\s!ru] [\v!april=\cyrillica \cyrillicp \cyrillicr
+ \cyrillice \cyrillicl \cyrillicya]
+\setuplabeltext [\s!ru] [\v!may=\cyrillicm \cyrillica \cyrillicya]
+\setuplabeltext [\s!ru] [\v!june=\cyrillici \cyrillicyu\cyrillicn
+ \cyrillicya]
+\setuplabeltext [\s!ru] [\v!july=\cyrillici \cyrillicyu\cyrillicl
+ \cyrillicya]
+\setuplabeltext [\s!ru] [\v!august=\cyrillica \cyrillicv \cyrillicg
+ \cyrillicu \cyrillics \cyrillict
+ \cyrillica]
+\setuplabeltext [\s!ru] [\v!september=\cyrillics \cyrillice \cyrillicn
+ \cyrillict \cyrillicya\cyrillicb
+ \cyrillicr \cyrillicya]
+\setuplabeltext [\s!ru] [\v!october=\cyrillico \cyrillick \cyrillict
+ \cyrillicya\cyrillicb \cyrillicr
+ \cyrillicya]
+\setuplabeltext [\s!ru] [\v!november=\cyrillicn \cyrillico \cyrillicya
+ \cyrillicb \cyrillicr \cyrillicya]
+\setuplabeltext [\s!ru] [\v!december=\cyrillicd \cyrillice \cyrillick
+ \cyrillica \cyrillicb \cyrillicr
+ \cyrillicya]
+
+\setuplabeltext [\s!ua] [\v!january=\cyrillics \cyrillicii\cyrillicch
+ \cyrillicn \cyrillicya]
+\setuplabeltext [\s!ua] [\v!february=\cyrillicl \cyrillicyu\cyrillict
+ \cyrillico \cyrillicg \cyrillico]
+\setuplabeltext [\s!ua] [\v!march=\cyrillicb \cyrillice \cyrillicr
+ \cyrillice \cyrillicz \cyrillicn
+ \cyrillicya]
+\setuplabeltext [\s!ua] [\v!april=\cyrillick \cyrillicv \cyrillicii
+ \cyrillict \cyrillicn \cyrillicya]
+\setuplabeltext [\s!ua] [\v!may=\cyrillict \cyrillicr \cyrillica
+ \cyrillicv \cyrillicn \cyrillicya]
+\setuplabeltext [\s!ua] [\v!june=\cyrillicch\cyrillice \cyrillicr
+ \cyrillicv \cyrillicn \cyrillicya]
+\setuplabeltext [\s!ua] [\v!july=\cyrillicl \cyrillici \cyrillicp
+ \cyrillicn \cyrillicya]
+\setuplabeltext [\s!ua] [\v!august=\cyrillics \cyrillice \cyrillicr
+ \cyrillicp \cyrillicn \cyrillicya]
+\setuplabeltext [\s!ua] [\v!september=\cyrillicv \cyrillice \cyrillicr
+ \cyrillice \cyrillics \cyrillicn
+ \cyrillicya]
+\setuplabeltext [\s!ua] [\v!october=\cyrilliczh\cyrillico \cyrillicv
+ \cyrillict \cyrillicn \cyrillicya]
+\setuplabeltext [\s!ua] [\v!november=\cyrillicl \cyrillici \cyrillics
+ \cyrillict \cyrillico \cyrillicp
+ \cyrillica \cyrillicd \cyrillica]
+\setuplabeltext [\s!ua] [\v!december=\cyrillicg \cyrillicr \cyrillicu
+ \cyrillicd \cyrillicn \cyrillicya]
+
+\setuplabeltext [\s!ru] [\v!sunday=\cyrillicv \cyrillico \cyrillics
+ \cyrillick \cyrillicr \cyrillice
+ \cyrillics \cyrillice \cyrillicn
+ \cyrillicsftsn \cyrillice]
+\setuplabeltext [\s!ru] [\v!monday=\cyrillicp \cyrillico \cyrillicn
+ \cyrillice \cyrillicd \cyrillice
+ \cyrillicl \cyrillicsftsn
+ \cyrillicn \cyrillici \cyrillick]
+\setuplabeltext [\s!ru] [\v!tuesday=\cyrillicv \cyrillict \cyrillico
+ \cyrillicr \cyrillicn \cyrillici
+ \cyrillick]
+\setuplabeltext [\s!ru] [\v!wednesday=\cyrillics \cyrillicr \cyrillice
+ \cyrillicd \cyrillica]
+\setuplabeltext [\s!ru] [\v!thursday=\cyrillicch\cyrillice \cyrillict
+ \cyrillicv \cyrillice \cyrillicr
+ \cyrillicg]
+\setuplabeltext [\s!ru] [\v!friday=\cyrillicp \cyrillicya\cyrillict
+ \cyrillicn \cyrillici \cyrillicc
+ \cyrillica]
+\setuplabeltext [\s!ru] [\v!saturday=\cyrillics \cyrillicu \cyrillicb
+ \cyrillicb \cyrillico \cyrillict
+ \cyrillica]
+
+\setuplabeltext [\s!ua] [\v!sunday=\cyrillicn \cyrillice \cyrillicd
+ \cyrillicii\cyrillicl \cyrillicya]
+\setuplabeltext [\s!ua] [\v!monday=\cyrillicp \cyrillico \cyrillicn
+ \cyrillice \cyrillicd \cyrillicii
+ \cyrillicl \cyrillico \cyrillick]
+\setuplabeltext [\s!ua] [\v!tuesday=\cyrillicv \cyrillicii\cyrillicv
+ \cyrillict \cyrillico \cyrillicr
+ \cyrillico \cyrillick]
+\setuplabeltext [\s!ua] [\v!wednesday=\cyrillics \cyrillice \cyrillicr
+ \cyrillice \cyrillicd \cyrillica]
+\setuplabeltext [\s!ua] [\v!thursday=\cyrillicch\cyrillice \cyrillict
+ \cyrillicv \cyrillice \cyrillicr]
+\setuplabeltext [\s!ua] [\v!friday=\cyrillicp'\cyrillicya\cyrillict
+ \cyrillicn \cyrillici \cyrillicc
+ \cyrillicya]
+\setuplabeltext [\s!ua] [\v!saturday=\cyrillics \cyrillicu \cyrillicb
+ \cyrillico \cyrillict \cyrillica]
+
+
+%D \ShowAllLanguageValues [\s!ru] [russian] {Russian} {doll}
+%D \ShowAllLanguageValues [\s!ua] [ukranian] {Ukranian} {dance}
+
+\protect \endinput
diff --git a/tex/context/base/lang-dis.mkii b/tex/context/base/lang-dis.mkii
new file mode 100644
index 000000000..f081bf4a9
--- /dev/null
+++ b/tex/context/base/lang-dis.mkii
@@ -0,0 +1,59 @@
+%D \module
+%D [ file=lang-dis,
+%D version=2005.02.12,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Distribution Patterns,
+%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.
+
+%D This code used to be part of cont-usr.tex but now that we
+%D use more generic pattern files, we decided to isolate these
+%D mappings.
+
+\writestatus{loading}{ConTeXt Language Macros / Distribution Patterns}
+
+%D Hyphenation patterns are normally sought in filed named
+%D \type {lang-xx.pat}. When present on the system, those
+%D patterns take precedence. This list will be adapted to
+%D the actual situation, given that it's noticed.
+
+%D The us/uk hyph 1/2 files will go
+
+\unprotect
+
+% \definefilefallback [lang-ca.pat] [cahyph.tex]
+% \definefilefallback [lang-da.pat] [dkhyph.tex]
+% \definefilefallback [lang-de.pat] [dehyphn.tex]
+% \definefilefallback [lang-es.pat] [eshyph.tex]
+% \definefilefallback [lang-fi.pat] [fihyph.tex]
+% \definefilefallback [lang-fr.pat] [frhyph.tex]
+% \definefilefallback [lang-hr.pat] [hrhyph.tex]
+% \definefilefallback [lang-hu.pat] [huhyph.tex]
+% \definefilefallback [lang-it.pat] [ithyph.tex]
+% \definefilefallback [lang-la.pat] [lahyph7.tex]
+% \definefilefallback [lang-no.pat] [nohyph.tex]
+% \definefilefallback [lang-pl.pat] [plhyph.tex]
+% \definefilefallback [lang-pt.pat] [pthyph.tex]
+% \definefilefallback [lang-ro.pat] [rohyph.tex]
+% \definefilefallback [lang-ru.pat] [ruenhyph.tex]
+% \definefilefallback [lang-sl.pat] [sihyph.tex,slhyph.tex]
+% \definefilefallback [lang-sv.pat] [svhyph.tex,sehyph.tex]
+% \definefilefallback [lang-tr.pat] [tkhyph.tex,trhyph.tex]
+% \definefilefallback [lang-ua.pat] [ukrenhyp.tex]
+% \definefilefallback [lang-uk.pat] [ukhyphen.tex,ukhyph.tex]
+% \definefilefallback [lang-us.pat] [ushyphmax.tex,ushyph.tex,ushyph1.tex,ushyph2.tex,hyphen.tex]
+% \definefilefallback [lang-nl.pat] [nehyph96.tex,dutch96.pat,nehyph.tex]
+% \definefilefallback [lang-cz.pat] [czhyphen.tex,czhyph.pat]
+% \definefilefallback [lang-sk.pat] [skhyphen.tex,skhyph.pat]
+% \definefilefallback [lang-deo.pat] [dehypht.tex]
+
+% \definefilesynonym [lang-af.pat] [lang-nl.pat]
+% \definefilesynonym [lang-en.pat] [lang-us.pat]
+% \definefilesynonym [lang-en.hyp] [lang-us.hyp]
+
+\protect \endinput
diff --git a/tex/context/base/lang-frd.tex b/tex/context/base/lang-frd.tex
new file mode 100644
index 000000000..6cc27080b
--- /dev/null
+++ b/tex/context/base/lang-frd.tex
@@ -0,0 +1,140 @@
+%D \module
+%D [ file=lang-frd,
+%D version=2004.01.15,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Language Frequency Table Data,
+%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.
+
+%D This is expewrimental work!
+
+% http://www.onzetaal.nl/advies/letterfreq.html
+
+\startcharactertable[nl]
+ \charfreq a 7.47
+ \charfreq b 1.58
+ \charfreq c 1.24
+ \charfreq d 5.93
+ \charfreq e 18.91
+ \charfreq f .81
+ \charfreq g 3.4
+ \charfreq h 2.38
+ \charfreq i 6.5
+ \charfreq j 1.46
+ \charfreq k 2.25
+ \charfreq l 3.57
+ \charfreq m 2.21
+ \charfreq n 10.03
+ \charfreq o 6.06
+ \charfreq p 1.57
+ \charfreq q .009
+ \charfreq r 6.41
+ \charfreq s 3.73
+ \charfreq t 6.79
+ \charfreq u 1.99
+ \charfreq v 2.85
+ \charfreq w 1.52
+ \charfreq x .04
+ \charfreq y .035
+ \charfreq z 1.39
+\stopcharactertable
+
+% http://caislab.icu.ac.kr/course/2001/spring/ice605/down/010306.pdf
+
+% \startcharactertable[en]
+% \charfreq a 8.2
+% \charfreq b 1.5
+% \charfreq c 2.8
+% \charfreq d 4.3
+% \charfreq e 12.7
+% \charfreq f 2.2
+% \charfreq g 2
+% \charfreq h 6.1
+% \charfreq i 7
+% \charfreq j .2
+% \charfreq k .8
+% \charfreq l 4
+% \charfreq m 2.4
+% \charfreq n 6.7
+% \charfreq o 7.5
+% \charfreq p 1.9
+% \charfreq q .1
+% \charfreq r 6
+% \charfreq s 6.3
+% \charfreq t 9.1
+% \charfreq u 2.8
+% \charfreq v 1
+% \charfreq w 2.3
+% \charfreq x .1
+% \charfreq y 2
+% \charfreq z .1
+% \stopcharactertable
+
+% http://www.blankenburg.de/gat/pages/fach/info/analyse2.htm
+
+\startcharactertable[en]
+ \charfreq a 8.04
+ \charfreq b 1.54
+ \charfreq c 3.06
+ \charfreq d 3.99
+ \charfreq e 12.51
+ \charfreq f 2.3
+ \charfreq g 1.96
+ \charfreq h 5.49
+ \charfreq i 7.26
+ \charfreq j .16
+ \charfreq k .67
+ \charfreq l 4.14
+ \charfreq m 2.53
+ \charfreq n 7.09
+ \charfreq o 7.6
+ \charfreq p 2
+ \charfreq q .11
+ \charfreq r 6.12
+ \charfreq s 6.54
+ \charfreq t 9.25
+ \charfreq u 2.71
+ \charfreq v .99
+ \charfreq w 1.92
+ \charfreq x .19
+ \charfreq y 1.73
+ \charfreq z .09
+\stopcharactertable
+
+% http://www.blankenburg.de/gat/pages/fach/info/analyse2.htm
+
+\startcharactertable[de]
+ \charfreq a 6.47
+ \charfreq b 1.93
+ \charfreq c 2.68
+ \charfreq d 4.83
+ \charfreq e 17.48
+ \charfreq f 1.65
+ \charfreq g 3.06
+ \charfreq h 4.23
+ \charfreq i 7.73
+ \charfreq j .27
+ \charfreq k 1.46
+ \charfreq l 3.49
+ \charfreq m 2.58
+ \charfreq n 9.84
+ \charfreq o 2.98
+ \charfreq p .96
+ \charfreq q .02
+ \charfreq r 7.54
+ \charfreq s 6.83
+ \charfreq t 6.13
+ \charfreq u 4.17
+ \charfreq v .94
+ \charfreq w 1.48
+ \charfreq x .04
+ \charfreq y .08
+ \charfreq z 1.14
+\stopcharactertable
+
+\endinput
diff --git a/tex/context/base/lang-frq.tex b/tex/context/base/lang-frq.tex
new file mode 100644
index 000000000..773230e6c
--- /dev/null
+++ b/tex/context/base/lang-frq.tex
@@ -0,0 +1,207 @@
+%D \module
+%D [ file=lang-frq,
+%D version=2004.01.15,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Frequency Tables,
+%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 Language Macros / Frequency Tables}
+
+\unprotect
+
+\ifx\s!en\undefined \def\v!en{en} \fi
+\ifx\??lg\undefined \def\??lg{@@lg} \fi
+
+%M \usemodule[layout]
+
+%D \macros
+%D {charwidthmethod}
+%D
+%D This module implements a method for determining the width of an
+%D average character in a language. It uses the dimensions of the
+%D current fonts.
+%D
+%D \def\ShwChrWd#1#2#3%
+%D {\chardef\charwidthmethod#1\relax
+%D \mainlanguage[#2#3]\the\dimexpr(\averagecharwidth)}
+%D
+%D \starttabulate[|c|c|c|c|c|c|]
+%D \HL
+%D \NC \NC\bf0=amount\NC\bf1=.5em\NC2=ex\NC\bf3=frequency\NC\bf4=list\NC\NR
+%D \HL
+%D \NC\bf en\NC\ShwChrWd0en\NC\ShwChrWd1en\NC\ShwChrWd2en\NC\ShwChrWd3en\NC\ShwChrWd4en\NC\NR
+%D \NC\bf nl\NC\ShwChrWd0nl\NC\ShwChrWd1nl\NC\ShwChrWd2nl\NC\ShwChrWd3nl\NC\ShwChrWd4nl\NC\NR
+%D \NC\bf de\NC\ShwChrWd0de\NC\ShwChrWd1de\NC\ShwChrWd2de\NC\ShwChrWd3de\NC\ShwChrWd4de\NC\NR
+%D \HL
+%D \stoptabulate
+%D
+%D Method~1 ignores the widths and assumes that each character has a
+%D width of .5em, which is true for most monospaced fonts. Method~2
+%D takes the x as starting point, and assumes that it's height kind of
+%D matches its width. Method~3 is the best one, and determines the
+%D average width based on the language specific character table.
+%D Method~4 is a mixture between the first two methods: character
+%D specific widths applied to an equal distribution. Method~0 reports
+%D the total count, which normally is~100.
+
+\chardef\charwidthmethod=3 % 0=amount 1=em 2=ex 3=frequency 4=flattened >4=ex
+
+%D \macros
+%D {charwidthlanguage}
+%D
+%D The language used for the calculations is defined as:
+
+\def\charwidthlanguage{\currentmainlanguage}
+
+%D \macros
+%D {charfreq}
+%D
+%D This method comes into action in the following macro:
+
+\def\charfreq#1 #2 % character fraction
+ {+(\ifcase\charwidthmethod
+ #2\dimexpr100\onepoint\relax
+ \or
+ #2\dimexpr.5em\relax % \emwidth/2
+ \or
+ #2\dimexpr\exheight\relax
+ \or
+ #2\fontcharwd\font`#1%
+ \or
+ \dimexpr100\fontcharwd\font`#1/\charactertsize\charwidthlanguage\relax % ugly hack
+ \else
+ #2\dimexpr\exheight\relax
+ \fi)}
+
+%D \macros
+%D {startcharactertable}
+%D
+%D A frequency table is defined with the following macro. The \type
+%D {charfreq} macro is used in this table.
+
+\def\startcharactertable[#1]#2\stopcharactertable % \dimexpr has fuzzy lookahead
+ {\startnointerference
+ \long\setgvalue{\??lg:w:#1}{#2}% the width vector
+ \scratchcounter\zerocount \def\charfreq##1 ##2 {\advance\scratchcounter\plusone} #2%
+ \long\setxvalue{\??lg:c:#1}{\the\scratchcounter}% the character count
+ \stopnointerference}
+
+%D \macros
+%D {charactertable,charactertsize}
+%D
+%D The table content as well as the number of entries can be fetched with
+%D the following two macros. The architecture of the table and calling
+%D macro permits a fully expandable application.
+
+\def\charactertable#1%
+ {\csname\??lg:w:\ifcsname\??lg:w:#1\endcsname#1\else\s!en\fi\endcsname}
+
+\def\charactertsize#1%
+ {\csname\??lg:c:\ifcsname\??lg:c:#1\endcsname#1\else\s!en\fi\endcsname}
+
+%D Although it is of hardly any use, you can inherit a character table:
+%D
+%D \starttyping
+%D \startcharactertable[cz] \charactertable{en} \stopcharactertable
+%D \stoptyping
+%D
+%D We define a default vector with 100\% x's.
+
+\startcharactertable[en] 100 x \stopcharactertable % kind of default
+
+%D \macros
+%D {averagecharwidth}
+%D
+%D This macro reports the average width for the current main
+%D language (\the \dimexpr (\averagecharwidth)).
+
+\def\averagecharwidth{\dimexpr((\zeropoint\charactertable\charwidthlanguage)/100)}
+
+\def\showcharfreq
+ {\hbox\bgroup
+ \charwidthlanguage:%
+ \dostepwiserecurse041%
+ {\chardef\charwidthmethod\recurselevel\relax
+ \enspace\recurselevel/\the\dimexpr(\averagecharwidth)}%
+ \egroup}
+
+%D Just for fun, we show a few frequency tables as graphic (\in {figure}
+%D [fig:charfreq]).
+%D
+%D \startbuffer
+%D \definepalet [charfreq] [en=darkred, nl=darkgreen, de=darkblue]
+%D
+%D \def\charfreq#1 #2 %
+%D {\startMPdrawing
+%D interim linejoin := butt ;
+%D a := ASCII "#1" ;
+%D if (a >= (ASCII "a")) and (a <= (ASCII "z")) :
+%D draw ((0,#2*.25cm)--origin--(0,#2*.5cm))
+%D shifted (a*4mm+o,0)
+%D withpen pencircle scaled .5mm
+%D withcolor c;
+%D fi ;
+%D \stopMPdrawing}
+%D
+%D \resetMPdrawing
+%D \startMPdrawing
+%D numeric a, o ; a := o := 0 ;
+%D color c ; c := .5white ;
+%D string s ; s := "" ;
+%D \stopMPdrawing
+%D
+%D \startMPdrawing o := 0mm ; c := \MPcolor{charfreq:en} ; \stopMPdrawing
+%D \charactertable{en}
+%D
+%D \startMPdrawing o := 1mm ; c := \MPcolor{charfreq:nl} ; \stopMPdrawing
+%D \charactertable{nl}
+%D
+%D \startMPdrawing o := 2mm ; c := \MPcolor{charfreq:de} ; \stopMPdrawing
+%D \charactertable{de}
+%D
+%D \startMPdrawing
+%D for a := ASCII "a" upto ASCII "z" :
+%D draw textext.bot("\strut\tttf " & char a) shifted (a*4mm+1mm,-1mm) ;
+%D endfor ;
+%D \stopMPdrawing
+%D
+%D \MPdrawingdonetrue \getMPdrawing \resetMPdrawing
+%D \stopbuffer
+%D
+%D \placefigure
+%D [here]
+%D [fig:charfreq]
+%D {The character distributions for English, Dutch and German.}
+%D {\getbuffer}
+%D
+%D A few samples of usage of this mechanism are shown below:
+%D
+%D \startbuffer
+%D {\mainlanguage[en]\hsize65\averagecharwidth\mainlanguage[en]\input ward \blank}
+%D {\mainlanguage[nl]\hsize65\averagecharwidth\mainlanguage[en]\input ward \blank}
+%D {\mainlanguage[de]\hsize65\averagecharwidth\mainlanguage[en]\input ward \blank}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D Although the widthts differ, the consequenes for breaking the paragraph
+%D into lines are minimal.
+
+%D \macros
+%D {freezeaveragecharacterwidth}
+%D
+%D This macro can be used to make sure that the width does not change during a
+%D page break when another font is used.
+
+\let\normalaveragecharacterwidth\averagecharacterwidth
+
+\def\freezeaveragecharacterwidth % global
+ {\xdef\averagecharacterwidth{\dimexpr(\the\normalaveragecharacterwidth)}}
+
+\protect \endinput
diff --git a/tex/context/base/lang-ger.tex b/tex/context/base/lang-ger.tex
new file mode 100644
index 000000000..1ffbb33e6
--- /dev/null
+++ b/tex/context/base/lang-ger.tex
@@ -0,0 +1,738 @@
+%D \module
+%D [ file=lang-ger,
+%D version=1997.09.03,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Germanic Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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 Language Macros / Germanic Languages}
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+%D
+%D \starttabulate[|lB|l|]
+%D \NC Norwegian \NC Hans Fredrik Nordhaug \NC \NR
+%D \NC Danish \NC Arne Jorgensen \NC \NR % check the o
+%D \NC Afrikaans \NC \NC \NR
+%D \stoptabulate
+
+% Danish, Faeroese, Icelandic, Norwegian, Swedish, German, Yiddish
+% Afrikaans, Dutch, English, Flemush, Frisian, Plattdeutsch
+
+\unprotect
+
+\installlanguage
+ [\s!nl]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\lowerleftsingleninequote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\lowerleftdoubleninequote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year},
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
+
+\installlanguage
+ [\s!en]
+ [\c!spacing=\v!broad,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!month,\ ,\v!day,{,\ },\v!year},
+ \s!patterns=\s!us,
+ \s!lefthyphenmin=2,
+ \s!righthyphenmin=3]
+
+\installlanguage
+ [\s!de]
+ [\c!spacing=\v!packed,
+ \s!lefthyphenmin=3,
+ \s!righthyphenmin=3,
+ \c!leftsentence={\hbox{--~}},
+ \c!rightsentence={\hbox{~--}},
+ \c!leftsubsentence={--},
+ \c!rightsubsentence={--},
+ \c!leftquote=\lowerleftsingleninequote,
+ \c!rightquote=\upperrightsinglesixquote,
+ \c!leftquotation=\lowerleftdoubleninequote,
+ \c!rightquotation=\upperrightdoublesixquote,
+ \c!date={\v!day,{.},\ ,\v!month,\ ,\v!year},
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
+
+\installlanguage
+ [\s!da]
+ [\c!spacing=\v!packed,
+ \c!leftsentence={\hbox{--\hskip.5em}},
+ \c!rightsentence={\hbox{\hskip.5em--}},
+ \c!leftsubsentence={--},
+ \c!rightsubsentence={--},
+ \c!leftquote=\lowerleftsingleninequote,
+ \c!rightquote=\upperrightsinglesixquote,
+ \c!leftquotation=\lowerleftdoubleninequote,
+ \c!rightquotation=\upperrightdoublesixquote,
+ \c!date={\v!day,{.},\ ,\v!month,\ ,\v!year}]
+
+\installlanguage
+ [\s!sv]
+ [\c!spacing=\v!packed,
+ \c!leftsentence={\hbox{--~}},
+ \c!rightsentence={\hbox{~--}},
+ \c!leftsubsentence={--},
+ \c!rightsubsentence={--},
+ \c!leftquote=\upperrightsingleninequote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperrightdoubleninequote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
+
+\installlanguage
+ [\s!af]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day},
+ \s!patterns=\s!nl]
+
+\installlanguage
+ [\s!nb]
+ [spacing=packed,
+ lefthyphenmin=2,
+ righthyphenmin=2,
+ leftsentence=---,
+ rightsentence=---,
+ leftsubsentence=---,
+ rightsubsentence=---,
+ leftquote=\upperleftsinglesixquote,
+ rightquote=\upperrightsingleninequote,
+ leftquotation=\leftguillemot,
+ rightquotation=\rightguillemot,
+ date={day,{.},\ ,month,\ ,year},
+ state=stop]
+
+\installlanguage
+ [\s!nn]
+ [spacing=packed,
+ lefthyphenmin=2,
+ righthyphenmin=2,
+ leftsentence=---,
+ rightsentence=---,
+ leftsubsentence=---,
+ rightsubsentence=---,
+ leftquote=\upperleftsinglesixquote,
+ rightquote=\upperrightsingleninequote,
+ leftquotation=\leftguillemot,
+ rightquotation=\rightguillemot,
+ date={day,{.},\ ,month,\ ,year},
+ state=stop]
+
+\installlanguage [\s!no] [\s!nb]
+\installlanguage [\s!norwegian] [\s!nb]
+\installlanguage [\s!bokmal] [\s!nb]
+\installlanguage [\s!nynorsk] [\s!nn]
+
+%D Extra:
+
+% \mainlanguage[en]
+% \mainlanguage[de]
+% \mainlanguage[deo]
+% \mainlanguage[de-de]
+% \mainlanguage[de-at]
+% \mainlanguage[de-ch]
+%
+% \starttext
+% Die Herren Meier\index{Meier}, Müller\index{Müller}, Huber\index{Huber}
+% und Schmidt\index{Schmidt} arbeiten in der gleichen Firma.
+%
+% \index{Mass}\index{Mas}\index{Maß}\index{Maße}\index{Masse}
+% \index{Muller}\index{Mûller}
+% \index{Hutte}\index{Hütte}\index{Huttf}
+% \index{paar}\index{Paar}
+% \index{a}\index{aa}\index{ä}\index{az}\index{aza}
+% \index{o}\index{oo}\index{ö}\index{oz}\index{oza}
+% \index{u}\index{uu}\index{ü}\index{uz}\index{uza}\index{üa}
+% \index{call}\index{chip}
+%
+% \subject{Index} \placeindex
+% \stoptext
+
+\installlanguage % old german
+ [deo]
+ [\c!spacing=\v!packed,
+ \c!default=\s!de]
+
+\installlanguage
+ [de-de]
+ [\c!spacing=\v!packed,
+ \c!default=\s!de]
+
+\installlanguage
+ [de-at]
+ [\c!spacing=\v!packed,
+ \c!default=\s!de,
+ \c!leftquote=\leftguillemot,
+ \c!rightquote=\rightguillemot,
+ \c!leftquotation=\leftguillemot,
+ \c!rightquotation=\rightguillemot]
+
+\installlanguage
+ [de-ch]
+ [\c!spacing=\v!packed,
+ \c!default=\s!de]
+
+%D And some alternative (but very real) english patterns:
+
+\installlanguage
+ [en-gb]
+ [\c!default=\s!en,
+ \s!patterns=\s!gb,
+ \s!lefthyphenmin=3,
+ \s!righthyphenmin=3]
+
+\installlanguage
+ [en-us]
+ [\c!default=\s!en]
+
+\installlanguage [\s!uk] [en-gb]
+\installlanguage [\s!us] [en-us]
+
+%D For compatibility reasons we also define:
+
+%installlanguage [du] [\s!de] % old times context
+%installlanguage [sp] [\s!es] % old times context /lang-ita
+
+\installlanguage [usenglish] [en-us]
+\installlanguage [ukenglish] [en-gb]
+\installlanguage [english] [en-us]
+\installlanguage [dutch] [\s!nl]
+\installlanguage [german] [\s!de]
+\installlanguage [danish] [\s!da]
+\installlanguage [swedish] [\s!sv]
+\installlanguage [afrikaans] [\s!af]
+
+\setupheadtext [\s!en] [\v!content=Contents]
+\setupheadtext [\s!nl] [\v!content=Inhoud]
+\setupheadtext [\s!de] [\v!content=Inhalt]
+\setupheadtext [\s!da] [\v!content=Indhold]
+\setupheadtext [\s!sv] [\v!content=Inneh\aring ll]
+\setupheadtext [\s!af] [\v!content=Inhoud]
+\setupheadtext [\s!nb] [\v!content=Innhold]
+\setupheadtext [\s!nn] [\v!content=Innhald]
+
+\setupheadtext [\s!en] [\v!tables=Tables]
+\setupheadtext [\s!nl] [\v!tables=Tabellen]
+\setupheadtext [\s!de] [\v!tables=Tabellen]
+\setupheadtext [\s!da] [\v!tables=Tabeller]
+\setupheadtext [\s!sv] [\v!tables=Tabeller]
+\setupheadtext [\s!af] [\v!tables=Tabelle]
+\setupheadtext [\s!nb] [\v!tables=Tabeller]
+\setupheadtext [\s!nn] [\v!tables=Tabellar]
+
+\setupheadtext [\s!en] [\v!figures=Figures]
+\setupheadtext [\s!nl] [\v!figures=Figuren]
+\setupheadtext [\s!de] [\v!figures=Abbildungen]
+\setupheadtext [\s!da] [\v!figures=Figurer]
+\setupheadtext [\s!sv] [\v!figures=Figurer]
+\setupheadtext [\s!af] [\v!figures=Figure]
+\setupheadtext [\s!nb] [\v!figures=Figurer]
+\setupheadtext [\s!nn] [\v!figures=Figurar]
+
+\setupheadtext [\s!en] [\v!graphics=Graphics]
+\setupheadtext [\s!nl] [\v!graphics=Grafieken]
+\setupheadtext [\s!de] [\v!graphics=Graphiken]
+\setupheadtext [\s!da] [\v!graphics=Grafik]
+\setupheadtext [\s!sv] [\v!graphics=Grafik]
+\setupheadtext [\s!af] [\v!graphics=Grafieke]
+\setupheadtext [\s!nb] [\v!graphics=Bilde]
+\setupheadtext [\s!nn] [\v!graphics=Bilete]
+
+\setupheadtext [\s!en] [\v!intermezzi=Intermezzos]
+\setupheadtext [\s!nl] [\v!intermezzi=Intermezzo's]
+\setupheadtext [\s!de] [\v!intermezzi=Intermezzi]
+\setupheadtext [\s!da] [\v!intermezzi=Intermezzoer]
+\setupheadtext [\s!sv] [\v!intermezzi=Intermezzon]
+\setupheadtext [\s!af] [\v!intermezzi=Intermezzos]
+\setupheadtext [\s!nb] [\v!intermezzi=Intermesso]
+\setupheadtext [\s!nn] [\v!intermezzi=Intermesso]
+
+\setupheadtext [\s!en] [\v!index=Index]
+\setupheadtext [\s!nl] [\v!index=Index]
+\setupheadtext [\s!de] [\v!index=Index]
+\setupheadtext [\s!da] [\v!index=Indeks]
+\setupheadtext [\s!sv] [\v!index=Sakregister]
+\setupheadtext [\s!af] [\v!index=Indeks]
+\setupheadtext [\s!nb] [\v!index=Register]
+\setupheadtext [\s!nn] [\v!index=Register]
+
+\setupheadtext [\s!en] [\v!abbreviations=Abbreviations]
+\setupheadtext [\s!nl] [\v!abbreviations=Afkortingen]
+\setupheadtext [\s!de] [\v!abbreviations=Abk\uumlaut rzungen]
+\setupheadtext [\s!da] [\v!abbreviations=Forkortelser]
+\setupheadtext [\s!sv] [\v!abbreviations=F\oumlaut rkortningar]
+\setupheadtext [\s!af] [\v!abbreviations=Afkortings]
+\setupheadtext [\s!nb] [\v!abbreviations=Forkortelser]
+\setupheadtext [\s!nn] [\v!abbreviations=Forkortingar]
+
+\setupheadtext [\s!en] [\v!logos=Logos]
+\setupheadtext [\s!nl] [\v!logos=Logo's]
+\setupheadtext [\s!de] [\v!logos=Logos]
+\setupheadtext [\s!da] [\v!logos=Logoer]
+\setupheadtext [\s!sv] [\v!logos=Loggor]
+\setupheadtext [\s!af] [\v!logos=Logos]
+\setupheadtext [\s!nb] [\v!logos=Logoer]
+\setupheadtext [\s!nn] [\v!logos=Logoar]
+
+\setupheadtext [\s!en] [\v!units=Units]
+\setupheadtext [\s!nl] [\v!units=Eenheden]
+\setupheadtext [\s!de] [\v!units=Einheiten]
+\setupheadtext [\s!da] [\v!units=Enheder]
+\setupheadtext [\s!sv] [\v!units=Enheter]
+\setupheadtext [\s!af] [\v!units=Eenhede]
+\setupheadtext [\s!nb] [\v!units=Enheter]
+\setupheadtext [\s!nn] [\v!units=Einingar]
+
+\setupheadtext [\s!en] [pubs=References]
+\setupheadtext [\s!nl] [pubs=Literatuur]
+\setupheadtext [\s!de] [pubs=Literatur]
+%setupheadtext [\s!da] [pubs=?]
+%setupheadtext [\s!sv] [pubs=?]
+%setupheadtext [\s!af] [pubs=?]
+%setupheadtext [\s!nb] [pubs=?]
+%setupheadtext [\s!nn] [pubs=?]
+
+\setuplabeltext [\s!en] [\v!table=Table ]
+\setuplabeltext [\s!nl] [\v!table=Tabel ]
+\setuplabeltext [\s!de] [\v!table=Tabelle ]
+\setuplabeltext [\s!da] [\v!table=Tabel ]
+\setuplabeltext [\s!sv] [\v!table=Tabell ]
+\setuplabeltext [\s!af] [\v!table=Tabel]
+\setuplabeltext [\s!nb] [\v!table=Tabell ]
+\setuplabeltext [\s!nn] [\v!table=Tabell ]
+
+\setuplabeltext [\s!en] [\v!figure=Figure ]
+\setuplabeltext [\s!nl] [\v!figure=Figuur ]
+\setuplabeltext [\s!de] [\v!figure=Abbildung ]
+\setuplabeltext [\s!da] [\v!figure=Figur ]
+\setuplabeltext [\s!sv] [\v!figure=Figur ]
+\setuplabeltext [\s!af] [\v!figure=Figuur ]
+\setuplabeltext [\s!nb] [\v!figure=Figur ]
+\setuplabeltext [\s!nn] [\v!figure=Figur ]
+
+\setuplabeltext [\s!en] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!nl] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!de] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!da] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!sv] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!af] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!nb] [\v!intermezzo=Intermesso ]
+\setuplabeltext [\s!nn] [\v!intermezzo=Intermesso ]
+
+\setuplabeltext [\s!en] [\v!graphic=Graphic ]
+\setuplabeltext [\s!nl] [\v!graphic=Grafiek ]
+\setuplabeltext [\s!de] [\v!graphic=Graphik ]
+\setuplabeltext [\s!da] [\v!graphic=Grafik ]
+\setuplabeltext [\s!sv] [\v!graphic=Grafik ]
+\setuplabeltext [\s!af] [\v!graphic=Grafiek ]
+\setuplabeltext [\s!nb] [\v!graphic=Bilde ]
+\setuplabeltext [\s!nn] [\v!graphic=Bilete ]
+
+%D We don't set these here. One can do that in a style.
+
+\setuplabeltext [\s!en] [\v!chapter=] % Chapter
+\setuplabeltext [\s!nl] [\v!chapter=]
+\setuplabeltext [\s!de] [\v!chapter=] % Kapitel
+\setuplabeltext [\s!da] [\v!chapter=]
+\setuplabeltext [\s!sv] [\v!chapter=]
+\setuplabeltext [\s!af] [\v!chapter=] % Hoofstuk
+\setuplabeltext [\s!nb] [\v!chapter=]
+\setuplabeltext [\s!nn] [\v!chapter=]
+
+\setuplabeltext [\s!en] [\v!section=]
+\setuplabeltext [\s!nl] [\v!section=]
+\setuplabeltext [\s!de] [\v!section=]
+\setuplabeltext [\s!da] [\v!section=]
+\setuplabeltext [\s!sv] [\v!section=]
+\setuplabeltext [\s!af] [\v!section=] % Paragraaf
+\setuplabeltext [\s!nb] [\v!section=]
+\setuplabeltext [\s!nn] [\v!section=]
+
+\setuplabeltext [\s!en] [\v!subsection=]
+\setuplabeltext [\s!nl] [\v!subsection=]
+\setuplabeltext [\s!de] [\v!subsection=]
+\setuplabeltext [\s!da] [\v!subsection=]
+\setuplabeltext [\s!sv] [\v!subsection=]
+\setuplabeltext [\s!af] [\v!subsection=]
+\setuplabeltext [\s!nb] [\v!subsection=]
+\setuplabeltext [\s!nn] [\v!subsection=]
+
+\setuplabeltext [\s!en] [\v!subsubsection=]
+\setuplabeltext [\s!nl] [\v!subsubsection=]
+\setuplabeltext [\s!de] [\v!subsubsection=]
+\setuplabeltext [\s!da] [\v!subsubsection=]
+\setuplabeltext [\s!sv] [\v!subsubsection=]
+\setuplabeltext [\s!af] [\v!subsubsection=]
+\setuplabeltext [\s!nb] [\v!subsubsection=]
+\setuplabeltext [\s!nn] [\v!subsubsection=]
+
+\setuplabeltext [\s!en] [\v!subsubsubsection=]
+\setuplabeltext [\s!nl] [\v!subsubsubsection=]
+\setuplabeltext [\s!de] [\v!subsubsubsection=]
+\setuplabeltext [\s!da] [\v!subsubsubsection=]
+\setuplabeltext [\s!sv] [\v!subsubsubsection=]
+\setuplabeltext [\s!af] [\v!subsubsubsection=]
+\setuplabeltext [\s!nb] [\v!subsubsubsection=]
+\setuplabeltext [\s!nn] [\v!subsubsubsection=]
+
+\setuplabeltext [\s!en] [\v!appendix=] % Appendix
+\setuplabeltext [\s!nl] [\v!appendix=]
+\setuplabeltext [\s!de] [\v!appendix=] % Anhang
+\setuplabeltext [\s!da] [\v!appendix=] % Bilag
+\setuplabeltext [\s!sv] [\v!appendix=]
+\setuplabeltext [\s!af] [\v!appendix=] % Bylae
+\setuplabeltext [\s!nb] [\v!appendix=] % Tillegg
+\setuplabeltext [\s!nn] [\v!appendix=] % Tillegg
+
+\setuplabeltext [\s!en] [\v!part=Part ]
+\setuplabeltext [\s!nl] [\v!part=Deel ]
+\setuplabeltext [\s!de] [\v!part=Teil ]
+\setuplabeltext [\s!da] [\v!part=Del ]
+\setuplabeltext [\s!sv] [\v!part=Del ]
+\setuplabeltext [\s!af] [\v!part=Deel ]
+\setuplabeltext [\s!nb] [\v!part=Del]
+\setuplabeltext [\s!nn] [\v!part=Del]
+
+\setuplabeltext [\s!en] [\v!line=line ]
+\setuplabeltext [\s!nl] [\v!line=regel ]
+\setuplabeltext [\s!de] [\v!line=Zeile ]
+\setuplabeltext [\s!da] [\v!line=linie ] % or linje
+\setuplabeltext [\s!sv] [\v!line=rad ]
+\setuplabeltext [\s!af] [\v!line=re\ediaeresis l ]
+\setuplabeltext [\s!nb] [\v!line=linje ]
+\setuplabeltext [\s!nn] [\v!line=linje ]
+
+\setuplabeltext [\s!en] [\v!lines=lines ]
+\setuplabeltext [\s!nl] [\v!lines=regels ]
+\setuplabeltext [\s!de] [\v!lines=Zeilen ]
+\setuplabeltext [\s!da] [\v!lines=linier ] % or linjer
+\setuplabeltext [\s!sv] [\v!lines=rader ]
+\setuplabeltext [\s!af] [\v!lines=re\ediaeresis ls ]
+\setuplabeltext [\s!nb] [\v!lines=linjer ]
+\setuplabeltext [\s!nn] [\v!lines=linjer ]
+
+\setuplabeltext [\s!en] [\v!january=January]
+\setuplabeltext [\s!en] [\v!february=February]
+\setuplabeltext [\s!en] [\v!march=March]
+\setuplabeltext [\s!en] [\v!april=April]
+\setuplabeltext [\s!en] [\v!may=May]
+\setuplabeltext [\s!en] [\v!june=June]
+\setuplabeltext [\s!en] [\v!july=July]
+\setuplabeltext [\s!en] [\v!august=August]
+\setuplabeltext [\s!en] [\v!september=September]
+\setuplabeltext [\s!en] [\v!october=October]
+\setuplabeltext [\s!en] [\v!november=November]
+\setuplabeltext [\s!en] [\v!december=December]
+
+\setuplabeltext [\s!nl] [\v!january=januari]
+\setuplabeltext [\s!nl] [\v!february=februari]
+\setuplabeltext [\s!nl] [\v!march=maart]
+\setuplabeltext [\s!nl] [\v!april=april]
+\setuplabeltext [\s!nl] [\v!may=mei]
+\setuplabeltext [\s!nl] [\v!june=juni]
+\setuplabeltext [\s!nl] [\v!july=juli]
+\setuplabeltext [\s!nl] [\v!august=augustus]
+\setuplabeltext [\s!nl] [\v!september=september]
+\setuplabeltext [\s!nl] [\v!october=oktober]
+\setuplabeltext [\s!nl] [\v!november=november]
+\setuplabeltext [\s!nl] [\v!december=december]
+
+\setuplabeltext [\s!de] [\v!january=Januar]
+\setuplabeltext [\s!de] [\v!february=Februar]
+\setuplabeltext [\s!de] [\v!march=M\aumlaut rz]
+\setuplabeltext [\s!de] [\v!april=April]
+\setuplabeltext [\s!de] [\v!may=Mai]
+\setuplabeltext [\s!de] [\v!june=Juni]
+\setuplabeltext [\s!de] [\v!july=Juli]
+\setuplabeltext [\s!de] [\v!august=August]
+\setuplabeltext [\s!de] [\v!september=September]
+\setuplabeltext [\s!de] [\v!october=Oktober]
+\setuplabeltext [\s!de] [\v!november=November]
+\setuplabeltext [\s!de] [\v!december=Dezember]
+
+\setuplabeltext [\s!da] [\v!january=januar]
+\setuplabeltext [\s!da] [\v!february=februar]
+\setuplabeltext [\s!da] [\v!march=marts]
+\setuplabeltext [\s!da] [\v!april=april]
+\setuplabeltext [\s!da] [\v!may=maj]
+\setuplabeltext [\s!da] [\v!june=juni]
+\setuplabeltext [\s!da] [\v!july=juli]
+\setuplabeltext [\s!da] [\v!august=august]
+\setuplabeltext [\s!da] [\v!september=september]
+\setuplabeltext [\s!da] [\v!october=oktober]
+\setuplabeltext [\s!da] [\v!november=november]
+\setuplabeltext [\s!da] [\v!december=december]
+
+\setuplabeltext [\s!sv] [\v!january=januari]
+\setuplabeltext [\s!sv] [\v!february=februari]
+\setuplabeltext [\s!sv] [\v!march=mars]
+\setuplabeltext [\s!sv] [\v!april=april]
+\setuplabeltext [\s!sv] [\v!may=maj]
+\setuplabeltext [\s!sv] [\v!june=juni]
+\setuplabeltext [\s!sv] [\v!july=juli]
+\setuplabeltext [\s!sv] [\v!august=augusti]
+\setuplabeltext [\s!sv] [\v!september=september]
+\setuplabeltext [\s!sv] [\v!october=oktober]
+\setuplabeltext [\s!sv] [\v!november=november]
+\setuplabeltext [\s!sv] [\v!december=december]
+
+\setuplabeltext [\s!af] [\v!january=januarie]
+\setuplabeltext [\s!af] [\v!february=februarie]
+\setuplabeltext [\s!af] [\v!march=maart]
+\setuplabeltext [\s!af] [\v!april=april]
+\setuplabeltext [\s!af] [\v!may=mei]
+\setuplabeltext [\s!af] [\v!june=junie]
+\setuplabeltext [\s!af] [\v!july=julie]
+\setuplabeltext [\s!af] [\v!august=augustus]
+\setuplabeltext [\s!af] [\v!september=september]
+\setuplabeltext [\s!af] [\v!october=oktober]
+\setuplabeltext [\s!af] [\v!november=november]
+\setuplabeltext [\s!af] [\v!december=desember]
+
+\setuplabeltext [\s!nb] [\v!january=januar]
+\setuplabeltext [\s!nb] [\v!february=februar]
+\setuplabeltext [\s!nb] [\v!march=mars]
+\setuplabeltext [\s!nb] [\v!april=april]
+\setuplabeltext [\s!nb] [\v!may=mai]
+\setuplabeltext [\s!nb] [\v!june=juni]
+\setuplabeltext [\s!nb] [\v!july=juli]
+\setuplabeltext [\s!nb] [\v!august=august]
+\setuplabeltext [\s!nb] [\v!september=september]
+\setuplabeltext [\s!nb] [\v!october=oktober]
+\setuplabeltext [\s!nb] [\v!november=november]
+\setuplabeltext [\s!nb] [\v!december=desember]
+
+\setuplabeltext [\s!nn] [\v!january=januar]
+\setuplabeltext [\s!nn] [\v!february=februar]
+\setuplabeltext [\s!nn] [\v!march=mars]
+\setuplabeltext [\s!nn] [\v!april=april]
+\setuplabeltext [\s!nn] [\v!may=mai]
+\setuplabeltext [\s!nn] [\v!june=juni]
+\setuplabeltext [\s!nn] [\v!july=juli]
+\setuplabeltext [\s!nn] [\v!august=august]
+\setuplabeltext [\s!nn] [\v!september=september]
+\setuplabeltext [\s!nn] [\v!october=oktober]
+\setuplabeltext [\s!nn] [\v!november=november]
+\setuplabeltext [\s!nn] [\v!december=desember]
+
+\setuplabeltext [\s!en] [\v!sunday=Sunday]
+\setuplabeltext [\s!en] [\v!monday=Monday]
+\setuplabeltext [\s!en] [\v!tuesday=Tuesday]
+\setuplabeltext [\s!en] [\v!wednesday=Wednesday]
+\setuplabeltext [\s!en] [\v!thursday=Thursday]
+\setuplabeltext [\s!en] [\v!friday=Friday]
+\setuplabeltext [\s!en] [\v!saturday=Saturday]
+
+\setuplabeltext [\s!nl] [\v!sunday=zondag]
+\setuplabeltext [\s!nl] [\v!monday=maandag]
+\setuplabeltext [\s!nl] [\v!tuesday=dinsdag]
+\setuplabeltext [\s!nl] [\v!wednesday=woensdag]
+\setuplabeltext [\s!nl] [\v!thursday=donderdag]
+\setuplabeltext [\s!nl] [\v!friday=vrijdag]
+\setuplabeltext [\s!nl] [\v!saturday=zaterdag]
+
+\setuplabeltext [\s!de] [\v!sunday=Sonntag]
+\setuplabeltext [\s!de] [\v!monday=Montag]
+\setuplabeltext [\s!de] [\v!tuesday=Dienstag]
+\setuplabeltext [\s!de] [\v!wednesday=Mittwoch]
+\setuplabeltext [\s!de] [\v!thursday=Donnerstag]
+\setuplabeltext [\s!de] [\v!friday=Freitag]
+\setuplabeltext [\s!de] [\v!saturday=Samstag]
+
+\setuplabeltext [\s!da] [\v!sunday=s\ostroke ndag]
+\setuplabeltext [\s!da] [\v!monday=mandag]
+\setuplabeltext [\s!da] [\v!tuesday=tirsdag]
+\setuplabeltext [\s!da] [\v!wednesday=onsdag]
+\setuplabeltext [\s!da] [\v!thursday=torsdag]
+\setuplabeltext [\s!da] [\v!friday=fredag]
+\setuplabeltext [\s!da] [\v!saturday=l\ostroke rdag]
+
+\setuplabeltext [\s!sv] [\v!sunday=s\oumlaut ndag]
+\setuplabeltext [\s!sv] [\v!monday=m\aring ndag]
+\setuplabeltext [\s!sv] [\v!tuesday=tisdag]
+\setuplabeltext [\s!sv] [\v!wednesday=onsdag]
+\setuplabeltext [\s!sv] [\v!thursday=torsdag]
+\setuplabeltext [\s!sv] [\v!friday=fredag]
+\setuplabeltext [\s!sv] [\v!saturday=l\oumlaut rdag]
+
+\setuplabeltext [\s!af] [\v!sunday=sondag]
+\setuplabeltext [\s!af] [\v!monday=maandag]
+\setuplabeltext [\s!af] [\v!tuesday=dinsdag]
+\setuplabeltext [\s!af] [\v!wednesday=woensdag]
+\setuplabeltext [\s!af] [\v!thursday=donderdag]
+\setuplabeltext [\s!af] [\v!friday=vrydag]
+\setuplabeltext [\s!af] [\v!saturday=saterdag]
+
+\setuplabeltext [\s!nb] [\v!sunday=s\ostroke ndag]
+\setuplabeltext [\s!nb] [\v!monday=mandag]
+\setuplabeltext [\s!nb] [\v!tuesday=tirsdag]
+\setuplabeltext [\s!nb] [\v!wednesday=onsdag]
+\setuplabeltext [\s!nb] [\v!thursday=torsdag]
+\setuplabeltext [\s!nb] [\v!friday=fredag]
+\setuplabeltext [\s!nb] [\v!saturday=l\ostroke rdag]
+
+\setuplabeltext [\s!nn] [\v!sunday=sundag]
+\setuplabeltext [\s!nn] [\v!monday=m\aring ndag]
+\setuplabeltext [\s!nn] [\v!tuesday=tysdag]
+\setuplabeltext [\s!nn] [\v!wednesday=onsdag]
+\setuplabeltext [\s!nn] [\v!thursday=torsdag]
+\setuplabeltext [\s!nn] [\v!friday=fredag]
+\setuplabeltext [\s!nn] [\v!saturday=laurdag]
+
+%D Rather new ...
+
+\setuplabeltext [\s!nl] [\v!page=pagina ]
+\setuplabeltext [\s!nl] [\v!atpage=op pagina ]
+\setuplabeltext [\s!nl] [\v!hencefore=hierboven]
+\setuplabeltext [\s!nl] [\v!hereafter=hieronder]
+\setuplabeltext [\s!nl] [\v!see=zie ]
+
+\setuplabeltext [\s!en] [\v!page=page ]
+\setuplabeltext [\s!en] [\v!atpage=at page ]
+\setuplabeltext [\s!en] [\v!hencefore=as we show above]
+\setuplabeltext [\s!en] [\v!hereafter=as we show below]
+\setuplabeltext [\s!en] [\v!see=see ]
+
+\setuplabeltext [\s!de] [\v!page=Seite ]
+\setuplabeltext [\s!de] [\v!atpage=auf Seite ]
+\setuplabeltext [\s!de] [\v!hencefore=siehe oben]
+\setuplabeltext [\s!de] [\v!hereafter=siehe unten]
+\setuplabeltext [\s!de] [\v!see=siehe ]
+
+\setuplabeltext [\s!da] [\v!page=Side ]
+\setuplabeltext [\s!da] [\v!atpage=p\aring\ side ]
+\setuplabeltext [\s!da] [\v!hencefore=se foroven]
+\setuplabeltext [\s!da] [\v!hereafter=se forneden]
+\setuplabeltext [\s!da] [\v!see=se ]
+
+\setuplabeltext [\s!sv] [\v!page=Sida ]
+\setuplabeltext [\s!sv] [\v!atpage=p\aring\ sida ]
+\setuplabeltext [\s!sv] [\v!hencefore=se ovan]
+\setuplabeltext [\s!sv] [\v!hereafter=se nedan]
+\setuplabeltext [\s!sv] [\v!see=se ]
+
+\setuplabeltext [\s!nb] [\v!page=side ]
+\setuplabeltext [\s!nb] [\v!atpage=p\aring\ side ]
+\setuplabeltext [\s!nb] [\v!hencefore=som vist over]
+\setuplabeltext [\s!nb] [\v!hereafter=som vist under]
+\setuplabeltext [\s!nb] [\v!see=se ]
+
+\setuplabeltext [\s!nn] [\v!page=side ]
+\setuplabeltext [\s!nn] [\v!atpage=p\aring\ side ]
+\setuplabeltext [\s!nn] [\v!hencefore=som vist over]
+\setuplabeltext [\s!nn] [\v!hereafter=som vist under]
+\setuplabeltext [\s!nn] [\v!see=sj\aring\ ]
+
+%D ... and to be completed!
+
+%D Next we implement couple of ordinal mumber converters:
+
+\def\enordinaldaynumber#1%
+ {#1\ifnum\lasttwodigits{#1}=11
+ \highordinalstr{th}%
+ \else\ifnum\lasttwodigits{#1}=12
+ \highordinalstr{th}%
+ \else\ifnum\lasttwodigits{#1}=13
+ \highordinalstr{th}%
+ \else\ifcase\lastdigit{#1}%
+ \highordinalstr{th}%
+ \or % 1
+ \highordinalstr{st}%
+ \or % 2
+ \highordinalstr{nd}%
+ \or % 3
+ \highordinalstr{rd}%
+ \else
+ \highordinalstr{th}%
+ \fi\fi\fi\fi}
+
+% \def\enordinaldaynumber#1%
+% {#1\ordinalstr{\ifnum\lasttwodigits{#1}=11 th\else\ifcase\lastdigit{#1}
+% th\or st\or nd\or rd\else th\fi\fi}}
+
+\def\nlordinaldaynumber#1%
+ {#1\highordinalstr{e}}
+
+%D \ShowAllLanguageValues [\s!en] [english] {English} {horn} % engelse humor
+%D \ShowAllLanguageValues [\s!nl] [dutch] {Dutch} {treat} % nederlandse zuinigheid
+%D \ShowAllLanguageValues [\s!de] [german] {German} {beer} % duitse degelijkheid
+%D \ShowAllLanguageValues [\s!da] [danish] {Danish} {pastry}
+%D \ShowAllLanguageValues [\s!sv] [swedish] {Swedish} {design}
+%D \ShowAllLanguageValues [\s!af] [afrikaans] {Afrikaaner} {boer} % afrikaanse gasvryheid
+%D \ShowAllLanguageValues [\s!nb] [bokmal] {Norwegian} {wood}
+%D \ShowAllLanguageValues [\s!nn] [nynorsk] {Norwegian} {fish}
+
+%D Extra month names:
+
+\setuplabeltext [\s!en] [\v!january :\s!mnem=jan]
+\setuplabeltext [\s!en] [\v!february :\s!mnem=feb]
+\setuplabeltext [\s!en] [\v!march :\s!mnem=mar]
+\setuplabeltext [\s!en] [\v!april :\s!mnem=apr]
+\setuplabeltext [\s!en] [\v!may :\s!mnem=may]
+\setuplabeltext [\s!en] [\v!june :\s!mnem=jun]
+\setuplabeltext [\s!en] [\v!july :\s!mnem=jul]
+\setuplabeltext [\s!en] [\v!august :\s!mnem=aug]
+\setuplabeltext [\s!en] [\v!september:\s!mnem=sep]
+\setuplabeltext [\s!en] [\v!october :\s!mnem=oct]
+\setuplabeltext [\s!en] [\v!november :\s!mnem=nov]
+\setuplabeltext [\s!en] [\v!december :\s!mnem=dec]
+
+\setuplabeltext [\s!nb] [\v!january :\s!mnem=jan.]
+\setuplabeltext [\s!nb] [\v!february :\s!mnem=feb.]
+\setuplabeltext [\s!nb] [\v!march :\s!mnem=mars]
+\setuplabeltext [\s!nb] [\v!april :\s!mnem=april]
+\setuplabeltext [\s!nb] [\v!may :\s!mnem=mai]
+\setuplabeltext [\s!nb] [\v!june :\s!mnem=juni]
+\setuplabeltext [\s!nb] [\v!july :\s!mnem=juli]
+\setuplabeltext [\s!nb] [\v!august :\s!mnem=aug.]
+\setuplabeltext [\s!nb] [\v!september:\s!mnem=sep.]
+\setuplabeltext [\s!nb] [\v!october :\s!mnem=okt.]
+\setuplabeltext [\s!nb] [\v!november :\s!mnem=nov.]
+\setuplabeltext [\s!nb] [\v!december :\s!mnem=des.]
+
+\setuplabeltext [\s!nn] [\v!january :\s!mnem=jan.]
+\setuplabeltext [\s!nn] [\v!february :\s!mnem=feb.]
+\setuplabeltext [\s!nn] [\v!march :\s!mnem=mars]
+\setuplabeltext [\s!nn] [\v!april :\s!mnem=april]
+\setuplabeltext [\s!nn] [\v!may :\s!mnem=mai]
+\setuplabeltext [\s!nn] [\v!june :\s!mnem=juni]
+\setuplabeltext [\s!nn] [\v!july :\s!mnem=juli]
+\setuplabeltext [\s!nn] [\v!august :\s!mnem=aug.]
+\setuplabeltext [\s!nn] [\v!september:\s!mnem=sep.]
+\setuplabeltext [\s!nn] [\v!october :\s!mnem=okt.]
+\setuplabeltext [\s!nn] [\v!november :\s!mnem=nov.]
+\setuplabeltext [\s!nn] [\v!december :\s!mnem=des.]
+
+\protect \endinput
diff --git a/tex/context/base/lang-grk.tex b/tex/context/base/lang-grk.tex
new file mode 100644
index 000000000..e4ba781eb
--- /dev/null
+++ b/tex/context/base/lang-grk.tex
@@ -0,0 +1,94 @@
+%D \module
+%D [ file=lang-grk,
+%D version=2003.04.01,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Uralic Languages,
+%D author=Apostolos Syropoulos
+%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 Language Macros / Greek}
+
+%D The framework of this module is set up by Hans Hagen while
+%D all the translations have been done by Apostolos Syropoulos
+
+\unprotect
+
+\installlanguage
+ [\s!gr]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\greekleftquot,
+ \c!rightquote=\greekrightquot,
+ \c!leftquotation=\greekleftquot,
+ \c!rightquotation=\greekrightquot,
+ \c!date={\v!day\ \v!month\ \v!year}]
+
+\installlanguage [greek] [\s!gr]
+
+\setupheadtext [\s!gr] [\v!content=\greekPi\greekepsilon\greekrho\greekiota\greekepsilon\greekchi\greekomicrontonos\greekmu\greekepsilon\greeknu\greekalpha]
+\setupheadtext [\s!gr] [\v!tables=\greekPi\greekiotatonos\greeknu\greekalpha\greekkappa\greekepsilon\greekfinalsigma]
+\setupheadtext [\s!gr] [\v!figures=\greekSigma\greekchi\greeketatonos\greekmu\greekalpha\greektau\greekalpha]
+\setupheadtext [\s!gr] [\v!graphics=\greekGamma\greekrho\greekalpha\greekphi\greekiota\greekkappa\greekalphatonos]
+\setupheadtext [\s!gr] [\v!intermezzi=\greekPi\greekalpha\greekupsilontonos\greeksigma\greekepsilon\greekiota\greekfinalsigma]
+\setupheadtext [\s!gr] [\v!index=\greekEpsilon\greekupsilon\greekrho\greekepsilon\greektau\greeketatonos\greekrho\greekiota\greekomicron]
+\setupheadtext [\s!gr] [\v!abbreviations=\greekSigma\greekupsilon\greeknu\greektau\greekomicron\greekmu\greekomicron\greekgamma\greekrho\greekalpha\greekphi\greekiotatonos\greekepsilon\greekfinalsigma]
+\setupheadtext [\s!gr] [\v!logos=\greekLambda\greekomicron\greekgamma\greekomicrontonos\greektau\greekupsilon\greekpi\greekalpha]
+\setupheadtext [\s!gr] [\v!units=\greekMu\greekomicron\greeknu\greekalphatonos\greekdelta\greekepsilon\greekfinalsigma]
+
+\setuplabeltext [\s!gr] [\v!table=\greekPi\greekiotatonos\greeknu\greekalpha\greekkappa\greekalpha\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!figure=\greekSigma\greekchi\greeketatonos\greekmu\greekalpha]
+\setuplabeltext [\s!gr] [\v!intermezzo=\greekPi\greekalpha\greekupsilontonos\greeksigma\greeketa]
+\setuplabeltext [\s!gr] [\v!graphic=\greekGamma\greekrho\greekalpha\greekphi\greekiota\greekkappa\greekomicrontonos]
+
+\setuplabeltext [\s!gr] [\v!chapter=\greekKappa\greekepsilon\greekphi\greekalphatonos\greeklambda\greekalpha\greekiota\greekomicron]
+\setuplabeltext [\s!gr] [\v!section=\greekEpsilon\greeknu\greekomicrontonos\greektau\greeketa\greektau\greekalpha]
+\setuplabeltext [\s!gr] [\v!subsection=\greekUpsilon\greekpi\greekomicrontonos\greekepsilon\greeknu\greekomicrontonos\greektau\greeketa\greektau\greekalpha]
+\setuplabeltext [\s!gr] [\v!subsubsection=]
+\setuplabeltext [\s!gr] [\v!subsubsubsection=]
+
+\setuplabeltext [\s!gr] [\v!appendix=\greekPi\greekalpha\greekrho\greekalphatonos\greekrho\greektau\greeketa\greekmu\greekalpha]
+\setuplabeltext [\s!gr] [\v!part=\greekMu\greekepsilontonos\greekrho\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!line=\greekGamma\greekrho\greekalpha\greekmu\greekmu\greeketatonos]
+\setuplabeltext [\s!gr] [\v!lines=\greekGamma\greekrho\greekalpha\greekmu\greekmu\greekepsilontonos\greekfinalsigma]
+
+\setuplabeltext [\s!gr] [\v!january=\greekIota\greekalpha\greeknu\greekomicron\greekupsilon\greekalphatonos\greekrho\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!february=\greekPhi\greekepsilon\greekbeta\greekrho\greekomicron\greekupsilon\greekalphatonos\greekrho\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!march=\greekMu\greekalphatonos\greekrho\greektau\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!april=\greekAlpha\greekpi\greekrho\greekiotatonos\greeklambda\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!may=\greekMu\greekalphatonos\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!june=\greekIota\greekomicron\greekupsilontonos\greeknu\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!july=\greekIota\greekomicron\greekupsilontonos\greeklambda\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!august=\greekAlpha\greekupsilontonos\greekgamma\greekomicron\greekupsilon\greeksigma\greektau\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!september=\greekSigma\greekepsilon\greekpi\greektau\greekepsilontonos\greekmu\greekbeta\greekrho\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!october=\greekOmicron\greekkappa\greektau\greekomegatonos\greekbeta\greekrho\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!november=\greekNu\greekomicron\greekepsilontonos\greekmu\greekbeta\greekrho\greekiota\greekomicron\greekfinalsigma]
+\setuplabeltext [\s!gr] [\v!december=\greekDelta\greekepsilon\greekkappa\greekepsilontonos\greekmu\greekbeta\greekrho\greekiota\greekomicron\greekfinalsigma]
+
+\setuplabeltext [\s!gr] [\v!sunday=\greekKappa\greekupsilon\greekrho\greekiota\greekalpha\greekkappa\greeketatonos]
+\setuplabeltext [\s!gr] [\v!monday=\greekDelta\greekepsilon\greekupsilon\greektau\greekepsilontonos\greekrho\greekalpha]
+\setuplabeltext [\s!gr] [\v!tuesday=\greekTau\greekrho\greekiotatonos\greektau\greeketa]
+\setuplabeltext [\s!gr] [\v!wednesday=\greekTau\greekepsilon\greektau\greekalphatonos\greekrho\greektau\greeketa]
+\setuplabeltext [\s!gr] [\v!thursday=\greekPi\greekepsilontonos\greekmu\greekpi\greektau\greeketa]
+\setuplabeltext [\s!gr] [\v!friday=\greekPi\greekalpha\greekrho\greekalpha\greeksigma\greekkappa\greekepsilon\greekupsilon\greeketatonos]
+\setuplabeltext [\s!gr] [\v!saturday=\greekSigma\greekalphatonos\greekbeta\greekbeta\greekalpha\greektau\greekomicron]
+
+%D % \ShowAllLanguageValues [\s!gr] [\greekEpsilon\greeklambda\greeklambda\greeketa\greeknu\greekiota\greekkappa\greekalphatonos] {Greek} {love}
+
+\installlanguage
+ [\s!agr]
+ [\s!default=\s!gr,
+ \s!patterns=\s!agr,
+ \s!mapping=\s!agr,
+ \s!encoding=\s!agr]
+
+\installlanguage [ancientgreek] [\s!agr]
+
+\protect \endinput
diff --git a/tex/context/base/lang-ind.tex b/tex/context/base/lang-ind.tex
new file mode 100644
index 000000000..9b6e5ff1d
--- /dev/null
+++ b/tex/context/base/lang-ind.tex
@@ -0,0 +1,26 @@
+%D \module
+%D [ file=lang--ind,
+%D version=1997.09.03,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Indo Iranian Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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 Language Macros / Indo-Iranian Languages}
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+
+% 34 languages
+
+\unprotect
+
+\protect \endinput
diff --git a/tex/context/base/lang-ini.lua b/tex/context/base/lang-ini.lua
new file mode 100644
index 000000000..239e5390c
--- /dev/null
+++ b/tex/context/base/lang-ini.lua
@@ -0,0 +1,321 @@
+if not modules then modules = { } end modules ['lang-ini'] = {
+ version = 1.001,
+ comment = "companion to lang-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- needs a cleanup (share locals)
+
+local utf = unicode.utf8
+local utfbyte = utf.byte
+local format = string.format
+local concat = table.concat
+local lpegmatch = lpeg.match
+
+local trace_patterns = false trackers.register("languages.patterns", function(v) trace_patterns = v end)
+
+languages = languages or {}
+languages.version = 1.009
+languages.hyphenation = languages.hyphenation or { }
+languages.hyphenation.data = languages.hyphenation.data or { }
+
+local langdata = languages.hyphenation.data
+
+-- 002D : hyphen-minus (ascii)
+-- 2010 : hyphen
+-- 2011 : nonbreakable hyphen
+-- 2013 : endash (compound hyphen)
+
+--~ lang:hyphenation(string)
+--~ string =lang:hyphenation()
+--~ lang:clear_hyphenation()
+
+-- we can consider hiding data (faster access too)
+
+-- loading the 26 languages that we normally load in mkiv, the string based variant
+-- takes .84 seconds (probably due to the sub's) while the lpeg variant takes .78
+-- seconds
+--
+-- the following lpeg can probably be improved (it was one of the first I made)
+
+local leftbrace = lpeg.P("{")
+local rightbrace = lpeg.P("}")
+local spaces = lpeg.S(" \r\n\t\f")
+local spacing = spaces^0
+local validchar = 1-(spaces+rightbrace+leftbrace)
+local validword = validchar^1
+local content = spacing * leftbrace * spacing * lpeg.C((spacing * validword)^0) * spacing * rightbrace * lpeg.P(true)
+
+local command = lpeg.P("\\patterns")
+local parser = (1-command)^0 * command * content
+
+local function filterpatterns(filename)
+ if file.extname(filename) == "rpl" then
+ return io.loaddata(resolvers.find_file(filename)) or ""
+ else
+ return lpegmatch(parser,io.loaddata(resolvers.find_file(filename)) or "")
+ end
+end
+
+local command = lpeg.P("\\hyphenation")
+local parser = (1-command)^0 * command * content
+
+local function filterexceptions(filename)
+ if file.extname(filename) == "rhl" then
+ return io.loaddata(resolvers.find_file(filename)) or ""
+ else
+ return lpegmatch(parser,io.loaddata(resolvers.find_file(filename)) or {}) -- "" ?
+ end
+end
+
+local function record(tag)
+ local data = langdata[tag]
+ if not data then
+ data = lang.new()
+ langdata[tag] = data or 0
+ end
+ return data
+end
+
+languages.hyphenation.record = record
+
+function languages.hyphenation.define(tag)
+ local data = record(tag)
+ return data:id()
+end
+
+function languages.hyphenation.number(tag)
+ local d = langdata[tag]
+ return (d and d:id()) or 0
+end
+
+lang.exceptions = lang.hyphenation
+
+local function loadthem(tag, filename, filter, target)
+ statistics.starttiming(languages)
+ local data = record(tag)
+ local fullname = (filename and filename ~= "" and resolvers.find_file(filename)) or ""
+ local ok = fullname ~= ""
+ if ok then
+ if trace_patterns then
+ logs.report("languages","filtering %s for language '%s' from '%s'",target,tag,fullname)
+ end
+ lang[target](data,filterpatterns(fullname))
+ else
+ if trace_patterns then
+ logs.report("languages","no %s for language '%s' in '%s'",target,tag,filename or "?")
+ end
+ lang[target](data,"")
+ end
+ langdata[tag] = data
+ statistics.stoptiming(languages)
+ return ok
+end
+
+function languages.hyphenation.loadpatterns(tag, patterns)
+ return loadthem(tag, patterns, filterpatterns, "patterns")
+end
+
+function languages.hyphenation.loadexceptions(tag, exceptions)
+ return loadthem(tag, patterns, filterexceptions, "exceptions")
+end
+
+function languages.hyphenation.exceptions(tag, ...)
+ local data = record(tag)
+ data:hyphenation(...)
+end
+
+function languages.hyphenation.hyphenate(tag, str)
+ return lang.hyphenate(record(tag), str)
+end
+
+function languages.hyphenation.lefthyphenmin(tag, value)
+ local data = record(tag)
+ if value then data:lefthyphenmin(value) end
+ return data:lefthyphenmin()
+end
+function languages.hyphenation.righthyphenmin(tag, value)
+ local data = record(tag)
+ if value then data:righthyphenmin(value) end
+ return data:righthyphenmin()
+end
+
+function languages.hyphenation.n()
+ return table.count(langdata)
+end
+
+languages.registered = languages.registered or { }
+languages.associated = languages.associated or { }
+languages.numbers = languages.numbers or { }
+
+storage.register("languages/registered",languages.registered,"languages.registered")
+storage.register("languages/associated",languages.associated,"languages.associated")
+
+local numbers = languages.numbers
+local registered = languages.registered
+local associated = languages.associated
+
+-- we can speed this one up with locals if needed
+
+local function tolang(what)
+ local kind = type(what)
+ if kind == "number" then
+ local w = what >= 0 and what <= 0x7FFF and numbers[what]
+ return (w and langdata[w]) or 0
+ elseif kind == "string" then
+ return langdata[what]
+ else
+ return what
+ end
+end
+
+function languages.setup(what,settings)
+ what = languages.tolang(what or tex.language)
+ local lefthyphen = settings.lefthyphen
+ local righthyphen = settings.righthyphen
+ lefthyphen = lefthyphen ~= "" and lefthyphen or nil
+ righthyphen = righthyphen ~= "" and righthyphen or nil
+ lefthyphen = lefthyphen and utfbyte(lefthyphen) or 0
+ righthyphen = righthyphen and utfbyte(righthyphen) or 0
+ lang.posthyphenchar(what,lefthyphen)
+ lang.prehyphenchar (what,righthyphen)
+ lang.postexhyphenchar(what,lefthyphen)
+ lang.preexhyphenchar (what,righthyphen)
+end
+
+function languages.prehyphenchar(what)
+ return lang.prehyphenchar(tolang(what))
+end
+function languages.posthyphenchar(what)
+ return lang.posthyphenchar(tolang(what))
+end
+
+languages.tolang = tolang
+
+function languages.register(tag,parent,patterns,exceptions)
+ parent = parent or tag
+ registered[tag] = {
+ parent = parent,
+ patterns = patterns or format("lang-%s.pat",parent),
+ exceptions = exceptions or format("lang-%s.hyp",parent),
+ loaded = false,
+ number = 0,
+ }
+end
+
+function languages.associate(tag,script,language)
+ associated[tag] = { script, language }
+end
+
+function languages.association(tag)
+ if type(tag) == "number" then
+ tag = numbers[tag]
+ end
+ local lat = tag and associated[tag]
+ if lat then
+ return lat[1], lat[2]
+ else
+ return nil, nil
+ end
+end
+
+function languages.loadable(tag)
+ local l = registered[tag]
+ if l and l.patterns and resolvers.find_file(patterns) then
+ return true
+ else
+ return false
+ end
+end
+
+languages.share = false -- we don't share language numbers
+
+function languages.enable(tags)
+ -- beware: we cannot set tex.language, but need tex.normallanguage
+ for i=1,#tags do
+ local tag = tags[i]
+ local l = registered[tag]
+ if l and l ~= "" then
+ if not l.loaded then
+ local tag = l.parent
+ local number = languages.hyphenation.number(tag)
+ if languages.share and number > 0 then
+ l.number = number
+ else
+ -- we assume the same filenames
+ l.number = languages.hyphenation.define(tag)
+ languages.hyphenation.loadpatterns(tag,l.patterns)
+ languages.hyphenation.loadexceptions(tag,l.exceptions)
+ numbers[l.number] = tag
+ end
+ l.loaded = true
+ if trace_patterns then
+ logs.report("languages","assigning number %s",l.number)
+ end
+ end
+ if l.number > 0 then
+ return l.number
+ end
+ end
+ end
+ return 0
+end
+
+-- e['implementer']= 'imple{m}{-}{-}menter'
+-- e['manual'] = 'man{}{}{}'
+-- e['as'] = 'a-s'
+-- e['user-friendly'] = 'user=friend-ly'
+-- e['exceptionally-friendly'] = 'excep-tionally=friend-ly'
+
+function languages.hyphenation.loadwords(tag, filename)
+ local id = languages.hyphenation.number(tag)
+ if id > 0 then
+ local l = lang.new(id) or 0
+ statistics.starttiming(languages)
+ local data = io.loaddata(filename) or ""
+ l:hyphenation(data)
+ statistics.stoptiming(languages)
+ end
+end
+
+languages.hyphenation.define ("zerolanguage")
+languages.hyphenation.loadpatterns ("zerolanguage") -- else bug
+languages.hyphenation.loadexceptions("zerolanguage") -- else bug
+
+languages.logger = languages.logger or { }
+
+function languages.logger.report()
+ local result = { }
+ local sorted = table.sortedkeys(registered)
+ for i=1,#sorted do
+ local tag = sorted[i]
+ local l = registered[tag]
+ if l.loaded then
+ local p = (l.patterns and "pat") or '-'
+ local e = (l.exceptions and "exc") or '-'
+ result[#result+1] = format("%s:%s:%s:%s:%s", tag, l.parent, p, e, l.number)
+ end
+ end
+ return (#result > 0 and concat(result," ")) or "none"
+end
+
+-- must happen at the tex end
+
+languages.associate('en','latn','eng')
+languages.associate('uk','latn','eng')
+languages.associate('nl','latn','nld')
+languages.associate('de','latn','deu')
+languages.associate('fr','latn','fra')
+
+statistics.register("loaded patterns", function()
+ local result = languages.logger.report()
+ if result ~= "none" then
+ return result
+ end
+end)
+
+statistics.register("language load time", function()
+ return statistics.elapsedseconds(languages, format(", n=%s",languages.hyphenation.n()))
+end)
diff --git a/tex/context/base/lang-ini.mkii b/tex/context/base/lang-ini.mkii
new file mode 100644
index 000000000..91ac59847
--- /dev/null
+++ b/tex/context/base/lang-ini.mkii
@@ -0,0 +1,696 @@
+%D \module
+%D [ file=lang-ini,
+%D version=1996.01.25,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Initialization,
+%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.
+
+%D This module needs a further cleanup (real split between ii/iv).
+
+%D This module implements the (for the moment still simple)
+%D multi||language support of \CONTEXT, which should not be
+%D confused with the multi||lingual interface. This support
+%D will be extended when needed.
+
+\writestatus{loading}{ConTeXt Language Macros / Initialization}
+
+\unprotect
+
+\ifx\nonfrenchspacing\undefined \let\nonfrenchspacing\relax \fi
+\ifx\frenchspacing \undefined \let\frenchspacing \relax \fi
+
+%D When loading hyphenation patterns, \TEX\ assign a number to
+%D each loaded table, starting with~0. Switching to a specific
+%D table is done by assigning the relevant number to the
+%D predefined \COUNTER\ \type{\language}.
+
+%D We keep track of the last loaded patterns by means of a
+%D pseudo \COUNTER. This just one of those situations in which
+%D we don't want to spent a real one. Language zero has no
+%D patterns, first of all because I like to start numbering
+%D at one. It may come in handy for special purposes as well.
+
+\normallanguage\zerocount \def\loadedlanguage{1}
+
+%D \macros
+%D {currentlanguage, setupcurrentlanguage}
+%D
+%D Instead of numbers,we are going to use symbolic names for
+%D the languages. The current langage is saved in the macro
+%D \type {\currentlanguage}. The setup macro is mainly used
+%D for cosmetic purposes.
+%D
+%D \starttyping
+%D \dorecurse{3}
+%D {\language[nl]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode
+%D \language[en]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode}
+%D \stoptyping
+
+\let\currentlanguage \empty
+\let\currentmainlanguage\empty
+
+\def\setupcurrentlanguage[#1]{\setcurrentlanguage\currentmainlanguage{#1}}
+
+\def\setcurrentlanguage#1#2% sets modes: **id (currentmain) *id (current)
+ {\doifsomething{#1}
+ {\ifx\currentmainlanguage\empty\else\resetsystemmode{\systemmodeprefix\currentmainlanguage}\fi
+ \edef\currentmainlanguage{#1}%
+ \setsystemmode{\systemmodeprefix\currentmainlanguage}}%
+ \doifsomething{#2}
+ {\ifx\currentlanguage\empty\else\resetsystemmode\currentlanguage\fi
+ \edef\currentlanguage{#2}%
+ \setsystemmode\currentlanguage}}
+
+%D The internal macros will be defined later.
+
+%D \macros
+%D {installlanguage}
+%D
+%D Hyphenation patterns can only be loaded when the format file
+%D is prepared. The next macro takes care of this loading. A
+%D language is specified with
+%D
+%D \showsetup{installlanguage}
+%D
+%D When \type {state} equals \type {start}, both patterns
+%D and additional hyphenation specifications are loaded. These
+%D files are seached for on the system path and are to be
+%D named:
+%D
+%D \starttyping
+%D \f!languageprefix-identifier.\f!patternsextension
+%D \f!languageprefix-identifier.\f!hyhensextension
+%D \stoptyping
+%D
+%D The \type{spacing} variable specifies how the spaces after
+%D punctuation has to be handled. English is by tradition more
+%D tolerant to inter||sentence spacing than other languages.
+%D
+%D This macro also defines \type {\identifier} as a shortcut
+%D switch to the language. Furthermore the command defined as
+%D being language specific, are executed. With
+%D \type {default} we can default to another language
+%D (patterns) at format generation time. This default language
+%D is overruled when the appropriate patterns are loaded (some
+%D implementations support run time addition of patterns to a
+%D preloaded format).
+
+\def\dodoinstalllanguage#1#2% #2 added
+ {\doifundefined{#1}{\setvalue{#1}{\complexlanguage[#2]}}%
+ \expanded{\noexpand\uppercase{\noexpand\edef\noexpand\ascii{#1}}}%
+ \doifundefined\ascii{\setvalue\ascii{\complexlanguage[#2]}}}
+
+%D \macros
+%D {preloadlanguages}
+%D
+%D We first try to load the files defined as file synonym
+%D for \type {lang-*.pat} and \type {lang-*.hyp}. After that we
+%D fall back on those files. The macro \type {\preloadpatterns}
+%D reports which patterns are loaded and what hyphenmin
+%D values are set.
+
+\let\installedlanguages\empty
+
+\def\doiflanguageelse#1{\doifdefinedelse{\??la#1\c!state}}
+
+\def\doloadlanguagefiles#1%
+ {\doifelsevalue{\??la#1\c!state}\v!start
+ {\edef\languagesuffix{\specificlanguageparameter{#1}\s!patterns}%
+ \ifx\languagesuffix\empty
+ \edef\languagesuffix{\defaultlanguage{#1}}%
+ \else\ifx\languagesuffix\relax
+ \edef\languagesuffix{\defaultlanguage{#1}}%
+ \fi\fi
+ \ifx\languagesuffix\empty
+ \edef\languagesuffix{#1}%
+ \fi
+ \doifundefinedelse{\??la\??la:\currentencoding:\currentmapping:\languagesuffix}
+ {\doloadpatterns{#1}\languagesuffix}
+ {\bgroup
+ \edef\loadedlanguage{\getvalue{\??la\??la:\currentencoding:\currentmapping:\languagesuffix}}%
+ %\showmessage\m!linguals1{\languagesuffix,#1,\loadedlanguage,*,*}%
+ %\showmessage\m!linguals3{\languagesuffix,#1,\loadedlanguage,*,*}%
+ \egroup}}
+ {\showmessage\m!linguals5{#1}}}
+
+\def\doinstalllanguage[#1][#2]%
+ {\doifassignmentelse{#2}
+ {\doiflanguageelse{#1}
+ {\getparameters[\??la#1][#2]}
+ {\setvalue{\l!prefix!#1}{#1}%
+ \addtocommalist{#1}\installedlanguages
+ \dodoinstalllanguage{#1}{#1}%
+ \getparameters[\??la#1][\c!state=\v!start,#2]}%
+ \doloadlanguagefiles{#1}}
+ {\setvalue{\l!prefix!#1}{#2}%
+ \getparameters[\??la#1][\s!default=#2]%
+ \dodoinstalllanguage{#1}{#2}}}
+
+\def\reallanguagetag#1%
+ {\ifcsname\l!prefix!#1\endcsname\csname\l!prefix!#1\endcsname\else#1\fi}
+
+\let\preloadedpatterns\empty
+\let\preloadedpmessage\empty
+
+\def\doshowpatterns#1#2#3#4% language number encoding mapping
+ {#1->#3:#4->#2->\specificlanguageparameter{#1}\s!lefthyphenmin:\specificlanguageparameter{#1}\s!righthyphenmin\space}
+
+\def\preloadlanguages
+ {\doifsomething\preloadedpmessage{\showmessage\m!linguals{10}\preloadedpmessage}}
+
+\def\preloadallpatterns
+ {\gdef\preloadallpatterns##1{\installlanguage[##1][\c!state=\v!start]}%
+ \processcommacommand[\installedlanguages]\preloadallpatterns
+ \global\let\preloadallpatterns\relax}
+
+% ^^ \language[#1] gave unwanted side effect of loading language specifics
+
+\def\installlanguage
+ {\dodoubleargument\doinstalllanguage}
+
+%D When the second argument is a language identifier, a
+%D synonym is created. This feature is present because we
+%D used dutch mnemonics in the dutch version, but nowadays
+%D conform a standard.
+
+\let \patternencoding \s!default
+\let \patternmapping \s!default
+
+\def\doifpatternselse#1%
+ {\expanded{\doifinsetelse{#1}{\preloadedpatterns}}}
+
+\def\doloadpatterns#1#2%
+ {\edef\askedlanguageencoding{\specificlanguageparameter{#1}\s!encoding}%
+ \edef\askedlanguagemapping {\specificlanguageparameter{#1}\s!mapping}%
+ \expanded{\getcommacommandsize[\askedlanguageencoding]}%
+ % slightly faster: \let\unicodechar\utfunihashglyph
+ \ifnum\commalistsize>0
+ %\message{[nofpatterns #2: \commalistsize/\askedlanguageencoding]}%
+ \dorecurse\commalistsize
+ {\expanded{\getfromcommacommand[\askedlanguageencoding][\recurselevel]}%
+ \let\patternencoding\commalistelement
+ \expanded{\getfromcommacommand[\askedlanguagemapping][\recurselevel]}%
+ \let\patternmapping \commalistelement
+ %\message{[patterns: #1/#2/\patternencoding/\patternmapping]}%
+ \dodoloadpatterns{#1}{#2}\patternencoding\patternmapping}%
+ \else
+ %\message{[patterns: #1/#2]}%
+ \dodoloadpatterns{#1}{#2}{}{}%
+ \fi}
+
+\ifnum\texengine=\xetexengine
+
+ \def\doloadpatterns#1#2%
+ {%\letvalue{\??la#2\s!encoding}\empty
+ %\letvalue{\??la#2\s!mapping }\empty
+ \dodoloadpatterns{#1}{#2}{}{}}
+
+\fi
+
+\def\setuphyppatencoding
+ {\pathypsettings
+ \enableregime[utf]}
+
+\def\dodoloadpatterns#1#2#3#4% beware, loaded language also incr
+ {\normallanguage\loadedlanguage % when not really needed
+ \bgroup
+ \let\synchronizepatterns\relax % needed?
+ \let\enabledmapping \empty % needed?
+ \doifelsenothing{#3}{\enableencoding[\s!default]}{\enableencoding[#3]}%
+ \doifelsenothing{#4}{\enablemapping [\s!default]}{\enablemapping [#4]}%
+ \setuphyppatencoding
+ \ifundefined{\??la\??la:\currentencoding:\currentmapping:#2}%
+ \let\doshowpatterns\relax
+ \edef\alreadyloadedlanguage
+ {\executeifdefined{\??la\??la:\currentencoding:\currentmapping:\truefilename{\f!languageprefix#2.\f!patternsextension}}\empty}%
+ \edef\alreadyloadedlanguage
+ {\executeifdefined{\??la\??la:\currentencoding:\currentmapping:\f!languageprefix#2.\f!patternsextension}\alreadyloadedlanguage}%
+ \ifx\alreadyloadedlanguage\empty
+ \letgvalue{\??la\??la:\currentencoding:\currentmapping:#2}\loadedlanguage
+ \doifundefined{\??la\??la:\s!default:\s!default:#2}{\letgvalue{\??la\??la:\s!default:\s!default:#2}\loadedlanguage}% fall back
+ \startpatternloading{\truefilename{\f!languageprefix#2.\f!patternsextension}}{#3}{#4}%
+ \readsysfile{\truefilename{\f!languageprefix#2.\f!patternsextension}}
+ {\setxvalue{\??la#1\s!patterns}{#2}%
+ \setxvalue{\??la\??la:\currentencoding:\currentmapping:\truefilename{\f!languageprefix#2.\f!patternsextension}}{\number\loadedlanguage}%
+ \xdef\preloadedpmessage{\preloadedpmessage\doshowpatterns{#2}{\number\normallanguage}{\currentencoding}{\currentmapping}}%
+ \doglobal\addtocommalist{#2}\preloadedpatterns
+ \showmessage\m!linguals1{#2,#1,\loadedlanguage,\currentencoding,\currentmapping}}
+ {\showmessage\m!linguals2{#2,#1,\loadedlanguage,\currentencoding,\currentmapping,\f!languageprefix#2.\f!patternsextension,\truefilename{\f!languageprefix#2.\f!patternsextension}}}%
+ \stoppatternloading
+ \startpatternloading{\truefilename{\f!languageprefix#2.\f!hyphensextension}}{#3}{#4}%
+ \readsysfile{\truefilename{\f!languageprefix#2.\f!hyphensextension}}
+ {\showmessage\m!linguals3{#2,#1,\loadedlanguage,\currentencoding,\currentmapping}}
+ {\showmessage\m!linguals4{#2,#1,\loadedlanguage,\currentencoding,\currentmapping}}%
+ \stoppatternloading
+ \doglobal\increment\loadedlanguage
+ % \stopencoding
+ \else % optimization, introduced 2004.08.24, while sorting out changes in tl
+ \letgvalue{\??la\??la:\currentencoding:\currentmapping:#2}\alreadyloadedlanguage
+ \doifundefined{\??la\??la:\s!default:\s!default:#2}{\letgvalue{\??la\??la:\s!default:\s!default:#2}\loadedlanguage}% fall back
+ \setxvalue{\??la#1\s!patterns}{#2}%
+ \xdef\preloadedpmessage{\preloadedpmessage\doshowpatterns{#2}{[\number\alreadyloadedlanguage]}{\currentencoding}{\currentmapping}}%
+ \doglobal\addtocommalist{#2}\preloadedpatterns
+ \showmessage\m!linguals1{#2,#1,[\alreadyloadedlanguage],\currentencoding,\currentmapping}%
+ \fi
+ \fi
+ \egroup}
+
+\fetchruntimecommand \showpatterns {\f!languageprefix\s!run.mkii}
+
+%D Since we can only load patterns in ini\TeX, we nil the
+%D loading before dumping (which saves a bit of memory, but
+%D strangely enough not in the format).
+
+\appendtoks
+ \gdef\doloadpatterns{\doglobal\increment\loadedlanguage\gobbletwoarguments}%
+ \globallet\dodoloadpatterns\gobblefourarguments
+\to \everydump
+
+%D \macros
+%D {setuplanguage}
+%D
+%D Quick and dirty, but useful:
+%D
+%D \showsetup{setuplanguage}
+%D
+%D Beware, this command can only be used when a language is installed.
+
+\unprotected \def\setuplanguage
+ {\dodoubleempty\dosetuplanguage}
+
+\def\dosetuplanguage[#1][#2]% handy patch for testing
+ {\ifsecondargument
+ \getparameters[\??la#1][#2]%
+ \doif{#1}\currentlanguage\docomplexlanguage
+ \else
+ \getparameters[\??la\currentlanguage][#1]%
+ \docomplexlanguage
+ \fi}
+
+\setuplanguage
+ [\s!default]
+ [\s!lefthyphenmin=2,
+ \s!righthyphenmin=2,
+ \s!patterns=,
+ \c!spacing=\v!packed,
+ \s!encoding=,
+ \s!mapping=,
+ \c!lefthyphen=,
+ \c!righthyphen=-,
+ \c!hyphen=-,
+ \c!midsentence=---,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!leftspeech=\languageparameter\c!leftquotation,
+ \c!middlespeech=,
+ \c!rightspeech=\languageparameter\c!rightquotation,
+ \c!limittext=\unknown,
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day},
+ \c!text=Ag]
+
+% rather new, split and per language
+
+\setuplanguage
+ [\s!default]
+ [\c!compoundhyphen=\compoundhyphen,
+ \c!leftcompoundhyphen=\compoundhyphen,
+ \c!rightcompoundhyphen=]
+
+%D The values \type {leftsentence} and \type
+%D {rightsentence} can be (and are) used to implement
+%D automatic subsentence boundary glyphs, like in {\fr
+%D |<|french guillemots|>|} or {\de |<|german guillemots|>|} or
+%D {\nl |<|dutch dashes|>|} like situations. Furthermore \type
+%D {leftquotation} and \type {leftquote} come into view
+%D \quotation {when we quote} or \quote {quote} something.
+
+%D \macros
+%D {currentdatespecification}
+%D
+%D Just to make things easy we can ask for the current date
+%D specification by saying:
+
+\def\currentdatespecification{\languageparameter\c!date}
+
+%D This command is not meant for users.
+
+%D Carefull reading of these macros shows that it's legal to
+%D say
+%D
+%D \starttyping
+%D \installlanguage [du] [de]
+%D \stoptyping
+
+%D \macros
+%D {language,mainlanguage}
+%D
+%D Switching to another language (actually another hyphenation
+%D pattern) is done with:
+%D
+%D \starttyping
+%D \language[identifier]
+%D \stoptyping
+%D
+%D or with \type{\identifier}. Just to be compatible with
+%D \PLAIN\ \TEX, we still support the original meaning, so
+%D
+%D \starttyping
+%D \language=1
+%D \stoptyping
+%D
+%D is a valid operation, where the relation between number
+%D and language depends on the order in installing languages.
+%D
+%D \showsetup{language}
+%D \showsetup{mainlanguage}
+%D
+%D Both commands take a predefined language identifier as
+%D argument. We can use \type{\mainlanguage[identifier]} for
+%D setting the (indeed) main language. This is the language
+%D used for translating labels like {\em figure} and {\em
+%D table}. The main language defaults to the current language.
+%D
+%D We take care of local as well as standardized language
+%D switching (fr and fa, de and du, but nl and nl).
+
+\ifx\synchronizepatterns \undefined \let\synchronizepatterns\relax \fi
+\ifx\synchronizepatternswithfont\undefined \def\synchronizepatternswithfont{\synchronizepatterns} \fi
+
+\def\setnormallanguage#1#2% current default
+ {% called quite often, so we use \csname
+ % \def\synchronizepatterns{\setnormallanguage
+ % {\csname\??la\currentlanguage\s!patterns\endcsname}}% called often
+ % of even better pre-expand in an ugly way:
+ \ifnum\normallanguage<\zerocount
+ % we've blocked hyphenation (e.g. verbatim)
+ \else
+ \edef\synchronizepatterns{\noexpand\dosetnormallanguage{\languageparameter\s!patterns}}%
+ \donefalse
+ \synchronizepatterns
+ \ifdone\else
+ \def\synchronizepatterns{\dosetnormallanguage\currentlanguage}%
+ \synchronizepatterns
+ \ifdone\else
+ \ifx\currentdefaultlanguage\empty\else
+ \edef\synchronizepatterns{\noexpand\dosetnormallanguage{\specificlanguageparameter\currentdefaultlanguage\s!patterns}}%
+ \synchronizepatterns
+ \ifdone\else
+ \dosetnormallanguage\currentdefaultlanguage
+ \synchronizepatterns
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi}
+
+\normallanguage\zerocount
+
+\def\dosetnormallanguage#1% #1 == \cs (no longer)
+ {\ifnum\normallanguage<\zerocount
+ % we've blocked hyphenation (e.g. verbatim)
+ \else
+ \dodosetnormallanguage{:\currentencoding:\currentmapping:}{#1}{%
+ \dodosetnormallanguage{:\currentencoding:\s!default :}{#1}{%
+ \dodosetnormallanguage{:\s!default :\currentmapping:}{#1}{%
+ \dodosetnormallanguage{:\s!default :\s!default :}{#1}\empty}}}%
+ \fi}
+
+\def\dodosetnormallanguage#1#2%
+ {\ifcsname\??la\??la#1#2\endcsname
+ \edef\thenormallanguage{\csname\??la\??la#1#2\endcsname}% can be \chardef
+ \ifx\thenormallanguage\empty
+ \@EAEAEA\firstofoneargument
+ \else
+ \donetrue
+ \@EA\xdef\csname\??la\currentlanguage\s!patterns\endcsname{#2}%
+ \normallanguage\thenormallanguage\relax % \relax is needed for lookahead problems
+ \@EAEAEA\gobbleoneargument
+ \fi
+ \else
+ \@EA\firstofoneargument
+ \fi}
+
+\newevery \everylanguage \relax
+
+\def\disablelanguagespecifics
+ {\ignorecompoundcharacter}
+
+\def\sethyphenationvariables
+ {\lefthyphenmin 0\languageparameter\s!lefthyphenmin \relax
+ \righthyphenmin0\languageparameter\s!righthyphenmin\relax
+ \lefthyphenmin \numexpr\lefthyphenmin +\hyphenminoffset\relax
+ \righthyphenmin\numexpr\righthyphenmin+\hyphenminoffset\relax}
+
+\def\docomplexlanguage% assumes that \currentlanguage is set
+ {\edef\currentdefaultlanguage{\defaultlanguage\currentlanguage}%
+ \setnormallanguage\currentlanguage\currentdefaultlanguage
+ \the\everylanguage
+ \enablelanguagespecifics[\currentlanguage]%
+ \sethyphenationvariables
+ \relax
+ % will be definable and move to core-spa !
+ \doifelse{\languageparameter\c!spacing}\v!broad\nonfrenchspacing\frenchspacing}
+
+\ifx\enablelanguagespecifics\undefined \def\enablelanguagespecifics[#1]{} \fi
+
+% The following may be a solution for the fact that one cannot
+% change catcodes of characters like : and ; inside an environment.
+
+\appendtoks
+ \enablelanguagespecifics[\currentlanguage]%
+\to \everystarttext
+
+\def\complexlanguage[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty \else
+ \ifcsname\l!prefix!\askedlanguage\endcsname
+ \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
+ \ifx\currentlanguage\askedlanguage \else
+ \setcurrentlanguage\currentmainlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \else
+ \showmessage\m!linguals6{#1}%
+ \fi
+ \fi}
+
+\let\simplelanguage\normallanguage
+
+\definecomplexorsimple\language
+
+\def\mainlanguage[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty \else
+ \ifcsname\l!prefix!\askedlanguage\endcsname
+ \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
+ \ifx\currentlanguage\askedlanguage
+ \ifx\currentmainlanguage\askedlanguage
+ \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \fi
+ \fi}
+
+%D \macros
+%D {defaultlanguage,languageparameter,specificlanguageparameter}
+
+\def\defaultlanguage#1%
+ {\ifcsname\??la#1\s!default\endcsname
+ \expandafter\defaultlanguage\csname\??la#1\s!default\endcsname
+ \else
+ #1%
+ \fi}
+
+\def\languageparameter#1%
+ {\ifcsname\??la\currentlanguage#1\endcsname
+ \csname\??la\currentlanguage#1\endcsname
+ \else\ifcsname\??la\currentlanguage\s!default\endcsname
+ \expandafter\specificlanguageparameter\csname\??la\currentlanguage\s!default\endcsname{#1}%
+ \else\ifcsname\??la\s!default#1\endcsname
+ \csname\??la\s!default#1\endcsname
+ \fi\fi\fi}
+
+\def\specificlanguageparameter#1#2%
+ {\ifcsname\??la#1#2\endcsname
+ \csname\??la#1#2\endcsname
+ \else\ifcsname\??la#1\s!default\endcsname
+ \expandafter\specificlanguageparameter\csname\??la#1\s!default\endcsname{#2}%
+ \else\ifcsname\??la\s!default#2\endcsname
+ \csname\??la\s!default#2\endcsname
+ \fi\fi\fi}
+
+%D New (see nomarking and nolist):
+
+\def\splitsequence#1#2%
+ {\doifelse{#1}\v!no{#2}{\doifelse{#1}\v!yes{\languageparameter\c!limittext}{#1}}}
+
+\def\splitsymbol#1%
+ {\splitsequence{#1}{\languageparameter\c!limittext}}
+
+%D Just like with subsentence boundary symbols, quotes
+%D placement depends on the current language, therefore we show
+%D the defaults here.
+%D
+%D \def\ShowLanguageValues [#1] [#2] #3 #4
+%D {\blank
+%D \startlinecorrection
+%D \vbox\bgroup
+%D \language[#1]%
+%D \setbox0=\hbox to \hsize{\hss\bf#2 subsentence symbol and quotes\hss}
+%D \dp0=0pt
+%D \box0
+%D \vskip.5em
+%D \hrule
+%D \vskip.5em
+%D \let\normalbar=|
+%D \hbox to \hsize
+%D {\hfil\quotation{#3 #4}\hfil\quote{#2}\hfil
+%D \let|=\normalbar\strut|<||<|#3|>|#4|>|\hfil}
+%D \vskip.5em
+%D \hrule
+%D \egroup
+%D \stoplinecorrection
+%D \blank}
+%D
+%D \ShowLanguageValues [af] [afrikaans] afrikaanse ...
+%D \ShowLanguageValues [ca] [catalan] catalan ...
+%D \ShowLanguageValues [cs] [czech] tjechisch tex
+%D \ShowLanguageValues [cs] [slovak] slowaakse ...
+%D \ShowLanguageValues [da] [danish] deense ...
+%D \ShowLanguageValues [de] [german] duitse degelijkheid
+%D \ShowLanguageValues [en] [english] engelse humor
+%D \ShowLanguageValues [fi] [finnish] finse ...
+%D \ShowLanguageValues [fr] [french] franse slag
+%D \ShowLanguageValues [it] [italian] italiaanse ...
+%D \ShowLanguageValues [la] [latin] latijnse missen
+%D \ShowLanguageValues [nl] [dutch] nederlandse zuinigheid
+%D \ShowLanguageValues [nb] [bokmal] noorse zalm
+%D \ShowLanguageValues [nn] [nnynorsk] noorse zalm
+%D \ShowLanguageValues [pl] [polish] poolse vlag
+%D \ShowLanguageValues [pt] [portuguese] portugese ...
+%D \ShowLanguageValues [es] [spanish] spaans benauwd
+%D \ShowLanguageValues [sv] [swedish] zweedse ...
+%D \ShowLanguageValues [tr] [turkish] turks fruit
+
+%D We support a lot of languages. These are specified and
+%D loaded in separate files, according to their roots. Here
+%D we only take care of (postponed) setting of the current
+%D language.
+%D
+%D \unprotect
+%D \placetable{The germanic languages (\type{lang-ger})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!nl \NC dutch \NC germanic \NC\FR
+%D \NC \s!en \NC english \NC germanic \NC\MR
+%D \NC \s!de \NC german \NC germanic \NC\MR
+%D \NC \s!da \NC danish \NC germanic \NC\MR
+%D \NC \s!sv \NC swedish \NC germanic \NC\MR
+%D \NC \s!af \NC afrikaans \NC germanic \NC\MR
+%D \NC \s!nb \NC bokmal \NC germanic \NC\LR
+%D \NC \s!nn \NC nynorsk \NC germanic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The italic languages (\type{lang-ita})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fr \NC french \NC italic \NC\FR
+%D \NC \s!ca \NC catalan \NC italic \NC\MR
+%D \NC \s!es \NC spanish \NC italic \NC\MR
+%D \NC \s!it \NC italian \NC italic \NC\MR
+%D \NC \s!la \NC latin \NC italic \NC\MR
+%D \NC \s!pt \NC portuguese \NC italic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The slavic languages (\type{lang-sla})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!pl \NC polish \NC slavic \NC\FR
+%D \NC \s!cs \NC czech \NC slavic \NC\MR
+%D \NC \s!sk \NC slavik \NC slavic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D \unprotect
+%D
+%D \placetable{The altaic languages (\type{lang-alt})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!tr \NC turkish \NC altaic \NC\SR
+%D \HL
+%D \stoptable
+%D
+%D \placetable{The uralic languages (\type{lang-ura})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fi \NC finnish \NC uralic \NC\SR
+%D \HL
+%D \stoptable
+%D \protect
+
+% \bgroup \normallanguage255 \patterns{} \egroup
+% \def\nopatterns{\normallanguage255 }
+
+\def\nopatterns{\normallanguage\minusone}
+
+%D \XETEX\ is \UNICODE:
+
+\ifnum\texengine=\xetexengine
+
+ \def\synchronizepatternswithfont{}
+ \def\doloadpatterns #1#2{\dodoloadpatterns{#1}{#2}\s!default\s!default}
+ \def\dosetnormallanguage #1{\dodosetnormallanguage{:\s!default:\s!default:}{#1}\empty}
+ \def\setuphyppatencoding {\pathypsettings}
+
+\fi
+
+%D We default to the language belonging to the interface. This
+%D is one of the few places outside the interface modules where
+%D \type{\startinterface} is used.
+
+%D We default to english:
+
+\setupcurrentlanguage[\s!en]
+
+\def\initializemainlanguage
+ {\mainlanguage[\currentlanguage]%
+ \showmessage\m!linguals9\currentlanguage}
+
+\protect \endinput
diff --git a/tex/context/base/lang-ini.mkiv b/tex/context/base/lang-ini.mkiv
new file mode 100644
index 000000000..45bb71b85
--- /dev/null
+++ b/tex/context/base/lang-ini.mkiv
@@ -0,0 +1,560 @@
+%D \module
+%D [ file=lang-ini,
+%D version=1996.01.25,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Initialization,
+%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.
+
+%D This module needs a further cleanup (real split between ii/iv).
+
+%D This module implements the (for the moment still simple)
+%D multi||language support of \CONTEXT, which should not be
+%D confused with the multi||lingual interface. This support
+%D will be extended when needed.
+
+\writestatus{loading}{ConTeXt Language Macros / Initialization}
+
+\registerctxluafile{lang-ini}{1.001}
+
+\unprotect
+
+% \def\testlanguage[#1]%
+% {\start
+% \language[#1]
+% \number\normallanguage/\the\lefthyphenmin/\the\righthyphenmin:
+% \input tufte
+% \hyphenatedword{effetestenofditwerkt}
+% \par
+% \stop}
+%
+% \testlanguage[de] \testlanguage[de-de] \testlanguage[de-at] \testlanguage[de-ch] \page
+% \testlanguage[en] \testlanguage[us] \testlanguage[en-us] \testlanguage[uk] \testlanguage[en-gb] \page
+
+\ifx\nonfrenchspacing\undefined \let\nonfrenchspacing\relax \fi
+\ifx\frenchspacing \undefined \let\frenchspacing \relax \fi
+
+%D When loading hyphenation patterns, \TEX\ assign a number to
+%D each loaded table, starting with~0. Switching to a specific
+%D table is done by assigning the relevant number to the
+%D predefined \COUNTER\ \type{\language}.
+
+%D We keep track of the last loaded patterns by means of a
+%D pseudo \COUNTER. This just one of those situations in which
+%D we don't want to spent a real one. Language zero has no
+%D patterns, first of all because I like to start numbering
+%D at one. It may come in handy for special purposes as well.
+
+\normallanguage\zerocount \def\loadedlanguage{1}
+
+%D \macros
+%D {currentlanguage, setupcurrentlanguage}
+%D
+%D Instead of numbers,we are going to use symbolic names for
+%D the languages. The current langage is saved in the macro
+%D \type {\currentlanguage}. The setup macro is mainly used
+%D for cosmetic purposes.
+%D
+%D \starttyping
+%D \dorecurse{3}
+%D {\language[nl]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode
+%D \language[en]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode}
+%D \stoptyping
+
+\let\currentlanguage \empty
+\let\currentmainlanguage\empty
+
+\unexpanded\def\setupcurrentlanguage[#1]{\setcurrentlanguage\currentmainlanguage{#1}}
+
+\def\setcurrentlanguage#1#2% sets modes: **id (currentmain) *id (current)
+ {\edef\xaskedlanguage{#1}% otherwise clash with \askedlanguage
+ \ifx\xaskedlanguage\empty \else
+ \ifx\currentmainlanguage\empty\else\resetsystemmode{\systemmodeprefix\currentmainlanguage}\fi
+ \let\currentmainlanguage\xaskedlanguage
+ \setsystemmode{\systemmodeprefix\currentmainlanguage}%
+ \fi
+ \edef\xaskedlanguage{#2}%
+ \ifx\xaskedlanguage\empty \else
+ \ifx\currentlanguage\empty\else\resetsystemmode\currentlanguage\fi
+ \let\currentlanguage\xaskedlanguage
+ \setsystemmode\currentlanguage
+ \fi}
+
+%D The internal macros will be defined later.
+
+%D \macros
+%D {installlanguage}
+%D
+%D Hyphenation patterns can only be loaded when the format file
+%D is prepared. The next macro takes care of this loading. A
+%D language is specified with
+%D
+%D \showsetup{installlanguage}
+%D
+%D When \type {state} equals \type {start}, both patterns
+%D and additional hyphenation specifications are loaded. These
+%D files are seached for on the system path and are to be
+%D named:
+%D
+%D \starttyping
+%D \f!languageprefix-identifier.\f!patternsextension
+%D \f!languageprefix-identifier.\f!hyhensextension
+%D \stoptyping
+%D
+%D The \type{spacing} variable specifies how the spaces after
+%D punctuation has to be handled. English is by tradition more
+%D tolerant to inter||sentence spacing than other languages.
+%D
+%D This macro also defines \type {\identifier} as a shortcut
+%D switch to the language. Furthermore the command defined as
+%D being language specific, are executed. With
+%D \type {default} we can default to another language
+%D (patterns) at format generation time. This default language
+%D is overruled when the appropriate patterns are loaded (some
+%D implementations support run time addition of patterns to a
+%D preloaded format).
+
+\def\dodoinstalllanguage#1#2% #2 added
+ {\expanded{\noexpand\uppercase{\noexpand\edef\noexpand\ascii{#1}}}%
+ \ifcsname #1\endcsname\else\setvalue {#1}{\complexlanguage[#2]}\fi
+ \ifcsname\ascii\endcsname\else\setvalue\ascii{\complexlanguage[#2]}\fi}
+
+%D \macros
+%D {preloadlanguages}
+%D
+%D We first try to load the files defined as file synonym
+%D for \type {lang-*.pat} and \type {lang-*.hyp}. After that we
+%D fall back on those files. The macro \type {\preloadpatterns}
+%D reports which patterns are loaded and what hyphenmin
+%D values are set.
+
+\let\installedlanguages\empty
+
+\def\doiflanguageelse#1{\doifdefinedelse{\??la#1\c!state}}
+
+\def\doloadpatterns#1#2%
+ {\ctxlua{languages.register(
+ "#1",
+ "#2",
+ "\truefilename{\f!languageprefix#2.\f!patternsextension}",
+ "\truefilename{\f!languageprefix#2.\f!hyphensextension }")
+ }}
+
+\def\doloadlanguagefiles#1%
+ {\edef\languagesuffix{\specificlanguageparameter{#1}\s!patterns}%
+ \ifx\languagesuffix\empty
+ \edef\languagesuffix{\defaultlanguage{#1}}%
+ \else\ifx\languagesuffix\relax
+ \edef\languagesuffix{\defaultlanguage{#1}}%
+ \fi\fi
+ \ifx\languagesuffix\empty
+ \edef\languagesuffix{#1}%
+ \fi
+ \doloadpatterns{#1}\languagesuffix}
+
+\def\doinstalllanguage[#1][#2]%
+ {\doifassignmentelse{#2}
+ {\doiflanguageelse{#1}
+ {\getparameters[\??la#1][#2]}
+ {\setvalue{\l!prefix!#1}{#1}%
+ \addtocommalist{#1}\installedlanguages
+ \dodoinstalllanguage{#1}{#1}%
+ \getparameters[\??la#1][\c!state=\v!start,#2]}%
+ \doloadlanguagefiles{#1}}
+ {\setvalue{\l!prefix!#1}{#2}%
+ \getparameters[\??la#1][\s!default=#2]%
+ \dodoinstalllanguage{#1}{#2}}}
+
+\def\reallanguagetag#1%
+ {\ifcsname\l!prefix!#1\endcsname\csname\l!prefix!#1\endcsname\else#1\fi}
+
+% ^^ \language[#1] gave unwanted side effect of loading language specifics
+
+\def\installlanguage
+ {\dodoubleargument\doinstalllanguage}
+
+%D When the second argument is a language identifier, a
+%D synonym is created. This feature is present because we
+%D used dutch mnemonics in the dutch version, but nowadays
+%D conform a standard.
+
+\def\doifpatternselse#1%
+ {\ctxlua{cs.testcase(languages.loadable("#1"))}}
+
+%D \macros
+%D {setuplanguage}
+%D
+%D Quick and dirty, but useful:
+%D
+%D \showsetup{setuplanguage}
+%D
+%D Beware, this command can only be used when a language is installed.
+
+\unexpanded\def\setuplanguage
+ {\dodoubleempty\dosetuplanguage}
+
+\def\dosetuplanguage[#1][#2]% handy patch for testing
+ {\ifsecondargument
+ \getparameters[\??la#1][#2]%
+ \doif{#1}\currentlanguage\docomplexlanguage
+ \else
+ \getparameters[\??la\currentlanguage][#1]%
+ \docomplexlanguage
+ \fi}
+
+\setuplanguage
+ [\s!default]
+ [\s!lefthyphenmin=2,
+ \s!righthyphenmin=2,
+ \s!patterns=,
+ \c!spacing=\v!packed,
+ \c!lefthyphen=,
+ \c!righthyphen=-,
+ \c!hyphen=-,
+ \c!midsentence=---,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!leftspeech=\languageparameter\c!leftquotation,
+ \c!middlespeech=,
+ \c!rightspeech=\languageparameter\c!rightquotation,
+ \c!limittext=\unknown,
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day},
+ \c!text=Ag]
+
+% rather new, split and per language
+
+\setuplanguage
+ [\s!default]
+ [\c!compoundhyphen=\compoundhyphen,
+ \c!rightcompoundhyphen=\compoundhyphen,
+ \c!leftcompoundhyphen=]
+
+%D The values \type {leftsentence} and \type
+%D {rightsentence} can be (and are) used to implement
+%D automatic subsentence boundary glyphs, like in {\fr
+%D |<|french guillemots|>|} or {\de |<|german guillemots|>|} or
+%D {\nl |<|dutch dashes|>|} like situations. Furthermore \type
+%D {leftquotation} and \type {leftquote} come into view
+%D \quotation {when we quote} or \quote {quote} something.
+
+%D \macros
+%D {currentdatespecification}
+%D
+%D Just to make things easy we can ask for the current date
+%D specification by saying:
+
+\def\currentdatespecification{\languageparameter\c!date}
+
+%D This command is not meant for users.
+
+%D Carefull reading of these macros shows that it's legal to
+%D say
+%D
+%D \starttyping
+%D \installlanguage [du] [de]
+%D \stoptyping
+
+%D \macros
+%D {language,mainlanguage}
+%D
+%D Switching to another language (actually another hyphenation
+%D pattern) is done with:
+%D
+%D \starttyping
+%D \language[identifier]
+%D \stoptyping
+%D
+%D or with \type{\identifier}. Just to be compatible with
+%D \PLAIN\ \TEX, we still support the original meaning, so
+%D
+%D \starttyping
+%D \language=1
+%D \stoptyping
+%D
+%D is a valid operation, where the relation between number
+%D and language depends on the order in installing languages.
+%D
+%D \showsetup{language}
+%D \showsetup{mainlanguage}
+%D
+%D Both commands take a predefined language identifier as
+%D argument. We can use \type{\mainlanguage[identifier]} for
+%D setting the (indeed) main language. This is the language
+%D used for translating labels like {\em figure} and {\em
+%D table}. The main language defaults to the current language.
+%D
+%D We take care of local as well as standardized language
+%D switching (fr and fa, de and du, but nl and nl).
+
+\def\dosetnormallanguage#1#2% current default
+ {\edef\askedlanguagepatterns{\specificlanguageparameter{#1}\s!patterns}%
+ \normallanguage=\ctxlua{tex.sprint(languages.enable({"\askedlanguagepatterns","#1","#2"}))}%
+ \ifproductionrun
+ \setxvalue{\??la\??la#1#2}{\number\normallanguage}%
+ \fi}
+
+\def\setnormallanguage#1#2% current default / we can freeze the number here
+ {\ifcsname\??la\??la#1#2\endcsname
+ \normallanguage\csname\??la\??la#1#2\endcsname % todo: we can set language at the lua end now
+ \else
+ \dosetnormallanguage{#1}{#2}%
+ \fi}
+
+\newtoks \everylanguage
+
+\def\sethyphenationvariables % as we can have cloning we need to set it each time, unless we move all to lua
+ {\ctxlua{languages.setup(tex.language, {
+ lefthyphen = "\languageparameter\c!lefthyphen",
+ righthyphen = "\languageparameter\c!righthyphen",
+ } )}%
+ \lefthyphenmin \numexpr0\languageparameter\s!lefthyphenmin +\hyphenminoffset\relax
+ \righthyphenmin\numexpr0\languageparameter\s!righthyphenmin+\hyphenminoffset\relax}
+
+\def\docomplexlanguage% assumes that \currentlanguage is set
+ {\edef\currentdefaultlanguage{\defaultlanguage\currentlanguage}%
+ \setnormallanguage\currentlanguage\currentdefaultlanguage
+ \the\everylanguage
+ \sethyphenationvariables
+ \relax
+ % will be definable and move to core-spa !
+ \doifelse{\languageparameter\c!spacing}\v!broad\nonfrenchspacing\frenchspacing}
+
+% \mainlanguage[nl] \setuplanguage[nl][lefthyphen=,righthyphen=?]
+%
+% \dorecurse{100}{dit is toch wel een heel\normalhyphendiscretionary lang\normalhyphendiscretionary woord \recurselevel\ }
+% \dorecurse{100}{dit is toch wel een heellangwoord \recurselevel\ }
+
+% The following may be a solution for the fact that one cannot
+% change catcodes of characters like : and ; inside an environment.
+
+\def\complexlanguage[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty \else
+ \ifcsname\l!prefix!\askedlanguage\endcsname
+ \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
+ \ifx\currentlanguage\askedlanguage \else
+ \setcurrentlanguage\currentmainlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \else
+ \showmessage\m!linguals6{#1}%
+ \fi
+ \fi}
+
+\let\simplelanguage\normallanguage
+
+\definecomplexorsimple\language
+
+\def\mainlanguage[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty \else
+ \ifcsname\l!prefix!\askedlanguage\endcsname
+ \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
+ \ifx\currentlanguage\askedlanguage
+ \ifx\currentmainlanguage\askedlanguage
+ \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \fi
+ \fi}
+
+%D \macros
+%D {defaultlanguage,languageparameter,specificlanguageparameter}
+
+\def\defaultlanguage#1%
+ {\ifcsname\??la#1\s!default\endcsname
+ \expandafter\defaultlanguage\csname\??la#1\s!default\endcsname
+ \else
+ #1%
+ \fi}
+
+\def\languageparameter#1%
+ {\ifcsname\??la\currentlanguage#1\endcsname
+ \csname\??la\currentlanguage#1\endcsname
+ \else\ifcsname\??la\currentlanguage\s!default\endcsname
+ \expandafter\specificlanguageparameter\csname\??la\currentlanguage\s!default\endcsname{#1}%
+ \else\ifcsname\??la\s!default#1\endcsname
+ \csname\??la\s!default#1\endcsname
+ \fi\fi\fi}
+
+\def\specificlanguageparameter#1#2%
+ {\ifcsname\??la#1#2\endcsname
+ \csname\??la#1#2\endcsname
+ \else\ifcsname\??la#1\s!default\endcsname
+ \expandafter\specificlanguageparameter\csname\??la#1\s!default\endcsname{#2}%
+ \else\ifcsname\??la\s!default#2\endcsname
+ \csname\??la\s!default#2\endcsname
+ \fi\fi\fi}
+
+%D New (see nomarking and nolist):
+
+\def\splitsequence#1#2%
+ {\doifelse{#1}\v!no{#2}{\doifelse{#1}\v!yes{\languageparameter\c!limittext}{#1}}}
+
+\def\splitsymbol#1%
+ {\splitsequence{#1}{\languageparameter\c!limittext}}
+
+%D Just like with subsentence boundary symbols, quotes
+%D placement depends on the current language, therefore we show
+%D the defaults here.
+%D
+%D \def\ShowLanguageValues [#1] [#2] #3 #4
+%D {\blank
+%D \startlinecorrection
+%D \vbox\bgroup
+%D \language[#1]%
+%D \setbox0=\hbox to \hsize{\hss\bf#2 subsentence symbol and quotes\hss}
+%D \dp0=0pt
+%D \box0
+%D \vskip.5em
+%D \hrule
+%D \vskip.5em
+%D \let\normalbar=|
+%D \hbox to \hsize
+%D {\hfil\quotation{#3 #4}\hfil\quote{#2}\hfil
+%D \let|=\normalbar\strut|<||<|#3|>|#4|>|\hfil}
+%D \vskip.5em
+%D \hrule
+%D \egroup
+%D \stoplinecorrection
+%D \blank}
+%D
+%D \ShowLanguageValues [af] [afrikaans] afrikaanse ...
+%D \ShowLanguageValues [ca] [catalan] catalan ...
+%D \ShowLanguageValues [cs] [czech] tjechisch tex
+%D \ShowLanguageValues [cs] [slovak] slowaakse ...
+%D \ShowLanguageValues [da] [danish] deense ...
+%D \ShowLanguageValues [de] [german] duitse degelijkheid
+%D \ShowLanguageValues [en] [english] engelse humor
+%D \ShowLanguageValues [fi] [finnish] finse ...
+%D \ShowLanguageValues [fr] [french] franse slag
+%D \ShowLanguageValues [it] [italian] italiaanse ...
+%D \ShowLanguageValues [la] [latin] latijnse missen
+%D \ShowLanguageValues [nl] [dutch] nederlandse zuinigheid
+%D \ShowLanguageValues [nb] [bokmal] noorse zalm
+%D \ShowLanguageValues [nn] [nnynorsk] noorse zalm
+%D \ShowLanguageValues [pl] [polish] poolse vlag
+%D \ShowLanguageValues [pt] [portuguese] portugese ...
+%D \ShowLanguageValues [es] [spanish] spaans benauwd
+%D \ShowLanguageValues [sv] [swedish] zweedse ...
+%D \ShowLanguageValues [tr] [turkish] turks fruit
+
+%D We support a lot of languages. These are specified and
+%D loaded in separate files, according to their roots. Here
+%D we only take care of (postponed) setting of the current
+%D language.
+%D
+%D \unprotect
+%D \placetable{The germanic languages (\type{lang-ger})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!nl \NC dutch \NC germanic \NC\FR
+%D \NC \s!en \NC english \NC germanic \NC\MR
+%D \NC \s!de \NC german \NC germanic \NC\MR
+%D \NC \s!da \NC danish \NC germanic \NC\MR
+%D \NC \s!sv \NC swedish \NC germanic \NC\MR
+%D \NC \s!af \NC afrikaans \NC germanic \NC\MR
+%D \NC \s!nb \NC bokmal \NC germanic \NC\LR
+%D \NC \s!nn \NC nynorsk \NC germanic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The italic languages (\type{lang-ita})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fr \NC french \NC italic \NC\FR
+%D \NC \s!ca \NC catalan \NC italic \NC\MR
+%D \NC \s!es \NC spanish \NC italic \NC\MR
+%D \NC \s!it \NC italian \NC italic \NC\MR
+%D \NC \s!la \NC latin \NC italic \NC\MR
+%D \NC \s!pt \NC portuguese \NC italic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The slavic languages (\type{lang-sla})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!pl \NC polish \NC slavic \NC\FR
+%D \NC \s!cs \NC czech \NC slavic \NC\MR
+%D \NC \s!sk \NC slavik \NC slavic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D \unprotect
+%D
+%D \placetable{The altaic languages (\type{lang-alt})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!tr \NC turkish \NC altaic \NC\SR
+%D \HL
+%D \stoptable
+%D
+%D \placetable{The uralic languages (\type{lang-ura})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fi \NC finnish \NC uralic \NC\SR
+%D \HL
+%D \stoptable
+%D \protect
+
+% \bgroup \normallanguage255 \patterns{} \egroup
+% \def\nopatterns{\normallanguage255 }
+
+\def\nopatterns{\normallanguage\minusone}
+
+%D We default to the language belonging to the interface. This
+%D is one of the few places outside the interface modules where
+%D \type{\startinterface} is used.
+
+%D We default to english:
+
+\setupcurrentlanguage[\s!en]
+
+\def\initializemainlanguage
+ {\mainlanguage[\currentlanguage]%
+ \showmessage\m!linguals9\currentlanguage}
+
+%D Might be in use:
+
+\let\preloadallpatterns\relax % just for old times sake
+\let\preloadlanguages \relax % just for old times sake
+
+\uchyph=1
+
+\exhyphenchar=45 % to permit breaking at explicit hyphens
+
+\protect \endinput
diff --git a/tex/context/base/lang-ita.tex b/tex/context/base/lang-ita.tex
new file mode 100644
index 000000000..03efb0614
--- /dev/null
+++ b/tex/context/base/lang-ita.tex
@@ -0,0 +1,518 @@
+%D \module
+%D [ file=lang-ita,
+%D version=1997.09.03,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Italic Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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.
+
+% Todo: replace \'.. by \namedglyph
+
+\writestatus{loading}{ConTeXt Language Macros / Italic Languages}
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+%D
+%D \starttabulate[|lB|l|]
+%D \NC Italian \NC Giuseppe Bilotta \NC \NR
+%D \NC Romanian \NC Dan Seracu \NC \NR
+%D \NC Portuguese \NC Pedro F. M. Mendon\c a \NC \NR
+%D \stoptabulate
+
+% Latin, Italian, Rhaeto-Romanic, Rumanian, Sardian
+% Catalan, French, Ladino, Portuguese, Proven\c{c}al, Spanish
+
+\unprotect
+
+\ifx\guillemotspace\undefined \let\guillemotspace\empty \fi
+\ifx\sentencespace \undefined \let\sentencespace \empty \fi
+
+\installlanguage
+ [\s!fr]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=\emdash,
+ \c!rightsentence=\emdash,
+ \c!leftsubsentence=\emdash,
+ \c!rightsubsentence=\emdash,
+ \c!leftquote=\leftguillemot,
+ \c!rightquote=\rightguillemot,
+ \c!leftquotation=\leftguillemot,
+ \c!rightquotation=\rightguillemot,
+ \c!date={\v!day+,\v!space,\v!month,\v!space,\v!year},
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
+
+\installlanguage
+ [\s!es]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
+
+\installlanguage [sp] [\s!es] % old times context
+
+\installlanguage
+ [\s!ca]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
+
+% Note GB left|/|right (sub)sentences are for \quote {incisi}.
+
+\installlanguage
+ [\s!it]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=--,
+ \c!rightsubsentence=--,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!leftspeech=\leftguillemot,
+ \c!middlespeech=\leftguillemot,
+ \c!rightspeech=\rightguillemot,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year},
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
+
+\installlanguage % the same as italian
+ [\s!la]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\lowerrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\lowerrightdoubleninequote,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
+
+\installlanguage
+ [\s!pt]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day},
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
+
+\installlanguage
+ [\s!ro]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\leftguillemot,
+ \c!rightquote=\rightguillemot,
+ \c!leftquotation=\lowerrightdoubleninequote,
+ \c!rightquotation=\upperleftdoublesixquote,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
+
+%D For compatibility reasons we also define:
+
+\installlanguage [fa] [\s!fr] % for dutchies only
+
+\installlanguage [french] [\s!fr]
+\installlanguage [spanish] [\s!es]
+\installlanguage [catalan] [\s!ca]
+\installlanguage [italian] [\s!it]
+\installlanguage [latin] [\s!la]
+\installlanguage [portuguese] [\s!pt]
+\installlanguage [romanian] [\s!ro]
+
+%D Labels and header texts.
+
+\setupheadtext [\s!fr] [\v!content=Table des mati\`eres]
+\setupheadtext [\s!es] [\v!content=\'Indice]
+\setupheadtext [\s!ca] [\v!content=\'Index de continguts]
+\setupheadtext [\s!it] [\v!content=Indice]
+\setupheadtext [\s!la] [\v!content=Quod in libro continetur] %Argumentum
+\setupheadtext [\s!pt] [\v!content=Conte\'udo]
+\setupheadtext [\s!ro] [\v!content=Cuprins]
+
+\setupheadtext [\s!fr] [\v!tables=Tableaux]
+\setupheadtext [\s!es] [\v!tables=Tablas]
+\setupheadtext [\s!ca] [\v!tables=Taules]
+\setupheadtext [\s!it] [\v!tables=Tabelle]
+\setupheadtext [\s!la] [\v!tables=Tabulae]
+\setupheadtext [\s!pt] [\v!tables=Tabelas]
+\setupheadtext [\s!ro] [\v!tables=Tabele]
+
+\setupheadtext [\s!fr] [\v!figures=Figures]
+\setupheadtext [\s!es] [\v!figures=Ilustraciones]
+\setupheadtext [\s!ca] [\v!figures=Figures]
+\setupheadtext [\s!it] [\v!figures=Figure]
+\setupheadtext [\s!la] [\v!figures=Imagines]
+\setupheadtext [\s!pt] [\v!figures=Figuras]
+\setupheadtext [\s!ro] [\v!figures=Figuri]
+
+\setupheadtext [\s!fr] [\v!graphics=Graphiques]
+\setupheadtext [\s!es] [\v!graphics=Gr\'aficos]
+\setupheadtext [\s!it] [\v!graphics=Grafici]
+\setupheadtext [\s!ca] [\v!graphics=Gr\`afiques]
+\setupheadtext [\s!la] [\v!graphics=Typi]
+\setupheadtext [\s!pt] [\v!graphics=Gr\'aficos]
+\setupheadtext [\s!ro] [\v!graphics=Grafice]
+
+\setupheadtext [\s!fr] [\v!intermezzi=Interm\`edes]
+\setupheadtext [\s!es] [\v!intermezzi=Intermedios]
+\setupheadtext [\s!ca] [\v!intermezzi=Intermedis]
+\setupheadtext [\s!it] [\v!intermezzi=Intermezzi]
+\setupheadtext [\s!la] [\v!intermezzi=Intermissa]
+\setupheadtext [\s!pt] [\v!intermezzi=Interm\'edios]
+\setupheadtext [\s!ro] [\v!intermezzi=Intermzzo]
+
+\setupheadtext [\s!fr] [\v!index=Index]
+\setupheadtext [\s!es] [\v!index=\'Indice alfab\'etico]
+\setupheadtext [\s!ca] [\v!index=\'Index alfab\`etic]
+\setupheadtext [\s!it] [\v!index=Indice]
+\setupheadtext [\s!la] [\v!index=Indices]
+\setupheadtext [\s!pt] [\v!index=\'Indice]
+\setupheadtext [\s!ro] [\v!index=Index]
+
+\setupheadtext [\s!fr] [\v!abbreviations=Abr\'eviations]
+\setupheadtext [\s!es] [\v!abbreviations=Abreviaturas]
+\setupheadtext [\s!ca] [\v!abbreviations=Abreviacions]
+\setupheadtext [\s!it] [\v!abbreviations=Abbreviazioni]
+\setupheadtext [\s!la] [\v!abbreviations=Notae]
+\setupheadtext [\s!pt] [\v!abbreviations=Abreviaturas]
+\setupheadtext [\s!ro] [\v!abbreviations=Abrevieri]
+
+\setupheadtext [\s!fr] [\v!logos=Logos]
+\setupheadtext [\s!es] [\v!logos=Logotipos]
+\setupheadtext [\s!ca] [\v!logos=Logotips]
+\setupheadtext [\s!it] [\v!logos=Logotipi]
+\setupheadtext [\s!la] [\v!logos=Typi negotiales]
+\setupheadtext [\s!pt] [\v!logos=Logotipos]
+\setupheadtext [\s!ro] [\v!logos=Logo-uri]
+
+\setupheadtext [\s!fr] [\v!units=Unit\'es]
+\setupheadtext [\s!es] [\v!units=Unidades]
+\setupheadtext [\s!ca] [\v!units=Unitats]
+\setupheadtext [\s!it] [\v!units=Unit\`a]
+\setupheadtext [\s!la] [\v!units=Modi]
+\setupheadtext [\s!pt] [\v!units=Unidades]
+\setupheadtext [\s!ro] [\v!units=Unit\u{a}\c{t}i]
+
+\setupheadtext [\s!fr] [pubs=Bibliographie]
+\setupheadtext [\s!es] [pubs=Bibliograf\'\ia]
+\setupheadtext [\s!ca] [pubs=Referències]
+\setupheadtext [\s!it] [pubs=Bibliografia]
+%setupheadtext [\s!la] [pubs=?]
+%setupheadtext [\s!pt] [pubs=?]
+%setupheadtext [\s!ro] [pubs=?]
+
+\setuplabeltext [\s!fr] [\v!table=Tableau ]
+\setuplabeltext [\s!es] [\v!table=Tabla ]
+\setuplabeltext [\s!ca] [\v!table=Taula ]
+\setuplabeltext [\s!it] [\v!table=Tabella ]
+\setuplabeltext [\s!la] [\v!table=Tabula ]
+\setuplabeltext [\s!pt] [\v!table=Tabela ]
+\setuplabeltext [\s!ro] [\v!table=Tabelul ]
+
+\setuplabeltext [\s!fr] [\v!figure=Figure ]
+\setuplabeltext [\s!es] [\v!figure=Ilustraci\'on ]
+\setuplabeltext [\s!ca] [\v!figure=Figura ]
+\setuplabeltext [\s!it] [\v!figure=Fig. ]
+\setuplabeltext [\s!la] [\v!figure=Imago ]
+\setuplabeltext [\s!pt] [\v!figure=Figura ]
+\setuplabeltext [\s!ro] [\v!figure=Figura ]
+
+\setuplabeltext [\s!fr] [\v!intermezzo=Interm\`ede ]
+\setuplabeltext [\s!es] [\v!intermezzo=Intermedio ]
+\setuplabeltext [\s!ca] [\v!intermezzo=Intermedi ]
+\setuplabeltext [\s!it] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!la] [\v!intermezzo=Intermissum ]
+\setuplabeltext [\s!pt] [\v!intermezzo=Interm\'edio ]
+\setuplabeltext [\s!ro] [\v!intermezzo=Intermezzo ]
+
+\setuplabeltext [\s!fr] [\v!graphic=Illustration ]
+\setuplabeltext [\s!es] [\v!graphic=Gr\'afico ]
+\setuplabeltext [\s!ca] [\v!graphic=Gr\`afica ]
+\setuplabeltext [\s!it] [\v!graphic=Grafico ]
+\setuplabeltext [\s!la] [\v!graphic=Typus ]
+\setuplabeltext [\s!pt] [\v!graphic=Gr\'afico ]
+\setuplabeltext [\s!ro] [\v!graphic=Graficul ]
+
+\setuplabeltext [\s!fr] [\v!chapter=] % Chapitre
+\setuplabeltext [\s!es] [\v!chapter=] % Cap\'\i tulo
+\setuplabeltext [\s!ca] [\v!chapter=] % Cap\'\i tol
+\setuplabeltext [\s!it] [\v!chapter=]
+\setuplabeltext [\s!la] [\v!chapter=]
+\setuplabeltext [\s!pt] [\v!chapter=]
+\setuplabeltext [\s!ro] [\v!chapter=]
+
+\setuplabeltext [\s!fr] [\v!section=] % Section
+\setuplabeltext [\s!es] [\v!section=] % Secci\'on
+\setuplabeltext [\s!ca] [\v!section=] % Secci\'o
+\setuplabeltext [\s!it] [\v!section=]
+\setuplabeltext [\s!la] [\v!section=]
+\setuplabeltext [\s!pt] [\v!section=]
+\setuplabeltext [\s!ro] [\v!section=]
+
+\setuplabeltext [\s!fr] [\v!subsection=] % Soussection
+\setuplabeltext [\s!es] [\v!subsection=] % Subsecci\'on
+\setuplabeltext [\s!ca] [\v!subsection=] % Subsecci\'o
+\setuplabeltext [\s!it] [\v!subsection=]
+\setuplabeltext [\s!la] [\v!subsection=]
+\setuplabeltext [\s!pt] [\v!subsection=]
+\setuplabeltext [\s!ro] [\v!subsection=]
+
+\setuplabeltext [\s!fr] [\v!subsubsection=] % Soussoussection
+\setuplabeltext [\s!es] [\v!subsubsection=] % Subsubsecci\'on
+\setuplabeltext [\s!ca] [\v!subsubsection=] % Subsubsecci\'o
+\setuplabeltext [\s!it] [\v!subsubsection=]
+\setuplabeltext [\s!la] [\v!subsubsection=]
+\setuplabeltext [\s!pt] [\v!subsubsection=]
+\setuplabeltext [\s!ro] [\v!subsubsection=]
+
+\setuplabeltext [\s!fr] [\v!subsubsubsection=] % Soussoussoussection
+\setuplabeltext [\s!es] [\v!subsubsubsection=] % Subsubsubsecci\'on
+\setuplabeltext [\s!ca] [\v!subsubsubsection=] % Subsubsubsecci\'o
+\setuplabeltext [\s!it] [\v!subsubsubsection=]
+\setuplabeltext [\s!la] [\v!subsubsubsection=]
+\setuplabeltext [\s!pt] [\v!subsubsubsection=]
+\setuplabeltext [\s!ro] [\v!subsubsubsection=]
+
+\setuplabeltext [\s!fr] [\v!appendix=] % Annexe
+\setuplabeltext [\s!es] [\v!appendix=] % Ap\'endice
+\setuplabeltext [\s!ca] [\v!appendix=] % Ap\`endix
+\setuplabeltext [\s!it] [\v!appendix=]
+\setuplabeltext [\s!la] [\v!appendix=]
+\setuplabeltext [\s!pt] [\v!appendix=]
+\setuplabeltext [\s!ro] [\v!appendix=]
+
+\setuplabeltext [\s!fr] [\v!part=Partie ]
+\setuplabeltext [\s!es] [\v!part=Parte ]
+\setuplabeltext [\s!ca] [\v!part=Part ]
+\setuplabeltext [\s!it] [\v!part=Parte ]
+\setuplabeltext [\s!la] [\v!part=Pars ]
+\setuplabeltext [\s!pt] [\v!part=Parte ]
+\setuplabeltext [\s!ro] [\v!part=Partea ]
+
+\setuplabeltext [\s!fr] [\v!line=ligne ]
+\setuplabeltext [\s!es] [\v!line=l\'\i nea ]
+\setuplabeltext [\s!ca] [\v!line=l\'\i nia ]
+\setuplabeltext [\s!it] [\v!line=riga ]
+\setuplabeltext [\s!la] [\v!line=versus ]
+\setuplabeltext [\s!pt] [\v!line=linha ]
+\setuplabeltext [\s!ro] [\v!line=linia ]
+
+\setuplabeltext [\s!fr] [\v!lines=lignes ]
+\setuplabeltext [\s!es] [\v!lines=l\'\i neas ]
+\setuplabeltext [\s!ca] [\v!lines=l\'\i nies ]
+\setuplabeltext [\s!it] [\v!lines=righe ]
+\setuplabeltext [\s!la] [\v!lines=versus ]
+\setuplabeltext [\s!pt] [\v!lines=linhas ]
+\setuplabeltext [\s!ro] [\v!lines=liniile ]
+
+\setuplabeltext [\s!fr] [\v!january=janvier]
+\setuplabeltext [\s!fr] [\v!february=f\'evrier]
+\setuplabeltext [\s!fr] [\v!march=mars]
+\setuplabeltext [\s!fr] [\v!april=avril]
+\setuplabeltext [\s!fr] [\v!may=mai]
+\setuplabeltext [\s!fr] [\v!june=juin]
+\setuplabeltext [\s!fr] [\v!july=juillet]
+\setuplabeltext [\s!fr] [\v!august=ao\^ut]
+\setuplabeltext [\s!fr] [\v!september=septembre]
+\setuplabeltext [\s!fr] [\v!october=octobre]
+\setuplabeltext [\s!fr] [\v!november=novembre]
+\setuplabeltext [\s!fr] [\v!december=d\'ecembre]
+
+\setuplabeltext [\s!es] [\v!january=enero]
+\setuplabeltext [\s!es] [\v!february=febrero]
+\setuplabeltext [\s!es] [\v!march=marzo]
+\setuplabeltext [\s!es] [\v!april=abril]
+\setuplabeltext [\s!es] [\v!may=mayo]
+\setuplabeltext [\s!es] [\v!june=junio]
+\setuplabeltext [\s!es] [\v!july=julio]
+\setuplabeltext [\s!es] [\v!august=agosto]
+\setuplabeltext [\s!es] [\v!september=septiembre]
+\setuplabeltext [\s!es] [\v!october=octubre]
+\setuplabeltext [\s!es] [\v!november=noviembre]
+\setuplabeltext [\s!es] [\v!december=diciembre]
+
+\setuplabeltext [\s!ca] [\v!january=gener]
+\setuplabeltext [\s!ca] [\v!february=febrer]
+\setuplabeltext [\s!ca] [\v!march=mar\c{c}]
+\setuplabeltext [\s!ca] [\v!april=abril]
+\setuplabeltext [\s!ca] [\v!may=maig]
+\setuplabeltext [\s!ca] [\v!june=juny]
+\setuplabeltext [\s!ca] [\v!july=juliol]
+\setuplabeltext [\s!ca] [\v!august=agost]
+\setuplabeltext [\s!ca] [\v!september=setembre]
+\setuplabeltext [\s!ca] [\v!october=octubre]
+\setuplabeltext [\s!ca] [\v!november=novembre]
+\setuplabeltext [\s!ca] [\v!december=desembre]
+
+\setuplabeltext [\s!it] [\v!january=gennaio]
+\setuplabeltext [\s!it] [\v!february=febbraio]
+\setuplabeltext [\s!it] [\v!march=marzo]
+\setuplabeltext [\s!it] [\v!april=aprile]
+\setuplabeltext [\s!it] [\v!may=maggio]
+\setuplabeltext [\s!it] [\v!june=giugno]
+\setuplabeltext [\s!it] [\v!july=luglio]
+\setuplabeltext [\s!it] [\v!august=agosto]
+\setuplabeltext [\s!it] [\v!september=settembre]
+\setuplabeltext [\s!it] [\v!october=ottobre]
+\setuplabeltext [\s!it] [\v!november=novembre]
+\setuplabeltext [\s!it] [\v!december=dicembre]
+
+\setuplabeltext [\s!la] [\v!january=Ianuarius]
+\setuplabeltext [\s!la] [\v!february=Februarius]
+\setuplabeltext [\s!la] [\v!march=Martius]
+\setuplabeltext [\s!la] [\v!april=Aprilis]
+\setuplabeltext [\s!la] [\v!may=Maius]
+\setuplabeltext [\s!la] [\v!june=Iunius]
+\setuplabeltext [\s!la] [\v!july=Iulius] % formerly Quintilis
+\setuplabeltext [\s!la] [\v!august=Augustus] % formerly Sextilis
+\setuplabeltext [\s!la] [\v!september=September]
+\setuplabeltext [\s!la] [\v!october=October]
+\setuplabeltext [\s!la] [\v!november=November]
+\setuplabeltext [\s!la] [\v!december=December]
+
+\setuplabeltext [\s!pt] [\v!january=janeiro]
+\setuplabeltext [\s!pt] [\v!february=fevereiro]
+\setuplabeltext [\s!pt] [\v!march=mar\c{c}o]
+\setuplabeltext [\s!pt] [\v!april=abril]
+\setuplabeltext [\s!pt] [\v!may=maio]
+\setuplabeltext [\s!pt] [\v!june=junho]
+\setuplabeltext [\s!pt] [\v!july=julho]
+\setuplabeltext [\s!pt] [\v!august=agosto]
+\setuplabeltext [\s!pt] [\v!september=setembro]
+\setuplabeltext [\s!pt] [\v!october=outubro]
+\setuplabeltext [\s!pt] [\v!november=novembro]
+\setuplabeltext [\s!pt] [\v!december=dezembro]
+
+\setuplabeltext [\s!ro] [\v!january=ianuarie]
+\setuplabeltext [\s!ro] [\v!february=februarie]
+\setuplabeltext [\s!ro] [\v!march=martie]
+\setuplabeltext [\s!ro] [\v!april=aprilie]
+\setuplabeltext [\s!ro] [\v!may=mai]
+\setuplabeltext [\s!ro] [\v!june=iunie]
+\setuplabeltext [\s!ro] [\v!july=iulie]
+\setuplabeltext [\s!ro] [\v!august=august]
+\setuplabeltext [\s!ro] [\v!september=septembrie]
+\setuplabeltext [\s!ro] [\v!october=octombrie]
+\setuplabeltext [\s!ro] [\v!november=noiembrie]
+\setuplabeltext [\s!ro] [\v!december=decembrie]
+
+\setuplabeltext [\s!fr] [\v!sunday=dimanche]
+\setuplabeltext [\s!fr] [\v!monday=lundi]
+\setuplabeltext [\s!fr] [\v!tuesday=mardi]
+\setuplabeltext [\s!fr] [\v!wednesday=mercredi]
+\setuplabeltext [\s!fr] [\v!thursday=jeudi]
+\setuplabeltext [\s!fr] [\v!friday=vendredi]
+\setuplabeltext [\s!fr] [\v!saturday=samedi]
+
+\setuplabeltext [\s!es] [\v!sunday=domingo]
+\setuplabeltext [\s!es] [\v!monday=lunes]
+\setuplabeltext [\s!es] [\v!tuesday=martes]
+\setuplabeltext [\s!es] [\v!wednesday=mi\'ercoles]
+\setuplabeltext [\s!es] [\v!thursday=jueves]
+\setuplabeltext [\s!es] [\v!friday=viernes]
+\setuplabeltext [\s!es] [\v!saturday=s\'abado]
+
+\setuplabeltext [\s!ca] [\v!sunday=diumenge]
+\setuplabeltext [\s!ca] [\v!monday=dilluns]
+\setuplabeltext [\s!ca] [\v!tuesday=dimarts]
+\setuplabeltext [\s!ca] [\v!wednesday=dimecres]
+\setuplabeltext [\s!ca] [\v!thursday=dijous]
+\setuplabeltext [\s!ca] [\v!friday=divendres]
+\setuplabeltext [\s!ca] [\v!saturday=dissabte]
+
+\setuplabeltext [\s!it] [\v!sunday=domenica]
+\setuplabeltext [\s!it] [\v!monday=luned\`\i]
+\setuplabeltext [\s!it] [\v!tuesday=marted\`\i]
+\setuplabeltext [\s!it] [\v!wednesday=mercoled\`\i]
+\setuplabeltext [\s!it] [\v!thursday=gioved\`\i]
+\setuplabeltext [\s!it] [\v!friday=venerd\`\i]
+\setuplabeltext [\s!it] [\v!saturday=sabato]
+
+\setuplabeltext [\s!la] [\v!sunday=Dies Solis]
+\setuplabeltext [\s!la] [\v!monday=Dies Lunae]
+\setuplabeltext [\s!la] [\v!tuesday=Dies Martis]
+\setuplabeltext [\s!la] [\v!wednesday=Dies Mercuri]
+\setuplabeltext [\s!la] [\v!thursday=Dies Iovis]
+\setuplabeltext [\s!la] [\v!friday=Dies Veneris]
+\setuplabeltext [\s!la] [\v!saturday=Dies Saturni]
+
+\setuplabeltext [\s!pt] [\v!sunday=domingo]
+\setuplabeltext [\s!pt] [\v!monday=segunda-feira]
+\setuplabeltext [\s!pt] [\v!tuesday=ter\c{c}a-feira]
+\setuplabeltext [\s!pt] [\v!wednesday=quarta-feira]
+\setuplabeltext [\s!pt] [\v!thursday=quinta-feira]
+\setuplabeltext [\s!pt] [\v!friday=sexta-feira]
+\setuplabeltext [\s!pt] [\v!saturday=s\'abado]
+
+\setuplabeltext [\s!ro] [\v!sunday=duminic\u{a}]
+\setuplabeltext [\s!ro] [\v!monday=luni]
+\setuplabeltext [\s!ro] [\v!tuesday=mar\c{t}i]
+\setuplabeltext [\s!ro] [\v!wednesday=miercuri]
+\setuplabeltext [\s!ro] [\v!thursday=joi]
+\setuplabeltext [\s!ro] [\v!friday=vineri]
+\setuplabeltext [\s!ro] [\v!saturday=s\^{a}mb\u{a}t\u{a}]
+
+%D Rather new \unknown
+
+\setuplabeltext [\s!it] [\v!page=pagina ]
+\setuplabeltext [\s!it] [\v!atpage=a pagina ]
+\setuplabeltext [\s!it] [\v!hencefore=come mostrato sopra]
+\setuplabeltext [\s!it] [\v!hereafter=come mostrato sotto]
+\setuplabeltext [\s!it] [\v!see=cf. ]
+
+\setuplabeltext [\s!fr] [\v!page=page ]
+\setuplabeltext [\s!fr] [\v!atpage=à la page ]
+\setuplabeltext [\s!fr] [\v!hencefore=ci-dessus]
+\setuplabeltext [\s!fr] [\v!hereafter=ci-dessous]
+\setuplabeltext [\s!fr] [\v!see=cf. ]
+
+%D Ordinal converters:
+
+\def\frordinaldaynumber#1% date is masculine
+ {\number#1\ifcase#1\or
+ \highordinalstr{er}%
+ \fi}
+
+\defineconversion [\s!fr] [\v!day+] [\frordinaldaynumber]
+
+%D \ShowAllLanguageValues [\s!fr] [french] {French} {kiss} % franse slag
+%D \ShowAllLanguageValues [\s!es] [spanish] {Spanish} {guitar} % spaans benauwd
+%D \ShowAllLanguageValues [\s!ca] [catalan] {Catalan} {cream}
+%D \ShowAllLanguageValues [\s!it] [italian] {Italian} {aria}
+%D \ShowAllLanguageValues [\s!la] [latin] {Latin} {lover} % latijnse missen
+%D \ShowAllLanguageValues [\s!pt] [portuguese] {Portuguese} {fisherman}
+%D \ShowAllLanguageValues [\s!ro] [romanian] {Romanian} {traveller}
+
+\protect \endinput
diff --git a/tex/context/base/lang-jap.mkii b/tex/context/base/lang-jap.mkii
new file mode 100644
index 000000000..05c9b1d41
--- /dev/null
+++ b/tex/context/base/lang-jap.mkii
@@ -0,0 +1,234 @@
+%D \module
+%D [ file=lang-jap,
+%D version=2006.01.13,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Japanese,
+%D author={Richard Gabriel},
+%D date=\currentdate,
+%D copyright={PRAGMA / RG}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% rgabriel@kerio.com
+
+\writestatus{loading}{ConTeXt Language Macros / Japanese}
+
+\unprotect
+
+\definesystemconstant {japanese} \definesystemconstant {ja}
+
+\installlanguage
+ [\s!ja]
+ [\c!leftsentence=\jaencoding\jaleftsentence,
+ \c!rightsentence=\jaencoding\jarightsentence,
+ \c!leftsubsentence=\jaencoding\jaleftsubsentence,
+ \c!rightsubsentence=\jaencoding\jarightsubsentence,
+ \c!leftquote=\jaencoding\jaencodedsinglestartquote,
+ \c!rightquote=\jaencoding\jaencodedsingleendquote,
+ \c!leftquotation=\jaencoding\jaencodedstartquote,
+ \c!rightquotation=\jaencoding\jaencodedendquote,
+ \c!date={\jaencodedchristiandate,\v!year,\jaencodedyear,\v!month,\jaencodedmonth,\v!day,\jaencodedday}]
+
+\setupheadtext [\s!ja] [\v!content={\jaencoding\jaencodedtableofcontents}]
+\setupheadtext [\s!ja] [\v!tables={\jaencoding\jaencodedtables}]
+\setupheadtext [\s!ja] [\v!figures={\jaencoding\jaencodedfigures}]
+\setupheadtext [\s!ja] [\v!graphics={\jaencoding\jaencodedgraphics}]
+\setupheadtext [\s!ja] [\v!intermezzi={\jaencoding\jaencodedintermezzos}]
+\setupheadtext [\s!ja] [\v!index={\jaencoding\jaencodedindex}]
+\setupheadtext [\s!ja] [\v!abbreviations={\jaencoding\jaencodedabbreviations}]
+\setupheadtext [\s!ja] [\v!logos={\jaencoding\jaencodedlogos}]
+\setupheadtext [\s!ja] [\v!units={\jaencoding\jaencodedunits}]
+
+\setuplabeltext [\s!ja] [\v!table={\jaencoding\jaencodedtable}]
+\setuplabeltext [\s!ja] [\v!figure={\jaencoding\jaencodedfigure}]
+\setuplabeltext [\s!ja] [\v!intermezzo={\jaencoding\jaencodedintermezzo}]
+\setuplabeltext [\s!ja] [\v!graphic={\jaencoding\jaencodedillustration}]
+\setuplabeltext [\s!ja] [\v!appendix={\jaencoding\jaencodedappendix}]
+\setuplabeltext [\s!ja] [\v!part={\jaencoding\jaencodedintro,\jaencoding\jaencodedpart}]
+\setuplabeltext [\s!ja] [\v!chapter={\jaencoding\jaencodedintro,\jaencoding\jaencodedchapter}]
+\setuplabeltext [\s!ja] [\v!section={\jaencoding\jaencodedintro,\jaencoding\jaencodedsection}]
+\setuplabeltext [\s!ja] [\v!line={\jaencoding\jaencodedline}]
+\setuplabeltext [\s!ja] [\v!lines={\jaencoding\jaencodedline}]
+
+\setuplabeltext [\s!ja] [\v!subsection=]
+\setuplabeltext [\s!ja] [\v!subsubsection=]
+\setuplabeltext [\s!ja] [\v!subsubsubsection=]
+
+%D Why are these languagespecifics ?
+
+\setuplabeltext [\s!ja] [\v!january=1]
+\setuplabeltext [\s!ja] [\v!february=2]
+\setuplabeltext [\s!ja] [\v!march=3]
+\setuplabeltext [\s!ja] [\v!april=4]
+\setuplabeltext [\s!ja] [\v!may=5]
+\setuplabeltext [\s!ja] [\v!june=6]
+\setuplabeltext [\s!ja] [\v!july=7]
+\setuplabeltext [\s!ja] [\v!august=8]
+\setuplabeltext [\s!ja] [\v!september=9]
+\setuplabeltext [\s!ja] [\v!october=10]
+\setuplabeltext [\s!ja] [\v!november=11]
+\setuplabeltext [\s!ja] [\v!december=12]
+
+\setuplabeltext [\s!ja] [\v!sunday=\jaencoding\jaencodedsunday ]
+\setuplabeltext [\s!ja] [\v!monday=\jaencoding\jaencodedmonday ]
+\setuplabeltext [\s!ja] [\v!tuesday=\jaencoding\jaencodedtuesday ]
+\setuplabeltext [\s!ja] [\v!wednesday=\jaencoding\jaencodedwednesday]
+\setuplabeltext [\s!ja] [\v!thursday=\jaencoding\jaencodedthursday ]
+\setuplabeltext [\s!ja] [\v!friday=\jaencoding\jaencodedfriday ]
+\setuplabeltext [\s!ja] [\v!saturday=\jaencoding\jaencodedsaturday ]
+
+% Hardcoded - \japaneseencoding should be defined similarly to \chineseencoding
+
+\unexpanded\def\jaencoding{\enableencoding[cjk-uni]}
+
+%D This list is taken from DocBook XSL stylesheets (http://docbook.sourceforge.net/).
+
+\startencoding[cjk-uni]
+
+ \definecommand jaencodedabstract {\uchar{105}{130}\uchar{137}{129}}
+ \definecommand jaencodedand {\uchar{48}{1}}
+ \definecommand jaencodedanswer {\uchar{123}{84}\uchar{255}{26}}
+ \definecommand jaencodedappendix {\uchar{78}{216}\uchar{147}{50}}
+ \definecommand jaencodedarticle {\uchar{152}{5}\uchar{118}{238}}
+ \definecommand jaencodedbibliography {\uchar{83}{194}\uchar{128}{3}\uchar{101}{135}\uchar{115}{46}}
+ \definecommand jaencodedbook {\uchar{48}{214}\uchar{48}{195}\uchar{48}{175}}
+ \definecommand jaencodedbridgehead {\uchar{152}{5}}
+ \definecommand jaencodedbullet {\uchar{37}{207}}
+ \definecommand jaencodedby {\uchar{255}{26}}
+ \definecommand jaencodedcaution {\uchar{108}{232}\uchar{97}{15}}
+ \definecommand jaencodedcolophon {\uchar{89}{101}\uchar{78}{216}}
+ \definecommand jaencodedcopyright {\uchar{136}{253}\uchar{79}{92}\uchar{132}{87}\uchar{79}{92}}
+ \definecommand jaencodeddedication {\uchar{139}{29}\uchar{143}{158}}
+ \definecommand jaencodededited {\uchar{125}{232}\uchar{128}{5}}
+ \definecommand jaencodededitedby {\uchar{125}{232}\uchar{128}{5}\uchar{255}{26}}
+ \definecommand jaencodededition {\uchar{125}{232}\uchar{150}{198}}
+ \definecommand jaencodedendquote {\uchar{48}{13}}
+ \definecommand jaencodedequation {\uchar{95}{15}}
+ \definecommand jaencodedexample {\uchar{79}{139}}
+ \definecommand jaencodedfigure {\uchar{86}{243}}
+ \definecommand jaencodedglossary {\uchar{117}{40}\uchar{138}{158}\uchar{150}{198}}
+ \definecommand jaencodedglosssee {\uchar{83}{194}\uchar{113}{103}}
+ \definecommand jaencodedglossseealso {\uchar{83}{194}\uchar{113}{103}}
+ \definecommand jaencodedchapter {\uchar{122}{224}}
+ \definecommand jaencodedimportant {\uchar{145}{205}\uchar{137}{129}\uchar{152}{5}\uchar{118}{238}}
+ \definecommand jaencodedindex {\uchar{118}{238}\uchar{107}{33}}
+ \definecommand jaencodedindexsymbols {\uchar{48}{183}\uchar{48}{243}\uchar{48}{220}\uchar{48}{235}}
+ \definecommand jaencodedintro {\uchar{123}{44}}
+ \definecommand jaencodedlistofequations {\uchar{95}{15}\uchar{118}{238}\uchar{107}{33}}
+ \definecommand jaencodedlistofexamples {\uchar{79}{139}\uchar{118}{238}\uchar{107}{33}}
+ \definecommand jaencodedlistoffigures {\uchar{86}{243}\uchar{118}{238}\uchar{107}{33}}
+ \definecommand jaencodedlistoftables {\uchar{136}{104}\uchar{118}{238}\uchar{107}{33}}
+ \definecommand jaencodedlistofunknown {\uchar{78}{13}\uchar{102}{14}\uchar{118}{238}\uchar{107}{33}}
+ \definecommand jaencodedmsgaud {\uchar{91}{254}\uchar{140}{97}\uchar{128}{5}}
+ \definecommand jaencodedmsglevel {\uchar{48}{236}\uchar{48}{217}\uchar{48}{235}}
+ \definecommand jaencodedmsgorig {\uchar{118}{122}\uchar{79}{225}\uchar{81}{67}}
+ \definecommand jaencodednavhome {\uchar{48}{219}\uchar{48}{252}\uchar{48}{224}}
+ \definecommand jaencodednavnext {\uchar{107}{33}\uchar{48}{110}\uchar{48}{218}\uchar{48}{252}\uchar{48}{184}}
+ \definecommand jaencodednavnextsibling {\uchar{101}{233}\uchar{144}{1}\uchar{48}{138}}
+ \definecommand jaencodednavprev {\uchar{82}{77}\uchar{48}{110}\uchar{48}{218}\uchar{48}{252}\uchar{48}{184}}
+ \definecommand jaencodednavprevsibling {\uchar{93}{251}\uchar{98}{59}\uchar{48}{87}}
+ \definecommand jaencodednavup {\uchar{78}{10}\uchar{48}{107}\uchar{98}{59}\uchar{48}{139}}
+ \definecommand jaencodednestedendquote {\uchar{48}{15}}
+ \definecommand jaencodednestedstartquote {\uchar{48}{14}}
+ \definecommand jaencodednonexistantelement {\uchar{137}{129}\uchar{125}{32}\uchar{48}{76}\uchar{91}{88}\uchar{87}{40}\uchar{48}{87}\uchar{48}{126}\uchar{48}{91}\uchar{48}{147}}
+ \definecommand jaencodednote {\uchar{108}{232}\uchar{97}{15}}
+ \definecommand jaencodednotes {\uchar{108}{232}\uchar{97}{15}}
+ \definecommand jaencodedpages {\uchar{80}{103}\uchar{115}{46}}
+ \definecommand jaencodedpart {\uchar{48}{209}\uchar{48}{252}\uchar{48}{200}}
+ \definecommand jaencodedpreface {\uchar{94}{143}\uchar{101}{135}}
+ \definecommand jaencodedprocedure {\uchar{98}{75}\uchar{152}{6}}
+ \definecommand jaencodedprocedureformal {\uchar{98}{75}\uchar{152}{6}}
+ \definecommand jaencodedproductionset {\uchar{48}{215}\uchar{48}{237}\uchar{48}{192}\uchar{48}{175}\uchar{48}{183}\uchar{48}{231}\uchar{48}{243}}
+ \definecommand jaencodedproductionsetformal {\uchar{48}{215}\uchar{48}{237}\uchar{48}{192}\uchar{48}{175}\uchar{48}{183}\uchar{48}{231}\uchar{48}{243}}
+ \definecommand jaencodedpublished {\uchar{118}{122}\uchar{136}{76}}
+ \definecommand jaencodedqandadiv {\uchar{85}{79}\uchar{255}{26}\uchar{48}{1}\uchar{123}{84}\uchar{255}{26}}
+ \definecommand jaencodedqandaentry {\uchar{85}{79}\uchar{255}{26}}
+ \definecommand jaencodedquestion {\uchar{85}{79}\uchar{255}{26}}
+ \definecommand jaencodedreference {\uchar{83}{194}\uchar{113}{103}}
+ \definecommand jaencodedrefname {\uchar{84}{13}\uchar{82}{77}}
+ \definecommand jaencodedrefsection {\uchar{152}{5}}
+ \definecommand jaencodedrefsynopsisdiv {\uchar{105}{130}\uchar{137}{129}}
+ \definecommand jaencodedrevhistory {\uchar{101}{57}\uchar{138}{2}\uchar{92}{101}\uchar{107}{116}}
+ \definecommand jaencodedrevision {\uchar{101}{57}\uchar{138}{2}}
+ \definecommand jaencodedsection {\uchar{152}{5}}
+ \definecommand jaencodedsee {\uchar{83}{194}\uchar{113}{103}}
+ \definecommand jaencodedseealso {\uchar{83}{194}\uchar{113}{103}}
+ \definecommand jaencodedseparator {\uchar{48}{1}}
+ \definecommand jaencodedset {\uchar{138}{45}\uchar{91}{154}}
+ \definecommand jaencodedsetindex {\uchar{118}{238}\uchar{107}{33}\uchar{138}{45}\uchar{91}{154}}
+ \definecommand jaencodedsidebar {\uchar{48}{181}\uchar{48}{164}\uchar{48}{201}\uchar{48}{208}\uchar{48}{252}}
+ \definecommand jaencodedsimplesect {\uchar{152}{5}}
+ \definecommand jaencodedsingleendquote {\uchar{32}{25}}
+ \definecommand jaencodedsinglestartquote {\uchar{32}{24}}
+ \definecommand jaencodedstartquote {\uchar{48}{12}}
+ \definecommand jaencodedstep {\uchar{48}{185}\uchar{48}{198}\uchar{48}{195}\uchar{48}{215}}
+ \definecommand jaencodedtable {\uchar{136}{104}}
+ \definecommand jaencodedtablenotes {\uchar{108}{232}\uchar{97}{15}}
+ \definecommand jaencodedtableofcontents {\uchar{118}{238}\uchar{107}{33}}
+ \definecommand jaencodedtip {\uchar{48}{198}\uchar{48}{163}\uchar{48}{195}\uchar{48}{215}}
+ \definecommand jaencodedunexpectedelementname {\uchar{78}{13}\uchar{102}{14}\uchar{48}{106}\uchar{137}{129}\uchar{125}{32}\uchar{84}{13}}
+ \definecommand jaencodedunsupported {\uchar{48}{181}\uchar{48}{221}\uchar{48}{252}\uchar{48}{200}\uchar{48}{87}\uchar{48}{126}\uchar{48}{91}\uchar{48}{147}}
+ \definecommand jaencodedwarning {\uchar{139}{102}\uchar{84}{74}}
+
+ \definecommand jaencodedyear {\uchar{94}{116}}
+ \definecommand jaencodedmonth {\uchar{103}{8}}
+ \definecommand jaencodedday {\uchar{101}{229}}
+
+\stopencoding
+
+%D Taken from Chinese (will be investigated yet...)
+
+\startencoding[cjk-uni]
+
+ \definecommand jaencodedleftsentence {\uchar{32}{20}\uchar{32}{20}}
+ \definecommand jaencodedrightsentence {\uchar{32}{20}\uchar{32}{20}}
+ \definecommand jaencodedleftsubsentence {\uchar{32}{20}\uchar{32}{20}}
+ \definecommand jaencodedrightsubsentence {\uchar{32}{20}\uchar{32}{20}}
+
+\stopencoding
+
+%D Special thanxx to Eizo Tsuchihashi (eizo@arcbrain.jp) for the following stuff
+
+\startencoding[cjk-uni]
+
+ \definecommand jaencodedchristiandate {\uchar{137}{127}\uchar{102}{166}}
+
+ \definecommand jaencodedtables {\uchar{103}{58}}
+ \definecommand jaencodedfigures {\uchar{86}{243}}
+ \definecommand jaencodedabbreviations {\uchar{117}{101}\uchar{138}{158}}
+ \definecommand jaencodedlogos {\uchar{116}{6}\uchar{96}{39}}
+ \definecommand jaencodedunits {\uchar{48}{230}\uchar{48}{203}\uchar{48}{195}\uchar{48}{196}}
+
+ \definecommand jaencodedgraphics {\uchar{48}{176}\uchar{48}{233}\uchar{48}{213}}
+ \definecommand jaencodedintermezzo {\uchar{149}{147}\uchar{89}{79}\uchar{102}{242}}
+ \definecommand jaencodedintermezzos {\uchar{149}{147}\uchar{89}{79}\uchar{102}{242}}
+ \definecommand jaencodedillustration {\uchar{48}{164}\uchar{48}{233}\uchar{48}{185}\uchar{48}{200}}
+ \definecommand jaencodedline {\uchar{125}{218}}
+ \definecommand jaencodedlines {\uchar{125}{218}}
+
+ \definecommand jaencodedjanuary {\uchar{78}{0}\uchar{103}{8}}
+ \definecommand jaencodedfebruary {\uchar{78}{140}\uchar{103}{8}}
+ \definecommand jaencodedmarch {\uchar{78}{9}\uchar{103}{8}}
+ \definecommand jaencodedapril {\uchar{86}{219}\uchar{103}{8}}
+ \definecommand jaencodedmay {\uchar{78}{148}\uchar{103}{8}}
+ \definecommand jaencodedjune {\uchar{81}{109}\uchar{103}{8}}
+ \definecommand jaencodedjuly {\uchar{78}{3}\uchar{103}{8}}
+ \definecommand jaencodedaugust {\uchar{81}{107}\uchar{103}{8}}
+ \definecommand jaencodedseptember {\uchar{78}{93}\uchar{103}{8}}
+ \definecommand jaencodedoctober {\uchar{83}{65}\uchar{103}{8}}
+ \definecommand jaencodednovember {\uchar{83}{65}\uchar{78}{0}\uchar{103}{8}}
+ \definecommand jaencodeddecember {\uchar{83}{65}\uchar{78}{140}\uchar{103}{8}}
+
+ \definecommand jaencodedsunday {\uchar{103}{8}\uchar{102}{220}\uchar{101}{229}}
+ \definecommand jaencodedmonday {\uchar{112}{107}\uchar{102}{220}\uchar{101}{229}}
+ \definecommand jaencodedtuesday {\uchar{108}{52}\uchar{102}{220}\uchar{101}{229}}
+ \definecommand jaencodedwednesday {\uchar{103}{40}\uchar{102}{220}\uchar{101}{229}}
+ \definecommand jaencodedthursday {\uchar{145}{209}\uchar{102}{220}\uchar{101}{229}}
+ \definecommand jaencodedfriday {\uchar{87}{31}\uchar{102}{220}\uchar{101}{229}}
+ \definecommand jaencodedsaturday {\uchar{101}{229}\uchar{102}{220}\uchar{101}{229}}
+
+\stopencoding
+
+\protect \endinput
diff --git a/tex/context/base/lang-lab.mkii b/tex/context/base/lang-lab.mkii
new file mode 100644
index 000000000..269ac249b
--- /dev/null
+++ b/tex/context/base/lang-lab.mkii
@@ -0,0 +1,295 @@
+%D \module
+%D [ file=lang-lab,
+%D version=1997.08.27,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Labels,
+%D author=Hans Hagen / Tobias Burnus,
+%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.
+
+\unprotect
+
+%D In this module we deal with language dependant labels and
+%D prefixes, like in {\em Figure~12} and {\em Chapter 1}. In
+%D this file we set the default values. Users can easily
+%D overrule these.
+%D
+%D This module is dedicated to the grandfather of Tobias
+%D Burnus, who's extensive languages oriented library helped us
+%D a lot in finding the right translations. All those labels
+%D are collected in files that reflect their common ancestor.
+%D
+%D Not all languages can be satisfied with the labeling
+%D mechanism as provided here. Chinese for instance put a label
+%D in front as well as after a part number. This is why the
+%D current implementation of labels supports two labels too.
+
+%D \macros
+%D {setupheadtext, setuplabeltext}
+%D
+%D First we present some macros that deal with what we will
+%D call head and label texts. Such texts are defines by:
+%D
+%D \showsetup{setupheadtext}
+%D \showsetup{setuplabeltext}
+%D
+%D In a few paragraphs we'll show quite a lot of examples
+%D of its use.
+
+\let\handletextprefix\relax
+
+\def\setupheadtext {\dosetupsometextprefix[\c!title]}
+\def\setuplabeltext{\dosetupsometextprefix[\c!label]}
+
+\def\dosetupsometextprefix
+ {\let\dodocommand\xdosetupsometextprefix
+ \dotripleempty\dodosetupsometextprefix}
+
+% \def\dodosetupsometextprefix[#1][#2][#3]%
+% {\ifthirdargument
+% \def\docommand##1{\dodocommand[#1#2][##1]}%
+% \processcommalist[#3]\docommand
+% \else
+% \def\docommand##1{\dodocommand[#1\currentmainlanguage][##1]}%
+% \processcommalist[#2]\docommand
+% \fi}
+
+\def\dodosetupsometextprefix[#1][#2][#3]%
+ {\ifthirdargument
+ \def\docommand##1{\expanded{\dodocommand[#1\reallanguagetag{#2}]}[##1]}%
+ \processcommalist[#3]\docommand
+ \else
+ \def\docommand##1{\expanded{\dodocommand[#1\reallanguagetag\currentmainlanguage]}[##1]}%
+ \processcommalist[#2]\docommand
+ \fi}
+
+\def\doassignsometextprefix[#1][#2,#3,#4]%
+ {\setvalue{#1}{\handletextprefix{#2}{#3}}}
+
+\def\xdosetupsometextprefix[#1][#2=#3]%
+ {\doassignsometextprefix[#1#2][#3,,]}
+
+%D By changing the meaning of \type {\handletextprefix} we
+%D can filter the left and right labeltext as well as convert
+%D labels to uppercase.
+%D
+%D These commands accept all kind of inputs:
+%D
+%D \starttyping
+%D \setuplabeltext [language] [labellabel=text]
+%D \setuplabeltext [language] [labellabel=text,labellabel=text,...]
+%D \setuplabeltext [labellabel=text]
+%D \setuplabeltext [labellabel=text,labellabel=text,...]
+%D \stoptyping
+%D
+%D The last two cases concern the current language.
+
+%D \macros
+%D {headtext,
+%D labeltext, leftlabeltext, rightlabeltext, labeltexts,
+%D LABELTEXT, LEFTLABELTEXT, RIGHTLABELTEXT, LABELTEXTS}
+%D
+%D Once defined, head and label texts can be called upon using:
+%D
+%D \showsetup{headtext}
+%D \showsetup{labeltext}
+%D
+%D The latter one has an upcased alternative \type{\LABELTEXT}.
+
+% \def\labellanguage{\currentmainlanguage}
+% \def\headlanguage {\currentmainlanguage}
+
+% \def\labellanguage{\defaultlanguage\currentmainlanguage}
+% \def\headlanguage {\defaultlanguage\currentmainlanguage}
+
+\def\labellanguage{\reallanguagetag{\defaultlanguage\currentmainlanguage}}
+\def\headlanguage {\reallanguagetag{\defaultlanguage\currentmainlanguage}}
+
+\appendtoks \let\labellanguage\currentlanguage \to \everycurrentdate
+
+\unexpanded\def\headtext
+ {\let\handletextprefix\firstoftwoarguments
+ \let\reporttextprefixerror\doreporttextprefixerror
+ \global\labeltextdonetrue
+ \dogetupsometextprefix\headlanguage\c!title}
+
+\unexpanded\def\leftlabeltext
+ {\let\handletextprefix\firstoftwoarguments
+ \let\reporttextprefixerror\doreporttextprefixerror
+ \global\labeltextdonetrue
+ \dogetupsometextprefix\labellanguage\c!label}
+
+\unexpanded\def\rightlabeltext
+ {\let\handletextprefix\secondoftwoarguments
+ \let\reporttextprefixerror\doreporttextprefixerror
+ \global\labeltextdonetrue
+ \dogetupsometextprefix\labellanguage\c!label}
+
+\unexpanded\def\LEFTLABELTEXT
+ {\def\handletextprefix##1##2{\uppercase{##1}}\DOLABELTEXT}
+
+\unexpanded\def\RIGHTLABELTEXT
+ {\def\handletextprefix##1##2{\uppercase{##2}}\DOLABELTEXT}
+
+\def\DOLABELTEXT#1%
+ {\bgroup
+ \the\everyuppercase
+ \let\reporttextprefixerror\doreporttextprefixerror
+ \global\labeltextdonetrue
+ \dogetupsometextprefix\labellanguage\c!label{#1}% not \labeltext (see \MONTH)
+ \egroup}
+
+\let\labeltext \leftlabeltext
+\let\LABELTEXT \LEFTLABELTEXT
+
+\unexpanded\def\labeltexts#1#2{\leftlabeltext{#1}#2\rightlabeltext{#1}}
+\unexpanded\def\LABELTEXTS#1#2{\LEFTLABELTEXT{#1}#2\RIGHTLABELTEXT{#1}}
+
+\newif\iflabeltextdone % needs to be reset elsewhere
+\newif\iftracelabels % shows missing labels
+
+\def\doreporttextprefixerror#1#2#3%
+ {\iftracelabels{\tttf[#2:~#3/#1]~}\fi}
+
+\def\dosetexpandedheadlabeltext#1#2#3%
+ {\bgroup
+ \let\handletextprefix\firstoftwoarguments
+ \let\reporttextprefixerror\gobblethreearguments
+ \keepencodedtokens % test on multilingual pascal, ok in stretched
+ %\dontexpandencodedtokens % not usable in token handler
+ \expanded
+ {\egroup\noexpand\def\noexpand#2% watch out, no \edef
+ {\dogetupsometextprefix{\headlanguage}{#1}{#3}}}}
+
+\def\setexpandedheadtext {\dosetexpandedheadlabeltext\c!title}
+\def\setexpandedlabeltext{\dosetexpandedheadlabeltext\c!label}
+
+% \def\dogetupsometextprefix#1#2#3%
+% {\ifcsname#2#1#3\endcsname
+% \csname#2#1#3\endcsname \else
+% \ifcsname#2#3\endcsname
+% \csname#2#3\endcsname \else
+% \ifcsname#2\defaultlanguage#1#3\endcsname
+% \csname#2\defaultlanguage#1#3\endcsname \else
+% \ifcsname#2\s!en#3\endcsname
+% \csname#2\s!en#3\endcsname \else
+% \ifcsname#2\s!nl#3\endcsname
+% \csname#2\s!nl#3\endcsname \else
+% \reporttextprefixerror{#1}{#2}{#3}%
+% \fi\fi\fi\fi\fi}
+%
+% \def\dogetupsometextprefix#1#2#3% must be expandable !
+% {\ifcsname#2#1#3\endcsname
+% \csname#2#1#3\endcsname
+% \else\@EA\ifx\csname\??la#1\c!default\endcsname\empty
+% \ifcsname#2#3\endcsname
+% \csname#2#3\endcsname
+% \else\ifcsname#2\s!en#3\endcsname
+% \csname#2\s!en#3\endcsname
+% \else
+% \reporttextprefixerror{#1}{#2}{#3}%
+% \fi\fi
+% \else
+% \dogetupsometextprefix{\csname\??la#1\c!default\endcsname}{#2}{#3}%
+% \fi\fi}
+
+\def\dogetupsometextprefix#1#2#3% must be expandable ! #1 == language
+ {\ifcsname#2#1#3\endcsname
+ \csname#2#1#3\endcsname
+ \else\ifcsname\??la#1\s!default\endcsname
+ \expandafter\dogetupsometextprefix\csname\??la#1\s!default\endcsname{#2}{#3}%
+ \else\ifcsname#2#3\endcsname
+ \csname#2#3\endcsname
+ \else\ifcsname#1\s!en#3\endcsname
+ \csname#2\s!en#3\endcsname
+ \else
+ \reporttextprefixerror{#1}{#2}{#3}%
+ \fi\fi\fi\fi}
+
+\ifx\simplifiedcommands\undefined \newtoks\simplifiedcommands \fi
+
+\appendtoks
+ \let \headtext \firstofoneargument
+ \let \labeltext \firstofoneargument
+ \let \leftlabeltext \firstofoneargument
+ \let \rightlabeltext \firstofoneargument
+ \let \HEADTEXT \firstofoneargument
+ \let \LABELTEXT \firstofoneargument
+ \let \LEFTLABELTEXT \firstofoneargument
+ \let \RIGHTLABELTEXT \firstofoneargument
+\to \simplifiedcommands
+
+%D \macros
+%D {presetheadtext,presetlabeltext}
+%D
+%D The next two macros enable us to automatically define
+%D head and label texts without replacing predefined ones.
+%D These are internal macros.
+
+\def\xdopresetsometextprefix[#1][#2=#3]%
+ {\ifundefined{#1#2}\doassignsometextprefix[#1\reallanguagetag{#2}][#3,,]\fi}
+
+\def\dopresetsometextprefix
+ {\let\dodocommand\xdopresetsometextprefix
+ \dotripleempty\dodosetupsometextprefix}
+
+\def\presetheadtext {\dopresetsometextprefix[\c!title]}
+\def\presetlabeltext{\dopresetsometextprefix[\c!label]}
+
+%D \macros
+%D {translate}
+%D
+%D Sometismes macros contain language specific words that are to
+%D be typeset. Such macros can be made (more) language
+%D independant by using:
+%D
+%D \showsetup{translate}
+%D
+%D like for instance:
+%D
+%D \starttyping
+%D \translate[en=something,nl=iets]
+%D \stoptyping
+%D
+%D which expands to {\em something} or {\em iets}, depending on
+%D de current language.
+
+\def\dotranslate[#1]%
+ {\getparameters[\??lg][#1]%
+ \ifcsname\??lg\currentlanguage\endcsname
+ \csname\??lg\currentlanguage\endcsname
+ \else\ifcsname\??lg\s!en\endcsname
+ \csname\??lg\s!en\endcsname
+ \else
+ [translation #1]%
+ \fi\fi}
+
+\unexpanded\def\translate
+ {\dosingleempty\dotranslate}
+
+%D When used without argument, the last defined values are
+%D used. This enables repetitive use like
+%D
+%D \starttyping
+%D \en \translate\ means \nl \translate
+%D \stoptyping
+
+%D \macros
+%D {assigntranslation}
+%D
+%D This macro is a system macro, and can be used to assign a
+%D translation to a macro. Its form is:
+%D
+%D \starttyping
+%D \assigntranslation[en=something,nl=iets]\to\command
+%D \stoptyping
+
+\def\assigntranslation[#1]\to#2%
+ {\getparameters[\??lg][#1]%
+ \edef#2{\csname\??lg\currentlanguage\endcsname}}
+
+\protect \endinput
diff --git a/tex/context/base/lang-lab.mkiv b/tex/context/base/lang-lab.mkiv
new file mode 100644
index 000000000..42f2db8ff
--- /dev/null
+++ b/tex/context/base/lang-lab.mkiv
@@ -0,0 +1,283 @@
+%D \module
+%D [ file=lang-lab,
+%D version=1997.08.27,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Labels,
+%D author=Hans Hagen / Tobias Burnus,
+%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.
+
+\unprotect
+
+%D In this module we deal with language dependant labels and
+%D prefixes, like in {\em Figure~12} and {\em Chapter 1}. In
+%D this file we set the default values. Users can easily
+%D overrule these.
+%D
+%D This module is dedicated to the grandfather of Tobias
+%D Burnus, who's extensive languages oriented library helped us
+%D a lot in finding the right translations. All those labels
+%D are collected in files that reflect their common ancestor.
+%D
+%D Not all languages can be satisfied with the labeling
+%D mechanism as provided here. Chinese for instance put a label
+%D in front as well as after a part number. This is why the
+%D current implementation of labels supports two labels too.
+
+%D \macros
+%D {setupheadtext, setuplabeltext}
+%D
+%D First we present some macros that deal with what we will
+%D call head and label texts. Such texts are defines by:
+%D
+%D \showsetup{setupheadtext}
+%D \showsetup{setuplabeltext}
+%D
+%D A regular \CONTEXT\ stores some 1500 labels at most.
+
+\let\handletextprefix\relax
+
+\newconditional\protecttextprefixes
+
+\let\currenttextprefixtag \s!unknown
+\let\currenttextprefixclass\s!unknown
+
+\unexpanded\def\setupheadtext {\setfalse\protecttextprefixes\let\currenttextprefixclass\??mh\dodoubleempty\dosetupsometextprefix}
+\unexpanded\def\setuplabeltext {\setfalse\protecttextprefixes\let\currenttextprefixclass\??ml\dodoubleempty\dosetupsometextprefix}
+\unexpanded\def\setupmathlabeltext{\setfalse\protecttextprefixes\let\currenttextprefixclass\??mm\dodoubleempty\dosetupsometextprefix}
+
+\def\dosetupsometextprefix[#1][#2]%
+ {\ifsecondargument
+ \edef\currenttextprefixtag{\reallanguagetag{#1}}%
+ \processcommalist[#2]\dodosetupsometextprefix
+ \else
+ \edef\currenttextprefixtag{\reallanguagetag\currentmainlanguage}%
+ \processcommalist[#1]\dodosetupsometextprefix
+ \fi}
+
+\def\dodosetupsometextprefix#1%
+ {\dododosetupsometextprefix[#1]}
+
+\def\dododosetupsometextprefix[#1=#2]%
+ {\doassignsometextprefix{#1}[#2,,]}
+
+\def\doassignsometextprefix#1%
+ {\ifconditional\protecttextprefixes
+ \ifcsname\currenttextprefixclass\currenttextprefixtag#1\endcsname
+ \expandafter\expandafter\expandafter\doassignsometextprefixnop
+ \else
+ \expandafter\expandafter\expandafter\doassignsometextprefixyes
+ \fi
+ \else
+ \expandafter\doassignsometextprefixyes
+ \fi{#1}}
+
+\ifdefined\Word\else \let\Word\relax \fi
+
+% Checking saves some 8K in the compressed format and getting rid of the embedded
+% \handletextprefix was good for another 6K. In the end the new solution is not
+% even that inefficient. And the checking is done at format generation time anyway.
+
+\def\doassignsometextprefixyes#1[#2,#3,#4]%
+ {\edef\!!stringa{#2}%
+ \edef\!!stringb{#3}%
+ \ifx\!!stringb\empty
+ \ifx\!!stringa\empty
+ \expandafter\def\csname\currenttextprefixclass\currenttextprefixtag#1\endcsname{\empty\empty}%
+ \else
+ \expandafter\def\csname\currenttextprefixclass\currenttextprefixtag#1\endcsname{{#2}\empty}%
+ \fi
+ \else
+ \expandafter\def\csname\currenttextprefixclass\currenttextprefixtag#1\endcsname{{#2}{#3}}%
+ \fi}
+
+\def\doassignsometextprefixnop#1[#2]%
+ {}
+
+%D By changing the meaning of \type {\handletextprefix} we
+%D can filter the left and right labeltext as well as convert
+%D labels to uppercase.
+%D
+%D These commands accept all kind of inputs:
+%D
+%D \starttyping
+%D \setuplabeltext [language] [labellabel=text]
+%D \setuplabeltext [language] [labellabel=text,labellabel=text,...]
+%D \setuplabeltext [labellabel=text]
+%D \setuplabeltext [labellabel=text,labellabel=text,...]
+%D \stoptyping
+%D
+%D The last two cases concern the current language.
+
+%D \macros
+%D {headtext,
+%D labeltext, leftlabeltext, rightlabeltext, labeltexts,
+%D LABELTEXT, LEFTLABELTEXT, RIGHTLABELTEXT, LABELTEXTS}
+%D
+%D Once defined, head and label texts can be called upon using:
+%D
+%D \showsetup{headtext}
+%D \showsetup{labeltext}
+%D
+%D The latter one has an upcased alternative \type{\LABELTEXT}.
+
+\def\labellanguage {\reallanguagetag{\defaultlanguage\currentmainlanguage}}
+\def\headlanguage {\reallanguagetag{\defaultlanguage\currentmainlanguage}}
+\def\mathlabellanguage{\reallanguagetag{\defaultlanguage\currentmainlanguage}}
+
+\appendtoks \let\labellanguage\currentlanguage \to \everycurrentdate
+
+\def\dummytextprefix{\empty\empty}
+
+\def\dogetupsomelabeltext {\dodogetupsomelabeltext \labellanguage } % second argument is textlabel
+\def\dogetupsomeheadtext {\dodogetupsomeheadtext \headlanguage } % second argument is headlabel
+\def\dogetupsomemathlabeltext{\dodogetupsomemathlabeltext\mathlabellanguage } % second argument is headlabel
+
+\def\dodogetupsomelabeltext#1#2%
+ {\ifcsname\??ml#1#2\endcsname
+ \expandafter\let\expandafter\thetextprefix\csname\??ml#1#2\endcsname
+ \else\ifcsname\??la\labellanguage\s!default\endcsname
+ \expandafter\dodogetupsomelabeltext\csname\??la\labellanguage\s!default\endcsname{#2}%
+ \else\ifcsname\??ml#2\endcsname
+ \expandafter\let\expandafter\thetextprefix\csname\??ml#2\endcsname
+ \else\ifcsname\??ml\s!en#2\endcsname
+ \expandafter\let\expandafter\thetextprefix\csname\??ml\s!en#2\endcsname
+ \else
+ \let\thetextprefix\dummytextprefix
+ \fi\fi\fi\fi}
+
+\def\dodogetupsomeheadtext#1#2%
+ {\ifcsname\??mh#1#2\endcsname
+ \expandafter\let\expandafter\thetextprefix\csname\??mh#1#2\endcsname
+ \else\ifcsname\??la\headlanguage\s!default\endcsname
+ \expandafter\dodogetupsomeheadtext\csname\??la\headlanguage\s!default\endcsname{#2}%
+ \else\ifcsname\??mh#2\endcsname
+ \expandafter\let\expandafter\thetextprefix\csname\??mh#2\endcsname
+ \else\ifcsname\??mh\s!en#2\endcsname
+ \expandafter\let\expandafter\thetextprefix\csname\??mh\s!en#2\endcsname
+ \else
+ \let\thetextprefix\dummytextprefix
+ \fi\fi\fi\fi}
+
+\def\dodogetupsomemathlabeltext#1#2%
+ {\ifcsname\??mm#1#2\endcsname
+ \expandafter\let\expandafter\thetextprefix\csname\??mm#1#2\endcsname
+ \else\ifcsname\??la\mathlabellanguage\s!default\endcsname
+ \expandafter\dodogetupsomemathlabeltext\csname\??la\mathlabellanguage\s!default\endcsname{#2}%
+ \else\ifcsname\??mm#2\endcsname
+ \expandafter\let\expandafter\thetextprefix\csname\??mm#2\endcsname
+ \else\ifcsname\??mm\s!en#2\endcsname
+ \expandafter\let\expandafter\thetextprefix\csname\??mm\s!en#2\endcsname
+ \else
+ \let\thetextprefix\dummytextprefix
+ \fi\fi\fi\fi}
+
+% The WORD variants are a bit inefficient when #1/#2 are empty but they are
+% seldom used (one can better set the style).
+
+\let\flushleftlabeltext \firstoftwoarguments
+\let\flushrightlabeltext \secondoftwoarguments
+\let\flushleftmathlabeltext \firstoftwoarguments
+\let\flushrightmathlabeltext\secondoftwoarguments
+
+\def\flushleftlabelWORD #1#2{\WORD{#1}}
+\def\flushrightlabelWORD #1#2{\WORD{#2}}
+\def\flushbothlabeltexts #1#2#3{#1#3#2}
+\def\flushbothlabelTEXTS #1#2#3{\WORD{#1}#3\WORD{#2}}
+
+\unexpanded\def\headtext #1{\dogetupsomeheadtext {#1}\expandafter\flushleftlabeltext \thetextprefix}
+\unexpanded\def\leftlabeltext #1{\dogetupsomelabeltext {#1}\expandafter\flushleftlabeltext \thetextprefix}
+\unexpanded\def\rightlabeltext #1{\dogetupsomelabeltext {#1}\expandafter\flushrightmathlabeltext\thetextprefix}
+\unexpanded\def\LEFTLABELTEXT #1{\dogetupsomelabeltext {#1}\expandafter\flushleftlabelWORD \thetextprefix}
+\unexpanded\def\RIGHTLABELTEXT #1{\dogetupsomelabeltext {#1}\expandafter\flushrightlabelWORD \thetextprefix}
+\unexpanded\def\labeltexts #1{\dogetupsomelabeltext {#1}\expandafter\flushbothlabeltexts \thetextprefix} % #2
+\unexpanded\def\LABELTEXTS #1{\dogetupsomelabeltext {#1}\expandafter\flushbothlabelTEXTS \thetextprefix} % #2
+\unexpanded\def\leftmathlabeltext #1{\dogetupsomemathlabeltext{#1}\expandafter\flushleftmathlabeltext \thetextprefix}
+\unexpanded\def\rightmathlabeltext#1{\dogetupsomemathlabeltext{#1}\expandafter\flushrightlabeltext \thetextprefix}
+
+\let\labeltext \leftlabeltext
+\let\LABELTEXT \LEFTLABELTEXT
+\let\mathlabeltext\leftmathlabeltext
+
+\ifx\simplifiedcommands\undefined \newtoks\simplifiedcommands \fi
+
+\appendtoks
+ \let \headtext \firstofoneargument
+ \let \labeltext \firstofoneargument
+ \let \leftlabeltext \firstofoneargument
+ \let \rightlabeltext \firstofoneargument
+ \let \HEADTEXT \firstofoneargument
+ \let \LABELTEXT \firstofoneargument
+ \let \LEFTLABELTEXT \firstofoneargument
+ \let \RIGHTLABELTEXT \firstofoneargument
+ \let \mathlabeltext \firstofoneargument
+\to \simplifiedcommands
+
+%D \macros
+%D {presetheadtext,presetlabeltext}
+%D
+%D The next two macros enable us to automatically define
+%D head and label texts without replacing predefined ones.
+%D These are internal macros.
+
+\def\presetheadtext {\settrue\protecttextprefixes\let\currenttextprefixclass\??mh\dodoubleempty\dosetupsometextprefix}
+\def\presetlabeltext {\settrue\protecttextprefixes\let\currenttextprefixclass\??ml\dodoubleempty\dosetupsometextprefix}
+\def\presetmathlabeltext{\settrue\protecttextprefixes\let\currenttextprefixclass\??mm\dodoubleempty\dosetupsometextprefix}
+
+%D \macros
+%D {translate}
+%D
+%D Sometismes macros contain language specific words that are to
+%D be typeset. Such macros can be made (more) language
+%D independant by using:
+%D
+%D \showsetup{translate}
+%D
+%D like for instance:
+%D
+%D \starttyping
+%D \translate[en=something,nl=iets]
+%D \stoptyping
+%D
+%D which expands to {\em something} or {\em iets}, depending on
+%D de current language.
+
+\def\dotranslate[#1]%
+ {\getparameters[\??lg][#1]%
+ \ifcsname\??lg\currentlanguage\endcsname
+ \csname\??lg\currentlanguage\endcsname
+ \else\ifcsname\??lg\s!en\endcsname
+ \csname\??lg\s!en\endcsname
+ \else
+ [translation #1]%
+ \fi\fi}
+
+\unexpanded\def\translate
+ {\dosingleempty\dotranslate}
+
+%D When used without argument, the last defined values are
+%D used. This enables repetitive use like
+%D
+%D \starttyping
+%D \en \translate\ means \nl \translate
+%D \stoptyping
+
+%D \macros
+%D {assigntranslation}
+%D
+%D This macro is a system macro, and can be used to assign a
+%D translation to a macro. Its form is:
+%D
+%D \starttyping
+%D \assigntranslation[en=something,nl=iets]\to\command
+%D \stoptyping
+
+\def\assigntranslation[#1]\to#2%
+ {\getparameters[\??lg][#1]%
+ \edef#2{\csname\??lg\currentlanguage\endcsname}}
+
+\protect \endinput
diff --git a/tex/context/base/lang-mis.mkii b/tex/context/base/lang-mis.mkii
new file mode 100644
index 000000000..eb7bb1a04
--- /dev/null
+++ b/tex/context/base/lang-mis.mkii
@@ -0,0 +1,683 @@
+%D \module
+%D [ file=lang-mis,
+%D version=1997.03.20, % used to be supp-lan.tex
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Compounds,
+%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 Language Macros / Compounds}
+
+%D \gdef\starttest
+%D {\blank
+%D \noindent
+%D \halign\bgroup\tt##\hskip2em#\hskip2em#\cr}
+%D
+%D \gdef\stoptest
+%D {\egroup
+%D \blank}
+%D
+%D \gdef\test#1%
+%D {\defconvertedargument\ascii{#1}\ascii&\hyphenatedword{#1}\cr}
+
+\unprotect
+
+%D One of \TEX's strong points in building paragraphs is the way
+%D hyphenations are handled. Although for real good hyphenation
+%D of non||english languages some extensions to the program are
+%D needed, fairly good results can be reached with the standard
+%D mechanisms and an additional macro, at least in Dutch.
+
+%D \CONTEXT\ originates in the wish to typeset educational
+%D materials, especially in a technical environment. In
+%D production oriented environments, a lot of compound words
+%D are used. Because the Dutch language poses no limits on
+%D combining words, we often favor putting dashes between those
+%D words, because it facilitates reading, at least for those
+%D who are not that accustomed to it.
+%D
+%D In \TEX\ compound words, separated by a hyphen, are not
+%D hyphenated at all. In spite of the multiple pass paragraph
+%D typesetting this can lead to parts of words sticking into
+%D the margin. The solution lays in saying \type
+%D {spoelwater||terugwinunit} instead of \type
+%D {spoelwater-terugwinunit}. By using a one character command
+%D like \type {|}, delimited by the same character \type {|},
+%D we get ourselves both a decent visualization (in \TEXEDIT\
+%D and colored verbatim we color these commands yellow) and an
+%D efficient way of combining words.
+%D
+%D The sequence \type{||} simply leads to two words connected by
+%D a hyphen. Because we want to distinguish such a hyphen from
+%D the one inserted when \TEX\ hyphenates a word, we use a bit
+%D longer one.
+%D
+%D \hyphenation {spoel-wa-ter te-rug-win-unit}
+%D
+%D \starttest
+%D \test {spoelwater||terugwinunit}
+%D \stoptest
+%D
+%D As we already said, the \type{|} is a command. This commands
+%D accepts an optional argument before it's delimiter, which is
+%D also a \type{|}.
+%D
+%D \hyphenation {po-ly-meer che-mie}
+%D
+%D \starttest
+%D \test {polymeer|*|chemie}
+%D \stoptest
+%D
+%D Arguments like \type{*} are not interpreted and inserted
+%D directly, in contrary to arguments like:
+%D
+%D \starttest
+%D \test {polymeer|~|chemie}
+%D \test {|(|polymeer|)|chemie}
+%D \test {polymeer|(|chemie|)| }
+%D \stoptest
+%D
+%D Although such situations seldom occur |<|we typeset thousands
+%D of pages before we encountered one that forced us to enhance
+%D this mechanism|>| we also have to take care of comma's.
+%D
+%D \hyphenation {uit-stel-len}
+%D
+%D \starttest
+%D \test {op||, in|| en uitstellen}
+%D \stoptest
+%D
+%D The next special case (concerning quotes) was brought to my
+%D attention by Piet Tutelaers, one of the driving forces
+%D behind rebuilding hyphenation patterns for the dutch
+%D language.\footnote{In 1996 the spelling of the dutch
+%D language has been slightly reformed which made this topic
+%D actual again.} We'll also take care of this case.
+%D
+%D \starttest
+%D \test {AOW|'|er}
+%D \test {cd|'|tje}
+%D \test {ex|-|PTT|'|er}
+%D \test {rock|-|'n|-|roller}
+%D \stoptest
+%D
+%D Tobias Burnus pointed out that I should also support
+%D something like
+%D
+%D \starttest
+%D \test {well|_|known}
+%D \stoptest
+%D
+%D to stress the compoundness of hyphenated words.
+%D
+%D Of course we also have to take care of the special case:
+%D
+%D \starttest
+%D \test {text||color and ||font}
+%D \stoptest
+
+%D \macros
+%D {installdiscretionaries}
+%D
+%D The mechanism described here is one of the older inner parts
+%D of \CONTEXT. The most recent extensions concerns some
+%D special cases as well as the possibility to install other
+%D characters as delimiters. The prefered way of specifying
+%D compound words is using \type{||}, which is installed by:
+%D
+%D \starttyping
+%D \installdiscretionaries || -
+%D \stoptyping
+%D
+%D Some alternative definitions are:
+%D
+%D \startbuffer
+%D \installdiscretionaries ** -
+%D \installdiscretionaries ++ -
+%D \installdiscretionaries // -
+%D \installdiscretionaries ~~ -
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D after which we can say:
+%D
+%D \bgroup
+%D \getbuffer
+%D \starttest
+%D \test {test**test**test}
+%D \test {test++test++test}
+%D \test {test//test//test}
+%D \test {test~~test~~test}
+%D \stoptest
+%D \egroup
+
+%D \macros
+%D {compoundhyphen,
+%D beginofsubsentence,endofsubsentence}
+%D
+%D Now let's go to the macros. First we define some variables.
+%D In the main \CONTEXT\ modules these can be tuned by a setup
+%D command. Watch the (maybe) better looking compound hyphen.
+
+\ifx\compoundhyphen \undefined \def\compoundhyphen{\hbox{-\kern-.25ex-}} \fi
+
+\ifx\beginofsubsentence \undefined \def\beginofsubsentence{\hbox{---}} \fi
+\ifx\endofsubsentence \undefined \def\endofsubsentence {\hbox{---}} \fi
+
+%D The last two variables are needed for subsentences
+%D |<|like this one|>| which we did not yet mention.
+%D
+%D We want to enable breaking but at the same time don't want
+%D compound characters like |-| or || to be separated from the
+%D words. \TEX\ hackers will recognise the next two macro's:
+
+\ifx\prewordbreak \undefined \def\prewordbreak {\penalty\plustenthousand\hskip\zeropoint\relax} \fi
+%ifx\postwordbreak \undefined \def\postwordbreak{\penalty\zerocount \prewordbreak } \fi
+\ifx\postwordbreak \undefined \def\postwordbreak{\penalty\zerocount \hskip\zeropoint\relax} \fi
+
+\ifx\hspaceamount \undefined \def\hspaceamount#1#2{.16667em} \fi % language specific
+
+%D \macros
+%D {beginofsubsentencespacing,endofsubsentencespacing}
+%D
+%D In the previous macros we provided two hooks which can be
+%D used to support nested sub||sentences. In \CONTEXT\ these
+%D hooks are used to insert a small space when needed.
+
+\ifx\beginofsubsentencespacing\undefined \let\beginofsubsentencespacing\relax \fi
+\ifx\endofsubsentencespacing \undefined \let\endofsubsentencespacing \relax \fi
+
+%D The following piece of code is a torture test compound
+%D hndling. The \type {\relax} before the \type {\ifmmode} is
+%D needed because of the alignment scanner (in \ETEX\ this
+%D problem is not present because there a protected macro is
+%D not expanded. Thanks to Tobias Burnus for providing this
+%D example.
+%D
+%D \startformula
+%D \left|f(x_n)-{1\over2}\right| =
+%D {\cases{|{1\over2}-x_n| &for $0\le x_n < {1\over2}$\cr
+%D |x_n-{1\over2}| &for ${1\over2}\zeropoint
+ (\prewordbreak
+ \else
+ \prewordbreak\discretionary{}{(-}{(}\prewordbreak
+ \fi}
+
+\definetextmodediscretionary ~
+ {\prewordbreak\discretionary{-}{}{\thinspace}\postwordbreak}
+
+\definetextmodediscretionary '
+ {\prewordbreak\discretionary{-}{}{'}\postwordbreak}
+
+\definetextmodediscretionary ^
+ {\prewordbreak\discretionary{\hbox{$|$}}{}{\hbox{$|$}}%
+ \allowbreak\postwordbreak} % bugged
+
+\definetextmodediscretionary <
+ {\beginofsubsentence\prewordbreak\beginofsubsentencespacing}
+
+\definetextmodediscretionary >
+ {\endofsubsentencespacing\prewordbreak\endofsubsentence}
+
+\definetextmodediscretionary =
+ {\prewordbreak\midsentence\prewordbreak} % {\prewordbreak\compoundhyphen}
+
+% french
+
+\definetextmodediscretionary : {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{:}:}
+\definetextmodediscretionary ; {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{;};}
+\definetextmodediscretionary ? {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{?}?}
+\definetextmodediscretionary ! {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{!}!}
+
+\definetextmodediscretionary *
+ {\prewordbreak\discretionary{-}{}{\kern.05em}\prewordbreak}
+
+% spanish
+
+\definetextmodediscretionary ?? {\prewordbreak\questiondown}
+\definetextmodediscretionary !! {\prewordbreak\exclamdown}
+
+% \ifx\normalcompound\undefined \let\normalcompound=| \fi
+
+%D \installdiscretionary | +
+%D \installdiscretionary + =
+
+\def\defaultdiscretionaryhyphen{\compoundhyphen}
+
+\installdiscretionary | \defaultdiscretionaryhyphen % installs in ctx and prt will fall back on it
+
+%D \macros
+%D {fakecompoundhyphen}
+%D
+%D In headers and footers as well as in active pieces of text
+%D we need a dirty hack. Try to imagine what is needed to
+%D savely break the next text across a line and at the same
+%D time make the words interactive.
+%D
+%D \starttyping
+%D \goto{Some||Long||Word}
+%D \stoptyping
+
+\def\fakecompoundhyphen
+ {\def\|{\mathortext\vert\dofakecompoundhyphen}}
+
+\def\dofakecompoundhyphen
+ {\def##1|%
+ {\doifelsenothing{##1}\compoundhyphen{##1}%
+ \kern\compoundbreakpoint\allowbreak}}
+
+%D \macros
+%D {midworddiscretionary}
+%D
+%D If needed, one can add a discretionary hyphen using \type
+%D {\midworddiscretionary}. This macro does the same as
+%D \PLAIN\ \TEX's \type {\-}, but, like the ones implemented
+%D earlier, this one also looks ahead for spaces and grouping
+%D tokens.
+
+\def\midworddiscretionary
+ {\futurelet\next\domidworddiscretionary}
+
+\def\domidworddiscretionary
+ {\ifx\next\blankspace\else
+ \ifx\next\bgroup \else
+ \ifx\next\egroup \else
+ \discretionary{-}{}{}%
+ \fi\fi\fi}
+
+%D \macros
+%D {installcompoundcharacter}
+%D
+%D When Tobias Burnus started translating the dutch manual of
+%D \PPCHTEX\ into german, he suggested to let \CONTEXT\ support
+%D the \type{german.sty} method of handling compound
+%D characters, especially the umlaut. This package is meant for
+%D use with \PLAIN\ \TEX\ as well as \LATEX.
+%D
+%D I decided to implement compound character support as
+%D versatile as possible. As a result one can define his own
+%D compound character support, like:
+%D
+%D \starttyping
+%D \installcompoundcharacter "a {\"a}
+%D \installcompoundcharacter "e {\"e}
+%D \installcompoundcharacter "i {\"i}
+%D \installcompoundcharacter "u {\"u}
+%D \installcompoundcharacter "o {\"o}
+%D \installcompoundcharacter "s {\SS}
+%D \stoptyping
+%D
+%D or even
+%D
+%D \starttyping
+%D \installcompoundcharacter "ck {\discretionary {k-}{k}{ck}}
+%D \installcompoundcharacter "ff {\discretionary{ff-}{f}{ff}}
+%D \stoptyping
+%D
+%D The support is not limited to alphabetic characters, so the
+%D next definition is also valid.
+%D
+%D \starttyping
+%D \installcompoundcharacter ". {.\doifnextcharelse{\spacetoken}{}{\kern.125em}}
+%D \stoptyping
+%D
+%D The implementation looks familiar and uses the same tricks as
+%D mentioned earlier in this module. We take care of two
+%D arguments, which complicates things a bit.
+
+\def\@nc@{@nc@} % normal character
+\def\@cc@{@cc@} % compound character
+\def\@cs@{@cs@} % compound characters
+\def\@cx@{@cx@} % compound definition
+
+%D When we started working on MK IV code, we needed a different
+%D approach for defining the active character itself. In MK II as
+%D well as in MK IV we now use the catcode vectors.
+
+\chardef\compoundcharactermode\plusone
+
+\def\installcompoundcharacter #1#2#3 #4% {#4} no grouping
+ {\ifcase\compoundcharactermode
+ % ignore mode
+ \else
+ \chardef\thecompoundcharacter`#1%
+ \@EA\chardef\csname\@nc@\string#1\endcsname\thecompoundcharacter
+ \def\!!stringa{#3}%
+ \@EA\def\csname\ifx\!!stringa\empty\@cc@\else\@cs@\fi\detokenize{#1#2#3}\endcsname{#4}%
+ \setevalue{\@cx@\detokenize{#1}}{\noexpand\handlecompoundcharacter{\detokenize{#1}}}% beter nr's
+% \@EA\letcatcodecommand\@EA\prtcatcodes\@EA\thecompoundcharacter\csname\@cx@\detokenize{#1}\endcsname
+% \@EA\letcatcodecommand\@EA\texcatcodes\@EA\thecompoundcharacter\csname\@cx@\detokenize{#1}\endcsname
+ \@EA\letcatcodecommand\@EA\ctxcatcodes\@EA\thecompoundcharacter\csname\@cx@\detokenize{#1}\endcsname
+ \fi}
+
+%D In order to serve the language specific well, we will introduce
+%D a namespace:
+
+% \ifx\currentlanguage\undefined
+ \let\compoundcharacterclass\empty
+% \else
+% \def\compoundcharacterclass{\currentlanguage}
+% \fi
+
+\def\@cc@{@cc@\compoundcharacterclass} % compound character
+\def\@cs@{@cs@\compoundcharacterclass} % compound characters
+
+%D We can also ignore definitions (needed in for instance \XML). Beware,
+%D this macro is supposed to be used grouped!
+
+\def\ignorecompoundcharacter
+ {\chardef\compoundcharactermode\zerocount}
+
+\let\restorecompoundcharacter \gobbleoneargument % obsolete
+\let\enableactivediscretionaries\relax % obsolete
+
+%D In handling the compound characters we have to take care of
+%D \type{\bgroup} and \type{\egroup} tokens, so we end up with
+%D a multi||step interpretation macro. We look ahead for a
+%D \type{\bgroup}, \type{\egroup} or \type{\blankspace}. Being
+%D no user of this mechanism, the credits for testing them goes
+%D to Tobias Burnus, the first german user of \CONTEXT.
+%D
+%D We define these macros as \type{\long} because we can
+%D expect \type{\par} tokens. We need to look into the future
+%D with \type{\futurelet} to prevent spaces from
+%D disappearing.
+
+\def\handlecompoundcharacter#1%
+ {\def\xhandlecompoundcharacter{\dohandlecompoundcharacter{#1}}%
+ \futurelet\next\xhandlecompoundcharacter}
+
+\def\dohandlecompoundcharacter
+ {\ifx\next\bgroup
+ %\@EA\dodohandlecompoundcharacter % handle "{ee} -> \"ee
+ %\@EA\gobbleoneargument % forget "{ee} -> ee
+ \@EA\handlecompoundcharacterone % ignore "{ee} -> "ee
+ \else\ifx\next\egroup
+ \@EAEAEA\donohandlecompoundcharacter
+ \else\ifx\next\blankspace
+ \@EA\@EAEAEA\@EA\donohandlecompoundcharacter
+ \else
+ \@EA\@EAEAEA\@EA\dodohandlecompoundcharacter
+ \fi\fi\fi}
+
+\def\donohandlecompoundcharacter#1{\csname\@nc@\string#1\endcsname}
+
+\def\dododohandlecompoundcharacter
+ {\ifx\next\bgroup
+ \@EA\handlecompoundcharacterone
+ \else\ifx\next\egroup
+ \@EAEAEA\handlecompoundcharacterone
+ \else\ifx\next\blankspace
+ \@EA\@EAEAEA\@EA\handlecompoundcharacterone
+ \else
+ \@EA\@EAEAEA\@EA\handlecompoundcharactertwo
+ \fi\fi\fi}
+
+\def\dodohandlecompoundcharacter#1#2% preserve space
+ {\def\xdodohandlecompoundcharacter{\dododohandlecompoundcharacter#1#2}%
+ \futurelet\next\xdodohandlecompoundcharacter}
+
+%D Besides taken care of the grouping and space tokens, we have
+%D to deal with three situations. First we look if the next
+%D character equals the first one, if so, then we just insert
+%D the original. Next we look if indeed a compound character is
+%D defined. We either execute the compound character or just
+%D insert the first. So we have
+%D
+%D \starttyping
+%D
+%D \stoptyping
+%D
+%D In later modules we will see how these commands are used.
+
+\long\def\handlecompoundcharacterone#1#2%
+ {\if\string#1\string#2% was: \ifx#1#2%
+ \def\next{\csname\@nc@\string#1\endcsname}%
+ \else\ifcsname\@cc@\string#1\string#2\endcsname
+ \def\next{\csname\@cc@\string#1\string#2\endcsname}%
+ \else
+ \def\next{\csname\@nc@\string#1\endcsname#2}%
+ \fi\fi
+ \next}
+
+\long\def\handlecompoundcharactertwo#1#2#3%
+ {\if\string#1\string#2%
+ \def\next{\csname\@nc@\string#1\endcsname#3}%
+ \else\ifcsname\@cs@\string#1\string#2\string#3\endcsname
+ \def\next{\csname\@cs@\string#1\string#2\string#3\endcsname}%
+ \else\ifcsname\@cc@\string#1\string#2\endcsname
+ \def\next{\csname\@cc@\string#1\string#2\endcsname#3}%
+ \else
+ \def\next{\csname\@nc@\string#1\endcsname#2#3}%
+ \fi\fi\fi
+ \next}
+
+%D For very obscure applications (see for an application \type
+%D {lang-sla.tex}) we provide:
+
+\def\simplifiedcompoundcharacter#1#2%
+ {\ifcsname\@cc@\string#1\string#2\endcsname
+ \@EA\@EA\@EA\firstofoneargument\csname\@cc@\string#1\string#2\endcsname
+ \else
+ #2%
+ \fi}
+
+%D \macros
+%D {disablediscretionaries,disablecompoundcharacter}
+%D
+%D Occasionally we need to disable this mechanism. For the
+%D moment we assume that \type {|} is used.
+
+\let\disablediscretionaries \ignorediscretionaries
+\let\disablecompoundcharacters\ignorecompoundcharacter
+
+%D \macros
+%D {normalcompound}
+%D
+%D Handy in for instance XML. (Kind of obsolete)
+
+\ifx\normalcompound\undefined \let\normalcompound=| \fi
+
+\protect \endinput
diff --git a/tex/context/base/lang-mis.mkiv b/tex/context/base/lang-mis.mkiv
new file mode 100644
index 000000000..0df45877b
--- /dev/null
+++ b/tex/context/base/lang-mis.mkiv
@@ -0,0 +1,689 @@
+%D \module
+%D [ file=lang-mis,
+%D version=1997.03.20, % used to be supp-lan.tex
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Compounds,
+%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 Language Macros / Compounds}
+
+%D \gdef\starttest
+%D {\blank
+%D \noindent
+%D \halign\bgroup\tt##\hskip2em#\hskip2em#\cr}
+%D
+%D \gdef\stoptest
+%D {\egroup
+%D \blank}
+%D
+%D \gdef\test#1%
+%D {\defconvertedargument\ascii{#1}\ascii&\hyphenatedword{#1}\cr}
+
+\unprotect
+
+%D One of \TEX's strong points in building paragraphs is the way
+%D hyphenations are handled. Although for real good hyphenation
+%D of non||english languages some extensions to the program are
+%D needed, fairly good results can be reached with the standard
+%D mechanisms and an additional macro, at least in Dutch.
+
+%D \CONTEXT\ originates in the wish to typeset educational
+%D materials, especially in a technical environment. In
+%D production oriented environments, a lot of compound words
+%D are used. Because the Dutch language poses no limits on
+%D combining words, we often favor putting dashes between those
+%D words, because it facilitates reading, at least for those
+%D who are not that accustomed to it.
+%D
+%D In \TEX\ compound words, separated by a hyphen, are not
+%D hyphenated at all. In spite of the multiple pass paragraph
+%D typesetting this can lead to parts of words sticking into
+%D the margin. The solution lays in saying \type
+%D {spoelwater||terugwinunit} instead of \type
+%D {spoelwater-terugwinunit}. By using a one character command
+%D like \type {|}, delimited by the same character \type {|},
+%D we get ourselves both a decent visualization (in \TEXEDIT\
+%D and colored verbatim we color these commands yellow) and an
+%D efficient way of combining words.
+%D
+%D The sequence \type{||} simply leads to two words connected by
+%D a hyphen. Because we want to distinguish such a hyphen from
+%D the one inserted when \TEX\ hyphenates a word, we use a bit
+%D longer one.
+%D
+%D \hyphenation {spoel-wa-ter te-rug-win-unit}
+%D
+%D \starttest
+%D \test {spoelwater||terugwinunit}
+%D \stoptest
+%D
+%D As we already said, the \type{|} is a command. This commands
+%D accepts an optional argument before it's delimiter, which is
+%D also a \type{|}.
+%D
+%D \hyphenation {po-ly-meer che-mie}
+%D
+%D \starttest
+%D \test {polymeer|*|chemie}
+%D \stoptest
+%D
+%D Arguments like \type{*} are not interpreted and inserted
+%D directly, in contrary to arguments like:
+%D
+%D \starttest
+%D \test {polymeer|~|chemie}
+%D \test {|(|polymeer|)|chemie}
+%D \test {polymeer|(|chemie|)| }
+%D \stoptest
+%D
+%D Although such situations seldom occur |<|we typeset thousands
+%D of pages before we encountered one that forced us to enhance
+%D this mechanism|>| we also have to take care of comma's.
+%D
+%D \hyphenation {uit-stel-len}
+%D
+%D \starttest
+%D \test {op||, in|| en uitstellen}
+%D \stoptest
+%D
+%D The next special case (concerning quotes) was brought to my
+%D attention by Piet Tutelaers, one of the driving forces
+%D behind rebuilding hyphenation patterns for the dutch
+%D language.\footnote{In 1996 the spelling of the dutch
+%D language has been slightly reformed which made this topic
+%D actual again.} We'll also take care of this case.
+%D
+%D \starttest
+%D \test {AOW|'|er}
+%D \test {cd|'|tje}
+%D \test {ex|-|PTT|'|er}
+%D \test {rock|-|'n|-|roller}
+%D \stoptest
+%D
+%D Tobias Burnus pointed out that I should also support
+%D something like
+%D
+%D \starttest
+%D \test {well|_|known}
+%D \stoptest
+%D
+%D to stress the compoundness of hyphenated words.
+%D
+%D Of course we also have to take care of the special case:
+%D
+%D \starttest
+%D \test {text||color and ||font}
+%D \stoptest
+
+%D \macros
+%D {installdiscretionaries}
+%D
+%D The mechanism described here is one of the older inner parts
+%D of \CONTEXT. The most recent extensions concerns some
+%D special cases as well as the possibility to install other
+%D characters as delimiters. The prefered way of specifying
+%D compound words is using \type{||}, which is installed by:
+%D
+%D \starttyping
+%D \installdiscretionaries || -
+%D \stoptyping
+%D
+%D Some alternative definitions are:
+%D
+%D \startbuffer
+%D \installdiscretionaries ** -
+%D \installdiscretionaries ++ -
+%D \installdiscretionaries // -
+%D \installdiscretionaries ~~ -
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D after which we can say:
+%D
+%D \bgroup
+%D \getbuffer
+%D \starttest
+%D \test {test**test**test}
+%D \test {test++test++test}
+%D \test {test//test//test}
+%D \test {test~~test~~test}
+%D \stoptest
+%D \egroup
+
+%D \macros
+%D {compoundhyphen,
+%D beginofsubsentence,endofsubsentence}
+%D
+%D Now let's go to the macros. First we define some variables.
+%D In the main \CONTEXT\ modules these can be tuned by a setup
+%D command. Watch the (maybe) better looking compound hyphen.
+
+\ifx\compoundhyphen \undefined \def\compoundhyphen{\hbox{-\kern-.25ex-}} \fi
+
+\ifx\beginofsubsentence \undefined \def\beginofsubsentence{\hbox{---}} \fi
+\ifx\endofsubsentence \undefined \def\endofsubsentence {\hbox{---}} \fi
+
+%D The last two variables are needed for subsentences
+%D |<|like this one|>| which we did not yet mention.
+%D
+%D We want to enable breaking but at the same time don't want
+%D compound characters like |-| or || to be separated from the
+%D words. \TEX\ hackers will recognise the next two macro's:
+
+\ifx\prewordbreak \undefined \def\prewordbreak {\penalty\plustenthousand\hskip\zeropoint\relax} \fi
+%ifx\postwordbreak \undefined \def\postwordbreak{\penalty\zerocount \prewordbreak } \fi
+\ifx\postwordbreak \undefined \def\postwordbreak{\penalty\zerocount \hskip\zeropoint\relax} \fi
+
+\ifx\hspaceamount \undefined \def\hspaceamount#1#2{.16667em} \fi % language specific
+
+%D \macros
+%D {beginofsubsentencespacing,endofsubsentencespacing}
+%D
+%D In the previous macros we provided two hooks which can be
+%D used to support nested sub||sentences. In \CONTEXT\ these
+%D hooks are used to insert a small space when needed.
+
+\ifx\beginofsubsentencespacing\undefined \let\beginofsubsentencespacing\relax \fi
+\ifx\endofsubsentencespacing \undefined \let\endofsubsentencespacing \relax \fi
+
+%D The following piece of code is a torture test compound
+%D hndling. The \type {\relax} before the \type {\ifmmode} is
+%D needed because of the alignment scanner (in \ETEX\ this
+%D problem is not present because there a protected macro is
+%D not expanded. Thanks to Tobias Burnus for providing this
+%D example.
+%D
+%D \startformula
+%D \left|f(x_n)-{1\over2}\right| =
+%D {\cases{|{1\over2}-x_n| &for $0\le x_n < {1\over2}$\cr
+%D |x_n-{1\over2}| &for ${1\over2}2xxx
+
+\def\hyphenliketextmodediscretionary#1#2%
+ {\ifconditional\spaceafterdiscretionary
+ \prewordbreak\hbox{#1}\relax
+ \else\ifconditional\punctafterdiscretionary
+ \prewordbreak\hbox{#1}\relax
+ \else
+ \prewordbreak#2\postwordbreak % was prewordbreak
+ \fi\fi}
+
+\definetextmodediscretionary {}
+ {\hyphenliketextmodediscretionary\textmodehyphen\textmodehyphendiscretionary}
+
+\definetextmodediscretionary -
+ {\hyphenliketextmodediscretionary\normalhyphen\normalhyphendiscretionary}
+
+\definetextmodediscretionary _
+ {\hyphenliketextmodediscretionary\composedhyphen\composedhyphendiscretionary}
+
+\definetextmodediscretionary )
+ {\hyphenliketextmodediscretionary{)}{\discretionary{-)}{}{)}}}
+
+\definetextmodediscretionary (
+ {\ifdim\lastskip>\zeropoint
+ (\prewordbreak
+ \else
+ \prewordbreak\discretionary{}{(-}{(}\prewordbreak
+ \fi}
+
+\definetextmodediscretionary ~
+ {\prewordbreak\discretionary{-}{}{\thinspace}\postwordbreak}
+
+\definetextmodediscretionary '
+ {\prewordbreak\discretionary{-}{}{'}\postwordbreak}
+
+\definetextmodediscretionary ^
+ {\prewordbreak\discretionary{\hbox{$|$}}{}{\hbox{$|$}}%
+ \allowbreak\postwordbreak} % bugged
+
+\definetextmodediscretionary <
+ {\beginofsubsentence\prewordbreak\beginofsubsentencespacing}
+
+\definetextmodediscretionary >
+ {\endofsubsentencespacing\prewordbreak\endofsubsentence}
+
+\definetextmodediscretionary =
+ {\prewordbreak\midsentence\prewordbreak} % {\prewordbreak\compoundhyphen}
+
+% french
+
+\definetextmodediscretionary : {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{:}:}
+\definetextmodediscretionary ; {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{;};}
+\definetextmodediscretionary ? {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{?}?}
+\definetextmodediscretionary ! {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{!}!}
+
+\definetextmodediscretionary *
+ {\prewordbreak\discretionary{-}{}{\kern.05em}\prewordbreak}
+
+% spanish
+
+\definetextmodediscretionary ?? {\prewordbreak\questiondown}
+\definetextmodediscretionary !! {\prewordbreak\exclamdown}
+
+% \ifx\normalcompound\undefined \let\normalcompound=| \fi
+
+%D \installdiscretionary | +
+%D \installdiscretionary + =
+
+\def\defaultdiscretionaryhyphen{\compoundhyphen}
+
+\installdiscretionary | \defaultdiscretionaryhyphen % installs in ctx and prt will fall back on it
+
+%D \macros
+%D {fakecompoundhyphen}
+%D
+%D In headers and footers as well as in active pieces of text
+%D we need a dirty hack. Try to imagine what is needed to
+%D savely break the next text across a line and at the same
+%D time make the words interactive.
+%D
+%D \starttyping
+%D \goto{Some||Long||Word}
+%D \stoptyping
+
+\def\fakecompoundhyphen
+ {\def\|{\mathortext\vert\dofakecompoundhyphen}}
+
+\def\dofakecompoundhyphen
+ {\def##1|%
+ {\doifelsenothing{##1}\compoundhyphen{##1}%
+ \kern\compoundbreakpoint\allowbreak}}
+
+%D \macros
+%D {midworddiscretionary}
+%D
+%D If needed, one can add a discretionary hyphen using \type
+%D {\midworddiscretionary}. This macro does the same as
+%D \PLAIN\ \TEX's \type {\-}, but, like the ones implemented
+%D earlier, this one also looks ahead for spaces and grouping
+%D tokens.
+
+\def\midworddiscretionary
+ {\futurelet\next\domidworddiscretionary}
+
+\def\domidworddiscretionary
+ {\ifx\next\blankspace\else
+ \ifx\next\bgroup \else
+ \ifx\next\egroup \else
+ \discretionary{-}{}{}%
+ \fi\fi\fi}
+
+%D \macros
+%D {installcompoundcharacter}
+%D
+%D When Tobias Burnus started translating the dutch manual of
+%D \PPCHTEX\ into german, he suggested to let \CONTEXT\ support
+%D the \type{german.sty} method of handling compound
+%D characters, especially the umlaut. This package is meant for
+%D use with \PLAIN\ \TEX\ as well as \LATEX.
+%D
+%D I decided to implement compound character support as
+%D versatile as possible. As a result one can define his own
+%D compound character support, like:
+%D
+%D \starttyping
+%D \installcompoundcharacter "a {\"a}
+%D \installcompoundcharacter "e {\"e}
+%D \installcompoundcharacter "i {\"i}
+%D \installcompoundcharacter "u {\"u}
+%D \installcompoundcharacter "o {\"o}
+%D \installcompoundcharacter "s {\SS}
+%D \stoptyping
+%D
+%D or even
+%D
+%D \starttyping
+%D \installcompoundcharacter "ck {\discretionary {k-}{k}{ck}}
+%D \installcompoundcharacter "ff {\discretionary{ff-}{f}{ff}}
+%D \stoptyping
+%D
+%D The support is not limited to alphabetic characters, so the
+%D next definition is also valid.
+%D
+%D \starttyping
+%D \installcompoundcharacter ". {.\doifnextcharelse{\spacetoken}{}{\kern.125em}}
+%D \stoptyping
+%D
+%D The implementation looks familiar and uses the same tricks as
+%D mentioned earlier in this module. We take care of two
+%D arguments, which complicates things a bit.
+
+\def\@nc@{@nc@} % normal character
+\def\@cc@{@cc@} % compound character
+\def\@cs@{@cs@} % compound characters
+\def\@cx@{@cx@} % compound definition
+
+%D When we started working on MK IV code, we needed a different
+%D approach for defining the active character itself. In MK II as
+%D well as in MK IV we now use the catcode vectors.
+
+\chardef\compoundcharactermode\plusone
+
+\def\installcompoundcharacter #1#2#3 #4% {#4} no grouping
+ {\ifcase\compoundcharactermode
+ % ignore mode
+ \else
+ \chardef\thecompoundcharacter`#1%
+ \@EA\chardef\csname\@nc@\string#1\endcsname\thecompoundcharacter
+ \def\!!stringa{#3}%
+ \@EA\def\csname\ifx\!!stringa\empty\@cc@\else\@cs@\fi\detokenize{#1#2#3}\endcsname{#4}%
+ \setevalue{\@cx@\detokenize{#1}}{\noexpand\handlecompoundcharacter{\detokenize{#1}}}% beter nr's
+% \@EA\letcatcodecommand\@EA\prtcatcodes\@EA\thecompoundcharacter\csname\@cx@\detokenize{#1}\endcsname
+% \@EA\letcatcodecommand\@EA\texcatcodes\@EA\thecompoundcharacter\csname\@cx@\detokenize{#1}\endcsname
+ \@EA\letcatcodecommand\@EA\ctxcatcodes\@EA\thecompoundcharacter\csname\@cx@\detokenize{#1}\endcsname
+ \fi}
+
+%D In order to serve the language specific well, we will introduce
+%D a namespace:
+
+% \ifx\currentlanguage\undefined
+ \let\compoundcharacterclass\empty
+% \else
+% \def\compoundcharacterclass{\currentlanguage}
+% \fi
+
+\def\@cc@{@cc@\compoundcharacterclass} % compound character
+\def\@cs@{@cs@\compoundcharacterclass} % compound characters
+
+%D We can also ignore definitions (needed in for instance \XML). Beware,
+%D this macro is supposed to be used grouped!
+
+\def\ignorecompoundcharacter
+ {\chardef\compoundcharactermode\zerocount}
+
+\let\restorecompoundcharacter \gobbleoneargument % obsolete
+\let\enableactivediscretionaries\relax % obsolete
+
+%D In handling the compound characters we have to take care of
+%D \type{\bgroup} and \type{\egroup} tokens, so we end up with
+%D a multi||step interpretation macro. We look ahead for a
+%D \type{\bgroup}, \type{\egroup} or \type{\blankspace}. Being
+%D no user of this mechanism, the credits for testing them goes
+%D to Tobias Burnus, the first german user of \CONTEXT.
+%D
+%D We define these macros as \type{\long} because we can
+%D expect \type{\par} tokens. We need to look into the future
+%D with \type{\futurelet} to prevent spaces from
+%D disappearing.
+
+\def\handlecompoundcharacter#1%
+ {\def\xhandlecompoundcharacter{\dohandlecompoundcharacter{#1}}%
+ \futurelet\next\xhandlecompoundcharacter}
+
+\def\dohandlecompoundcharacter
+ {\ifx\next\bgroup
+ %\@EA\dodohandlecompoundcharacter % handle "{ee} -> \"ee
+ %\@EA\gobbleoneargument % forget "{ee} -> ee
+ \@EA\handlecompoundcharacterone % ignore "{ee} -> "ee
+ \else\ifx\next\egroup
+ \@EAEAEA\donohandlecompoundcharacter
+ \else\ifx\next\blankspace
+ \@EA\@EAEAEA\@EA\donohandlecompoundcharacter
+ \else
+ \@EA\@EAEAEA\@EA\dodohandlecompoundcharacter
+ \fi\fi\fi}
+
+\def\donohandlecompoundcharacter#1{\csname\@nc@\string#1\endcsname}
+
+\def\dododohandlecompoundcharacter
+ {\ifx\next\bgroup
+ \@EA\handlecompoundcharacterone
+ \else\ifx\next\egroup
+ \@EAEAEA\handlecompoundcharacterone
+ \else\ifx\next\blankspace
+ \@EA\@EAEAEA\@EA\handlecompoundcharacterone
+ \else
+ \@EA\@EAEAEA\@EA\handlecompoundcharactertwo
+ \fi\fi\fi}
+
+\def\dodohandlecompoundcharacter#1#2% preserve space
+ {\def\xdodohandlecompoundcharacter{\dododohandlecompoundcharacter#1#2}%
+ \futurelet\next\xdodohandlecompoundcharacter}
+
+%D Besides taken care of the grouping and space tokens, we have
+%D to deal with three situations. First we look if the next
+%D character equals the first one, if so, then we just insert
+%D the original. Next we look if indeed a compound character is
+%D defined. We either execute the compound character or just
+%D insert the first. So we have
+%D
+%D \starttyping
+%D
+%D \stoptyping
+%D
+%D In later modules we will see how these commands are used.
+
+\long\def\handlecompoundcharacterone#1#2%
+ {\if\string#1\string#2% was: \ifx#1#2%
+ \def\next{\csname\@nc@\string#1\endcsname}%
+ \else\ifcsname\@cc@\string#1\string#2\endcsname
+ \def\next{\csname\@cc@\string#1\string#2\endcsname}%
+ \else
+ \def\next{\csname\@nc@\string#1\endcsname#2}%
+ \fi\fi
+ \next}
+
+\long\def\handlecompoundcharactertwo#1#2#3%
+ {\if\string#1\string#2%
+ \def\next{\csname\@nc@\string#1\endcsname#3}%
+ \else\ifcsname\@cs@\string#1\string#2\string#3\endcsname
+ \def\next{\csname\@cs@\string#1\string#2\string#3\endcsname}%
+ \else\ifcsname\@cc@\string#1\string#2\endcsname
+ \def\next{\csname\@cc@\string#1\string#2\endcsname#3}%
+ \else
+ \def\next{\csname\@nc@\string#1\endcsname#2#3}%
+ \fi\fi\fi
+ \next}
+
+%D For very obscure applications (see for an application \type
+%D {lang-sla.tex}) we provide:
+
+\def\simplifiedcompoundcharacter#1#2%
+ {\ifcsname\@cc@\string#1\string#2\endcsname
+ \@EA\@EA\@EA\firstofoneargument\csname\@cc@\string#1\string#2\endcsname
+ \else
+ #2%
+ \fi}
+
+%D \macros
+%D {disablediscretionaries,disablecompoundcharacter}
+%D
+%D Occasionally we need to disable this mechanism. For the
+%D moment we assume that \type {|} is used.
+
+\let\disablediscretionaries \ignorediscretionaries
+\let\disablecompoundcharacters\ignorecompoundcharacter
+
+%D \macros
+%D {normalcompound}
+%D
+%D Handy in for instance XML. (Kind of obsolete)
+
+\ifx\normalcompound\undefined \let\normalcompound=| \fi
+
+\protect \endinput
diff --git a/tex/context/base/lang-run.mkii b/tex/context/base/lang-run.mkii
new file mode 100644
index 000000000..4b332cfb9
--- /dev/null
+++ b/tex/context/base/lang-run.mkii
@@ -0,0 +1,36 @@
+%D \module
+%D [ file=lang-run,
+%D version=2005.09.08,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Runtime Macros,
+%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.
+
+%D [This code is hooked into the core macros and saves some
+%D format space.]
+
+\unprotect
+
+\gdef\showpatterns
+ {\bgroup
+ \def\doshowpatterns##1##2##3##4% language number encoding mapping
+ {\NC##1\NC##3\NC##4\NC##2\NC
+ \specificlanguageparameter{##1}\s!lefthyphenmin \NC
+ \specificlanguageparameter{##1}\s!righthyphenmin\NC\NR}%
+ \starttabulate[|c|c|c|c|c|c|]
+ \HL
+ \NC \bf language \NC \bf encoding \NC \bf mapping \NC \bf number \NC
+ \bf left\low{min} \NC
+ \bf right\low{min} \NC \NR
+ \HL
+ \preloadedpmessage
+ \HL
+ \stoptabulate
+ \egroup}
+
+\protect \endinput
diff --git a/tex/context/base/lang-sla.mkii b/tex/context/base/lang-sla.mkii
new file mode 100644
index 000000000..62483aeb6
--- /dev/null
+++ b/tex/context/base/lang-sla.mkii
@@ -0,0 +1,30 @@
+%D \module
+%D [ file=lang-sla,
+%D version=1999.09.13, % 1997.09.03
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Slavic Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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.
+
+\def\sloveniancharacter#1%
+ {\ifcase#1\unknowncharacter
+ \or a\or b\or c\or \ccaron\or d\or e\or f\or g\or h\or i\or j\or k\or l\or m%
+ \or n\or o\or p\or r\or s\or \scaron\or t\or u\or v\or z\or \zcaron
+ \else
+ \unknowncharacter
+ \fi}
+
+\def\slovenianCharacter#1%
+ {\ifcase#1\unknowncharacter
+ \or A\or B\or C\or \Ccaron\or D\or E\or F\or G\or H\or I\or J\or K\or L\or M%
+ \or N\or O\or P\or R\or S\or \Scaron\or T\or U\or V\or Z\or \Zcaron
+ \else
+ \unknowncharacter
+ \fi}
+
+\endinput
diff --git a/tex/context/base/lang-sla.mkiv b/tex/context/base/lang-sla.mkiv
new file mode 100644
index 000000000..479012615
--- /dev/null
+++ b/tex/context/base/lang-sla.mkiv
@@ -0,0 +1,17 @@
+%D \module
+%D [ file=lang-sla,
+%D version=2006.09.16,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Slavic Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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.
+
+\def\sloveniancharacters#1{\ctxlua{converters.alphabetic(\number#1,"sl")}}
+\def\slovenianCharacters#1{\ctxlua{converters.Alphabetic(\number#1,"sl")}}
+
+\endinput
diff --git a/tex/context/base/lang-sla.tex b/tex/context/base/lang-sla.tex
new file mode 100644
index 000000000..2c645af5a
--- /dev/null
+++ b/tex/context/base/lang-sla.tex
@@ -0,0 +1,497 @@
+%D \module
+%D [ file=lang-sla,
+%D version=1999.09.13, % 1997.09.03
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Slavic Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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.
+
+% Todo: replace \'.. by \namedglyph
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+%D
+%D \starttabulate[|lB|l|]
+%D \NC Czech \NC Tom Hudec, Petr Sojka \NC \NR
+%D \NC Polish \NC Grzegorz Sapijaszko \NC \NR
+%D \NC Croatian \NC \Zcaron eljko Vrba \NC \NR
+%D \NC Slovenian \NC Mojca Miklavec \NC \NR
+%D \NC Cz and Sk \NC Richard Gabriel \NC \NR
+%D \stoptabulate
+
+% Belarussian, Russian, Ukrainian, Bulgarian, Macedonian,
+% Serbo-Croatian, Slovenian, Czech, Kushubian,
+% Lusatian/Sorbian/Wendish, Polish, Slovak, Albanian,
+% Illyrian, Armenian
+
+\writestatus{loading}{ConTeXt Language Macros / Slavic Languages}
+
+\unprotect
+
+% \unexpanded\def\textormathglue#1#2#3% submitted original
+% {\begingroup
+% \scratchdimen=#1\hspaceamount\empty{#3}%
+% \scratchskip=\zeropoint\!!plus.5\scratchdimen\!!minus.3\scratchdimen\relax
+% \ifmmode
+% \mskip#1#2%
+% \else
+% \kern#1\hspaceamount\empty{#3}%
+% \hskip\scratchskip
+% \fi
+% \endgroup}
+
+% actually we could use the new pdftex features
+
+\unexpanded\def\textormathglue#1#2#3% cleaned up one
+ {\begingroup
+ \ifmmode
+ \mskip#1#2%
+ \else
+ \scratchdimen#1\hspaceamount\empty{#3}%
+ \scratchskip\scratchdimen\!!plus.5\scratchdimen\!!minus.3\scratchdimen
+ \hskip\scratchskip
+ \fi
+ \endgroup}
+
+\def\thinglue {\textormathglue+\thinmuskip 1}
+\def\medglue {\textormathglue+\medmuskip 2}
+\def\thickglue{\textormathglue+\thickmuskip3}
+
+\installlanguage
+ [\s!pl]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\lowerleftsingleninequote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\lowerleftdoubleninequote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!day,{.},\ ,\v!month,\ ,\v!year},
+ \s!mapping={pl0,ec,qx},
+ \s!encoding={pl0,ec,qx}]
+
+\installlanguage
+ [\s!cs]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=\thickglue--\thickglue\penalty-20\relax, % hh, \relax added
+ \c!rightsentence=\thickglue--\thickglue\penalty-20\relax,
+ \c!leftsubsentence=~---~\penalty-20\relax,
+ \c!rightsubsentence=~---~\penalty-20\relax,
+ \c!leftquote=\lowerleftsingleninequote,
+ \c!rightquote=\upperrightsinglesixquote,
+ \c!leftquotation=\lowerleftdoubleninequote,
+ \c!rightquotation=\upperrightdoublesixquote,
+ \c!date={\v!day,{.\,},\v!month,\ ,\v!year},
+ \s!mapping={il2,ec},
+ \s!encoding={il2,ec}]
+
+\installlanguage
+ [\s!sk]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!day,{.\,},\v!month,\ ,\v!year},
+ \s!mapping={il2,ec},
+ \s!encoding={il2,ec}]
+
+\installlanguage
+ [\s!hr]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year},
+ \s!mapping=ec,
+ \s!encoding=ec]
+
+%D The default quotation marks for Slovenian were chosen as
+%D \lowerleftdoubleninequote these ones\upperrightdoublesixquote\
+%D which was probably due to the strong influence computers
+%D had on typesetting, but \rightguillemot these ones\leftguillemot\
+%D are \quotation{more correct}.
+%D
+%D If you still want the other quotation marks, use this:
+%D
+%D \starttyping
+%D \installlanguage
+%D [sl]
+%D [leftquote=\lowerleftsingleninequote,
+%D rightquote=\upperrightsinglesixquote,
+%D leftquotation=\lowerleftdoubleninequote,
+%D rightquotation=\upperrightdoublesixquote]
+%D \stoptyping
+%D
+%D If you disagree with the change, please send an email to Mojca, but
+%D best use some pretty strong arguments because she loves S{\sl love}nia
+%D to much to comprimise on this.
+%D
+%D German faces approximately the same problem. I (MM) would prefer to
+%D have something like:
+%D
+%D \starttyping
+%D \mainlanguage[sl][quotationstyle=guillemot|doublequote] % better name needed
+%D \stoptyping
+%D
+%D but users are expected to respect the rules of nice and correct
+%D typography anyway.
+
+\installlanguage
+ [\s!sl]
+ [\c!spacing=\v!packed,
+ \c!leftsentence={\hbox{--~}},
+ \c!rightsentence={\hbox{~--}},
+ \c!leftsubsentence={--},
+ \c!rightsubsentence={--},
+ %\c!leftquote=\lowerleftsingleninequote,
+ %\c!rightquote=\upperrightsinglesixquote,
+ %\c!leftquotation=\lowerleftdoubleninequote,
+ %\c!rightquotation=\upperrightdoublesixquote,
+ \c!leftquote=\guilsingleright,
+ \c!rightquote=\guilsingleleft,
+ \c!leftquotation=\rightguillemot,
+ \c!rightquotation=\leftguillemot,
+ \c!date={\v!day,{.},\ ,\v!month,\ ,\v!year},
+ \s!mapping=ec,
+ \s!encoding=ec]
+
+\installlanguage [polish] [\s!pl]
+\installlanguage [czech] [\s!cs]
+\installlanguage [slovak] [\s!sk]
+\installlanguage [croatian] [\s!hr]
+\installlanguage [slovenian] [\s!sl]
+\installlanguage [slovene] [\s!sl] % both possible (mojca: still needed?)
+
+\installlanguage [cz] [\s!cs]
+
+% labels
+
+\setupheadtext [\s!pl] [\v!content=Spis tre\sacute ci]
+\setupheadtext [\s!cs] [\v!content=Obsah]
+\setupheadtext [\s!sk] [\v!content=Obsah]
+\setupheadtext [\s!hr] [\v!content=Sadr\zcaron aj]
+\setupheadtext [\s!sl] [\v!content=Kazalo]
+
+\setupheadtext [\s!pl] [\v!tables=Tabele]
+\setupheadtext [\s!cs] [\v!tables=Tabulky]
+\setupheadtext [\s!sk] [\v!tables=Tabuliek]
+\setupheadtext [\s!hr] [\v!tables=Tablice]
+\setupheadtext [\s!sl] [\v!tables=Tabele]
+
+\setupheadtext [\s!pl] [\v!figures=Ilustracje]
+\setupheadtext [\s!cs] [\v!figures=Obr\aacute zky]
+\setupheadtext [\s!sk] [\v!figures=Obr\aacute zkov]
+\setupheadtext [\s!hr] [\v!figures=Slike]
+\setupheadtext [\s!sl] [\v!figures=Slike]
+
+\setupheadtext [\s!pl] [\v!graphics=Grafika]
+\setupheadtext [\s!cs] [\v!graphics=Grafy]
+\setupheadtext [\s!sk] [\v!graphics=Graf]
+\setupheadtext [\s!hr] [\v!graphics=Slike]
+\setupheadtext [\s!sl] [\v!graphics=Slike]
+
+\setupheadtext [\s!pl] [\v!intermezzi=Intermezza]
+\setupheadtext [\s!cs] [\v!intermezzi=Intermezza]
+\setupheadtext [\s!sk] [\v!intermezzi=Intermezz\aacute]
+\setupheadtext [\s!hr] [\v!intermezzi=Intermezza]
+\setupheadtext [\s!sl] [\v!intermezzi=Intermezzi]
+
+\setupheadtext [\s!pl] [\v!index=Indeks]
+\setupheadtext [\s!cs] [\v!index=Rejst\rcaron\iacute k]
+\setupheadtext [\s!sk] [\v!index=Zoznam]
+\setupheadtext [\s!hr] [\v!index=Indeks]
+\setupheadtext [\s!sl] [\v!index=Stvarno kazalo]
+
+\setupheadtext [\s!pl] [\v!abbreviations=Skr\oacute cenie]
+\setupheadtext [\s!cs] [\v!abbreviations=Zkratky]
+\setupheadtext [\s!sk] [\v!abbreviations=Skratky]
+\setupheadtext [\s!hr] [\v!abbreviations=Kratice]
+\setupheadtext [\s!sl] [\v!abbreviations=Kratice]
+
+\setupheadtext [\s!pl] [\v!logos=Znaki]
+\setupheadtext [\s!cs] [\v!logos=Loga]
+\setupheadtext [\s!sk] [\v!logos=Log\aacute]
+\setupheadtext [\s!hr] [\v!logos=Znakovi]
+\setupheadtext [\s!sl] [\v!logos=Logotipi]
+
+\setupheadtext [\s!pl] [\v!units=Jednostki]
+\setupheadtext [\s!cs] [\v!units=Jednotky]
+\setupheadtext [\s!sk] [\v!units=Jednotky]
+\setupheadtext [\s!hr] [\v!units=Jednostki]
+\setupheadtext [\s!sl] [\v!units=Enote]
+
+%setupheadtext [\s!pl] [pubs=?]
+\setupheadtext [\s!cs] [pubs=Literatura]
+%setupheadtext [\s!sk] [pubs=?]
+%setupheadtext [\s!hr] [pubs=?]
+\setupheadtext [\s!sl] [pubs=Literatura]
+
+\setuplabeltext [\s!pl] [\v!table=Tabela ]
+\setuplabeltext [\s!cs] [\v!table=Tabulka ]
+\setuplabeltext [\s!sk] [\v!table=Tabu\lcaron ka ]
+\setuplabeltext [\s!hr] [\v!table=T\aacute bl\aacute zat ] % [\v!table=Tablica ]
+\setuplabeltext [\s!sl] [\v!table=Tabela ]
+
+\setuplabeltext [\s!pl] [\v!figure=Ilustracja ]
+\setuplabeltext [\s!cs] [\v!figure=Obr\aacute zek ]
+\setuplabeltext [\s!sk] [\v!figure=Obr\aacute zok ]
+\setuplabeltext [\s!hr] [\v!figure=Slika ]
+\setuplabeltext [\s!sl] [\v!figure=Slika ]
+
+\setuplabeltext [\s!pl] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!cs] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!sk] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!hr] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!sl] [\v!intermezzo=Intermezzo ]
+
+\setuplabeltext [\s!pl] [\v!graphic=Grafika ]
+\setuplabeltext [\s!cs] [\v!graphic=Graf ]
+\setuplabeltext [\s!sk] [\v!graphic=Graf ]
+\setuplabeltext [\s!hr] [\v!graphic=Slika ]
+\setuplabeltext [\s!sl] [\v!graphic=Slika ]
+
+\setuplabeltext [\s!pl] [\v!chapter=] % Rozdzia\l
+\setuplabeltext [\s!cs] [\v!chapter=] % Kapitola
+\setuplabeltext [\s!sk] [\v!chapter=] % Kapitola
+\setuplabeltext [\s!hr] [\v!chapter=] % Rozdzia\l
+\setuplabeltext [\s!sl] [\v!chapter=] % Poglavje
+
+\setuplabeltext [\s!pl] [\v!section=] % Podrozdzia\l
+\setuplabeltext [\s!cs] [\v!section=] % Sekce
+\setuplabeltext [\s!sk] [\v!section=] % Sekcia
+\setuplabeltext [\s!hr] [\v!section=] % Podrozdzia\l
+\setuplabeltext [\s!sl] [\v!section=]
+
+\setuplabeltext [\s!pl] [\v!subsection=]
+\setuplabeltext [\s!cs] [\v!subsection=] % Podsekce
+\setuplabeltext [\s!sk] [\v!subsection=] % Podsekcia
+\setuplabeltext [\s!hr] [\v!subsection=]
+\setuplabeltext [\s!sl] [\v!subsection=]
+
+\setuplabeltext [\s!pl] [\v!subsubsection=]
+\setuplabeltext [\s!cs] [\v!subsubsection=] % Podpodsekce
+\setuplabeltext [\s!sk] [\v!subsubsection=] % Podpodsekcia
+\setuplabeltext [\s!hr] [\v!subsubsection=]
+\setuplabeltext [\s!sl] [\v!subsubsection=]
+
+\setuplabeltext [\s!pl] [\v!subsubsubsection=]
+\setuplabeltext [\s!cs] [\v!subsubsubsection=] % Podpodpodsekce
+\setuplabeltext [\s!sk] [\v!subsubsubsection=] % Podpodpodsekcia
+\setuplabeltext [\s!hr] [\v!subsubsubsection=]
+\setuplabeltext [\s!sl] [\v!subsubsubsection=]
+
+\setuplabeltext [\s!pl] [\v!appendix=] % Dodatek
+\setuplabeltext [\s!cs] [\v!appendix=P\rcaron\iacute loha ]
+\setuplabeltext [\s!sk] [\v!appendix=Pr\iacute loha ]
+\setuplabeltext [\s!hr] [\v!appendix=Dodatak ]
+\setuplabeltext [\s!sl] [\v!appendix=Dodatek ]
+
+\setuplabeltext [\s!pl] [\v!part=Ust\eogonek p ]
+\setuplabeltext [\s!cs] [\v!part=\Ccaron \aacute st ]
+\setuplabeltext [\s!sk] [\v!part=\Ccaron as\tcaron{} ]
+\setuplabeltext [\s!hr] [\v!part=Dio ]
+\setuplabeltext [\s!sl] [\v!part=Del ]
+
+\setuplabeltext [\s!pl] [\v!line=wiersz ]
+\setuplabeltext [\s!cs] [\v!line=\rcaron\aacute dek ]
+\setuplabeltext [\s!sk] [\v!line=riadok ]
+\setuplabeltext [\s!hr] [\v!line=red ]
+\setuplabeltext [\s!sl] [\v!line=vrstica ]
+
+\setuplabeltext [\s!pl] [\v!lines=wiersze ]
+\setuplabeltext [\s!cs] [\v!lines=\rcaron\aacute dky ]
+\setuplabeltext [\s!sk] [\v!lines=riadky ]
+\setuplabeltext [\s!hr] [\v!lines=redovi ]
+\setuplabeltext [\s!sl] [\v!lines=vrstice ]
+
+\setuplabeltext [\s!pl] [\v!january=stycznia]
+\setuplabeltext [\s!pl] [\v!february=lutego]
+\setuplabeltext [\s!pl] [\v!march=marca]
+\setuplabeltext [\s!pl] [\v!april=kwietnia]
+\setuplabeltext [\s!pl] [\v!may=maja]
+\setuplabeltext [\s!pl] [\v!june=czerwca]
+\setuplabeltext [\s!pl] [\v!july=lipca]
+\setuplabeltext [\s!pl] [\v!august=sierpnia]
+\setuplabeltext [\s!pl] [\v!september=wrze\sacute nia]
+\setuplabeltext [\s!pl] [\v!october=pa\zacute dziernika]
+\setuplabeltext [\s!pl] [\v!november=listopada]
+\setuplabeltext [\s!pl] [\v!december=grudnia]
+
+\setuplabeltext [\s!cs] [\v!january=ledna]
+\setuplabeltext [\s!cs] [\v!february=\uacute nora]
+\setuplabeltext [\s!cs] [\v!march=b\rcaron ezna]
+\setuplabeltext [\s!cs] [\v!april=dubna]
+\setuplabeltext [\s!cs] [\v!may=kv\ecaron tna]
+\setuplabeltext [\s!cs] [\v!june=\ccaron ervna]
+\setuplabeltext [\s!cs] [\v!july=\ccaron ervence]
+\setuplabeltext [\s!cs] [\v!august=srpna]
+\setuplabeltext [\s!cs] [\v!september=z\aacute\rcaron\iacute{}]
+\setuplabeltext [\s!cs] [\v!october=\rcaron\iacute jna]
+\setuplabeltext [\s!cs] [\v!november=listopadu]
+\setuplabeltext [\s!cs] [\v!december=prosince]
+
+\setuplabeltext [\s!sk] [\v!january=janu\aacute ra]
+\setuplabeltext [\s!sk] [\v!february=febru\aacute ra]
+\setuplabeltext [\s!sk] [\v!march=marca]
+\setuplabeltext [\s!sk] [\v!april=apr\iacute la]
+\setuplabeltext [\s!sk] [\v!may=m\aacute ja]
+\setuplabeltext [\s!sk] [\v!june=j\uacute na]
+\setuplabeltext [\s!sk] [\v!july=j\uacute la]
+\setuplabeltext [\s!sk] [\v!august=augusta]
+\setuplabeltext [\s!sk] [\v!september=septembra]
+\setuplabeltext [\s!sk] [\v!october=okt\oacute bra]
+\setuplabeltext [\s!sk] [\v!november=novembra]
+\setuplabeltext [\s!sk] [\v!december=decembra]
+
+\setuplabeltext [\s!hr] [\v!january=sije\ccaron anj]
+\setuplabeltext [\s!hr] [\v!february=velja\ccaron a]
+\setuplabeltext [\s!hr] [\v!march=o\zcaron ujak]
+\setuplabeltext [\s!hr] [\v!april=travanj]
+\setuplabeltext [\s!hr] [\v!may=svibanj]
+\setuplabeltext [\s!hr] [\v!june=lipanj]
+\setuplabeltext [\s!hr] [\v!july=srpanj]
+\setuplabeltext [\s!hr] [\v!august=kolovoz]
+\setuplabeltext [\s!hr] [\v!september=rujan]
+\setuplabeltext [\s!hr] [\v!october=listopad]
+\setuplabeltext [\s!hr] [\v!november=studeni]
+\setuplabeltext [\s!hr] [\v!december=prosinac]
+
+\setuplabeltext [\s!sl] [\v!january=januar]
+\setuplabeltext [\s!sl] [\v!february=februar]
+\setuplabeltext [\s!sl] [\v!march=marec]
+\setuplabeltext [\s!sl] [\v!april=april]
+\setuplabeltext [\s!sl] [\v!may=maj]
+\setuplabeltext [\s!sl] [\v!june=junij]
+\setuplabeltext [\s!sl] [\v!july=julij]
+\setuplabeltext [\s!sl] [\v!august=avgust]
+\setuplabeltext [\s!sl] [\v!september=september]
+\setuplabeltext [\s!sl] [\v!october=oktober]
+\setuplabeltext [\s!sl] [\v!november=november]
+\setuplabeltext [\s!sl] [\v!december=december]
+
+\setuplabeltext [\s!pl] [\v!sunday=niedziela]
+\setuplabeltext [\s!pl] [\v!monday=poniedzia\lstroke ek]
+\setuplabeltext [\s!pl] [\v!tuesday=wtorek]
+\setuplabeltext [\s!pl] [\v!wednesday=\sacute roda]
+\setuplabeltext [\s!pl] [\v!thursday=czwartek]
+\setuplabeltext [\s!pl] [\v!friday=pi\aogonek tek]
+\setuplabeltext [\s!pl] [\v!saturday=sobota]
+
+% new
+\setuplabeltext [\s!cs] [\v!sunday=ned\ecaron le]
+\setuplabeltext [\s!cs] [\v!monday=pond\ecaron l\iacute]
+\setuplabeltext [\s!cs] [\v!tuesday=\uacute ter\yacute]
+\setuplabeltext [\s!cs] [\v!wednesday=st\rcaron eda]
+\setuplabeltext [\s!cs] [\v!thursday=\ccaron tvrtek]
+\setuplabeltext [\s!cs] [\v!friday=p\aacute tek]
+\setuplabeltext [\s!cs] [\v!saturday=sobota]
+
+\setuplabeltext [\s!hr] [\v!sunday=nedjelja]
+\setuplabeltext [\s!hr] [\v!monday=ponedjeljak]
+\setuplabeltext [\s!hr] [\v!tuesday=utorak]
+\setuplabeltext [\s!hr] [\v!wednesday=srijeda]
+\setuplabeltext [\s!hr] [\v!thursday=\ccaron etvrtak]
+\setuplabeltext [\s!hr] [\v!friday=petak]
+\setuplabeltext [\s!hr] [\v!saturday=subota]
+
+\setuplabeltext [\s!sl] [\v!sunday=nedelja]
+\setuplabeltext [\s!sl] [\v!monday=ponedeljek]
+\setuplabeltext [\s!sl] [\v!tuesday=torek]
+\setuplabeltext [\s!sl] [\v!wednesday=sreda]
+\setuplabeltext [\s!sl] [\v!thursday=\ccaron etrtek]
+\setuplabeltext [\s!sl] [\v!friday=petek]
+\setuplabeltext [\s!sl] [\v!saturday=sobota]
+
+%D Rather new ...
+%\installlanguage
+% [\s!cs]
+% [\c!spacing=\v!packed,
+% \c!leftsentence=---,
+% \c!rightsentence=---,
+% \c!leftsubsentence=---,
+% \c!rightsubsentence=---,
+% \c!leftquote=\lowerleftsingleninequote,
+% \c!rightquote=\upperrightsinglesixquote,
+% \c!leftquotation=\lowerleftdoubleninequote,
+% \c!rightquotation=\upperrightdoublesixquote,
+% \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
+
+\setuplabeltext [\s!sl] [\v!page=stran ]
+\setuplabeltext [\s!sl] [\v!atpage=na strani ]
+\setuplabeltext [\s!sl] [\v!hencefore=glej zgoraj]
+\setuplabeltext [\s!sl] [\v!hereafter=glej spodaj]
+\setuplabeltext [\s!sl] [\v!see=glej ]
+
+% new
+\setuplabeltext [\s!cs] [\v!page=strana ]
+\setuplabeltext [\s!cs] [\v!atpage=na stran\ecaron\ ]
+\setuplabeltext [\s!cs] [\v!hencefore=viz v\yacute\scaron e ]
+\setuplabeltext [\s!cs] [\v!hereafter=viz n\iacute\zcaron e ]
+\setuplabeltext [\s!cs] [\v!see=viz ]
+
+%D \ShowAllLanguageValues [\s!pl] [polish] {Polish} {furniture}
+%D \ShowAllLanguageValues [\s!cs] [czech] {Czech} {mate}
+%D \ShowAllLanguageValues [\s!sk] [slovak] {Slovakian} {face}
+%D \ShowAllLanguageValues [\s!hr] [croatian] {Croatian} {heartthrob}
+%D \ShowAllLanguageValues [\s!sl] [slovenian] {Slovenian} {mountains}
+
+%D A present from Brooks Moses and Hans Hagen for Mojca Miklavec:
+
+\def\doconvertsloveniancharacters{\dodoconvertcharacters{25}}
+
+\def\sloveniancharacters{\doconvertsloveniancharacters\sloveniancharacter}
+\def\slovenianCharacters{\doconvertsloveniancharacters\slovenianCharacter}
+
+%D Define general-purpose macros for Slovenian character enumerations:
+
+\defineconversion [sloveniancharacter] [\sloveniancharacter]
+\defineconversion [slovenianCharacter] [\slovenianCharacter]
+
+\defineconversion [sloveniancharacters] [\sloveniancharacters]
+\defineconversion [slovenianCharacters] [\slovenianCharacters]
+
+%D Define these as the general character enumeration when
+%D language is Slovenian. If you feel uncomfortable with this,
+%D mail Mojca, since she promised to to take the heat.
+
+\defineconversion [sl] [character] [\sloveniancharacter]
+\defineconversion [sl] [Character] [\slovenianCharacter]
+
+\defineconversion [sl] [characters] [\sloveniancharacters]
+\defineconversion [sl] [Characters] [\slovenianCharacters]
+
+\defineconversion [sl] [a] [\sloveniancharacters]
+\defineconversion [sl] [A] [\slovenianCharacters]
+\defineconversion [sl] [AK] [\smallcapped\sloveniancharacters]
+\defineconversion [sl] [KA] [\smallcapped\sloveniancharacters]
+
+% this will become more generic : \languagecharacters{sl}{..}
+
+\let\sloveniancharacter\gobbleoneargument
+\let\slovenianCharacter\gobbleoneargument
+
+%D Plugins:
+
+\loadmarkfile{lang-sla}
+
+\protect \endinput
diff --git a/tex/context/base/lang-spa.tex b/tex/context/base/lang-spa.tex
new file mode 100644
index 000000000..f6e22aa51
--- /dev/null
+++ b/tex/context/base/lang-spa.tex
@@ -0,0 +1,74 @@
+%D \module
+%D [ file=lang-spa,
+%D version=2002.04.17,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Spacing,
+%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 Language Macros / Spacing}
+
+%D This module was created in the process of enhancing
+%D support for French (with the help of Daniel Flipo).
+
+\unprotect
+
+\definehspace [\s!fr] [quotation] [\flexiblespaceamount{.8}{.3}{.8}]
+\definehspace [\s!fr] [sentence] [\fixedspaceamount{1}]
+
+%definehspace [\s!fr] [quote] [\flexiblespaceamount{.8}{.3}{.8}]
+%definehspace [\s!fr] [speech] [\flexiblespaceamount{.8}{.3}{.8}]
+
+\definehspace [\s!fr] [interquotation] [\zeropoint]
+\definehspace [\s!fr] [intersentence] [\zeropoint]
+
+\definehspace [\string :] [\zeropoint]
+\definehspace [\string ;] [\zeropoint]
+\definehspace [\string !] [\zeropoint]
+\definehspace [\string ?] [\zeropoint]
+
+\definehspace [\s!fr] [\string :] [\spaceamount]
+\definehspace [\s!fr] [\string ;] [.16667em]
+\definehspace [\s!fr] [\string !] [.16667em]
+\definehspace [\s!fr] [\string ?] [.16667em]
+
+%D Alternative discretionary handlers:
+
+\definetextmodediscretionary :
+ {\removeunwantedspaces\prewordbreak\kern\hspaceamount\currentlanguage{:}:}
+
+\definetextmodediscretionary ;
+ {\removeunwantedspaces\prewordbreak\kern\hspaceamount\currentlanguage{;};}
+
+\definetextmodediscretionary ?
+ {\removeunwantedspaces\prewordbreak\kern\hspaceamount\currentlanguage{?}?}
+
+\definetextmodediscretionary !
+ {\removeunwantedspaces\prewordbreak\kern\hspaceamount\currentlanguage{!}!}
+
+%D \startbuffer
+%D \mainlanguage[en] \quotation{test \quotation{test} test}\par
+%D \mainlanguage[nl] \quotation{test \quotation{test} test}\par
+%D \mainlanguage[fr] \quotation{test \quotation{test} test}\par
+%D
+%D \mainlanguage[en] \quotation{\quotation{test} test}\par
+%D \mainlanguage[nl] \quotation{\quotation{test} test}\par
+%D \mainlanguage[fr] \quotation{\quotation{test} test}\par
+%D
+%D \mainlanguage[en] |<|test |<|test|>| test|>| \par
+%D \mainlanguage[nl] |<|test |<|test|>| test|>| \par
+%D \mainlanguage[fr] |<|test |<|test|>| test|>| \par
+%D
+%D \mainlanguage[en] |<||<|test|>| test|>| \par
+%D \mainlanguage[nl] |<||<|test|>| test|>| \par
+%D \mainlanguage[fr] |<||<|test|>| test|>| \par
+%D \stopbuffer
+%D
+%D \typebuffer {\getbuffer}
+
+\protect \endinput
diff --git a/tex/context/base/lang-spe.mkii b/tex/context/base/lang-spe.mkii
new file mode 100644
index 000000000..7911b0c95
--- /dev/null
+++ b/tex/context/base/lang-spe.mkii
@@ -0,0 +1,244 @@
+%D \module
+%D [ file=lang-spe,
+%D version=2002.05.07, % 1996.01.25,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Specifics,
+%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.
+
+%D This code was originally placed in the language
+%D initialization module, but isolating it is clearer. Language
+%D specifics evolved out of user demands for special features,
+%D like the german active quote. After a while I decided to
+%D associate them to languages in a more general way so that we
+%D could associate all kind of things with language switching.
+%D
+%D This is a typical example of functionality that occasionally
+%D gets improved based on user input and experience. Much of the
+%D code is pretty old and could probabbly be done in better ways.
+%D It's probably also the kind of code that has been and will be
+%D written over and over again by \TEX\ users around the world,
+%D so there are probably better implementations of similar
+%D functionality around. Therefore, users are invited to pop in
+%D their own handling as long as it does not interfere with
+%D existing code. Writing the more obscure macros that deal with
+%D this is a good learning experience (catcodes, lccodes, token
+%D lists, expansion, \unknown).
+
+\writestatus{loading}{ConTeXt Language Macros / Specifics}
+
+\unprotect
+
+%D \macros
+%D {everyresetlanguagespecifics,resetlanguagespecifics}
+%D
+%D Cleanup macros.
+
+\newevery \everyresetlanguagespecifics \relax
+
+\def\resetlanguagespecifics
+ {\ifcase\protectionlevel
+ \the\everyresetlanguagespecifics
+ \else % to be translated
+ % \writestatus\m!systems{don't change language in unprotected mode!}%
+ \fi}
+
+\appendtoks
+ \resetlanguagespecifics
+\to \everycleanupfeatures
+
+%D \macros
+%D {startlanguagespecifics,enablelanguagespecifics}
+%D
+%D Each language has its own typographic pecularities. Some of
+%D those can be influenced by parameters, others are handled by
+%D the interface, but as soon as specific commands come into
+%D view we need another mechanism. In the macro that activates
+%D a language, we call \type{\enablelanguagespecifics}. This
+%D macro in return calls for the setup of language specific
+%D macros. Such specifics are defined as:
+%D
+%D \starttyping
+%D \startlanguagespecifics[de]
+%D \installcompoundcharacter "a {\"a}
+%D \installcompoundcharacter "e {\"e}
+%D \installcompoundcharacter "s {\SS}
+%D \stoplanguagespecifics
+%D \stoptyping
+%D
+%D Instead of \type{[du]} we can pass a comma separated
+%D list, like \type{[du,nl]}. Next calls to this macro add the
+%D specifics to the current list.
+%D
+%D Before we actually read the specifics, we first take some
+%D precautions that will prevent spurious spaces to creep into
+%D the list.
+
+% We should use token registers, but alas, we run out of them and
+% \ETEX\ has a bug. Well, let's use a token register now (2006).
+
+\def\startlanguagespecifics% % we use double to
+ {\bgroup
+ \catcode`\^^I=\@@ignore
+ \catcode`\^^M=\@@ignore
+ \catcode`\^^L=\@@ignore
+ \dodoubleempty\dostartlanguagespecifics} % get rid of spaces
+
+%D The main macro looks quite complicated but actually does
+%D nothing special. By embedding \type{\do} we can easily
+%D append to the lists and also execute them at will. Just to
+%D be sure, we check on spurious spaces. The second dummy
+%D argument gobbles spaces.
+
+\def\languageencoding
+ {\ifx\characterencoding\nocharacterencoding \else
+ \characterencoding-%
+ \fi}
+
+\long\def\dostartlanguagespecifics[#1][#2]#3\stoplanguagespecifics
+ {\egroup
+ \processcommalist[#1]{\dosetlanguagespecifics{#3}}}
+
+% \long\def\dosetlanguagespecifics#1#2%
+% {\ifundefined{\??la\languageencoding#2\??la}\forgetlanguagespecifics[#2]\fi
+% % the next line catches the case that specifics are enabled *before* they are defined
+% \expandafter\ifx\csname\??la\languageencoding#2\??la\endcsname\relax\forgetlanguagespecifics[#2]\fi
+% \appendvalue{\??la\languageencoding#2\??la}{#1}%
+% \bgroup
+% \setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}%
+% \ifdim\wd\scratchbox>\zeropoint
+% \showmessage\m!linguals7{\currentencoding-#2,\the\wd\scratchbox\space}\wait
+% \else
+% \showmessage\m!linguals8{\currentencoding-#2}%
+% \fi
+% \egroup
+% \doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}}
+
+\def\languagespectag#1{\??la\languageencoding#1\??la}
+
+\long\def\dosetlanguagespecifics#1#2%
+ {\edef\askedlanguagespecificstag{\languagespectag{#2}}%
+ \ifcsname\askedlanguagespecificstag\endcsname \else
+ \expandafter\newtoks\csname\askedlanguagespecificstag\endcsname
+ \fi
+ \csname\askedlanguagespecificstag\endcsname\@EA{\the\csname\askedlanguagespecificstag\endcsname#1}%
+ \bgroup
+ \setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \showmessage\m!linguals7{\currentencoding-#2,\the\wd\scratchbox\space}\wait
+ \else
+ \showmessage\m!linguals8{\currentencoding-#2}%
+ \fi
+ \egroup
+ \doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}}
+
+\def\forgetlanguagespecifics[#1]%
+ {\csname\languagespectag{#1}\endcsname\emptytoks}
+
+%D Enabling them is rather straightforward. We only have to
+%D define \type{\do} in such a way that \type{{ }} is removed
+%D and the language key is gobbled.
+
+% \def\enablelanguagespecifics[#1]%
+% {\the\executeifdefined{\??la
+% \@EA\ifx\csname\??la#1\c!default\endcsname\relax
+% \languageencoding
+% \else
+% \csname\??la#1\c!default\endcsname
+% \fi
+% \??la}\emptytoks
+% \the\executeifdefined{\??la#1\??la}\emptytoks
+% \the\executeifdefined{\??la\languageencoding#1\??la}\emptytoks} % dup ?
+
+\def\enablelanguagespecifics[#1]%
+ {\edef\askedlanguagespecificslanguage{\defaultlanguage{#1}}%
+ \ifcsname\??la\askedlanguagespecificslanguage\??la\endcsname
+ \the\csname\??la\askedlanguagespecificslanguage\??la\endcsname
+ \fi
+ \ifx\languageencoding\empty\else
+ \ifcsname\??la\languageencoding\askedlanguagespecificslanguage\??la\endcsname
+ \the\csname\??la\languageencoding\askedlanguagespecificslanguage\??la\endcsname
+ \fi
+ \fi}
+
+%D \macros
+%D {deactivatelanguagespecific}
+%D
+%D The next code makes it possible to disable the specifics.
+
+% \def\deactivatelanguagespecific#1%
+% {\ifundefined{l g s \string#1}%
+% \letgvalueempty{l g s \string#1}% signal to prevent dup def
+% \bgroup
+% \catcode`#1=\@@active
+% \uccode`~=`#1
+% \uppercase{\doglobal\appendtoks\dodeactivatetoken{~}\to\everyresetlanguagespecifics}%
+% \egroup
+% \expanded{\doglobal\noexpand\appendtoks{#1}{\the\catcode`#1}}\to\everyresetlanguagespecifics
+% \fi}
+
+% \def\dodeactivatetoken#1#2#3% test needed to avoid clash with \unprotect
+% {\def#1{#2}\ifnum\catcode`#2=\@@active\catcode`#2=#3\relax\fi}
+
+%D We cannot hook this into the installer since language
+%D specifics can be anything. So far, we have the following
+%D potentially active characters.
+
+%D Beware, this should happen under an unprotected regime;
+%D thanks to Giuseppe Oblomov Bilotta, who first noticed
+%D that something was wrong.
+
+\protect
+
+% \deactivatelanguagespecific "
+% \deactivatelanguagespecific /
+% \deactivatelanguagespecific :
+% \deactivatelanguagespecific ;
+% \deactivatelanguagespecific ?
+% \deactivatelanguagespecific !
+
+\unprotect
+
+% yes or no (taco wins: no)
+
+% \startlanguagespecifics[nl,cs,sk,fr]
+% \lccode`\'=`\'
+% \stoplanguagespecifics
+
+%D \macros
+%D {ordinaldaynumber, highordinalstr, ordinalstr}
+%D
+%D Efficient general ordinal number converters are sometimes
+%D difficult to implement. Fortunately dates never exceed the
+%D number~31.
+
+\ifx\high \undefined \let\high \firstofoneargument \fi % todo
+\ifx\notsmallcapped\undefined \let\notsmallcapped\firstofoneargument \fi % todo
+
+\def\highordinalstr#1{\high{\notsmallcapped{#1}}}
+\def\ordinalstr #1{\notsmallcapped{#1}}
+
+\def\ordinaldaynumber#1% \strippedcsname\ordinaldaynumber
+ {\expanded{\executeifdefined{\currentlanguage ordinaldaynumber}%
+ \noexpand\firstofoneargument{\number#1}}}
+
+%D Language specific converters have definitions like:
+%D
+%D \starttyping
+%D \def\enordinaldaynumber#1{...}
+%D \stoptyping
+%D
+%D Examples can be found in the other \type {lang} modules.
+
+% \ifprocessingXML is a nasty dependency
+
+\appendtoks
+ \ifprocessingXML \else \resetlanguagespecifics \fi
+\to \everylanguage
+
+\protect \endinput
diff --git a/tex/context/base/lang-ura.tex b/tex/context/base/lang-ura.tex
new file mode 100644
index 000000000..a2bcd3d2b
--- /dev/null
+++ b/tex/context/base/lang-ura.tex
@@ -0,0 +1,158 @@
+%D \module
+%D [ file=lang-sla,
+%D version=1997.09.03,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Uralic Languages,
+%D author=Hans Hagen / Tobias Burnus,
+%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.
+
+% Todo: replace \'.. by \namedglyph
+
+\writestatus{loading}{ConTeXt Language Macros / Uralic Languages}
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+%D
+%D \starttabulate[|lB|l|]
+%D \NC Finnish \NC \NC \NR
+%D \NC Hungarian \NC Balazs Nagy \NC \NR
+%D \stoptabulate
+
+% Cheremiss, Estonian, Finnish, Karelian, Laap, Mordvinian,
+% Permian tongues, Hungarian, Ostyak, Vogul, Samoyed
+
+\unprotect
+
+\installlanguage
+ [\s!fi]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day}]
+
+\installlanguage
+ [\s!hu]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\lowerleftsingleninequote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\lowerleftdoubleninequote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!date={\v!year,.,\ ,\v!month,\ ,\v!day,.},
+ \s!mapping=ec,
+ \s!encoding=ec]
+
+\installlanguage [finish] [\s!fi]
+\installlanguage [hungarian] [\s!hu]
+
+\setupheadtext [\s!fi] [\v!content=Sis\"allys]
+\setupheadtext [\s!fi] [\v!tables=Taulukkoj]
+\setupheadtext [\s!fi] [\v!figures=Kuvi]
+\setupheadtext [\s!fi] [\v!graphics=Grafiikkaoi]
+\setupheadtext [\s!fi] [\v!intermezzi=Intermezzos]
+\setupheadtext [\s!fi] [\v!index=Indeksiluku]
+\setupheadtext [\s!fi] [\v!abbreviations=Lyhennyksi]
+\setupheadtext [\s!fi] [\v!logos=Vertauskuva]
+\setupheadtext [\s!fi] [\v!units=Yksik\"ot]
+
+\setupheadtext [\s!hu] [\v!content=Tartalom]
+\setupheadtext [\s!hu] [\v!tables=T\'abl\'azatok]
+\setupheadtext [\s!hu] [\v!figures=\'Abr\'ak]
+\setupheadtext [\s!hu] [\v!graphics=Grafik\'ak]
+\setupheadtext [\s!hu] [\v!intermezzi=Intermezzok]
+\setupheadtext [\s!hu] [\v!index=Index]
+\setupheadtext [\s!hu] [\v!abbreviations=R\"ovid\'it\'esek]
+\setupheadtext [\s!hu] [\v!logos=Fejl\'ecek]
+\setupheadtext [\s!hu] [\v!units=M\'ert\'ekegys\'egek]
+
+\setuplabeltext [\s!fi] [\v!table=Taulukko ]
+\setuplabeltext [\s!fi] [\v!figure=Kuva ]
+\setuplabeltext [\s!fi] [\v!intermezzo=Intermezzo ]
+\setuplabeltext [\s!fi] [\v!graphic=Grafiikka ]
+\setuplabeltext [\s!fi] [\v!chapter=]
+\setuplabeltext [\s!fi] [\v!section=]
+\setuplabeltext [\s!fi] [\v!subsection=]
+\setuplabeltext [\s!fi] [\v!subsubsection=]
+\setuplabeltext [\s!fi] [\v!subsubsubsection=]
+\setuplabeltext [\s!fi] [\v!appendix=]
+\setuplabeltext [\s!fi] [\v!part=Osa ]
+\setuplabeltext [\s!fi] [\v!line=rivi ]
+\setuplabeltext [\s!fi] [\v!lines=rivie ]
+
+\setuplabeltext [\s!hu] [\v!table={,.~t\'abl\'azat:}]
+\setuplabeltext [\s!hu] [\v!figure={,.~\'abra:}]
+\setuplabeltext [\s!hu] [\v!intermezzo={,.~intermezzo:}]
+\setuplabeltext [\s!hu] [\v!graphic={,.~k\'ep:}]
+\setuplabeltext [\s!hu] [\v!chapter={,.~fejezet:}]
+\setuplabeltext [\s!hu] [\v!section={,.}]
+\setuplabeltext [\s!hu] [\v!subsection={,.}]
+\setuplabeltext [\s!hu] [\v!subsubsection={,.}]
+\setuplabeltext [\s!hu] [\v!subsubsubsection={,.}]
+\setuplabeltext [\s!hu] [\v!appendix=]
+\setuplabeltext [\s!hu] [\v!part={,.~r\'esz:}]
+\setuplabeltext [\s!hu] [\v!line={,.~sor:}]
+\setuplabeltext [\s!hu] [\v!lines=sorok]
+
+\setuplabeltext [\s!fi] [\v!january=tammikuu]
+\setuplabeltext [\s!fi] [\v!february=helmikuu]
+\setuplabeltext [\s!fi] [\v!march=maaliskuu]
+\setuplabeltext [\s!fi] [\v!april=huhtikuu]
+\setuplabeltext [\s!fi] [\v!may=toukokuu]
+\setuplabeltext [\s!fi] [\v!june=kes\"akuu]
+\setuplabeltext [\s!fi] [\v!july=hein\"akuu]
+\setuplabeltext [\s!fi] [\v!august=elokuu]
+\setuplabeltext [\s!fi] [\v!september=syyskuu]
+\setuplabeltext [\s!fi] [\v!october=lokakuu]
+\setuplabeltext [\s!fi] [\v!november=marraskuu]
+\setuplabeltext [\s!fi] [\v!december=joulukuu]
+
+\setuplabeltext [\s!hu] [\v!january=janu\'ar]
+\setuplabeltext [\s!hu] [\v!february=febru\'ar]
+\setuplabeltext [\s!hu] [\v!march=m\'arcius]
+\setuplabeltext [\s!hu] [\v!april=\'aprilis]
+\setuplabeltext [\s!hu] [\v!may=m\'ajus]
+\setuplabeltext [\s!hu] [\v!june=j\'unius]
+\setuplabeltext [\s!hu] [\v!july=j\'ulius]
+\setuplabeltext [\s!hu] [\v!august=augusztus]
+\setuplabeltext [\s!hu] [\v!september=szeptember]
+\setuplabeltext [\s!hu] [\v!october=okt\'ober]
+\setuplabeltext [\s!hu] [\v!november=november]
+\setuplabeltext [\s!hu] [\v!december=december]
+
+\setuplabeltext [\s!fi] [\v!sunday=sunnuntai]
+\setuplabeltext [\s!fi] [\v!monday=maanantai]
+\setuplabeltext [\s!fi] [\v!tuesday=tiistai]
+\setuplabeltext [\s!fi] [\v!wednesday=keskiviikko]
+\setuplabeltext [\s!fi] [\v!thursday=torstai]
+\setuplabeltext [\s!fi] [\v!friday=perjantai]
+\setuplabeltext [\s!fi] [\v!saturday=lauantai]
+
+\setuplabeltext [\s!hu] [\v!sunday=vas\'arnap]
+\setuplabeltext [\s!hu] [\v!monday=h\'etf\H{o}]
+\setuplabeltext [\s!hu] [\v!tuesday=kedd]
+\setuplabeltext [\s!hu] [\v!wednesday=szerda]
+\setuplabeltext [\s!hu] [\v!thursday=cs\"ut\"ort\"ok]
+\setuplabeltext [\s!hu] [\v!friday=p\'entek]
+\setuplabeltext [\s!hu] [\v!saturday=szombat]
+
+%D \ShowAllLanguageValues [\s!fi] [finnish] {Finnish} {phone}
+%D \ShowAllLanguageValues [\s!hu] [hungarian] {Hungarian} {rhapsody}
+
+\protect \endinput
diff --git a/tex/context/base/lang-url.lua b/tex/context/base/lang-url.lua
new file mode 100644
index 000000000..b0a71ec67
--- /dev/null
+++ b/tex/context/base/lang-url.lua
@@ -0,0 +1,101 @@
+if not modules then modules = { } end modules ['lang-url'] = {
+ version = 1.001,
+ comment = "companion to lang-url.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+local utfbyte, utfgsub = utf.byte, utf.gsub
+
+local ctxcatcodes, texsprint = tex.ctxcatcodes, tex.sprint
+
+commands = commands or { }
+
+--[[
+
Hyphenating 's is somewhat tricky and a matter of taste. I did
+consider using a dedicated hyphenation pattern or dealing with it by node
+parsing, but the following solution suits as well. After all, we're mostly
+dealing with characters.
+]]--
+
+commands.hyphenatedurl = commands.hyphenatedurl or { }
+
+local hyphenatedurl = commands.hyphenatedurl
+
+hyphenatedurl.characters = {
+ ["!"] = 1,
+ ["\""] = 1,
+ ["#"] = 1,
+ ["$"] = 1,
+ ["%"] = 1,
+ ["&"] = 1,
+ ["("] = 1,
+ ["*"] = 1,
+ ["+"] = 1,
+ [","] = 1,
+ ["-"] = 1,
+ ["."] = 1,
+ ["/"] = 1,
+ [":"] = 1,
+ [";"] = 1,
+ ["<"] = 1,
+ ["="] = 1,
+ [">"] = 1,
+ ["?"] = 1,
+ ["@"] = 1,
+ ["["] = 1,
+ ["\\"] = 1,
+ ["^"] = 1,
+ ["_"] = 1,
+ ["`"] = 1,
+ ["{"] = 1,
+ ["|"] = 1,
+ ["~"] = 1,
+
+ ["'"] = 2,
+ [")"] = 2,
+ ["]"] = 2,
+ ["}"] = 2
+}
+
+hyphenatedurl.lefthyphenmin = 2
+hyphenatedurl.righthyphenmin = 3
+hyphenatedurl.discretionary = nil
+
+local chars = hyphenatedurl.characters
+
+function hyphenatedurl.action(str, left, right, disc)
+ local n = 0
+ local b = math.max( left or hyphenatedurl.lefthyphenmin, 2)
+ local e = math.min(#str-(right or hyphenatedurl.righthyphenmin)+2,#str)
+ local d = disc or hyphenatedurl.discretionary
+ for s in utfcharacters(str) do
+ n = n + 1
+ if s == d then
+ texsprint(ctxcatcodes,"\\d{",utfbyte(s),"}")
+ else
+ local c = chars[s]
+ if not c or n<=b or n>=e then
+ texsprint(ctxcatcodes,"\\n{",utfbyte(s),"}")
+ elseif c == 1 then
+ texsprint(ctxcatcodes,"\\b{",utfbyte(s),"}")
+ elseif c == 2 then
+ texsprint(ctxcatcodes,"\\a{",utfbyte(s),"}")
+ end
+ end
+ end
+end
+
+-- todo, no interface in mkiv yet
+
+function hyphenatedurl.setcharacters(str,value) -- 1, 2 == before, after
+ for s in utfcharacters(str) do
+ chars[s] = value or 1
+ end
+end
+
+-- .hyphenatedurl.setcharacters("')]}",2)
diff --git a/tex/context/base/lang-url.mkii b/tex/context/base/lang-url.mkii
new file mode 100644
index 000000000..fdf530b45
--- /dev/null
+++ b/tex/context/base/lang-url.mkii
@@ -0,0 +1,306 @@
+%D \module
+%D [ file=lang-url,
+%D version=2008.01.22, % used to be lang-mis
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Language Options,
+%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.
+
+\unprotect
+
+%D This is rather old code. The following solution was used
+%D for a long time and is kind of built-up over the years.
+
+\ifx\\\undefined \let\\\crlf \fi
+
+%D \macros
+%D {hyphenatedurl}
+%D
+%D For those who want to put full \URL's in a text, we offer
+%D
+%D \startbuffer
+%D \hyphenatedurl{http://optimist.optimist/optimist/optimist.optimist#optimist}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D which breaks at the appropriate places. Watch the \type{#}
+%D hack.
+%D
+%D When passed as argument, like in \type {\goto}, one needs
+%D to substitute a \type {\\} for each \type{#}.
+%D
+%D \startbuffer
+%D \hyphenatedurl{http://this.is.a.rather/strange/reference#indeed}
+%D \stopbuffer
+%D
+%D \typebuffer
+
+\ifx\urlsplitmode\undefined \chardef\urlsplitmode\plusone \fi
+
+% 0 => don't split
+% 1 => . : na, rest voor
+% 2 => alles na
+% 3 => alles voor
+
+% \bgroup \catcode`\~=\active \catcode`\/=\active
+%
+% \unexpanded\gdef\hyphenatedurl#1% {}{} handles accents
+% {\bgroup
+% \ifnum\hyphenpenalty<10000 \else
+% \def\discretionary##1##2##3{##1\allowbreak##2}%
+% \fi
+% \obeyhyphens
+% \def\splitbefore##1%
+% {\setbox\scratchbox=\hbox{##1{}{}}%
+% \ifcase\urlsplitmode
+% \box\scratchbox
+% \or
+% \postwordbreak\box\scratchbox\prewordbreak
+% \or
+% \prewordbreak\discretionary{\box\scratchbox}{}{\box\scratchbox}\prewordbreak
+% \else
+% \postwordbreak\box\scratchbox\prewordbreak
+% \fi}%
+% \def\splitafter##1%
+% {\ifcase\urlsplitmode
+% ##1{}{}%
+% \or
+% \prewordbreak\discretionary{##1{}{}}{}{##1{}{}}\prewordbreak
+% \or
+% \prewordbreak\discretionary{##1{}{}}{}{##1{}{}}\prewordbreak
+% \else
+% \prewordbreak\discretionary{}{##1{}{}}{##1{}{}}\prewordbreak
+% \fi}%
+% \def\splitanyway##1%
+% {\prewordbreak##1\prewordbreak}%
+% \def\flushurl%
+% {\savedurl\let\savedurl\empty}%
+% \def\\%
+% {\spliturl\#}%
+% \let\~=\lettertilde\let~=\~%
+% \let\/=\letterslash\let/=\/%
+% \let\savedurl\empty
+% \scratchcounter\zerocount % used for hyphenmethod
+% \handletokens#1\with\scanurl\savedurl
+% \egroup}
+%
+% \egroup
+
+% \chardef\urlhyphenmethod=0
+
+% \def\scanurl#1%
+% {\advance\scratchcounter\plusone
+% \ifx#1\blankspace
+% \flushurl\splitanyway\normalspace
+% \else\ifx#1\ %
+% \flushurl\splitanyway\normalspace
+% \else\ifx#1\space
+% \flushurl\splitanyway\normalspace
+% \else\ifx#1\~%
+% \flushurl\splitbefore\~%
+% \else\ifx#1\#%
+% \flushurl\splitbefore\#%
+% \else\ifx#1\&%
+% \flushurl\splitbefore\&%
+% \else\ifx#1\%%
+% \flushurl\splitbefore\%%
+% \else\ifx#1\_%
+% \flushurl\splitbefore\_%
+% \else\if\noexpand#1\relax
+% #1%
+% \else\ifnum\catcode`#1=8
+% \flushurl\splitbefore\_%
+% \else\ifnum\catcode`#1=6
+% \flushurl\splitbefore\#%
+% \else\ifnum\catcode`#1=4
+% \flushurl\splitbefore\&%
+% \else\expandafter\if\string#1\lettertilde
+% \flushurl\splitbefore\~%
+% \else\expandafter\if\string#1\letterpercent
+% \flushurl\splitbefore\%%
+% \else\expandafter\if\string#1\letterunderscore
+% \flushurl\splitbefore\_%
+% \else\expandafter\if\string#1\letterquestionmark
+% \flushurl\splitafter\letterquestionmark
+% \else\expandafter\if\string#1\letterat
+% \flushurl\splitafter\letterat
+% \else\expandafter\if\string#1\letterslash
+% \edef\savedurl{\savedurl\letterslash}%
+% \else\expandafter\if\string#1+%
+% \flushurl\splitafter+%
+% \else\expandafter\if\string#1:%
+% \flushurl\splitafter:%
+% \else\expandafter\if\string#1.%
+% \flushurl\splitafter.%
+% \else\expandafter\if\string#1(%
+% \flushurl\splitbefore(%
+% \else\expandafter\if\string#1)%
+% \flushurl\splitafter)%
+% \else
+% \ifx\savedurl\empty\else
+% \splitbefore\savedurl
+% \let\savedurl\empty
+% \fi
+% \ifcase\urlhyphenmethod
+% \string#1%
+% \else
+% \ifnum\scratchcounter>\plusthree % so, \http: will not break
+% \edef\savedurl{\string#1}%
+% \else
+% \string#1%
+% \fi
+% \fi
+% \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+%D The following approach takes more resources but is cleaner (after all, we now
+%D have huge \TEX's. It's is basically a \TEX\ version of the \MKIV\ variant.
+
+\newtoks\everyhyphenatedurl
+
+\appendtoks
+ \let\&\letterampersand
+ \let\#\letterhash
+ \let\~\lettertilde
+ \let\\\letterbackslash
+ \let\$\letterdollar
+ \let\^\letterhat
+ \let\_\letterunderscore
+ \let\{\letterleftbrace
+ \let\}\letterrightbrace
+ \let\|\letterbar
+ \let~=\lettertilde
+ \let|=\letterbar
+\to \everyhyphenatedurl
+
+\def\hyphenatedurlseparator{} % \periodcentered
+
+\def\dohyphenatedurlnormal#1{\char#1\relax}%
+\def\dohyphenatedurlafter #1{\char#1\discretionary{}{\hyphenatedurlseparator}{}}%
+\def\dohyphenatedurlbefore#1{\discretionary{\hyphenatedurlseparator}{}{}\char#1\relax}%
+
+% 0=normal 1=before 2=after
+
+\def\sethyphenatedurlnormal#1{\expandafter\chardef\csname url @ #1\endcsname\zerocount}
+\def\sethyphenatedurlbefore#1{\expandafter\chardef\csname url @ #1\endcsname\plusone }
+\def\sethyphenatedurlafter #1{\expandafter\chardef\csname url @ #1\endcsname\plustwo }
+
+\sethyphenatedurlbefore !
+\sethyphenatedurlbefore "
+\sethyphenatedurlbefore \letterhash
+\sethyphenatedurlbefore \letterdollar
+\sethyphenatedurlbefore \letterpercent
+\sethyphenatedurlbefore \letterampersand
+\sethyphenatedurlbefore (
+\sethyphenatedurlbefore *
+\sethyphenatedurlbefore +
+\sethyphenatedurlbefore ,
+\sethyphenatedurlbefore -
+\sethyphenatedurlbefore .
+\sethyphenatedurlbefore /
+\sethyphenatedurlbefore :
+\sethyphenatedurlbefore ;
+\sethyphenatedurlbefore <
+\sethyphenatedurlbefore =
+\sethyphenatedurlbefore >
+\sethyphenatedurlbefore ?
+\sethyphenatedurlbefore @
+\sethyphenatedurlbefore [
+\sethyphenatedurlbefore \letterbackslash
+\sethyphenatedurlbefore ^
+\sethyphenatedurlbefore _
+\sethyphenatedurlbefore `
+\sethyphenatedurlbefore \letteropenbrace
+\sethyphenatedurlbefore \letterbar
+\sethyphenatedurlbefore \lettertilde
+
+\sethyphenatedurlafter '
+\sethyphenatedurlafter )
+\sethyphenatedurlafter ]
+\sethyphenatedurlafter \letterclosebrace
+
+\unexpanded \def\hyphenatedurl#1%
+ {\dontleavehmode
+ \begingroup
+ \the\everyhyphenatedurl
+ \edef\ascii{#1}%
+ \expanded{\handletokens{\detokenize\expandafter{\ascii}}}\with\dohyphenatedurl
+ \endgroup}
+
+\def\dohyphenatedurl#1%
+ {\ifcase\executeifdefined{url @ #1}\zerocount\relax
+ \expandafter\dohyphenatedurlnormal
+ \or
+ \expandafter\dohyphenatedurlbefore
+ \or
+ \expandafter\dohyphenatedurlafter
+ \fi{\number`#1}}
+
+% maybe ... to be finished
+%
+% \def\hyphenatedstring#1%
+% {\bgroup
+% \nohyphens
+% \def\next##1{##1\doif{##1}{-}{\allowbreak}}%
+% \handletokens#1\with\next
+% \egroup}
+%
+% {\hsize1cm\hyphenatedstring{ABXXXXXXXXXXC-12345-12345}}
+
+%D \macros
+%D {hyphenatedfilename}
+%D
+%D For the moment we treat filenames in a similar way,
+%D
+%D \starttyping
+%D \hyphenatedfilename{here/there/filename.suffix}
+%D \stoptyping
+
+\ifx\hyphenatedfilename\undefined \let\hyphenatedfilename\hyphenatedurl \fi
+
+% \def\test#1%
+% {\dontleavehmode
+% \begingroup
+% \tttf
+% \hyphenatedurl {%
+% \letterampersand #1\letterampersand #1\letterampersand #1\letterampersand #1\letterampersand
+% \letterhash #1\letterhash #1\letterpercent #1\letterslash #1\letterampersand
+% }%
+% \endgroup}
+
+% \dorecurse{100}{\test{a} \test{ab} \test{abc} \test{abcd} \test{abcde} \test{abcdef}}
+
+\protect \endinput
+
+% \bgroup
+
+% \gdef\lettercolon{:}
+
+% \catcode`\:=\active
+% \catcode`\^=\active
+% \catcode`\/=\active
+% \catcode`\~=\active
+
+% \gdef\theurlcolon {\nobreak\hbox{\lettercolon}\allowbreak}
+% \gdef\theurlslash#1{\nobreak\hbox{\letterslash}\ifx#1\relax\else\ifnum`/=\expandafter`\string#1\else\allowbreak\fi#1\fi}
+% \gdef\theurlhat {\allowbreak\hbox{\letterhat}\nobreak}
+% \gdef\theurltilde {\allowbreak\hbox{\lettertilde}\nobreak}
+
+% \gdef\ForMojcaWhoLikesHacks#1%
+% {\dontleavehmode
+% \begingroup
+% \mathcode`\:="8000 \let:\theurlcolon
+% \mathcode`\^="8000 \let^\theurlhat
+% \mathcode`\/="8000 \let/\theurlslash
+% \mathcode`\~="8000 \let~\theurltilde
+% \everymath\emptytoks
+% \mathsurround\zeropoint$\tf#1\relax$%
+% \endgroup}
+% \egroup
+
+% \hsize 1mm \ForMojcaWhoLikesHacks{http://www.sil.org//silesr/}
diff --git a/tex/context/base/lang-url.mkiv b/tex/context/base/lang-url.mkiv
new file mode 100644
index 000000000..0f6b23d05
--- /dev/null
+++ b/tex/context/base/lang-url.mkiv
@@ -0,0 +1,117 @@
+%D \module
+%D [ file=lang-url,
+%D version=2008.01.22, % used to be lang-mis
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Language Options,
+%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.
+
+\registerctxluafile{lang-url}{1.001}
+
+\unprotect
+
+%D \macros
+%D {hyphenatedurl}
+%D
+%D For those who want to put full \URL's in a text, we offer
+%D
+%D \startbuffer
+%D \hyphenatedurl{http://optimist.optimist/optimist/optimist.optimist#optimist}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D which breaks at the appropriate places. Watch the \type{#}
+%D hack.
+%D
+%D When passed as argument, like in \type {\goto}, one needs
+%D to substitute a \type {\\} for each \type{#}.
+%D
+%D \startbuffer
+%D \hyphenatedurl{http://this.is.a.rather/strange/reference#indeed}
+%D \stopbuffer
+%D
+%D \typebuffer
+
+\ifx\urlsplitmode\undefined \chardef\urlsplitmode\zerocount \fi % not supported in mkiv
+
+\newtoks\everyhyphenatedurl
+
+\appendtoks
+ \let\&\letterampersand
+ \let\#\letterhash
+ \let\~\lettertilde
+ \let\\\letterbackslash
+ \let\$\letterdollar
+ \let\^\letterhat
+ \let\_\letterunderscore
+ \let\{\letterleftbrace
+ \let\}\letterrightbrace
+ \let\|\letterbar
+ \let~=\lettertilde
+ \let|=\letterbar
+\to \everyhyphenatedurl
+
+\def\hyphenatedurlseparator{} % \periodcentered
+
+\def\dohyphenatedurlafter #1{\char#1\discretionary{}{\hyphenatedurlseparator}{}}%
+\def\dohyphenatedurlbefore#1{\discretionary{\hyphenatedurlseparator}{}{}\char#1\relax}%
+\def\dohyphenatedurlnormal#1{\char#1\relax}%
+\def\dohyphenatedurldisc #1{\discretionary{}{}{}}
+
+\def\sethyphenatedurlnormal #1{\ctxlua{commands.hyphenatedurl.setcharacters(\!!bs#1\!!es,0)}}
+\def\sethyphenatedurlbefore #1{\ctxlua{commands.hyphenatedurl.setcharacters(\!!bs#1\!!es,1)}}
+\def\sethyphenatedurlafter #1{\ctxlua{commands.hyphenatedurl.setcharacters(\!!bs#1\!!es,2)}}
+
+\def\hyphenatedurldiscretionary{}
+
+% \sethyphenatedurlafter{ABCDEF}
+
+\chardef\hyphenatedurllefthyphenmin = 3
+\chardef\hyphenatedurlrighthyphenmin = 3
+
+\unexpanded \def\hyphenatedurl#1%
+ {\dontleavehmode
+ \begingroup
+ \the\everyhyphenatedurl
+ \let\n\dohyphenatedurlnormal
+ \let\b\dohyphenatedurlbefore
+ \let\a\dohyphenatedurlafter
+ \let\d\dohyphenatedurldisc
+ \normalexpanded{\noexpand\ctxlua{commands.hyphenatedurl.action(
+ \!!bs\noexpand\detokenize{#1}\!!es,
+ \number\hyphenatedurllefthyphenmin,
+ \number\hyphenatedurlrighthyphenmin,
+ "\hyphenatedurldiscretionary"
+ )}}%
+ \endgroup}
+
+%D \macros
+%D {hyphenatedfilename}
+%D
+%D For the moment we treat filenames in a similar way,
+%D
+%D \starttyping
+%D \hyphenatedfilename{here/there/filename.suffix}
+%D \stoptyping
+
+\ifx\hyphenatedfilename\undefined \let\hyphenatedfilename\hyphenatedurl \fi
+
+% \def\test#1%
+% {\dontleavehmode
+% \begingroup
+% \tttf
+% \hyphenatedurl {%
+% \letterampersand #1\letterampersand #1\letterampersand #1\letterampersand #1\letterampersand
+% \letterhash #1\letterhash #1\letterpercent #1\letterslash #1\letterampersand
+% }%
+% \endgroup}
+
+% \dorecurse{100}{\test{a} \test{ab} \test{abc} \test{abcd} \test{abcde} \test{abcdef}}
+
+\protect \endinput
diff --git a/tex/context/base/lang-vn.tex b/tex/context/base/lang-vn.tex
new file mode 100644
index 000000000..27d2a48a1
--- /dev/null
+++ b/tex/context/base/lang-vn.tex
@@ -0,0 +1,92 @@
+%D \module
+%D [ file=lang-vn,
+%D version=2004.11.22, % 1999.12.12,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Vietnamese,
+%D author={Han The Thanh \& Adam Lindsay \& Hans Hagen},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Language Macros / Vietnamese Language}
+
+%D The framework of this module is set up by Hans Hagen while
+%D many of the first translations were done by Tobias. Later
+%D on, corrections were made by users. If you have suggestions,
+%D or feel that your name missing here, don't hesitate to send
+%D us an email.
+%D
+%D \starttabulate[|lB|l|]
+%D \NC Vietnamese \NC \THANH\ \NC \NR
+%D \stoptabulate
+
+\unprotect
+
+\installlanguage
+ [\s!vi]
+ [\c!spacing=\v!packed,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\quoteleft,
+ \c!rightquote=\quoteright,
+ \c!leftquotation=\quotedblleft,
+ \c!rightquotation=\quotedblright,
+ \c!date={{ },dd,{/},mm,{/},yy},
+ \s!mapping=t5,
+ \s!encoding=t5]
+
+\installlanguage [vietnamese] [\s!vi]
+
+\setupheadtext [\s!vi] [\v!content=M\udotbelow c l\udotbelow c]
+\setupheadtext [\s!vi] [\v!tables=Danh s\aacute ch b\ahook ng]
+\setupheadtext [\s!vi] [\v!figures=Danh s\aacute ch h\igrave nh v\etilde]
+\setupheadtext [\s!vi] [\v!graphics=\Dstroke\ocircumflexgrave\ th\idotbelow]
+\setupheadtext [\s!vi] [\v!intermezzi=Intermezzos]
+\setupheadtext [\s!vi] [\v!index=Ch\ihook\ s\ocircumflexacute]
+\setupheadtext [\s!vi] [\v!abbreviations=Ch\uhorntilde\ vi\ecircumflexacute t t\abreveacute t]
+\setupheadtext [\s!vi] [\v!logos=Bi\ecircumflexhook u t\uhorn \ohorndotbelow ng]
+\setupheadtext [\s!vi] [\v!units=\Dstroke\ohorn n v\idotbelow]
+
+\setuplabeltext [\s!vi] [\v!table=B\ahook ng ]
+\setuplabeltext [\s!vi] [\v!figure=H\igrave nh ]
+\setuplabeltext [\s!vi] [\v!intermezzo=intermezzo]
+\setuplabeltext [\s!vi] [\v!graphic=\Dstroke\ocircumflexgrave\ th\idotbelow]
+\setuplabeltext [\s!vi] [\v!chapter=Ch\uhorn \ohorn ng ]
+\setuplabeltext [\s!vi] [\v!section=] % not set
+\setuplabeltext [\s!vi] [\v!subsection=] % not set
+\setuplabeltext [\s!vi] [\v!subsubsection=] % not set
+\setuplabeltext [\s!vi] [\v!subsubsubsection=] % not set
+\setuplabeltext [\s!vi] [\v!appendix=] % not set
+\setuplabeltext [\s!vi] [\v!part=Ph\acircumflexgrave n ]
+\setuplabeltext [\s!vi] [\v!line=d\ograve ng ]
+\setuplabeltext [\s!vi] [\v!lines=d\ograve ng ]
+
+\setuplabeltext [\s!vi] [\v!sunday=ch\uhook\ nh\acircumflexdotbelow t]
+\setuplabeltext [\s!vi] [\v!monday=th\uhornacute\ hai]
+\setuplabeltext [\s!vi] [\v!tuesday=th\uhornacute\ ba]
+\setuplabeltext [\s!vi] [\v!wednesday=th\uhornacute\ t\uhorn]
+\setuplabeltext [\s!vi] [\v!thursday=th\uhornacute\ n\abreve m]
+\setuplabeltext [\s!vi] [\v!friday=th\uhornacute\ s\aacute u]
+\setuplabeltext [\s!vi] [\v!saturday=th\uhornacute\ b\ahook y]
+
+\setuplabeltext [\s!vi] [\v!january=th\aacute ng gi\ecircumflex ng]
+\setuplabeltext [\s!vi] [\v!february=th\aacute ng hai]
+\setuplabeltext [\s!vi] [\v!march=th\aacute ng ba]
+\setuplabeltext [\s!vi] [\v!april=th\aacute ng t\uhorn]
+\setuplabeltext [\s!vi] [\v!may=th\aacute ng n\abreve m]
+\setuplabeltext [\s!vi] [\v!june=th\aacute ng s\aacute u]
+\setuplabeltext [\s!vi] [\v!july=th\aacute ng b\ahook y]
+\setuplabeltext [\s!vi] [\v!august=th\aacute ng t\aacute m]
+\setuplabeltext [\s!vi] [\v!september=th\aacute ng ch\iacute n]
+\setuplabeltext [\s!vi] [\v!october=th\aacute ng m\uhorn\ohorngrave i]
+\setuplabeltext [\s!vi] [\v!november=th\aacute ng m\uhorn\ohorngrave i m\ocircumflexdotbelow t]
+\setuplabeltext [\s!vi] [\v!december=th\aacute ng m\uhorn\ohorngrave i hai]
+
+%D \ShowAllLanguageValues [\s!vi] [vietnamese] {Vietnamese} {water||puppets}
+
+\protect \endinput
diff --git a/tex/context/base/lang-wrd.lua b/tex/context/base/lang-wrd.lua
new file mode 100644
index 000000000..095e44443
--- /dev/null
+++ b/tex/context/base/lang-wrd.lua
@@ -0,0 +1,225 @@
+if not modules then modules = { } end modules ['lang-ini'] = {
+ version = 1.001,
+ comment = "companion to lang-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+local lower, utfchar = string.lower, utf.char
+local lpegmatch = lpeg.match
+
+languages.words = languages.words or { }
+
+local words = languages.words
+
+words.data = words.data or { }
+words.enables = false
+words.threshold = 4
+
+local set_attribute = node.set_attribute
+local unset_attribute = node.unset_attribute
+local traverse_nodes = node.traverse
+local node_id = node.id
+local wordsdata = words.data
+local chardata = characters.data
+
+local glyph_node = node_id('glyph')
+local disc_node = node_id('disc')
+local kern_node = node_id('kern')
+
+words.colors = {
+ ["known"] = "green",
+ ["unknown"] = "red",
+}
+
+local spacing = lpeg.S(" \n\r\t")
+local markup = lpeg.S("-=")
+local lbrace = lpeg.P("{")
+local rbrace = lpeg.P("}")
+local disc = (lbrace * (1-rbrace)^0 * rbrace)^1 -- or just 3 times, time this
+local word = lpeg.Cs((markup/"" + disc/"" + (1-spacing))^1)
+
+local loaded = { } -- we share lists
+
+function words.load(tag,filename)
+ local fullname = resolvers.find_file(filename,'other text file') or ""
+ if fullname ~= "" then
+ statistics.starttiming(languages)
+ local list = loaded[fullname]
+ if not list then
+ list = wordsdata[tag] or { }
+ local parser = (spacing + word/function(s) list[s] = true end)^0
+ lpegmatch(parser,io.loaddata(fullname) or "")
+ loaded[fullname] = list
+ end
+ wordsdata[tag] = list
+ statistics.stoptiming(languages)
+ else
+ logs.report("languages","missing words file '%s'",filename)
+ end
+end
+
+function words.found(id, str)
+ local tag = languages.numbers[id]
+ if tag then
+ local data = wordsdata[tag]
+ return data and (data[str] or data[lower(str)])
+ else
+ return false
+ end
+end
+
+-- The following code is an adaption of experimental code for
+-- hyphenating and spell checking.
+
+local function mark_words(head,whenfound) -- can be optimized
+ local current, start, str, language, n = head, nil, "", nil, 0
+ local function action()
+ if #str > 0 then
+ local f = whenfound(language,str)
+ if f then
+ for i=1,n do
+ f(start)
+ start = start.next
+ end
+ end
+ end
+ str, start, n = "", nil, 0
+ end
+ while current do
+ local id = current.id
+ if id == glyph_node then
+ local a = current.lang
+ if a then
+ if a ~= language then
+ if start then
+ action()
+ end
+ language = a
+ end
+ elseif start then
+ action()
+ language = a
+ end
+ local components = current.components
+ if components then
+ start = start or current
+ n = n + 1
+ for g in traverse_nodes(components) do
+ str = str .. utfchar(g.char)
+ end
+ else
+ local code = current.char
+ if chardata[code].uccode or chardata[code].lccode then
+ start = start or current
+ n = n + 1
+ str = str .. utfchar(code)
+ elseif start then
+ action()
+ end
+ end
+ elseif id == disc_node then
+ if n > 0 then
+ n = n + 1
+ end
+ elseif id == kern_node and current.subtype == 0 and start then
+ -- ok
+ elseif start then
+ action()
+ end
+ current = current.next
+ end
+ if start then
+ action()
+ end
+ return head
+end
+
+words.methods = { }
+words.method = 1
+
+local methods = words.methods
+
+methods[1] = function(head, attribute, yes, nop)
+ local right, wrong = false, false
+ if yes then right = function(n) set_attribute(n,attribute,yes) end end
+ if nop then wrong = function(n) set_attribute(n,attribute,nop) end end
+ for n in traverse_nodes(head) do
+ unset_attribute(n,attribute) -- hm, not that selective (reset color)
+ end
+ local found, done = words.found, false
+ mark_words(head, function(language,str)
+ if #str < words.threshold then
+ return false
+ elseif found(language,str) then
+ done = true
+ return right
+ else
+ done = true
+ return wrong
+ end
+ end)
+ return head, done
+end
+
+local list, dump = { }, false -- todo: per language
+
+local lower = characters.lower
+
+methods[2] = function(head, attribute)
+ dump = true
+ mark_words(head, function(language,str)
+ if #str >= words.threshold then
+ str = lower(str)
+ list[str] = (list[str] or 0) + 1
+ end
+ end)
+ return head, true
+end
+
+words.used = list
+
+function words.dump_used_words(name)
+ if dump then
+ logs.report("languages","saving list of used words in '%s'",name)
+ io.savedata(name,table.serialize(list))
+ end
+end
+
+local color = attributes.private('color')
+
+function words.check(head)
+ if words.enabled and head.next then
+ local colors = words.colors
+ local alc = attributes.list[color]
+ return methods[words.method](head, color, alc[colors.known], alc[colors.unknown])
+ else
+ return head, false
+ end
+end
+
+function words.enable(method)
+ tasks.enableaction("processors","languages.words.check")
+ words.method = method or words.method or 1
+ words.enabled = true
+end
+
+function words.disable()
+ words.enabled = false
+end
+
+-- for the moment we hook it into the attribute handler
+
+--~ languagehacks = { }
+
+--~ function languagehacks.process(namespace,attribute,head)
+--~ return languages.check(head)
+--~ end
+
+--~ chars.plugins[chars.plugins+1] = {
+--~ name = "language",
+--~ namespace = languagehacks,
+--~ processor = languagehacks.process
+--~ }
diff --git a/tex/context/base/lang-wrd.mkiv b/tex/context/base/lang-wrd.mkiv
new file mode 100644
index 000000000..b6fc6a9d3
--- /dev/null
+++ b/tex/context/base/lang-wrd.mkiv
@@ -0,0 +1,54 @@
+%D \module
+%D [ file=lang-wrd,
+%D version=2006.XX.XX,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Checking,
+%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.
+
+%D Experimental.
+
+\writestatus{loading}{ConTeXt Language Macros / Checking}
+
+\registerctxluafile{lang-wrd}{1.001}
+
+\unprotect
+
+% \loadspellchecklist[en][words-en.txt]
+% \loadspellchecklist[us][words-en.txt]
+% \loadspellchecklist[nl][words-nl.txt]
+% \setupspellchecking[state=start,method=1]
+%
+% \setupspellchecking[state=start,method=2]
+% ...
+% \typefile{\jobname.words}
+
+\def\loadspellchecklist
+ {\dodoubleempty\doloadspellchecklist}
+
+\def\doloadspellchecklist[#1][#2]%
+ {\ctxlua{languages.words.load("#1","#2")}}
+
+\unexpanded\def\setupspellchecking
+ {\dosingleargument\dosetupspellchecking}
+
+\unexpanded\def\setupspellchecking[#1]% todo colors
+ {\getparameters[\??wl][#1]%
+ \doifelse\@@wlstate\v!start
+ {\ctxlua{languages.words.enable(\@@wlmethod)}}
+ {\ctxlua{languages.words.disable()}}}
+
+\setupspellchecking
+ [\c!state=\v!stop,
+ \c!method=1]
+
+\appendtoks
+ \ctxlua{languages.words.dump_used_words("\jobname.words")}%
+\to \everybye
+
+\protect \endinput
diff --git a/tex/context/base/lpdf-ano.lua b/tex/context/base/lpdf-ano.lua
new file mode 100644
index 000000000..e9e67e163
--- /dev/null
+++ b/tex/context/base/lpdf-ano.lua
@@ -0,0 +1,589 @@
+if not modules then modules = { } end modules ['lpdf-ano'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local tostring, format, rep = tostring, string.rep, string.format
+local texcount = tex.count
+
+local trace_references = false trackers.register("references.references", function(v) trace_references = v end)
+local trace_destinations = false trackers.register("references.destinations", function(v) trace_destinations = v end)
+local trace_bookmarks = false trackers.register("references.bookmarks", function(v) trace_bookmarks = v end)
+
+local variables = interfaces.variables
+local constants = interfaces.constants
+
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
+
+jobreferences = jobreferences or { }
+jobreferences.runners = jobreferences.runners or { }
+jobreferences.specials = jobreferences.specials or { }
+jobreferences.handlers = jobreferences.handlers or { }
+jobreferences.executers = jobreferences.executers or { }
+
+local runners = jobreferences.runners
+local specials = jobreferences.specials
+local handlers = jobreferences.handlers
+local executers = jobreferences.executers
+
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfconstant = lpdf.constant
+local pdfflushobject = lpdf.flushobject
+local pdfreserveobject = lpdf.reserveobject
+local pdfannotation = nodes.pdfannotation
+local pdfdestination = nodes.pdfdestination
+
+local pdfpagereference = tex.pdfpageref
+
+local pdf_uri = pdfconstant("URI")
+local pdf_gotor = pdfconstant("GoToR")
+local pdf_goto = pdfconstant("GoTo")
+local pdf_launch = pdfconstant("Launch")
+local pdf_javascript = pdfconstant("JavaScript")
+local pdf_link = pdfconstant("Link")
+local pdf_n = pdfconstant("N")
+local pdf_t = pdfconstant("T")
+local pdf_border = pdfarray { 0, 0, 0 }
+
+local cache = { }
+
+local function pagedest(n)
+ local pd = cache[n]
+ if not pd then
+ local a = pdfarray {
+ pdfreference(pdfpagereference(n)),
+ pdfconstant("Fit")
+ }
+ pd = pdfreference(pdfflushobject(a))
+ cache[n] = pd
+ end
+ return pd
+end
+
+lpdf.pagedest = pagedest
+
+local defaultdestination = pdfarray { 0, pdfconstant("Fit") }
+
+local function link(url,filename,destination,page,actions)
+ if filename and filename ~= "" then
+ if file.basename(filename) == tex.jobname then
+ return false
+ else
+ filename = file.addsuffix(filename,"pdf")
+ end
+ end
+ if url and url ~= "" then
+ if filename and filename ~= "" then
+ if destination and destination ~= "" then
+ url = file.join(url,filename).."#"..destination
+ else
+ url = file.join(url,filename)
+ end
+ end
+ return pdfdictionary {
+ S = pdf_uri,
+ URI = url,
+ }
+ elseif filename and filename ~= "" then
+ return pdfdictionary {
+ S = pdf_gotor, -- can also be pdf_launch
+ F = filename,
+ D = (destination and destination ~= "" and destination), -- or defaultdestination,
+ NewWindow = (actions.newwindow and true) or nil,
+ }
+ elseif destination and destination ~= "" then
+ local realpage, p = texcount.realpageno, tonumber(page)
+ if not p then
+ -- sorry
+ elseif p > realpage then
+ texcount.referencepagestate = 3
+ elseif p < realpage then
+ texcount.referencepagestate = 2
+ else
+ texcount.referencepagestate = 1
+ end
+ return pdfdictionary {
+ S = pdf_goto,
+ D = destination,
+ }
+ elseif page and page ~= "" then
+ local realpage, p = texcount.realpageno, tonumber(page)
+ if p then
+ if p > realpage then
+ texcount.referencepagestate = 3
+ elseif p < realpage then
+ texcount.referencepagestate = 2
+ else
+ texcount.referencepagestate = 1
+ end
+ return pdfdictionary {
+ S = pdf_goto,
+ D = pagedest(p),
+ }
+ else
+ commands.writestatus("references","invalid page reference: %s",page or "?")
+ end
+ end
+ return false
+end
+
+lpdf.link = link
+
+function lpdf.launch(program,parameters)
+ if program and program ~= "" then
+ local d = pdfdictionary {
+ S = pdf_launch,
+ F = program,
+ D = ".",
+ }
+ if parameters and parameters ~= "" then
+ d.P = parameters
+ end
+ return d
+ end
+end
+
+function lpdf.javascript(name,arguments)
+ local script = javascripts.code(name,arguments) -- make into object (hash)
+ if script then
+ return pdfdictionary {
+ S = pdf_javascript,
+ JS = script,
+ }
+ end
+end
+
+local function pdfaction(actions)
+ local nofactions = #actions
+ texcount.referencepagestate = 0 -- goodie, as we do all in the backend, we need to set it here too
+ if nofactions > 0 then
+ local a = actions[1]
+ local action = runners[a.kind]
+ if action then
+ action = action(a,actions)
+ end
+ if action then
+ local first = action
+ for i=2,nofactions do
+ local a = actions[i]
+ local what = runners[a.kind]
+ if what then
+ what = what(a,actions)
+ end
+ if what then
+ action.next = what
+ action = what
+ else
+ -- error
+ return nil
+ end
+ end
+ return first
+ end
+ end
+end
+
+lpdf.pdfaction = pdfaction
+
+function codeinjections.prerollreference(actions)
+ local main = actions and pdfaction(actions)
+ if main then
+ main = pdfdictionary {
+ Subtype = pdf_link,
+ Border = pdf_border,
+ H = (not actions.highlight and pdf_n) or nil,
+ A = main,
+ -- does not work at all in spite of specification
+ -- OC = (actions.layer and lpdf.layerreferences[actions.layer]) or nil,
+ -- OC = backends.pdf.layerreference(actions.layer),
+ }
+ return main("A") -- todo: cache this, maybe weak
+ end
+end
+
+-- local cache = { } -- no real gain in thsi
+--
+-- function codeinjections.prerollreference(actions)
+-- local main = actions and pdfaction(actions)
+-- if main then
+-- main = pdfdictionary {
+-- Subtype = pdf_link,
+-- Border = pdf_border,
+-- H = (not actions.highlight and pdf_n) or nil,
+-- A = main,
+-- }
+-- local cm = cache[main]
+-- if not cm then
+-- cm = "/A ".. tostring(pdfreference(pdfflushobject(main))
+-- cache[main] = cm
+-- end
+-- return cm
+-- end
+-- end
+
+function nodeinjections.reference(width,height,depth,prerolled)
+ if prerolled then
+ if swapdir then
+ width = - width
+ end
+ if trace_references then
+ logs.report("references","w=%s, h=%s, d=%s, a=%s",width,height,depth,prerolled)
+ end
+ return pdfannotation(width,height,depth,prerolled)
+ end
+end
+
+function nodeinjections.destination(width,height,depth,name,view)
+ if swapdir then
+ width = - width
+ end
+ if trace_destinations then
+ logs.report("destinations","w=%s, h=%s, d=%s, n=%s, v=%s",width,height,depth,name,view or "no view")
+ end
+ return pdfdestination(width,height,depth,name,view)
+end
+
+-- runners and specials
+
+local method = "internal"
+
+runners["inner"] = function(var,actions)
+ if method == "internal" then
+ local vir = var.i.references
+ local internal = vir and vir.internal
+ if internal then
+ var.inner = "aut:"..internal
+ end
+ end
+ return link(nil,nil,var.inner,var.r,actions)
+end
+
+runners["inner with arguments"] = function(var,actions)
+ logs.report("references","todo: inner with arguments")
+ return false
+end
+
+runners["outer"] = function(var,actions)
+ local file, url = jobreferences.checkedfileorurl(var.outer,var.outer)
+ return link(url,file,var.arguments,nil,actions)
+end
+
+runners["outer with inner"] = function(var,actions)
+ local file = jobreferences.checkedfile(var.f)
+ return link(nil,file,var.inner,var.r,actions)
+end
+
+runners["special outer with operation"] = function(var,actions)
+ local handler = specials[var.special]
+ return handler and handler(var,actions)
+end
+
+runners["special outer"] = function(var,actions)
+ logs.report("references","todo: special outer")
+ return false
+end
+
+runners["special"] = function(var,actions)
+ local handler = specials[var.special]
+ return handler and handler(var,actions)
+end
+
+runners["outer with inner with arguments"] = function(var,actions)
+ logs.report("references","todo: outer with inner with arguments")
+ return false
+end
+
+runners["outer with special and operation and arguments"] = function(var,actions)
+ logs.report("references","todo: outer with special and operation and arguments")
+ return false
+end
+
+runners["outer with special"] = function(var,actions)
+ logs.report("references","todo: outer with special")
+ return false
+end
+
+runners["outer with special and operation"] = function(var,actions)
+ logs.report("references","todo: outer with special and operation")
+ return false
+end
+
+runners["special operation"] = runners["special"]
+runners["special operation with arguments"] = runners["special"]
+
+function specials.internal(var,actions) -- better resolve in strc-ref
+ local i = tonumber(var.operation)
+ local v = jobreferences.internals[i]
+ if not v then
+ -- error
+ elseif method == "internal" then
+ -- named
+ return link(nil,nil,"aut:"..i,v.references.realpage,actions)
+ else
+ -- page
+ return link(nil,nil,nil,v.references.realpage,actions)
+ end
+end
+
+specials.i = specials.internal
+
+function specials.page(var,actions) -- better resolve in strc-ref
+ local file = var.f
+ if file then
+ file = jobreferences.checkedfile(file)
+ return link(nil,file,nil,p or var.operation,actions)
+ else
+ local p = jobreferences.pages[var.operation]
+ if type(p) == "function" then
+ p = p()
+ end
+ return link(nil,nil,nil,p or var.operation,actions)
+ end
+end
+
+-- todo, do this in references namespace ordered instead (this is an experiment)
+
+local splitter = lpeg.splitat(":")
+
+function specials.order(var,actions) -- jobreferences.specials !
+ local operation = var.operation
+ if operation then
+ local kind, name, n = lpegmatch(splitter,operation)
+ local order = lists.ordered[kind]
+ order = order and order[name]
+ local v = order[tonumber(n)]
+ local r = v and v.references.realpage
+ if r then
+ var.operation = r -- brrr, but test anyway
+ return specials.page(var,actions)
+ end
+ end
+end
+
+function specials.url(var,actions)
+ local url = jobreferences.checkedurl(var.operation)
+ return link(url,nil,var.arguments,nil,actions)
+end
+
+function specials.file(var,actions)
+ local file = jobreferences.checkedfile(var.operation)
+ return link(nil,file,var.arguments,nil,actions)
+end
+
+function specials.fileorurl(var,actions)
+ local file, url = jobreferences.checkedfileorurl(var.operation,var.operation)
+ return link(url,file,var.arguments,nil,actions)
+end
+
+function specials.program(var,content)
+ local program = jobreferences.checkedprogram(var.operation)
+ return lpdf.launch(program,var.arguments)
+end
+
+function specials.javascript(var)
+ return lpdf.javascript(var.operation,var.arguments)
+end
+
+specials.JS = specials.javascript
+
+local pdf_named = pdfconstant("Named")
+
+executers.importform = pdfdictionary { S = pdf_named, N = pdfconstant("AcroForm:ImportFDF") }
+executers.exportform = pdfdictionary { S = pdf_named, N = pdfconstant("AcroForm:ExportFDF") }
+executers.first = pdfdictionary { S = pdf_named, N = pdfconstant("FirstPage") }
+executers.previous = pdfdictionary { S = pdf_named, N = pdfconstant("PrevPage") }
+executers.next = pdfdictionary { S = pdf_named, N = pdfconstant("NextPage") }
+executers.last = pdfdictionary { S = pdf_named, N = pdfconstant("LastPage") }
+executers.backward = pdfdictionary { S = pdf_named, N = pdfconstant("GoBack") }
+executers.forward = pdfdictionary { S = pdf_named, N = pdfconstant("GoForward") }
+executers.print = pdfdictionary { S = pdf_named, N = pdfconstant("Print") }
+executers.exit = pdfdictionary { S = pdf_named, N = pdfconstant("Quit") }
+executers.close = pdfdictionary { S = pdf_named, N = pdfconstant("Close") }
+executers.save = pdfdictionary { S = pdf_named, N = pdfconstant("Save") }
+executers.savenamed = pdfdictionary { S = pdf_named, N = pdfconstant("SaveAs") }
+executers.opennamed = pdfdictionary { S = pdf_named, N = pdfconstant("Open") }
+executers.help = pdfdictionary { S = pdf_named, N = pdfconstant("HelpUserGuide") }
+executers.toggle = pdfdictionary { S = pdf_named, N = pdfconstant("FullScreen") }
+executers.search = pdfdictionary { S = pdf_named, N = pdfconstant("Find") }
+executers.searchagain = pdfdictionary { S = pdf_named, N = pdfconstant("FindAgain") }
+executers.gotopage = pdfdictionary { S = pdf_named, N = pdfconstant("GoToPage") }
+executers.query = pdfdictionary { S = pdf_named, N = pdfconstant("AcroSrch:Query") }
+executers.queryagain = pdfdictionary { S = pdf_named, N = pdfconstant("AcroSrch:NextHit") }
+executers.fitwidth = pdfdictionary { S = pdf_named, N = pdfconstant("FitWidth") }
+executers.fitheight = pdfdictionary { S = pdf_named, N = pdfconstant("FitHeight") }
+
+local function fieldset(arguments)
+ -- [\dogetfieldset{#1}]
+ return nil
+end
+
+function executers.resetform(arguments)
+ arguments = (type(arguments) == "table" and arguments) or aux.settings_to_array(arguments)
+ return pdfdictionary {
+ S = pdfconstant("ResetForm"),
+ Field = fieldset(arguments[1])
+ }
+end
+
+local formmethod = "post" -- "get" "post"
+local formformat = "xml" -- "xml" "html" "fdf"
+
+-- bit 3 = html bit 6 = xml bit 4 = get
+
+local flags = {
+ get = {
+ html = 12, fdf = 8, xml = 40,
+ },
+ post = {
+ html = 4, fdf = 0, xml = 32,
+ }
+}
+
+function executers.submitform(arguments)
+ arguments = (type(arguments) == "table" and arguments) or aux.settings_to_array(arguments)
+ local flag = flags[formmethod] or flags.post
+ flag = (flag and (flag[formformat] or flag.xml)) or 32 -- default: post, xml
+ return pdfdictionary {
+ S = pdfconstant("ResetForm"),
+ F = fieldset(arguments[1]),
+ Field = fieldset(arguments[2]),
+ Flags = flag,
+ -- \PDFsubmitfiller
+ }
+end
+
+function executers.hide(arguments)
+ return pdfdictionary {
+ S = pdfconstant("Hide"),
+ H = true,
+ T = arguments,
+ }
+end
+
+function executers.show(arguments)
+ return pdfdictionary {
+ S = pdfconstant("Hide"),
+ H = false,
+ T = arguments,
+ }
+end
+
+local pdf_movie = pdfconstant("Movie")
+local pdf_start = pdfconstant("Start")
+local pdf_stop = pdfconstant("Stop")
+local pdf_resume = pdfconstant("Resume")
+local pdf_pause = pdfconstant("Pause")
+
+local function movie_or_sound(operation,arguments)
+ arguments = (type(arguments) == "table" and arguments) or aux.settings_to_array(arguments)
+ return pdfdictionary {
+ S = pdf_movie,
+ T = format("movie %s",arguments[1] or "noname"),
+ Operation = operation,
+ }
+end
+
+function executers.startmovie (arguments) return movie_or_sound(pdf_start ,arguments) end
+function executers.stopmovie (arguments) return movie_or_sound(pdf_stop ,arguments) end
+function executers.resumemovie(arguments) return movie_or_sound(pdf_resume,arguments) end
+function executers.pausemovie (arguments) return movie_or_sound(pdf_pause ,arguments) end
+
+function executers.startsound (arguments) return movie_or_sound(pdf_start ,arguments) end
+function executers.stopsound (arguments) return movie_or_sound(pdf_stop ,arguments) end
+function executers.resumesound(arguments) return movie_or_sound(pdf_resume,arguments) end
+function executers.pausesound (arguments) return movie_or_sound(pdf_pause ,arguments) end
+
+function specials.action(var)
+ local operation = var.operation
+ if var.operation and operation ~= "" then
+ local e = executers[operation]
+ if type(e) == "table" then
+ return e
+ elseif type(e) == "function" then
+ return e(var.arguments)
+ end
+ end
+end
+
+--~ entry.A = pdfdictionary {
+--~ S = pdfconstant("GoTo"),
+--~ D = ....
+--~ }
+
+local function build(levels,start,parent,method)
+ local startlevel = levels[start][1]
+ local i, n = start, 0
+ local child, entry, m, prev, first, last, f, l
+-- to be tested: i can be nil
+ while i and i <= #levels do
+ local li = levels[i]
+ local level, title, reference, open = li[1], li[2], li[3], li[4]
+ if level == startlevel then
+ if trace_bookmarks then
+ logs.report("bookmark","%3i %s%s %s",reference.realpage,rep(" ",level-1),(open and "+") or "-",title)
+ end
+ local prev = child
+ child = pdfreserveobject()
+ if entry then
+ entry.Next = child and pdfreference(child)
+ pdfflushobject(prev,entry)
+ end
+ entry = pdfdictionary {
+ Title = pdfunicode(title),
+ Parent = parent,
+ Prev = prev and pdfreference(prev),
+ }
+ if method == "internal" then
+ entry.Dest = "aut:" .. reference.internal
+ else -- if method == "page" then
+ entry.Dest = pagedest(reference.realpage)
+ end
+ if not first then first, last = child, child end
+ prev = child
+ last = prev
+ n = n + 1
+ i = i + 1
+ elseif level < startlevel then
+ pdfflushobject(child,entry)
+ return i, n, first, last
+ elseif i < #levels and level > startlevel then
+ i, m, f, l = build(levels,i,pdfreference(child),method)
+ entry.Count = (open and m) or -m
+ if m > 0 then
+ entry.First, entry.Last = pdfreference(f), pdfreference(l)
+ end
+ else
+ -- missing intermediate level but ok
+ i, m, f, l = build(levels,i,pdfreference(child),method)
+ entry.Count = (open and m) or -m
+ if m > 0 then
+ entry.First, entry.Last = pdfreference(f), pdfreference(l)
+ end
+ pdfflushobject(child,entry)
+ return i, n, first, last
+ end
+ end
+ pdfflushobject(child,entry)
+ return nil, n, first, last
+end
+
+function codeinjections.addbookmarks(levels,method)
+ local parent = pdfreserveobject()
+ local _, m, first, last = build(levels,1,pdfreference(parent),method or "internal")
+ local dict = pdfdictionary {
+ Type = pdfconstant("Outlines"),
+ First = pdfreference(first),
+ Last = pdfreference(last),
+ Count = m,
+ }
+ pdfflushobject(parent,dict)
+ lpdf.addtocatalog("Outlines",lpdf.reference(parent))
+end
diff --git a/tex/context/base/lpdf-col.lua b/tex/context/base/lpdf-col.lua
new file mode 100644
index 000000000..18aa848ff
--- /dev/null
+++ b/tex/context/base/lpdf-col.lua
@@ -0,0 +1,150 @@
+if not modules then modules = { } end modules ['lpdf-mis'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type = type
+local format, gsub = string.format, string.gsub
+
+-- colors = colors or { }
+-- transparencies = transparencies or { }
+
+local registercolor = colors.register
+local registertransparancy = transparencies.register
+local colorsvalue = colors.value
+local transparenciesvalue = transparencies.value
+
+-- Literals needed to inject code in the mp stream, we cannot use attributes there
+-- since literals may have qQ's, much may go away once we have mplib code in place.
+--
+-- This module assumes that some functions are defined in the colors namespace
+-- which mostlikely will be loaded later.
+
+function lpdf.color(model,ca,default) -- todo: use gray when no color
+ local cv = colorsvalue(ca)
+ if cv then
+ if model == 1 then
+ model = cv[1]
+ end
+ if model == 2 then
+ local s = cv[2]
+ return format("%s g %s G",s,s)
+ elseif model == 3 then
+ local r, g, b = cv[3], cv[4], cv[5]
+ return format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b)
+ elseif model == 4 then
+ local c, m, y, k = cv[6],cv[7],cv[8],cv[9]
+ return format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k)
+ else
+ local n,f,d,p = cv[10],cv[11],cv[12],cv[13]
+ if type(p) == "string" then
+ p = gsub(p,","," ") -- brr misuse of spot
+ end
+ return format("/%s cs /%s CS %s SCN %s scn",n,n,p,p)
+ end
+ else
+ return format("%s g %s G",default or 0,default or 0)
+ end
+end
+
+function lpdf.transparency(ct,default) -- kind of overlaps with transparencycode
+ -- beware, we need this hack because normally transparencies are not
+ -- yet registered and therefore the number is not not known ... we
+ -- might use the attribute number itself in the future
+ local ct = transparenciesvalue(ct)
+ if ct then
+ return format("/Tr%s gs",registertransparancy(nil,ct[1],ct[2],true))
+ else
+ return "/Tr0 gs"
+ end
+end
+
+function lpdf.colorvalue(model,ca,default)
+ local cv = colorsvalue(ca)
+ if cv then
+ if model == 1 then
+ model = cv[1]
+ end
+ if model == 2 then
+ return format("%s",cv[2])
+ elseif model == 3 then
+ return format("%s %s %s",cv[3],cv[4],cv[5])
+ elseif model == 4 then
+ return format("%s %s %s %s",cv[6],cv[7],cv[8],cv[9])
+ else
+ return format("%s",cv[13])
+ end
+ else
+ return format("%s",default or 0)
+ end
+end
+
+function lpdf.fdfcolor(model,ca,default)
+ local cv = colorsvalue(ca)
+ if cv then
+ if model == 1 then
+ model = cv[1]
+ end
+ if model == 2 then
+ return format("[%s]",cv[2])
+ elseif model == 3 then
+ return format("[%s %s %s]",cv[3],cv[4],cv[5])
+ elseif model == 4 then
+ return format("[%s %s %s %s]",cv[6],cv[7],cv[8],cv[9])
+ elseif model == 4 then
+ return format("[%s]",cv[13])
+ end
+ else
+ return format("[%s]",default or 0)
+ end
+end
+
+function lpdf.colorspace(model,ca)
+ local cv = colorsvalue(ca)
+ if cv then
+ if model == 1 then
+ model = cv[1]
+ end
+ if model == 2 then
+ return "DeviceGray"
+ elseif model == 3 then
+ return "DeviceRGB"
+ elseif model == 4 then
+ return "DeviceCMYK"
+ end
+ end
+ return "DeviceGRAY"
+end
+
+-- by registering we getconversion for free (ok, at the cost of overhead)
+
+local intransparency = false
+local pdfcolor = lpdf.color
+
+function lpdf.rgbcode(model,r,g,b)
+ return pdfcolor(model,registercolor(nil,'rgb',r,g,b))
+end
+function lpdf.cmykcode(model,c,m,y,k)
+ return pdfcolor(model,registercolor(nil,'cmyk',c,m,y,k))
+end
+function lpdf.graycode(model,s)
+ return pdfcolor(model,registercolor(nil,'gray',s))
+end
+function lpdf.spotcode(model,n,f,d,p)
+ return pdfcolor(model,registercolor(nil,'spot',n,f,d,p)) -- incorrect
+end
+function lpdf.transparencycode(a,t)
+ intransparency = true
+ return format("/Tr%s gs",registertransparancy(nil,a,t,true)) -- true forces resource
+end
+function lpdf.finishtransparencycode()
+ if intransparency then
+ intransparency = false
+ return "/Tr0 gs" -- we happen to know this -)
+ else
+ return ""
+ end
+end
diff --git a/tex/context/base/lpdf-fld.lua b/tex/context/base/lpdf-fld.lua
new file mode 100644
index 000000000..c034aec6c
--- /dev/null
+++ b/tex/context/base/lpdf-fld.lua
@@ -0,0 +1,885 @@
+if not modules then modules = { } end modules ['lpdf-fld'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- cleaned up, e.g. no longer older viewers
+-- always kids so no longer explicit main / clone / copy
+-- some optimizations removed (will come bakc if needed)
+
+local gmatch, lower, format = string.gmatch, string.lower, string.format
+local lpegmatch = lpeg.match
+
+local trace_fields = false trackers.register("widgets.fields", function(v) trace_fields = v end)
+
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+
+local variables = interfaces.variables
+
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
+
+local registeredsymbol = codeinjections.registeredsymbol
+
+local pdfstream = lpdf.stream
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfstring = lpdf.string
+local pdfconstant = lpdf.constant
+local pdftoeight = lpdf.toeight
+local pdfflushobject = lpdf.flushobject
+local pdfreserveobject = lpdf.reserveobject
+local pdfannotation = nodes.pdfannotation
+
+local submitoutputformat = 0 -- 0=unknown 1=HTML 2=FDF 3=XML => not yet used, needs to be checked
+
+local splitter = lpeg.splitat("=>")
+
+local formats = {
+ html = 1, fdf = 2, xml = 3,
+}
+
+function codeinjections.setformsmethod(name)
+ submitoutputformat = formats[lower(name)] or 3
+end
+
+local flag = {
+ MultiLine = 4096, -- 13
+ NoToggleToOff = 16384, -- 15
+ Radio = 32768, -- 16
+ PushButton = 65536, -- 17
+ PopUp = 131072, -- 18
+ Edit = 262144, -- 19
+ RadiosInUnison = 33554432, -- 26
+ DoNotSpellCheck = 4194304, -- 23
+ DoNotScroll = 8388608, -- 24
+ ReadOnly = 1, -- 1
+ Required = 2, -- 2
+ NoExport = 4, -- 3
+ Password = 8192, -- 14
+ Sort = 524288, -- 20
+ FileSelect = 1048576, -- 21
+}
+
+local plus = {
+ Invisible = 1, -- 1
+ Hidden = 2, -- 2
+ Printable = 4, -- 3
+ NoView = 32, -- 6
+ ToggleNoView = 256, -- 9
+ AutoView = 256, -- 288 (6+9)
+}
+
+-- todo: check what is interfaced
+
+flag.readonly = flag.ReadOnly
+flag.required = flag.Required
+flag.protected = flag.Password
+flag.sorted = flag.Sort
+flag.unavailable = flag.NoExport
+flag.nocheck = flag.DoNotSpellCheck
+flag.fixed = flag.DoNotScroll
+flag.file = flag.FileSelect
+
+plus.hidden = plus.Hidden
+plus.printable = plus.Printable
+plus.auto = plus.AutoView
+
+-- some day .. lpeg with function or table
+
+local function fieldflag(specification)
+ local o, n = specification.options, 0
+ if o and o ~= "" then
+ for f in gmatch(o,"[^, ]+") do
+ n = n + (flag[f] or 0)
+ end
+ end
+ return n
+end
+
+local function fieldplus(specification)
+ local o, n = specification.options, 0
+ if o and o ~= "" then
+ for p in gmatch(o,"[^, ]+") do
+ n = n + (plus[p] or 0)
+ end
+ end
+ return n
+end
+
+
+local function checked(what)
+ if what and what ~= "" then
+ local set, bug = jobreferences.identify("",what)
+ return not bug and #set > 0 and lpdf.pdfaction(set)
+ end
+end
+
+local function fieldactions(specification) -- share actions
+--~ print(table.serialize(specification))
+ local d, a = { }, nil
+ a = specification.mousedown if a and a ~= "" then d.D = checked(a) end
+ a = specification.mouseup if a and a ~= "" then d.U = checked(a) end
+ a = specification.regionin if a and a ~= "" then d.E = checked(a) end -- Enter
+ a = specification.regionout if a and a ~= "" then d.X = checked(a) end -- eXit
+ a = specification.afterkeystroke if a and a ~= "" then d.K = checked(a) end
+ a = specification.formatresult if a and a ~= "" then d.F = checked(a) end
+ a = specification.validateresult if a and a ~= "" then d.V = checked(a) end
+ a = specification.calculatewhatever if a and a ~= "" then d.C = checked(a) end
+ a = specification.focusin if a and a ~= "" then d.Fo = checked(a) end
+ a = specification.focusout if a and a ~= "" then d.Bl = checked(a) end
+ -- a = specification.openpage if a and a ~= "" then d.PO = checked(a) end
+ -- a = specification.closepage if a and a ~= "" then d.PC = checked(a) end
+ -- a = specification.visiblepage if a and a ~= "" then d.PV = checked(a) end
+ -- a = specification.invisiblepage if a and a ~= "" then d.PI = checked(a) end
+ return next(d) and pdfdictionary(d)
+end
+
+-- fonts and color
+
+local fontnames = {
+ rm = {
+ tf = "Times-Roman",
+ bf = "Times-Bold",
+ it = "Times-Italic",
+ sl = "Times-Italic",
+ bi = "Times-BoldItalic",
+ bs = "Times-BoldItalic",
+ },
+ ss = {
+ tf = "Helvetica",
+ bf = "Helvetica-Bold",
+ it = "Helvetica-Oblique",
+ sl = "Helvetica-Oblique",
+ bi = "Helvetica-BoldOblique",
+ bs = "Helvetica-BoldOblique",
+ },
+ tt = {
+ tf = "Courier",
+ bf = "Courier-Bold",
+ it = "Courier-Oblique",
+ sl = "Courier-Oblique",
+ bi = "Courier-BoldOblique",
+ bs = "Courier-BoldOblique",
+ }
+}
+
+local usedfonts = { }
+
+local function fieldsurrounding(specification)
+ local size = specification.fontsize or "12pt"
+ local style = specification.fontstyle or "rm"
+ local alternative = specification.fontalternative or "tf"
+ local s = fontnames[style]
+ if not s then
+ style, s = "rm", fontnames.rm
+ end
+ local a = s[alternative]
+ if not a then
+ alternative, a = "tf", s.tf
+ end
+ local tag = style .. alternative
+ size = string.todimen(size)
+ local stream = pdfstream {
+ pdfconstant(tag),
+ format("%0.4f Tf",(size and (number.dimenfactors.bp * size)) or 12),
+ }
+ usedfonts[tag] = a -- the name
+ -- add color to stream: 0 g
+ -- move up with "x.y Ts"
+ return tostring(stream)
+end
+
+local function registerfonts()
+ if next(usedfonts) then
+ local d = pdfdictionary()
+ for tag, name in next, usedfonts do
+ local f = pdfdictionary {
+ Type = pdfconstant("Font"),
+ Subtype = pdfconstant("Type1"), -- todo
+ Name = pdfconstant(tag),
+ BaseFont = pdfconstant(name),
+ }
+ d[tag] = pdfreference(pdfflushobject(f))
+ end
+ return d
+ end
+end
+
+-- cache
+
+local function fieldattributes(specification)
+--~ return pdfarray {
+--~ -- BG = -- backgroundcolor
+--~ -- BC = -- framecolor
+--~ }
+ return nil
+end
+
+-- symbols
+
+local function fieldappearances(specification)
+ -- todo: caching
+ local values = specification.values
+ local default = specification.default -- todo
+ if not values then
+ -- error
+ return
+ end
+ local v = aux.settings_to_array(values)
+ local n, r, d
+ if #v == 1 then
+ n, r, d = v[1], v[1], v[1]
+ elseif #v == 2 then
+ n, r, d = v[1], v[1], v[2]
+ else
+ n, r, d = v[1], v[2], v[3]
+ end
+ local appearance = pdfdictionary { -- cache this one
+ N = registeredsymbol(n), R = registeredsymbol(r), D = registeredsymbol(d),
+ }
+ return lpdf.sharedobj(tostring(appearance))
+end
+
+local function fieldstates(specification,forceyes,values,default)
+ -- we don't use Opt here (too messy for radio buttons)
+ local values, default = values or specification.values, default or specification.default
+ if not values then
+ -- error
+ return
+ end
+ local v = aux.settings_to_array(values)
+ local yes, off
+ if #v == 1 then
+ yes, off = v[1], v[1]
+ else
+ yes, off = v[1], v[2]
+ end
+ local yesshown, yesvalue = lpegmatch(splitter,yes)
+ if not (yesshown and yesvalue) then
+ yesshown = yes, yes
+ end
+ yes = aux.settings_to_array(yesshown)
+ local offshown, offvalue = lpegmatch(splitter,off)
+ if not (offshown and offvalue) then
+ offshown = off, off
+ end
+ off = aux.settings_to_array(offshown)
+ if #yes == 1 then
+ yesn, yesr, yesd = yes[1], yes[1], yes[1]
+ elseif #yes == 2 then
+ yesn, yesr, yesd = yes[1], yes[1], yes[2]
+ else
+ yesn, yesr, yesd = yes[1], yes[2], yes[3]
+ end
+ if #off == 1 then
+ offn, offr, offd = off[1], off[1], off[1]
+ elseif #off == 2 then
+ offn, offr, offd = off[1], off[1], off[2]
+ else
+ offn, offr, offd = off[1], off[2], off[3]
+ end
+ if not yesvalue then
+ yesvalue = yesn
+ end
+ if not offvalue then
+ offvalue = offn
+ end
+ if forceyes == true then
+ forceyes = forceyes and "On" -- spec likes Yes more but we've used On for ages now
+ else
+ -- false or string
+ end
+ if default == yesn then
+ default = pdfconstant(forceyes or yesn)
+ else
+ default = pdfconstant("Off")
+ end
+ local appearance = pdfdictionary { -- maybe also cache components
+ N = pdfdictionary { [forceyes or yesn] = registeredsymbol(yesn), Off = registeredsymbol(offn) },
+ R = pdfdictionary { [forceyes or yesr] = registeredsymbol(yesr), Off = registeredsymbol(offr) },
+ D = pdfdictionary { [forceyes or yesd] = registeredsymbol(yesd), Off = registeredsymbol(offd) }
+ }
+ local appearanceref = lpdf.sharedobj(tostring(appearance))
+ return appearanceref, default
+end
+
+local function fieldoptions(specification)
+ local values = specification.values
+ local default = specification.default
+ if values then
+ local v = aux.settings_to_array(values)
+ for i=1,#v do
+ local vi = v[i]
+ local shown, value = lpegmatch(splitter,vi)
+ if shown and value then
+ v[i] = pdfarray { pdfunicode(value), shown }
+ else
+ v[i] = pdfunicode(v[i])
+ end
+ end
+ return pdfarray(v)
+ end
+end
+
+local function radiodefault(parent,field,forceyes)
+ local default, values = parent.default, parent.values
+ if not default or default == "" then
+ values = aux.settings_to_array(values)
+ default = values[1]
+ end
+ local name = field.name
+ local fieldvalues = aux.settings_to_array(field.values)
+ local yes, off = fieldvalues[1], fieldvalues[2] or fieldvalues[1]
+ if not default then
+ return pdfconstant((forceyes and "On") or yes)
+ elseif default == name then
+ return pdfconstant((forceyes and "On") or default)
+ else
+ return pdfconstant("Off")
+ end
+end
+
+-- layers
+
+local function fieldlayer(specification) -- we can move this in line
+ local layer = specification.layer
+ return (layer and lpdf.layerreferences[layer]) or nil
+end
+
+-- defining
+
+local fields, radios, clones, fieldsets, calculationset = { }, { }, { }, { }, nil
+
+function codeinjections.definefieldset(tag,list)
+ fieldsets[tag] = list
+end
+
+function codeinjections.getfieldset(tag)
+ return fieldsets[tag]
+end
+
+local function fieldsetlist(tag)
+ if tag then
+ local ft = fieldsets[tag]
+ if ft then
+ local a = pdfarray()
+ for name in gmatch(list,"[^, ]+") do
+ local f = field[name]
+ if f and f.pobj then
+ a[#a+1] = pdfreference(f.pobj)
+ end
+ end
+ return a
+ end
+ end
+end
+
+function codeinjections.setfieldcalculationset(tag)
+ calculationset = tag
+end
+
+local function predefinesymbols(specification)
+ local values = specification.values
+ if values then
+ local symbols = aux.settings_to_array(values)
+ for i=1,#symbols do
+ local symbol = symbols[i]
+ local a, b = lpegmatch(splitter,symbol)
+ codeinjections.presetsymbol(a or symbol)
+ end
+ end
+end
+
+function codeinjections.getdefaultfieldvalue(name)
+ local f = fields[name]
+ if f then
+ local values = f.values
+ local default = f.default
+ if not default or default == "" then
+ local symbols = aux.settings_to_array(values)
+ local symbol = symbols[1]
+ if symbol then
+ local a, b = lpegmatch(splitter,symbol) -- splits at =>
+ default = a or symbol
+ end
+ end
+ if default then
+ tex.sprint(ctxcatcodes,default)
+ end
+ end
+end
+
+function codeinjections.definefield(specification)
+ local n = specification.name
+ local f = fields[n]
+ if not f then
+ local kind = specification.kind
+ if not kind then
+ if trace_fields then
+ logs.report("fields","invalid definition of '%s': unknown type",n)
+ end
+ elseif kind == "radio" then
+ local values = specification.values
+ if values and values ~= "" then
+ values = aux.settings_to_array(values)
+ for v=1,#values do
+ radios[values[v]] = { parent = n }
+ end
+ fields[n] = specification
+ if trace_fields then
+ logs.report("fields","defining '%s' as radio",n or "?")
+ end
+ elseif trace_fields then
+ logs.report("fields","invalid definition of radio '%s': missing values",n)
+ end
+ elseif kind == "sub" then
+ -- not in main field list !
+ local radio = radios[n]
+ if radio then
+ -- merge specification
+ for key, value in next, specification do
+ radio[key] = value
+ end
+ if trace_fields then
+ local p = radios[n] and radios[n].parent
+ logs.report("fields","defining '%s' as sub of radio '%s'",n or "?",p or "?")
+ end
+ elseif trace_fields then
+ logs.report("fields","invalid definition of radio sub '%s': no parent",n)
+ end
+ predefinesymbols(specification)
+ elseif kind == "text" or kind == "line" then
+ fields[n] = specification
+ if trace_fields then
+ logs.report("fields","defining '%s' as %s",n,kind)
+ end
+ if specification.values ~= "" and specification.default == "" then
+ specification.default, specification.values = specification.values, nil
+ end
+ else
+ fields[n] = specification
+ if trace_fields then
+ logs.report("fields","defining '%s' as %s",n,kind)
+ end
+ predefinesymbols(specification)
+ end
+ elseif trace_fields then
+ logs.report("fields","invalid definition of '%s': already defined",n)
+ end
+end
+
+function codeinjections.clonefield(specification)
+ local p, c, v = specification.parent, specification.children, specification.variant
+ if not p or not c then
+ if trace_fields then
+ logs.report("fields","invalid clone: children: '%s', parent '%s', variant: '%s'",p or "?",c or "?", v or "?")
+ end
+ else
+ for n in gmatch(c,"[^, ]+") do
+ local f, r, c, x = fields[n], radios[n], clones[n], fields[p]
+ if f or r or c then
+ if trace_fields then
+ logs.report("fields","already cloned: child: '%s', parent '%s', variant: '%s'",p or "?",n or "?", v or "?")
+ end
+ elseif x then
+ if trace_fields then
+ logs.report("fields","invalid clone: child: '%s', variant: '%s', no parent",n or "?", v or "?")
+ end
+ else
+ if trace_fields then
+ logs.report("fields","cloning: child: '%s', parent '%s', variant: '%s'",p or "?",n or "?", v or "?")
+ end
+ clones[n] = specification
+ predefinesymbols(specification)
+ end
+ end
+ end
+end
+
+function codeinjections.getfieldgroup(name)
+ local f = fields[name] or radios[name] or clones[name]
+ local g = f and f.group
+ if not g or g == "" then
+ local v, p, k = f.variant, f.parent, f.kind
+ if v == "clone" or v == "copy" then
+ f = fields[p] or radios[p]
+ g = f and f.group
+ elseif k == "sub" then
+ f = fields[p]
+ g = f and f.group
+ end
+ end
+ if g then
+ texsprint(ctxcatcodes,g)
+ end
+end
+
+--
+
+function codeinjections.doiffieldset(tag)
+ commands.testcase(fieldsets[tag])
+end
+
+function codeinjections.doiffieldelse(name)
+ commands.testcase(fields[name])
+end
+
+--
+
+local alignments = {
+ flushleft = 0, right = 0,
+ center = 1, middle = 1,
+ flushright = 2, left = 2,
+}
+
+local function fieldalignment(specification)
+ return alignments[specification.align] or 0
+end
+
+local function enhance(specification,option)
+ local so = specification.options
+ if so and so ~= "" then
+ specification.options = so .. "," .. option
+ else
+ specification.options = option
+ end
+ return specification
+end
+
+-- finish
+
+local collected = pdfarray()
+
+local function finishfields()
+ for name, field in next, fields do
+ local kids = field.kids
+ if kids then
+ pdfflushobject(field.kobj,kids)
+ end
+ local pobj = field.pobj
+ end
+ for name, field in next, radios do
+ local kids = field.kids
+ if kids then
+ pdfflushobject(field.kobj,kids)
+ end
+ end
+ if #collected > 0 then
+ usedfonts.tttf = fontnames.tt.tf
+ local acroform = pdfdictionary {
+ NeedAppearances = true,
+ Fields = pdfreference(pdfflushobject(collected)),
+ DR = pdfdictionary { Font = registerfonts() },
+ CO = fieldsetlist(calculationset),
+ DA = "/tttf 12 Tf 0 g",
+ }
+ lpdf.addtocatalog("AcroForm",pdfreference(pdfflushobject(acroform)))
+ end
+end
+
+lpdf.registerdocumentfinalizer(finishfields)
+
+local pdf_widget = pdfconstant("Widget")
+local pdf_tx = pdfconstant("Tx")
+local pdf_ch = pdfconstant("Ch")
+local pdf_btn = pdfconstant("Btn")
+local pdf_yes = pdfconstant("Yes")
+local pdf_p = pdfconstant("P") -- None Invert Outline Push
+local pdf_n = pdfconstant("N") -- None Invert Outline Push
+--
+local pdf_no_rect = pdfarray { 0, 0, 0, 0 }
+
+local methods = { }
+
+function codeinjections.typesetfield(name,specification)
+ local field = fields[name] or radios[name] or clones[name]
+ if not field then
+ logs.report("fields", "unknown child '%s'",name)
+ -- unknown field
+ return
+ end
+ local variant, parent = field.variant, field.parent
+ if variant == "copy" or variant == "clone" then -- only in clones
+ field = fields[parent] or radios[parent]
+ end
+ local method = methods[field.kind]
+ if method then
+ method(name,specification,variant)
+ else
+ logs.report("fields", "unknown method '%s' for child '%s'",field.kind,name)
+ end
+end
+
+-- can be optional multipass optimization (share objects)
+
+local function save_parent(field,specification,d)
+ local kn = pdfreserveobject()
+ d.Kids = pdfreference(kn)
+ field.kobj = kn
+ field.kids = pdfarray()
+ local pn = pdfflushobject(d)
+ field.pobj = pn
+ collected[#collected+1] = pdfreference(pn)
+end
+
+local function save_kid(field,specification,d)
+ local kn = pdfreserveobject()
+ field.kids[#field.kids+1] = pdfreference(kn)
+ node.write(pdfannotation(specification.width,specification.height,0,d(),kn))
+end
+
+function methods.line(name,specification,variant,extras)
+ local field = fields[name]
+ if variant == "copy" or variant == "clone" then
+ logs.report("fields","todo: clones of text fields")
+ end
+ local kind = field.kind
+ if not field.pobj then
+ if trace_fields then
+ logs.report("fields","using parent text '%s'",name)
+ end
+ if extras then
+ enhance(specification,extras)
+ end
+ local text = pdfunicode(field.default)
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ MK = fieldsurrounding(specification), -- needed ?
+ DA = fieldsurrounding(specification),
+ AA = fieldactions(specification),
+ FT = pdf_tx,
+ Q = fieldalignment(specification),
+ MaxLen = (specification.length == 0 and 1000) or specification.length,
+ DV = text,
+ V = text,
+ }
+ save_parent(field,specification,d)
+ field.specification = specification
+ end
+ specification = field.specification or { } -- todo: radio spec
+ if trace_fields then
+ logs.report("fields","using child text '%s'",name)
+ end
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ Parent = pdfreference(field.pobj),
+ F = fieldplus(specification),
+ DA = fieldattributes(specification),
+ OC = fieldlayer(specification),
+ MK = fieldsurrounding(specification),
+ DA = fieldsurrounding(specification),
+ AA = fieldactions(specification),
+ Q = fieldalignment(specification),
+ }
+ save_kid(field,specification,d)
+end
+
+function methods.text(name,specification,variant)
+ methods.line(name,specification,variant,"MultiLine")
+end
+
+function methods.choice(name,specification,variant,extras)
+ local field = fields[name]
+ if variant == "copy" or variant == "clone" then
+ logs.report("fields","todo: clones of choice fields")
+ end
+ local kind = field.kind
+ local d
+ if not field.pobj then
+ if trace_fields then
+ logs.report("fields","using parent choice '%s'",name)
+ end
+ if extras then
+ enhance(specification,extras)
+ end
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ FT = pdf_ch,
+ Opt = fieldoptions(field),
+ }
+ save_parent(field,specification,d)
+ field.specification = specification
+ end
+ specification = field.specification or { }
+ if trace_fields then
+ logs.report("fields","using child choice '%s'",name)
+ end
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ Parent = pdfreference(field.pobj),
+ F = fieldplus(specification),
+ DA = fieldattributes(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ }
+ save_kid(field,specification,d)
+end
+
+function methods.popup(name,specification,variant)
+ methods.choice(name,specification,variant,"PopUp")
+end
+function methods.combo(name,specification,variant)
+ methods.choice(name,specification,variant,"PopUp,Edit")
+end
+
+-- Probably no default appearance needed for first kid and no javascripts for the
+-- parent ... I will look into it when I have to make a complex document.
+
+function methods.check(name,specification,variant)
+ -- no /Opt because (1) it's messy - see pdf spec, (2) it discouples kids and
+ -- contrary to radio there is no way to associate then
+ local field = fields[name]
+ if variant == "copy" or variant == "clone" then
+ logs.report("fields","todo: clones of check fields")
+ end
+ local kind = field.kind
+ local appearance, default = fieldstates(field,true)
+ if not field.pobj then
+ if trace_fields then
+ logs.report("fields","using parent check '%s'",name)
+ end
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ FT = pdf_btn,
+ DV = default,
+ V = default,
+ AS = default,
+ AP = appearance,
+ H = pdf_n,
+ }
+ save_parent(field,specification,d)
+ field.specification = specification
+ end
+ specification = field.specification or { } -- todo: radio spec
+ if trace_fields then
+ logs.report("fields","using child check '%s'",name)
+ end
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ Parent = pdfreference(field.pobj),
+ F = fieldplus(specification),
+ DA = fieldattributes(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ DV = default,
+ V = default,
+ AS = default,
+ AP = appearance,
+ H = pdf_n,
+ }
+ save_kid(field,specification,d)
+end
+
+function methods.push(name,specification,variant)
+ local field = fields[name]
+ if variant == "copy" or variant == "clone" then
+ logs.report("fields","todo: clones of push fields")
+ end
+ local kind = field.kind
+ if not field.pobj then
+ if trace_fields then
+ logs.report("fields","using parent push '%s'",name)
+ end
+ enhance(specification,"PushButton")
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ FT = pdf_btn,
+ AP = fieldappearances(field),
+ H = pdf_p,
+ }
+ save_parent(field,specification,d)
+ field.specification = specification
+ end
+ specification = field.specification or { } -- todo: radio spec
+ if trace_fields then
+ logs.report("fields","using child push '%s'",name)
+ end
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ Parent = pdfreference(field.pobj),
+ F = fieldplus(specification),
+ DA = fieldattributes(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ AP = fieldappearances(field),
+ H = pdf_p,
+ }
+ save_kid(field,specification,d)
+end
+
+function methods.sub(name,specification,variant)
+ local field = radios[name] or fields[name] or clones[name] -- fields in case of a clone, maybe use dedicated clones
+ local values
+ if variant == "copy" or variant == "clone" then
+ name = field.parent
+ values = field.values -- clone only, copy has nil so same as parent
+ field = radios[name]
+ else
+ values = field.values
+ end
+ local parent = fields[field.parent]
+ if not parent then
+ return
+ end
+ local appearance = fieldstates(field,name,values) -- we need to force the 'On' name
+ local default = radiodefault(parent,field)
+ if not parent.pobj then
+ if trace_fields then
+ logs.report("fields","using parent '%s' of radio '%s' with values '%s' and default '%s'",parent.name,name,parent.values or "?",parent.default or "?")
+ end
+ local specification = parent.specification or { }
+ -- enhance(specification,"Radio,RadiosInUnison")
+ enhance(specification,"RadiosInUnison") -- maybe also PushButton as acrobat does
+ local d = pdfdictionary {
+ T = parent.name,
+ FT = pdf_btn,
+ Rect = pdf_no_rect,
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ H = pdf_n,
+ V = default,
+ }
+ save_parent(parent,specification,d)
+ end
+ if trace_fields then
+ logs.report("fields","using child radio '%s' with values '%s'",name,values or "?")
+ end
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ Parent = pdfreference(parent.pobj),
+ F = fieldplus(specification),
+ DA = fieldattributes(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ AS = default,
+ AP = appearance,
+ H = pdf_n,
+ }
+ save_kid(parent,specification,d)
+end
diff --git a/tex/context/base/lpdf-grp.lua b/tex/context/base/lpdf-grp.lua
new file mode 100644
index 000000000..ad01e4d4f
--- /dev/null
+++ b/tex/context/base/lpdf-grp.lua
@@ -0,0 +1,68 @@
+if not modules then modules = { } end modules ['lpdf-grp'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
+
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfconstant = lpdf.constant
+local pdfreference = lpdf.reference
+local pdfflushobject = lpdf.flushobject
+
+local function shade(stype,name,domain,color_a,color_b,n,colorspace,coordinates)
+ local f = pdfdictionary {
+ FunctionType = 2,
+ Domain = pdfarray(domain), -- domain is actually a string
+ C0 = pdfarray(color_a),
+ C1 = pdfarray(color_b),
+ N = tonumber(n),
+ }
+ local s = pdfdictionary {
+ ShadingType = stype,
+ ColorSpace = pdfconstant(colorspace),
+ Function = pdfreference(pdfflushobject(f)),
+ Coords = pdfarray(coordinates),
+ Extend = pdfarray { true, true },
+ }
+ lpdf.adddocumentshade(name,pdfreference(pdfflushobject(s)))
+end
+
+function lpdf.circularshade(name,domain,color_a,color_b,n,colorspace,coordinates)
+ shade(3,name,domain,color_a,color_b,n,colorspace,coordinates)
+end
+
+function lpdf.linearshade(name,domain,color_a,color_b,n,colorspace,coordinates)
+ shade(2,name,domain,color_a,color_b,n,colorspace,coordinates)
+end
+
+function lpdf.colorspec(model,ca,default)
+ if ca and ca > 0 then
+ local cv = colors.value(ca)
+ if cv then
+ if model == 1 then
+ model = cv[1]
+ end
+ if model == 2 then
+ return pdfarray { cv[2] }
+ elseif model == 3 then
+ return pdfarray { cv[3],cv[4],cv[5] }
+ elseif model == 4 then
+ return pdfarray { cv[6],cv[7],cv[8],cv[9] }
+ elseif model == 5 then
+ return pdfarray { cv[13] }
+ end
+ end
+ end
+ if default then
+ return default
+ end
+end
diff --git a/tex/context/base/lpdf-ini.lua b/tex/context/base/lpdf-ini.lua
new file mode 100644
index 000000000..e0ffd4052
--- /dev/null
+++ b/tex/context/base/lpdf-ini.lua
@@ -0,0 +1,670 @@
+if not modules then modules = { } end modules ['lpdf-ini'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local setmetatable, getmetatable, type, next, tostring, tonumber, rawset = setmetatable, getmetatable, type, next, tostring, tonumber, rawset
+local char, byte, format, gsub, concat, match, sub, gmatch = string.char, string.byte, string.format, string.gsub, table.concat, string.match, string.sub, string.gmatch
+local utfvalues = string.utfvalues
+local texwrite, texset, texsprint, ctxcatcodes = tex.write, tex.set, tex.sprint, tex.ctxcatcodes
+local sind, cosd = math.sind, math.cosd
+local lpegmatch = lpeg.match
+
+local pdfreserveobj = pdf and pdf.reserveobj or function() return 1 end -- for testing
+local pdfimmediateobj = pdf and pdf.immediateobj or function() return 2 end -- for testing
+
+local trace_finalizers = false trackers.register("backend.finalizers", function(v) trace_finalizers = v end)
+local trace_resources = false trackers.register("backend.resources", function(v) trace_resources = v end)
+local trace_objects = false trackers.register("backend.objects", function(v) trace_objects = v end)
+local trace_detail = false trackers.register("backend.detail", function(v) trace_detail = v end)
+
+lpdf = lpdf or { }
+
+local function tosixteen(str)
+ if not str or str == "" then
+ return "()"
+ else
+ local r = { ""
+ return concat(r)
+ end
+end
+
+lpdf.tosixteen = tosixteen
+
+-- lpeg is some 5 times faster than gsub (in test) on escaping
+
+-- local escapes = {
+-- ["\\"] = "\\\\",
+-- ["/"] = "\\/", ["#"] = "\\#",
+-- ["<"] = "\\<", [">"] = "\\>",
+-- ["["] = "\\[", ["]"] = "\\]",
+-- ["("] = "\\(", [")"] = "\\)",
+-- }
+--
+-- local escaped = lpeg.Cs(lpeg.Cc("(") * (lpeg.S("\\/#<>[]()")/escapes + lpeg.P(1))^0 * lpeg.Cc(")"))
+--
+-- local function toeight(str)
+-- if not str or str == "" then
+-- return "()"
+-- else
+-- return lpegmatch(escaped,str)
+-- end
+-- end
+--
+-- -- no need for escaping .. just use unicode instead
+
+-- \0 \t \n \r \f ( ) [ ] { } / %
+
+local function toeight(str)
+ return "(" .. str .. ")"
+end
+
+lpdf.toeight = toeight
+
+--~ local escaped = lpeg.Cs((lpeg.S("\0\t\n\r\f ()[]{}/%")/"#" + lpeg.P(1))^0)
+--~
+--~ local function cleaned(str)
+--~ return (str and str ~= "" and lpegmatch(escaped,str)) or ""
+--~ end
+--~
+--~ lpdf.cleaned = cleaned -- not public yet
+
+local function merge_t(a,b)
+ local t = { }
+ for k,v in next, a do t[k] = v end
+ for k,v in next, b do t[k] = v end
+ return setmetatable(t,getmetatable(a))
+end
+
+local tostring_a, tostring_d
+
+tostring_d = function(t,contentonly,key)
+ if not next(t) then
+ if contentonly then
+ return ""
+ else
+ return "<< >>"
+ end
+ else
+ local r = { }
+ for k, v in next, t do
+ local tv = type(v)
+ if tv == "string" then
+ r[#r+1] = format("/%s %s",k,toeight(v))
+ elseif tv == "unicode" then
+ r[#r+1] = format("/%s %s",k,tosixteen(v))
+ elseif tv == "table" then
+ local mv = getmetatable(v)
+ if mv and mv.__lpdftype then
+ r[#r+1] = format("/%s %s",k,tostring(v))
+ elseif v[1] then
+ r[#r+1] = format("/%s %s",k,tostring_a(v))
+ else
+ r[#r+1] = format("/%s %s",k,tostring_d(v))
+ end
+ else
+ r[#r+1] = format("/%s %s",k,tostring(v))
+ end
+ end
+ if contentonly then
+ return concat(r, " ")
+ elseif key then
+ return format("/%s << %s >>", key, concat(r, " "))
+ else
+ return format("<< %s >>", concat(r, " "))
+ end
+ end
+end
+
+tostring_a = function(t,contentonly,key)
+ if #t == 0 then
+ if contentonly then
+ return ""
+ else
+ return "[ ]"
+ end
+ else
+ local r = { }
+ for k, v in next, t do
+ local tv = type(v)
+ if tv == "string" then
+ r[#r+1] = toeight(v)
+ elseif tv == "unicode" then
+ r[#r+1] = tosixteen(v)
+ elseif tv == "table" then
+ local mv = getmetatable(v)
+ local mt = mv and mv.__lpdftype
+ if mt then
+ r[#r+1] = tostring(v)
+ elseif v[1] then
+ r[#r+1] = tostring_a(v)
+ else
+ r[#r+1] = tostring_d(v)
+ end
+ else
+ r[#r+1] = tostring(v)
+ end
+ end
+ if contentonly then
+ return concat(r, " ")
+ elseif key then
+ return format("/%s [ %s ]", key, concat(r, " "))
+ else
+ return format("[ %s ]", concat(r, " "))
+ end
+ end
+end
+
+local tostring_x = function(t) return concat(t, " ") end
+local tostring_s = function(t) return toeight(t[1]) end
+local tostring_u = function(t) return tosixteen(t[1]) end
+local tostring_n = function(t) return tostring(t[1]) end -- tostring not needed
+local tostring_c = function(t) return t[1] end -- already prefixed (hashed)
+local tostring_z = function() return "null" end
+local tostring_t = function() return "true" end
+local tostring_f = function() return "false" end
+local tostring_r = function(t) return t[1] .. " 0 R" end
+
+local tostring_v = function(t)
+ local s = t[1]
+ if type(s) == "table" then
+ return concat(s,"")
+ else
+ return s
+ end
+end
+
+local function value_x(t) return t end -- the call is experimental
+local function value_s(t,key) return t[1] end -- the call is experimental
+local function value_u(t,key) return t[1] end -- the call is experimental
+local function value_n(t,key) return t[1] end -- the call is experimental
+local function value_c(t) return sub(t[1],2) end -- the call is experimental
+local function value_d(t) return tostring_d(t,true,key) end -- the call is experimental
+local function value_a(t) return tostring_a(t,true,key) end -- the call is experimental
+local function value_z() return nil end -- the call is experimental
+local function value_t(t) return t.value or true end -- the call is experimental
+local function value_f(t) return t.value or false end -- the call is experimental
+local function value_r() return t[1] end -- the call is experimental
+local function value_v() return t[1] end -- the call is experimental
+
+local function add_x(t,k,v) rawset(t,k,tostring(v)) end
+
+local mt_x = { __lpdftype = "stream", __tostring = tostring_x, __call = value_x, __newindex = add_x }
+local mt_d = { __lpdftype = "dictionary", __tostring = tostring_d, __call = value_d }
+local mt_a = { __lpdftype = "array", __tostring = tostring_a, __call = value_a }
+local mt_u = { __lpdftype = "unicode", __tostring = tostring_u, __call = value_u }
+local mt_s = { __lpdftype = "string", __tostring = tostring_s, __call = value_s }
+local mt_n = { __lpdftype = "number", __tostring = tostring_n, __call = value_n }
+local mt_c = { __lpdftype = "constant", __tostring = tostring_c, __call = value_c }
+local mt_z = { __lpdftype = "null", __tostring = tostring_z, __call = value_z }
+local mt_t = { __lpdftype = "true", __tostring = tostring_t, __call = value_t }
+local mt_f = { __lpdftype = "false", __tostring = tostring_f, __call = value_f }
+local mt_r = { __lpdftype = "reference", __tostring = tostring_r, __call = value_r }
+local mt_v = { __lpdftype = "verbose", __tostring = tostring_v, __call = value_v }
+
+local function pdfstream(t) -- we need to add attrbutes
+ if t then
+ for i=1,#t do
+ t[i] = tostring(t[i])
+ end
+ end
+ return setmetatable(t or { },mt_x)
+end
+
+local function pdfdictionary(t)
+ return setmetatable(t or { },mt_d)
+end
+
+local function pdfarray(t)
+ if type(t) == "string" then
+ return setmetatable({ t },mt_a)
+ else
+ return setmetatable(t or { },mt_a)
+ end
+end
+
+local function pdfstring(str,default)
+ return setmetatable({ str or default or "" },mt_s)
+end
+
+local function pdfunicode(str,default)
+ return setmetatable({ str or default or "" },mt_u)
+end
+
+local cache = { } -- can be weak
+
+local function pdfnumber(n,default) -- 0-10
+ n = n or default
+ local c = cache[n]
+ if not c then
+ c = setmetatable({ n },mt_n)
+ -- cache[n] = c -- too many numbers
+ end
+ return c
+end
+
+for i=-1,9 do cache[i] = pdfnumber(i) end
+
+local cache = { } -- can be weak
+
+local forbidden, replacements = "\0\t\n\r\f ()[]{}/%%#\\", { } -- table faster than function
+
+for s in gmatch(forbidden,".") do
+ replacements[s] = format("#%02x",byte(s))
+end
+
+local escaped = lpeg.Cs(lpeg.Cc("/") * (lpeg.S(forbidden)/replacements + lpeg.P(1))^0)
+
+local function pdfconstant(str,default)
+ str = str or default or ""
+ local c = cache[str]
+ if not c then
+ -- c = setmetatable({ "/" .. str },mt_c)
+ c = setmetatable({ lpegmatch(escaped,str) },mt_c)
+ cache[str] = c
+ end
+ return c
+end
+
+local p_null = { } setmetatable(p_null, mt_z)
+local p_true = { } setmetatable(p_true, mt_t)
+local p_false = { } setmetatable(p_false,mt_f)
+
+local function pdfnull()
+ return p_null
+end
+
+--~ print(pdfboolean(false),pdfboolean(false,false),pdfboolean(false,true))
+--~ print(pdfboolean(true),pdfboolean(true,false),pdfboolean(true,true))
+--~ print(pdfboolean(nil,true),pdfboolean(nil,false))
+
+local function pdfboolean(b,default)
+ if type(b) == "boolean" then
+ return b and p_true or p_false
+ else
+ return default and p_true or p_false
+ end
+end
+
+local function pdfreference(r)
+ return setmetatable({ r or 0 },mt_r)
+end
+
+local function pdfverbose(t) -- maybe check for type
+ return setmetatable({ t or "" },mt_v)
+end
+
+lpdf.stream = pdfstream
+lpdf.dictionary = pdfdictionary
+lpdf.array = pdfarray
+lpdf.string = pdfstring
+lpdf.unicode = pdfunicode
+lpdf.number = pdfnumber
+lpdf.constant = pdfconstant
+lpdf.null = pdfnull
+lpdf.boolean = pdfboolean
+lpdf.reference = pdfreference
+lpdf.verbose = pdfverbose
+
+-- n = pdf.obj(n, str)
+-- n = pdf.obj(n, "file", filename)
+-- n = pdf.obj(n, "stream", streamtext, attrtext)
+-- n = pdf.obj(n, "streamfile", filename, attrtext)
+
+-- we only use immediate objects
+
+-- todo: tracing
+
+local names, cache = { }, { }
+
+function lpdf.reserveobject(name)
+ local r = pdfreserveobj()
+ if name then
+ names[name] = r
+ if trace_objects then
+ logs.report("backends", "reserving object number %s under name '%s'",r,name)
+ end
+ elseif trace_objects then
+ logs.report("backends", "reserving object number %s",r)
+ end
+ return r
+end
+
+--~ local pdfreserveobject = lpdf.reserveobject
+
+function lpdf.flushobject(name,data)
+ if data then
+ name = names[name] or name
+ if name then
+ if trace_objects then
+ if trace_detail then
+ logs.report("backends", "flushing object data to reserved object with name '%s' -> %s",name,tostring(data))
+ else
+ logs.report("backends", "flushing object data to reserved object with name '%s'",name)
+ end
+ end
+ return pdfimmediateobj(name,tostring(data))
+ else
+ if trace_objects then
+ if trace_detail then
+ logs.report("backends", "flushing object data to reserved object with number %s -> %s",name,tostring(data))
+ else
+ logs.report("backends", "flushing object data to reserved object with number %s",name)
+ end
+ end
+ return pdfimmediateobj(tostring(data))
+ end
+ else
+ if trace_objects and trace_detail then
+ logs.report("backends", "flushing object data -> %s",tostring(name))
+ end
+ return pdfimmediateobj(tostring(name))
+ end
+end
+
+function lpdf.sharedobj(content)
+ local r = cache[content]
+ if not r then
+ r = pdfreference(pdfimmediateobj(content))
+ cache[content] = r
+ end
+ return r
+end
+
+--~ local d = lpdf.dictionary()
+--~ local e = lpdf.dictionary { ["e"] = "abc", x = lpdf.dictionary { ["f"] = "ABC" } }
+--~ local f = lpdf.dictionary { ["f"] = "ABC" }
+--~ local a = lpdf.array { lpdf.array { lpdf.string("xxx") } }
+
+--~ print(a)
+--~ os.exit()
+
+--~ d["test"] = lpdf.string ("test")
+--~ d["more"] = "more"
+--~ d["bool"] = true
+--~ d["numb"] = 1234
+--~ d["oeps"] = lpdf.dictionary { ["hans"] = "ton" }
+--~ d["whow"] = lpdf.array { lpdf.string("ton") }
+
+--~ a[#a+1] = lpdf.string("xxx")
+--~ a[#a+1] = lpdf.string("yyy")
+
+--~ d.what = a
+
+--~ print(e)
+
+--~ local d = lpdf.dictionary()
+--~ d["abcd"] = { 1, 2, 3, "test" }
+--~ print(d)
+--~ print(d())
+
+--~ local d = lpdf.array()
+--~ d[#d+1] = 1
+--~ d[#d+1] = 2
+--~ d[#d+1] = 3
+--~ d[#d+1] = "test"
+--~ print(d)
+
+--~ local d = lpdf.array()
+--~ d[#d+1] = { 1, 2, 3, "test" }
+--~ print(d)
+
+--~ local d = lpdf.array()
+--~ d[#d+1] = { a=1, b=2, c=3, d="test" }
+--~ print(d)
+
+--~ local s = lpdf.constant("xx")
+--~ print(s) -- fails somehow
+--~ print(s()) -- fails somehow
+
+--~ local s = lpdf.boolean(false)
+--~ s.value = true
+--~ print(s)
+--~ print(s())
+
+-- three priority levels, default=2
+
+local pagefinalizers, documentfinalizers = { { }, { }, { } }, { { }, { }, { } }
+
+local pageresources, pageattributes, pagesattributes
+
+local function resetpageproperties()
+ pageresources = pdfdictionary()
+ pageattributes = pdfdictionary()
+ pagesattributes = pdfdictionary()
+end
+
+local function setpageproperties()
+--~ texset("global", "pdfpageresources", pageresources ())
+--~ texset("global", "pdfpageattr", pageattributes ())
+--~ texset("global", "pdfpagesattr", pagesattributes())
+ pdf.pageresources = pageresources ()
+ pdf.pageattributes = pageattributes ()
+ pdf.pagesattributes = pagesattributes()
+end
+
+function lpdf.addtopageresources (k,v) pageresources [k] = v end
+function lpdf.addtopageattributes (k,v) pageattributes [k] = v end
+function lpdf.addtopagesattributes(k,v) pagesattributes[k] = v end
+
+local function set(where,f,when,what)
+ when = when or 2
+ local w = where[when]
+ w[#w+1] = f
+ if trace_finalizers then
+ logs.report("backend","%s set: [%s,%s]",what,when,#w)
+ end
+end
+
+local function run(where,what)
+ for i=1,#where do
+ local w = where[i]
+ for j=1,#w do
+ if trace_finalizers then
+ logs.report("backend","%s finalizer: [%s,%s]",what,i,j)
+ end
+ w[j]()
+ end
+ end
+end
+
+function lpdf.registerpagefinalizer(f,when)
+ set(pagefinalizers,f,when,"page")
+end
+
+function lpdf.registerdocumentfinalizer(f,when)
+ set(documentfinalizers,f,when,"document")
+end
+
+function lpdf.finalizepage()
+ if not environment.initex then
+ resetpageproperties()
+ run(pagefinalizers,"page")
+ setpageproperties()
+ end
+end
+
+function lpdf.finalizedocument()
+ if not environment.initex then
+ run(documentfinalizers,"document")
+ function lpdf.finalizedocument()
+ logs.report("backend","serious error: the document is finalized multiple times")
+ function lpdf.finalizedocument() end
+ end
+ end
+end
+
+-- some minimal tracing, handy for checking the order
+
+local function trace_set(what,key)
+ if trace_resources then
+ logs.report("backend", "setting key '%s' in '%s'",key,what)
+ end
+end
+local function trace_flush(what)
+ if trace_resources then
+ logs.report("backend", "flushing '%s'",what)
+ end
+end
+
+lpdf.protectresources = true
+
+local catalog, info, names = pdfdictionary(), pdfdictionary(), pdfdictionary()
+
+local function flushcatalog() if not environment.initex then trace_flush("catalog") pdf.catalog = catalog() end end
+local function flushinfo () if not environment.initex then trace_flush("info") pdf.info = info () end end
+local function flushnames () if not environment.initex then trace_flush("names") pdf.names = names () end end
+
+function lpdf.addtocatalog(k,v) if not (lpdf.protectresources and catalog[k]) then trace_set("catalog",k) catalog[k] = v end end
+function lpdf.addtoinfo (k,v) if not (lpdf.protectresources and info [k]) then trace_set("info", k) info [k] = v end end
+function lpdf.addtonames (k,v) if not (lpdf.protectresources and names [k]) then trace_set("names", k) names [k] = v end end
+
+local dummy = pdfreserveobj() -- else bug in hvmd due so some internal luatex conflict
+
+local r_extgstates, d_extgstates = pdfreserveobj(), pdfdictionary() local p_extgstates = pdfreference(r_extgstates)
+local r_colorspaces, d_colorspaces = pdfreserveobj(), pdfdictionary() local p_colorspaces = pdfreference(r_colorspaces)
+local r_patterns, d_patterns = pdfreserveobj(), pdfdictionary() local p_patterns = pdfreference(r_patterns)
+local r_shades, d_shades = pdfreserveobj(), pdfdictionary() local p_shades = pdfreference(r_shades)
+
+local function checkextgstates () if next(d_extgstates ) then lpdf.addtopageresources("ExtGState", p_extgstates ) end end
+local function checkcolorspaces() if next(d_colorspaces) then lpdf.addtopageresources("ColorSpace",p_colorspaces) end end
+local function checkpatterns () if next(d_patterns ) then lpdf.addtopageresources("Pattern", p_patterns ) end end
+local function checkshades () if next(d_shades ) then lpdf.addtopageresources("Shading", p_shades ) end end
+
+local function flushextgstates () if next(d_extgstates ) then trace_flush("extgstates") pdfimmediateobj(r_extgstates, tostring(d_extgstates )) end end
+local function flushcolorspaces() if next(d_colorspaces) then trace_flush("colorspaces") pdfimmediateobj(r_colorspaces,tostring(d_colorspaces)) end end
+local function flushpatterns () if next(d_patterns ) then trace_flush("patterns") pdfimmediateobj(r_patterns, tostring(d_patterns )) end end
+local function flushshades () if next(d_shades ) then trace_flush("shades") pdfimmediateobj(r_shades, tostring(d_shades )) end end
+
+local collected = pdfdictionary {
+ ExtGState = p_extgstates,
+ ColorSpace = p_colorspaces,
+ Pattern = p_patterns,
+ Shading = p_shades,
+} ; collected = collected()
+
+function lpdf.collectedresources()
+ tex.sprint(tex.ctxcatcodes,collected)
+end
+
+function lpdf.adddocumentextgstate (k,v) d_extgstates [k] = v end
+function lpdf.adddocumentcolorspace(k,v) d_colorspaces[k] = v end
+function lpdf.adddocumentpattern (k,v) d_patterns [k] = v end
+function lpdf.adddocumentshade (k,v) d_shades [k] = v end
+
+lpdf.registerdocumentfinalizer(flushextgstates,3)
+lpdf.registerdocumentfinalizer(flushcolorspaces,3)
+lpdf.registerdocumentfinalizer(flushpatterns,3)
+lpdf.registerdocumentfinalizer(flushshades,3)
+
+lpdf.registerdocumentfinalizer(flushcatalog,3)
+lpdf.registerdocumentfinalizer(flushinfo,3)
+lpdf.registerdocumentfinalizer(flushnames,3)
+
+lpdf.registerpagefinalizer(checkextgstates,3)
+lpdf.registerpagefinalizer(checkcolorspaces,3)
+lpdf.registerpagefinalizer(checkpatterns,3)
+lpdf.registerpagefinalizer(checkshades,3)
+
+-- in strc-bkm: lpdf.registerdocumentfinalizer(function() structure.bookmarks.place() end,1)
+
+function lpdf.rotationcm(a)
+ local s, c = sind(a), cosd(a)
+ texwrite(format("%s %s %s %s 0 0 cm",c,s,-s,c))
+end
+
+-- ! -> universaltime
+
+local timestamp = os.date("%Y-%m-%dT%X") .. os.timezone(true)
+
+function lpdf.timestamp()
+ return timestamp
+end
+
+function lpdf.pdftimestamp(str)
+ local Y, M, D, h, m, s, Zs, Zh, Zm = match(str,"^(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)([%+%-])(%d%d):(%d%d)$")
+ return Y and format("D:%s%s%s%s%s%s%s%s'%s'",Y,M,D,h,m,s,Zs,Zh,Zm)
+end
+
+function lpdf.id()
+ return format("%s.%s",tex.jobname,timestamp)
+end
+
+function lpdf.checkedkey(t,key,kind)
+ local pn = t[key]
+ if pn then
+ local tn = type(pn)
+ if tn == kind then
+ if kind == "string" then
+ return pn ~= "" and pn
+ elseif kind == "table" then
+ return next(pn) and pn
+ else
+ return pn
+ end
+ elseif tn == "string" and kind == "number" then
+ return tonumber(pn)
+ end
+ end
+end
+
+function lpdf.checkedvalue(value,kind) -- code not shared
+ if value then
+ local tv = type(value)
+ if tv == kind then
+ if kind == "string" then
+ return value ~= "" and value
+ elseif kind == "table" then
+ return next(value) and value
+ else
+ return value
+ end
+ elseif tv == "string" and kind == "number" then
+ return tonumber(value)
+ end
+ end
+end
+
+function lpdf.limited(n,min,max,default)
+ if not n then
+ return default
+ else
+ n = tonumber(n)
+ if not n then
+ return default
+ elseif n > max then
+ return max
+ elseif n < min then
+ return min
+ else
+ return n
+ end
+ end
+end
+
+-- lpdf.addtoinfo("ConTeXt.Version", tex.contextversiontoks)
+-- lpdf.addtoinfo("ConTeXt.Time", os.date("%Y.%m.%d %H:%M")) -- :%S
+-- lpdf.addtoinfo("ConTeXt.Jobname", tex.jobname)
+-- lpdf.addtoinfo("ConTeXt.Url", "www.pragma-ade.com")
+
+-- saves definitions later on
+
+backends = backends or { }
+backends.pdf = backends.pdf or {
+ comment = "backend for directly generating pdf output",
+ nodeinjections = { },
+ codeinjections = { },
+ registrations = { },
+ helpers = { },
+}
diff --git a/tex/context/base/lpdf-ini.mkiv b/tex/context/base/lpdf-ini.mkiv
new file mode 100644
index 000000000..7c7dce3ef
--- /dev/null
+++ b/tex/context/base/lpdf-ini.mkiv
@@ -0,0 +1,271 @@
+%D \module
+%D [ file=lpdf-ini,
+%D version=2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=PDF,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Backend Macros / PDF}
+
+\registerctxluafile{lpdf-ini}{1.001}
+\registerctxluafile{lpdf-xmp}{1.001}
+\registerctxluafile{lpdf-nod}{1.001}
+%registerctxluafile{lpdf-col}{1.001} % will be loaded later
+\registerctxluafile{lpdf-mis}{1.001}
+\registerctxluafile{lpdf-ano}{1.001}
+\registerctxluafile{lpdf-ren}{1.001}
+\registerctxluafile{lpdf-grp}{1.001}
+\registerctxluafile{lpdf-wid}{1.001}
+\registerctxluafile{lpdf-fld}{1.001}
+\registerctxluafile{lpdf-u3d}{1.001}
+\registerctxluafile{lpdf-swf}{1.001}
+
+\unprotect
+
+% for the moment here
+
+%D \macros
+%D {doovalbox}
+%D
+%D Drawing frames with round corners is inherited from the
+%D main module.
+%D
+%D For drawing ovals we use quite raw \PDF\ code. The next
+%D implementation does not differ that much from the one
+%D implemented in the \POSTSCRIPT\ driver. This code is
+%D somewhat obsolete as we now have metapost embedded.
+
+\def\doPDFovalcalc#1#2#3%
+ {\PointsToBigPoints{\dimexpr#1+#2\relax}#3}
+
+\def\doovalbox#1#2#3#4#5#6#7#8% todo: \scratchdimen/\scatchbox
+ {\forcecolorhack
+ \bgroup
+ \dimen0=#4\divide\dimen0 \plustwo
+ \doPDFovalcalc{0pt}{+\dimen0}\xmin
+ \doPDFovalcalc{#1}{-\dimen0}\xmax
+ \doPDFovalcalc{#2}{-\dimen0}\ymax
+ \doPDFovalcalc{-#3}{+\dimen0}\ymin
+ \advance\dimen0 by #5%
+ \doPDFovalcalc{0pt}{+\dimen0}\xxmin
+ \doPDFovalcalc{#1}{-\dimen0}\xxmax
+ \doPDFovalcalc{#2}{-\dimen0}\yymax
+ \doPDFovalcalc{-#3}{+\dimen0}\yymin
+ \doPDFovalcalc{#4}{\zeropoint}\stroke
+ \doPDFovalcalc{#5}{\zeropoint}\radius
+ \edef\dostroke{#6}%
+ \edef\dofill{#7}%
+ \edef\mode{\number#8 \space}%
+ % no \ifcase, else \relax in pdfcode
+ \setbox\scratchbox\hbox
+ {\ifnum\dostroke\dofill>\zerocount
+ \pdfliteral
+ {q
+ \stroke\space w
+ \ifcase\mode
+ \xxmin\space \ymin \space m
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax\space \ymax \space y
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ h
+ \or % 1
+ \xxmin\space \ymin \space m
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \ymax \space l
+ \xmin \space \ymax \space l
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ h
+ \or % 2
+ \xxmin\space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \ymax \space l
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ h
+ \or % 3
+ \xmin \space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax\space \ymax \space y
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \ymin \space l
+ h
+ \or % 4
+ \xmin \space \ymin \space m
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax\space \ymax \space y
+ \xmin \space \ymax \space l
+ \xmin \space \ymin\space l
+ h
+ \or % 5
+ \xmin \space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax\space \ymax \space y
+ \xmin \space \ymax \space l
+ \xmin \space \ymin \space l
+ h
+ \or % 6
+ \xmin \space \ymin \space m
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \ymax \space l
+ \xmin \space \ymax \space l
+ \xmin \space \ymin \space l
+ h
+ \or
+ \xxmin\space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \ymax \space l
+ \xmin \space \ymax \space l
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ h
+ \or
+ \xmin \space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \ymax \space l
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \ymin \space l
+ h
+ \or % 9 top open
+ \xmin \space \ymax \space m
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \ymax \space l
+ \or % 10 right open
+ \xmax \space \ymax \space m
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ \xmax\space \ymin \space l
+ \or % 11 bottom open
+ \xmax \space \ymin \space m
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax \space \ymax\space y
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \ymin \space l
+ \or % 12 left open
+ \xmin \space \ymax \space m
+ \xxmax\space \ymax \space l
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmax \space \yymin\space l
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xmin \space \ymin \space l
+ \or % 13
+ \xmin \space \ymax \space m
+ \xxmax\space \ymax \space l
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmax\space \ymin \space l
+ \or % 14
+ \xmax \space \ymax \space m
+ \xmax \space \yymin\space l
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xmin \space \ymin \space l
+ \or % 15
+ \xmax \space \ymin \space m
+ \xxmin\space \ymin \space l
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \xmin \space \ymax \space l
+ \or % 16
+ \xmin \space \ymin \space m
+ \xmin \space \yymax\space l
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \xmax \space \ymax \space l
+ \or % 17
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \or % 18
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \or % 19
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \or % 20
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 21
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 22
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \or % 23
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \or % 24
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 25
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 26
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 27
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \or % 28
+ \fi
+ \ifnum\mode>8
+ S
+ \else
+ \ifnum\dostroke=\plusone S \fi
+ \ifnum\dofill =\plusone f \fi
+ \fi
+ Q}%
+ \fi}%
+ \wd\scratchbox#1\ht\scratchbox#2\dp\scratchbox#3\box\scratchbox
+ \egroup}
+
+\unexpanded\def\pdfactualtext#1#2%
+ {\pdfliteral direct{/Span <> BDC}%
+ #1%
+ \pdfliteral direct{EMC}}
+
+% \starttext
+% text \pdfactualtext{Meier}{Müller} text
+% \stoptext
+
+\protect \endinput
diff --git a/tex/context/base/lpdf-mis.lua b/tex/context/base/lpdf-mis.lua
new file mode 100644
index 000000000..a68c7b487
--- /dev/null
+++ b/tex/context/base/lpdf-mis.lua
@@ -0,0 +1,292 @@
+if not modules then modules = { } end modules ['lpdf-mis'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Although we moved most pdf handling to the lua end, we didn't change
+-- the overall approach. For instance we share all resources i.e. we
+-- don't make subsets for each xform or page. The current approach is
+-- quite efficient. A big difference between MkII and MkIV is that we
+-- now use forward references. In this respect the MkII code shows that
+-- it evolved over a long period, when backends didn't provide forward
+-- referencing and references had to be tracked in multiple passes. Of
+-- course there are a couple of more changes.
+
+local next, tostring = next, tostring
+local format = string.format
+local texsprint, texset = tex.sprint, tex.set
+local ctxcatcodes = tex.ctxcatcodes
+
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
+
+local copy_node = node.copy
+
+local pdfliteral, register = nodes.pdfliteral, nodes.register
+
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfboolean = lpdf.boolean
+local pdfconstant = lpdf.constant
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfverbose = lpdf.verbose
+local pdfstring = lpdf.string
+local pdfflushobject = lpdf.flushobject
+
+local pdfimmediateobj = pdf.immediateobj
+
+local tobasepoints = number.tobasepoints
+local variables = interfaces.variables
+
+--
+
+local positive = register(pdfliteral("/GSpositive gs"))
+local negative = register(pdfliteral("/GSnegative gs"))
+local overprint = register(pdfliteral("/GSoverprint gs"))
+local knockout = register(pdfliteral("/GSknockout gs"))
+
+local function initializenegative()
+ local a = pdfarray { 0, 1 }
+ local g = pdfconstant("ExtGState")
+ local d = pdfdictionary {
+ FunctionType = 4,
+ Range = a,
+ Domain = a,
+ }
+ local negative = pdfdictionary { Type = g, TR = pdfreference(pdf.immediateobj("stream","1 exch sub",d())) }
+ local positive = pdfdictionary { Type = g, TR = pdfconstant("Identity") }
+ lpdf.adddocumentextgstate("GSnegative", pdfreference(pdfflushobject(negative)))
+ lpdf.adddocumentextgstate("GSPositive", pdfreference(pdfflushobject(positive)))
+ initializenegative = nil
+end
+
+local function initializeoverprint()
+ local g = pdfconstant("ExtGState")
+ local knockout = pdfdictionary { Type = g, OP = false, OPM = 0 }
+ local overprint = pdfdictionary { Type = g, OP = true, OPM = 1 }
+ lpdf.adddocumentextgstate("GSknockout", pdfreference(pdfflushobject(knockout)))
+ lpdf.adddocumentextgstate("GSoverprint", pdfreference(pdfflushobject(overprint)))
+ initializeoverprint = nil
+end
+
+function nodeinjections.overprint()
+ if initializeoverprint then initializeoverprint() end
+ return copy_node(overprint)
+end
+function nodeinjections.knockout ()
+ if initializeoverprint then initializeoverprint() end
+ return copy_node(knockout)
+end
+
+function nodeinjections.positive()
+ if initializenegative then initializenegative() end
+ return copy_node(positive)
+end
+function nodeinjections.negative()
+ if initializenegative then initializenegative() end
+ return copy_node(negative)
+end
+
+--
+
+function codeinjections.addtransparencygroup()
+ -- png: /CS /DeviceRGB /I true
+ local d = pdfdictionary {
+ S = pdfconstant("Transparency"),
+ I = true,
+ K = true,
+ }
+ lpdf.registerpagefinalizer(function() lpdf.addtopageattributes("Group",d) end) -- hm
+end
+
+-- actions (todo: store and update when changed)
+
+local openpage, closepage, opendocument, closedocument
+
+function codeinjections.flushdocumentactions(open,close)
+ opendocument, closedocument = open, close
+end
+
+function codeinjections.flushpageactions(open,close)
+ openpage, closepage = open, close
+end
+
+local function flushdocumentactions()
+ if opendocument then
+ lpdf.addtocatalog("OpenAction",lpdf.pdfaction(opendocument))
+ end
+ if closedocument then
+ lpdf.addtocatalog("CloseAction",lpdf.pdfaction(closedocument))
+ end
+end
+
+local function flushpageactions()
+ if openpage or closepage then
+ local d = pdfdictionary()
+ if openpage then
+ d.O = lpdf.pdfaction(openpage)
+ end
+ if closepage then
+ d.C = lpdf.pdfaction(closepage)
+ end
+ lpdf.addtopageattributes("AA",d)
+ end
+end
+
+lpdf.registerpagefinalizer(flushpageactions)
+lpdf.registerdocumentfinalizer(flushdocumentactions)
+
+--- info
+
+function codeinjections.setupidentity(specification)
+ local title = specification.title or ""
+ if title ~= "" then
+ lpdf.addtoinfo("Title", pdfunicode(title), title)
+ end
+ local subject = specification.subject or ""
+ if subject ~= "" then
+ lpdf.addtoinfo("Subject", pdfunicode(subject), subject)
+ end
+ local author = specification.author or ""
+ if author ~= "" then
+ lpdf.addtoinfo("Author", pdfunicode(author), author) -- '/Author' in /Info, 'Creator' in XMP
+ end
+ local creator = specification.creator or ""
+ if creator ~= "" then
+ lpdf.addtoinfo("Creator", pdfunicode(creator), creator) -- '/Creator' in /Info, 'CreatorTool' in XMP
+ end
+ lpdf.addtoinfo("CreationDate", pdfstring(lpdf.pdftimestamp(lpdf.timestamp())))
+ local date = specification.date or ""
+ local pdfdate = lpdf.pdftimestamp(date)
+ if pdfdate then
+ lpdf.addtoinfo("ModDate", pdfstring(pdfdate), date)
+ else
+ -- users should enter the date in 2010-01-19T23:27:50+01:00 format
+ -- and if not provided that way we use the creation time instead
+ date = lpdf.timestamp()
+ lpdf.addtoinfo("ModDate", pdfstring(lpdf.pdftimestamp(date)), date)
+ end
+ local keywords = specification.keywords or ""
+ if keywords ~= "" then
+ keywords = string.gsub(keywords, "[%s,]+", " ")
+ lpdf.addtoinfo("Keywords",pdfunicode(keywords), keywords)
+ end
+ local id = lpdf.id()
+ lpdf.addtoinfo("ID", pdfstring(id), id) -- needed for pdf/x
+end
+
+local function flushjavascripts()
+ local t = javascripts.flushpreambles()
+ if #t > 0 then
+ local a = pdfarray()
+ local pdf_javascript = pdfconstant("JavaScript")
+ for i=1,#t do
+ local name, script = t[i][1], t[i][2]
+ local j = pdfdictionary {
+ S = pdf_javascript,
+ JS = pdfreference(pdfimmediateobj("stream",script)),
+ }
+ a[#a+1] = pdfstring(name)
+ a[#a+1] = pdfreference(pdfflushobject(j))
+ end
+ lpdf.addtonames("JavaScript",pdfreference(pdfflushobject(pdfdictionary{ Names = a })))
+ end
+end
+
+lpdf.registerdocumentfinalizer(flushjavascripts)
+
+-- -- --
+
+local pagespecs = {
+ [variables.max] = { "FullScreen", false, false },
+ [variables.bookmark] = { "UseOutlines", false, false },
+ [variables.fit] = { "UseNone", false, true },
+ [variables.doublesided] = { "UseNone", "TwoColumnRight", true },
+ [variables.singlesided] = { "UseNone", false, false },
+ [variables.default] = { "UseNone", "auto", false },
+ [variables.auto] = { "UseNone", "auto", false },
+ [variables.none] = { false, false, false },
+}
+
+local pagespec, topoffset, leftoffset, height, width, doublesided = "default", 0, 0, 0, 0, false
+
+function codeinjections.setupcanvas(specification)
+ local paperheight = specification.paperheight
+ local paperwidth = specification.paperwidth
+ local paperdouble = specification.doublesided
+ if paperheight then
+ texset('global','pdfpageheight',paperheight)
+ end
+ if paperwidth then
+ texset('global','pdfpagewidth',paperwidth)
+ end
+ pagespec = specification.mode or pagespec
+ topoffset = specification.topoffset or 0
+ leftoffset = specification.leftoffset or 0
+ height = specification.height or tex.pdfpageheight
+ width = specification.width or tex.pdfpagewidth
+ if paperdouble ~= nil then
+ doublesided = paperdouble
+ end
+end
+
+local function documentspecification()
+ local spec = pagespecs[pagespec] or pagespecs[variables.default]
+ if spec then
+ local mode, layout, fit = spec[1], spec[2], spec[3]
+ if layout == variables.auto then
+ if doublesided then
+ spec = pagespecs[variables.doublesided] -- to be checked voor interfaces
+ if spec then
+ mode, layout, fit = spec[1], spec[2], spec[3]
+ end
+ else
+ layout = false
+ end
+ end
+ mode = mode and pdfconstant(mode)
+ layout = layout and pdfconstant(layout)
+ fit = fit and pdfdictionary { FitWindow = true }
+ if layout then
+ lpdf.addtocatalog("PageLayout",layout)
+ end
+ if mode then
+ lpdf.addtocatalog("PageMode",mode)
+ end
+ if fit then
+ lpdf.addtocatalog("ViewerPreferences",fit)
+ end
+ lpdf.addtoinfo ("Trapped", pdfconstant("False")) -- '/Trapped' in /Info, 'Trapped' in XMP
+ lpdf.addtocatalog("Version", pdfconstant(format("1.%s",tex.pdfminorversion)))
+ end
+end
+
+-- temp hack: the mediabox is not under our control and has a precision of 4 digits
+
+local factor = number.dimenfactors.bp
+
+local function boxvalue(n) -- we could share them
+ return pdfverbose(format("%0.4f",factor * n))
+end
+
+local function pagespecification()
+ local pageheight = tex.pdfpageheight
+ local box = pdfarray { -- can be cached
+ boxvalue(leftoffset),
+ boxvalue(pageheight-topoffset-height),
+ boxvalue(width-leftoffset),
+ boxvalue(pageheight-topoffset),
+ }
+ lpdf.addtopageattributes("CropBox",box) -- mandate for rendering
+ lpdf.addtopageattributes("TrimBox",box) -- mandate for pdf/x
+ -- lpdf.addtopageattributes("BleedBox",box)
+ -- lpdf.addtopageattributes("ArtBox",box)
+end
+
+lpdf.registerpagefinalizer(pagespecification)
+lpdf.registerdocumentfinalizer(documentspecification)
diff --git a/tex/context/base/lpdf-nod.lua b/tex/context/base/lpdf-nod.lua
new file mode 100644
index 000000000..0ae900123
--- /dev/null
+++ b/tex/context/base/lpdf-nod.lua
@@ -0,0 +1,53 @@
+if not modules then modules = { } end modules ['lpdf-nod'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local copy_node, new_node = node.copy, node.new
+
+local pdfliteral = nodes.register(new_node("whatsit", 8)) pdfliteral.mode = 1
+local pdfdest = nodes.register(new_node("whatsit",19)) pdfdest.named_id = 1 -- xyz_zoom untouched
+local pdfannot = nodes.register(new_node("whatsit",15))
+
+local variables = interfaces.variables
+
+local views = { -- beware, we do support the pdf keys but this is *not* official
+ xyz = 0, [variables.standard] = 0,
+ fit = 1, [variables.fit] = 1,
+ fith = 2, [variables.width] = 2,
+ fitv = 3, [variables.height] = 3,
+ fitb = 4,
+ fitbh = 5, [variables.minwidth] = 5,
+ fitbv = 6, [variables.minheight] = 6,
+ fitr = 7,
+}
+
+function nodes.pdfliteral(str)
+ local t = copy_node(pdfliteral)
+ t.data = str
+ return t
+end
+
+function nodes.pdfannotation(w,h,d,data,n)
+ local t = copy_node(pdfannot)
+ if w and w ~= 0 then t.width = w end
+ if h and h ~= 0 then t.height = h end
+ if d and d ~= 0 then t.depth = d end
+ if n then t.objnum = n end
+ if data and data ~= "" then t.data = data end
+ return t
+end
+
+function nodes.pdfdestination(w,h,d,name,view,n)
+ local t = copy_node(pdfdest)
+ if w and w ~= 0 then t.width = w end
+ if h and h ~= 0 then t.height = h end
+ if d and d ~= 0 then t.depth = d end
+ if n then t.objnum = n end
+ t.dest_id = name
+ t.dest_type = views[view] or view or 1 -- fit is default
+ return t
+end
diff --git a/tex/context/base/lpdf-pdx.lua b/tex/context/base/lpdf-pdx.lua
new file mode 100644
index 000000000..0a440c1e6
--- /dev/null
+++ b/tex/context/base/lpdf-pdx.lua
@@ -0,0 +1,139 @@
+if not modules then modules = { } end modules ['lpdf-pdx'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Peter Rold and Hans Hagen",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local codeinjections = backends.codeinjections -- normally it is registered
+local variables = interfaces.variables
+
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfconstant = lpdf.constant
+local pdfreference = lpdf.reference
+local pdfflushobject = lpdf.flushobject
+local pdfstring = lpdf.string
+local pdfverbose = lpdf.verbose
+
+local lower, gmatch = string.lower, string.gmatch
+
+local channels = {
+ gray = 1,
+ grey = 1,
+ rgb = 3,
+ cmyk = 4,
+}
+
+local prefixes = {
+ gray = "DefaultGray",
+ grey = "DefaultGray",
+ rgb = "DefaultRGB",
+ cmyk = "DefaultCMYK",
+}
+
+local profiles = { }
+local defaults = { }
+local intents = pdfarray()
+local lastprofile = nil
+
+function codeinjections.useinternalICCprofile(colorspace,filename)
+ local name = lower(file.basename(filename))
+ local profile = profiles[name]
+ if not profile then
+ local colorspace = lower(colorspace)
+ local filename = resolvers.findctxfile(filename) or ""
+ local channel = channels[colorspace]
+ if channel and filename ~= "" then
+ local a = pdfdictionary { N = channel }
+ profile = pdf.obj {
+ compresslevel = 0,
+ immediate = true,
+ type = "stream",
+ file = filename,
+ attr = a(),
+ }
+ profiles[name] = profile
+ end
+ end
+ lastprofile = profile
+ return profile
+end
+
+function codeinjections.useexternalICCprofile(colorspace,name,urls,checksum,version)
+ local profile = profiles[name]
+ if not profile then
+ local u = pdfarray()
+ for url in gmatch(urls,"([^, ]+)") do
+ u[#u+1] = pdfdictionary {
+ FS = pdfconstant("URL"),
+ F = pdfstring(url),
+ }
+ end
+ local d = pdfdictionary {
+ ProfileName = name, -- not file name!
+ ProfileCS = colorspace,
+ URLs = u, -- array containing at least one URL
+ CheckSum = pdfverbose { "<", checksum, ">" }, -- 16byte MD5 hash
+ ICCVersion = pdfverbose { "<", version, ">" }, -- bytes 8..11 from the header of the ICC profile, as a hex string
+ }
+ local n = pdfflushobject(d)
+ profiles[name] = n
+ lastprofile = n
+ return n
+ end
+end
+
+local function embedprofile(colorspace,filename)
+ local colorspace = lower(colorspace)
+ local n = codeinjections.useinternaliccprofile(colorspace,filename)
+ if n then
+ local a = pdfarray {
+ pdfconstant("ICCBased"),
+ pdfreference(n),
+ }
+ lpdf.adddocumentcolorspace(prefixes[colorspace],pdfreference(pdfflushobject(a))) -- part of page /Resources
+ defaults[lower(colorspace)] = filename
+ end
+end
+
+
+function codeinjections.useICCdefaultprofile(colorspace,filename)
+ defaults[lower(colorspace)] = filename
+end
+
+local function flushembeddedprofiles()
+ for colorspace, filename in next, defaults do
+ embedprofile(colorspace,filename)
+ end
+end
+
+function codeinjections.usePDFXoutputintent(id,name,reference,outputcondition,info)
+ local d = {
+ Type = pdfconstant("OutputIntent"),
+ S = pdfconstant("GTS_PDFX"),
+ OutputConditionIdentifier = id,
+ RegistryName = name,
+ OutputCondition = outputcondition,
+ Info = info,
+ }
+ local icc = lastprofile
+ if reference == variables.yes then
+ d["DestOutputProfileRef"] = pdfreference(icc)
+ else
+ d["DestOutputProfile"] = pdfreference(icc)
+ end
+ -- intents[#intents+1] = pdfdictionary(d)
+ intents[#intents+1] = pdfreference(pdfflushobject(pdfdictionary(d))) -- nicer as separate object
+end
+
+local function flushoutputintents()
+ if #intents > 0 then
+ lpdf.addtocatalog("OutputIntents",pdfreference(pdfflushobject(intents)))
+ end
+end
+
+
+lpdf.registerdocumentfinalizer(flushoutputintents,1)
+lpdf.registerdocumentfinalizer(flushembeddedprofiles,1)
diff --git a/tex/context/base/lpdf-pdx.mkiv b/tex/context/base/lpdf-pdx.mkiv
new file mode 100644
index 000000000..ffb7f5269
--- /dev/null
+++ b/tex/context/base/lpdf-pdx.mkiv
@@ -0,0 +1,71 @@
+%D \module
+%D [ file=lpdf-pdx,
+%D version=2010.02.11,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=PDF-X,
+%D author=Peter Rolf \& Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA] % and peter
+%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 Backend Macros / PDF-X}
+
+\unprotect
+
+% declare default color space
+% all device based entries of the same CS are mapped to the defined ICCprofile then;
+% i.e. /DeviceRGB --> /ICCBased RGB profile
+% TODO: allow multiple default profiles (one per CS)
+%
+% external ICC profile dictionary (PDF/X-4p and PDF/X-5p)
+%
+% - ProfileName (not file name!)
+% - URLs (array containing at least one URL); the keyword FSA is wrong!
+% - CheckSum (16byte MD5 hash)
+% - ProfileCS (GRAY,RGB,CMYK)
+% - ICCVersion (bytes 8..11 from the header of the ICC profile, as a hex string)
+
+\registerctxluafile{lpdf-pdx} {}
+
+% \def\embedICCprofile#1#2% colorspace, name
+% {\ctxlua{backends.codeinjections.addiccprofile("#1","#2")}}
+
+\def\douseinternalICCprofile[#1]%
+ {\getparameters[\??ic][colorspace=,filename=,#1]%
+ \ctxlua{backends.codeinjections.useinternalICCprofile(
+ "\@@iccolorspace","\@@icfilename")}}
+
+% create a dictionary for an external ICC profile (PDF/X-4p and PDF/X-5pg only)
+% the referenced ICC profile is not embedded
+
+\def\douseexternalICCprofile[#1]%
+ {\getparameters[\??ic][colorspace=,name=,url=,checksum=,version=,#1]%
+ \ctxlua{backends.codeinjections.useexternalICCprofile(
+ "\@@iccolorspace","\@@icname","\@@icurl","\@@icchecksum","\@@icversion")}}
+
+% use an ICC profile as default colorspace for all device dependend colors;
+% all device based entries of the same CS are mapped to the defined ICCprofile then;
+% i.e. /DeviceRGB --> /ICCBased RGB profile always embed the profile!
+
+\def\douseICCdefaultprofile[#1]%
+ {\getparameters[\??ic][colorspace=,filename=,#1]%
+ \ctxlua{backends.codeinjections.useICCdefaultprofile(
+ "\@@iccolorspace","\@@icfilename")}}
+
+% embedding rules for output intent profile differ for the PDF/X versions
+
+\def\dousePDFXoutputintent[#1]%
+ {\getparameters[\??ic][reference=\v!yes,outputcondition=,info=,id=,name=,#1]%
+ \ctxlua{backends.codeinjections.usePDFXoutputintent(
+ "\@@icid","\@@icname","\@@icreference","\@@icoutputcondition","\@@icinfo")}}
+
+\def\useinternalICCprofile{\dosingleempty\douseinternalICCprofile}
+\def\useexternalICCprofile{\dosingleempty\douseexternalICCprofile}
+\def\useICCdefaultprofile {\dosingleempty\douseICCdefaultprofile }
+\def\usePDFXoutputintent {\dosingleempty\dousePDFXoutputintent }
+
+\protect \endinput
+
diff --git a/tex/context/base/lpdf-ren.lua b/tex/context/base/lpdf-ren.lua
new file mode 100644
index 000000000..e6bbd67fe
--- /dev/null
+++ b/tex/context/base/lpdf-ren.lua
@@ -0,0 +1,207 @@
+if not modules then modules = { } end modules ['lpdf-ren'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- rendering
+
+local tostring, tonumber, next = tostring, tonumber, next
+local format = string.format
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
+
+jobreferences = jobreferences or { }
+--~ jobreferences.runners = jobreferences.runners or { }
+--~ jobreferences.specials = jobreferences.specials or { }
+--~ jobreferences.handlers = jobreferences.handlers or { }
+jobreferences.executers = jobreferences.executers or { }
+
+--~ local runners = jobreferences.runners
+--~ local specials = jobreferences.specials
+--~ local handlers = jobreferences.handlers
+local executers = jobreferences.executers
+
+local variables = interfaces.variables
+
+local pdfconstant = lpdf.constant
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfflushobject = lpdf.flushobject
+
+local pdf_ocg = pdfconstant("OCG")
+local pdf_ocmd = pdfconstant("OCMD")
+local pdf_off = pdfconstant("OFF")
+local pdf_on = pdfconstant("ON")
+local pdf_toggle = pdfconstant("Toggle")
+local pdf_setocgstate = pdfconstant("SetOCGState")
+
+local lpdf_usage = pdfdictionary { Print = pdfdictionary { PrintState = pdfconstant("OFF") } }
+
+local pdfln, pdfld = { }, { }
+local textlayers, hidelayers, videlayers = pdfarray(), pdfarray(), pdfarray()
+local pagelayers = pdfdictionary()
+
+lpdf.layerreferences = pdfln
+
+function backends.pdf.layerreference(name)
+ return pdfln[name]
+end
+
+function codeinjections.defineviewerlayer(specification)
+ if textlayers then
+ local tag = specification.tag
+ -- todo: reserve
+ local n = pdfdictionary {
+ Type = pdf_ocg,
+ Name = specification.title or "unknown",
+ Intent = ((specification.kind > 0) and pdf_design) or nil, -- disable layer hiding by user
+ Usage = ((specification.printable == variables.no) and lpdf_usage) or nil , -- printable or not
+ }
+ local nr = pdfreference(pdfflushobject(n))
+ pdfln[tag] = nr -- was n
+ local d = pdfdictionary {
+ Type = pdf_ocmd,
+ OCGs = pdfarray { nr },
+ }
+ local dr = pdfreference(pdfflushobject(d))
+ pdfld[tag] = dr
+ textlayers[#textlayers+1] = nr
+ if specification.visible == variables.start then
+ videlayers[#videlayers+1] = nr
+ else
+ hidelayers[#hidelayers+1] = nr
+ end
+ pagelayers[tag] = dr -- check
+ end
+end
+
+local function flushtextlayers()
+ if textlayers and #textlayers > 0 then
+ local d = pdfdictionary {
+ OCGs = textlayers,
+ D = pdfdictionary {
+ Order = textlayers,
+ ON = videlayers,
+ OFF = hidelayers,
+ },
+ }
+ lpdf.addtocatalog("OCProperties",d)
+ textlayers = nil
+ end
+end
+
+local function flushpagelayers()
+ if next(pagelayers) then
+ lpdf.addtopageresources("Properties",pagelayers)
+ end
+end
+
+lpdf.registerpagefinalizer (flushpagelayers)
+lpdf.registerdocumentfinalizer(flushtextlayers)
+
+local function setlayer(what,arguments)
+ -- maybe just a gmatch of even better, earlier in lpeg
+ arguments = (type(arguments) == "table" and arguments) or aux.settings_to_array(arguments)
+ local state = pdfarray { what }
+ for i=1,#arguments do
+ local p = pdfln[arguments[i]]
+ if p then
+ state[#state+1] = p
+ end
+ end
+ return pdfdictionary {
+ S = pdf_setocgstate,
+ State = state,
+ }
+end
+
+function executers.hidelayer (arguments) setlayer(pdf_off, arguments) end
+function executers.videlayer (arguments) setlayer(pdf_on, arguments) end
+function executers.togglelayer(arguments) setlayer(pdf_toggle,arguments) end
+
+-- transitions
+
+local pagetransitions = {
+ {"split","in","vertical"}, {"split","in","horizontal"},
+ {"split","out","vertical"}, {"split","out","horizontal"},
+ {"blinds","horizontal"}, {"blinds","vertical"},
+ {"box","in"}, {"box","out"},
+ {"wipe","east"}, {"wipe","west"}, {"wipe","north"}, {"wipe","south"},
+ {"dissolve"},
+ {"glitter","east"}, {"glitter","south"},
+ {"fly","in","east"}, {"fly","in","west"}, {"fly","in","north"}, {"fly","in","south"},
+ {"fly","out","east"}, {"fly","out","west"}, {"fly","out","north"}, {"fly","out","south"},
+ {"push","east"}, {"push","west"}, {"push","north"}, {"push","south"},
+ {"cover","east"}, {"cover","west"}, {"cover","north"}, {"cover","south"},
+ {"uncover","east"}, {"uncover","west"}, {"uncover","north"}, {"uncover","south"},
+ {"fade"},
+}
+
+local mapping = {
+ split = { "S" , pdfconstant("Split") },
+ blinds = { "S" , pdfconstant("Blinds") },
+ box = { "S" , pdfconstant("Box") },
+ wipe = { "S" , pdfconstant("Wipe") },
+ dissolve = { "S" , pdfconstant("Dissolve") },
+ glitter = { "S" , pdfconstant("Glitter") },
+ replace = { "S" , pdfconstant("R") },
+ fly = { "S" , pdfconstant("Fly") },
+ push = { "S" , pdfconstant("Push") },
+ cover = { "S" , pdfconstant("Cover") },
+ uncover = { "S" , pdfconstant("Uncover") },
+ fade = { "S" , pdfconstant("Fade") },
+ horizontal = { "Dm" , pdfconstant("H") },
+ vertical = { "Dm" , pdfconstant("V") },
+ ["in"] = { "M" , pdfconstant("I") },
+ out = { "M" , pdfconstant("O") },
+ east = { "Di" , 0 },
+ north = { "Di" , 90 },
+ west = { "Di" , 180 },
+ south = { "Di" , 270 },
+}
+
+local last = 0
+
+-- n: number, "stop", "reset", "random", "a,b,c" delay: number, "none"
+
+function codeinjections.setpagetransition(specification)
+ local n, delay = specification.n, specification.delay
+ if n == variables.auto then
+ if last >= #pagetransitions then
+ last = 0
+ end
+ n = last + 1
+ elseif n == variables.stop then
+ return
+ elseif n == variables.reset then
+ last = 0
+ return
+ elseif n == variables.random then
+ n = math.random(1,#pagetransitions)
+ else
+ n = tonumber(n)
+ end
+ local t = n and pagetransitions[n] or pagetransitions[1]
+ if not t then
+ t = aux.settings_to_array(n)
+ end
+ if t and #t > 0 then
+ local d = pdfdictionary()
+ for i=1,#t do
+ local m = mapping[t[i]]
+ d[m[1]] = m[2]
+ end
+ delay = tonumber(delay)
+ if delay and delay > 0 then
+ lpdf.addtopageattributes("Dur",delay)
+ end
+ lpdf.addtopageattributes("Trans",d)
+ end
+end
diff --git a/tex/context/base/lpdf-swf.lua b/tex/context/base/lpdf-swf.lua
new file mode 100644
index 000000000..9fe0cd09f
--- /dev/null
+++ b/tex/context/base/lpdf-swf.lua
@@ -0,0 +1,109 @@
+if not modules then modules = { } end modules ['lpdf-swf'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- The following code is based on tests by Luigi Scarso. His prototype
+-- was using tex code. This is the official implementation.
+
+local format = string.format
+
+local pdfconstant = lpdf.constant
+local pdfboolean = lpdf.boolean
+local pdfstring = lpdf.string
+local pdfunicode = lpdf.unicode
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfnull = lpdf.null
+local pdfreference = lpdf.reference
+
+function backends.pdf.helpers.insertswf(spec)
+
+ local width, height, filename = spec.width, spec.height, spec.foundname
+
+ local eref = backends.codeinjections.embedfile(filename)
+
+ local flash = pdfdictionary {
+ Subtype = pdfconstant("Flash"),
+ Instances = pdfarray {
+ pdfdictionary {
+ Asset = eref,
+ Params = pdfdictionary {
+ Binding = pdfconstant("Foreground")
+ }
+ },
+ },
+ }
+
+ local fref = pdfreference(pdf.immediateobj(tostring(flash)))
+
+ local configuration = pdfdictionary {
+ Configurations = pdfarray { fref },
+ Assets = pdfdictionary {
+ Names = pdfarray {
+ pdfstring(filename),
+ eref,
+ }
+ },
+ }
+
+ local cref = pdfreference(pdf.immediateobj(tostring(configuration)))
+
+ local activation = pdfdictionary {
+ Activation = pdfdictionary {
+ Type = pdfconstant("RichMediaActivation"),
+ Condition = pdfconstant("PO"),
+ Configuration = fref,
+ Animation = pdfdictionary {
+ Subtype = pdfconstant("Linear"),
+ Speed = 1,
+ Playcount = 1,
+ },
+ Deactivation = pdfdictionary {
+ Type = pdfconstant("RichMediaDeactivation"),
+ Condition = pdfconstant("XD"),
+ },
+ Presentation = pdfdictionary {
+ PassContextClick = false,
+ Style = pdfconstant("Embedded"),
+ Toolbar = false,
+ NavigationPane = false,
+ Transparent = true,
+ Window = pdfdictionary {
+ Type = pdfconstant("RichMediaWindow"),
+ Width = pdfdictionary {
+ Default = 100,
+ Min = 100,
+ Max = 100,
+ },
+ Height = pdfdictionary {
+ Default = 100,
+ Min = 100,
+ Max = 100,
+ },
+ Position = pdfdictionary {
+ Type = pdfconstant("RichMediaPosition"),
+ HAlign = pdfconstant("Near"),
+ VAlign = pdfconstant("Near"),
+ HOffset = 0,
+ VOffset = 0,
+ }
+ }
+ }
+ }
+ }
+
+ local aref = pdfreference(pdf.immediateobj(tostring(activation)))
+
+ local annotation = pdfdictionary {
+ Subtype = pdfconstant("RichMedia"),
+ RichMediaContent = cref,
+ RichMediaSettings = aref,
+ }
+
+ return annotation, nil, nil
+
+end
diff --git a/tex/context/base/lpdf-u3d.lua b/tex/context/base/lpdf-u3d.lua
new file mode 100644
index 000000000..f7a62c6c9
--- /dev/null
+++ b/tex/context/base/lpdf-u3d.lua
@@ -0,0 +1,474 @@
+if not modules then modules = { } end modules ['lpdf-u3d'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- The following code is based on a working prototype provided
+-- by Michael Vidiassov. It is rewritten using the lpdf library
+-- and different checking is used. The macro calls are adapted
+-- (and will eventually be removed). The user interface needs
+-- an overhaul. There are some messy leftovers that will be
+-- removed in future versions.
+
+local format, find = string.format, string.find
+local cos, sin, sqrt, pi, atan2, abs = math.cos, math.sin, math.sqrt, math.pi, math.atan2, math.abs
+
+local pdfconstant = lpdf.constant
+local pdfboolean = lpdf.boolean
+local pdfnumber = lpdf.number
+local pdfunicode = lpdf.unicode
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfnull = lpdf.null
+local pdfreference = lpdf.reference
+
+local pdfimmediateobj = pdf.immediateobj
+
+local checkedkey = lpdf.checkedkey
+local limited = lpdf.limited
+
+local schemes = table.tohash {
+ "Artwork", "None", "White", "Day", "Night", "Hard",
+ "Primary", "Blue", "Red", "Cube", "CAD", "Headlamp",
+}
+
+local modes = table.tohash {
+ "Solid", "SolidWireframe", "Transparent", "TransparentWireframe", "BoundingBox",
+ "TransparentBoundingBox", "TransparentBoundingBoxOutline", "Wireframe",
+ "ShadedWireframe", "HiddenWireframe", "Vertices", "ShadedVertices", "Illustration",
+ "SolidOutline", "ShadedIllustration",
+}
+
+local function normalize(x, y, z)
+ local modulo = sqrt(x*x + y*y + z*z);
+ if modulo ~= 0 then
+ return x/modulo, y/modulo, z/modulo
+ else
+ return x, y, z
+ end
+end
+
+local function rotate(vect_x,vect_y,vect_z, tet, axis_x,axis_y,axis_z)
+ -- rotate vect by tet about axis counterclockwise
+ local c, s = cos(tet*pi/180), sin(tet*pi/180)
+ local r = 1 - c
+ local n = sqrt(axis_x*axis_x+axis_y*axis_y+axis_z*axis_z)
+ axis_x, axis_y, axis_z = axis_x/n, axis_y/n, axis_z/n
+ return
+ (axis_x*axis_x*r+c )*vect_x + (axis_x*axis_y*r-axis_z*s)*vect_y + (axis_x*axis_z*r+axis_y*s)*vect_z,
+ (axis_x*axis_y*r+axis_z*s)*vect_x + (axis_y*axis_y*r+c )*vect_y + (axis_y*axis_z*r-axis_x*s)*vect_z,
+ (axis_x*axis_z*r-axis_y*s)*vect_x + (axis_y*axis_z*r+axis_x*s)*vect_y + (axis_z*axis_z*r+c )*vect_z
+end
+
+local function make3dview(view)
+
+ local name = view.name
+ local name = pdfunicode(name ~= "" and name or "unknown view")
+
+ local viewdict = pdfdictionary {
+ Type = pdfconstant("3DView"),
+ XN = name,
+ IN = name,
+ NR = true,
+ }
+
+ local bg = checkedkey(view,"bg","table")
+ if bg then
+ viewdict.BG = pdfdictionary {
+ Type = pdfconstant("3DBG"),
+ C = pdfarray { limited(bg[1],1,1,1), limited(bg[2],1,1,1), limited(bg[3],1,1,1) },
+ }
+ end
+
+ local lights = checkedkey(view,"lights","string")
+ if lights and schemes[lights] then
+ viewdict.LS = pdfdictionary {
+ Type = pdfconstant("3DLightingScheme"),
+ Subtype = pdfconstant(lights),
+ }
+ end
+
+ -- camera position is taken from 3d model
+
+ local u3dview = checkedkey(view, "u3dview", "string")
+ if u3dview then
+ viewdict.MS = pdfconstant("U3D")
+ viewdict.U3DPath = u3dview
+ end
+
+ -- position the camera as given
+
+ local c2c = checkedkey(view, "c2c", "table")
+ local coo = checkedkey(view, "coo", "table")
+ local roo = checkedkey(view, "roo", "number")
+ local azimuth = checkedkey(view, "azimuth", "number")
+ local altitude = checkedkey(view, "altitude", "number")
+
+ if c2c or coo or roo or azimuth or altitude then
+
+ local pos = checkedkey(view, "pos", "table")
+ local dir = checkedkey(view, "dir", "table")
+ local upv = checkedkey(view, "upv", "table")
+ local roll = checkedkey(view, "roll", "table")
+
+ local coo_x, coo_y, coo_z = 0, 0, 0
+ local dir_x, dir_y, dir_z = 0, 0, 0
+ local trans_x, trans_y, trans_z = 0, 0, 0
+ local left_x, left_y, left_z = 0, 0, 0
+ local up_x, up_y, up_z = 0, 0, 0
+
+ -- point camera is aimed at
+
+ if coo then
+ coo_x, coo_y, coo_z = tonumber(coo[1]) or 0, tonumber(coo[2]) or 0, tonumber(coo[3]) or 0
+ end
+
+ -- distance from camera to target
+
+ if roo then
+ roo = abs(roo)
+ end
+ if not roo or roo == 0 then
+ roo = 0.000000000000000001
+ end
+
+ -- set it via camera position
+
+ if pos then
+ dir_x = coo_x - (tonumber(pos[1]) or 0)
+ dir_y = coo_y - (tonumber(pos[2]) or 0)
+ dir_z = coo_z - (tonumber(pos[3]) or 0)
+ if not roo then
+ roo = sqrt(dir_x*dir_x + dir_y*dir_y + dir_z*dir_z)
+ end
+ if dir_x == 0 and dir_y == 0 and dir_z == 0 then dir_y = 1 end
+ dir_x, dir_y, dir_z = normalize(dir_x,dir_y,dir_z)
+ end
+
+ -- set it directly
+
+ if dir then
+ dir_x, dir_y, dir_z = tonumber(dir[1] or 0), tonumber(dir[2] or 0), tonumber(dir[3] or 0)
+ if dir_x == 0 and dir_y == 0 and dir_z == 0 then dir_y = 1 end
+ dir_x, dir_y, dir_z = normalize(dir_x,dir_y,dir_z)
+ end
+
+ -- set it movie15 style with vector from target to camera
+
+ if c2c then
+ dir_x, dir_y, dir_z = - tonumber(c2c[1] or 0), - tonumber(c2c[2] or 0), - tonumber(c2c[3] or 0)
+ if dir_x == 0 and dir_y == 0 and dir_z == 0 then dir_y = 1 end
+ dir_x, dir_y, dir_z = normalize(dir_x,dir_y,dir_z)
+ end
+
+ -- set it with azimuth and altitutde
+
+ if altitude or azimuth then
+ dir_x, dir_y, dir_z = -1, 0, 0
+ if altitude then dir_x, dir_y, dir_z = rotate(dir_x,dir_y,dir_z, -altitude, 0,1,0) end
+ if azimuth then dir_x, dir_y, dir_z = rotate(dir_x,dir_y,dir_z, azimuth, 0,0,1) end
+ end
+
+ -- set it with rotation like in MathGL
+
+ if rot then
+ if dir_x == 0 and dir_y == 0 and dir_z == 0 then dir_z = -1 end
+ dir_x,dir_y,dir_z = rotate(dir_x,dir_y,dir_z, tonumber(rot[1]) or 0, 1,0,0)
+ dir_x,dir_y,dir_z = rotate(dir_x,dir_y,dir_z, tonumber(rot[2]) or 0, 0,1,0)
+ dir_x,dir_y,dir_z = rotate(dir_x,dir_y,dir_z, tonumber(rot[3]) or 0, 0,0,1)
+ end
+
+ -- set it with default movie15 orientation looking up y axis
+
+ if dir_x == 0 and dir_y == 0 and dir_z == 0 then dir_y = 1 end
+
+ -- left-vector
+ -- up-vector
+
+ if upv then
+ up_x, up_y, up_z = tonumber(upv[1]) or 0, tonumber(upv[2]) or 0, tonumber(upv[3]) or 0
+ else
+ -- set default up-vector
+ if abs(dir_x) == 0 and abs(dir_y) == 0 then
+ if dir_z < 0 then
+ up_y = 1 -- top view
+ else
+ up_y = -1 -- bottom view
+ end
+ else
+ -- other camera positions than top and bottom, up-vector = up_world - (up_world dot dir) dir
+ up_x, up_y, up_z = - dir_z*dir_x, - dir_z*dir_y, - dir_z*dir_z + 1
+ end
+ end
+
+ -- normalize up-vector
+
+ up_x, up_y, up_z = normalize(up_x,up_y,up_z)
+
+ -- left vector = up x dir
+
+ left_x, left_y, left_z = dir_z*up_y - dir_y*up_z, dir_x*up_z - dir_z*up_x, dir_y*up_x - dir_x*up_y
+
+ -- normalize left vector
+
+ left_x, left_y, left_z = normalize(left_x,left_y,left_z)
+
+ -- apply camera roll
+
+ if roll then
+ local sinroll = sin((roll/180.0)*pi)
+ local cosroll = cos((roll/180.0)*pi)
+ left_x = left_x*cosroll + up_x*sinroll
+ left_y = left_y*cosroll + up_y*sinroll
+ left_z = left_z*cosroll + up_z*sinroll
+ up_x = up_x*cosroll + left_x*sinroll
+ up_y = up_y*cosroll + left_y*sinroll
+ up_z = up_z*cosroll + left_z*sinroll
+ end
+
+ -- translation vector
+
+ trans_x, trans_y, trans_z = coo_x - roo*dir_x, coo_y - roo*dir_y, coo_z - roo*dir_z
+
+ viewdict.MS = pdfconstant("M")
+ viewdict.CO = roo
+ viewdict.C2W = pdfarray {
+ left_x, left_y, left_z,
+ up_x, up_y, up_z,
+ dir_x, dir_y, dir_z,
+ trans_x, trans_y, trans_z,
+ }
+
+ end
+
+ local aac = tonumber(view.aac) -- perspective projection
+ local mag = tonumber(view.mag) -- ortho projection
+
+ if aac and aac > 0 and aac < 180 then
+ viewdict.P = pdfdictionary {
+ Subtype = pdfconstant("P"),
+ PS = pdfconstant("Min"),
+ FOV = aac,
+ }
+ elseif mag and mag > 0 then
+ viewdict.P = pdfdictionary {
+ Subtype = pdfconstant("O"),
+ OS = mag,
+ }
+ end
+
+ local mode = modes[view.rendermode]
+ if mode then
+ pdfdictionary {
+ Type = pdfconstant("3DRenderMode"),
+ Subtype = pdfconstant(mode),
+ }
+ end
+
+ -- crosssection
+
+ local crosssection = checkedkey(view,"crosssection","table")
+ if crosssection then
+ local crossdict = pdfdictionary {
+ Type = pdfconstant("3DCrossSection")
+ }
+
+ local c = checkedkey(crosssection,"point","table") or checkedkey(crosssection,"center","table")
+ if c then
+ crossdict.C = pdfarray { tonumber(c[1]) or 0, tonumber(c[2]) or 0, tonumber(c[3]) or 0 }
+ end
+
+ local normal = checkedkey(crosssection,"normal","table")
+ if normal then
+ local x, y, z = tonumber(normal[1] or 0), tonumber(normal[2] or 0), tonumber(normal[3] or 0)
+ if sqrt(x*x + y*y + z*z) == 0 then
+ x, y, z = 1, 0, 0
+ end
+ crossdict.O = pdfarray {
+ pdfnull,
+ atan2(-z,sqrt(x*x + y*y))*180/pi,
+ atan2(y,x)*180/pi,
+ }
+ end
+
+ local orient = checkedkey(crosssection,"orient","table")
+ if orient then
+ crossdict.O = pdfarray {
+ tonumber(orient[1]) or 1,
+ tonumber(orient[2]) or 0,
+ tonumber(orient[3]) or 0,
+ }
+ end
+
+ crossdict.IV = cross.intersection or false
+ crossdict.ST = cross.transparent or false
+
+ viewdict.SA = next(crossdict) and pdfarray { crossdict } -- maybe test if # > 1
+ end
+
+ local nodes = checkedkey(view,"nodes","table")
+ if nodes then
+ local nodelist = pdfarray()
+ for i=1,#nodes do
+ local node = checkedkey(nodes,i,"table")
+ if node then
+ local position = checkedkey(node,"position","table")
+ nodelist[#nodelist+1] = pdfdictionary {
+ Type = pdfconstant("3DNode"),
+ N = node.name or ("node_" .. i), -- pdfunicode ?
+ M = position and #position == 12 and pdfarray(position),
+ V = node.visible or true,
+ O = node.opacity or 0,
+ RM = pdfdictionary {
+ Type = pdfconstant("3DRenderMode"),
+ Subtype = pdfconstant(node.rendermode or "Solid"),
+ },
+ }
+ end
+ end
+ viewdict.NA = nodelist
+ end
+
+ return viewdict
+
+end
+
+local stored_js, stored_3d, stored_pr, streams = { }, { }, { }, { }
+
+function backends.pdf.helpers.insert3d(spec) -- width, height, factor, display, controls, label, foundname
+
+ local width, height, factor = spec.width, spec.height, spec.factor or number.dimenfactors.bp
+ local display, controls, label, foundname = spec.display, spec.controls, spec.label, spec.foundname
+
+ local param = (display and parametersets[display]) or { }
+ local streamparam = (controls and parametersets[controls]) or { }
+ local name = "3D Artwork " .. (param.name or label or "Unknown")
+
+ local activationdict = pdfdictionary {
+ TB = pdfboolean(param.toolbar,true),
+ NP = pdfboolean(param.tree,false),
+ }
+
+ local stream = streams[label]
+ if not stream then
+
+ local subtype, subdata = "U3D", io.loaddata(foundname) or ""
+ if find(subdata,"^PRC") then
+ subtype = "PRC"
+ elseif find(subdata,"^U3D") then
+ subtype = "U3D"
+ elseif file.extname(foundname) == "prc" then
+ subtype = "PRC"
+ end
+
+ local attr = pdfdictionary {
+ Type = pdfconstant("3D"),
+ Subtype = pdfconstant(subtype),
+ }
+ local streamviews = checkedkey(streamparam, "views", "table")
+ if streamviews then
+ local list = pdfarray()
+ for i=1,#streamviews do
+ local v = checkedkey(streamviews, i, "table")
+ if v then
+ list[#list+1] = make3dview(v)
+ end
+ end
+ attr.VA = list
+ end
+ if checkedkey(streamparam, "view", "table") then
+ attr.DV = make3dview(streamparam.view)
+ elseif checkedkey(streamparam, "view", "string") then
+ attr.DV = streamparam.view
+ end
+ local js = checkedkey(streamparam, "js", "string")
+ if js then
+ local jsref = stored_js[js]
+ if not jsref then
+ jsref = pdfimmediateobj("streamfile",js)
+ stored_js[js] = jsref
+ end
+ attr.OnInstantiate = pdfreference(jsref)
+ end
+ stored_3d[label] = pdfimmediateobj("streamfile",foundname,attr())
+ stream = 1
+ else
+ stream = stream + 1
+ end
+ streams[label] = stream
+
+ local name = pdfunicode(name)
+
+ local annot = pdfdictionary {
+ Subtype = pdfconstant("3D"),
+ T = name,
+ Contents = name,
+ NM = name,
+ ["3DD"] = pdfreference(stored_3d[label]),
+ ["3DA"] = activationdict,
+ }
+ if checkedkey(param,"view","table") then
+ annot["3DV"] = make3dview(param.view)
+ elseif checkedkey(param,"view","string") then
+ annot["3DV"] = param.view
+ end
+
+ local preview = checkedkey(param,"preview","string")
+ if preview then
+ activationdict.A = pdfconstant("XA")
+ local tag = format("%s:%s:%s",label,stream,preview)
+ local ref = stored_pr[tag]
+ if not ref then
+ local figure = img.immediatewrite {
+ filename = preview,
+ width = width,
+ height = height
+ }
+ -- local figure = img.immediatewrite {
+ -- stream = ".5 .75 .75 rg 0 0 20 10 re f",
+ -- bbox = { 0, 0, 20, 10 }
+ -- }
+ ref = figure.objnum
+ stored_pr[tag] = ref
+ end
+ if ref then
+ local zero, one = pdfnumber(0), pdfnumber(1) -- not really needed
+ local pw = pdfdictionary {
+ Type = pdfconstant("XObject"),
+ Subtype = pdfconstant("Form"),
+ FormType = one,
+ BBox = pdfarray { zero, zero, pdfnumber(factor*width), pdfnumber(factor*height) },
+ Matrix = pdfarray { one, zero, zero, one, zero, zero },
+ Resources = pdfdictionary {
+ XObject = pdfdictionary {
+ IM = pdfreference(ref)
+ }
+ },
+ ExtGState = pdfdictionary {
+ GS = pdfdictionary {
+ Type = pdfconstant("ExtGState"),
+ CA = one,
+ ca = one,
+ }
+ },
+ ProcSet = pdfarray { pdfconstant("PDF"), pdfconstant("ImageC") },
+ }
+ local pwd = pdfimmediateobj(
+ "stream",
+ format("q /GS gs %s 0 0 %s 0 0 cm /IM Do Q",
+ factor*width,factor*height),
+ pw()
+ )
+ annot.AP = pdfdictionary {
+ N = pdfreference(pwd)
+ }
+ end
+ return annot, figure, ref
+ else
+ activationdict.A = pdfconstant("PV")
+ return annot, nil, nil
+ end
+end
diff --git a/tex/context/base/lpdf-wid.lua b/tex/context/base/lpdf-wid.lua
new file mode 100644
index 000000000..40a81e7d4
--- /dev/null
+++ b/tex/context/base/lpdf-wid.lua
@@ -0,0 +1,355 @@
+if not modules then modules = { } end modules ['lpdf-wid'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, gmatch, gsub, find = string.format, string.gmatch, string.gsub, string.find
+local texsprint, ctxcatcodes, texbox, texcount = tex.sprint, tex.ctxcatcodes, tex.box, tex.count
+
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
+
+local executers = jobreferences.executers
+local variables = interfaces.variables
+
+local pdfconstant = lpdf.constant
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfstring = lpdf.string
+local pdfcolorspec = lpdf.colorspec
+local pdfflushobject = lpdf.flushobject
+local pdfreserveobject = lpdf.reserveobject
+
+local pdfreserveobj = pdf.reserveobj
+local pdfimmediateobj = pdf.immediateobj
+
+local pdfannotation = nodes.pdfannotation
+
+local hpack_node, write_node = node.hpack, node.write
+
+-- symbols
+
+local presets = { } -- xforms
+
+function codeinjections.registersymbol(name,n)
+ presets[name] = pdfreference(n)
+end
+
+function codeinjections.registeredsymbol(name)
+ return presets[name]
+end
+
+function codeinjections.presetsymbol(symbol)
+ if not presets[symbol] then
+ texsprint(ctxcatcodes,format("\\predefinesymbol[%s]",symbol))
+ end
+end
+
+function codeinjections.presetsymbollist(list)
+ if list then
+ for symbol in gmatch(list,"[^, ]+") do
+ codeinjections.presetsymbol(symbol)
+ end
+ end
+end
+
+-- comments
+
+local symbols = {
+ New = pdfconstant("Insert"),
+ Insert = pdfconstant("Insert"),
+ Balloon = pdfconstant("Comment"),
+ Comment = pdfconstant("Comment"),
+ Text = pdfconstant("Note"),
+ Addition = pdfconstant("NewParagraph"),
+ NewParagraph = pdfconstant("NewParagraph"),
+ Help = pdfconstant("Help"),
+ Paragraph = pdfconstant("Paragraph"),
+ Key = pdfconstant("Key"),
+ Graph = pdfconstant("Graph"),
+ Paperclip = pdfconstant("Paperclip"),
+ Attachment = pdfconstant("Attachment"),
+ Tag = pdfconstant("Tag"),
+}
+
+symbols[variables.normal] = pdfconstant("Note")
+
+local nofcomments, usepopupcomments, stripleading = 0, true, true
+
+local function analyzesymbol(symbol)
+ if not symbol or symbol == "" then
+ return symbols.normal, nil
+ elseif symbols[symbol] then
+ return symbols[symbol], nil
+ else
+ local set = aux.settings_to_array(symbol)
+ local normal, down = set[1], set[2]
+ if normal then
+ normal = codeinjections.registeredsymbol(down or normal)
+ end
+ if down then
+ down = codeinjections.registeredsymbol(normal)
+ end
+ if down or normal then
+ return nil, pdfdictionary {
+ N = normal,
+ D = down,
+ }
+ end
+ end
+end
+
+local function analyzelayer(layer)
+ -- todo: (specification.layer ~= "" and pdfreference(specification.layer)) or nil, -- todo: ref to layer
+end
+
+function codeinjections.registercomment(specification)
+ nofcomments = nofcomments + 1
+ local text = buffers.collect(specification.buffer)
+ if stripleading then
+ text = gsub(text,"[\n\r] *","\n")
+ end
+ local name, appearance = analyzesymbol(specification.symbol)
+ local d = pdfdictionary {
+ Subtype = pdfconstant("Text"),
+ Open = specification.open,
+ Contents = pdfunicode(text),
+ T = (specification.title ~= "" and pdfunicode(specification.title)) or nil,
+ C = pdfcolorspec(specification.colormodel,specification.colorvalue),
+ OC = analyzelayer(specification.layer),
+ Name = name,
+ AP = appearance,
+ }
+ -- watch the nice feed back to tex hack
+ if usepopupcomments then
+ local nd = pdfreserveobject()
+ local nc = pdfreserveobject()
+ local c = pdfdictionary {
+ Subtype = pdfconstant("Popup"),
+ Parent = pdfreference(nd),
+ }
+ d.Popup = pdfreference(nc)
+ texbox["commentboxone"] = hpack_node(pdfannotation(0,0,0,d(),nd)) -- current dir
+ texbox["commentboxtwo"] = hpack_node(pdfannotation(specification.width,specification.height,0,c(),nc)) -- current dir
+ else
+ texbox["commentboxone"] = hpack_node(pdfannotation(0,0,0,d())) -- current dir
+ texbox["commentboxtwo"] = nil
+ end
+end
+
+--
+
+local nofattachments, attachments, filestreams = 0, { }, { }
+
+function codeinjections.embedfile(filename)
+ local r = filestreams[filename]
+ if r == false then
+ return nil
+ elseif r then
+ return r
+ elseif not lfs.isfile(filename) then
+ interfaces.showmessage("interactions",5,filename)
+ filestreams[filename] = false
+ return nil
+ else
+ local basename = file.basename(filename)
+ local a = pdfdictionary { Type = pdfconstant("EmbeddedFile") }
+ local f = pdfimmediateobj("streamfile",filename,a())
+ local d = pdfdictionary {
+ Type = pdfconstant("Filespec"),
+ F = pdfstring(newname or basename),
+ UF = pdfstring(newname or basename),
+ EF = pdfdictionary { F = pdfreference(f) },
+ }
+ local r = pdfreference(pdfflushobject(d))
+ filestreams[filename] = r
+ return r
+ end
+end
+
+function codeinjections.attachfile(specification)
+ local attachment = interactions.attachment(specification.label)
+ if not attachment then
+ -- todo: message
+ return
+ end
+ local filename = attachment.filename
+ if not filename or filename == "" then
+ -- todo: message
+ return
+ end
+ nofattachments = nofattachments + 1
+ local label = attachment.label or ""
+ local title = attachment.title or ""
+ local newname = attachment.newname or ""
+ if label == "" then label = filename end
+ if title == "" then title = label end
+ if newname == "" then newname = filename end
+ local aref = attachments[label]
+ if not aref then
+ aref = codeinjections.embedfile(filename,newname)
+ attachments[label] = aref
+ end
+ local name, appearance = analyzesymbol(specification.symbol)
+ local d = pdfdictionary {
+ Subtype = pdfconstant("FileAttachment"),
+ FS = aref,
+ Contents = pdfunicode(title),
+ Name = name,
+ AP = appearance,
+ OC = analyzelayer(specification.layer),
+ C = pdfcolorspec(specification.colormodel,specification.colorvalue),
+ }
+ -- as soon as we can ask for the dimensions of an xform we can
+ -- use them here
+ local width = specification.width or 0
+ local height = specification.height or 0
+ local depth = specification.depth or 0
+ write_node(pdfannotation(width,height,depth,d()))
+end
+
+function codeinjections.attachmentid(filename)
+ return filestreams[filename]
+end
+
+-- rendering stuff
+--
+-- object_1 -> <> >>
+-- object_2 -> <> >>
+-- rendering -> <>
+--
+-- we only work foreward here
+-- annotation is to be packed at the tex end
+
+-- aiff audio/aiff
+-- au audio/basic
+-- avi video/avi
+-- mid audio/midi
+-- mov video/quicktime
+-- mp3 audio/x-mp3 (mpeg)
+-- mp4 audio/mp4
+-- mp4 video/mp4
+-- mpeg video/mpeg
+-- smil application/smil
+-- swf application/x-shockwave-flash
+
+local ms, mu, mf = { }, { }, { }
+
+local delayed = { }
+
+local function insertrenderingwindow(label,width,height,specification)
+ if options == variables.auto then
+ if openpageaction then
+ -- \handlereferenceactions{\v!StartRendering{#2}}
+ end
+ if closepageaction then
+ -- \handlereferenceactions{\v!StopRendering {#2}}
+ end
+ end
+ local actions = nil
+ if openpage or closepage then
+ actions = pdfdictionary {
+ PO = (openpage and lpdf.pdfaction(openpage )) or nil,
+ PC = (closepage and lpdf.pdfaction(closepage)) or nil,
+ }
+ end
+ local page = tonumber(specification.page) or texcount.realpageno
+ local d = pdfdictionary {
+ Subtype = pdfconstant("Screen"),
+ P = pdfreference(tex.pdfpageref(page)),
+ A = mf[label],
+ Border = pdfarray { 0, 0, 0 } ,
+ AA = actions,
+ }
+ local r = pdfreserveobj("annot")
+ write_node(pdfannotation(width,height,0,d(),r)) -- save ref
+ return pdfreference(r)
+end
+
+local function insertrendering(specification)
+ local label = specification.label
+ if not mf[label] then
+ local filename = specification.filename
+ local isurl = find(filename,"://")
+ local d = pdfdictionary {
+ Type = pdfconstant("Rendition"),
+ S = pdfconstant("MR"),
+ C = pdfdictionary {
+ Type = pdfconstant("MediaClip"),
+ S = pdfconstant("MCD"),
+ N = label,
+ CT = specification.mime,
+ Alt = pdfarray {
+ "", "file not found", -- language id + message
+ },
+ D = pdfdictionary {
+ Type = pdfconstant("Filespec"),
+ F = filename,
+ FS = (isurl and pdfconstant("URL")) or nil,
+ }
+ }
+ }
+ mf[label] = pdfreference(pdfflushobject(d))
+ if not ms[label] then
+ mu[label] = insertrenderingwindow(label,0,0,specification.options)
+ end
+ end
+end
+
+local function insertrenderingobject(specification)
+ local label = specification.label
+ if not mf[label] then
+ local d = pdfdictionary {
+ Type = pdfconstant("Rendition"),
+ S = pdfconstant("MR"),
+ C = pdfdictionary {
+ Type = pdfconstant("MediaClip"),
+ S = pdfconstant("MCD"),
+ N = label,
+ D = pdfreference(unknown), -- not label but objectname, hm
+ }
+ }
+ mf[label] = pdfreference(pdfflushobject(d))
+ if ms[label] then
+ insertrenderingwindow(label,0,0,specification)
+ end
+ end
+end
+
+function codeinjections.insertrenderingwindow(specification)
+ local label = specification.label
+ codeinjections.processrendering(label) -- was check at tex end
+ ms[label] = insertrenderingwindow(label,specification.width,specification.height,specification)
+end
+
+function codeinjections.processrendering(label)
+ local specification = interactions.rendering(label)
+ if specification then
+ if specification.kind == "external" then
+ insertrendering(specification)
+ else
+ insertrenderingobject(specification)
+ end
+ end
+end
+
+local function set(operation,arguments)
+ codeinjections.processrendering(arguments) -- was check at the tex end
+ return pdfdictionary {
+ S = pdfconstant("Rendition"),
+ OP = operation,
+ R = mf[arguments],
+ AN = ms[arguments] or mu[arguments],
+ }
+end
+
+function executers.startrendering (arguments) return set(0,arguments) end
+function executers.stoprendering (arguments) return set(1,arguments) end
+function executers.pauserendering (arguments) return set(2,arguments) end
+function executers.resumerendering(arguments) return set(3,arguments) end
diff --git a/tex/context/base/lpdf-xmp.lua b/tex/context/base/lpdf-xmp.lua
new file mode 100644
index 000000000..c8e7b2b57
--- /dev/null
+++ b/tex/context/base/lpdf-xmp.lua
@@ -0,0 +1,165 @@
+if not modules then modules = { } end modules ['lpdf-xmp'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+ comment = "with help from Peter Rolf",
+}
+
+local format, random, char, gsub, concat = string.format, math.random, string.char, string.gsub, table.concat
+local xmlfillin = xml.fillin
+
+local trace_xmp = false trackers.register("backend.xmp", function(v) trace_xmp = v end)
+
+local pdfdictionary = lpdf.dictionary
+local pdfconstant = lpdf.constant
+
+-- i wonder why this begin end is empty / w (no time now to look into it)
+
+local xpacket = [[
+
+
+%s
+
+]]
+
+local mapping = {
+ -- user defined keys (pdfx:)
+ ["ConTeXt.Jobname"] = "rdf:Description/pdfx:ConTeXt.Jobname",
+ ["ConTeXt.Time"] = "rdf:Description/pdfx:ConTeXt.Time",
+ ["ConTeXt.Url"] = "rdf:Description/pdfx:ConTeXt.Url",
+ ["ConTeXt.Version"] = "rdf:Description/pdfx:ConTeXt.Version",
+ ["ID"] = "rdf:Description/pdfx:ID",
+ ["PTEX.Fullbanner"] = "rdf:Description/pdfx:PTEX.Fullbanner",
+ -- Adobe PDF schema
+ ["Keywords"] = "rdf:Description/pdf:Keywords",
+ ["Producer"] = "rdf:Description/pdf:Producer",
+ -- ["Trapped"] = "rdf:Description/pdf:Trapped", -- '/False' in /Info, but 'False' in XMP
+ -- Dublin Core schema
+ ["Author"] = "rdf:Description/dc:creator/rdf:Seq/rdf:li",
+ ["Format"] = "rdf:Description/dc:format", -- optional, but nice to have
+ ["Subject"] = "rdf:Description/dc:description",
+ ["Title"] = "rdf:Description/dc:title/rdf:Alt/rdf:li",
+ -- XMP Basic schema
+ ["CreateDate"] = "rdf:Description/xmp:CreateDate",
+ ["Creator"] = "rdf:Description/xmp:CreatorTool",
+ ["MetadataDate"] = "rdf:Description/xmp:MetadataDate",
+ ["ModifyDate"] = "rdf:Description/xmp:ModifyDate",
+ -- XMP Media Management schema
+ ["DocumentID"] = "rdf:Description/xmpMM:DocumentID",
+ ["InstanceID"] = "rdf:Description/xmpMM:InstanceID",
+ ["RenditionClass"] = "rdf:Description/xmpMM:RenditionClass", -- PDF/X-4
+ ["VersionID"] = "rdf:Description/xmpMM:VersionID", -- PDF/X-4
+ -- additional entries
+ -- PDF/X
+ ["GTS_PDFXVersion"] = "rdf:Description/pdfxid:GTS_PDFXVersion",
+ -- optional entries
+ -- all what is visible in the 'document properties --> additional metadata' window
+ -- XMP Rights Management schema (optional)
+ ["Marked"] = "rdf:Description/xmpRights:Marked",
+ -- ["Owner"] = "rdf:Description/xmpRights:Owner/rdf:Bag/rdf:li", -- maybe useful (not visible)
+ -- ["UsageTerms"] = "rdf:Description/xmpRights:UsageTerms", -- maybe useful (not visible)
+ ["WebStatement"] = "rdf:Description/xmpRights:WebStatement",
+ -- Photoshop PDF schema (optional)
+ ["AuthorsPosition"] = "rdf:Description/photoshop:AuthorsPosition",
+ ["Copyright"] = "rdf:Description/photoshop:Copyright",
+ ["CaptionWriter"] = "rdf:Description/photoshop:CaptionWriter",
+}
+
+-- maybe some day we will load the xmp file at runtime
+
+local xmp, xmpfile, xmpname = nil, nil, "lpdf-xmp.xml"
+
+function lpdf.setxmpfile(name)
+ xmpfile = resolvers.findctxfile(name) or ""
+ if xmpfile == "" then
+ xmpfile = nil
+ end
+end
+
+local function valid_xmp()
+ if not xmp then
+ local xmpfile = xmpfile or resolvers.find_file(xmpname) or ""
+ local xmpdata = (xmpfile ~= "" and io.loaddata(xmpfile)) or ""
+ xmp = xml.convert(xmpdata)
+ end
+ return xmp
+end
+
+function lpdf.addxmpinfo(tag,value,check)
+ local pattern = mapping[tag]
+ if pattern then
+ xmlfillin(xmp or valid_xmp(),pattern,value,check)
+ end
+end
+
+-- redefined
+
+local addtoinfo = lpdf.addtoinfo
+local addxmpinfo = lpdf.addxmpinfo
+
+function lpdf.addtoinfo(tag,pdfvalue,strvalue)
+ addtoinfo(tag,pdfvalue)
+ addxmpinfo(tag,strvalue or gsub(tostring(pdfvalue),"^%((.*)%)$","%1")) -- hack
+end
+
+-- for the do-it-yourselvers
+
+function lpdf.insertxmpinfo(pattern,whatever,prepend)
+ xml.insert(xmp or valid_xmp(),pattern,whatever,prepend)
+end
+
+function lpdf.injectxmpinfo(pattern,whatever,prepend)
+ xml.inject(xmp or valid_xmp(),pattern,whatever,prepend)
+end
+
+-- flushing
+
+local t = { } for i=1,24 do t[i] = random() end
+
+local function flushxmpinfo()
+
+ commands.freezerandomseed(os.clock()) -- hack
+
+ local t = { } for i=1,24 do t[i] = char(96 + random(26)) end
+ local packetid = concat(t)
+ local time = lpdf.timestamp()
+ addxmpinfo("Producer",format("LuaTeX-%0.2f.%s",tex.luatexversion/100,tex.luatexrevision))
+ addxmpinfo("DocumentID",format("uuid:%s",os.uuid()))
+ addxmpinfo("InstanceID",format("uuid:%s",os.uuid()))
+ addxmpinfo("CreatorTool","LuaTeX + ConTeXt MkIV")
+ addxmpinfo("CreateDate",time)
+ addxmpinfo("ModifyDate",time)
+ addxmpinfo("MetadataDate",time)
+ addxmpinfo("PTEX.Fullbanner", tex.pdftexbanner)
+ local blob = xml.tostring(xml.first(xmp or valid_xmp(),"/x:xmpmeta"))
+ local md = pdfdictionary {
+ Subtype = pdfconstant("XML"),
+ Type = pdfconstant("Metadata"),
+ }
+ if trace_xmp then
+ commands.writestatus("system","xmp data flushed (see log file)")
+ texio.write_nl("log","")
+ texio.write("log","\n% ",(gsub(blob,"[\r\n]","\n%% ")),"\n")
+ end
+ blob = format(xpacket,packetid,blob)
+ if tex.pdfcompresslevel > 0 then
+ blob = gsub(blob,">%s+<","><")
+ end
+ local r = pdf.obj {
+ immediate = true,
+ compresslevel = 0,
+ type = "stream",
+ string = blob,
+ attr = md(),
+ }
+ lpdf.addtocatalog("Metadata",lpdf.reference(r))
+
+ commands.defrostrandomseed() -- hack
+
+end
+
+-- his will be enabled when we can inhibit compression for a stream at the lua end
+
+lpdf.registerdocumentfinalizer(flushxmpinfo,1)
diff --git a/tex/context/base/lpdf-xmp.xml b/tex/context/base/lpdf-xmp.xml
new file mode 100644
index 000000000..2947211bd
--- /dev/null
+++ b/tex/context/base/lpdf-xmp.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+ application/pdf
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+
+
+
+
+
+
+
diff --git a/tex/context/base/luat-bas.mkiv b/tex/context/base/luat-bas.mkiv
new file mode 100644
index 000000000..581a5d95a
--- /dev/null
+++ b/tex/context/base/luat-bas.mkiv
@@ -0,0 +1,65 @@
+%D \module
+%D [ file=luat-bas, % moved from luat-lib,
+%D version=2006.09.11,
+%D title=\CONTEXT\ Lua Macros,
+%D subtitle=Basic \LUA\ Libraries,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 Lua Macros / Basic Lua Libraries}
+
+%D This will move cq. become configurable. The XML like output is just
+%D an example.
+
+% todo \let\normaleverytoks\everytoks \newtoks\everytoke \normaleverytoks{\the\everytoks}
+
+\chardef\statuswidth=15
+\chardef\statuswrite=16
+
+\newtoks\everywritestring
+
+\def\writedirect {\immediate\write\statuswrite}
+\def\writeline {\writedirect{}}
+\def\writestring#1{\begingroup\the\everywritestring\writedirect{#1}\endgroup}
+
+\ifx\normalwritestatus\undefined \def\normalwritestatus#1#2{\writedirect{#1 : #2}} \fi
+
+% Because all libs are also on bytecodes we can start without stub. However,
+% some initializations need to take place before the \TEX\ engine itself
+% kicks in, especially memory settings and so. In due time we might make the
+% stub smaller and just create a configuration startup file.
+
+\registerctxluafile{l-string} {1.001}
+\registerctxluafile{l-lpeg} {1.001}
+\registerctxluafile{l-boolean}{1.001}
+\registerctxluafile{l-number} {1.001}
+\registerctxluafile{l-math} {1.001}
+\registerctxluafile{l-table} {1.001}
+\registerctxluafile{l-aux} {1.001}
+\registerctxluafile{l-io} {1.001}
+\registerctxluafile{l-os} {1.001}
+\registerctxluafile{l-file} {1.001}
+\registerctxluafile{l-md5} {1.001}
+\registerctxluafile{l-dir} {1.001}
+\registerctxluafile{l-unicode}{1.001}
+\registerctxluafile{l-utils} {1.001}
+\registerctxluafile{l-dimen} {1.001}
+\registerctxluafile{l-url} {1.001}
+\registerctxluafile{l-set} {1.001}
+\registerctxluafile{l-dimen} {1.001}
+
+% \registerctxluafile{socket.lua}{}
+% \registerctxluafile{ltn12.lua} {}
+% \registerctxluafile{mime.lua} {}
+% \registerctxluafile{http.lua} {}
+% \registerctxluafile{url.lua} {}
+% \registerctxluafile{tp.lua} {}
+% \registerctxluafile{ftp.lua} {}
+% %registerctxluafile{smtp.lua} {}
+
+\endinput
diff --git a/tex/context/base/luat-cbk.lua b/tex/context/base/luat-cbk.lua
new file mode 100644
index 000000000..3cb63ad6e
--- /dev/null
+++ b/tex/context/base/luat-cbk.lua
@@ -0,0 +1,247 @@
+if not modules then modules = { } end modules ['luat-cbk'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local insert, remove, find = table.insert, table.remove, string.find
+local collectgarbage, type, next = collectgarbage, type, next
+local round = math.round
+
+local trace_checking = false trackers.register("memory.checking", function(v) trace_checking = v end)
+
+--[[ldx--
+
Callbacks are the real asset of . They permit you to hook
+your own code into the engine. Here we implement a few handy
+auxiliary functions.
When you (temporarily) want to install a callback function, and after a
+while wants to revert to the original one, you can use the following two
+functions.
+--ldx]]--
+
+local trace_callbacks = false trackers.register("system.callbacks", function(v) trace_callbacks = v end)
+
+local register_callback, find_callback = callback.register, callback.find
+local frozen, stack = { }, { }
+
+callback.original_register_callback = register_callback
+
+local function frozen_message(what,name)
+ logs.report("callbacks","not %s frozen '%s' (%s)",what,name,frozen[name])
+end
+
+local function frozen_callback(name)
+ return nil, format("callback '%s' is frozen (%s)",name,frozen[name])
+end
+
+local function state(name)
+ local f = find_callback(name)
+ if f == false then
+ return "disabled"
+ elseif f then
+ return "enabled"
+ else
+ return "undefined"
+ end
+end
+
+function callbacks.report()
+ local list = callback.list()
+ for name, func in table.sortedhash(list) do
+ local str = frozen[name]
+ if str then
+ logs.report("callbacks","%s: %s -> %s",state(name),name,str)
+ else
+ logs.report("callbacks","%s: %s",state(name),name)
+ end
+ end
+end
+
+function callbacks.table()
+ local NC, NR, verbatim = context.NC, context.NR, context.type
+ context.starttabulate { "|l|l|p|" }
+ for name, func in table.sortedhash(callback.list()) do
+ NC() verbatim(name) NC() verbatim(state(name)) NC() context(frozen[name] or "") NC() NR()
+ end
+ context.stoptabulate()
+end
+
+function callbacks.freeze(name,freeze)
+ freeze = type(freeze) == "string" and freeze
+--~ print(name)
+ if find(name,"%*") then
+ local pattern = name -- string.simpleesc(name)
+ local list = callback.list()
+ for name, func in next, list do
+ if find(name,pattern) then
+ frozen[name] = freeze or frozen[name] or "frozen"
+ end
+ end
+ else
+ frozen[name] = freeze or frozen[name] or "frozen"
+ end
+end
+
+function callbacks.register(name,func,freeze)
+ if frozen[name] then
+ if trace_callbacks then
+ frozen_message("registering",name)
+ end
+ return frozen_callback(name)
+ elseif freeze then
+ frozen[name] = (type(freeze) == "string" and freeze) or "registered"
+ end
+ return register_callback(name,func)
+end
+
+function callback.register(name,func) -- original
+ if not frozen[name] then
+ return register_callback(name,func)
+ elseif trace_callbacks then
+ frozen_message("registering",name)
+ end
+ return frozen_callback(name)
+end
+
+function callbacks.push(name, func)
+ if not frozen[name] then
+ local sn = stack[name]
+ if not sn then
+ sn = { }
+ stack[name] = sn
+ end
+ insert(sn,find_callback(name))
+ register_callback(name, func)
+ elseif trace_callbacks then
+ frozen_message("pushing",name)
+ end
+end
+
+function callbacks.pop(name)
+ if not frozen[name] then
+ local sn = stack[name]
+ if not sn or #sn == 0 then
+ -- some error
+ register_callback(name, nil) -- ! really needed
+ else
+ -- this fails: register_callback(name, remove(stack[name]))
+ local func = remove(sn)
+ register_callback(name, func)
+ end
+ end
+end
+
+--~ -- somehow crashes later on
+--~
+--~ callbacks.freeze("find_.*_file","finding file")
+--~ callbacks.freeze("read_.*_file","reading file")
+--~ callbacks.freeze("open_.*_file","opening file")
+
+--[[ldx--
+
Callbacks may result in doing some hard work
+which takes time and above all resourses. Sometimes it makes
+sense to disable or tune the garbage collector in order to
+keep the use of resources acceptable.
+
+
At some point in the development we did some tests with counting
+nodes (in this case 121049).
+
+
+
setstepmul
seconds
megabytes
+
200
24.0
80.5
+
175
21.0
78.2
+
150
22.0
74.6
+
160
22.0
74.6
+
165
21.0
77.6
+
125
21.5
89.2
+
100
21.5
88.4
+
+
+
The following code is kind of experimental. In the documents
+that describe the development of we report
+on speed tests. One observation is thta it sometimes helps to
+restart the collector. Okay, experimental code has been removed,
+because messing aroudn with the gc is too unpredictable.
+--ldx]]--
+
+garbagecollector = garbagecollector or { }
+
+garbagecollector.enabled = false
+garbagecollector.criterium = 4*1024*1024
+
+-- Lua allocates up to 12 times the amount of memory needed for
+-- handling a string, and for large binary chunks (like chinese otf
+-- files) we get a prominent memory consumption. Even when a variable
+-- is nilled, there is some delay in freeing the associated memory (the
+-- hashed string) because if we do the same thing directly afterwards,
+-- we see only a slight increase in memory. For that reason it makes
+-- sense to do a collector pass after a huge file.
+--
+-- test file:
+--
+-- function test()
+-- local b = collectgarbage("count")
+-- local s = io.loaddata("some font table, e.g. a big tmc file")
+-- local a = collectgarbage("count")
+-- print(">>> STATUS",b,a,a-b,#s,1000*(a-b)/#s)
+-- end
+--
+-- test() test() test() test() collectgarbage("collect") test() test() test() test()
+--
+-- As a result of this, LuaTeX now uses an optimized version of f:read("*a"),
+-- one that does not use the 4K allocations but allocates in one step.
+
+function garbagecollector.check(size,criterium)
+ if garbagecollector.enabled then
+ criterium = criterium or garbagecollector.criterium
+ if not size or (criterium and criterium > 0 and size > criterium) then
+ if trace_checking then
+ local b = collectgarbage("count")
+ collectgarbage("collect")
+ local a = collectgarbage("count")
+ logs.report("memory","forced sweep, collected: %s MB, used: %s MB",round((b-a)/1000),round(a/1000))
+ else
+ collectgarbage("collect")
+ end
+ end
+ end
+end
diff --git a/tex/context/base/luat-cnf.lua b/tex/context/base/luat-cnf.lua
new file mode 100644
index 000000000..e45aceb79
--- /dev/null
+++ b/tex/context/base/luat-cnf.lua
@@ -0,0 +1,115 @@
+if not modules then modules = { } end modules ['luat-cnf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, concat, find = string.format, table.concat, string.find
+
+luatex = luatex or { }
+
+luatex.variablenames = {
+ 'main_memory', 'extra_mem_bot', 'extra_mem_top',
+ 'buf_size','expand_depth',
+ 'font_max', 'font_mem_size',
+ 'hash_extra', 'max_strings', 'pool_free', 'pool_size', 'string_vacancies',
+ 'obj_tab_size', 'pdf_mem_size', 'dest_names_size',
+ 'nest_size', 'param_size', 'save_size', 'stack_size','expand_depth',
+ 'trie_size', 'hyph_size', 'max_in_open',
+ 'ocp_stack_size', 'ocp_list_size', 'ocp_buf_size',
+ 'max_print_line',
+}
+
+function luatex.variables()
+ local t, x = { }, nil
+ for _,v in next, luatex.variablenames do
+ x = resolvers.var_value(v)
+ if x and find(x,"^%d+$") then
+ t[v] = tonumber(x)
+ end
+ end
+ return t
+end
+
+if not luatex.variables_set then
+ for k, v in next, luatex.variables() do
+ texconfig[k] = v
+ end
+ luatex.variables_set = true
+end
+
+local stub = [[
+-- checking
+
+storage = storage or { }
+luatex = luatex or { }
+
+-- we provide our own file handling
+
+texconfig.kpse_init = false
+texconfig.shell_escape = 't'
+
+-- as soon as possible
+
+luatex.starttime = os.gettimeofday()
+
+-- this will happen after the format is loaded
+
+function texconfig.init()
+
+ -- shortcut and helper
+
+ local b = lua.bytecode
+
+ local function init(start)
+ local i = start
+ while b[i] do
+ b[i]() ; b[i] = nil ; i = i + 1
+ -- collectgarbage('step')
+ end
+ return i - start
+ end
+
+ -- the stored tables and modules
+
+ storage.noftables = init(0)
+ storage.nofmodules = init(%s)
+
+end
+
+-- we provide a qualified path
+
+callback.register('find_format_file',function(name)
+ texconfig.formatname = name
+ return name
+end)
+
+-- done, from now on input and callbacks are internal
+]]
+
+function luatex.dumpstate(name,firsttable)
+ if tex and tex.luatexversion < 38 then
+ os.remove(name)
+ elseif true then
+ local t = {
+ "-- this file is generated, don't change it\n",
+ "-- configuration (can be overloaded later)\n"
+ }
+ for _,v in next, luatex.variablenames do
+ local tv = texconfig[v]
+ if tv then
+ t[#t+1] = format("texconfig.%s=%s",v,tv)
+ end
+ end
+ io.savedata(name,format("%s\n\n%s",concat(t,"\n"),format(stub,firsttable or 501)))
+ else
+ io.savedata(name,format(stub,firsttable or 501))
+ end
+end
+
+texconfig.kpse_init = false
+texconfig.max_print_line = 100000
+texconfig.max_in_open = 127
+texconfig.shell_escape = 't'
diff --git a/tex/context/base/luat-cod.mkiv b/tex/context/base/luat-cod.mkiv
new file mode 100644
index 000000000..d3b37d0e1
--- /dev/null
+++ b/tex/context/base/luat-cod.mkiv
@@ -0,0 +1,161 @@
+%D \module
+%D [ file=luat-cod,
+%D version=2005.05.26,
+%D title=\CONTEXT\ Lua Macros,
+%D subtitle=Code,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 Lua Macros / Code}
+
+%D Originally we compiled the lua files externally and loaded
+%D then at runtime, but when the amount grew, we realized that
+%D we needed away to store them in the format, which is what
+%D bytecode arrays do. And so the following is obsolete:
+%D
+%D \starttyping
+%D \chardef\ctxluaembeddingmode \plusone
+%D
+%D 0 = external compilation and loading
+%D 1 = runtime compilation and embedding
+%D \stoptyping
+%D
+%D Allocation of \LUA\ engines has changed too. The original idea
+%D was to have multiple \LUA\ instances and it worked that way for
+%D several years. Hoewver in practice we used only one engine because
+%D scripts need to share data anyway. So eventually \LUATEX\ got only
+%D one instance. Because each call is reentrant there is not much
+%D danger for crashes.
+
+\def\ctxdirectlua{\directlua\zerocount}
+\def\ctxlatelua {\latelua \zerocount}
+
+%D Take your choice \unknown
+
+\let\ctxlua \ctxdirectlua
+\let\luacode \ctxdirectlua
+\let\lateluacode \ctxlatelua
+\let\directluacode\ctxdirectlua
+
+%D Reporting the version of \LUA\ that we use is done as follows:
+
+\edef\luaversion{\ctxlua{tex.print(_VERSION)}}
+
+%D We want to define \LUA\ related things in the format but
+%D need to reload code because \LUA\ instances themselves are
+%D not dumped into the format.
+
+\newtoks\everyloadluacode
+\newtoks\everyfinalizeluacode
+
+\normaleveryjob{\the\everyloadluacode\the\everyfinalizeluacode\the\everyjob}
+
+\newif\ifproductionrun
+
+%D Here we operate in the \TEX\ catcode regime as we haven't yet defined
+%D catcode regimes. A chicken or egg problem.
+
+\normalprotected\long\def\startruntimeluacode#1\stopruntimeluacode % only simple code (load +init)
+ {\ifproductionrun
+ \global\let\startruntimeluacode\relax
+ \global\let\stopruntimeluacode \relax
+ \else
+ \global\everyloadluacode\expandafter{\the\everyloadluacode#1}%
+ \fi
+ #1} % maybe no interference
+
+\normalprotected\long\def\startruntimectxluacode#1\stopruntimectxluacode
+ {\startruntimeluacode\ctxlua{#1}\stopruntimeluacode}
+
+%D Next we load the initialization code.
+
+\startruntimectxluacode
+ environment = environment or { }
+ environment.jobname = "\jobname" % tex.jobname
+ environment.initex = \ifproductionrun false \else true \fi % tex.formatname == ""
+ environment.version = "\fmtversion"
+\stopruntimectxluacode
+
+% we start at 500, below this, we store predefined data (dumps)
+
+\newcount\luabytecodecounter \luabytecodecounter=500
+
+\startruntimectxluacode
+ lua.bytedata = lua.bytedata or { }
+\stopruntimectxluacode
+
+%D Handy when we expand:
+
+\let\stopruntimeluacode \relax
+\let\stopruntimectxluacode\relax
+
+\long\def\lastexpanded{} % todo: elsewhere we use \@@expanded
+
+\long\def\expanded#1{\long\xdef\lastexpanded{\noexpand#1}\lastexpanded}
+
+%D More code:
+
+% \def\ctxluabytecode#1% executes an already loaded chunk
+% {\ctxlua {
+% local str = ''
+% if lua.bytedata[#1] then
+% str = " from file " .. lua.bytedata[#1][1] .. " version " .. lua.bytedata[#1][2]
+% end
+% if lua.bytecode[#1] then
+% if environment.initex then
+% texio.write_nl("bytecode: executing blob " .. "#1" .. str)
+% assert(lua.bytecode[#1])()
+% else
+% texio.write_nl("bytecode: initializing blob " .. "#1" .. str)
+% assert(lua.bytecode[#1])()
+% lua.bytecode[#1] = nil
+% end
+% else
+% texio.write_nl("bytecode: invalid blob " .. "#1" .. str)
+% end
+% }}
+
+\def\ctxluabytecode#1% executes an already loaded chunk
+ {\ctxlua {
+ local lbc = lua.bytecode
+ if lbc[#1] then
+ assert(lbc[#1])()
+ if not environment.initex then
+ lbc[#1] = nil
+ end
+ end
+ }}
+
+\def\ctxluabyteload#1#2% registers and compiles chunk
+ {\global\advance\luabytecodecounter \plusone
+ \normalexpanded{\startruntimectxluacode
+ lua.bytedata[\the\luabytecodecounter] = { "#1", "#2" }
+ \stopruntimectxluacode}%
+ \ctxlua {
+ lua.bytedata[\the\luabytecodecounter] = { "#1", "#2" }
+ lua.bytecode[\the\luabytecodecounter] = environment.luafilechunk("#1")
+ }}
+
+\def\ctxloadluafile#1#2% load a (either not compiled) chunk at runtime
+ {\doifelsenothing{#2}
+ {\ctxlua{environment.loadluafile("#1")}}
+ {\ctxlua{environment.loadluafile("#1",#2)}}}
+
+\def\registerctxluafile#1#2% name version (modules and core code)
+ {\ifproductionrun
+ \ctxloadluafile{#1}{#2}%
+ \else
+ \ctxluabyteload{#1}{#2}% can go away
+ \fi
+ \global\everyloadluacode\expandafter\expandafter\expandafter{\expandafter\the\expandafter\everyloadluacode
+ \expandafter\ctxluabytecode\expandafter{\the\luabytecodecounter}}%
+ \ctxluabytecode{\the\luabytecodecounter}}
+
+\everydump\expandafter{\the\everydump\ctxlua{luatex.dumpstate(environment.jobname..".lui",501)}}
+
+\endinput
diff --git a/tex/context/base/luat-dum.lua b/tex/context/base/luat-dum.lua
new file mode 100644
index 000000000..4530c2ef3
--- /dev/null
+++ b/tex/context/base/luat-dum.lua
@@ -0,0 +1,126 @@
+if not modules then modules = { } end modules ['luat-dum'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local dummyfunction = function() end
+
+statistics = {
+ register = dummyfunction,
+ starttiming = dummyfunction,
+ stoptiming = dummyfunction,
+}
+directives = {
+ register = dummyfunction,
+ enable = dummyfunction,
+ disable = dummyfunction,
+}
+trackers = {
+ register = dummyfunction,
+ enable = dummyfunction,
+ disable = dummyfunction,
+}
+experiments = {
+ register = dummyfunction,
+ enable = dummyfunction,
+ disable = dummyfunction,
+}
+storage = {
+ register = dummyfunction,
+ shared = { },
+}
+logs = {
+ report = dummyfunction,
+ simple = dummyfunction,
+}
+tasks = {
+ new = dummyfunction,
+ actions = dummyfunction,
+ appendaction = dummyfunction,
+ prependaction = dummyfunction,
+}
+callbacks = {
+ register = function(n,f) return callback.register(n,f) end,
+}
+
+-- we need to cheat a bit here
+
+texconfig.kpse_init = true
+
+resolvers = resolvers or { } -- no fancy file helpers used
+
+local remapper = {
+ otf = "opentype fonts",
+ ttf = "truetype fonts",
+ ttc = "truetype fonts",
+ dfont = "truetype dictionary",
+ cid = "cid maps",
+ fea = "font feature files",
+}
+
+function resolvers.find_file(name,kind)
+ name = string.gsub(name,"\\","\/")
+ kind = string.lower(kind)
+ return kpse.find_file(name,(kind and kind ~= "" and (remapper[kind] or kind)) or file.extname(name,"tex"))
+end
+
+function resolvers.findbinfile(name,kind)
+ if not kind or kind == "" then
+ kind = file.extname(name) -- string.match(name,"%.([^%.]-)$")
+ end
+ return resolvers.find_file(name,(kind and remapper[kind]) or kind)
+end
+
+-- Caches ... I will make a real stupid version some day when I'm in the
+-- mood. After all, the generic code does not need the more advanced
+-- ConTeXt features. Cached data is not shared between ConTeXt and other
+-- usage as I don't want any dependency at all. Also, ConTeXt might have
+-- different needs and tricks added.
+
+caches = { }
+
+--~ containers.usecache = true
+
+function caches.setpath(category,subcategory)
+ local root = kpse.var_value("TEXMFCACHE") or ""
+ if root == "" then
+ root = kpse.var_value("VARTEXMF") or ""
+ end
+ if root ~= "" then
+ root = file.join(root,category)
+ lfs.mkdir(root)
+ root = file.join(root,subcategory)
+ lfs.mkdir(root)
+ return lfs.isdir(root) and root
+ end
+end
+
+local function makefullname(path,name)
+ if path and path ~= "" then
+ name = "temp-" and name -- clash prevention
+ return file.addsuffix(file.join(path,name),"lua")
+ end
+end
+
+function caches.iswritable(path,name)
+ local fullname = makefullname(path,name)
+ return fullname and file.iswritable(fullname)
+end
+
+function caches.loaddata(path,name)
+ local fullname = makefullname(path,name)
+ if fullname then
+ local data = loadfile(fullname)
+ return data and data()
+ end
+end
+
+function caches.savedata(path,name,data)
+ local fullname = makefullname(path,name)
+ if fullname then
+ table.tofile(fullname,data,'return',false,true,false)
+ end
+end
diff --git a/tex/context/base/luat-env.lua b/tex/context/base/luat-env.lua
new file mode 100644
index 000000000..0e21fca31
--- /dev/null
+++ b/tex/context/base/luat-env.lua
@@ -0,0 +1,283 @@
+if not modules then modules = { } end modules ['luat-env'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- A former version provided functionality for non embeded core
+-- scripts i.e. runtime library loading. Given the amount of
+-- Lua code we use now, this no longer makes sense. Much of this
+-- evolved before bytecode arrays were available and so a lot of
+-- code has disappeared already.
+
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
+
+local format, sub, match, gsub, find = string.format, string.sub, string.match, string.gsub, string.find
+local unquote, quote = string.unquote, string.quote
+
+-- precautions
+
+os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
+
+function os.setlocale()
+ -- no way you can mess with it
+end
+
+-- dirty tricks
+
+if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+if profiler and os.env["MTX_PROFILE_RUN"] == "YES" then
+ profiler.start("luatex-profile.log")
+end
+
+-- environment
+
+environment = environment or { }
+environment.arguments = { }
+environment.files = { }
+environment.sortedflags = nil
+
+if not environment.jobname or environment.jobname == "" then if tex then environment.jobname = tex.jobname end end
+if not environment.version or environment.version == "" then environment.version = "unknown" end
+if not environment.jobname then environment.jobname = "unknown" end
+
+function environment.initialize_arguments(arg)
+ local arguments, files = { }, { }
+ environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
+ for index=1,#arg do
+ local argument = arg[index]
+ if index > 0 then
+ local flag, value = match(argument,"^%-+(.-)=(.-)$")
+ if flag then
+ arguments[flag] = unquote(value or "")
+ else
+ flag = match(argument,"^%-+(.+)")
+ if flag then
+ arguments[flag] = true
+ else
+ files[#files+1] = argument
+ end
+ end
+ end
+ end
+ environment.ownname = environment.ownname or arg[0] or 'unknown.lua'
+end
+
+function environment.setargument(name,value)
+ environment.arguments[name] = value
+end
+
+-- todo: defaults, better checks e.g on type (boolean versus string)
+--
+-- tricky: too many hits when we support partials unless we add
+-- a registration of arguments so from now on we have 'partial'
+
+function environment.argument(name,partial)
+ local arguments, sortedflags = environment.arguments, environment.sortedflags
+ if arguments[name] then
+ return arguments[name]
+ elseif partial then
+ if not sortedflags then
+ sortedflags = table.sortedkeys(arguments)
+ for k=1,#sortedflags do
+ sortedflags[k] = "^" .. sortedflags[k]
+ end
+ environment.sortedflags = sortedflags
+ end
+ -- example of potential clash: ^mode ^modefile
+ for k=1,#sortedflags do
+ local v = sortedflags[k]
+ if find(name,v) then
+ return arguments[sub(v,2,#v)]
+ end
+ end
+ end
+ return nil
+end
+
+environment.argument("x",true)
+
+function environment.split_arguments(separator) -- rather special, cut-off before separator
+ local done, before, after = false, { }, { }
+ local original_arguments = environment.original_arguments
+ for k=1,#original_arguments do
+ local v = original_arguments[k]
+ if not done and v == separator then
+ done = true
+ elseif done then
+ after[#after+1] = v
+ else
+ before[#before+1] = v
+ end
+ end
+ return before, after
+end
+
+function environment.reconstruct_commandline(arg,noquote)
+ arg = arg or environment.original_arguments
+ if noquote and #arg == 1 then
+ local a = arg[1]
+ a = resolvers.resolve(a)
+ a = unquote(a)
+ return a
+ elseif #arg > 0 then
+ local result = { }
+ for i=1,#arg do
+ local a = arg[i]
+ a = resolvers.resolve(a)
+ a = unquote(a)
+ a = gsub(a,'"','\\"') -- tricky
+ if find(a," ") then
+ result[#result+1] = quote(a)
+ else
+ result[#result+1] = a
+ end
+ end
+ return table.join(result," ")
+ else
+ return ""
+ end
+end
+
+if arg then
+
+ -- new, reconstruct quoted snippets (maybe better just remove the " then and add them later)
+ local newarg, instring = { }, false
+
+ for index=1,#arg do
+ local argument = arg[index]
+ if find(argument,"^\"") then
+ newarg[#newarg+1] = gsub(argument,"^\"","")
+ if not find(argument,"\"$") then
+ instring = true
+ end
+ elseif find(argument,"\"$") then
+ newarg[#newarg] = newarg[#newarg] .. " " .. gsub(argument,"\"$","")
+ instring = false
+ elseif instring then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument
+ else
+ newarg[#newarg+1] = argument
+ end
+ end
+ for i=1,-5,-1 do
+ newarg[i] = arg[i]
+ end
+
+ environment.initialize_arguments(newarg)
+ environment.original_arguments = newarg
+ environment.raw_arguments = arg
+
+ arg = { } -- prevent duplicate handling
+
+end
+
+-- weird place ... depends on a not yet loaded module
+
+function environment.texfile(filename)
+ return resolvers.find_file(filename,'tex')
+end
+
+function environment.luafile(filename)
+ local resolved = resolvers.find_file(filename,'tex') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ resolved = resolvers.find_file(filename,'texmfscripts') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ return resolvers.find_file(filename,'luatexlibs') or ""
+end
+
+environment.loadedluacode = loadfile -- can be overloaded
+
+--~ function environment.loadedluacode(name)
+--~ if os.spawn("texluac -s -o texluac.luc " .. name) == 0 then
+--~ local chunk = loadstring(io.loaddata("texluac.luc"))
+--~ os.remove("texluac.luc")
+--~ return chunk
+--~ else
+--~ environment.loadedluacode = loadfile -- can be overloaded
+--~ return loadfile(name)
+--~ end
+--~ end
+
+function environment.luafilechunk(filename) -- used for loading lua bytecode in the format
+ filename = file.replacesuffix(filename, "lua")
+ local fullname = environment.luafile(filename)
+ if fullname and fullname ~= "" then
+ if trace_locating then
+ logs.report("fileio","loading file %s", fullname)
+ end
+ return environment.loadedluacode(fullname)
+ else
+ if trace_locating then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ return nil
+ end
+end
+
+-- the next ones can use the previous ones / combine
+
+function environment.loadluafile(filename, version)
+ local lucname, luaname, chunk
+ local basename = file.removesuffix(filename)
+ if basename == filename then
+ lucname, luaname = basename .. ".luc", basename .. ".lua"
+ else
+ lucname, luaname = nil, basename -- forced suffix
+ end
+ -- when not overloaded by explicit suffix we look for a luc file first
+ local fullname = (lucname and environment.luafile(lucname)) or ""
+ if fullname ~= "" then
+ if trace_locating then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ end
+ if chunk then
+ assert(chunk)()
+ if version then
+ -- we check of the version number of this chunk matches
+ local v = version -- can be nil
+ if modules and modules[filename] then
+ v = modules[filename].version -- new method
+ elseif versions and versions[filename] then
+ v = versions[filename] -- old method
+ end
+ if v == version then
+ return true
+ else
+ if trace_locating then
+ logs.report("fileio","version mismatch for %s: lua=%s, luc=%s", filename, v, version)
+ end
+ environment.loadluafile(filename)
+ end
+ else
+ return true
+ end
+ end
+ fullname = (luaname and environment.luafile(luaname)) or ""
+ if fullname ~= "" then
+ if trace_locating then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ if not chunk then
+ if trace_locating then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ else
+ assert(chunk)()
+ return true
+ end
+ end
+ return false
+end
diff --git a/tex/context/base/luat-exe.lua b/tex/context/base/luat-exe.lua
new file mode 100644
index 000000000..ca3b75162
--- /dev/null
+++ b/tex/context/base/luat-exe.lua
@@ -0,0 +1,71 @@
+if not modules then modules = { } end modules ['luat-exe'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local match, find = string.match, string.find
+local concat = table.concat
+
+if not executer then executer = { } end
+
+executer.permitted = { }
+executer.execute = os.execute
+
+function executer.register(...)
+ local ep = executer.permitted
+ local t = { ... }
+ for k=1,#t do
+ local v = t[k]
+ ep[#ep+1] = (v == "*" and ".*") or v
+ end
+end
+
+function executer.finalize() -- todo: os.exec, todo: report ipv print
+ local execute = os.execute
+ function executer.execute(...)
+ local t, name, arguments = {...}, "", ""
+ if #t == 1 then
+ if type(t[1]) == 'table' then
+ name, arguments = t[1], concat(t," ",2,#t)
+ else
+ name, arguments = match(t[1],"^(.-)%s+(.+)$")
+ if not (name and arguments) then
+ name, arguments = t[1], ""
+ end
+ end
+ else
+ name, arguments = t[1], concat(t," ",2,#t)
+ end
+ local permitted = executer.permitted
+ for k=1,#permitted do
+ local v = permitted[k]
+ if find(name,v) then
+ execute(name .. " " .. arguments)
+ -- print("executed: " .. name .. " " .. arguments)
+ else
+ print("not permitted: " .. name .. " " .. arguments)
+ end
+ end
+ end
+ function executer.finalize()
+ print("executer is already finalized")
+ end
+ function executer.register(name)
+ print("executer is already finalized")
+ end
+ os.execute = executer.execute
+end
+
+--~ executer.register('.*')
+--~ executer.register('*')
+--~ executer.register('dir','ls')
+--~ executer.register('dir')
+
+--~ executer.finalize()
+--~ executer.execute('dir',"*.tex")
+--~ executer.execute("dir *.tex")
+--~ executer.execute("ls *.tex")
+--~ os.execute('ls')
diff --git a/tex/context/base/luat-fio.lua b/tex/context/base/luat-fio.lua
new file mode 100644
index 000000000..0d1bd1808
--- /dev/null
+++ b/tex/context/base/luat-fio.lua
@@ -0,0 +1,83 @@
+if not modules then modules = { } end modules ['luat-fio'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local texiowrite_nl = (texio and texio.write_nl) or print
+local texiowrite = (texio and texio.write) or print
+
+local format = string.format
+
+texconfig.kpse_init = false
+texconfig.trace_file_names = true -- also influences pdf fonts reporting .. todo
+texconfig.max_print_line = 100000
+
+kpse = { } setmetatable(kpse, { __index = function(k,v) return input[v] end } )
+
+-- if still present, we overload kpse (put it off-line so to say)
+
+if not resolvers.instance then
+
+ resolvers.reset()
+
+ resolvers.instance.progname = 'context'
+ resolvers.instance.engine = 'luatex'
+ resolvers.instance.validfile = resolvers.validctxfile
+
+ resolvers.load()
+
+ if callback then
+
+ callback.register('find_read_file' , function(id,name) return resolvers.findtexfile(name) end)
+ callback.register('open_read_file' , function( name) return resolvers.opentexfile(name) end)
+
+ callback.register('find_data_file' , function(name) return resolvers.findbinfile(name,"tex") end)
+ callback.register('find_enc_file' , function(name) return resolvers.findbinfile(name,"enc") end)
+ callback.register('find_font_file' , function(name) return resolvers.findbinfile(name,"tfm") end)
+ callback.register('find_format_file' , function(name) return resolvers.findbinfile(name,"fmt") end)
+ callback.register('find_image_file' , function(name) return resolvers.findbinfile(name,"tex") end)
+ callback.register('find_map_file' , function(name) return resolvers.findbinfile(name,"map") end)
+ callback.register('find_ocp_file' , function(name) return resolvers.findbinfile(name,"ocp") end)
+ callback.register('find_opentype_file' , function(name) return resolvers.findbinfile(name,"otf") end)
+ callback.register('find_output_file' , function(name) return name end)
+ callback.register('find_pk_file' , function(name) return resolvers.findbinfile(name,"pk") end)
+ callback.register('find_sfd_file' , function(name) return resolvers.findbinfile(name,"sfd") end)
+ callback.register('find_truetype_file' , function(name) return resolvers.findbinfile(name,"ttf") end)
+ callback.register('find_type1_file' , function(name) return resolvers.findbinfile(name,"pfb") end)
+ callback.register('find_vf_file' , function(name) return resolvers.findbinfile(name,"vf") end)
+
+ callback.register('read_data_file' , function(file) return resolvers.loadbinfile(file,"tex") end)
+ callback.register('read_enc_file' , function(file) return resolvers.loadbinfile(file,"enc") end)
+ callback.register('read_font_file' , function(file) return resolvers.loadbinfile(file,"tfm") end)
+ -- format
+ -- image
+ callback.register('read_map_file' , function(file) return resolvers.loadbinfile(file,"map") end)
+ callback.register('read_ocp_file' , function(file) return resolvers.loadbinfile(file,"ocp") end)
+ -- output
+ callback.register('read_pk_file' , function(file) return resolvers.loadbinfile(file,"pk") end) -- 600dpi/manfnt.720pk
+ callback.register('read_sfd_file' , function(file) return resolvers.loadbinfile(file,"sfd") end)
+ callback.register('read_vf_file' , function(file) return resolvers.loadbinfile(file,"vf" ) end)
+
+ callback.register('find_font_file' , function(name) return resolvers.findbinfile(name,"ofm") end)
+ callback.register('find_vf_file' , function(name) return resolvers.findbinfile(name,"ovf") end)
+
+ callback.register('read_font_file' , function(file) return resolvers.loadbinfile(file,"ofm") end)
+ callback.register('read_vf_file' , function(file) return resolvers.loadbinfile(file,"ovf") end)
+
+ -- callback.register('read_opentype_file' , function(file) return resolvers.loadbinfile(file,"otf") end)
+ -- callback.register('read_truetype_file' , function(file) return resolvers.loadbinfile(file,"ttf") end)
+ -- callback.register('read_type1_file' , function(file) return resolvers.loadbinfile(file,"pfb") end)
+
+ callback.register('find_write_file' , function(id,name) return name end)
+ callback.register('find_format_file' , function(name) return name end)
+
+ end
+
+end
+
+statistics.register("input load time", function()
+ return format("%s seconds", statistics.elapsedtime(resolvers.instance))
+end)
diff --git a/tex/context/base/luat-ini.lua b/tex/context/base/luat-ini.lua
new file mode 100644
index 000000000..e6a715c07
--- /dev/null
+++ b/tex/context/base/luat-ini.lua
@@ -0,0 +1,162 @@
+if not modules then modules = { } end modules ['luat-ini'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--~ local ctxcatcodes = tex.ctxcatcodes
+
+--[[ldx--
+
We cannot load anything yet. However what we will do us reserve a fewtables.
+These can be used for runtime user data or third party modules and will not be
+cluttered by macro package code.
+--ldx]]--
+
+userdata = userdata or { } -- might be used
+thirddata = thirddata or { } -- might be used
+moduledata = moduledata or { } -- might be used
+document = document or { }
+parametersets = parametersets or { } -- experimental
+
+--[[ldx--
+
These can be used/set by the caller program; mtx-context.lua does it.
+--ldx]]--
+
+document.arguments = document.arguments or { }
+document.files = document.files or { }
+
+--[[ldx--
+
Please create a namespace within these tables before using them!
We could cook up a readonly model for global tables but it
+makes more sense to invite users to use one of the predefined
+namespaces. One can redefine the protector. After all, it's
+just a lightweight suggestive system, not a watertight
+one.
+--ldx]]--
+
+local debug = require "debug"
+
+local string, table, lpeg, math, io, system = string, table, lpeg, math, io, system
+local next, setfenv = next, setfenv or debug.setfenv
+local format = string.format
+
+local global = _G
+
+global.global = global
+
+local dummy = function() end
+
+local protected = {
+ -- global table
+ global = global,
+ -- user tables
+ userdata = userdata,
+ moduledata = moduledata,
+ thirddata = thirddata,
+ document = document,
+ -- reserved
+ protect = dummy,
+ unprotect = dummy,
+ -- luatex
+ tex = tex,
+ -- lua
+ string = string,
+ table = table,
+ lpeg = lpeg,
+ math = math,
+ io = io,
+ system = system,
+}
+
+userdata, thirddata, moduledata = nil, nil, nil
+
+if not setfenv then
+ texio.write_nl("warning: we need to fix setfenv by using 'load in' or '_ENV'")
+end
+
+function protect(name)
+ if name == "isolateddata" then
+ local t = { }
+ for k, v in next, protected do
+ t[k] = v
+ end
+ setfenv(2,t)
+ else
+ if not name then
+ name = "shareddata"
+ end
+ local t = global[name]
+ if not t then
+ t = { }
+ for k, v in next, protected do
+ t[k] = v
+ end
+ global[name] = t
+ end
+ setfenv(2,t)
+ end
+end
+
+lua.numbers = { }
+lua.messages = { }
+
+function lua.registername(name,message)
+ local lnn = lua.numbers[name]
+ if not lnn then
+ lnn = #lua.messages + 1
+ lua.messages[lnn] = message
+ lua.numbers[name] = lnn
+ end
+ lua.name[lnn] = message
+ tex.write(lnn)
+end
+
+--~ function lua.checknames()
+--~ lua.name[0] = "ctx"
+--~ for k, v in next, lua.messages do
+--~ lua.name[k] = v
+--~ end
+--~ end
+
+storage.register("lua/numbers", lua.numbers, "lua.numbers")
+storage.register("lua/messages", lua.messages, "lua.messages")
+
+--~ local arguments, files = document.arguments, document.files -- set later
+
+function document.setargument(key,value)
+ document.arguments[key] = value
+end
+
+function document.setdefaultargument(key,default)
+ local v = document.arguments[key]
+ if v == nil or v == "" then
+ document.arguments[key] = default
+ end
+end
+
+function document.getargument(key,default)
+ local v = document.arguments[key]
+ if type(v) == "boolean" then
+ v = (v and "yes") or "no"
+ document.arguments[key] = v
+ end
+ tex.sprint(tex.ctxcatcodes,v or default or "")
+end
+
+function document.setfilename(i,name)
+ document.files[tonumber(i)] = name
+end
+
+function document.getfilename(i)
+ tex.sprint(tex.ctxcatcodes,document.files[i] or "")
+end
diff --git a/tex/context/base/luat-ini.mkiv b/tex/context/base/luat-ini.mkiv
new file mode 100644
index 000000000..c9d88bf4f
--- /dev/null
+++ b/tex/context/base/luat-ini.mkiv
@@ -0,0 +1,243 @@
+%D \module
+%D [ file=luat-ini,
+%D version=2005.08.11,
+%D title=\CONTEXT\ Lua Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 Lua Macros / Initialization}
+
+\unprotect
+
+%D Loading lua code can be done using \type {startup.lua}. The following
+%D method uses the \TEX\ input file locator of kpse. At least we need to
+%D use that way of loading when we haven't yet define our own code, which
+%D we keep outside the format. We will keep code outside \TEX\ files as
+%D much as possible.
+
+\ifx\setnaturalcatcodes\undefined \let\setnaturalcatcodes\relax \fi
+\ifx\obeylualines \undefined \let\obeylualines \relax \fi
+\ifx\obeyluatokens \undefined \let\obeyluatokens \relax \fi
+
+%D A few more goodies:
+
+\long\def\dostartlua
+ {\begingroup
+ \obeylualines
+ \dodostartlua}
+
+\long\def\dodostartlua#1\stoplua
+ {\normalexpanded{\endgroup\noexpand\directlua\zerocount{#1}}}
+
+\long\def\dostartluacode
+ {\begingroup
+ \obeylualines
+ \obeyluatokens
+ \dodostartluacode}
+
+\long\def\dodostartluacode#1\stopluacode
+ {\normalexpanded{\endgroup\noexpand\directlua\zerocount{#1}}}
+
+\unexpanded\def\startlua {\dostartlua } % tex catcodes
+\unexpanded\def\startluacode{\dostartluacode} % lua catcodes
+
+%D Some delayed definitions:
+
+\ifx\obeylines \undefined \let\obeylines \relax \fi
+\ifx\obeyedline \undefined \let\obeyedline \relax \fi
+\ifx\obeyspaces \undefined \let\obeyspaces \relax \fi
+\ifx\obeyedspace \undefined \let\obeyedspace \relax \fi
+\ifx\outputnewlinechar\undefined \let\outputnewlinechar\relax \fi
+
+%D A previous version used a bit less code and no catcode table,
+%D simply becaus ethey were not around at the time of writing.
+%
+% we keep it around for archival purposes
+%
+% \def\obeylualines
+% {\obeylines \let\obeyedline \outputnewlinechar
+% \obeyspaces \let\obeyedspace\space}
+%
+% \def\obeyluatokens % todo: make this a proper catcode table, use let's
+% {\catcode`\%=12 \catcode`\#=12
+% \catcode`\_=12 \catcode`\^=12
+% \catcode`\&=12 \catcode`\|=12
+% \catcode`\{=12 \catcode`\}=12
+% \catcode`\~=12 \catcode`\$=12
+% \def\\{\string\\}\def\|{\string\|}\def\-{\string\-}%
+% \def\({\string\(}\def\){\string\)}\def\{{\string\{}\def\}{\string\}}%
+% \def\'{\string\'}\def\"{\string\"}%
+% \def\n{\string\n}\def\r{\string\r}\def\f{\string\f}\def\t{\string\t}%
+% \def\a{\string\a}\def\b{\string\b}\def\v{\string\v}\def\s{\string\s}%
+% \def\1{\string\1}\def\2{\string\2}\def\3{\string\3}\def\4{\string\4}\def\5{\string\5}%
+% \def\6{\string\6}\def\7{\string\7}\def\8{\string\8}\def\9{\string\9}\def\0{\string\0}}
+
+\let\obeylualines\relax
+
+\newtoks\everyluacode
+
+\edef\lualetterbackslash{\string\\}
+\edef\lualetterbar {\string\|} \edef\lualetterdash {\string\-}
+\edef\lualetterlparent {\string\(} \edef\lualetterrparent {\string\)}
+\edef\lualetterlbrace {\string\{} \edef\lualetterrbrace {\string\}}
+\edef\lualettersquote {\string\'} \edef\lualetterdquote {\string\"}
+\edef\lualettern {\string\n} \edef\lualetterr {\string\r}
+\edef\lualetterf {\string\f} \edef\lualettert {\string\t}
+\edef\lualettera {\string\a} \edef\lualetterb {\string\b}
+\edef\lualetterv {\string\v} \edef\lualetters {\string\s}
+\edef\lualetterone {\string\1} \edef\lualettertwo {\string\2}
+\edef\lualetterthree {\string\3} \edef\lualetterfour {\string\4}
+\edef\lualetterfive {\string\5} \edef\lualettersix {\string\6}
+\edef\lualetterseven {\string\7} \edef\lualettereight {\string\8}
+\edef\lualetternine {\string\9} \edef\lualetterzero {\string\0}
+
+\appendtoks
+ \let\\\lualetterbackslash
+ \let\|\lualetterbar \let\-\lualetterdash
+ \let\(\lualetterlparent \let\)\lualetterrparent
+ \let\{\lualetterlbrace \let\}\lualetterrbrace
+ \let\'\lualettersquote \let\"\lualetterdquote
+ \let\n\lualettern \let\r\lualetterr
+ \let\f\lualetterf \let\t\lualettert
+ \let\a\lualettera \let\b\lualetterb
+ \let\v\lualetterv \let\s\lualetters
+ \let\1\lualetterone \let\2\lualettertwo
+ \let\3\lualetterthree \let\4\lualetterfour
+ \let\5\lualetterfive \let\6\lualettersix
+ \let\7\lualetterseven \let\8\lualettereight
+ \let\9\lualetternine \let\0\lualetterzero
+\to \everyluacode
+
+\def\obeyluatokens
+ {\setcatcodetable \luacatcodes
+ \the\everyluacode}
+
+%D \macros
+%D {definenamedlua}
+%D
+%D We provide an interface for defining instances:
+
+\def\s!lua{lua} \def\v!code{code} \def\!!name{name} \def\s!data{data}
+
+%D Beware: because \type {\expanded} is een convert command, the error
+%D message will show \type{} as part of the message.
+
+\long\def\dostartnamedluacode#1%
+ {\begingroup
+ \obeylualines
+ \obeyluatokens
+ \csname dodostartnamed#1\v!code\endcsname}
+
+\unexpanded\def\definenamedlua[#1]#2[#3]% no optional arg handling here yet
+ {\scratchcounter\ctxlua{lua.registername("#1","#3")}%
+ \normalexpanded{\long\edef\csname dodostartnamed#1\v!code\endcsname##1\csname\e!stop#1\v!code\endcsname}%
+ {\endgroup\noexpand\directlua\the\scratchcounter{protect("#1\s!data")##1}}%
+ \long\expandafter\def \csname\e!start#1\v!code\endcsname {\dostartnamedluacode{#1}}%
+ \long\expandafter\edef\csname #1\v!code\endcsname##1{\noexpand\directlua\the\scratchcounter{protect("#1\s!data")##1}}}
+
+%D We predefine a few.
+
+\definenamedlua[user] [private user instance]
+\definenamedlua[third] [third party module instance]
+\definenamedlua[module] [module instance]
+\definenamedlua[isolated][isolated instance]
+
+%D In practice this works out as follows:
+%D
+%D \startbuffer
+%D \startluacode
+%D tex.print("LUA")
+%D \stopluacode
+%D
+%D \startusercode
+%D global.tex.print("USER 1")
+%D tex.print("USER 2")
+%D if characters then
+%D tex.print("ACCESS")
+%D else
+%D tex.print("NO ACCESS")
+%D end
+%D \stopusercode
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D We need a way to pass strings safely to \LUA\ without the
+%D need for tricky escaping. Compare:
+%D
+%D \starttyping
+%D \ctxlua {something("anything tricky can go here")}
+%D \ctxlua {something([\luastringsep[anything tricky can go here]\luastringsep])}
+%D \stoptyping
+
+\def\luastringsep{===} % this permits \typefile{self} otherwise nested b/e sep problems
+
+\edef\!!bs{[\luastringsep[}
+\edef\!!es{]\luastringsep]}
+
+%D We have a the following available as primitive so there is no need
+%D for it:
+%D
+%D \starttyping
+%D \long\edef\luaescapestring#1{\!!bs#1\!!es}
+%D \stoptyping
+
+\def\setdocumentfilename #1#2{\ctxlua{document.setfilename(#1,"#2")}}
+\def\setdocumentargument #1#2{\ctxlua{document.setargument("#1","#2")}}
+\def\setdocumentargumentdefault#1#2{\ctxlua{document.setdefaultargument("#1","#2")}}
+\def\getdocumentfilename #1{\ctxlua{document.getfilename("#1")}}
+\def\getdocumentargument #1{\ctxlua{document.getargument("#1")}}
+\def\getdocumentargumentdefault#1#2{\ctxlua{document.getargument("#1","#2")}}
+\def\doifdocumentargumentelse #1{\doifsomethingelse{\getdocumentargument{#1}}}
+\def\doifdocumentargument #1{\doifsomething {\getdocumentargument{#1}}}
+\def\doifnotdocumentargument #1{\doifnothing {\getdocumentargument{#1}}}
+\def\doifdocumentfilenameelse #1{\doifsomethingelse{\getdocumentfilename{#1}}}
+\def\doifdocumentfilename #1{\doifsomething {\getdocumentfilename{#1}}}
+\def\doifnotdocumentfilename #1{\doifnothing {\getdocumentfilename{#1}}}
+
+\let\doifelsedocumentargument\doifdocumentargumentelse
+
+%D A handy helper:
+
+\def\luaexpanded#1{\luaescapestring\expandafter{\normalexpanded{#1}}}
+
+%D Experimental:
+
+\unexpanded\def\startluaparameterset[#1]%
+ {\begingroup
+ \obeylualines
+ \obeyluatokens
+ \dostartluaparameterset{#1}}
+
+\long\def\dostartluaparameterset#1#2\stopluaparameterset
+ {\ctxlua{parametersets["#1"]={#2}}%
+ \endgroup}
+
+\def\luaparameterset#1#2{\ctxlua{parametersets["#1"]={#2} tex.sprint("#1")}}
+
+% todo: \mergeparameterset
+
+% usage:
+%
+% \startluaparameterset [u3d:myset:display:1]
+% toolbar=false,
+% tree=true
+% \stopluaparameterset
+%
+% options=u3d:myset:display:1
+%
+% or:
+%
+% options=\luaparameterset{u3d:myset:display:1}{toolbar=false,tree=true}
+
+%D A Handy helper:
+
+\def\luaconditional#1{\ifcase#1tru\else fals\fi e}
+
+\protect \endinput
diff --git a/tex/context/base/luat-iop.lua b/tex/context/base/luat-iop.lua
new file mode 100644
index 000000000..e5722d2bd
--- /dev/null
+++ b/tex/context/base/luat-iop.lua
@@ -0,0 +1,148 @@
+if not modules then modules = { } end modules ['luat-iop'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this paranoid stuff in web2c ... we cannot hook checks into the
+-- input functions because one can always change the callback but
+-- we can feed back specific patterns and paths into the next
+-- mechanism
+
+local lower, find, sub = string.lower, string.find, string.sub
+
+local ioinp = io.inp if not ioinp then ioinp = { } io.inp = ioinp end
+local ioout = io.out if not ioout then ioout = { } io.out = ioout end
+
+ioinp.modes, ioout.modes = { }, { } -- functions
+
+local inp_blocked, inp_permitted = { }, { }
+local out_blocked, out_permitted = { }, { }
+
+local function i_inhibit(name) inp_blocked [#inp_blocked +1] = name end
+local function o_inhibit(name) out_blocked [#out_blocked +1] = name end
+local function i_permit (name) inp_permitted[#inp_permitted+1] = name end
+local function o_permit (name) out_permitted[#out_permitted+1] = name end
+
+ioinp.inhibit, ioinp.permit = i_inhibit, o_permit
+ioout.inhibit, ioout.permit = o_inhibit, o_permit
+
+local blocked_openers = { } -- *.open(name,method)
+
+function io.register_opener(func)
+ blocked_openers[#blocked_openers+1] = func
+end
+
+local function checked(name,blocked,permitted)
+ local n = lower(name)
+ for _,b in next, blocked do
+ if find(n,b) then
+ for _,p in next, permitted do
+ if find(n,p) then
+ return true
+ end
+ end
+ return false
+ end
+ end
+ return true
+end
+
+function io.finalize_openers(func)
+ if #out_blocked > 0 or #inp_blocked > 0 then
+ local open = func -- why not directly?
+ return function(name,method)
+ if method and find(method,'[wa]') then
+ if #out_blocked > 0 and not checked(name,out_blocked,out_permitted) then
+ -- print("writing to " .. name .. " is not permitted")
+ return nil
+ end
+ else
+ if #inp_blocked > 0 and not checked(name,inp_blocked,inp_permitted) then
+ -- print("reading from " .. name .. " is not permitted")
+ return nil
+ end
+ end
+ return open(name,method)
+ end
+ else
+ return func
+ end
+end
+
+--~ io.inp.inhibit('^%.')
+--~ io.inp.inhibit('^/etc')
+--~ io.inp.inhibit('/windows/')
+--~ io.inp.inhibit('/winnt/')
+--~ io.inp.permit('c:/windows/wmsetup.log')
+
+--~ io.open = io.finalize_openers(io.open)
+
+--~ f = io.open('.tex') print(f)
+--~ f = io.open('tufte.tex') print(f)
+--~ f = io.open('t:/sources/tufte.tex') print(f)
+--~ f = io.open('/etc/passwd') print(f)
+--~ f = io.open('c:/windows/crap.log') print(f)
+--~ f = io.open('c:/windows/wmsetup.log') print(f)
+
+local inpout = { 'inp', 'out' }
+
+function io.set_opener_modes(i,o)
+ local first = sub(i,1,1)
+ for k=1,#inpout do
+ local iov = io[inpout[k]]
+ local f = iov[i] or iov[first]
+ if f then f() end
+ end
+ io.open = io.finalize_openers(io.open)
+end
+
+-- restricted
+
+function ioinp.modes.restricted()
+ i_inhibit('^%.[%a]')
+end
+
+function ioout.modes.restricted()
+ o_inhibit('^%.[%a]')
+end
+
+-- paranoid
+
+function ioinp.modes.paranoid()
+ i_inhibit('.*')
+ i_inhibit('%.%.')
+ i_permit('^%./')
+ i_permit('[^/]')
+ resolvers.do_with_path('TEXMF',i_permit)
+end
+
+function ioout.modes.paranoid()
+ o_inhibit('.*')
+ resolvers.do_with_path('TEXMFOUTPUT',o_permit)
+end
+
+-- handy
+
+function ioinp.modes.handy()
+ i_inhibit('%.%.')
+ if os.type == 'windows' then
+ i_inhibit('/windows/')
+ i_inhibit('/winnt/')
+ else
+ i_inhibit('^/etc')
+ end
+end
+
+function ioout.modes.handy()
+ o_inhibit('.*')
+ o_permit('%./')
+ o_permit('^%./')
+ o_permit('[^/]')
+end
+
+--~ io.set_opener_modes('p','p')
+--~ io.set_opener_modes('r','r')
+--~ io.set_opener_modes('h','h')
diff --git a/tex/context/base/luat-lib.mkiv b/tex/context/base/luat-lib.mkiv
new file mode 100644
index 000000000..91ddec0aa
--- /dev/null
+++ b/tex/context/base/luat-lib.mkiv
@@ -0,0 +1,70 @@
+%D \module
+%D [ file=luat-lib,
+%D version=2006.09.11,
+%D title=\CONTEXT\ Lua Macros,
+%D subtitle=Libraries,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 Lua Macros / Libraries}
+
+\registerctxluafile{trac-inf} {1.001}
+\registerctxluafile{trac-tra} {1.001}
+\registerctxluafile{trac-log} {1.001}
+
+\registerctxluafile{luat-cbk} {1.001}
+
+\registerctxluafile{data-res} {1.001}
+\registerctxluafile{data-tmp} {1.001}
+\registerctxluafile{data-pre} {1.001}
+\registerctxluafile{data-inp} {1.001}
+\registerctxluafile{data-out} {1.001}
+\registerctxluafile{data-tex} {1.001}
+\registerctxluafile{data-bin} {1.001}
+\registerctxluafile{data-zip} {1.001}
+%registerctxluafile{data-crl} {1.001}
+\registerctxluafile{data-sch} {1.001}
+\registerctxluafile{data-tre} {1.001}
+\registerctxluafile{data-lua} {1.001}
+\registerctxluafile{data-ctx} {1.001}
+\registerctxluafile{data-con} {1.001}
+\registerctxluafile{data-use} {1.001}
+
+\registerctxluafile{luat-run} {1.001}
+\registerctxluafile{luat-fio} {1.001} % not needed, part of startup file
+\registerctxluafile{luat-cnf} {1.001} % not needed, part of startup file
+\registerctxluafile{luat-lua} {1.001}
+\registerctxluafile{luat-sto} {1.001}
+\registerctxluafile{luat-ini} {1.001}
+\registerctxluafile{luat-env} {1.001}
+
+\registerctxluafile{lxml-tab} {1.001}
+\registerctxluafile{lxml-lpt} {1.001}
+\registerctxluafile{lxml-xml} {1.001}
+\registerctxluafile{lxml-aux} {1.001}
+\registerctxluafile{lxml-mis} {1.001}
+
+\startruntimeluacode
+ \edef\asciia{\ctxlua{tex.sprint(logs.mode)}}
+ \edef\asciib{xml}
+ \ifx\asciia\asciib % brrr
+ \long\def\writebanner #1{\writestring {#1}}
+ \long\def\writestatus#1#2{\writestring {#2}}
+ \long\def\message #1{\normalmessage{#1}}
+ \else
+ \let\writebanner\writestring
+ %\let\writestatus\normalwritestatus
+ \let\message \normalmessage
+ \fi
+\stopruntimeluacode
+
+%registerctxluafile{luat-tmp}{1.001}
+\registerctxluafile{luat-exe}{1.001}
+\registerctxluafile{luat-iop}{1.001}
+
+\endinput
diff --git a/tex/context/base/luat-lua.lua b/tex/context/base/luat-lua.lua
new file mode 100644
index 000000000..b964bf8e8
--- /dev/null
+++ b/tex/context/base/luat-lua.lua
@@ -0,0 +1,43 @@
+if not modules then modules = { } end modules ['luat-lua'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if lua then do
+
+ local delayed = { }
+
+ function lua.delay(f)
+ delayed[#delayed+1] = f
+ end
+
+ function lua.flush_delayed(...)
+ local t = delayed
+ delayed = { }
+ for i=1, #t do
+ t[i](...)
+ end
+ end
+
+ function lua.flush(...)
+ tex.sprint("\\directlua0{lua.flush_delayed(",table.concat({...},','),")}")
+ end
+
+end end
+
+--~ See mk.pdf for an explanation of the following code:
+--~
+--~ function test(n)
+--~ lua.delay(function(...)
+--~ tex.sprint(string.format("pi: %s %s %s\\par",...))
+--~ end)
+--~ lua.delay(function(...)
+--~ tex.sprint(string.format("more pi: %s %s %s\\par",...))
+--~ end)
+--~ tex.sprint(string.format("\\setbox0=\\hbox{%s}",math.pi*n))
+--~ local box = tex.box[0]
+--~ lua.flush(box.width,box.height,box.depth)
+--~ end
diff --git a/tex/context/base/luat-run.lua b/tex/context/base/luat-run.lua
new file mode 100644
index 000000000..b64a99fc6
--- /dev/null
+++ b/tex/context/base/luat-run.lua
@@ -0,0 +1,74 @@
+if not modules then modules = { } end modules ['luat-run'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, rpadd = string.format, string.rpadd
+
+main = main or { }
+
+local start_actions = { }
+local stop_actions = { }
+
+function main.register_start_actions(...) table.insert(start_actions, ...) end
+function main.register_stop_actions (...) table.insert(stop_actions, ...) end
+
+main.show_tex_stat = main.show_tex_stat or function() end
+main.show_job_stat = main.show_job_stat or statistics.show_job_stat
+
+function main.start()
+ if logs.start_run then
+ logs.start_run()
+ end
+ for _, action in next, start_actions do
+ action()
+ end
+end
+
+function main.stop()
+ for _, action in next, stop_actions do
+ action()
+ end
+ if main.show_job_stat then
+ statistics.show(logs.report_job_stat)
+ end
+ if main.show_tex_stat then
+ for k,v in next, status.list() do
+ logs.report_tex_stat(k,v)
+ end
+ end
+ if logs.stop_run then
+ logs.stop_run()
+ end
+end
+
+function main.start_shipout_page()
+ logs.start_page_number()
+end
+
+function main.stop_shipout_page()
+ logs.stop_page_number()
+end
+
+function main.report_output_pages()
+end
+
+function main.report_output_log()
+end
+
+-- this can be done later
+
+callbacks.register('start_run', main.start, "actions performed at the beginning of a run")
+callbacks.register('stop_run', main.stop, "actions performed at the end of a run")
+
+callbacks.register('report_output_pages', main.report_output_pages, "actions performed when reporting pages")
+callbacks.register('report_output_log', main.report_output_log, "actions performed when reporting log file")
+
+callbacks.register('start_page_number', main.start_shipout_page, "actions performed at the beginning of a shipout")
+callbacks.register('stop_page_number', main.stop_shipout_page, "actions performed at the end of a shipout")
+
+callbacks.register('process_input_buffer', false, "actions performed when reading data")
+callbacks.register('process_output_buffer', false, "actions performed when writing data")
diff --git a/tex/context/base/luat-soc.lua b/tex/context/base/luat-soc.lua
new file mode 100644
index 000000000..1095ed087
--- /dev/null
+++ b/tex/context/base/luat-soc.lua
@@ -0,0 +1,11 @@
+-- This is just a loader. The package handler knows about the TEX tree.
+
+--~ require "luatex/lua/socket.lua"
+--~ require "luatex/lua/ltn12.lua"
+--~ require "luatex/lua/mime.lua"
+--~ require "luatex/lua/socket/http.lua"
+--~ require "luatex/lua/socket/url.lua"
+--~ require "luatex/lua/socket/tp.lua"
+--~ require "luatex/lua/socket/ftp.lua"
+
+-- "luatex/lua/socket/smtp.lua"
diff --git a/tex/context/base/luat-sta.lua b/tex/context/base/luat-sta.lua
new file mode 100644
index 000000000..a81b0c206
--- /dev/null
+++ b/tex/context/base/luat-sta.lua
@@ -0,0 +1,196 @@
+if not modules then modules = { } end modules ['luat-sta'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this code is used in the updater
+
+local gmatch, match = string.gmatch, string.match
+local type = type
+
+states = states or { }
+states.data = states.data or { }
+states.hash = states.hash or { }
+states.tag = states.tag or ""
+states.filename = states.filename or ""
+
+function states.save(filename,tag)
+ tag = tag or states.tag
+ filename = file.addsuffix(filename or states.filename,'lus')
+ io.savedata(filename,
+ "-- generator : luat-sta.lua\n" ..
+ "-- state tag : " .. tag .. "\n\n" ..
+ table.serialize(states.data[tag or states.tag] or {},true)
+ )
+end
+
+function states.load(filename,tag)
+ states.filename = filename
+ states.tag = tag or "whatever"
+ states.filename = file.addsuffix(states.filename,'lus')
+ states.data[states.tag], states.hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { }
+end
+
+function states.set_by_tag(tag,key,value,default,persistent)
+ local d, h = states.data[tag], states.hash[tag]
+ if d then
+ if type(d) == "table" then
+ local dkey, hkey = key, key
+ local pre, post = match(key,"(.+)%.([^%.]+)$")
+ if pre and post then
+ for k in gmatch(pre,"[^%.]+") do
+ local dk = d[k]
+ if not dk then
+ dk = { }
+ d[k] = dk
+ elseif type(dk) == "string" then
+ -- invalid table, unable to upgrade structure
+ -- hope for the best or delete the state file
+ break
+ end
+ d = dk
+ end
+ dkey, hkey = post, key
+ end
+ if type(value) == nil then
+ value = value or default
+ elseif persistent then
+ value = value or d[dkey] or default
+ else
+ value = value or default
+ end
+ d[dkey], h[hkey] = value, value
+ elseif type(d) == "string" then
+ -- weird
+ states.data[tag], states.hash[tag] = value, value
+ end
+ end
+end
+
+function states.get_by_tag(tag,key,default)
+ local h = states.hash[tag]
+ if h and h[key] then
+ return h[key]
+ else
+ local d = states.data[tag]
+ if d then
+ for k in gmatch(key,"[^%.]+") do
+ local dk = d[k]
+ if dk then
+ d = dk
+ else
+ return default
+ end
+ end
+ return d or default
+ end
+ end
+end
+
+function states.set(key,value,default,persistent)
+ states.set_by_tag(states.tag,key,value,default,persistent)
+end
+
+function states.get(key,default)
+ return states.get_by_tag(states.tag,key,default)
+end
+
+--~ states.data.update = {
+--~ ["version"] = {
+--~ ["major"] = 0,
+--~ ["minor"] = 1,
+--~ },
+--~ ["rsync"] = {
+--~ ["server"] = "contextgarden.net",
+--~ ["module"] = "minimals",
+--~ ["repository"] = "current",
+--~ ["flags"] = "-rpztlv --stats",
+--~ },
+--~ ["tasks"] = {
+--~ ["update"] = true,
+--~ ["make"] = true,
+--~ ["delete"] = false,
+--~ },
+--~ ["platform"] = {
+--~ ["host"] = true,
+--~ ["other"] = {
+--~ ["mswin"] = false,
+--~ ["linux"] = false,
+--~ ["linux-64"] = false,
+--~ ["osx-intel"] = false,
+--~ ["osx-ppc"] = false,
+--~ ["sun"] = false,
+--~ },
+--~ },
+--~ ["context"] = {
+--~ ["available"] = {"current", "beta", "alpha", "experimental"},
+--~ ["selected"] = "current",
+--~ },
+--~ ["formats"] = {
+--~ ["cont-en"] = true,
+--~ ["cont-nl"] = true,
+--~ ["cont-de"] = false,
+--~ ["cont-cz"] = false,
+--~ ["cont-fr"] = false,
+--~ ["cont-ro"] = false,
+--~ },
+--~ ["engine"] = {
+--~ ["pdftex"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ ["pdftex"] = true,
+--~ },
+--~ },
+--~ ["luatex"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ },
+--~ },
+--~ ["xetex"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ ["xetex"] = false,
+--~ },
+--~ },
+--~ ["metapost"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ ["mpost"] = true,
+--~ ["metafun"] = true,
+--~ },
+--~ },
+--~ },
+--~ ["fonts"] = {
+--~ },
+--~ ["doc"] = {
+--~ },
+--~ ["modules"] = {
+--~ ["f-urwgaramond"] = false,
+--~ ["f-urwgothic"] = false,
+--~ ["t-bnf"] = false,
+--~ ["t-chromato"] = false,
+--~ ["t-cmscbf"] = false,
+--~ ["t-cmttbf"] = false,
+--~ ["t-construction-plan"] = false,
+--~ ["t-degrade"] = false,
+--~ ["t-french"] = false,
+--~ ["t-lettrine"] = false,
+--~ ["t-lilypond"] = false,
+--~ ["t-mathsets"] = false,
+--~ ["t-tikz"] = false,
+--~ ["t-typearea"] = false,
+--~ ["t-vim"] = false,
+--~ },
+--~ }
+
+--~ states.save("teststate", "update")
+--~ states.load("teststate", "update")
+
+--~ print(states.get_by_tag("update","rsync.server","unknown"))
+--~ states.set_by_tag("update","rsync.server","oeps")
+--~ print(states.get_by_tag("update","rsync.server","unknown"))
+--~ states.save("teststate", "update")
+--~ states.load("teststate", "update")
+--~ print(states.get_by_tag("update","rsync.server","unknown"))
diff --git a/tex/context/base/luat-sto.lua b/tex/context/base/luat-sto.lua
new file mode 100644
index 000000000..08da735db
--- /dev/null
+++ b/tex/context/base/luat-sto.lua
@@ -0,0 +1,135 @@
+if not modules then modules = { } end modules ['luat-sto'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, next = type, next
+local gmatch, format, write_nl = string.gmatch, string.format, texio.write_nl
+
+storage = storage or { }
+storage.min = 0 -- 500
+storage.max = storage.min - 1
+storage.noftables = storage.noftables or 0
+storage.nofmodules = storage.nofmodules or 0
+storage.data = { }
+storage.evaluators = { }
+
+local evaluators = storage.evaluators -- (evaluate,message,names)
+local data = storage.data
+
+function storage.register(...)
+ data[#data+1] = { ... }
+end
+
+-- evaluators .. messy .. to be redone
+
+function storage.evaluate(name)
+ evaluators[#evaluators+1] = name
+end
+
+function storage.finalize() -- we can prepend the string with "evaluate:"
+ for i=1,#evaluators do
+ local t = evaluators[i]
+ for i, v in next, t do
+ local tv = type(v)
+ if tv == "string" then
+ t[i] = loadstring(v)()
+ elseif tv == "table" then
+ for _, vv in next, v do
+ if type(vv) == "string" then
+ t[i] = loadstring(vv)()
+ end
+ end
+ elseif tv == "function" then
+ t[i] = v()
+ end
+ end
+ end
+end
+
+function storage.dump()
+ for i=1,#data do
+ local d = data[i]
+ local message, original, target, evaluate = d[1], d[2] ,d[3] ,d[4]
+ local name, initialize, finalize, code = nil, "", "", ""
+ for str in gmatch(target,"([^%.]+)") do
+ if name then
+ name = name .. "." .. str
+ else
+ name = str
+ end
+ initialize = format("%s %s = %s or {} ", initialize, name, name)
+ end
+ if evaluate then
+ finalize = "storage.evaluate(" .. name .. ")"
+ end
+ storage.max = storage.max + 1
+ if trace_storage then
+ logs.report('storage','saving %s in slot %s',message,storage.max)
+ code =
+ initialize ..
+ format("logs.report('storage','restoring %s from slot %s') ",message,storage.max) ..
+ table.serialize(original,name) ..
+ finalize
+ else
+ code = initialize .. table.serialize(original,name) .. finalize
+ end
+ lua.bytecode[storage.max] = loadstring(code)
+ collectgarbage("step")
+ end
+end
+
+-- we also need to count at generation time (nicer for message)
+
+if lua.bytecode then -- from 0 upwards
+ local i, b = storage.min, lua.bytecode
+ while b[i] do
+ storage.noftables = i
+ b[i]()
+ b[i] = nil
+ i = i + 1
+ end
+end
+
+statistics.register("stored bytecode data", function()
+ local modules = (storage.nofmodules > 0 and storage.nofmodules) or (status.luabytecodes - 500)
+ local dumps = (storage.noftables > 0 and storage.noftables) or storage.max-storage.min + 1
+ return format("%s modules, %s tables, %s chunks",modules,dumps,modules+dumps)
+end)
+
+if lua.bytedata then
+ storage.register("lua/bytedata",lua.bytedata,"lua.bytedata")
+end
+
+-- wrong place, kind of forward reference
+
+function statistics.report_storage(whereto)
+ whereto = whereto or "term and log"
+ write_nl(whereto," ","stored tables:"," ")
+ for k,v in table.sortedhash(storage.data) do
+ write_nl(whereto,format("%03i %s",k,v[1]))
+ end
+ write_nl(whereto," ","stored modules:"," ")
+ for k,v in table.sortedhash(lua.bytedata) do
+ write_nl(whereto,format("%03i %s %s",k,v[2],v[1]))
+ end
+ write_nl(whereto," ","stored attributes:"," ")
+ for k,v in table.sortedhash(attributes.names) do
+ write_nl(whereto,format("%03i %s",k,v))
+ end
+ write_nl(whereto," ","stored catcodetables:"," ")
+ for k,v in table.sortedhash(catcodes.names) do
+ write_nl(whereto,format("%03i %s",k,table.concat(v," ")))
+ end
+ write_nl(whereto," ")
+end
+
+storage.shared = storage.shared or { }
+
+-- Because the storage mechanism assumes tables, we define a table for storing
+-- (non table) values.
+
+storage.register("storage/shared", storage.shared, "storage.shared")
diff --git a/tex/context/base/lxml-aux.lua b/tex/context/base/lxml-aux.lua
new file mode 100644
index 000000000..00f791909
--- /dev/null
+++ b/tex/context/base/lxml-aux.lua
@@ -0,0 +1,543 @@
+if not modules then modules = { } end modules ['lxml-aux'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- not all functions here make sense anymore vbut we keep them for
+-- compatibility reasons
+
+local trace_manipulations = false trackers.register("lxml.manipulations", function(v) trace_manipulations = v end)
+
+local xmlparseapply, xmlconvert, xmlcopy, xmlname = xml.parse_apply, xml.convert, xml.copy, xml.name
+local xmlinheritedconvert = xml.inheritedconvert
+
+local type = type
+local insert, remove = table.insert, table.remove
+local gmatch, gsub = string.gmatch, string.gsub
+
+local function report(what,pattern,c,e)
+ logs.report("xml","%s element '%s' (root: '%s', position: %s, index: %s, pattern: %s)",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern)
+end
+
+local function withelements(e,handle,depth)
+ if e and handle then
+ local edt = e.dt
+ if edt then
+ depth = depth or 0
+ for i=1,#edt do
+ local e = edt[i]
+ if type(e) == "table" then
+ handle(e,depth)
+ withelements(e,handle,depth+1)
+ end
+ end
+ end
+ end
+end
+
+xml.withelements = withelements
+
+function xml.withelement(e,n,handle) -- slow
+ if e and n ~= 0 and handle then
+ local edt = e.dt
+ if edt then
+ if n > 0 then
+ for i=1,#edt do
+ local ei = edt[i]
+ if type(ei) == "table" then
+ if n == 1 then
+ handle(ei)
+ return
+ else
+ n = n - 1
+ end
+ end
+ end
+ elseif n < 0 then
+ for i=#edt,1,-1 do
+ local ei = edt[i]
+ if type(ei) == "table" then
+ if n == -1 then
+ handle(ei)
+ return
+ else
+ n = n + 1
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+xml.elements_only = xml.collected
+
+function xml.each_element(root,pattern,handle,reverse)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ if reverse then
+ for c=#collected,1,-1 do
+ handle(collected[c])
+ end
+ else
+ for c=1,#collected do
+ handle(collected[c])
+ end
+ end
+ return collected
+ end
+end
+
+xml.process_elements = xml.each_element
+
+function xml.process_attributes(root,pattern,handle)
+ local collected = xmlparseapply({ root },pattern)
+ if collected and handle then
+ for c=1,#collected do
+ handle(collected[c].at)
+ end
+ end
+ return collected
+end
+
+--[[ldx--
+
The following functions collect elements and texts.
+--ldx]]--
+
+-- are these still needed -> lxml-cmp.lua
+
+function xml.collect_elements(root, pattern)
+ return xmlparseapply({ root },pattern)
+end
+
+function xml.collect_texts(root, pattern, flatten) -- todo: variant with handle
+ local collected = xmlparseapply({ root },pattern)
+ if collected and flatten then
+ local xmltostring = xml.tostring
+ for c=1,#collected do
+ collected[c] = xmltostring(collected[c].dt)
+ end
+ end
+ return collected or { }
+end
+
+function xml.collect_tags(root, pattern, nonamespace)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ local t = { }
+ for c=1,#collected do
+ local e = collected[c]
+ local ns, tg = e.ns, e.tg
+ if nonamespace then
+ t[#t+1] = tg
+ elseif ns == "" then
+ t[#t+1] = tg
+ else
+ t[#t+1] = ns .. ":" .. tg
+ end
+ end
+ return t
+ end
+end
+
+--[[ldx--
+
We've now arrived at the functions that manipulate the tree.
+--ldx]]--
+
+local no_root = { no_root = true }
+
+function xml.redo_ni(d)
+ for k=1,#d do
+ local dk = d[k]
+ if type(dk) == "table" then
+ dk.ni = k
+ end
+ end
+end
+
+local function xmltoelement(whatever,root)
+ if not whatever then
+ return nil
+ end
+ local element
+ if type(whatever) == "string" then
+ element = xmlinheritedconvert(whatever,root)
+ else
+ element = whatever -- we assume a table
+ end
+ if element.error then
+ return whatever -- string
+ end
+ if element then
+ --~ if element.ri then
+ --~ element = element.dt[element.ri].dt
+ --~ else
+ --~ element = element.dt
+ --~ end
+ end
+ return element
+end
+
+xml.toelement = xmltoelement
+
+local function copiedelement(element,newparent)
+ if type(element) == "string" then
+ return element
+ else
+ element = xmlcopy(element).dt
+ if newparent and type(element) == "table" then
+ element.__p__ = newparent
+ end
+ return element
+ end
+end
+
+function xml.delete_element(root,pattern)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local p = e.__p__
+ if p then
+ if trace_manipulations then
+ report('deleting',pattern,c,e)
+ end
+ local d = p.dt
+ remove(d,e.ni)
+ xml.redo_ni(d) -- can be made faster and inlined
+ end
+ end
+ end
+end
+
+function xml.replace_element(root,pattern,whatever)
+ local element = root and xmltoelement(whatever,root)
+ local collected = element and xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local p = e.__p__
+ if p then
+ if trace_manipulations then
+ report('replacing',pattern,c,e)
+ end
+ local d = p.dt
+ d[e.ni] = copiedelement(element,p)
+ xml.redo_ni(d) -- probably not needed
+ end
+ end
+ end
+end
+
+local function inject_element(root,pattern,whatever,prepend)
+ local element = root and xmltoelement(whatever,root)
+ local collected = element and xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local r = e.__p__
+ local d, k, rri = r.dt, e.ni, r.ri
+ local edt = (rri and d[rri].dt) or (d and d[k] and d[k].dt)
+ if edt then
+ local be, af
+ local cp = copiedelement(element,e)
+ if prepend then
+ be, af = cp, edt
+ else
+ be, af = edt, cp
+ end
+ for i=1,#af do
+ be[#be+1] = af[i]
+ end
+ if rri then
+ r.dt[rri].dt = be
+ else
+ d[k].dt = be
+ end
+ xml.redo_ni(d)
+ end
+ end
+ end
+end
+
+local function insert_element(root,pattern,whatever,before) -- todo: element als functie
+ local element = root and xmltoelement(whatever,root)
+ local collected = element and xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local r = e.__p__
+ local d, k = r.dt, e.ni
+ if not before then
+ k = k + 1
+ end
+ insert(d,k,copiedelement(element,r))
+ xml.redo_ni(d)
+ end
+ end
+end
+
+xml.insert_element = insert_element
+xml.insert_element_after = insert_element
+xml.insert_element_before = function(r,p,e) insert_element(r,p,e,true) end
+xml.inject_element = inject_element
+xml.inject_element_after = inject_element
+xml.inject_element_before = function(r,p,e) inject_element(r,p,e,true) end
+
+local function include(xmldata,pattern,attribute,recursive,loaddata)
+ -- parse="text" (default: xml), encoding="" (todo)
+ -- attribute = attribute or 'href'
+ pattern = pattern or 'include'
+ loaddata = loaddata or io.loaddata
+ local collected = xmlparseapply({ xmldata },pattern)
+ if collected then
+ for c=1,#collected do
+ local ek = collected[c]
+ local name = nil
+ local ekdt = ek.dt
+ local ekat = ek.at
+ local epdt = ek.__p__.dt
+ if not attribute or attribute == "" then
+ name = (type(ekdt) == "table" and ekdt[1]) or ekdt -- ckeck, probably always tab or str
+ end
+ if not name then
+ for a in gmatch(attribute or "href","([^|]+)") do
+ name = ekat[a]
+ if name then break end
+ end
+ end
+ local data = (name and name ~= "" and loaddata(name)) or ""
+ if data == "" then
+ epdt[ek.ni] = "" -- xml.empty(d,k)
+ elseif ekat["parse"] == "text" then
+ -- for the moment hard coded
+ epdt[ek.ni] = xml.escaped(data) -- d[k] = xml.escaped(data)
+ else
+--~ local settings = xmldata.settings
+--~ settings.parent_root = xmldata -- to be tested
+--~ local xi = xmlconvert(data,settings)
+ local xi = xmlinheritedconvert(data,xmldata)
+ if not xi then
+ epdt[ek.ni] = "" -- xml.empty(d,k)
+ else
+ if recursive then
+ include(xi,pattern,attribute,recursive,loaddata)
+ end
+ epdt[ek.ni] = xml.body(xi) -- xml.assign(d,k,xi)
+ end
+ end
+ end
+ end
+end
+
+xml.include = include
+
+--~ local function manipulate(xmldata,pattern,manipulator) -- untested and might go away
+--~ local collected = xmlparseapply({ xmldata },pattern)
+--~ if collected then
+--~ local xmltostring = xml.tostring
+--~ for c=1,#collected do
+--~ local e = collected[c]
+--~ local data = manipulator(xmltostring(e))
+--~ if data == "" then
+--~ epdt[e.ni] = ""
+--~ else
+--~ local xi = xmlinheritedconvert(data,xmldata)
+--~ if not xi then
+--~ epdt[e.ni] = ""
+--~ else
+--~ epdt[e.ni] = xml.body(xi) -- xml.assign(d,k,xi)
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+
+--~ xml.manipulate = manipulate
+
+function xml.strip_whitespace(root, pattern, nolines) -- strips all leading and trailing space !
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for i=1,#collected do
+ local e = collected[i]
+ local edt = e.dt
+ if edt then
+ local t = { }
+ for i=1,#edt do
+ local str = edt[i]
+ if type(str) == "string" then
+ if str == "" then
+ -- stripped
+ else
+ if nolines then
+ str = gsub(str,"[ \n\r\t]+"," ")
+ end
+ if str == "" then
+ -- stripped
+ else
+ t[#t+1] = str
+ end
+ end
+ else
+ --~ str.ni = i
+ t[#t+1] = str
+ end
+ end
+ e.dt = t
+ end
+ end
+ end
+end
+
+function xml.strip_whitespace(root, pattern, nolines, anywhere) -- strips all leading and trailing spacing
+ local collected = xmlparseapply({ root },pattern) -- beware, indices no longer are valid now
+ if collected then
+ for i=1,#collected do
+ local e = collected[i]
+ local edt = e.dt
+ if edt then
+ if anywhere then
+ local t = { }
+ for e=1,#edt do
+ local str = edt[e]
+ if type(str) ~= "string" then
+ t[#t+1] = str
+ elseif str ~= "" then
+ -- todo: lpeg for each case
+ if nolines then
+ str = gsub(str,"%s+"," ")
+ end
+ str = gsub(str,"^%s*(.-)%s*$","%1")
+ if str ~= "" then
+ t[#t+1] = str
+ end
+ end
+ end
+ e.dt = t
+ else
+ -- we can assume a regular sparse xml table with no successive strings
+ -- otherwise we should use a while loop
+ if #edt > 0 then
+ -- strip front
+ local str = edt[1]
+ if type(str) ~= "string" then
+ -- nothing
+ elseif str == "" then
+ remove(edt,1)
+ else
+ if nolines then
+ str = gsub(str,"%s+"," ")
+ end
+ str = gsub(str,"^%s+","")
+ if str == "" then
+ remove(edt,1)
+ else
+ edt[1] = str
+ end
+ end
+ end
+ if #edt > 1 then
+ -- strip end
+ local str = edt[#edt]
+ if type(str) ~= "string" then
+ -- nothing
+ elseif str == "" then
+ remove(edt)
+ else
+ if nolines then
+ str = gsub(str,"%s+"," ")
+ end
+ str = gsub(str,"%s+$","")
+ if str == "" then
+ remove(edt)
+ else
+ edt[#edt] = str
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+local function rename_space(root, oldspace, newspace) -- fast variant
+ local ndt = #root.dt
+ for i=1,ndt or 0 do
+ local e = root[i]
+ if type(e) == "table" then
+ if e.ns == oldspace then
+ e.ns = newspace
+ if e.rn then
+ e.rn = newspace
+ end
+ end
+ local edt = e.dt
+ if edt then
+ rename_space(edt, oldspace, newspace)
+ end
+ end
+ end
+end
+
+xml.rename_space = rename_space
+
+function xml.remap_tag(root, pattern, newtg)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ collected[c].tg = newtg
+ end
+ end
+end
+
+function xml.remap_namespace(root, pattern, newns)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ collected[c].ns = newns
+ end
+ end
+end
+
+function xml.check_namespace(root, pattern, newns)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ if (not e.rn or e.rn == "") and e.ns == "" then
+ e.rn = newns
+ end
+ end
+ end
+end
+
+function xml.remap_name(root, pattern, newtg, newns, newrn)
+ local collected = xmlparseapply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ e.tg, e.ns, e.rn = newtg, newns, newrn
+ end
+ end
+end
+
+--[[ldx--
+
Here are a few synonyms.
+--ldx]]--
+
+xml.each = xml.each_element
+xml.process = xml.process_element
+xml.strip = xml.strip_whitespace
+xml.collect = xml.collect_elements
+xml.all = xml.collect_elements
+
+xml.insert = xml.insert_element_after
+xml.inject = xml.inject_element_after
+xml.after = xml.insert_element_after
+xml.before = xml.insert_element_before
+xml.delete = xml.delete_element
+xml.replace = xml.replace_element
diff --git a/tex/context/base/lxml-ctx.lua b/tex/context/base/lxml-ctx.lua
new file mode 100644
index 000000000..765754953
--- /dev/null
+++ b/tex/context/base/lxml-ctx.lua
@@ -0,0 +1,131 @@
+if not modules then modules = { } end modules ['lxml-ctx'] = {
+ version = 1.001,
+ comment = "companion to lxml-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- is this still used?
+
+xml.ctx = { }
+xml.ctx.enhancers = { }
+
+-- hashen
+
+function xml.ctx.enhancers.compound(root,lpath,before,tokens,after) -- todo lpeg
+ local before = before or "[%a%d][%a%d][%a%d]"
+ local tokens = tokens or "[%/%-]"
+ local after = after or "[%a%d][%a%d][%a%d]"
+ local pattern = "(" .. before .. ")(" .. tokens .. ")(" .. after .. ")"
+ local action = function(a,b,c)
+ return a .. "" .. c
+ end
+ xml.enhance(root,lpath,pattern,action) -- still present?
+end
+
+local loaded = { }
+
+local nodesettostring = xml.nodesettostring
+
+-- maybe use detokenize instead of \type
+
+function xml.ctx.tshow(specification)
+ local pattern = specification.pattern
+ local xmlroot = specification.xmlroot
+ local attribute = specification.attribute
+ if context then
+ local xmlpattern = pattern
+ if not string.find(xmlpattern,"^[%a]+://") then
+ xmlpattern = "xml://" .. pattern
+ end
+ parsed = xml.parse_pattern(xmlpattern)
+ titlecommand = specification.title or "type"
+ if parsed.state then
+ context[titlecommand]("pattern: " .. pattern .. " (".. parsed.state .. ")")
+ else
+ context[titlecommand]("pattern: " .. pattern)
+ end
+ context.starttabulate({ "|Tr|Tl|Tp|" } )
+ if specification.warning then
+ local comment = parsed.comment
+ if comment then
+ for k=1,#comment do
+ context.NC()
+ context("!")
+ context.NC()
+ context.rlap(comment[k])
+ context.NR()
+ end
+ context.TB()
+ end
+ end
+ for p=1,#parsed do
+ local pp = parsed[p]
+ local kind = pp.kind
+ context.NC()
+ context(p)
+ context.NC()
+ context(kind)
+ context.NC()
+ if kind == "axis" then
+ context(pp.axis)
+ elseif kind == "nodes" then
+ context(nodesettostring(pp.nodes,pp.nodetest))
+ elseif kind == "expression" then
+--~ context("%s => %s",pp.expression,pp.converted)
+ context(pp.expression)
+ elseif kind == "finalizer" then
+ context("%s(%s)",pp.name,pp.arguments)
+ elseif kind == "error" and pp.error then
+ context(pp.error)
+ end
+ context.NC()
+ context.NR()
+ end
+ context.stoptabulate()
+ if xmlroot and xmlroot ~= "" then
+ if not loaded[xmlroot] then
+ loaded[xmlroot] = { xml.convert(buffers.content(xmlroot) or "") }
+ end
+ local collected = xml.parse_apply(loaded[xmlroot],xmlpattern)
+ if collected then
+ local tc = type(collected)
+ if not tc then
+ -- skip
+ else
+ context.blank()
+ context.type("result : ")
+ if tc == "string" then
+ context.type(collected)
+ elseif tc == "table" then
+ if collected.tg then
+ collected = { collected }
+ end
+ for c=1,#collected do
+ local cc = collected[c]
+ if attribute and attribute ~= "" then
+ local ccat = cc.at
+ local a = ccat and ccat[attribute]
+ if a and a ~= "" then
+ context.type(a)
+ context.type(">")
+ end
+ end
+ local ccns = cc.ns
+ if ccns == "" then
+ context.type(cc.tg)
+ else
+ context.type(ccns .. ":" .. cc.tg)
+ end
+ context.space()
+ end
+ else
+ context.type(tostring(tc))
+ end
+ context.blank()
+ end
+ end
+ end
+ end
+end
diff --git a/tex/context/base/lxml-ctx.mkiv b/tex/context/base/lxml-ctx.mkiv
new file mode 100644
index 000000000..73d082d0d
--- /dev/null
+++ b/tex/context/base/lxml-ctx.mkiv
@@ -0,0 +1,64 @@
+%D \module
+%D [ file=lxml-ini,
+%D version=2007.08.17,
+%D title=\CONTEXT\ \XML\ Support,
+%D subtitle=Initialization,
+%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.
+
+%D Experimental. This might change! Also, it might become a module
+%D instead if core code.
+
+\writestatus{loading}{ConTeXt XML Support / Goodies}
+
+\registerctxluafile{lxml-ctx}{1.001}
+
+\unprotect
+
+% the letterbar is a messy hack and is needed for the tabulate
+
+\settrue \xmllshowbuffer
+\setfalse\xmllshowtitle
+\settrue \xmllshowwarning
+
+\definehead[lshowtitle][subsubsubsubsubject]
+\setuphead[lshowtitle][style=\tta]
+
+% \unexpanded\def\setuplxmlshow[#1]%
+% {\dodoubleargument\getparameters[\??xl]}
+
+\def\xmllshow#1%
+ {\begingroup
+ \let|=\letterbar
+ \ctxlua{xml.ctx.tshow {
+ pattern = \!!bs#1\!!es,
+ \ifconditional\xmllshowtitle
+ title = "lshowtitle",
+ \fi
+ \ifconditional\xmllshowwarning
+ warning = true,
+ \fi
+ } }%
+ \endgroup}
+
+\def\xmllshowbuffer#1#2#3%
+ {\begingroup
+ \let|=\letterbar
+ \ctxlua{xml.ctx.tshow {
+ pattern = \!!bs#2\!!es,
+ \ifconditional\xmllshowbuffer
+ xmlroot = "#1",
+ attribute = "#3",
+ \fi
+ \ifconditional\xmllshowwarning
+ warning = true,
+ \fi
+ } }%
+ \endgroup}
+
+\protect
diff --git a/tex/context/base/lxml-dir.lua b/tex/context/base/lxml-dir.lua
new file mode 100644
index 000000000..617ce3e20
--- /dev/null
+++ b/tex/context/base/lxml-dir.lua
@@ -0,0 +1,112 @@
+if not modules then modules = { } end modules ['lxml-dir'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, gsub = string.format, string.gsub
+local get_id = lxml.id
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+local xmlparseapply = xml.parse_apply
+
+--~
+--~
+--~
+--~
+--~
+--~
+--~
+
+
+
+lxml.directives = lxml.directives or { }
+
+local directives = lxml.directives
+
+local data = {
+ setup = { },
+ before = { },
+ after = { }
+}
+
+local function load_setup(filename)
+ local fullname = resolvers.findtexfile(filename) or ""
+ if fullname ~= "" then
+ filename = fullname
+ end
+ local collection = xmlparseapply({ get_id(xml.load(filename)) },"directive")
+ if collection then
+ local valid = 0
+ for i=1,#collection do
+ local at = collection[i].at
+ local attribute, value, element = at.attribute or "", at.value or "", at.element or '*'
+ local setup, before, after = at.setup or "", at.before or "", at.after or ""
+ if attribute ~= "" and value ~= "" then
+ local key = format("%s::%s::%s",element,attribute,value)
+ local t = data[key] or { }
+ if setup ~= "" then t.setup = setup end
+ if before ~= "" then t.before = before end
+ if after ~= "" then t.after = after end
+ data[key] = t
+ valid = valid + 1
+ end
+ end
+ commands.writestatus("lxml","%s directives found in '%s', %s valid",#collection,filename,valid)
+ else
+ commands.writestatus("lxml","no directives found in '%s'",filename)
+ end
+end
+
+local function handle_setup(category,root,attribute,element)
+ root = get_id(root)
+ if attribute then
+ local value = root.at[attribute]
+ if value then
+ if not element then
+ local ns, tg = root.rn or root.ns, root.tg
+ if ns == "" then
+ element = tg
+ else
+ element = ns .. ':' .. tg
+ end
+ end
+ local setup = data[format("%s::%s::%s",element,attribute,value)]
+ if setup then
+ setup = setup[category]
+ end
+ if setup then
+ texsprint(ctxcatcodes,"\\directsetup{",setup,"}")
+ else
+ setup = data[format("%s::%s::*",element,attribute)]
+ if setup then
+ setup = setup[category]
+ end
+ if setup then
+ texsprint(ctxcatcodes,"\\directsetup{",gsub(setup,'%*',value),"}")
+ end
+ end
+ end
+ end
+end
+
+directives.load = load_setup
+directives.handle = handle_setup
+
+function directives.setup(root,attribute,element)
+ handle_setup('setup',root,attribute,element)
+end
+function directives.before(root,attribute,element)
+ handle_setup('before',root,attribute,element)
+end
+function directives.after(root,attribute,element)
+ handle_setup('after',root,attribute,element)
+end
diff --git a/tex/context/base/lxml-ent.lua b/tex/context/base/lxml-ent.lua
new file mode 100644
index 000000000..193611937
--- /dev/null
+++ b/tex/context/base/lxml-ent.lua
@@ -0,0 +1,69 @@
+if not modules then modules = { } end modules ['lxml-ent'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, next, tonumber = type, next, tonumber
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+local utf = unicode.utf8
+local byte, format = string.byte, string.format
+local utfupper, utfchar = utf.upper, utf.char
+local lpegmatch = lpeg.match
+
+--[[ldx--
+
We provide (at least here) two entity handlers. The more extensive
+resolver consults a hash first, tries to convert to next,
+and finaly calls a handler when defines. When this all fails, the
+original entity is returned.
+
+
We do things different now but it's still somewhat experimental
+--ldx]]--
+
+local trace_entities = false trackers.register("xml.entities", function(v) trace_entities = v end)
+
+xml.entities = xml.entities or { } -- xml.entity_handler == function
+
+storage.register("xml/entities",xml.entities,"xml.entities") -- this will move to lxml
+
+local entities = xml.entities -- this is a shared hash
+
+xml.unknown_any_entity_format = nil -- has to be per xml
+
+local parsedentity = xml.parsedentitylpeg
+
+function xml.register_entity(key,value)
+ entities[key] = value
+ if trace_entities then
+ logs.report("xml","registering entity '%s' as: %s",key,value)
+ end
+end
+
+function xml.resolved_entity(str)
+ local e = entities[str]
+ if e then
+ local te = type(e)
+ if te == "function" then
+ e(str)
+ elseif e then
+ texsprint(ctxcatcodes,e)
+ end
+ else
+ -- resolve hex and dec, todo: escape # & etc for ctxcatcodes
+ -- normally this is already solved while loading the file
+ local chr, err = lpegmatch(parsedentity,str)
+ if chr then
+ texsprint(ctxcatcodes,chr)
+ elseif err then
+ texsprint(ctxcatcodes,err)
+ else
+ texsprint(ctxcatcodes,"\\xmle{",str,"}{",utfupper(str),"}") -- we need to use our own upper
+ end
+ end
+end
+
+entities.amp = function() tex.write("&") end
+entities.lt = function() tex.write("<") end
+entities.gt = function() tex.write(">") end
diff --git a/tex/context/base/lxml-inf.lua b/tex/context/base/lxml-inf.lua
new file mode 100644
index 000000000..629c869ec
--- /dev/null
+++ b/tex/context/base/lxml-inf.lua
@@ -0,0 +1,53 @@
+if not modules then modules = { } end modules ['lxml-inf'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This file will be loaded runtime by x-pending.tex.
+
+local status, stack
+
+local function get(e,d)
+ local ns, tg = e.ns, e.tg
+ local name = tg
+ if ns ~= "" then name = ns .. ":" .. tg end
+ stack[d] = name
+ local ec = e.command
+ if ec == true then
+ ec = "system: text"
+ elseif ec == false then
+ ec = "system: skip"
+ elseif ec == nil then
+ ec = "system: not set"
+ elseif type(ec) == "string" then
+ ec = "setup: " .. ec
+ else -- function
+ ec = tostring(ec)
+ end
+ local tag = concat(stack," => ",1,d)
+ local s = status[tag]
+ if not s then
+ s = { }
+ status[tag] = s
+ end
+ s[ec] = (s[ec] or 0) + 1
+end
+
+local function get_command_status(id)
+ status, stack = {}, {}
+ if id then
+ xmlwithelements(get_id(id),get)
+ return status
+ else
+ local t = { }
+ for id, _ in next, loaded do
+ t[id] = get_command_status(id)
+ end
+ return t
+ end
+end
+
+lxml.get_command_status = get_command_status
diff --git a/tex/context/base/lxml-ini.mkiv b/tex/context/base/lxml-ini.mkiv
new file mode 100644
index 000000000..0f04d0488
--- /dev/null
+++ b/tex/context/base/lxml-ini.mkiv
@@ -0,0 +1,414 @@
+%D \module
+%D [ file=lxml-ini,
+%D version=2007.08.17,
+%D title=\CONTEXT\ \XML\ Support,
+%D subtitle=Initialization,
+%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.
+
+%D Todo: auto apply setups (manage at lua end)
+
+\writestatus{loading}{ConTeXt XML Support / Initialization}
+
+%registerctxluafile{lxml-tab}{1.001} % loader
+%registerctxluafile{lxml-lpt}{1.001} % parser
+%registerctxluafile{lxml-xml}{1.001} % xml finalizers
+%registerctxluafile{lxml-aux}{1.001} % extras using parser
+%registerctxluafile{lxml-mis}{1.001} % extras independent of parser
+\registerctxluafile{lxml-ent}{1.001} % entity hacks
+\registerctxluafile{lxml-tex}{1.001} % tex finalizers
+\registerctxluafile{lxml-dir}{1.001} % ctx hacks
+
+\unprotect
+
+\def\c!entities{entities} % to be internationalized
+
+\def\xmlmain #1{\ctxlua{lxml.main("#1")}}
+\def\xmlmatch #1{\ctxlua{lxml.match("#1")}}
+\def\xmlall #1#2{\ctxlua{lxml.all("#1","#2")}}
+\def\xmlatt #1#2{\ctxlua{lxml.att("#1","#2")}}
+\def\xmlattdef #1#2#3{\ctxlua{lxml.att("#1","#2","#3")}}
+\def\xmlchainatt #1#2{\ctxlua{lxml.chainattribute("#1","/","#2")}}
+\def\xmlchainattdef #1#2#3{\ctxlua{lxml.chainattribute("#1","/","#2","#3")}}
+\def\xmlattribute #1#2#3{\ctxlua{lxml.attribute("#1","#2","#3")}}
+\def\xmlattributedef #1#2#3#4{\ctxlua{lxml.attribute("#1","#2","#3","#4")}}
+\def\xmlcommand #1#2#3{\ctxlua{lxml.command("#1","#2","#3")}}
+\def\xmlconcat #1#2#3{\ctxlua{lxml.concat("#1","#2",[[\detokenize{#3}]])}}
+\def\xmlconcatrange#1#2#3#4#5{\ctxlua{lxml.concatrange("#1","#2","#3","#4",[[\detokenize{#5}]])}}
+\def\xmlcount #1#2{\ctxlua{lxml.count("#1","#2")}}
+\def\xmldelete #1#2{\ctxlua{lxml.delete("#1","#2")}}
+\def\xmldirectives #1{\ctxlua{lxml.directives.setup("#1")}}
+\def\xmldirectivesbefore #1{\ctxlua{lxml.directives.before("#1")}}
+\def\xmldirectivesafter #1{\ctxlua{lxml.directives.after("#1")}}
+\def\xmlfilter #1#2{\ctxlua{lxml.filter("#1",\!!bs#2\!!es)}}
+\def\xmlfilterlist #1#2{\ctxlua{lxml.filterlist("#1",\!!bs#2\!!es)}}
+\def\xmlfunction #1#2{\ctxlua{lxml["function"]("#1",\!!bs#2\!!es)}}
+\def\xmlfirst #1#2{\ctxlua{lxml.first("#1","#2")}}
+\def\xmlflush #1{\ctxlua{lxml.flush("#1")}}
+%def\xmlcontent #1{\ctxlua{lxml.content("#1")}}
+%def\xmlflushstripped #1{\ctxlua{lxml.strip("#1",true)}}
+\def\xmldirect #1{\ctxlua{lxml.direct("#1")}} % in loops, not dt but root
+\def\xmlidx #1#2#3{\ctxlua{lxml.idx("#1","#2",\number#3)}}
+\def\xmlinclude #1#2#3{\ctxlua{lxml.include("#1","#2","#3",true)}}
+\def\xmlindex #1#2#3{\ctxlua{lxml.index("#1","#2",\number#3)}}
+\def\xmlinfo #1{\hbox{\ttxx[\ctxlua{lxml.info("#1")}]}}
+\def\xmlshow #1{\startpacked\ttx\xmlverbatim{#1}\stoppacked}
+\def\xmllast #1#2{\ctxlua{lxml.last("#1","#2")}}
+\def\xmlname #1{\ctxlua{lxml.name("#1")}}
+\def\xmlnamespace #1{\ctxlua{lxml.namespace("#1")}}
+\def\xmlnonspace #1#2{\ctxlua{lxml.nonspace("#1","#2")}}
+\def\xmlraw #1#2{\ctxlua{lxml.raw("#1","#2")}}
+\def\xmlcontext #1#2{\ctxlua{lxml.context("#1","#2")}}
+\def\xmlflushcontext #1{\ctxlua{lxml.context("#1")}}
+\def\xmlsnippet #1#2{\ctxlua{lxml.snippet("#1",#2)}}
+\def\xmlelement #1#2{\ctxlua{lxml.element("#1",#2)}}
+\def\xmlregisterns #1#2{\ctxlua{xml.registerns("#1","#2")}} % document
+\def\xmlremapname #1#2#3#4{\ctxlua{xml.remapname(lxml.id("#1"),"#2","#3","#4")}} % element
+\def\xmlremapnamespace #1#2#3{\ctxlua{xml.rename_space(lxml.id("#1"),"#2","#3")}} % document
+\def\xmlchecknamespace #1#2#3{\ctxlua{xml.check_namespace(lxml.id("#1"),"#2","#3")}} % element
+\def\xmlsetfunction #1#2#3{\ctxlua{lxml.setaction("#1","#2",#3)}}
+\def\xmlsetsetup #1#2#3{\ctxlua{lxml.setsetup("#1","#2","#3")}}
+\def\xmlstrip #1#2{\ctxlua{lxml.strip("#1","#2")}}
+\def\xmlstripnolines #1#2{\ctxlua{lxml.strip("#1","#2",true)}}
+\def\xmlstripanywhere #1#2{\ctxlua{lxml.strip("#1","#2",true,true)}}
+\def\xmlstripped #1#2{\ctxlua{lxml.stripped("#1","#2")}}
+\def\xmlstrippednolines #1#2{\ctxlua{lxml.stripped("#1","#2",true)}}
+\def\xmltag #1{\ctxlua{lxml.tag("#1")}}
+\def\xmltext #1#2{\ctxlua{lxml.text("#1","#2")}}
+\def\xmlverbatim #1{\ctxlua{lxml.verbatim("#1")}}
+\def\xmldisplayverbatim #1{\ctxlua{lxml.displayverbatim("#1")}}
+\def\xmlinlineverbatim #1{\ctxlua{lxml.inlineverbatim("#1")}}
+
+\def\xmlload #1#2{\ctxlua{lxml.load("#1","#2","\@@xmentities","\@@xmcompress")}}
+\def\xmlloadbuffer #1#2{\ctxlua{lxml.loadbuffer("#1","#2","\@@xmentities","\@@xmcompress")}}
+\def\xmlloaddata #1#2{\ctxlua{lxml.loaddata("#1",\!!bs#2\!!es,"\@@xmentities","\@@xmcompress")}}
+\def\xmlloadregistered #1#2{\ctxlua{lxml.loadregistered("#1","\@@xmentities","\@@xmcompress")}}
+\def\xmlloaddirectives #1{\ctxlua{lxml.directives.load("any:///#1")}}
+\def\xmlpos #1{\ctxlua{lxml.pos("#1")}}
+
+%def\xmldoifelse #1#2{\ctxlua{cs.testcase(xml.found(lxml.id("#1"),"#2",false))}}
+%def\xmldoifelsetext #1#2{\ctxlua{cs.testcase(xml.found(lxml.id("#1"),"#2",true ))}}
+
+% kind of special:
+
+\def\xmlstartraw{\ctxlua{lxml.startraw()}}
+\def\xmlstopraw {\ctxlua{lxml.stopraw()}}
+
+% todo: \xmldoifelseattribute
+
+\def\xmldoif #1#2{\ctxlua{lxml.doif (\!!bs#1\!!es,\!!bs#2\!!es)}}
+\def\xmldoifnot #1#2{\ctxlua{lxml.doifnot (\!!bs#1\!!es,\!!bs#2\!!es)}}
+\def\xmldoifelse #1#2{\ctxlua{lxml.doifelse (\!!bs#1\!!es,\!!bs#2\!!es)}}
+\def\xmldoiftext #1#2{\ctxlua{lxml.doiftext (\!!bs#1\!!es,\!!bs#2\!!es)}}
+\def\xmldoifnottext #1#2{\ctxlua{lxml.doifnottext (\!!bs#1\!!es,\!!bs#2\!!es)}}
+\def\xmldoifelsetext #1#2{\ctxlua{lxml.doifelsetext(\!!bs#1\!!es,\!!bs#2\!!es)}}
+
+%def\xmldoifelseempty #1#2{\ctxlua{lxml.doifelseempty("#1","#2")}} % #2, "*" or "" == self not yet implemented
+%def\xmldoifelseselfempty #1{\ctxlua{lxml.doifelseempty("#1")}}
+
+% \startxmlsetups xml:include
+% \xmlinclude{main}{include}{filename|href}
+% \stopxmlsetups
+%
+% \xmlprependsetup{xml:include}
+
+\let\xmlgrab\xmlsetsetup % obsolete
+\let\xmlself\s!unknown % obsolete
+
+\def\xmlsetup#1#2{\setupwithargument{#2}{#1}}
+
+\let\xmls\xmlsetup
+\let\xmlw\setupwithargument
+
+\newtoks \registeredxmlsetups
+
+% todo: 1:xml:whatever always before 3:xml:something
+
+\def\xmlprependsetup #1{\ctxlua{lxml.installsetup(1,"*","#1")}}
+\def\xmlappendsetup #1{\ctxlua{lxml.installsetup(2,"*","#1")}}
+\def\xmlbeforesetup #1#2{\ctxlua{lxml.installsetup(3,"*","#1","#2"))}}
+\def\xmlaftersetup #1#2{\ctxlua{lxml.installsetup(4,"*","#1","#2"))}}
+
+\def\xmlprependdocumentsetup #1#2{\ctxlua{lxml.installsetup(1,"#1","#2")}}
+\def\xmlappenddocumentsetup #1#2{\ctxlua{lxml.installsetup(2,"#1","#2")}}
+\def\xmlbeforedocumentsetup#1#2#3{\ctxlua{lxml.installsetup(3,"#1","#2","#3"))}}
+\def\xmlafterdocumentsetup #1#2#3{\ctxlua{lxml.installsetup(4,"#1","#2","#3"))}}
+
+\def\xmlremovesetup #1{\ctxlua{lxml.removesetup("*","#1")}}
+\def\xmlremovedocumentsetup #1#2{\ctxlua{lxml.removesetup("#1","#2")}}
+
+\def\xmlflushdocumentsetups #1#2{\ctxlua{lxml.flushsetups("#1","*","#2")}} % #1 == id where to apply * and #2
+\def\xmlresetdocumentsetups #1{\ctxlua{lxml.resetsetups("#1")}}
+
+\let\xmlregistersetup \xmlappendsetup
+\let\xmlregisterdocumentsetup\xmlappenddocumentsetup
+
+\def\xmldocument{main}
+
+\def\xmlregisteredsetups
+ {\xmlstarttiming
+ \xmlflushsetups
+ \xmldefaulttotext\xmldocument % after include
+ \xmlstoptiming}
+
+\def\xmlregistereddocumentsetups#1#2% id setups
+ {\xmlstarttiming
+ % todo: test for duplicates !
+ \xmlflushdocumentsetups{#1}{#2}%
+ \xmldefaulttotext{#1}% after include
+ \xmlstoptiming}
+
+\def\xmlstarttiming{\ctxlua{statistics.starttiming(lxml)}}
+\def\xmlstoptiming {\ctxlua{statistics.stoptiming (lxml)}}
+
+\def\doxmlprocess#1#2#3#4#5% flag \loader id name what initializersetup
+ {\begingroup
+ \edef\xmldocument{#3}% #2 can be \xmldocument and set as such
+ %xmlpushdocument{#3}%
+ #2{#3}{#4}%
+ \setcatcodetable\notcatcodes
+ \doifelsenothing{#5}
+ {\xmlsetup{#3}{xml:process}}
+ {\xmlsetup{#3}{#5}}%
+ %xmlpopdocument
+ \endgroup}
+
+\def\xmlprocessfile {\doxmlprocess\plusone \xmlload}
+\def\xmlprocessdata {\doxmlprocess\zerocount\xmlloaddata}
+\def\xmlprocessbuffer {\doxmlprocess\zerocount\xmlloadbuffer}
+\def\xmlprocessregistered{\doxmlprocess\zerocount\xmlloadregistered}
+\let\xmlprocess \xmlprocessfile
+
+\startxmlsetups xml:flush
+ \xmlflush{#1}
+\stopxmlsetups
+
+\startxmlsetups xml:process
+ \xmlregistereddocumentsetups{#1}{#1}
+ \xmlmain{#1}
+\stopxmlsetups
+
+\def\xmlloadonly#1#2#3%
+ {\xmlload{#1}{#2}%
+ \xmlregistereddocumentsetups{#1}{#3}}
+
+% beware: \xmlmain takes the real root, so also processing
+% instructions preceding the root element; well, in some
+% sense that is the root
+
+\long\def\xmlconnect#1#2#3% inefficient
+ {\scratchcounter\xmlcount{#1}{#2}\relax
+ \ifcase\scratchcounter \or
+ \xmlall{#1}{#2}%
+ \else
+ \dorecurse \scratchcounter
+ {\ifnum\recurselevel>\plusone#3\fi
+ \xmlidx{#1}{#2}\recurselevel}%
+ \fi}
+
+\def\xmlcdataobeyedline {\obeyedline}
+\def\xmlcdataobeyedspace{\strut\obeyedspace}
+\def\xmlcdatabefore {\bgroup\tt}
+\def\xmlcdataafter {\egroup}
+
+% verbatim (dodo:pre/post whitespace, maybe splot verbatim and
+% cdata commands), experimental:
+%
+% \xmlsetfunction{main}{verbatim}{lxml.displayverbatim}
+% \xmlsetfunction{main}{verb} {lxml.inlineverbatim}
+
+% \unexpanded\def\startxmldisplayverbatim[#1]{}
+% \unexpanded\def\stopxmldisplayverbatim {}
+% \unexpanded\def\startxmlinlineverbatim [#1]{}
+% \unexpanded\def\stopxmlinlineverbatim {}
+
+% we use an xml: namespace so one has to define a suitable verbatim, say
+%
+% \definetyping[xml:verbatim][typing]
+%
+% this is experimental!
+
+\unexpanded\def\startxmldisplayverbatim[#1]%
+ {\startpacked % \begingroup
+ \let\currenttypingclass\??tp
+ \edef\currenttyping{xml:#1}%
+ \unexpanded\def\stopxmldisplayverbatim
+ {\endofverbatimlines
+ \stoppacked} % \endgroup
+ \doinitializeverbatim
+ \beginofverbatimlines}
+
+\unexpanded\def\startxmlinlineverbatim[#1]%
+ {\begingroup
+ \let\currenttypingclass\??ty
+ \edef\currenttyping{xml:#1}%
+ \let\stopxmldisplayverbatim\endgroup
+ \doinitializeverbatim}
+
+% will move but is developed for xml
+
+\newtoks \collectingtoks
+
+\unexpanded\def\startcollect#1\stopcollect
+ {\collectingtoks\@EA{\the\collectingtoks#1}}
+
+\unexpanded\def\startexpandedcollect#1\stopexpandedcollect
+ {\normalexpanded{\collectingtoks{\the\collectingtoks#1}}}
+
+\unexpanded\def\startcollecting{\collectingtoks\emptytoks}
+\unexpanded\def\stopcollecting {\the\collectingtoks}
+
+\def\inlinemessage #1{\dontleavehmode{\tttf#1}}
+\def\displaymessage#1{\blank\inlinemessage{#1}\blank}
+
+\def\xmltraceentities
+ {\ctxlua{xml.set_text_cleanup(lxml.trace_text_entities)}%
+ \appendtoks\ctxlua{lxml.show_text_entities()}\to\everygoodbye}
+
+% processing instructions
+
+\def\xmlcontextdirective#1% kind class key value
+ {\executeifdefined{xml#1directive}\gobblethreearguments}
+
+% setting up xml:
+%
+% \setupxml[\c!default=] % mkiv only == text
+% \setupxml[\c!default=\v!none] % mkiv only, undefined -> hidden
+% \setupxml[\c!default=\v!text] % mkiv only, undefined -> text
+
+% \def\xmlctxdirective#1#2#3{\doif{#1}{clue}{\doif{#2}{page}}{\page[#3]}}
+
+\chardef\xmlprocessingmode=0 % 0=unset, 1=text, 2=hidden
+
+\newtoks\everysetupxml
+
+\unexpanded\def\setupxml[#1]{\getparameters[\??xm][#1]\the\everysetupxml}
+
+
+\letvalue{\??xm:\s!default:\v!normal}\zerocount
+\letvalue{\??xm:\s!default:\v!none }\zerocount
+\letvalue{\??xm:\s!default:\v!text }\plusone
+\letvalue{\??xm:\s!default:\v!hidden}\plustwo
+
+\def\xmldefaulttotext#1%
+ {\ifcase\xmlprocessingmode
+ % unset
+ \or
+ \ctxlua{lxml.set_command_to_text("#1")}% 1
+ \or
+ \ctxlua{lxml.set_command_to_none("#1")}% 2
+ \else
+ % unset
+ \fi}
+
+\appendtoks
+ \chardef\xmlprocessingmode\executeifdefined{\??xm:\s!default:\@@xmdefault}\plusone
+\to \everysetupxml
+
+\def\xmlinitialize{\the\everysetupxml}
+
+\setupxml
+ [\c!default=, % flush all
+ \c!compress=\v!no, % strip comment
+ \c!entities=\v!yes] % replace entities
+
+% \defineXMLenvironment[y]{(}{)}
+%
+% \startxmlsetups x
+% /\xmlflush{#1}/
+% \stopxmlsetups
+%
+% \startxmlsetups xx
+% \xmlsetsetup{main}{x}{*}
+% \stopxmlsetups
+%
+% \xmlregistersetup{xx}
+%
+% \startbuffer
+% a <&>{b} c
+% \stopbuffer
+%
+% mkii: [\processXMLbuffer]\quad mkiv: [\xmlprocessbuffer{main}{}{}]
+
+\def\xmlmapvalue #1#2#3{\setvalue{\??xm:v:#1:#2}{#3}} % keep #3 to grab spaces
+\def\xmlvalue #1#2#3{\executeifdefined{\??xm:v:#1:#2}{#3}}
+%def\xmlvalue #1#2{\ifcsname\??xm:v:#1:#2\endcsname\csname\??xm:v:#1:#2\expandafter\expandafter\gobbleoneargument\expandafter\endcsname\else\expandafter\firstofoneargument\fi}
+\def\xmldoifelsevalue #1#2{\ifcsname\??xm:v:#1:#2\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
+
+\let\xmlmapval\xmlmapvalue
+\let\xmlval \xmlvalue
+
+%D Experimental:
+
+\def\xmlgetindex #1{\ctxlua{lxml.getindex("\xmldocument","#1")}}
+\def\xmlrawindex #1{\ctxlua{lxml.rawindex("#1")}}
+\def\xmlwithindex #1#2{\ctxlua{lxml.withindex("\xmldocument","#1","#2")}}
+\def\xmlreference #1#2{\string\xmlwithindex{#1}{#2}}
+
+%D Entities:
+
+\chardef\xmlautoentities=1 % 0=off, 1=upper, 2=upper,lower
+
+\let\isolatedentity\firstofoneargument
+
+\def\xmlsetentity#1#2{\ctxlua{xml.register_entity('#1',\!!bs\detokenize{#2}\!!es)}}
+\def\xmltexentity#1#2{\ctxlua{xml.register_entity('#1',\!!bs\detokenize{\isolatedentity{#2}}\!!es)}}
+
+% \xmlsetentity{tex}{\TEX{}} % {} needed
+
+\unexpanded\def\xmle
+ {\ifcase\xmlautoentities
+ \expandafter\xmle@none
+ \or
+ \expandafter\xmle@upper
+ \or
+ \expandafter\xmle@upperlower
+ \else
+ \expandafter\xmle@none
+ \fi}
+
+\def\xmle@none#1#2% safe
+ {#1}
+
+\def\xmle@upper#1#2% can be abbreviation
+ {\ifcsname#2\endcsname
+ \csname#2\expandafter\endcsname
+ \else
+ #1%
+ \fi}
+
+\def\xmle@upperlower#1#2% can be anything, so unsafe
+ {\ifcsname#2\endcsname
+ \csname#2\expandafter\endcsname
+ \else\ifcsname#1\endcsname
+ \csname#1\expandafter\expandafter\expandafter\endcsname
+ \else
+ #1%
+ \fi\fi}
+
+\protect \endinput
+
+% \newcount\charactersactiveoffset \charactersactiveoffset="10000
+%
+% \startextendcatcodetable\ctxcatcodes
+% \catcode\numexpr\charactersactiveoffset+`<\relax=13
+% \catcode\numexpr\charactersactiveoffset+`&\relax=13
+% \catcode\numexpr\charactersactiveoffset+`>\relax=13
+% \stopextendcatcodetable
+%
+% \startextendcatcodetable\xmlcatcodes % not needed
+% \catcode\numexpr\charactersactiveoffset+`<\relax=13
+% \catcode\numexpr\charactersactiveoffset+`&\relax=13
+% \catcode\numexpr\charactersactiveoffset+`>\relax=13
+% \stopextendcatcodetable
+%
+% \ctxlua { % entities are remembered in the format
+% characters.remapentity("<",characters.active_offset + utf.byte("<"))
+% characters.remapentity("&",characters.active_offset + utf.byte("&"))
+% characters.remapentity(">",characters.active_offset + utf.byte(">"))
+% }
diff --git a/tex/context/base/lxml-lpt.lua b/tex/context/base/lxml-lpt.lua
new file mode 100644
index 000000000..bddbe4868
--- /dev/null
+++ b/tex/context/base/lxml-lpt.lua
@@ -0,0 +1,1259 @@
+if not modules then modules = { } end modules ['lxml-pth'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- e.ni is only valid after a filter run
+
+local concat, remove, insert = table.concat, table.remove, table.insert
+local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring
+local format, upper, lower, gmatch, gsub, find, rep = string.format, string.upper, string.lower, string.gmatch, string.gsub, string.find, string.rep
+local lpegmatch = lpeg.match
+
+-- beware, this is not xpath ... e.g. position is different (currently) and
+-- we have reverse-sibling as reversed preceding sibling
+
+--[[ldx--
+
This module can be used stand alone but also inside in
+which case it hooks into the tracker code. Therefore we provide a few
+functions that set the tracers. Here we overload a previously defined
+function.
+
If I can get in the mood I will make a variant that is XSLT compliant
+but I wonder if it makes sense.
+--ldx]]--
+
+--[[ldx--
+
Expecially the lpath code is experimental, we will support some of xpath, but
+only things that make sense for us; as compensation it is possible to hook in your
+own functions. Apart from preprocessing content for we also need
+this module for process management, like handling and
+files.
+
+
+a/b/c /*/c
+a/b/c/first() a/b/c/last() a/b/c/index(n) a/b/c/index(-n)
+a/b/c/text() a/b/c/text(1) a/b/c/text(-1) a/b/c/text(n)
+
+--ldx]]--
+
+local trace_lpath = false if trackers then trackers.register("xml.path", function(v) trace_lpath = v end) end
+local trace_lparse = false if trackers then trackers.register("xml.parse", function(v) trace_lparse = v end) end
+local trace_lprofile = false if trackers then trackers.register("xml.profile", function(v) trace_lpath = v trace_lparse = v trace_lprofile = v end) end
+
+--[[ldx--
+
We've now arrived at an interesting part: accessing the tree using a subset
+of and since we're not compatible we call it . We
+will explain more about its usage in other documents.
+--ldx]]--
+
+local lpathcalls = 0 function xml.lpathcalls () return lpathcalls end
+local lpathcached = 0 function xml.lpathcached() return lpathcached end
+
+xml.functions = xml.functions or { } -- internal
+xml.expressions = xml.expressions or { } -- in expressions
+xml.finalizers = xml.finalizers or { } -- fast do-with ... (with return value other than collection)
+xml.specialhandler = xml.specialhandler or { }
+
+local functions = xml.functions
+local expressions = xml.expressions
+local finalizers = xml.finalizers
+
+finalizers.xml = finalizers.xml or { }
+finalizers.tex = finalizers.tex or { }
+
+local function fallback (t, name)
+ local fn = finalizers[name]
+ if fn then
+ t[name] = fn
+ else
+ logs.report("xml","unknown sub finalizer '%s'",tostring(name))
+ fn = function() end
+ end
+ return fn
+end
+
+setmetatable(finalizers.xml, { __index = fallback })
+setmetatable(finalizers.tex, { __index = fallback })
+
+xml.defaultprotocol = "xml"
+
+-- as xsl does not follow xpath completely here we will also
+-- be more liberal especially with regards to the use of | and
+-- the rootpath:
+--
+-- test : all 'test' under current
+-- /test : 'test' relative to current
+-- a|b|c : set of names
+-- (a|b|c) : idem
+-- ! : not
+--
+-- after all, we're not doing transformations but filtering. in
+-- addition we provide filter functions (last bit)
+--
+-- todo: optimizer
+--
+-- .. : parent
+-- * : all kids
+-- / : anchor here
+-- // : /**/
+-- ** : all in between
+--
+-- so far we had (more practical as we don't transform)
+--
+-- {/test} : kids 'test' under current node
+-- {test} : any kid with tag 'test'
+-- {//test} : same as above
+
+-- evaluator (needs to be redone, for the moment copied)
+
+-- todo: apply_axis(list,notable) and collection vs single
+
+local apply_axis = { }
+
+apply_axis['root'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ local rt = ll
+ while ll do
+ ll = ll.__p__
+ if ll then
+ rt = ll
+ end
+ end
+ collected[#collected+1] = rt
+ end
+ return collected
+end
+
+apply_axis['self'] = function(list)
+--~ local collected = { }
+--~ for l=1,#list do
+--~ collected[#collected+1] = list[l]
+--~ end
+--~ return collected
+ return list
+end
+
+apply_axis['child'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ local dt = ll.dt
+ local en = 0
+ for k=1,#dt do
+ local dk = dt[k]
+ if dk.tg then
+ collected[#collected+1] = dk
+ dk.ni = k -- refresh
+ en = en + 1
+ dk.ei = en
+ end
+ end
+ ll.en = en
+ end
+ return collected
+end
+
+local function collect(list,collected)
+ local dt = list.dt
+ if dt then
+ local en = 0
+ for k=1,#dt do
+ local dk = dt[k]
+ if dk.tg then
+ collected[#collected+1] = dk
+ dk.ni = k -- refresh
+ en = en + 1
+ dk.ei = en
+ collect(dk,collected)
+ end
+ end
+ list.en = en
+ end
+end
+apply_axis['descendant'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ collect(list[l],collected)
+ end
+ return collected
+end
+
+local function collect(list,collected)
+ local dt = list.dt
+ if dt then
+ local en = 0
+ for k=1,#dt do
+ local dk = dt[k]
+ if dk.tg then
+ collected[#collected+1] = dk
+ dk.ni = k -- refresh
+ en = en + 1
+ dk.ei = en
+ collect(dk,collected)
+ end
+ end
+ list.en = en
+ end
+end
+apply_axis['descendant-or-self'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ if ll.special ~= true then -- catch double root
+ collected[#collected+1] = ll
+ end
+ collect(ll,collected)
+ end
+ return collected
+end
+
+apply_axis['ancestor'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ while ll do
+ ll = ll.__p__
+ if ll then
+ collected[#collected+1] = ll
+ end
+ end
+ end
+ return collected
+end
+
+apply_axis['ancestor-or-self'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ collected[#collected+1] = ll
+ while ll do
+ ll = ll.__p__
+ if ll then
+ collected[#collected+1] = ll
+ end
+ end
+ end
+ return collected
+end
+
+apply_axis['parent'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local pl = list[l].__p__
+ if pl then
+ collected[#collected+1] = pl
+ end
+ end
+ return collected
+end
+
+apply_axis['attribute'] = function(list)
+ return { }
+end
+
+apply_axis['namespace'] = function(list)
+ return { }
+end
+
+apply_axis['following'] = function(list) -- incomplete
+--~ local collected = { }
+--~ for l=1,#list do
+--~ local ll = list[l]
+--~ local p = ll.__p__
+--~ local d = p.dt
+--~ for i=ll.ni+1,#d do
+--~ local di = d[i]
+--~ if type(di) == "table" then
+--~ collected[#collected+1] = di
+--~ break
+--~ end
+--~ end
+--~ end
+--~ return collected
+ return { }
+end
+
+apply_axis['preceding'] = function(list) -- incomplete
+--~ local collected = { }
+--~ for l=1,#list do
+--~ local ll = list[l]
+--~ local p = ll.__p__
+--~ local d = p.dt
+--~ for i=ll.ni-1,1,-1 do
+--~ local di = d[i]
+--~ if type(di) == "table" then
+--~ collected[#collected+1] = di
+--~ break
+--~ end
+--~ end
+--~ end
+--~ return collected
+ return { }
+end
+
+apply_axis['following-sibling'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ local p = ll.__p__
+ local d = p.dt
+ for i=ll.ni+1,#d do
+ local di = d[i]
+ if type(di) == "table" then
+ collected[#collected+1] = di
+ end
+ end
+ end
+ return collected
+end
+
+apply_axis['preceding-sibling'] = function(list)
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ local p = ll.__p__
+ local d = p.dt
+ for i=1,ll.ni-1 do
+ local di = d[i]
+ if type(di) == "table" then
+ collected[#collected+1] = di
+ end
+ end
+ end
+ return collected
+end
+
+apply_axis['reverse-sibling'] = function(list) -- reverse preceding
+ local collected = { }
+ for l=1,#list do
+ local ll = list[l]
+ local p = ll.__p__
+ local d = p.dt
+ for i=ll.ni-1,1,-1 do
+ local di = d[i]
+ if type(di) == "table" then
+ collected[#collected+1] = di
+ end
+ end
+ end
+ return collected
+end
+
+apply_axis['auto-descendant-or-self'] = apply_axis['descendant-or-self']
+apply_axis['auto-descendant'] = apply_axis['descendant']
+apply_axis['auto-child'] = apply_axis['child']
+apply_axis['auto-self'] = apply_axis['self']
+apply_axis['initial-child'] = apply_axis['child']
+
+local function apply_nodes(list,directive,nodes)
+ -- todo: nodes[1] etc ... negated node name in set ... when needed
+ -- ... currently ignored
+ local maxn = #nodes
+ if maxn == 3 then --optimized loop
+ local nns, ntg = nodes[2], nodes[3]
+ if not nns and not ntg then -- wildcard
+ if directive then
+ return list
+ else
+ return { }
+ end
+ else
+ local collected, m, p = { }, 0, nil
+ if not nns then -- only check tag
+ for l=1,#list do
+ local ll = list[l]
+ local ltg = ll.tg
+ if ltg then
+ if directive then
+ if ntg == ltg then
+ local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end
+ collected[#collected+1], ll.mi = ll, m
+ end
+ elseif ntg ~= ltg then
+ local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end
+ collected[#collected+1], ll.mi = ll, m
+ end
+ end
+ end
+ elseif not ntg then -- only check namespace
+ for l=1,#list do
+ local ll = list[l]
+ local lns = ll.rn or ll.ns
+ if lns then
+ if directive then
+ if lns == nns then
+ local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end
+ collected[#collected+1], ll.mi = ll, m
+ end
+ elseif lns ~= nns then
+ local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end
+ collected[#collected+1], ll.mi = ll, m
+ end
+ end
+ end
+ else -- check both
+ for l=1,#list do
+ local ll = list[l]
+ local ltg = ll.tg
+ if ltg then
+ local lns = ll.rn or ll.ns
+ local ok = ltg == ntg and lns == nns
+ if directive then
+ if ok then
+ local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end
+ collected[#collected+1], ll.mi = ll, m
+ end
+ elseif not ok then
+ local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end
+ collected[#collected+1], ll.mi = ll, m
+ end
+ end
+ end
+ end
+ return collected
+ end
+ else
+ local collected, m, p = { }, 0, nil
+ for l=1,#list do
+ local ll = list[l]
+ local ltg = ll.tg
+ if ltg then
+ local lns = ll.rn or ll.ns
+ local ok = false
+ for n=1,maxn,3 do
+ local nns, ntg = nodes[n+1], nodes[n+2]
+ ok = (not ntg or ltg == ntg) and (not nns or lns == nns)
+ if ok then
+ break
+ end
+ end
+ if directive then
+ if ok then
+ local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end
+ collected[#collected+1], ll.mi = ll, m
+ end
+ elseif not ok then
+ local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end
+ collected[#collected+1], ll.mi = ll, m
+ end
+ end
+ end
+ return collected
+ end
+end
+
+local quit_expression = false
+
+local function apply_expression(list,expression,order)
+ local collected = { }
+ quit_expression = false
+ for l=1,#list do
+ local ll = list[l]
+ if expression(list,ll,l,order) then -- nasty, order alleen valid als n=1
+ collected[#collected+1] = ll
+ end
+ if quit_expression then
+ break
+ end
+ end
+ return collected
+end
+
+local P, V, C, Cs, Cc, Ct, R, S, Cg, Cb = lpeg.P, lpeg.V, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.Ct, lpeg.R, lpeg.S, lpeg.Cg, lpeg.Cb
+
+local spaces = S(" \n\r\t\f")^0
+local lp_space = S(" \n\r\t\f")
+local lp_any = P(1)
+local lp_noequal = P("!=") / "~=" + P("<=") + P(">=") + P("==")
+local lp_doequal = P("=") / "=="
+local lp_or = P("|") / " or "
+local lp_and = P("&") / " and "
+
+local lp_builtin = P (
+ P("firstindex") / "1" +
+ P("lastindex") / "(#ll.__p__.dt or 1)" +
+ P("firstelement") / "1" +
+ P("lastelement") / "(ll.__p__.en or 1)" +
+ P("first") / "1" +
+ P("last") / "#list" +
+ P("rootposition") / "order" +
+ P("position") / "l" + -- is element in finalizer
+ P("order") / "order" +
+ P("element") / "(ll.ei or 1)" +
+ P("index") / "(ll.ni or 1)" +
+ P("match") / "(ll.mi or 1)" +
+ P("text") / "(ll.dt[1] or '')" +
+ -- P("name") / "(ll.ns~='' and ll.ns..':'..ll.tg)" +
+ P("name") / "((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)" +
+ P("tag") / "ll.tg" +
+ P("ns") / "ll.ns"
+ ) * ((spaces * P("(") * spaces * P(")"))/"")
+
+local lp_attribute = (P("@") + P("attribute::")) / "" * Cc("(ll.at and ll.at['") * R("az","AZ","--","__")^1 * Cc("'])")
+local lp_fastpos_p = ((P("+")^0 * R("09")^1 * P(-1)) / function(s) return "l==" .. s end)
+local lp_fastpos_n = ((P("-") * R("09")^1 * P(-1)) / function(s) return "(" .. s .. "<0 and (#list+".. s .. "==l))" end)
+local lp_fastpos = lp_fastpos_n + lp_fastpos_p
+local lp_reserved = C("and") + C("or") + C("not") + C("div") + C("mod") + C("true") + C("false")
+
+local lp_lua_function = C(R("az","AZ","__")^1 * (P(".") * R("az","AZ","__")^1)^1) * ("(") / function(t) -- todo: better . handling
+ return t .. "("
+end
+
+local lp_function = C(R("az","AZ","__")^1) * P("(") / function(t) -- todo: better . handling
+ if expressions[t] then
+ return "expr." .. t .. "("
+ else
+ return "expr.error("
+ end
+end
+
+local lparent = lpeg.P("(")
+local rparent = lpeg.P(")")
+local noparent = 1 - (lparent+rparent)
+local nested = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent}
+local value = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"}
+
+local lp_child = Cc("expr.child(ll,'") * R("az","AZ","--","__")^1 * Cc("')")
+local lp_number = S("+-") * R("09")^1
+local lp_string = Cc("'") * R("az","AZ","--","__")^1 * Cc("'")
+local lp_content = (P("'") * (1-P("'"))^0 * P("'") + P('"') * (1-P('"'))^0 * P('"'))
+
+local cleaner
+
+local lp_special = (C(P("name")+P("text")+P("tag")+P("count")+P("child"))) * value / function(t,s)
+ if expressions[t] then
+ s = s and s ~= "" and lpegmatch(cleaner,s)
+ if s and s ~= "" then
+ return "expr." .. t .. "(ll," .. s ..")"
+ else
+ return "expr." .. t .. "(ll)"
+ end
+ else
+ return "expr.error(" .. t .. ")"
+ end
+end
+
+local content =
+ lp_builtin +
+ lp_attribute +
+ lp_special +
+ lp_noequal + lp_doequal +
+ lp_or + lp_and +
+ lp_reserved +
+ lp_lua_function + lp_function +
+ lp_content + -- too fragile
+ lp_child +
+ lp_any
+
+local converter = Cs (
+ lp_fastpos + (P { lparent * (V(1))^0 * rparent + content } )^0
+)
+
+cleaner = Cs ( (
+--~ lp_fastpos +
+ lp_reserved +
+ lp_number +
+ lp_string +
+1 )^1 )
+
+
+--~ expr
+
+local template_e = [[
+ local expr = xml.expressions
+ return function(list,ll,l,order)
+ return %s
+ end
+]]
+
+local template_f_y = [[
+ local finalizer = xml.finalizers['%s']['%s']
+ return function(collection)
+ return finalizer(collection,%s)
+ end
+]]
+
+local template_f_n = [[
+ return xml.finalizers['%s']['%s']
+]]
+
+--
+
+local register_self = { kind = "axis", axis = "self" } -- , apply = apply_axis["self"] }
+local register_parent = { kind = "axis", axis = "parent" } -- , apply = apply_axis["parent"] }
+local register_descendant = { kind = "axis", axis = "descendant" } -- , apply = apply_axis["descendant"] }
+local register_child = { kind = "axis", axis = "child" } -- , apply = apply_axis["child"] }
+local register_descendant_or_self = { kind = "axis", axis = "descendant-or-self" } -- , apply = apply_axis["descendant-or-self"] }
+local register_root = { kind = "axis", axis = "root" } -- , apply = apply_axis["root"] }
+local register_ancestor = { kind = "axis", axis = "ancestor" } -- , apply = apply_axis["ancestor"] }
+local register_ancestor_or_self = { kind = "axis", axis = "ancestor-or-self" } -- , apply = apply_axis["ancestor-or-self"] }
+local register_attribute = { kind = "axis", axis = "attribute" } -- , apply = apply_axis["attribute"] }
+local register_namespace = { kind = "axis", axis = "namespace" } -- , apply = apply_axis["namespace"] }
+local register_following = { kind = "axis", axis = "following" } -- , apply = apply_axis["following"] }
+local register_following_sibling = { kind = "axis", axis = "following-sibling" } -- , apply = apply_axis["following-sibling"] }
+local register_preceding = { kind = "axis", axis = "preceding" } -- , apply = apply_axis["preceding"] }
+local register_preceding_sibling = { kind = "axis", axis = "preceding-sibling" } -- , apply = apply_axis["preceding-sibling"] }
+local register_reverse_sibling = { kind = "axis", axis = "reverse-sibling" } -- , apply = apply_axis["reverse-sibling"] }
+
+local register_auto_descendant_or_self = { kind = "axis", axis = "auto-descendant-or-self" } -- , apply = apply_axis["auto-descendant-or-self"] }
+local register_auto_descendant = { kind = "axis", axis = "auto-descendant" } -- , apply = apply_axis["auto-descendant"] }
+local register_auto_self = { kind = "axis", axis = "auto-self" } -- , apply = apply_axis["auto-self"] }
+local register_auto_child = { kind = "axis", axis = "auto-child" } -- , apply = apply_axis["auto-child"] }
+
+local register_initial_child = { kind = "axis", axis = "initial-child" } -- , apply = apply_axis["initial-child"] }
+
+local register_all_nodes = { kind = "nodes", nodetest = true, nodes = { true, false, false } }
+
+local skip = { }
+
+local function errorrunner_e(str,cnv)
+ if not skip[str] then
+ logs.report("lpath","error in expression: %s => %s",str,cnv)
+ skip[str] = cnv or str
+ end
+ return false
+end
+local function errorrunner_f(str,arg)
+ logs.report("lpath","error in finalizer: %s(%s)",str,arg or "")
+ return false
+end
+
+local function register_nodes(nodetest,nodes)
+ return { kind = "nodes", nodetest = nodetest, nodes = nodes }
+end
+
+local function register_expression(expression)
+ local converted = lpegmatch(converter,expression)
+ local runner = loadstring(format(template_e,converted))
+ runner = (runner and runner()) or function() errorrunner_e(expression,converted) end
+ return { kind = "expression", expression = expression, converted = converted, evaluator = runner }
+end
+
+local function register_finalizer(protocol,name,arguments)
+ local runner
+ if arguments and arguments ~= "" then
+ runner = loadstring(format(template_f_y,protocol or xml.defaultprotocol,name,arguments))
+ else
+ runner = loadstring(format(template_f_n,protocol or xml.defaultprotocol,name))
+ end
+ runner = (runner and runner()) or function() errorrunner_f(name,arguments) end
+ return { kind = "finalizer", name = name, arguments = arguments, finalizer = runner }
+end
+
+local expression = P { "ex",
+ ex = "[" * C((V("sq") + V("dq") + (1 - S("[]")) + V("ex"))^0) * "]",
+ sq = "'" * (1 - S("'"))^0 * "'",
+ dq = '"' * (1 - S('"'))^0 * '"',
+}
+
+local arguments = P { "ar",
+ ar = "(" * Cs((V("sq") + V("dq") + V("nq") + P(1-P(")")))^0) * ")",
+ nq = ((1 - S("),'\""))^1) / function(s) return format("%q",s) end,
+ sq = P("'") * (1 - P("'"))^0 * P("'"),
+ dq = P('"') * (1 - P('"'))^0 * P('"'),
+}
+
+-- todo: better arg parser
+
+local function register_error(str)
+ return { kind = "error", error = format("unparsed: %s",str) }
+end
+
+-- there is a difference in * and /*/ and so we need to catch a few special cases
+
+local special_1 = P("*") * Cc(register_auto_descendant) * Cc(register_all_nodes) -- last one not needed
+local special_2 = P("/") * Cc(register_auto_self)
+local special_3 = P("") * Cc(register_auto_self)
+
+local parser = Ct { "patterns", -- can be made a bit faster by moving pattern outside
+
+ patterns = spaces * V("protocol") * spaces * (
+ ( V("special") * spaces * P(-1) ) +
+ ( V("initial") * spaces * V("step") * spaces * (P("/") * spaces * V("step") * spaces)^0 )
+ ),
+
+ protocol = Cg(V("letters"),"protocol") * P("://") + Cg(Cc(nil),"protocol"),
+
+ -- the / is needed for // as descendant or self is somewhat special
+ -- step = (V("shortcuts") + V("axis") * spaces * V("nodes")^0 + V("error")) * spaces * V("expressions")^0 * spaces * V("finalizer")^0,
+ step = ((V("shortcuts") + P("/") + V("axis")) * spaces * V("nodes")^0 + V("error")) * spaces * V("expressions")^0 * spaces * V("finalizer")^0,
+
+ axis = V("descendant") + V("child") + V("parent") + V("self") + V("root") + V("ancestor") +
+ V("descendant_or_self") + V("following_sibling") + V("following") +
+ V("reverse_sibling") + V("preceding_sibling") + V("preceding") + V("ancestor_or_self") +
+ #(1-P(-1)) * Cc(register_auto_child),
+
+ special = special_1 + special_2 + special_3,
+
+ initial = (P("/") * spaces * Cc(register_initial_child))^-1,
+
+ error = (P(1)^1) / register_error,
+
+ shortcuts_a = V("s_descendant_or_self") + V("s_descendant") + V("s_child") + V("s_parent") + V("s_self") + V("s_root") + V("s_ancestor"),
+
+ shortcuts = V("shortcuts_a") * (spaces * "/" * spaces * V("shortcuts_a"))^0,
+
+ s_descendant_or_self = (P("***/") + P("/")) * Cc(register_descendant_or_self), --- *** is a bonus
+ -- s_descendant_or_self = P("/") * Cc(register_descendant_or_self),
+ s_descendant = P("**") * Cc(register_descendant),
+ s_child = P("*") * #(1-P(":")) * Cc(register_child ),
+-- s_child = P("*") * #(P("/")+P(-1)) * Cc(register_child ),
+ s_parent = P("..") * Cc(register_parent ),
+ s_self = P("." ) * Cc(register_self ),
+ s_root = P("^^") * Cc(register_root ),
+ s_ancestor = P("^") * Cc(register_ancestor ),
+
+ descendant = P("descendant::") * Cc(register_descendant ),
+ child = P("child::") * Cc(register_child ),
+ parent = P("parent::") * Cc(register_parent ),
+ self = P("self::") * Cc(register_self ),
+ root = P('root::') * Cc(register_root ),
+ ancestor = P('ancestor::') * Cc(register_ancestor ),
+ descendant_or_self = P('descendant-or-self::') * Cc(register_descendant_or_self ),
+ ancestor_or_self = P('ancestor-or-self::') * Cc(register_ancestor_or_self ),
+ -- attribute = P('attribute::') * Cc(register_attribute ),
+ -- namespace = P('namespace::') * Cc(register_namespace ),
+ following = P('following::') * Cc(register_following ),
+ following_sibling = P('following-sibling::') * Cc(register_following_sibling ),
+ preceding = P('preceding::') * Cc(register_preceding ),
+ preceding_sibling = P('preceding-sibling::') * Cc(register_preceding_sibling ),
+ reverse_sibling = P('reverse-sibling::') * Cc(register_reverse_sibling ),
+
+ nodes = (V("nodefunction") * spaces * P("(") * V("nodeset") * P(")") + V("nodetest") * V("nodeset")) / register_nodes,
+
+ expressions = expression / register_expression,
+
+ letters = R("az")^1,
+ name = (1-lpeg.S("/[]()|:*!"))^1,
+ negate = P("!") * Cc(false),
+
+ nodefunction = V("negate") + P("not") * Cc(false) + Cc(true),
+ nodetest = V("negate") + Cc(true),
+ nodename = (V("negate") + Cc(true)) * spaces * ((V("wildnodename") * P(":") * V("wildnodename")) + (Cc(false) * V("wildnodename"))),
+ wildnodename = (C(V("name")) + P("*") * Cc(false)) * #(1-P("(")),
+ nodeset = spaces * Ct(V("nodename") * (spaces * P("|") * spaces * V("nodename"))^0) * spaces,
+
+ finalizer = (Cb("protocol") * P("/")^-1 * C(V("name")) * arguments * P(-1)) / register_finalizer,
+
+}
+
+local cache = { }
+
+local function nodesettostring(set,nodetest)
+ local t = { }
+ for i=1,#set,3 do
+ local directive, ns, tg = set[i], set[i+1], set[i+2]
+ if not ns or ns == "" then ns = "*" end
+ if not tg or tg == "" then tg = "*" end
+ tg = (tg == "@rt@" and "[root]") or format("%s:%s",ns,tg)
+ t[#t+1] = (directive and tg) or format("not(%s)",tg)
+ end
+ if nodetest == false then
+ return format("not(%s)",concat(t,"|"))
+ else
+ return concat(t,"|")
+ end
+end
+
+local function tagstostring(list)
+ if #list == 0 then
+ return "no elements"
+ else
+ local t = { }
+ for i=1, #list do
+ local li = list[i]
+ local ns, tg = li.ns, li.tg
+ if not ns or ns == "" then ns = "*" end
+ if not tg or tg == "" then tg = "*" end
+ t[#t+1] = (tg == "@rt@" and "[root]") or format("%s:%s",ns,tg)
+ end
+ return concat(t," ")
+ end
+end
+
+xml.nodesettostring = nodesettostring
+
+local parse_pattern -- we have a harmless kind of circular reference
+
+local function lshow(parsed)
+ if type(parsed) == "string" then
+ parsed = parse_pattern(parsed)
+ end
+ local s = table.serialize_functions -- ugly
+ table.serialize_functions = false -- ugly
+ logs.report("lpath","%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern,table.serialize(parsed,false))
+ table.serialize_functions = s -- ugly
+end
+
+xml.lshow = lshow
+
+local function add_comment(p,str)
+ local pc = p.comment
+ if not pc then
+ p.comment = { str }
+ else
+ pc[#pc+1] = str
+ end
+end
+
+parse_pattern = function (pattern) -- the gain of caching is rather minimal
+ lpathcalls = lpathcalls + 1
+ if type(pattern) == "table" then
+ return pattern
+ else
+ local parsed = cache[pattern]
+ if parsed then
+ lpathcached = lpathcached + 1
+ else
+ parsed = lpegmatch(parser,pattern)
+ if parsed then
+ parsed.pattern = pattern
+ local np = #parsed
+ if np == 0 then
+ parsed = { pattern = pattern, register_self, state = "parsing error" }
+ logs.report("lpath","parsing error in '%s'",pattern)
+ lshow(parsed)
+ else
+ -- we could have done this with a more complex parser but this
+ -- is cleaner
+ local pi = parsed[1]
+ if pi.axis == "auto-child" then
+ if false then
+ add_comment(parsed, "auto-child replaced by auto-descendant-or-self")
+ parsed[1] = register_auto_descendant_or_self
+ else
+ add_comment(parsed, "auto-child replaced by auto-descendant")
+ parsed[1] = register_auto_descendant
+ end
+ elseif pi.axis == "initial-child" and np > 1 and parsed[2].axis then
+ add_comment(parsed, "initial-child removed") -- we could also make it a auto-self
+ remove(parsed,1)
+ end
+ local np = #parsed -- can have changed
+ if np > 1 then
+ local pnp = parsed[np]
+ if pnp.kind == "nodes" and pnp.nodetest == true then
+ local nodes = pnp.nodes
+ if nodes[1] == true and nodes[2] == false and nodes[3] == false then
+ add_comment(parsed, "redundant final wildcard filter removed")
+ remove(parsed,np)
+ end
+ end
+ end
+ end
+ else
+ parsed = { pattern = pattern }
+ end
+ cache[pattern] = parsed
+ if trace_lparse and not trace_lprofile then
+ lshow(parsed)
+ end
+ end
+ return parsed
+ end
+end
+
+-- we can move all calls inline and then merge the trace back
+-- technically we can combine axis and the next nodes which is
+-- what we did before but this a bit cleaner (but slower too)
+-- but interesting is that it's not that much faster when we
+-- go inline
+--
+-- beware: we need to return a collection even when we filter
+-- else the (simple) cache gets messed up
+
+-- caching found lookups saves not that much (max .1 sec on a 8 sec run)
+-- and it also messes up finalizers
+
+-- watch out: when there is a finalizer, it's always called as there
+-- can be cases that a finalizer returns (or does) something in case
+-- there is no match; an example of this is count()
+
+local profiled = { } xml.profiled = profiled
+
+local function profiled_apply(list,parsed,nofparsed,order)
+ local p = profiled[parsed.pattern]
+ if p then
+ p.tested = p.tested + 1
+ else
+ p = { tested = 1, matched = 0, finalized = 0 }
+ profiled[parsed.pattern] = p
+ end
+ local collected = list
+ for i=1,nofparsed do
+ local pi = parsed[i]
+ local kind = pi.kind
+ if kind == "axis" then
+ collected = apply_axis[pi.axis](collected)
+ elseif kind == "nodes" then
+ collected = apply_nodes(collected,pi.nodetest,pi.nodes)
+ elseif kind == "expression" then
+ collected = apply_expression(collected,pi.evaluator,order)
+ elseif kind == "finalizer" then
+ collected = pi.finalizer(collected)
+ p.matched = p.matched + 1
+ p.finalized = p.finalized + 1
+ return collected
+ end
+ if not collected or #collected == 0 then
+ local pn = i < nofparsed and parsed[nofparsed]
+ if pn and pn.kind == "finalizer" then
+ collected = pn.finalizer(collected)
+ p.finalized = p.finalized + 1
+ return collected
+ end
+ return nil
+ end
+ end
+ if collected then
+ p.matched = p.matched + 1
+ end
+ return collected
+end
+
+local function traced_apply(list,parsed,nofparsed,order)
+ if trace_lparse then
+ lshow(parsed)
+ end
+ logs.report("lpath", "collecting : %s",parsed.pattern)
+ logs.report("lpath", " root tags : %s",tagstostring(list))
+ logs.report("lpath", " order : %s",order or "unset")
+ local collected = list
+ for i=1,nofparsed do
+ local pi = parsed[i]
+ local kind = pi.kind
+ if kind == "axis" then
+ collected = apply_axis[pi.axis](collected)
+ logs.report("lpath", "% 10i : ax : %s",(collected and #collected) or 0,pi.axis)
+ elseif kind == "nodes" then
+ collected = apply_nodes(collected,pi.nodetest,pi.nodes)
+ logs.report("lpath", "% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest))
+ elseif kind == "expression" then
+ collected = apply_expression(collected,pi.evaluator,order)
+ logs.report("lpath", "% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted)
+ elseif kind == "finalizer" then
+ collected = pi.finalizer(collected)
+ logs.report("lpath", "% 10i : fi : %s : %s(%s)",(type(collected) == "table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "")
+ return collected
+ end
+ if not collected or #collected == 0 then
+ local pn = i < nofparsed and parsed[nofparsed]
+ if pn and pn.kind == "finalizer" then
+ collected = pn.finalizer(collected)
+ logs.report("lpath", "% 10i : fi : %s : %s(%s)",(type(collected) == "table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "")
+ return collected
+ end
+ return nil
+ end
+ end
+ return collected
+end
+
+local function normal_apply(list,parsed,nofparsed,order)
+ local collected = list
+ for i=1,nofparsed do
+ local pi = parsed[i]
+ local kind = pi.kind
+ if kind == "axis" then
+ local axis = pi.axis
+ if axis ~= "self" then
+ collected = apply_axis[axis](collected)
+ end
+ elseif kind == "nodes" then
+ collected = apply_nodes(collected,pi.nodetest,pi.nodes)
+ elseif kind == "expression" then
+ collected = apply_expression(collected,pi.evaluator,order)
+ elseif kind == "finalizer" then
+ return pi.finalizer(collected)
+ end
+ if not collected or #collected == 0 then
+ local pf = i < nofparsed and parsed[nofparsed].finalizer
+ if pf then
+ return pf(collected) -- can be anything
+ end
+ return nil
+ end
+ end
+ return collected
+end
+
+local function parse_apply(list,pattern)
+ -- we avoid an extra call
+ local parsed = cache[pattern]
+ if parsed then
+ lpathcalls = lpathcalls + 1
+ lpathcached = lpathcached + 1
+ elseif type(pattern) == "table" then
+ lpathcalls = lpathcalls + 1
+ parsed = pattern
+ else
+ parsed = parse_pattern(pattern) or pattern
+ end
+ if not parsed then
+ return
+ end
+ local nofparsed = #parsed
+ if nofparsed == 0 then
+ return -- something is wrong
+ end
+ local one = list[1]
+ if not one then
+ return -- something is wrong
+ elseif not trace_lpath then
+ return normal_apply(list,parsed,nofparsed,one.mi)
+ elseif trace_lprofile then
+ return profiled_apply(list,parsed,nofparsed,one.mi)
+ else
+ return traced_apply(list,parsed,nofparsed,one.mi)
+ end
+end
+
+-- internal (parsed)
+
+expressions.child = function(e,pattern)
+ return parse_apply({ e },pattern) -- todo: cache
+end
+expressions.count = function(e,pattern)
+ local collected = parse_apply({ e },pattern) -- todo: cache
+ return (collected and #collected) or 0
+end
+
+-- external
+
+expressions.oneof = function(s,...) -- slow
+ local t = {...} for i=1,#t do if s == t[i] then return true end end return false
+end
+expressions.error = function(str)
+ xml.error_handler("unknown function in lpath expression",tostring(str or "?"))
+ return false
+end
+expressions.undefined = function(s)
+ return s == nil
+end
+
+expressions.quit = function(s)
+ if s or s == nil then
+ quit_expression = true
+ end
+ return true
+end
+
+expressions.print = function(...)
+ print(...)
+ return true
+end
+
+expressions.contains = find
+expressions.find = find
+expressions.upper = upper
+expressions.lower = lower
+expressions.number = tonumber
+expressions.boolean = toboolean
+
+-- user interface
+
+local function traverse(root,pattern,handle)
+ logs.report("xml","use 'xml.selection' instead for '%s'",pattern)
+ local collected = parse_apply({ root },pattern)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local r = e.__p__
+ handle(r,r.dt,e.ni)
+ end
+ end
+end
+
+local function selection(root,pattern,handle)
+ local collected = parse_apply({ root },pattern)
+ if collected then
+ if handle then
+ for c=1,#collected do
+ handle(collected[c])
+ end
+ else
+ return collected
+ end
+ end
+end
+
+xml.parse_parser = parser
+xml.parse_pattern = parse_pattern
+xml.parse_apply = parse_apply
+xml.traverse = traverse -- old method, r, d, k
+xml.selection = selection -- new method, simple handle
+
+local lpath = parse_pattern
+
+xml.lpath = lpath
+
+function xml.cached_patterns()
+ return cache
+end
+
+-- generic function finalizer (independant namespace)
+
+local function dofunction(collected,fnc)
+ if collected then
+ local f = functions[fnc]
+ if f then
+ for c=1,#collected do
+ f(collected[c])
+ end
+ else
+ logs.report("xml","unknown function '%s'",fnc)
+ end
+ end
+end
+
+xml.finalizers.xml["function"] = dofunction
+xml.finalizers.tex["function"] = dofunction
+
+-- functions
+
+expressions.text = function(e,n)
+ local rdt = e.__p__.dt
+ return (rdt and rdt[n]) or ""
+end
+
+expressions.name = function(e,n) -- ns + tg
+ local found = false
+ n = tonumber(n) or 0
+ if n == 0 then
+ found = type(e) == "table" and e
+ elseif n < 0 then
+ local d, k = e.__p__.dt, e.ni
+ for i=k-1,1,-1 do
+ local di = d[i]
+ if type(di) == "table" then
+ if n == -1 then
+ found = di
+ break
+ else
+ n = n + 1
+ end
+ end
+ end
+ else
+ local d, k = e.__p__.dt, e.ni
+ for i=k+1,#d,1 do
+ local di = d[i]
+ if type(di) == "table" then
+ if n == 1 then
+ found = di
+ break
+ else
+ n = n - 1
+ end
+ end
+ end
+ end
+ if found then
+ local ns, tg = found.rn or found.ns or "", found.tg
+ if ns ~= "" then
+ return ns .. ":" .. tg
+ else
+ return tg
+ end
+ else
+ return ""
+ end
+end
+
+expressions.tag = function(e,n) -- only tg
+ if not e then
+ return ""
+ else
+ local found = false
+ n = tonumber(n) or 0
+ if n == 0 then
+ found = (type(e) == "table") and e -- seems to fail
+ elseif n < 0 then
+ local d, k = e.__p__.dt, e.ni
+ for i=k-1,1,-1 do
+ local di = d[i]
+ if type(di) == "table" then
+ if n == -1 then
+ found = di
+ break
+ else
+ n = n + 1
+ end
+ end
+ end
+ else
+ local d, k = e.__p__.dt, e.ni
+ for i=k+1,#d,1 do
+ local di = d[i]
+ if type(di) == "table" then
+ if n == 1 then
+ found = di
+ break
+ else
+ n = n - 1
+ end
+ end
+ end
+ end
+ return (found and found.tg) or ""
+ end
+end
+
+--[[ldx--
+
This is the main filter function. It returns whatever is asked for.
+--ldx]]--
+
+function xml.filter(root,pattern) -- no longer funny attribute handling here
+ return parse_apply({ root },pattern)
+end
+
+--[[ldx--
+
Often using an iterators looks nicer in the code than passing handler
+functions. The book describes how to use coroutines for that
+purpose (). This permits
+code like:
+
+
+for r, d, k in xml.elements(xml.load('text.xml'),"title") do
+ print(d[k]) -- old method
+end
+for e in xml.collected(xml.load('text.xml'),"title") do
+ print(e) -- new one
+end
+
+--ldx]]--
+
+local wrap, yield = coroutine.wrap, coroutine.yield
+
+function xml.elements(root,pattern,reverse) -- r, d, k
+ local collected = parse_apply({ root },pattern)
+ if collected then
+ if reverse then
+ return wrap(function() for c=#collected,1,-1 do
+ local e = collected[c] local r = e.__p__ yield(r,r.dt,e.ni)
+ end end)
+ else
+ return wrap(function() for c=1,#collected do
+ local e = collected[c] local r = e.__p__ yield(r,r.dt,e.ni)
+ end end)
+ end
+ end
+ return wrap(function() end)
+end
+
+function xml.collected(root,pattern,reverse) -- e
+ local collected = parse_apply({ root },pattern)
+ if collected then
+ if reverse then
+ return wrap(function() for c=#collected,1,-1 do yield(collected[c]) end end)
+ else
+ return wrap(function() for c=1,#collected do yield(collected[c]) end end)
+ end
+ end
+ return wrap(function() end)
+end
diff --git a/tex/context/base/lxml-mis.lua b/tex/context/base/lxml-mis.lua
new file mode 100644
index 000000000..9fd4270af
--- /dev/null
+++ b/tex/context/base/lxml-mis.lua
@@ -0,0 +1,99 @@
+if not modules then modules = { } end modules ['lxml-mis'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local concat = table.concat
+local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring
+local format, gsub, match = string.format, string.gsub, string.match
+local lpegmatch = lpeg.match
+
+--[[ldx--
+
The following helper functions best belong to the lxml-ini
+module. Some are here because we need then in the mk
+document and other manuals, others came up when playing with
+this module. Since this module is also used in we've
+put them here instead of loading mode modules there then needed.
+--ldx]]--
+
+local function xmlgsub(t,old,new) -- will be replaced
+ local dt = t.dt
+ if dt then
+ for k=1,#dt do
+ local v = dt[k]
+ if type(v) == "string" then
+ dt[k] = gsub(v,old,new)
+ else
+ xmlgsub(v,old,new)
+ end
+ end
+ end
+end
+
+--~ xml.gsub = xmlgsub
+
+function xml.strip_leading_spaces(dk,d,k) -- cosmetic, for manual
+ if d and k then
+ local dkm = d[k-1]
+ if dkm and type(dkm) == "string" then
+ local s = match(dkm,"\n(%s+)")
+ xmlgsub(dk,"\n"..rep(" ",#s),"\n")
+ end
+ end
+end
+
+--~ xml.escapes = { ['&'] = '&', ['<'] = '<', ['>'] = '>', ['"'] = '"' }
+--~ xml.unescapes = { } for k,v in next, xml.escapes do xml.unescapes[v] = k end
+
+--~ function xml.escaped (str) return (gsub(str,"(.)" , xml.escapes )) end
+--~ function xml.unescaped(str) return (gsub(str,"(&.-;)", xml.unescapes)) end
+--~ function xml.cleansed (str) return (gsub(str,"<.->" , '' )) end -- "%b<>"
+
+local P, S, R, C, V, Cc, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Cs
+
+-- 100 * 2500 * "oeps< oeps> oeps&" : gsub:lpeg|lpeg|lpeg
+--
+-- 1021:0335:0287:0247
+
+-- 10 * 1000 * "oeps< oeps> oeps& asfjhalskfjh alskfjh alskfjh alskfjh ;al J;LSFDJ"
+--
+-- 1559:0257:0288:0190 (last one suggested by roberto)
+
+-- escaped = Cs((S("<&>") / xml.escapes + 1)^0)
+-- escaped = Cs((S("<")/"<" + S(">")/">" + S("&")/"&" + 1)^0)
+local normal = (1 - S("<&>"))^0
+local special = P("<")/"<" + P(">")/">" + P("&")/"&"
+local escaped = Cs(normal * (special * normal)^0)
+
+-- 100 * 1000 * "oeps< oeps> oeps&" : gsub:lpeg == 0153:0280:0151:0080 (last one by roberto)
+
+local normal = (1 - S"&")^0
+local special = P("<")/"<" + P(">")/">" + P("&")/"&"
+local unescaped = Cs(normal * (special * normal)^0)
+
+-- 100 * 5000 * "oeps oeps oeps " : gsub:lpeg == 623:501 msec (short tags, less difference)
+
+local cleansed = Cs(((P("<") * (1-P(">"))^0 * P(">"))/"" + 1)^0)
+
+xml.escaped_pattern = escaped
+xml.unescaped_pattern = unescaped
+xml.cleansed_pattern = cleansed
+
+function xml.escaped (str) return lpegmatch(escaped,str) end
+function xml.unescaped(str) return lpegmatch(unescaped,str) end
+function xml.cleansed (str) return lpegmatch(cleansed,str) end
+
+-- this might move
+
+function xml.fillin(root,pattern,str,check)
+ local e = xml.first(root,pattern)
+ if e then
+ local n = #e.dt
+ if not check or n == 0 or (n == 1 and e.dt[1] == "") then
+ e.dt = { str }
+ end
+ end
+end
diff --git a/tex/context/base/lxml-sor.lua b/tex/context/base/lxml-sor.lua
new file mode 100644
index 000000000..e220bfad6
--- /dev/null
+++ b/tex/context/base/lxml-sor.lua
@@ -0,0 +1,158 @@
+if not modules then modules = { } end modules ['lxml-sor'] = {
+ version = 1.001,
+ comment = "companion to lxml-sor.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, concat = string.format, table.concat
+local lpegmatch = lpeg.match
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+
+lxml.sorters = lxml.sorters or { }
+
+if not lxml.splitid then
+ local splitter = lpeg.C((1-lpeg.P(":"))^1) * lpeg.P("::") * lpeg.C(lpeg.P(1)^1)
+ function lxml.splitid(id)
+ local d, i = lpegmatch(splitter,id)
+ if d then
+ return d, i
+ else
+ return "", id
+ end
+ end
+end
+
+local lists = { }
+
+function lxml.sorters.reset(name)
+ lists[name] = {
+ sorted = false,
+ entries = { },
+ reverse = { },
+ results = { },
+ }
+end
+
+function lxml.sorters.add(name,n,key)
+ local list = lists[name]
+ if list.sorted then
+ -- reverse is messed up, we could regenerate it and go on
+ else
+ local entries = list and list.entries
+ if entries then
+ local reverse = list.reverse
+ local e = reverse[n]
+ if e then
+ local keys = entries[e][2]
+ keys[#keys+1] = key
+ else
+ entries[#entries+1] = { n, { key } }
+ reverse[n] = #entries
+ end
+ end
+ end
+end
+
+function lxml.sorters.show(name)
+ local list = lists[name]
+ local entries = list and list.entries
+ local NC, NR, bold = context.NC, context.NR, context.bold -- somehow bold is not working
+ if entries then
+ local maxn = 1
+ for i=1,#entries do
+ if #entries[i][2] > maxn then maxn = #entries[i][2] end
+ end
+ context.starttabulate { "|Tr|Tr|" .. string.rep("Tlp|",maxn) }
+ NC() bold("n")
+ NC() bold("id")
+ if maxn > 1 then
+ for i=1,maxn do
+ NC() bold("entry " .. i)
+ end
+ else
+ NC() bold("entry")
+ end
+ NC() NR()
+ context.HL()
+ for i=1,#entries do
+ local entry = entries[i]
+ local document, node = lxml.splitid(entry[1])
+ NC() context(i)
+ NC() context(node)
+ local e = entry[2]
+ for i=1,#e do
+ NC() context.detokenize(e[i])
+ end
+ NC() NR()
+ end
+ context.stoptabulate()
+ end
+end
+
+lxml.sorters.compare = sorters.comparers.basic -- (a,b)
+
+function lxml.sorters.sort(name)
+ local list = lists[name]
+ local entries = list and list.entries
+ if entries then
+ -- filtering
+ local results = { }
+ list.results = results
+ for i=1,#entries do
+ local entry = entries[i]
+ results[i] = {
+ entry = entry[1],
+ key = concat(entry[2], " "),
+ }
+ end
+ -- preparation
+ local strip = sorters.strip
+ local splitter = sorters.splitters.utf
+ local firstofsplit = sorters.firstofsplit
+ for i=1, #results do
+ local r = results[i]
+ r.split = splitter(strip(r.key))
+ end
+ -- sorting
+ sorters.sort(results,lxml.sorters.compare)
+ -- finalizing
+ list.nofsorted = #results
+ local split = { }
+ for k=1,#results do -- rather generic so maybe we need a function
+ local v = results[k]
+ local entry, tag = firstofsplit(v)
+ local s = split[entry] -- keeps track of change
+ if not s then
+ s = { tag = tag, data = { } }
+ split[entry] = s
+ end
+ s.data[#s.data+1] = v
+ end
+ list.results = split
+ -- done
+ list.sorted = true
+ end
+end
+
+function lxml.sorters.flush(name,setup)
+ local list = lists[name]
+ local results = list and list.results
+ local xmlw = context.xmlw
+ if results and next(results) then
+ for key, result in next, results do
+ local tag, data = result.tag, result.data
+ for d=1,#data do
+ xmlw(setup,data[d].entry)
+ end
+ end
+ else
+ local entries = list and list.entries
+ if entries then
+ for i=1,#entries do
+ xmlw(setup,entries[i][1])
+ end
+ end
+ end
+end
diff --git a/tex/context/base/lxml-sor.mkiv b/tex/context/base/lxml-sor.mkiv
new file mode 100644
index 000000000..14425967b
--- /dev/null
+++ b/tex/context/base/lxml-sor.mkiv
@@ -0,0 +1,94 @@
+%D \module
+%D [ file=lxml-sor,
+%D version=2009.08.24,
+%D title=\CONTEXT\ \XML\ Support,
+%D subtitle=Sorting,
+%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.
+
+%D THIS IS VERY EXPERIMENTAL!
+
+\writestatus{loading}{ConTeXt XML Support / Sorting}
+
+\registerctxluafile{lxml-sor}{1.001}
+
+\unprotect
+
+\def\xmlresetsorter #1{\ctxlua{lxml.sorters.reset("#1")}}
+\def\xmladdsortentry#1#2#3{\ctxlua{lxml.sorters.add("#1","#2",\!!bs#3\!!es)}}
+\def\xmlshowsorter #1{\ctxlua{lxml.sorters.show("#1")}}
+\def\xmlflushsorter #1#2{\ctxlua{lxml.sorters.flush("#1","#2")}}
+\def\xmlsortentries #1{\ctxlua{lxml.sorters.sort("#1")}}
+
+\protect \endinput
+
+\startbuffer[test]
+
+
+ one
+ alpha
+ alpha indeed
+
+
+ one
+ gamma
+ gamma indeed
+
+
+ one
+ beta
+ beta indeed
+
+
+ two
+ alpha
+ alpha again
+
+
+ two
+ gamma
+ gamma again
+
+
+ two
+ beta
+ beta again
+
+
+\stopbuffer
+
+\startxmlsetups xml:mysetups
+ \xmlsetsetup{\xmldocument}{demo|entry|content}{xml:*}
+\stopxmlsetups
+
+\xmlregistersetup{xml:mysetups}
+
+\startxmlsetups xml:demo
+ \xmlresetsorter{demo}
+ \xmlfilter{#1}{entry/command(xml:entry:getkeys)}
+ \blank sortkeys: \blank\xmlshowsorter{demo}\blank
+ \xmlsortentries{demo}
+ \xmlflushsorter{demo}{xml:entry:flush}
+\stopxmlsetups
+
+\startxmlsetups xml:entry:getkeys
+ \xmladdsortentry{demo}{#1}{\xmltext{#1}{category}}
+ \xmladdsortentry{demo}{#1}{\xmltext{#1}{key|entry}}
+\stopxmlsetups
+
+\startxmlsetups xml:entry:flush
+ \xmltext{#1}{content}\par
+\stopxmlsetups
+
+\startxmlsetups xml:entry
+ \xmltext{#1}{content}\par
+\stopxmlsetups
+
+\starttext
+ \xmlprocessbuffer{main}{test}{}
+\stoptext
diff --git a/tex/context/base/lxml-tab.lua b/tex/context/base/lxml-tab.lua
new file mode 100644
index 000000000..23cd1cf04
--- /dev/null
+++ b/tex/context/base/lxml-tab.lua
@@ -0,0 +1,1174 @@
+if not modules then modules = { } end modules ['lxml-tab'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this module needs a cleanup: check latest lpeg, passing args, (sub)grammar, etc etc
+-- stripping spaces from e.g. cont-en.xml saves .2 sec runtime so it's not worth the
+-- trouble
+
+local trace_entities = false trackers.register("xml.entities", function(v) trace_entities = v end)
+
+--[[ldx--
+
The parser used here is inspired by the variant discussed in the lua book, but
+handles comment and processing instructions, has a different structure, provides
+parent access; a first version used different trickery but was less optimized to we
+went this route. First we had a find based parser, now we have an based one.
+The find based parser can be found in l-xml-edu.lua along with other older code.
+
+
Beware, the interface may change. For instance at, ns, tg, dt may get more
+verbose names. Once the code is stable we will also remove some tracing and
+optimize the code.
First a hack to enable namespace resolving. A namespace is characterized by
+a . The following function associates a namespace prefix with a
+pattern. We use , which in this case is more than twice as fast as a
+find based solution where we loop over an array of patterns. Less code and
+much cleaner.
The next function associates a namespace prefix with an . This
+normally happens independent of parsing.
+
+
+xml.registerns("mml","mathml")
+
+--ldx]]--
+
+function xml.registerns(namespace, pattern) -- pattern can be an lpeg
+ check = check + C(P(lower(pattern))) / namespace
+ parse = P { P(check) + 1 * V(1) }
+end
+
+--[[ldx--
+
The next function also registers a namespace, but this time we map a
+given namespace prefix onto a registered one, using the given
+. This used for attributes like xmlns:m.
+
+
+xml.checkns("m","http://www.w3.org/mathml")
+
+--ldx]]--
+
+function xml.checkns(namespace,url)
+ local ns = lpegmatch(parse,lower(url))
+ if ns and namespace ~= ns then
+ xml.xmlns[namespace] = ns
+ end
+end
+
+--[[ldx--
+
Next we provide a way to turn an into a registered
+namespace. This used for the xmlns attribute.
A namespace in an element can be remapped onto the registered
+one efficiently by using the xml.xmlns table.
+--ldx]]--
+
+--[[ldx--
+
This version uses . We follow the same approach as before, stack and top and
+such. This version is about twice as fast which is mostly due to the fact that
+we don't have to prepare the stream for cdata, doctype etc etc. This variant is
+is dedicated to Luigi Scarso, who challenged me with 40 megabyte files that
+took 12.5 seconds to load (1.5 for file io and the rest for tree building). With
+the implementation we got that down to less 7.3 seconds. Loading the 14
+ interface definition files (2.6 meg) went down from 1.05 seconds to 0.55.
+
+
Next comes the parser. The rather messy doctype definition comes in many
+disguises so it is no surprice that later on have to dedicate quite some
+ code to it.
+
+
+
+
+
+
+
+
+
+
+
The code may look a bit complex but this is mostly due to the fact that we
+resolve namespaces and attach metatables. There is only one public function:
+
+
+local x = xml.convert(somestring)
+
+
+
An optional second boolean argument tells this function not to create a root
+element.
+
+
Valid entities are:
+
+
+
+
+
+
+--ldx]]--
+
+-- not just one big nested table capture (lpeg overflow)
+
+local nsremap, resolvens = xml.xmlns, xml.resolvens
+
+local stack, top, dt, at, xmlns, errorstr, entities = { }, { }, { }, { }, { }, nil, { }
+local strip, cleanup, utfize, resolve, resolve_predefined, unify_predefined = false, false, false, false, false, false
+local dcache, hcache, acache = { }, { }, { }
+
+local mt = { }
+
+function initialize_mt(root)
+ mt = { __index = root } -- will be redefined later
+end
+
+function xml.setproperty(root,k,v)
+ getmetatable(root).__index[k] = v
+end
+
+function xml.check_error(top,toclose)
+ return ""
+end
+
+local function add_attribute(namespace,tag,value)
+ if cleanup and #value > 0 then
+ value = cleanup(value) -- new
+ end
+ if tag == "xmlns" then
+ xmlns[#xmlns+1] = resolvens(value)
+ at[tag] = value
+ elseif namespace == "" then
+ at[tag] = value
+ elseif namespace == "xmlns" then
+ xml.checkns(tag,value)
+ at["xmlns:" .. tag] = value
+ else
+ -- for the moment this way:
+ at[namespace .. ":" .. tag] = value
+ end
+end
+
+local function add_empty(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
+ top = stack[#stack]
+ dt = top.dt
+ local t = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = top }
+ dt[#dt+1] = t
+ setmetatable(t, mt)
+ if at.xmlns then
+ remove(xmlns)
+ end
+ at = { }
+end
+
+local function add_begin(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
+ top = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = stack[#stack] }
+ setmetatable(top, mt)
+ dt = top.dt
+ stack[#stack+1] = top
+ at = { }
+end
+
+local function add_end(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local toclose = remove(stack)
+ top = stack[#stack]
+ if #stack < 1 then
+ errorstr = format("nothing to close with %s %s", tag, xml.check_error(top,toclose) or "")
+ elseif toclose.tg ~= tag then -- no namespace check
+ errorstr = format("unable to close %s with %s %s", toclose.tg, tag, xml.check_error(top,toclose) or "")
+ end
+ dt = top.dt
+ dt[#dt+1] = toclose
+ -- dt[0] = top -- nasty circular reference when serializing table
+ if toclose.at.xmlns then
+ remove(xmlns)
+ end
+end
+
+local function add_text(text)
+ if cleanup and #text > 0 then
+ dt[#dt+1] = cleanup(text)
+ else
+ dt[#dt+1] = text
+ end
+end
+
+local function add_special(what, spacing, text)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ if strip and (what == "@cm@" or what == "@dt@") then
+ -- forget it
+ else
+ dt[#dt+1] = { special=true, ns="", tg=what, dt={ text } }
+ end
+end
+
+local function set_message(txt)
+ errorstr = "garbage at the end of the file: " .. gsub(txt,"([ \n\r\t]*)","")
+end
+
+local reported_attribute_errors = { }
+
+local function attribute_value_error(str)
+ if not reported_attribute_errors[str] then
+ logs.report("xml","invalid attribute value: %q",str)
+ reported_attribute_errors[str] = true
+ at._error_ = str
+ end
+ return str
+end
+local function attribute_specification_error(str)
+ if not reported_attribute_errors[str] then
+ logs.report("xml","invalid attribute specification: %q",str)
+ reported_attribute_errors[str] = true
+ at._error_ = str
+ end
+ return str
+end
+
+function xml.unknown_dec_entity_format(str) return (str == "" and "&error;") or format("&%s;",str) end
+function xml.unknown_hex_entity_format(str) return format("%s;",str) end
+function xml.unknown_any_entity_format(str) return format("%s;",str) end
+
+local function fromhex(s)
+ local n = tonumber(s,16)
+ if n then
+ return utfchar(n)
+ else
+ return format("h:%s",s), true
+ end
+end
+
+local function fromdec(s)
+ local n = tonumber(s)
+ if n then
+ return utfchar(n)
+ else
+ return format("d:%s",s), true
+ end
+end
+
+-- one level expansion (simple case), no checking done
+
+local rest = (1-P(";"))^0
+local many = P(1)^0
+
+local parsedentity =
+ P("&") * (P("#x")*(rest/fromhex) + P("#")*(rest/fromdec)) * P(";") * P(-1) +
+ (P("#x")*(many/fromhex) + P("#")*(many/fromdec))
+
+-- parsing in the xml file
+
+local predefined_unified = {
+ [38] = "&",
+ [42] = """,
+ [47] = "'",
+ [74] = "<",
+ [76] = "&gr;",
+}
+
+local predefined_simplified = {
+ [38] = "&", amp = "&",
+ [42] = '"', quot = '"',
+ [47] = "'", apos = "'",
+ [74] = "<", lt = "<",
+ [76] = ">", gt = ">",
+}
+
+local function handle_hex_entity(str)
+ local h = hcache[str]
+ if not h then
+ local n = tonumber(str,16)
+ h = unify_predefined and predefined_unified[n]
+ if h then
+ if trace_entities then
+ logs.report("xml","utfize, converting hex entity %s; into %s",str,h)
+ end
+ elseif utfize then
+ h = (n and utfchar(n)) or xml.unknown_hex_entity_format(str) or ""
+ if not n then
+ logs.report("xml","utfize, ignoring hex entity %s;",str)
+ elseif trace_entities then
+ logs.report("xml","utfize, converting hex entity %s; into %s",str,h)
+ end
+ else
+ if trace_entities then
+ logs.report("xml","found entity %s;",str)
+ end
+ h = "" .. str .. ";"
+ end
+ hcache[str] = h
+ end
+ return h
+end
+
+local function handle_dec_entity(str)
+ local d = dcache[str]
+ if not d then
+ local n = tonumber(str)
+ d = unify_predefined and predefined_unified[n]
+ if d then
+ if trace_entities then
+ logs.report("xml","utfize, converting dec entity %s; into %s",str,d)
+ end
+ elseif utfize then
+ d = (n and utfchar(n)) or xml.unknown_dec_entity_format(str) or ""
+ if not n then
+ logs.report("xml","utfize, ignoring dec entity %s;",str)
+ elseif trace_entities then
+ logs.report("xml","utfize, converting dec entity %s; into %s",str,h)
+ end
+ else
+ if trace_entities then
+ logs.report("xml","found entity %s;",str)
+ end
+ d = "" .. str .. ";"
+ end
+ dcache[str] = d
+ end
+ return d
+end
+
+xml.parsedentitylpeg = parsedentity
+
+local function handle_any_entity(str)
+ if resolve then
+ local a = acache[str] -- per instance ! todo
+ if not a then
+ a = resolve_predefined and predefined_simplified[str]
+ if a then
+ -- one of the predefined
+ elseif type(resolve) == "function" then
+ a = resolve(str) or entities[str]
+ else
+ a = entities[str]
+ end
+ if a then
+ if trace_entities then
+ logs.report("xml","resolved entity &%s; -> %s (internal)",str,a)
+ end
+ a = lpegmatch(parsedentity,a) or a
+ else
+ if xml.unknown_any_entity_format then
+ a = xml.unknown_any_entity_format(str) or ""
+ end
+ if a then
+ if trace_entities then
+ logs.report("xml","resolved entity &%s; -> %s (external)",str,a)
+ end
+ else
+ if trace_entities then
+ logs.report("xml","keeping entity &%s;",str)
+ end
+ if str == "" then
+ a = "&error;"
+ else
+ a = "&" .. str .. ";"
+ end
+ end
+ end
+ acache[str] = a
+ elseif trace_entities then
+ if not acache[str] then
+ logs.report("xml","converting entity &%s; into %s",str,a)
+ acache[str] = a
+ end
+ end
+ return a
+ else
+ local a = acache[str]
+ if not a then
+ if trace_entities then
+ logs.report("xml","found entity &%s;",str)
+ end
+ a = resolve_predefined and predefined_simplified[str]
+ if a then
+ -- one of the predefined
+ acache[str] = a
+ elseif str == "" then
+ a = "&error;"
+ acache[str] = a
+ else
+ a = "&" .. str .. ";"
+ acache[str] = a
+ end
+ end
+ return a
+ end
+end
+
+local function handle_end_entity(chr)
+ logs.report("xml","error in entity, %q found instead of ';'",chr)
+end
+
+local space = S(' \r\n\t')
+local open = P('<')
+local close = P('>')
+local squote = S("'")
+local dquote = S('"')
+local equal = P('=')
+local slash = P('/')
+local colon = P(':')
+local semicolon = P(';')
+local ampersand = P('&')
+local valid = R('az', 'AZ', '09') + S('_-.')
+local name_yes = C(valid^1) * colon * C(valid^1)
+local name_nop = C(P(true)) * C(valid^1)
+local name = name_yes + name_nop
+local utfbom = lpeg.patterns.utfbom -- no capture
+local spacing = C(space^0)
+
+----- entitycontent = (1-open-semicolon)^0
+local anyentitycontent = (1-open-semicolon-space-close)^0
+local hexentitycontent = R("AF","af","09")^0
+local decentitycontent = R("09")^0
+local parsedentity = P("#")/"" * (
+ P("x")/"" * (hexentitycontent/handle_hex_entity) +
+ (decentitycontent/handle_dec_entity)
+ ) + (anyentitycontent/handle_any_entity)
+local entity = ampersand/"" * parsedentity * ( (semicolon/"") + #(P(1)/handle_end_entity))
+
+local text_unparsed = C((1-open)^1)
+local text_parsed = Cs(((1-open-ampersand)^1 + entity)^1)
+
+local somespace = space^1
+local optionalspace = space^0
+
+----- value = (squote * C((1 - squote)^0) * squote) + (dquote * C((1 - dquote)^0) * dquote) -- ampersand and < also invalid in value
+local value = (squote * Cs((entity + (1 - squote))^0) * squote) + (dquote * Cs((entity + (1 - dquote))^0) * dquote) -- ampersand and < also invalid in value
+
+local endofattributes = slash * close + close -- recovery of flacky html
+local whatever = space * name * optionalspace * equal
+local wrongvalue = C(P(1-whatever-close)^1 + P(1-close)^1) / attribute_value_error
+----- wrongvalue = C(P(1-whatever-endofattributes)^1 + P(1-endofattributes)^1) / attribute_value_error
+----- wrongvalue = C(P(1-space-endofattributes)^1) / attribute_value_error
+local wrongvalue = Cs(P(entity + (1-space-endofattributes))^1) / attribute_value_error
+
+local attributevalue = value + wrongvalue
+
+local attribute = (somespace * name * optionalspace * equal * optionalspace * attributevalue) / add_attribute
+----- attributes = (attribute)^0
+
+local attributes = (attribute + somespace^-1 * (((1-endofattributes)^1)/attribute_specification_error))^0
+
+local parsedtext = text_parsed / add_text
+local unparsedtext = text_unparsed / add_text
+local balanced = P { "[" * ((1 - S"[]") + V(1))^0 * "]" } -- taken from lpeg manual, () example
+
+local emptyelement = (spacing * open * name * attributes * optionalspace * slash * close) / add_empty
+local beginelement = (spacing * open * name * attributes * optionalspace * close) / add_begin
+local endelement = (spacing * open * slash * name * optionalspace * close) / add_end
+
+local begincomment = open * P("!--")
+local endcomment = P("--") * close
+local begininstruction = open * P("?")
+local endinstruction = P("?") * close
+local begincdata = open * P("![CDATA[")
+local endcdata = P("]]") * close
+
+local someinstruction = C((1 - endinstruction)^0)
+local somecomment = C((1 - endcomment )^0)
+local somecdata = C((1 - endcdata )^0)
+
+local function normalentity(k,v ) entities[k] = v end
+local function systementity(k,v,n) entities[k] = v end
+local function publicentity(k,v,n) entities[k] = v end
+
+local begindoctype = open * P("!DOCTYPE")
+local enddoctype = close
+local beginset = P("[")
+local endset = P("]")
+local doctypename = C((1-somespace-close)^0)
+local elementdoctype = optionalspace * P(" &
+ cleanup = settings.text_cleanup
+ stack, top, at, xmlns, errorstr, result, entities = { }, { }, { }, { }, nil, nil, settings.entities or { }
+ acache, hcache, dcache = { }, { }, { } -- not stored
+ reported_attribute_errors = { }
+ if settings.parent_root then
+ mt = getmetatable(settings.parent_root)
+ else
+ initialize_mt(top)
+ end
+ stack[#stack+1] = top
+ top.dt = { }
+ dt = top.dt
+ if not data or data == "" then
+ errorstr = "empty xml file"
+ elseif utfize or resolve then
+ if lpegmatch(grammar_parsed_text,data) then
+ errorstr = ""
+ else
+ errorstr = "invalid xml file - parsed text"
+ end
+ elseif type(data) == "string" then
+ if lpegmatch(grammar_unparsed_text,data) then
+ errorstr = ""
+ else
+ errorstr = "invalid xml file - unparsed text"
+ end
+ else
+ errorstr = "invalid xml file - no text at all"
+ end
+ if errorstr and errorstr ~= "" then
+ result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={ }, er = true } } }
+ setmetatable(stack, mt)
+ local error_handler = settings.error_handler
+ if error_handler == false then
+ -- no error message
+ else
+ error_handler = error_handler or xml.error_handler
+ if error_handler then
+ xml.error_handler("load",errorstr)
+ end
+ end
+ else
+ result = stack[1]
+ end
+ if not settings.no_root then
+ result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={ }, entities = entities, settings = settings }
+ setmetatable(result, mt)
+ local rdt = result.dt
+ for k=1,#rdt do
+ local v = rdt[k]
+ if type(v) == "table" and not v.special then -- always table -)
+ result.ri = k -- rootindex
+v.__p__ = result -- new, experiment, else we cannot go back to settings, we need to test this !
+ break
+ end
+ end
+ end
+ if errorstr and errorstr ~= "" then
+ result.error = true
+ end
+ return result
+end
+
+xml.convert = xmlconvert
+
+function xml.inheritedconvert(data,xmldata)
+ local settings = xmldata.settings
+ settings.parent_root = xmldata -- to be tested
+ -- settings.no_root = true
+ local xc = xmlconvert(data,settings)
+ -- xc.settings = nil
+ -- xc.entities = nil
+ -- xc.special = nil
+ -- xc.ri = nil
+ -- print(xc.tg)
+ return xc
+end
+
+--[[ldx--
+
Packaging data in an xml like table is done with the following
+function. Maybe it will go away (when not used).
+--ldx]]--
+
+function xml.is_valid(root)
+ return root and root.dt and root.dt[1] and type(root.dt[1]) == "table" and not root.dt[1].er
+end
+
+function xml.package(tag,attributes,data)
+ local ns, tg = match(tag,"^(.-):?([^:]+)$")
+ local t = { ns = ns, tg = tg, dt = data or "", at = attributes or {} }
+ setmetatable(t, mt)
+ return t
+end
+
+function xml.is_valid(root)
+ return root and not root.error
+end
+
+xml.error_handler = (logs and logs.report) or (input and logs.report) or print
+
+--[[ldx--
+
We cannot load an from a filehandle so we need to load
+the whole file first. The function accepts a string representing
+a filename or a file handle.
+--ldx]]--
+
+function xml.load(filename,settings)
+ local data = ""
+ if type(filename) == "string" then
+ -- local data = io.loaddata(filename) - -todo: check type in io.loaddata
+ local f = io.open(filename,'r')
+ if f then
+ data = f:read("*all")
+ f:close()
+ end
+ elseif filename then -- filehandle
+ data = filename:read("*all")
+ end
+ return xmlconvert(data,settings)
+end
+
+--[[ldx--
+
When we inject new elements, we need to convert strings to
+valid trees, which is what the next function does.
+--ldx]]--
+
+local no_root = { no_root = true }
+
+function xml.toxml(data)
+ if type(data) == "string" then
+ local root = { xmlconvert(data,no_root) }
+ return (#root > 1 and root) or root[1]
+ else
+ return data
+ end
+end
+
+--[[ldx--
+
For copying a tree we use a dedicated function instead of the
+generic table copier. Since we know what we're dealing with we
+can speed up things a bit. The second argument is not to be used!
+--ldx]]--
+
+local function copy(old,tables)
+ if old then
+ tables = tables or { }
+ local new = { }
+ if not tables[old] then
+ tables[old] = new
+ end
+ for k,v in next, old do
+ new[k] = (type(v) == "table" and (tables[v] or copy(v, tables))) or v
+ end
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+xml.copy = copy
+
+--[[ldx--
+
In serializing the tree or parts of the tree is a major
+actitivity which is why the following function is pretty optimized resulting
+in a few more lines of code than needed. The variant that uses the formatting
+function for all components is about 15% slower than the concatinating
+alternative.
+--ldx]]--
+
+-- todo: add when not present
+
+function xml.checkbom(root) -- can be made faster
+ if root.ri then
+ local dt, found = root.dt, false
+ for k=1,#dt do
+ local v = dt[k]
+ if type(v) == "table" and v.special and v.tg == "@pi@" and find(v.dt[1],"xml.*version=") then
+ found = true
+ break
+ end
+ end
+ if not found then
+ insert(dt, 1, { special=true, ns="", tg="@pi@", dt = { "xml version='1.0' standalone='yes'"} } )
+ insert(dt, 2, "\n" )
+ end
+ end
+end
+
+--[[ldx--
+
At the cost of some 25% runtime overhead you can first convert the tree to a string
+and then handle the lot.
+--ldx]]--
+
+-- new experimental reorganized serialize
+
+local function verbose_element(e,handlers)
+ local handle = handlers.handle
+ local serialize = handlers.serialize
+ local ens, etg, eat, edt, ern = e.ns, e.tg, e.at, e.dt, e.rn
+ local ats = eat and next(eat) and { }
+ if ats then
+ for k,v in next, eat do
+ ats[#ats+1] = format('%s=%q',k,v)
+ end
+ end
+ if ern and trace_remap and ern ~= ens then
+ ens = ern
+ end
+ if ens ~= "" then
+ if edt and #edt > 0 then
+ if ats then
+ handle("<",ens,":",etg," ",concat(ats," "),">")
+ else
+ handle("<",ens,":",etg,">")
+ end
+ for i=1,#edt do
+ local e = edt[i]
+ if type(e) == "string" then
+ handle(e)
+ else
+ serialize(e,handlers)
+ end
+ end
+ handle("",ens,":",etg,">")
+ else
+ if ats then
+ handle("<",ens,":",etg," ",concat(ats," "),"/>")
+ else
+ handle("<",ens,":",etg,"/>")
+ end
+ end
+ else
+ if edt and #edt > 0 then
+ if ats then
+ handle("<",etg," ",concat(ats," "),">")
+ else
+ handle("<",etg,">")
+ end
+ for i=1,#edt do
+ local ei = edt[i]
+ if type(ei) == "string" then
+ handle(ei)
+ else
+ serialize(ei,handlers)
+ end
+ end
+ handle("",etg,">")
+ else
+ if ats then
+ handle("<",etg," ",concat(ats," "),"/>")
+ else
+ handle("<",etg,"/>")
+ end
+ end
+ end
+end
+
+local function verbose_pi(e,handlers)
+ handlers.handle("",e.dt[1],"?>")
+end
+
+local function verbose_comment(e,handlers)
+ handlers.handle("")
+end
+
+local function verbose_cdata(e,handlers)
+ handlers.handle("")
+end
+
+local function verbose_doctype(e,handlers)
+ handlers.handle("")
+end
+
+local function verbose_root(e,handlers)
+ handlers.serialize(e.dt,handlers)
+end
+
+local function verbose_text(e,handlers)
+ handlers.handle(e)
+end
+
+local function verbose_document(e,handlers)
+ local serialize = handlers.serialize
+ local functions = handlers.functions
+ for i=1,#e do
+ local ei = e[i]
+ if type(ei) == "string" then
+ functions["@tx@"](ei,handlers)
+ else
+ serialize(ei,handlers)
+ end
+ end
+end
+
+local function serialize(e,handlers,...)
+ local initialize = handlers.initialize
+ local finalize = handlers.finalize
+ local functions = handlers.functions
+ if initialize then
+ local state = initialize(...)
+ if not state == true then
+ return state
+ end
+ end
+ local etg = e.tg
+ if etg then
+ (functions[etg] or functions["@el@"])(e,handlers)
+ -- elseif type(e) == "string" then
+ -- functions["@tx@"](e,handlers)
+ else
+ functions["@dc@"](e,handlers)
+ end
+ if finalize then
+ return finalize()
+ end
+end
+
+local function xserialize(e,handlers)
+ local functions = handlers.functions
+ local etg = e.tg
+ if etg then
+ (functions[etg] or functions["@el@"])(e,handlers)
+ -- elseif type(e) == "string" then
+ -- functions["@tx@"](e,handlers)
+ else
+ functions["@dc@"](e,handlers)
+ end
+end
+
+local handlers = { }
+
+local function newhandlers(settings)
+ local t = table.copy(handlers.verbose or { }) -- merge
+ if settings then
+ for k,v in next, settings do
+ if type(v) == "table" then
+ tk = t[k] if not tk then tk = { } t[k] = tk end
+ for kk,vv in next, v do
+ tk[kk] = vv
+ end
+ else
+ t[k] = v
+ end
+ end
+ if settings.name then
+ handlers[settings.name] = t
+ end
+ end
+ return t
+end
+
+local nofunction = function() end
+
+function xml.sethandlersfunction(handler,name,fnc)
+ handler.functions[name] = fnc or nofunction
+end
+
+function xml.gethandlersfunction(handler,name)
+ return handler.functions[name]
+end
+
+function xml.gethandlers(name)
+ return handlers[name]
+end
+
+newhandlers {
+ name = "verbose",
+ initialize = false, -- faster than nil and mt lookup
+ finalize = false, -- faster than nil and mt lookup
+ serialize = xserialize,
+ handle = print,
+ functions = {
+ ["@dc@"] = verbose_document,
+ ["@dt@"] = verbose_doctype,
+ ["@rt@"] = verbose_root,
+ ["@el@"] = verbose_element,
+ ["@pi@"] = verbose_pi,
+ ["@cm@"] = verbose_comment,
+ ["@cd@"] = verbose_cdata,
+ ["@tx@"] = verbose_text,
+ }
+}
+
+--[[ldx--
+
How you deal with saving data depends on your preferences. For a 40 MB database
+file the timing on a 2.3 Core Duo are as follows (time in seconds):
+
+
+1.3 : load data from file to string
+6.1 : convert string into tree
+5.3 : saving in file using xmlsave
+6.8 : converting to string using xml.tostring
+3.6 : saving converted string in file
+
+
+
Beware, these were timing with the old routine but measurements will not be that
+much different I guess.
+--ldx]]--
+
+-- maybe this will move to lxml-xml
+
+local result
+
+local xmlfilehandler = newhandlers {
+ name = "file",
+ initialize = function(name) result = io.open(name,"wb") return result end,
+ finalize = function() result:close() return true end,
+ handle = function(...) result:write(...) end,
+}
+
+-- no checking on writeability here but not faster either
+--
+-- local xmlfilehandler = newhandlers {
+-- initialize = function(name) io.output(name,"wb") return true end,
+-- finalize = function() io.close() return true end,
+-- handle = io.write,
+-- }
+
+
+function xml.save(root,name)
+ serialize(root,xmlfilehandler,name)
+end
+
+local result
+
+local xmlstringhandler = newhandlers {
+ name = "string",
+ initialize = function() result = { } return result end,
+ finalize = function() return concat(result) end,
+ handle = function(...) result[#result+1] = concat { ... } end
+}
+
+local function xmltostring(root) -- 25% overhead due to collecting
+ if root then
+ if type(root) == 'string' then
+ return root
+ else -- if next(root) then -- next is faster than type (and >0 test)
+ return serialize(root,xmlstringhandler) or ""
+ end
+ end
+ return ""
+end
+
+local function xmltext(root) -- inline
+ return (root and xmltostring(root)) or ""
+end
+
+function initialize_mt(root)
+ mt = { __tostring = xmltext, __index = root }
+end
+
+xml.defaulthandlers = handlers
+xml.newhandlers = newhandlers
+xml.serialize = serialize
+xml.tostring = xmltostring
+
+--[[ldx--
+
The next function operated on the content only and needs a handle function
+that accepts a string.
+--ldx]]--
+
+local function xmlstring(e,handle)
+ if not handle or (e.special and e.tg ~= "@rt@") then
+ -- nothing
+ elseif e.tg then
+ local edt = e.dt
+ if edt then
+ for i=1,#edt do
+ xmlstring(edt[i],handle)
+ end
+ end
+ else
+ handle(e)
+ end
+end
+
+xml.string = xmlstring
+
+--[[ldx--
+
A few helpers:
+--ldx]]--
+
+--~ xmlsetproperty(root,"settings",settings)
+
+function xml.settings(e)
+ while e do
+ local s = e.settings
+ if s then
+ return s
+ else
+ e = e.__p__
+ end
+ end
+ return nil
+end
+
+function xml.root(e)
+ local r = e
+ while e do
+ e = e.__p__
+ if e then
+ r = e
+ end
+ end
+ return r
+end
+
+function xml.parent(root)
+ return root.__p__
+end
+
+function xml.body(root)
+ return (root.ri and root.dt[root.ri]) or root -- not ok yet
+end
+
+function xml.name(root)
+ if not root then
+ return ""
+ elseif root.ns == "" then
+ return root.tg
+ else
+ return root.ns .. ":" .. root.tg
+ end
+end
+
+--[[ldx--
+
The next helper erases an element but keeps the table as it is,
+and since empty strings are not serialized (effectively) it does
+not harm. Copying the table would take more time. Usage:
+--ldx]]--
+
+function xml.erase(dt,k)
+ if dt then
+ if k then
+ dt[k] = ""
+ else for k=1,#dt do
+ dt[1] = { "" }
+ end end
+ end
+end
+
+--[[ldx--
+
The next helper assigns a tree (or string). Usage:
+
+
+dt[k] = xml.assign(root) or xml.assign(dt,k,root)
+
+--ldx]]--
+
+function xml.assign(dt,k,root)
+ if dt and k then
+ dt[k] = (type(root) == "table" and xml.body(root)) or root
+ return dt[k]
+ else
+ return xml.body(root)
+ end
+end
+
+-- the following helpers may move
+
+--[[ldx--
+
The next helper assigns a tree (or string). Usage:
+
+xml.tocdata(e)
+xml.tocdata(e,"error")
+
+--ldx]]--
+
+function xml.tocdata(e,wrapper)
+ local whatever = xmltostring(e.dt)
+ if wrapper then
+ whatever = format("<%s>%s%s>",wrapper,whatever,wrapper)
+ end
+ local t = { special = true, ns = "", tg = "@cd@", at = {}, rn = "", dt = { whatever }, __p__ = e }
+ setmetatable(t,getmetatable(e))
+ e.dt = { t }
+end
+
+function xml.makestandalone(root)
+ if root.ri then
+ local dt = root.dt
+ for k=1,#dt do
+ local v = dt[k]
+ if type(v) == "table" and v.special and v.tg == "@pi@" then
+ local txt = v.dt[1]
+ if find(txt,"xml.*version=") then
+ v.dt[1] = txt .. " standalone='yes'"
+ break
+ end
+ end
+ end
+ end
+end
diff --git a/tex/context/base/lxml-tex.lua b/tex/context/base/lxml-tex.lua
new file mode 100644
index 000000000..aaa90217f
--- /dev/null
+++ b/tex/context/base/lxml-tex.lua
@@ -0,0 +1,1410 @@
+if not modules then modules = { } end modules ['lxml-tst'] = {
+ version = 1.001,
+ comment = "companion to lxml-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local utfchar = utf.char
+local concat, insert, remove, gsub, find = table.concat, table.insert, table.remove
+local format, sub, gsub, find, gmatch, match = string.format, string.sub, string.gsub, string.find, string.gmatch, string.match
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+local lpegmatch = lpeg.match
+local P, S, C, Cc = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc
+
+if not tex and not tex.sprint then
+ tex = {
+ sprint = function(catcodes,...) texio.write(table.concat{...}) end,
+ print = function(catcodes,...) texio.write(table.concat{...}) end,
+ write = function( ...) texio.write(table.concat{...}) end,
+ }
+ commands = {
+ writestatus = logs.report
+ }
+ resolvers.loadbinfile = function(filename) return true, io.loaddata(filename) end
+end
+
+local texsprint, texprint, texwrite = tex.sprint, tex.print, tex.write
+local texcatcodes, ctxcatcodes, vrbcatcodes, notcatcodes = tex.texcatcodes, tex.ctxcatcodes, tex.vrbcatcodes, tex.notcatcodes
+
+local xmlelements, xmlcollected, xmlsetproperty = xml.elements, xml.collected, xml.setproperty
+local xmlparseapply, xmlwithelements = xml.parse_apply, xml.withelements
+local xmlserialize, xmlcollect, xmltext, xmltostring = xml.serialize, xml.collect, xml.text, xml.tostring
+
+local variables = (interfaces and interfaces.variables) or { }
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
+local trace_setups = false trackers.register("lxml.setups", function(v) trace_setups = v end)
+local trace_loading = false trackers.register("lxml.loading", function(v) trace_loading = v end)
+local trace_access = false trackers.register("lxml.access", function(v) trace_access = v end)
+local trace_comments = false trackers.register("lxml.comments", function(v) trace_comments = v end)
+
+lxml = lxml or { }
+lxml.loaded = lxml.loaded or { }
+
+local loaded = lxml.loaded
+
+-- print(contextdirective("context-mathml-directive function reduction yes "))
+-- print(contextdirective("context-mathml-directive function "))
+
+xml.defaultprotocol = "tex"
+
+local finalizers = xml.finalizers
+
+finalizers.xml = finalizers.xml or { }
+finalizers.tex = finalizers.tex or { }
+
+-- this might look inefficient but it's actually rather efficient
+-- because we avoid tokenization of leading spaces and xml can be
+-- rather verbose (indented)
+
+local newline = lpeg.patterns.newline
+local space = lpeg.patterns.spacer
+local ampersand = P("&")
+local semicolon = P(";")
+local spacing = newline * space^0
+local content = C((1-spacing-ampersand)^1)
+local verbose = C((1-(space+newline))^1)
+local entity = ampersand * C((1-semicolon)^1) * semicolon
+
+local xmltextcapture = (
+ space^0 * newline^2 * Cc("") / texprint + -- better ^-2 ?
+ space^0 * newline * space^0 * Cc(" ") / texsprint +
+ content / function(str) return texsprint(notcatcodes,str) end + -- was just texsprint, current catcodes regime is notcatcodes
+ entity / xml.resolved_entity
+)^0
+
+local ctxtextcapture = (
+ space^0 * newline^2 * Cc("") / texprint + -- better ^-2 ?
+ space^0 * newline * space^0 * Cc(" ") / texsprint +
+ content / function(str) return texsprint(ctxcatcodes,str) end + -- was just texsprint, current catcodes regime is notcatcodes
+ entity / xml.resolved_entity
+)^0
+
+local forceraw, rawroot = false, nil
+
+function lxml.startraw()
+ forceraw = true
+end
+
+function lxml.stopraw()
+ forceraw = false
+end
+
+function lxml.rawroot()
+ return rawroot
+end
+
+--~ function lxml.rawpath(rootid)
+--~ if rawroot and type(rawroot) == "table" then
+--~ local text, path, rp
+--~ if not rawroot.dt then
+--~ text, path, rp = "text", "", rawroot[0]
+--~ else
+--~ path, rp = "tree", "", rawroot.__p__
+--~ end
+--~ while rp do
+--~ local rptg = rp.tg
+--~ if rptg then
+--~ path = rptg .. "/" .. path
+--~ end
+--~ rp = rp.__p__
+--~ end
+--~ return { rootid, "/" .. path, text }
+--~ end
+--~ end
+
+-- cdata
+
+local linecommand = "\\obeyedline"
+local spacecommand = "\\obeyedspace" -- "\\strut\\obeyedspace"
+local beforecommand = ""
+local aftercommand = ""
+
+local xmlverbosecapture = (
+ newline / function( ) texsprint(texcatcodes,linecommand,"{}") end +
+ verbose / function(s) texsprint(vrbcatcodes,s) end +
+ space / function( ) texsprint(texcatcodes,spacecommand,"{}") end
+)^0
+
+local function toverbatim(str)
+ if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end
+ lpegmatch(xmlverbosecapture,str)
+ if aftercommand then texsprint(texcatcodes,aftercommand,"{}") end
+end
+
+function lxml.set_verbatim(before,after,obeyedline,obeyedspace)
+ beforecommand, aftercommand, linecommand, spacecommand = before, after, obeyedline, obeyedspace
+end
+
+local obeycdata = true
+
+function lxml.set_cdata()
+ obeycdata = true
+end
+
+function lxml.reset_cdata()
+ obeycdata = false
+end
+
+-- cdata and verbatim
+
+lxml.set_verbatim("\\xmlcdatabefore", "\\xmlcdataafter", "\\xmlcdataobeyedline", "\\xmlcdataobeyedspace")
+
+-- local capture = (space^0*newline)^0 * capture * (space+newline)^0 * -1
+
+function lxml.toverbatim(str)
+ if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end
+ -- todo: add this to capture
+ str = gsub(str,"^[ \t]+[\n\r]+","")
+ str = gsub(str,"[ \t\n\r]+$","")
+ lpegmatch(xmlverbosecapture,str)
+ if aftercommand then texsprint(texcatcodes,aftercommand,"{}") end
+end
+
+-- storage
+
+function lxml.store(id,root,filename)
+ loaded[id] = root
+ xmlsetproperty(root,"name",id)
+ if filename then
+ xmlsetproperty(root,"filename",filename)
+ end
+end
+
+local splitter = lpeg.splitat("::")
+
+lxml.idsplitter = splitter
+
+function lxml.splitid(id)
+ local d, i = lpegmatch(splitter,id)
+ if d then
+ return d, i
+ else
+ return "", id
+ end
+end
+
+local function get_id(id, qualified)
+ if id then
+ local lid = loaded[id]
+ if lid then
+ return lid
+ elseif type(id) == "table" then
+ return id
+ else
+ local d, i = lpegmatch(splitter,id)
+ if d then
+ local ld = loaded[d]
+ if ld then
+ local ldi = ld.index
+ if ldi then
+ local root = ldi[tonumber(i)]
+ if root then
+ if qualified then -- we need this else two args that confuse others
+ return root, d
+ else
+ return root
+ end
+ elseif trace_access then
+ logs.report("lxml","'%s' has no index entry '%s'",d,i)
+ end
+ elseif trace_access then
+ logs.report("lxml","'%s' has no index",d)
+ end
+ elseif trace_access then
+ logs.report("lxml","'%s' is not loaded",d)
+ end
+ elseif trace_access then
+ logs.report("lxml","'%s' is not loaded",i)
+ end
+ end
+ elseif trace_access then
+ logs.report("lxml","invalid id (nil)")
+ end
+end
+
+lxml.id = get_id
+lxml.get_id = get_id
+
+function lxml.root(id)
+ return loaded[id]
+end
+
+-- index
+
+local nofindices = 0
+
+local function addindex(name,check_sum,force)
+ local root = get_id(name)
+ if root and (not root.index or force) then -- weird, only called once
+ local n, index, maxindex, check = 0, root.index or { }, root.maxindex or 0, root.check or { }
+ local function nest(root)
+ local dt = root.dt
+ if not root.ix then
+ maxindex = maxindex + 1
+ root.ix = maxindex
+ check[maxindex] = root.tg -- still needed ?
+ index[maxindex] = root
+ n = n + 1
+ end
+ if dt then
+ for k=1,#dt do
+ local dk = dt[k]
+ if type(dk) == "table" then
+ nest(dk)
+ end
+ end
+ end
+ end
+ nest(root)
+ nofindices = nofindices + n
+ --
+ if type(name) ~= "string" then
+ name = "unknown"
+ end
+ root.index = index
+ root.maxindex = maxindex
+ if trace_access then
+ logs.report("lxml","%s indexed, %s nodes",tostring(name),maxindex)
+ end
+ end
+end
+
+lxml.addindex = addindex
+
+-- another cache
+
+local function lxmlparseapply(id,pattern) -- better inline, saves call
+ return xmlparseapply({ get_id(id) }, pattern)
+end
+
+lxml.filter = lxmlparseapply
+
+function lxml.filterlist(list,pattern)
+ for s in gmatch(list,"[^, ]+") do -- we could cache a table
+ lxmlparseapply(s,pattern)
+ end
+end
+
+lxml["function"] = function(id,name)
+ local f = xml.functions[name]
+ return f and f(get_id(id))
+end
+
+-- rather new, indexed storage (backward refs), maybe i will merge this
+
+function lxml.checkindex(name)
+ local root = get_id(name)
+ return (root and root.index) or 0
+end
+
+function lxml.withindex(name,n,command) -- will change as name is always there now
+ local i, p = lpegmatch(splitter,n)
+ if p then
+ texsprint(ctxcatcodes,"\\xmlw{",command,"}{",n,"}")
+ else
+ texsprint(ctxcatcodes,"\\xmlw{",command,"}{",name,"::",n,"}")
+ end
+end
+
+function lxml.getindex(name,n) -- will change as name is always there now
+ local i, p = lpegmatch(splitter,n)
+ if p then
+ texsprint(ctxcatcodes,n)
+ else
+ texsprint(ctxcatcodes,name,"::",n)
+ end
+end
+
+-- loading (to be redone, no overload)
+
+xml.originalload = xml.originalload or xml.load
+
+local noffiles, nofconverted = 0, 0
+
+function xml.load(filename,settings)
+ noffiles, nofconverted = noffiles + 1, nofconverted + 1
+ starttiming(xml)
+ local ok, data = resolvers.loadbinfile(filename)
+ local xmltable = xml.convert((ok and data) or "",settings)
+ stoptiming(xml)
+ return xmltable
+end
+
+local entities = xml.entities
+
+local function entityconverter(id,str)
+ return entities[str] and "&"..str..";" -- feed back into tex end later
+end
+
+function lxml.convert(id,data,entities,compress)
+ local settings = {
+ unify_predefined_entities = true,
+ }
+ if compress and compress == variables.yes then
+ settings.strip_cm_and_dt = true
+ end
+ if entities and entities == variables.yes then
+ settings.utfize_entities = true
+ settings.resolve_entities = function (str) return entityconverter(id,str) end
+ end
+ return xml.convert(data,settings)
+end
+
+function lxml.load(id,filename,compress,entities)
+ filename = commands.preparedfile(filename)
+ if trace_loading then
+ commands.writestatus("lxml","loading file '%s' as '%s'",filename,id)
+ end
+ noffiles, nofconverted = noffiles + 1, nofconverted + 1
+ -- local xmltable = xml.load(filename)
+ local ok, data = resolvers.loadbinfile(filename)
+ local xmltable = lxml.convert(id,(ok and data) or "",compress,entities)
+ lxml.store(id,xmltable,filename)
+ return xmltable, filename
+end
+
+function lxml.register(id,xmltable,filename)
+ lxml.store(id,xmltable,filename)
+ return xmltable
+end
+
+function lxml.include(id,pattern,attribute,recurse)
+ starttiming(xml)
+ local root = get_id(id)
+ xml.include(root,pattern,attribute,recurse,function(filename)
+ if filename then
+ filename = commands.preparedfile(filename)
+ if file.dirname(filename) == "" and root.filename then
+ local dn = file.dirname(root.filename)
+ if dn ~= "" then
+ filename = file.join(dn,filename)
+ end
+ end
+ if trace_loading then
+ commands.writestatus("lxml","including file: %s",filename)
+ end
+ noffiles, nofconverted = noffiles + 1, nofconverted + 1
+ return resolvers.loadtexfile(filename) or ""
+ else
+ return ""
+ end
+ end)
+ stoptiming(xml)
+end
+
+function xml.getbuffer(name,compress,entities) -- we need to make sure that commands are processed
+ if not name or name == "" then
+ name = tex.jobname
+ end
+ nofconverted = nofconverted + 1
+ xmltostring(lxml.convert(name,concat(buffers.data[name] or {},""),compress,entities))
+end
+
+function lxml.loadbuffer(id,name,compress,entities)
+ if not name or name == "" then
+ name = tex.jobname
+ end
+ starttiming(xml)
+ nofconverted = nofconverted + 1
+ local xmltable = lxml.convert(id,buffers.collect(name or id,"\n"),compress,entities)
+ lxml.store(id,xmltable)
+ stoptiming(xml)
+ return xmltable, name or id
+end
+
+function lxml.loaddata(id,str,compress,entities)
+ starttiming(xml)
+ nofconverted = nofconverted + 1
+ local xmltable = lxml.convert(id,str or "",compress,entities)
+ lxml.store(id,xmltable)
+ stoptiming(xml)
+ return xmltable, id
+end
+
+function lxml.loadregistered(id)
+ return loaded[id], id
+end
+
+-- e.command:
+--
+-- string : setup
+-- true : text (no )
+-- false : ignore
+-- function : call
+
+local function tex_doctype(e,handlers)
+ -- ignore
+end
+
+local function tex_comment(e,handlers)
+ if trace_comments then
+ logs.report("lxml","comment: %s",e.dt[1])
+ end
+end
+
+local default_element_handler = xml.gethandlers("verbose").functions["@el@"]
+
+local function tex_element(e,handlers)
+ local command = e.command
+ if command == nil then
+ default_element_handler(e,handlers)
+ elseif command == true then
+ -- text (no ) / so, no mkii fallback then
+ handlers.serialize(e.dt,handlers)
+ elseif command == false then
+ -- ignore
+ else
+ local tc = type(command)
+ if tc == "string" then
+ local rootname, ix = e.name, e.ix
+ if rootname then
+ if not ix then
+ addindex(rootname,false,true)
+ ix = e.ix
+ end
+ texsprint(ctxcatcodes,"\\xmlw{",command,"}{",rootname,"::",ix,"}")
+ else
+ logs.report("lxml", "fatal error: no index for '%s'",command)
+ texsprint(ctxcatcodes,"\\xmlw{",command,"}{",ix or 0,"}")
+ end
+ elseif tc == "function" then
+ command(e)
+ end
+ end
+end
+
+local pihandlers = { } xml.pihandlers = pihandlers
+
+local kind = P("context-") * C((1-P("-"))^1) * P("-directive")
+local space = S(" \n\r")
+local spaces = space^0
+local class = C((1-space)^0)
+local key = class
+local value = C(P(1-(space * -1))^0)
+
+local parser = kind * spaces * class * spaces * key * spaces * value
+
+pihandlers[#pihandlers+1] = function(str)
+-- local kind, class, key, value = lpegmatch(parser,str)
+ if str then
+ local a, b, c, d = lpegmatch(parser,str)
+ if d then
+ texsprint(ctxcatcodes,"\\xmlcontextdirective{",a",}{",b,"}{",c,"}{",d,"}")
+ end
+ end
+end
+
+local function tex_pi(e,handlers)
+ local str = e.dt[1]
+ for i=1,#pihandlers do
+ pihandlers[i](str)
+ end
+end
+
+local function tex_cdata(e,handlers)
+ if obeycdata then
+ toverbatim(e.dt[1])
+ end
+end
+
+local function tex_text(e)
+ lpegmatch(xmltextcapture,e)
+end
+
+local function ctx_text(e)
+ lpegmatch(ctxtextcapture,e)
+end
+
+local function tex_handle(...)
+-- logs.report("lxml", "error while flushing: %s", concat { ... })
+ texsprint(...) -- notcatcodes is active anyway
+end
+
+local xmltexhandler = xml.newhandlers {
+ name = "tex",
+ handle = tex_handle,
+ functions = {
+ -- ["@dc@"] = tex_document,
+ ["@dt@"] = tex_doctype,
+ -- ["@rt@"] = tex_root,
+ ["@el@"] = tex_element,
+ ["@pi@"] = tex_pi,
+ ["@cm@"] = tex_comment,
+ ["@cd@"] = tex_cdata,
+ ["@tx@"] = tex_text,
+ }
+}
+
+lxml.xmltexhandler = xmltexhandler
+
+function lxml.serialize(root)
+ xmlserialize(root,xmltexhandler)
+end
+
+function lxml.setaction(id,pattern,action)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ for c=1,#collected do
+ collected[c].command = action
+ end
+ end
+end
+
+local function sprint(root)
+ if root then
+ local tr = type(root)
+ if tr == "string" then -- can also be result of lpath
+ -- rawroot = false
+ lpegmatch(xmltextcapture,root)
+ elseif tr == "table" then
+ if forceraw then
+ rawroot = root
+ texwrite(xmltostring(root))
+ else
+ xmlserialize(root,xmltexhandler)
+ end
+ end
+ end
+end
+
+local function tprint(root) -- we can move sprint inline
+ local tr = type(root)
+ if tr == "table" then
+ local n = #root
+ if n == 0 then
+ -- skip
+ else
+ for i=1,n do
+ sprint(root[i])
+ end
+ end
+ elseif tr == "string" then
+ lpegmatch(xmltextcapture,root)
+ end
+end
+
+local function cprint(root) -- content
+ if not root then
+ -- rawroot = false
+ -- quit
+ elseif type(root) == 'string' then
+ -- rawroot = false
+ lpegmatch(xmltextcapture,root)
+ else
+ local rootdt = root.dt
+ if forceraw then
+ rawroot = root
+ texwrite(xmltostring(rootdt or root))
+ else
+ xmlserialize(rootdt or root,xmltexhandler)
+ end
+ end
+end
+
+xml.sprint = sprint local xmlsprint = sprint -- redo these names
+xml.tprint = tprint local xmltprint = tprint
+xml.cprint = cprint local xmlcprint = cprint
+
+-- now we can flush
+
+function lxml.main(id)
+ xmlserialize(get_id(id),xmltexhandler) -- the real root (@rt@)
+end
+
+--~ -- lines (untested)
+--~
+--~ local buffer = { }
+--~
+--~ local xmllinescapture = (
+--~ newline^2 / function() buffer[#buffer+1] = "" end +
+--~ newline / function() buffer[#buffer] = buffer[#buffer] .. " " end +
+--~ content / function(s) buffer[#buffer] = buffer[#buffer] .. s end
+--~ )^0
+--~
+--~ local xmllineshandler = table.copy(xmltexhandler)
+--~
+--~ xmllineshandler.handle = function(...) lpegmatch(xmllinescapture,concat{ ... }) end
+--~
+--~ function lines(root)
+--~ if not root then
+--~ -- rawroot = false
+--~ -- quit
+--~ elseif type(root) == 'string' then
+--~ -- rawroot = false
+--~ lpegmatch(xmllinescapture,root)
+--~ elseif next(root) then -- tr == 'table'
+--~ xmlserialize(root,xmllineshandler)
+--~ end
+--~ end
+--~
+--~ function xml.lines(root) -- used at all?
+--~ buffer = { "" }
+--~ lines(root)
+--~ return result
+--~ end
+
+local function to_text(e)
+ if e.command == nil then
+ local etg = e.tg
+ if etg and e.special and etg ~= "@rt@" then
+ e.command = false -- i.e. skip
+ else
+ e.command = true -- i.e. no
+ end
+ end
+end
+
+local function to_none(e)
+ if e.command == nil then
+ e.command = false -- i.e. skip
+ end
+end
+
+-- setups
+
+local setups = { }
+
+function lxml.set_command_to_text(id)
+ xmlwithelements(get_id(id),to_text)
+end
+
+function lxml.set_command_to_none(id)
+ xmlwithelements(get_id(id),to_none)
+end
+
+function lxml.installsetup(what,document,setup,where)
+ document = document or "*"
+ local sd = setups[document]
+ if not sd then sd = { } setups[document] = sd end
+ for k=1,#sd do
+ if sd[k] == setup then sd[k] = nil break end
+ end
+ if what == 1 then
+ if trace_loading then
+ commands.writestatus("lxml","prepending setup %s for %s",setup,document)
+ end
+ insert(sd,1,setup)
+ elseif what == 2 then
+ if trace_loading then
+ commands.writestatus("lxml","appending setup %s for %s",setup,document)
+ end
+ insert(sd,setup)
+ elseif what == 3 then
+ if trace_loading then
+ commands.writestatus("lxml","inserting setup %s for %s before %s",setup,document,where)
+ end
+ table.insert_before_value(sd,setup,where)
+ elseif what == 4 then
+ if trace_loading then
+ commands.writestatus("lxml","inserting setup %s for %s after %s",setup,document,where)
+ end
+ table.insert_after_value(sd,setup,where)
+ end
+end
+
+function lxml.flushsetups(id,...)
+ local done, list = { }, { ... }
+ for i=1,#list do
+ local document = list[i]
+ local sd = setups[document]
+ if sd then
+ for k=1,#sd do
+ local v= sd[k]
+ if not done[v] then
+ if trace_loading then
+ commands.writestatus("lxml","applying setup %02i = %s to %s",k,v,document)
+ end
+ texsprint(ctxcatcodes,"\\xmlsetup{",id,"}{",v,"}")
+ done[v] = true
+ end
+ end
+ elseif trace_loading then
+ commands.writestatus("lxml","no setups for %s",document)
+ end
+ end
+end
+
+function lxml.resetsetups(document)
+ if trace_loading then
+ commands.writestatus("lxml","resetting all setups for %s",document)
+ end
+ setups[document] = { }
+end
+
+function lxml.removesetup(document,setup)
+ local s = setups[document]
+ if s then
+ for i=1,#s do
+ if s[i] == setup then
+ if trace_loading then
+ commands.writestatus("lxml","removing setup %s for %s",setup,document)
+ end
+ remove(t,i)
+ break
+ end
+ end
+ end
+end
+
+function lxml.setsetup(id,pattern,setup)
+ if not setup or setup == "" or setup == "*" or setup == "-" or setup == "+" then
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ if trace_setups then
+ for c=1, #collected do
+ local e = collected[c]
+ local ix = e.ix or 0
+ if setup == "-" then
+ e.command = false
+ logs.report("lxml","lpath matched (a) %5i: %s = %s -> skipped",c,ix,setup)
+ elseif setup == "+" then
+ e.command = true
+ logs.report("lxml","lpath matched (b) %5i: %s = %s -> text",c,ix,setup)
+ else
+ local tg = e.tg
+ if tg then -- to be sure
+ e.command = tg
+ local ns = e.rn or e.ns
+ if ns == "" then
+ logs.report("lxml","lpath matched (c) %5i: %s = %s -> %s",c,ix,tg,tg)
+ else
+ logs.report("lxml","lpath matched (d) %5i: %s = %s:%s -> %s",c,ix,ns,tg,tg)
+ end
+ end
+ end
+ end
+ else
+ for c=1, #collected do
+ local e = collected[c]
+ if setup == "-" then
+ e.command = false
+ elseif setup == "+" then
+ e.command = true
+ else
+ e.command = e.tg
+ end
+ end
+ end
+ elseif trace_setups then
+ logs.report("lxml","no lpath matches for %s",pattern)
+ end
+ else
+ local a, b = match(setup,"^(.+:)([%*%-])$")
+ if a and b then
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ if trace_setups then
+ for c=1, #collected do
+ local e = collected[c]
+ local ns, tg, ix = e.rn or e.ns, e.tg, e.ix or 0
+ if b == "-" then
+ e.command = false
+ if ns == "" then
+ logs.report("lxml","lpath matched (e) %5i: %s = %s -> skipped",c,ix,tg)
+ else
+ logs.report("lxml","lpath matched (f) %5i: %s = %s:%s -> skipped",c,ix,ns,tg)
+ end
+ elseif b == "+" then
+ e.command = true
+ if ns == "" then
+ logs.report("lxml","lpath matched (g) %5i: %s = %s -> text",c,ix,tg)
+ else
+ logs.report("lxml","lpath matched (h) %5i: %s = %s:%s -> text",c,ix,ns,tg)
+ end
+ else
+ e.command = a .. tg
+ if ns == "" then
+ logs.report("lxml","lpath matched (i) %5i: %s = %s -> %s",c,ix,tg,e.command)
+ else
+ logs.report("lxml","lpath matched (j) %5i: %s = %s:%s -> %s",c,ix,ns,tg,e.command)
+ end
+ end
+ end
+ else
+ for c=1, #collected do
+ local e = collected[c]
+ if b == "-" then
+ e.command = false
+ elseif b == "+" then
+ e.command = true
+ else
+ e.command = a .. e.tg
+ end
+ end
+ end
+ elseif trace_setups then
+ logs.report("lxml","no lpath matches for %s",pattern)
+ end
+ else
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ if trace_setups then
+ for c=1, #collected do
+ local e = collected[c]
+ e.command = setup
+ local ns, tg, ix = e.rn or e.ns, e.tg, e.ix or 0
+ if ns == "" then
+ logs.report("lxml","lpath matched (k) %5i: %s = %s -> %s",c,ix,tg,setup)
+ else
+ logs.report("lxml","lpath matched (l) %5i: %s = %s:%s -> %s",c,ix,ns,tg,setup)
+ end
+ end
+ else
+ for c=1, #collected do
+ collected[c].command = setup
+ end
+ end
+ elseif trace_setups then
+ logs.report("lxml","no lpath matches for %s",pattern)
+ end
+ end
+ end
+end
+
+-- finalizers
+
+local finalizers = xml.finalizers.tex
+
+local function first(collected)
+ if collected then
+ xmlsprint(collected[1])
+ end
+end
+
+local function last(collected)
+ if collected then
+ xmlsprint(collected[#collected])
+ end
+end
+
+local function all(collected)
+ if collected then
+ for c=1,#collected do
+ xmlsprint(collected[c])
+ end
+ end
+end
+
+local function reverse(collected)
+ if collected then
+ for c=#collected,1,-1 do
+ xmlsprint(collected[c])
+ end
+ end
+end
+
+local function count(collected)
+ texwrite((collected and #collected) or 0)
+end
+
+local function position(collected,n)
+ -- todo: if not n then == match
+ if collected then
+ n = tonumber(n) or 0
+ if n < 0 then
+ n = #collected + n + 1
+ end
+ if n > 0 then
+ xmlsprint(collected[n])
+ end
+ end
+end
+
+local function match(collected) -- is match in preceding collected, never change, see bibxml
+ texwrite((collected and collected[1].mi) or 0)
+end
+
+local function index(collected,n)
+ if collected then
+ n = tonumber(n) or 0
+ if n < 0 then
+ n = #collected + n + 1
+ end
+ if n > 0 then
+ texwrite(collected[n].ni or 0)
+ end
+ end
+end
+
+local function command(collected,cmd)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local ix = e.ix
+ if not ix then
+ lxml.addindex(e.name,false,true)
+ ix = e.ix
+ end
+ texsprint(ctxcatcodes,"\\xmlw{",cmd,"}{",e.name,"::",ix,"}")
+ end
+ end
+end
+
+local function attribute(collected,a,default)
+ if collected and #collected > 0 then
+ local at = collected[1].at
+ local str = (at and at[a]) or default
+ if str and str ~= "" then
+ texsprint(notcatcodes,str)
+ end
+ elseif default then
+ texsprint(notcatcodes,default)
+ end
+end
+
+local function chainattribute(collected,arguments) -- todo: optional levels
+ if collected then
+ local e = collected[1]
+ while e do
+ local at = e.at
+ if at then
+ local a = at[arguments]
+ if a then
+ texsprint(notcatcodes,a)
+ end
+ else
+ break -- error
+ end
+ e = e.__p__
+ end
+ end
+end
+
+local function text(collected)
+ if collected then
+ local nc = #collected
+ if nc == 1 then -- hardly any gain so this will go
+ cprint(collected[1])
+ else for c=1,nc do
+ cprint(collected[c])
+ end end
+ end
+end
+
+local function ctxtext(collected)
+ if collected then
+ for c=1,#collected do
+ texsprint(ctxcatcodes,collected[1].dt)
+ end
+ end
+end
+
+local lowerchars, upperchars = characters.lower, characters.upper
+
+local function lower(collected)
+ if collected then
+ for c=1,#collected do
+ texsprint(ctxcatcodes,lowerchars(collected[1].dt[1]))
+ end
+ end
+end
+
+local function upper(collected)
+ if collected then
+ for c=1,#collected do
+ texsprint(ctxcatcodes,upperchars(collected[1].dt[1]))
+ end
+ end
+end
+
+local function number(collected)
+ if collected then
+ local n = 0
+ for c=1,#collected do
+ n = n + tonumber(collected[c].dt[1] or 0)
+ end
+ texwrite(n)
+ end
+end
+
+local function concatrange(collected,start,stop,separator,lastseparator,textonly) -- test this on mml
+ if collected then
+ local nofcollected = #collected
+ local separator = separator or ""
+ local lastseparator = lastseparator or separator or ""
+ start, stop = (start == "" and 1) or tonumber(start) or 1, (stop == "" and nofcollected) or tonumber(stop) or nofcollected
+ if stop < 0 then stop = nofcollected + stop end -- -1 == last-1
+ for i=start,stop do
+ if textonly then
+ xmlcprint(collected[i])
+ else
+ xmlsprint(collected[i])
+ end
+ if i == nofcollected then
+ -- nothing
+ elseif i == nofcollected-1 and lastseparator ~= "" then
+ texsprint(ctxcatcodes,lastseparator)
+ elseif separator ~= "" then
+ texsprint(ctxcatcodes,separator)
+ end
+ end
+ end
+end
+
+local function concat(collected,separator,lastseparator,textonly) -- test this on mml
+ concatrange(collected,false,false,separator,lastseparator,textonly)
+end
+
+finalizers.first = first
+finalizers.last = last
+finalizers.all = all
+finalizers.reverse = reverse
+finalizers.count = count
+finalizers.command = command
+finalizers.attribute = attribute
+finalizers.text = text
+finalizers.lower = lower
+finalizers.upper = upper
+finalizers.ctxtext = ctxtext
+finalizers.context = ctxtext
+finalizers.position = position
+finalizers.match = match
+finalizers.index = index
+finalizers.concat = concat
+finalizers.concatrange = concatrange
+finalizers.chainattribute = chainattribute
+finalizers.default = all -- !!
+
+local concat = table.concat
+
+function finalizers.tag(collected)
+ if collected then
+ local c
+ if n == 0 or not n then
+ c = collected[1]
+ elseif n > 1 then
+ c = collected[n]
+ else
+ c = collected[#collected-n+1]
+ end
+ if c then
+ texsprint(c.tg)
+ end
+ end
+end
+
+function finalizers.name(collected)
+ if collected then
+ local c
+ if n == 0 or not n then
+ c = collected[1]
+ elseif n > 1 then
+ c = collected[n]
+ else
+ c = collected[#collected-n+1]
+ end
+ if c then
+ if c.ns == "" then
+ texsprint(c.tg)
+ else
+ texsprint(c.ns,":",c.tg)
+ end
+ end
+ end
+end
+
+function finalizers.tags(collected,nonamespace)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ local ns, tg = e.ns, e.tg
+ if nonamespace or ns == "" then
+ texsprint(tg)
+ else
+ texsprint(ns,":",tg)
+ end
+ end
+ end
+end
+
+--
+
+local function verbatim(id,before,after)
+ local root = get_id(id)
+ if root then
+ if before then texsprint(ctxcatcodes,before,"[",root.tg or "?","]") end
+ lxml.toverbatim(xmltostring(root.dt))
+ if after then texsprint(ctxcatcodes,after) end
+ end
+end
+function lxml.inlineverbatim(id)
+ verbatim(id,"\\startxmlinlineverbatim","\\stopxmlinlineverbatim")
+end
+function lxml.displayverbatim(id)
+ verbatim(id,"\\startxmldisplayverbatim","\\stopxmldisplayverbatim")
+end
+
+lxml.verbatim = verbatim
+
+-- helpers
+
+function lxml.first(id,pattern)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ first(collected)
+ end
+end
+
+function lxml.last(id,pattern)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ last(collected)
+ end
+end
+
+function lxml.all(id,pattern)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ all(collected)
+ end
+end
+
+function lxml.count(id,pattern)
+ -- always needs to produce a result so no test here
+ count(lxmlparseapply(id,pattern))
+end
+
+function lxml.attribute(id,pattern,a,default)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ attribute(collected,a,default)
+ end
+end
+
+function lxml.raw(id,pattern) -- the content, untouched by commands
+ local collected = (pattern and lxmlparseapply(id,pattern)) or get_id(id)
+ if collected then
+ texsprint(xmltostring(collected[1].dt))
+ end
+end
+
+function lxml.context(id,pattern) -- the content, untouched by commands
+ if not pattern then
+ local collected = get_id(id)
+ -- texsprint(ctxcatcodes,collected.dt[1])
+ ctx_text(collected.dt[1])
+ else
+ local collected = lxmlparseapply(id,pattern) or get_id(id)
+ if collected and #collected > 0 then
+ texsprint(ctxcatcodes,collected[1].dt)
+ end
+ end
+end
+
+function lxml.text(id,pattern)
+ local collected = (pattern and lxmlparseapply(id,pattern)) or get_id(id)
+ if collected then
+ text(collected)
+ end
+end
+
+lxml.content = text
+
+function lxml.position(id,pattern,n)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ position(collected,n)
+ end
+end
+
+function lxml.chainattribute(id,pattern,a,default)
+ local collected = lxmlparseapply(id,pattern)
+ if collected then
+ chainattribute(collected,a,default)
+ end
+end
+
+function lxml.concatrange(id,pattern,start,stop,separator,lastseparator,textonly) -- test this on mml
+ concatrange(lxmlparseapply(id,pattern),start,stop,separator,lastseparator,textonly)
+end
+
+function lxml.concat(id,pattern,separator,lastseparator,textonly)
+ concatrange(lxmlparseapply(id,pattern),false,false,separator,lastseparator,textonly)
+end
+
+function lxml.element(id,n)
+ position(lxmlparseapply(id,"/*"),n)
+end
+
+lxml.index = lxml.position
+
+function lxml.pos(id)
+ local root = get_id(id)
+ texwrite((root and root.ni) or 0)
+end
+
+function lxml.att(id,a,default)
+ local root = get_id(id)
+ if root then
+ local at = root.at
+ local str = (at and at[a]) or default
+ if str and str ~= "" then
+ texsprint(notcatcodes,str)
+ end
+ elseif default then
+ texsprint(notcatcodes,default)
+ end
+end
+
+function lxml.name(id) -- or remapped name? -> lxml.info, combine
+ local r = get_id(id)
+ local ns = r.rn or r.ns or ""
+ if ns ~= "" then
+ texsprint(ns,":",r.tg)
+ else
+ texsprint(r.tg)
+ end
+end
+
+function lxml.match(id) -- or remapped name? -> lxml.info, combine
+ texsprint(get_id(id).mi or 0)
+end
+
+function lxml.tag(id) -- tag vs name -> also in l-xml tag->name
+ texsprint(get_id(id).tg or "")
+end
+
+function lxml.namespace(id) -- or remapped name?
+ local root = get_id(id)
+ texsprint(root.rn or root.ns or "")
+end
+
+function lxml.flush(id)
+ id = get_id(id)
+ local dt = id and id.dt
+ if dt then
+ xmlsprint(dt)
+ end
+end
+
+function lxml.snippet(id,i)
+ local e = get_id(id)
+ if e then
+ local edt = e.dt
+ if edt then
+ xmlsprint(edt[i])
+ end
+ end
+end
+
+function lxml.direct(id)
+ xmlsprint(get_id(id))
+end
+
+function lxml.command(id,pattern,cmd)
+ local i, p = get_id(id,true)
+ local collected = lxmlparseapply(i,pattern)
+ if collected then
+ local rootname = p or i.name
+ for c=1,#collected do
+ local e = collected[c]
+ local ix = e.ix
+ if not ix then
+ addindex(rootname,false,true)
+ ix = e.ix
+ end
+ texsprint(ctxcatcodes,"\\xmlw{",cmd,"}{",rootname,"::",ix,"}")
+ end
+ end
+end
+
+-- loops
+
+function lxml.collected(id,pattern,reverse)
+ return xmlcollected(get_id(id),pattern,reverse)
+end
+
+function lxml.elements(id,pattern,reverse)
+ return xmlelements(get_id(id),pattern,reverse)
+end
+
+-- obscure ones
+
+lxml.info = lxml.name
+
+-- testers
+
+local found, empty = xml.found, xml.empty
+
+local doif, doifnot, doifelse = commands.doif, commands.doifnot, commands.doifelse
+
+function lxml.doif (id,pattern) doif (found(get_id(id),pattern)) end
+function lxml.doifnot (id,pattern) doifnot (found(get_id(id),pattern)) end
+function lxml.doifelse (id,pattern) doifelse(found(get_id(id),pattern)) end
+function lxml.doiftext (id,pattern) doif (not empty(get_id(id),pattern)) end
+function lxml.doifnottext (id,pattern) doifnot (not empty(get_id(id),pattern)) end
+function lxml.doifelsetext (id,pattern) doifelse(not empty(get_id(id),pattern)) end
+
+-- special case: "*" and "" -> self else lpath lookup
+
+--~ function lxml.doifelseempty(id,pattern) doifelse(isempty(get_id(id),pattern ~= "" and pattern ~= nil)) end -- not yet done, pattern
+
+-- status info
+
+statistics.register("xml load time", function()
+ if noffiles > 0 or nofconverted > 0 then
+ return format("%s seconds, %s files, %s converted", statistics.elapsedtime(xml), noffiles, nofconverted)
+ else
+ return nil
+ end
+end)
+
+statistics.register("lxml preparation time", function()
+ local calls, cached = xml.lpathcalls(), xml.lpathcached()
+ if calls > 0 or cached > 0 then
+ return format("%s seconds, %s nodes, %s lpath calls, %s cached calls",
+ statistics.elapsedtime(lxml), nofindices, calls, cached)
+ else
+ return nil
+ end
+end)
+
+statistics.register("lxml lpath profile", function()
+ local p = xml.profiled
+ if p and next(p) then
+ local s = table.sortedkeys(p)
+ local tested, matched, finalized = 0, 0, 0
+ texio.write_nl("log","\nbegin of lxml profile\n")
+ texio.write_nl("log","\n tested matched finalized pattern\n\n")
+ for i=1,#s do
+ local pattern = s[i]
+ local pp = p[pattern]
+ local t, m, f = pp.tested, pp.matched, pp.finalized
+ tested, matched, finalized = tested + t, matched + m, finalized + f
+ texio.write_nl("log",format("%9i %9i %9i %s",t,m,f,pattern))
+ end
+ texio.write_nl("log","\nend of lxml profile\n")
+ return format("%s patterns, %s tested, %s matched, %s finalized (see log for details)",#s,tested,matched,finalized)
+ else
+ return nil
+ end
+end)
+
+-- misc
+
+function lxml.nonspace(id,pattern) -- slow, todo loop
+ xmltprint(xmlcollect(get_id(id),pattern,true))
+end
+
+function lxml.strip(id,pattern,nolines,anywhere)
+ xml.strip(get_id(id),pattern,nolines,anywhere)
+end
+
+function lxml.stripped(id,pattern,nolines)
+ local str = xmltext(get_id(id),pattern) or ""
+ str = gsub(str,"^%s*(.-)%s*$","%1")
+ if nolines then
+ str = gsub(str,"%s+"," ")
+ end
+ xmlsprint(str)
+end
+
+function lxml.delete(id,pattern)
+ xml.delete(get_id(id),pattern)
+end
diff --git a/tex/context/base/lxml-xml.lua b/tex/context/base/lxml-xml.lua
new file mode 100644
index 000000000..f791ec0f8
--- /dev/null
+++ b/tex/context/base/lxml-xml.lua
@@ -0,0 +1,288 @@
+if not modules then modules = { } end modules ['lxml-xml'] = {
+ version = 1.001,
+ comment = "this module is the basis for the lxml-* ones",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local finalizers = xml.finalizers.xml
+local xmlfilter = xml.filter -- we could inline this one for speed
+local xmltostring = xml.tostring
+local xmlserialize = xml.serialize
+
+local function first(collected) -- wrong ?
+ return collected and collected[1]
+end
+
+local function last(collected)
+ return collected and collected[#collected]
+end
+
+local function all(collected)
+ return collected
+end
+
+local function reverse(collected)
+ if collected then
+ local reversed = { }
+ for c=#collected,1,-1 do
+ reversed[#reversed+1] = collected[c]
+ end
+ return reversed
+ end
+end
+
+local function attribute(collected,name)
+ if collected and #collected > 0 then
+ local at = collected[1].at
+ return at and at[name]
+ end
+end
+
+local function att(id,name)
+ local at = id.at
+ return at and at[name]
+end
+
+local function count(collected)
+ return (collected and #collected) or 0
+end
+
+local function position(collected,n)
+ if collected then
+ n = tonumber(n) or 0
+ if n < 0 then
+ return collected[#collected + n + 1]
+ elseif n > 0 then
+ return collected[n]
+ else
+ return collected[1].mi or 0
+ end
+ end
+end
+
+local function match(collected)
+ return (collected and collected[1].mi) or 0 -- match
+end
+
+local function index(collected)
+ if collected then
+ return collected[1].ni
+ end
+end
+
+local function attributes(collected,arguments)
+ if collected then
+ local at = collected[1].at
+ if arguments then
+ return at[arguments]
+ elseif next(at) then
+ return at -- all of them
+ end
+ end
+end
+
+local function chainattribute(collected,arguments) -- todo: optional levels
+ if collected then
+ local e = collected[1]
+ while e do
+ local at = e.at
+ if at then
+ local a = at[arguments]
+ if a then
+ return a
+ end
+ else
+ break -- error
+ end
+ e = e.__p__
+ end
+ end
+ return ""
+end
+
+local function raw(collected) -- hybrid
+ if collected then
+ local e = collected[1] or collected
+ return (e and xmlserialize(e)) or "" -- only first as we cannot concat function
+ else
+ return ""
+ end
+end
+
+local function text(collected) -- hybrid
+ if collected then
+ local e = collected[1] or collected
+ return (e and xmltostring(e.dt)) or ""
+ else
+ return ""
+ end
+end
+
+local function texts(collected)
+ if collected then
+ local t = { }
+ for c=1,#collected do
+ local e = collection[c]
+ if e and e.dt then
+ t[#t+1] = e.dt
+ end
+ end
+ return t
+ end
+end
+
+local function tag(collected,n)
+ if collected then
+ local c
+ if n == 0 or not n then
+ c = collected[1]
+ elseif n > 1 then
+ c = collected[n]
+ else
+ c = collected[#collected-n+1]
+ end
+ return c and c.tg
+ end
+end
+
+local function name(collected,n)
+ if collected then
+ local c
+ if n == 0 or not n then
+ c = collected[1]
+ elseif n > 1 then
+ c = collected[n]
+ else
+ c = collected[#collected-n+1]
+ end
+ if c then
+ if c.ns == "" then
+ return c.tg
+ else
+ return c.ns .. ":" .. c.tg
+ end
+ end
+ end
+end
+
+local function tags(collected,nonamespace)
+ if collected then
+ local t = { }
+ for c=1,#collected do
+ local e = collected[c]
+ local ns, tg = e.ns, e.tg
+ if nonamespace or ns == "" then
+ t[#t+1] = tg
+ else
+ t[#t+1] = ns .. ":" .. tg
+ end
+ end
+ return t
+ end
+end
+
+local function empty(collected)
+ if collected then
+ for c=1,#collected do
+ local e = collected[c]
+ if e then
+ local edt = e.dt
+ if edt then
+ local n = #edt
+ if n == 1 then
+ local edk = edt[1]
+ local typ = type(edk)
+ if typ == "table" then
+ return false
+ elseif edk ~= "" then -- maybe an extra tester for spacing only
+ return false
+ end
+ elseif n > 1 then
+ return false
+ end
+ end
+ end
+ end
+ end
+ return true
+end
+
+finalizers.first = first
+finalizers.last = last
+finalizers.all = all
+finalizers.reverse = reverse
+finalizers.elements = all
+finalizers.default = all
+finalizers.attribute = attribute
+finalizers.att = att
+finalizers.count = count
+finalizers.position = position
+finalizers.match = match
+finalizers.index = index
+finalizers.attributes = attributes
+finalizers.chainattribute = chainattribute
+finalizers.text = text
+finalizers.texts = texts
+finalizers.tag = tag
+finalizers.name = name
+finalizers.tags = tags
+finalizers.empty = empty
+
+-- shortcuts -- we could support xmlfilter(id,pattern,first)
+
+function xml.first(id,pattern)
+ return first(xmlfilter(id,pattern))
+end
+
+function xml.last(id,pattern)
+ return last(xmlfilter(id,pattern))
+end
+
+function xml.count(id,pattern)
+ return count(xmlfilter(id,pattern))
+end
+
+function xml.attribute(id,pattern,a,default)
+ return attribute(xmlfilter(id,pattern),a,default)
+end
+
+function xml.raw(id,pattern)
+ if pattern then
+ return raw(xmlfilter(id,pattern))
+ else
+ return raw(id)
+ end
+end
+
+function xml.text(id,pattern)
+ if pattern then
+ -- return text(xmlfilter(id,pattern))
+ local collected = xmlfilter(id,pattern)
+ return (collected and xmltostring(collected[1].dt)) or ""
+ elseif id then
+ -- return text(id)
+ return xmltostring(id.dt) or ""
+ else
+ return ""
+ end
+end
+
+xml.content = text
+
+function xml.position(id,pattern,n) -- element
+ return position(xmlfilter(id,pattern),n)
+end
+
+function xml.match(id,pattern) -- number
+ return match(xmlfilter(id,pattern))
+end
+
+function xml.empty(id,pattern)
+ return empty(xmlfilter(id,pattern))
+end
+
+xml.all = xml.filter
+xml.index = xml.position
+xml.found = xml.filter
diff --git a/tex/context/base/m-arabtex.tex b/tex/context/base/m-arabtex.tex
new file mode 100644
index 000000000..61e56e93a
--- /dev/null
+++ b/tex/context/base/m-arabtex.tex
@@ -0,0 +1,450 @@
+%D \module
+%D [ file=m-arabtex, % was font-arb,
+%D version=2003.02.22, % 1999.11.06,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Arabic,
+%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.
+
+% I still need to hook in some features into the setup
+% macro. I also have to (re)define farsi etc. in ways
+% similar to arab, so that we have dedicated environments.
+%
+% keywords needed: vocalize transscribe
+%
+% \startarabic[option=vocalize] % or vocalize=yes
+% ......
+% \stoparabic
+
+\writestatus{loading}{ConTeXt Font Macros / ArabTeX support}
+
+%D At the \NTG\ 10\high{th} anniversary meeting Klaus Lagally
+%D introduced the audience to arabic typesetting, and after
+%D that I knew that some day I really had to look into his
+%D generic package. And then, sort of simultaniously Maarten
+%D Wisse and Imran Ahsan Nyazee asked me if \CONTEXT\ could
+%D support \ARABTEX, a package that provides right to left
+%D typesetting of (several variants of) arab and hebrew.
+%D Having implemented support for chinese a few weeks before,
+%D I could not resist to build in support for arab and hebrew
+%D too. Writing support for languages that don't give me any
+%D cue on how to pronounce their script, is kind of special.
+
+%D This is a beta version, since I still have to take care of some
+%D macros that conflict with existing stuff.
+
+\unprotect
+
+\definesystemvariable{ARABTEX}
+
+\def\setupARABTEX
+ {\getparameters[\??ARABTEX]}
+
+\setupARABTEX
+ [\s!rscale=1.2,
+ \c!before=,
+ \c!after=,
+ \c!inner=\setarab,
+ \c!style=\setarabicfont\fontstylesuffix]
+
+%D A few (maybe too) simple hooks into the font mechanism. The
+%D hook into the language module is not yet done.
+
+% \unexpanded\def\setarabicfont#1% rscale
+% {\scratchdimen\@@ARABTEXrscale\bodyfontsize
+% \font\arbfont\truefontname{Arabic#1} at \currentfontscale\scratchdimen
+% \setx@skels
+% \newfonttrue
+% \arbfont}
+%
+% more modern
+%
+% \unexpanded\def\setarabicfont#1% rscale
+% {\definefont[arbfont][Arabic#1 sa \@@ARABTEXrscale]%
+% \setx@skels
+% \newfonttrue
+% \arbfont}
+%
+% more efficient
+
+\unexpanded\def\setarabicfont#1%
+ {\setx@skels
+ \newfonttrue
+ \definedfont[Arabic#1 sa \ARABTEXparameter\s!rscale]}
+
+%D Just to be compatible with Arab\TEX\ we define:
+
+\unexpanded\def\nash {\setarabicfont\s!Regular}
+\unexpanded\def\nashbf {\setarabicfont\s!Bold }
+\unexpanded\def\pnash {\setarabicfont\s!Regular}
+\unexpanded\def\pnashbf{\setarabicfont\s!Bold }
+\unexpanded\def\xnash {\setarabicfont\s!Regular}
+\unexpanded\def\xnashbf{\setarabicfont\s!Bold }
+
+%D The display arabic environment (will be an installable
+%D object) uses a few conditionals. Let's do it the
+%D \CONTEXT\ way and define an anvironment that we later can
+%D adapt.
+
+\newif\if@ignore
+\newif\if@endpe
+
+\def\setupARABTEXalternative[#1]%
+ {\dodoubleempty\getparameters[\??ARABTEX#1]}
+
+\def\defineARABTEXalternative
+ {\dodoubleempty\dodefineARABTEXalternative}
+
+\def\dodefineARABTEXalternative[#1][#2]%
+ {\iffirstargument % \startarab is defined but used already
+ \getparameters
+ [\??ARABTEX#1]
+ [\c!before=\@@ARABTEXbefore,
+ \c!after=\@@ARABTEXafter,
+ \c!inner=\@@ARABTEXinner,
+ \c!style=\@@ARABTEXstyle,
+ \s!rscale=\@@ARABTEXrscale,
+ #2]%
+ \setvalue {\e!start#1}{\displayARABTEXalternative{#1}}%
+ \unexpanded\setvalue{#1}{\inlineARABTEXalternative {#1}}%
+ \unexpanded\def\RL{\getvalue{#1}}%
+ \unexpanded\def\LR{\a@LR}%
+ \let\R=\RL
+ \let\L=\LR
+ \expandafter\all@wcmd\csname\e!stop#1\endcsname
+ \else
+ \defineARABTEXalternative[arabic]%
+ \fi}
+
+\def\initializeARABTEXinternals
+ {\ARABTEXparameter\c!inner
+ \the\everyARABTEXpreset}
+
+\newtoks \everyARABTEXpreset
+
+\let\currentARABTEXalternative\empty
+
+\def\ARABTEXparameter#1%
+ {\csname\??ARABTEX\currentARABTEXalternative#1\endcsname}
+
+\def\inlineARABTEXalternative#1#2%
+ {\bgroup
+ \edef\currentARABTEXalternative{#1}%
+ \initializeARABTEXinternals
+ \a@RL{#2}%
+ \egroup}
+
+\def\displayARABTEXalternative#1%
+ {\dodoubleempty\dostartARABTEXalternative[#1]}
+
+\def\dostartARABTEXalternative[#1][#2]%
+ {\begingroup
+ \edef\currentARABTEXalternative{#1}%
+ \getparameters[\??ARABTEX\currentARABTEXalternative][#2]%
+ \ifnum1<0\ARABTEXparameter\c!n\relax
+ \startcolumns
+ \else
+ \ARABTEXparameter\c!before
+ \fi
+ \initializeARABTEXinternals
+ \initializeARABTEXend
+ \arabtext
+ \initializeARABTEXalternative}
+
+\def\initializeARABTEXalternative
+ {\ARABTEXparameter\c!style}
+
+\def\initializeARABTEXend% \CONTEXT\ does use \end quite differently
+ {\long\def\end##1%
+ {\endarabtext
+ \ifnum1<0\ARABTEXparameter\c!n\relax
+ \stopcolumns
+ \else
+ \ARABTEXparameter\c!after
+ \fi
+ \endgroup}%
+ \let\a@l@end\end
+ \letvalue{\e!stop\currentARABTEXalternative}=\end
+ \long\def\end##1%
+ {\endarabtext
+ \endgroup
+ \if@ignore\global\@ignorefalse\expandafter\ignorespaces\fi}}
+
+%D Arabic verbatim.
+
+\def\typearab{\a@@verb}
+
+%D Some \LATEX\ macros.
+
+\def \makeatletter{\unprotect}
+\def \makeatother {\protect}
+\def \typeout {\writestatus{arabtex}}
+
+%D We have to save some macros.
+
+\let\ARABTEXversion=\empty
+
+\def\startloadingARABTEX% ugly hacks
+ {\catcode`!=12
+ \catcode`?=12
+ \pushmacro\output \let \output \scratchtoks
+ \pushmacro\LaTeX \let \LaTeX \undefined
+ \pushmacro\CJK \let \CJK \undefined
+% \pushmacro\peek@token \let \peek@token \undefined
+% \pushmacro\edmacloaded \let \edmacloaded \undefined
+ \pushmacro\year \let \year \normalyear
+ \pushmacro\month \let \month \normalmonth
+ \pushmacro\day \let \day \normalday
+ \pushmacro\input \def \input ##1 {\normalinput ##1 }
+ \pushmacro\linewidth
+ \pushmacro\datum \def\datum {\toks0}
+ \pushmacro\version \def\version {\toks2}
+ \pushmacro\theversion \let\theversion \ARABTEXversion
+ \pushmacro\emphasize
+ \pushmacro\cap}
+
+\def\stoploadingARABTEX
+ {\catcode`!=11
+ \catcode`?=11
+ \popmacro\cap
+ \popmacro\emphasize
+ \popmacro\theversion
+ \popmacro\version
+ \popmacro\datum
+ \popmacro\linewidth
+ \popmacro\input
+ \popmacro\day
+ \popmacro\month
+ \popmacro\year
+% \popmacro\edmacloaded
+% \popmacro\peek@token
+ \popmacro\CJK
+ \popmacro\LaTeX
+ \popmacro\output}
+
+%D We save some macros:
+
+\startloadingARABTEX
+
+%D When loading \ARABTEX\ we have to set back the~! and~?.
+
+\input arabtex.sty
+
+%D Since \ARABTEX\ has its own \type {\cap}, we save the
+%D new meaning. We also redefine some \PLAIN\ macros, which
+%D happen to have a different meaning in \LATEX.
+
+\let\ARABTEXversion\theversion
+\let\ARABTEXcap \cap
+
+\appendtoks
+ \let\cap\ARABTEXcap
+\to \everyARABTEXpreset
+
+\def\ARABTEXsh@ft#1%
+ {\dimen@.00#1ex
+ \multiply\dimen@\slantperpoint
+ \kern-.0156\dimen@}
+
+\appendtoks
+ \let\sh@ft\ARABTEXsh@ft
+\to \everyARABTEXpreset
+
+\def\ARABTEXd#1%
+ {{\o@lign{\relax#1\crcr\hidewidth\sh@ft{10}%
+ .\hidewidth}}}
+
+\def\ARABTEXb#1%
+ {{\o@lign{\relax#1\crcr\hidewidth\sh@ft{29}%
+ \vbox to.2ex{\hbox{\char22}\vss}\hidewidth}}}
+
+\appendtoks
+ \let\b\ARABTEXb
+ \let\d\ARABTEXd
+\to \everyARABTEXpreset
+
+\def \ARABTEXbreakA {\hfill\break}
+\def \ARABTEXbreakB {\break}
+\edef\ARABTEXbar {\string|}
+\def \ARABTEXcomma {\relax\ifmmode\mskip\thinmuskip\else\thinspace\fi}
+
+\appendtoks
+ \let\\=\ARABTEXbreakA
+ \let\|=\ARABTEXbreakB
+ \let |=\ARABTEXbar
+ \let\,=\ARABTEXcomma
+\to \everyARABTEXpreset
+
+\let\ARABTEXprotect\relax
+
+\appendtoks
+ \let\protect\ARABTEXprotect
+\to \everyARABTEXpreset
+
+%D Now we can pop the saved macros.
+
+\stoploadingARABTEX
+
+%D Ah, we have to get rid of some \type {\protect} stuff but
+%D to permit testing we add it in the \CONTEXT\ way.
+
+% \bgroup
+% \catcode`\<=\@other
+% \unexpanded\gdef\a@ins
+% {\ifmmode
+% \expandafter<%
+% \else
+% \dontleavehmode \bgroup
+% \arab@codes \set@arabfont \@waslafalse \@wasfalse
+% \expandafter\arab@insert
+% \fi}
+% \unexpanded\gdef\<{\a@ins}
+% \catcode`\<=\active
+% \global\let<=\a@ins
+% \egroup
+%
+% cleaner:
+
+\defineactivecharacter < {\a@ins} \unexpanded\gdef\<{\a@ins}%
+
+\def\normal@a@ins
+ {\dontleavehmode % context prefers this instead of \leavevmode
+ \bgroup
+ \arab@codes
+ \set@arabfont
+ \@waslafalse
+ \@wasfalse
+ \arab@insert}
+
+\unexpanded\gdef\a@ins
+ {\mathortext<\normal@a@ins}
+
+%D We also need to register a few macros:
+
+\all@wcmd\initializeARABTEXalternative % no argument, internal command
+\all@wcmd\tx % no argument, small font
+\all@wcmd\txx % no argument, smaller font
+
+%D We also hook it into the presetter.
+
+\appendtoks
+ \let\normaltx \tx \def\tx {\normaltx \setarabicfont\fontstylesuffix}%
+ \let\normaltxx\txx\def\txx{\normaltxx\setarabicfont\fontstylesuffix}%
+\to \everyARABTEXpreset
+
+%D The main definitions are:
+
+\definefontsynonym [ArabicRegular] [xnsh14]
+\definefontsynonym [ArabicBold] [xnsh14bf]
+
+\defineARABTEXalternative
+ [arabic]
+ [\c!inner=\setarab,
+ \c!style=\setarabicfont\fontstylesuffix]
+
+\defineARABTEXalternative
+ [farsi]
+ [\c!inner=\setfarsi,
+ \c!style=\setarabicfont\fontstylesuffix]
+
+\defineARABTEXalternative
+ [urdu]
+ [\c!inner=\seturdu,
+ \c!style=\setarabicfont\fontstylesuffix]
+
+\defineARABTEXalternative
+ [maghribi]
+ [\c!inner=\setmaghribi,
+ \c!style=\setarabicfont\fontstylesuffix]
+
+%D Apart from such definitions, one can adapt the settings
+%D using \type {\setupARABTEXalternative}.
+%D
+%D A few years ago at the Holland Festivities, I attended {\em
+%D The Cave}, one of the most impressive combinations of music
+%D and video I know. This composition of Steve Reich (music)
+%D and .. (video) concentrates on the common grounds of arabs
+%D and jews: their ancestor Abram. Listening to the \CDROM's
+%D of {\em The Cave}, provided me the right ambiance for
+%D filling in the details of this module. In {\em The Cave},
+%D interviews, music, and |<|believe it or not|>| rhythmic
+%D typography are the cornerstones. Remembering those big
+%D screens, it strikes me that like music, \TEX\ too is a
+%D perfect instrument to cross cultural and linguistic
+%D borders. So, let's load Hebrew support as well:
+
+\unexpanded\def\sethebrewfont#1%
+ {\setx@skels
+ \newfonttrue
+ \definedfont[Hebrew#1 sa \ARABTEXparameter\s!rscale]}
+
+% \let \setheb \sethebrew
+
+\unexpanded\def\pheb {\sethebrewfont\s!Regular}
+\unexpanded\def\phebbf{\sethebrewfont\s!Bold}
+
+% \startloadingARABTEX
+
+% \ReadFile{hebtex.sty}
+% \ReadFile{apatch.sty}
+% \ReadFile{hepatch.sty}
+
+% \stoploadingARABTEX
+
+\definefontsynonym [HebrewRegular] [hclassic]
+\definefontsynonym [HebrewBold] [hcaption]
+
+\defineARABTEXalternative
+ [hebrew]
+ [\c!inner=\sethebrew,
+ \c!style=\sethebrewfont\fontstylesuffix]
+
+%D Now we're done:
+
+\protect \endinput
+
+% everyoutput : \charsubdefmax \arab@charsubdefmax
+
+% \defineconversion [abjad] [\abj@d]
+%
+% voetnoten verbatim lijsten indexen tabellen uitlijnen
+%
+% \v!hoofdstuk=al-fa.slu
+% \v!inhoud=al-mu.htawayAtu
+% \v!figuren=qA'imaTu al-.suwaru
+% \v!tabellen=qA'imaTu al-^gadAwilu
+% \v!grafieken=qA'imaTu al-rusUmu
+% \v!index=al-fihrisu
+% \v!bijlage=al-mul.haqu
+
+% \usemodule[arabtex]
+%
+% \usetypescript[postscript] \switchtotypeface[postscript]
+%
+% \setarab \novocalize
+%
+% \starttext
+%
+% \placecontent
+%
+% \section{\} % short arabic use \< .. >
+% \section{\} % short arabic use \< .. >
+%
+% \startarabic
+% mu.hammad 'i_d q"aAm zay"d" + i_d yaqUm zyd + A_d zyd q"aAm
+%
+% mu.hammad 'i_d q"aAm zay"d" + i_d yaqUm zyd + A_d zyd q"aAm
+% \stoparabic
+%
+% \section{\}
+%
+% \startarabic
+% mu.hammad 'i_d q"aAm zay"d" + i_d yaqUm zyd + A_d zyd q"aAm
+% \stoparabic
+%
+% \stoptext
diff --git a/tex/context/base/m-barcodes.mkiv b/tex/context/base/m-barcodes.mkiv
new file mode 100644
index 000000000..b0eae1485
--- /dev/null
+++ b/tex/context/base/m-barcodes.mkiv
@@ -0,0 +1,122 @@
+%D \module
+%D [ file=m-pstricks,
+%D version=2010.03.14,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Barcodes,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% \startTEXpage
+% \startPSTRICKS
+% \pspicture(-4mm,-1mm)(38mm,26mm)
+% \psbarcode{9781860742712}{includetext guardwhitespace}{ean13}%
+% \endpspicture
+% \stopPSTRICKS
+% \stopTEXpage
+
+% 978-94-90688-01-1
+%
+% 978 = ean isbn identifier (979 also)
+% 94 = country code
+% 90688 = publisher code
+% 01 = title 1
+% 1 = checksum
+
+\usemodule[pstricks]
+
+\usePSTRICKSmodule[pst-barcode]
+
+\definefont[barcodefont][file:ocrb10]
+% \definefont[barcodefont][file:texgyreheros-regular]
+
+\startluacode
+plugins.barcodes = { }
+
+local function split(code)
+ local t = { string.byte(code,1,#code) }
+ if #t >= 12 then
+ local s = 0
+ for i=1,11,2 do
+ s = s + (t[i]-48)
+ end
+ for i=2,12,2 do
+ s = s + 3 * (t[i]-48)
+ end
+ local m = s % 10
+ local c = (m > 0 and (10 - m)) or 0
+ return t, s, m, c
+ end
+end
+
+function plugins.barcodes.isbn_1(original)
+ local code = string.gsub(original,"%-","")
+ local t, s, m, c = split(code)
+ if t then
+ if #t == 13 then
+ local e = ((c == t[13] - 48) and "correct") or "wrong"
+ logs.report("isbn code","code=%s, sum=%s, checksum=%s, modulo=%s, status=%s",original,s,m,c,e)
+ else
+ logs.report("isbn code","code=%s, sum=%s, checksum=%s, modulo=%s",original,s,m,c)
+ code= code .. c
+ end
+ end
+ tex.sprint(code)
+end
+
+function plugins.barcodes.isbn_2(original)
+ local code = string.gsub(original,"%-","")
+ local t, s, m, c = split(code)
+ if t and #t == 12 then
+ original = original .. "-" .. c
+ end
+ tex.sprint(original)
+end
+\stopluacode
+
+\startsetups barcode:isbn
+ \scale
+ [width=5cm]
+ {
+ \vbox {
+ \hbox {
+ \hskip3.7mm
+ \scale[width=34mm]{\barcodefont ISBN \ctxlua{plugins.barcodes.isbn_2("\getvariable{barcode}{code}")}}
+ }
+ \par
+ \normalexpanded { \noexpand \setPSTRICKS {
+ \noexpand \pspicture(-4mm,-1mm)(38mm,26mm)
+ \noexpand \psbarcode {
+ \ctxlua{plugins.barcodes.isbn_1("\getvariable{barcode}{code}")}
+ } {
+ includetext guardwhitespace
+ } {
+ ean13
+ }
+ \noexpand \endpspicture
+ }
+ \noexpand \processPSTRICKS }
+ }
+ }
+\stopsetups
+
+\def\barcode[#1]%
+ {\bgroup
+ \setvariables[barcode][type=isbn,#1]%
+ \directsetup{barcode:\getvariable{barcode}{type}}%
+ \egroup}
+
+% \usemodule[barcodes]
+%
+% \starttext
+% \startTEXpage
+% \barcode[type=isbn,code=978-94-90688-01-1]
+% \stopTEXpage
+% \stoptext
+
+\endinput
+
diff --git a/tex/context/base/m-chart.mkii b/tex/context/base/m-chart.mkii
new file mode 100644
index 000000000..2554fa2d4
--- /dev/null
+++ b/tex/context/base/m-chart.mkii
@@ -0,0 +1,48 @@
+%D \module
+%D [ file=m-chart,
+%D version=1998.10.10,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Flow Charts,
+%D author={Hans Hagen \& Ton Otten},
+%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.
+
+%D The \XML\ interface:
+
+\unprotect
+
+\startXMLdefinitions flowchart
+
+\defineXMLargument [flowchartdefinition]
+ {\defineFLOWchart[\XMLpar{flowchartdefinition}{identifier}{unknown}]}
+
+\defineXMLpickup [flowcell]
+ {\startFLOWcell
+ \defineXMLargument[name]{\unspaceafter\name}%
+ \defineXMLargument[shape]{\unspaceafter\shape}%
+ \defineXMLnestedargument[text]{\text}}
+ {\stopFLOWcell}
+
+\defineXMLenvironment [location] % global unspace/store
+ {\bgroup\defineXMLpush[x]\defineXMLpush[y]}
+ {\XMLunspace{x}\XMLunspace{y}%
+ \expanded{\egroup\noexpand\location{\XMLpop{x},\XMLpop{y}}}}
+
+\defineXMLenvironment [connection]
+ {\bgroup\defineXMLpush[type]\defineXMLpush[name]}%
+ {\XMLunspace{type}\XMLunspace{name}%
+ \expanded{\egroup\noexpand\connection[\XMLpop{type}]{\XMLpop{name}}}}
+
+\defineXMLsingular [flowchart]
+ {\expanded{\FLOWchart[\XMLpar{flowchart}{identifier}{unknown}]}}
+
+\defineXMLdirective [flowchart] [shapes] \setupFLOWshapes
+\defineXMLdirective [flowchart] [lines] \setupFLOWlines
+
+\stopXMLdefinitions
+
+\protect \endinput
diff --git a/tex/context/base/m-chart.mkiv b/tex/context/base/m-chart.mkiv
new file mode 100644
index 000000000..4c008a5ee
--- /dev/null
+++ b/tex/context/base/m-chart.mkiv
@@ -0,0 +1,20 @@
+%D \module
+%D [ file=m-chart,
+%D version=1998.10.10,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Flow Charts,
+%D author={Hans Hagen \& Ton Otten},
+%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.
+
+%D The \XML\ interface:
+
+\unprotect
+
+\writestatus\m!systems{The chart mkiv xml interface is not yet defined!}
+
+\protect \endinput
diff --git a/tex/context/base/m-chart.tex b/tex/context/base/m-chart.tex
new file mode 100644
index 000000000..5ccf4c2ad
--- /dev/null
+++ b/tex/context/base/m-chart.tex
@@ -0,0 +1,1285 @@
+%D \module
+%D [ file=m-chart,
+%D version=1998.10.10,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Flow Charts,
+%D author={Hans Hagen \& Ton Otten},
+%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.
+
+% todo: \localpushmacro/\localpopmacro (dohandleflowchart etc)
+% todo: make mkiv variant
+% todo: use dimexpr/numspr
+
+% will be redone with layers and dimexpr or even better, by just using
+% textext .. a nice example of old code
+
+%D This is an experimental module. Pieces of code will be moved
+%D to other modules. More features are possible but will be
+%D interfaces later.
+%D
+%D When finished this module will be documented. The main macro
+%D is still a rather big one and there is some redundant and
+%D slow code that needs a clean up.
+
+% arrow, dash
+% crossing
+% \goto -> \normalgoto
+% class -> class:name (ref prefix)
+% c, automatisch geen overlap zoeken
+% eind eerder chart connecties
+% relateren aan korps
+% check op bestaan naam, bestaan shape
+% auto als extern figuur
+% subchart
+% pijlen
+% focus
+% ook nog \MPmessage
+% areapath -> krappe vlak
+% clippath -> gehele vlak
+%
+% offset : clip offset
+% breedte : breedte cel
+% hoogte : hoogte cel
+% dx : halve afstand in breedte (grid breedte = breedte + 2dx)
+% dy : halve afstand in hoogte (grid hoogte = hoogte + 2dy)
+% x : x offset (clipping)
+% y : y offset (clipping)
+% nx : minimaal aantal cellen horizontaal
+% ny : minimaal aantal cellen vertikaal
+%
+% shape none en geen equivalent maken
+%
+% kaderkleur achtergrondkleur
+% lijnkleur lijndikte
+% focus focuskaderkleur focusachtergrondkleur
+% richting
+%
+% focus koppelen aan kleur
+
+\unprotect
+
+\definesorting [flowchart] [flowcharts] [\v!none] % no access
+\setupsorting [flowchart] [\c!state=\v!stop] % off by default
+
+\def\@FLOW@{@FLOW@}
+\def\@FLOC@{@FLOC@}
+\def\@FLOX@{@FLOX@}
+
+\def\@@FLOW{@@FLOW}
+\def\@@FLOL{@@FLOL}
+\def\@@FLOS{@@FLOS}
+\def\@@FLOF{@@FLOF}
+\def\@@FLOT{@@FLOT}
+\def\@@FLOX{@@FLOX}
+
+\def\@@MPx {@@MPx}
+\def\@@MPy {@@MPy}
+
+\def\FLOWbufferprefix{flw-}
+
+\def\processFLOWbuffer#1{\getbuffer[\FLOWbufferprefix#1]}
+\def\typeFLOWbuffer #1{\typebuffer[\FLOWbufferprefix#1]}
+
+\def\setFLOWname#1#2% funny hack that makes sure that we get
+ {\bgroup % names that are acceptable for METAPOST
+ \lccode`0=`a\lccode`1=`b\lccode`2=`c\lccode`3=`d\lccode`4=`e%
+ \lccode`5=`f\lccode`6=`g\lccode`7=`h\lccode`8=`i\lccode`9=`j%
+ \lccode` =`\_\lccode`-=`\_\lccode`_=`\_%
+ \lowercase{\gdef#1{#2}}%
+ \egroup}
+
+% een gobble als default is sneller, en dan alleen setten als
+% nodig
+
+\def\resetFLOWcell
+ {% variables
+ \global\let\FLOWname \empty
+ \global\let\FLOWalign \empty
+ \global\let\FLOWshape \empty
+ \global\let\FLOWlocation \empty
+ \global\let\FLOWtext \empty
+ \global\let\FLOWhelp \empty
+ \global\let\FLOWdestination\empty
+ \global\let\FLOWoverlay \empty
+ \global\let\FLOWfocus \empty
+ \global\let\tFLOWlabel \empty
+ \global\let\bFLOWlabel \empty
+ \global\let\lFLOWlabel \empty
+ \global\let\rFLOWlabel \empty
+ \global\let\bcFLOWlabel \empty
+ \global\let\tcFLOWlabel \empty
+ \global\let\lcFLOWlabel \empty
+ \global\let\rcFLOWlabel \empty
+ \global\let\tFLOWexit \empty
+ \global\let\bFLOWexit \empty
+ \global\let\lFLOWexit \empty
+ \global\let\rFLOWexit \empty
+ % commands
+ \let\name \doFLOWname
+ \let\shape \doFLOWshape
+ \let\destination\doFLOWdestination
+ \let\location \doFLOWlocation
+ \let\focus \doFLOWfocus
+ \let\overlay \doFLOWoverlay
+ \let\figure \doFLOWfigure
+ \let\text \doFLOWtext
+ \let\comment \doFLOWcomment
+ \let\label \doFLOWlabel
+ \let\help \doFLOWhelp
+ \let\connection \doFLOWconnection
+ \let\exit \doFLOWexit
+ % convenience commands
+ \let\locate \doFLOWlocate
+ \let\connect \doFLOWconnect}
+
+\let\FLOWcell \s!unknown
+\let\FLOWshape \s!unknown
+\let\FLOWdestination\s!unknown
+\let\FLOWfocus \s!unknown
+\let\FLOWoverlay \empty
+\let\FLOWtext \empty
+
+\def\doFLOWname#1%
+ {\def\FLOWcell{#1}\setFLOWname\FLOWname{name_#1}\ignorespaces}
+
+\def\doFLOWshape#1%
+ {\gdef\FLOWshape{#1}\ignorespaces}
+
+\def\doFLOWdestination#1%
+ {\gdef\FLOWdestination{#1}\ignorespaces}
+
+\def\doFLOWlocation#1%
+ {\setFLOWlocation#1\end\ignorespaces}
+
+\def\doFLOWfocus#1%
+ {\gdef\FLOWfocus{#1}\ignorespaces}
+
+\def\doFLOWoverlay#1%
+ {\gdef\FLOWoverlay{#1}\ignorespaces}
+
+\def\doFLOWfigure#1%
+ {\defineoverlay[\s!dummy][\overlayfigure{#1}]%
+ \overlay\s!dummy}
+
+\def\doFLOWtext
+ {\dosingleempty\dodoFLOWtext}
+
+\def\dodoFLOWtext[#1]% % #2%
+ {\gdef\FLOWalign{#1}\gdef\FLOWtext}% {#2}}
+
+\def\doFLOWcomment[#1]#2%
+ {\ignorespaces\dogobblesingleempty}
+
+\def\doFLOWlabel[#1]#2% wordt dit gebruikt ?
+ {\setgvalue{#1FLOWlabel}{#2}\ignorespaces}
+
+\def\doFLOWhelp#1%
+ {\gdef\FLOWhelp{#1}\ignorespaces}
+
+\def\doFLOWconnection
+ {\dodoubleempty\dodoFLOWconnection}
+
+\def\dodoFLOWconnection[#1][#2]#3%
+ {\ignorespaces}
+
+\def\doFLOWconnect
+ {\connection}
+
+\def\doFLOWlocate
+ {\location}
+
+\def\doFLOWexit[#1]#2%
+ {\setgvalue{#1FLOWexit}{#2}\ignorespaces}
+
+\def\startFLOWchart
+ {\bgroup
+ \let\stopFLOWchart\egroup
+ \obeylines % lelijk, buffers nog eens fatsoeneren
+ \dodoubleempty\dostartFLOWchart}
+
+\def\dostartFLOWchart[#1][#2]%
+ {\preparenextFLOWchart{#1}{#2}%
+ \dostartbuffer[\FLOWbufferprefix\nofFLOWcharts][startFLOWchart][stopFLOWchart]}
+
+\def\defineFLOWchart%
+ {\dodoubleempty\dodefineFLOWchart}
+
+\long\def\dodefineFLOWchart[#1][#2]#3%
+ {\preparenextFLOWchart{#1}{#2}%
+ \setbuffer[\FLOWbufferprefix\nofFLOWcharts]#3\endbuffer}
+
+\def\preparenextFLOWchart#1#2%
+ {\doglobal\increment\nofFLOWcharts
+ \flowchart{#1}%
+ \setxvalue{\@FLOW@-#1}{\noexpand\dohandleflowchart[\nofFLOWcharts][#2]}}
+
+\def\setupFLOWcharts{\dodoubleargument\getparameters[\@@FLOW]}
+\def\setupFLOWlines {\dodoubleargument\getparameters[\@@FLOL]}
+\def\setupFLOWshapes{\dodoubleargument\getparameters[\@@FLOS]}
+\def\setupFLOWfocus {\dodoubleargument\getparameters[\@@FLOF]}
+\def\setupFLOWsets {\dodoubleargument\getparameters[\@@FLOX]}
+
+\setupFLOWcharts
+ [\c!option=,
+ \c!bodyfont=,
+ \c!dot=, % private option
+ \c!width=12\bodyfontsize,
+ \c!height=7\bodyfontsize,
+ \c!maxwidth=,
+ \c!maxheight=,
+ \c!offset=\v!standard, % == auto offset
+ \c!dx=2\bodyfontsize,
+ \c!dy=2\bodyfontsize,
+ \c!nx=0, % 1,
+ \c!ny=0, % 1,
+ \c!x=1,
+ \c!y=1,
+ \c!autofocus=,
+ \c!focus=,
+ \c!background=, % \v!color,
+ \c!backgroundcolor=\s!white,
+ \c!rulethickness=\linewidth,
+ \c!frame=\v!off,
+ \c!framecolor=]
+
+\setupFLOWlines
+ [\c!corner=\v!round,
+ \c!arrow=\v!yes,
+ \c!dash=\v!no,
+ \c!radius=.375\bodyfontsize, % 2.5\c!rulethickness
+ \c!color=FLOWlinecolor,
+ \c!rulethickness=.15\bodyfontsize, % 2pt,
+ \c!offset=\v!none]
+
+\setupFLOWshapes
+ [\c!default=action,
+ \c!framecolor=FLOWframecolor,
+ \c!background=\v!color,
+ \c!backgroundcolor=FLOWbackgroundcolor,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!rulethickness=.15\bodyfontsize, % 2pt,
+ \c!offset=.5\bodyfontsize]
+
+\setupFLOWfocus
+ [\c!framecolor=FLOWfocuscolor,
+ \c!background=\@@FLOSbackground,
+ \c!backgroundcolor=\@@FLOSbackgroundcolor,
+ \c!backgroundscreen=\@@FLOSbackgroundscreen,
+ \c!rulethickness=\@@FLOSrulethickness,
+ \c!offset=\@@FLOSoffset]
+
+\definecolor [FLOWfocuscolor] [s=.2]
+\definecolor [FLOWlinecolor] [s=.5]
+\definecolor [FLOWframecolor] [s=.7]
+\definecolor [FLOWbackgroundcolor] [s=.9]
+
+\newcounter\includeFLOWx
+\newcounter\includeFLOWy
+
+\def\includeFLOWchart
+ {\dodoubleempty\doincludeFLOWchart}
+
+\def\doincludeFLOWchart[#1][#2]%
+ {\pushmacro\includeFLOWx
+ \pushmacro\includeFLOWy
+ \getparameters[FLOWi][x=1,y=1,#2]%
+ \increment(\includeFLOWx,0\FLOWix)\decrement\includeFLOWx
+ \increment(\includeFLOWy,0\FLOWiy)\decrement\includeFLOWy
+ \def\dodoincludeFLOWchart##1%
+ {\doifdefined{\@FLOW@-##1}
+ {\globalpushmacro\dohandleflowchart % was local
+ \gdef\dohandleflowchart[####1][####2]%
+ {\globalpopmacro\dohandleflowchart % was local
+ \resetFLOWlocation
+ \processFLOWbuffer{####1}}%
+ \getvalue{\@FLOW@-##1}}}%
+ \processcommalist[#1]\dodoincludeFLOWchart
+ \popmacro\includeFLOWx
+ \popmacro\includeFLOWy}
+
+\def\resetFLOWlocation
+ {\globallet\lastFLOWx\!!zerocount
+ \globallet\lastFLOWy\!!zerocount}
+
+\def\dosetFLOWlocation[#1#2]#3#4%
+ {\processaction
+ [#1#2]
+ [ +=>\scratchcounter\numexpr#4+ 1+#3\relax,
+ -=>\scratchcounter\numexpr#4- 1+#3\relax,
+ +#2=>\scratchcounter\numexpr#4+#2+#3\relax,
+ -#2=>\scratchcounter\numexpr#4-#2+#3\relax,
+ \s!default=>\scratchcounter\numexpr#4 +#3\relax,
+ \s!unknown=>\scratchcounter\numexpr0#1#2+#3\relax]%
+ \xdef#4{\the\scratchcounter}}
+
+\def\setFLOWlocation#1,#2\end
+ {\dosetFLOWlocation[#1\empty]\includeFLOWx\lastFLOWx
+ \dosetFLOWlocation[#2\empty]\includeFLOWy\lastFLOWy
+ \xdef\FLOWlocation{\lastFLOWx,\lastFLOWy}}
+
+\def\FLOWshapes
+ {node, action, procedure, product, decision, archive,
+ loop, wait, subprocedure, singledocument, multidocument,
+ sub procedure, single document, multi document, up, down,
+ left, right}
+
+\def\FLOWlines
+ {up, down, left, right}
+
+\def\FLOWsetconnect#1%
+ {\donefalse
+ \let\cFLOWfrom\empty
+ \let\cFLOWto\empty
+ \let\zFLOWfrom\!!zerocount
+ \let\zFLOWto\!!zerocount
+ \handletokens#1\with\doFLOWsetconnect
+ \ifx\cFLOWto\empty\let\cFLOWfrom\empty\fi}
+
+\def\doFLOWsetconnect#1%
+ {\ifx #1p%
+ \ifdone\def\zFLOWto{+1}\else\def\zFLOWfrom{+1}\fi
+ \else\ifx#1+%
+ \ifdone\def\zFLOWto{+1}\else\def\zFLOWfrom{+1}\fi
+ \else\ifx#1n%
+ \ifdone\def\zFLOWto{-1}\else\def\zFLOWfrom{-1}\fi
+ \else\ifx#1-%
+ \ifdone\def\zFLOWto{-1}\else\def\zFLOWfrom{-1}\fi
+ \else\ifdone
+ \edef\cFLOWto{\FLOWconnector#1}%
+ \else
+ \edef\cFLOWfrom{\FLOWconnector#1}%
+ \donetrue
+ \fi\fi\fi\fi\fi}
+
+\def\FLOWconnector#1%
+ {\if#1bbottom\else\if#1ttop\else\if#1lleft\else\if#1rright\fi\fi\fi\fi}
+
+\newif\ifFLOWscaling \FLOWscalingtrue
+
+\def\@@FLOW@@offset{\@@FLOWoffset}
+
+\def\getFLOWchart
+ {\dodoubleempty\dogetFLOWchart}
+
+\def\dogetFLOWchart[#1][#2]%
+ {\doifundefinedelse{\@FLOW@-#1}
+ {\writestatus{FLOW}{unknown chart #1}%
+ \framed
+ [\c!width=12\bodyfontsize,\c!height=8\bodyfontsize]
+ {\tttf [chart #1]}}
+ {\dodogetFLOWchart[#1][#2]}}
+
+\def\dodogetFLOWchart[#1][#2]% to be split a bit more
+ {\vbox\bgroup
+ \insidefloattrue
+ \forgetall
+ \dontcomplain
+ % \offinterlineskip % we now explicitly use \nointerlineskip later on
+ \def\dohandleflowchart[##1][##2]%
+ {\def\currentFLOWnumber{##1}%
+ \getparameters[\@@FLOW][##2]}%
+ \getvalue{\@FLOW@-#1}%
+ \getparameters[\@@FLOW][#2]% dubbelop ?
+ \doifsomething{\@@FLOWautofocus}
+ {\checkFLOWautofocus}%
+ %\message{AUTOSHAPE 3: (\@@FLOWx,\@@FLOWy)->(\@@FLOWnx,\@@FLOWny)}\wait
+ \global\let\FLOWwidth \@@FLOWnx
+ \global\let\FLOWheight\@@FLOWny
+ \let\startFLOWcell\startFLOWcellA
+ \resetFLOWlocation
+ \processFLOWbuffer\currentFLOWnumber
+ \ifcase\@@FLOWnx\relax \let\@@FLOWnx\FLOWwidth \fi
+ \ifcase\@@FLOWny\relax \let\@@FLOWny\FLOWheight \fi
+ \doifnothing{\@@FLOWmaxwidth\@@FLOWmaxheight}{\FLOWscalingfalse}%
+ \ifFLOWscaling
+ \doifnothing{\@@FLOWmaxwidth }{\let\@@FLOWmaxwidth \maxdimen}%
+ \doifnothing{\@@FLOWmaxheight}{\let\@@FLOWmaxheight\maxdimen}%
+ \scratchcounter\bodyfontpoints
+ \doloop % NOG FONTSWITCH OM EX EN EM TE LATEN WERKEN
+ {\ifnum\scratchcounter>1 % NU DIMENSIONS IN TERMS OF BODYFONTSIZE
+ \bodyfontsize=\the\scratchcounter pt
+ \dimen0=\@@FLOWmaxwidth
+ \dimen2=\@@FLOWwidth
+ \dimen4=\@@FLOWdx
+ \advance\dimen2 2\dimen4
+ \dimen2=\@@FLOWnx\dimen2
+ \advance\dimen2 2\dimen4
+ \ifdim\dimen2>\dimen0
+ \advance\scratchcounter \minusone
+ \else
+ \dimen0=\@@FLOWmaxheight
+ \dimen2=\@@FLOWheight
+ \dimen4=\@@FLOWdy
+ \advance\dimen2 2\dimen4
+ \dimen2=\@@FLOWny\dimen2
+ \advance\dimen2 2\dimen4
+ \ifdim\dimen2>\dimen0
+ \advance\scratchcounter \minusone
+ \else
+ \exitloop
+ \fi
+ \fi
+ \else
+ \exitloop
+ \fi}%
+ \expanded{\switchtobodyfont[\the\scratchcounter pt]}%
+ \forgetall
+ % \offinterlineskip % needed ?
+ \else\ifx\@@FLOWbodyfont\empty\else
+ \expanded{\switchtobodyfont[\@@FLOWbodyfont]}% \expanded ?
+ \fi\fi
+ \global\let\FLOWcells\empty
+ \dimen0=\@@FLOWwidth
+ \edef\FLOWshapewidth{\the\dimen0}%
+ \dimen2=\@@FLOWdx
+ \advance\dimen0 2\dimen2
+ \edef\FLOWgridwidth{\the\dimen0}%
+ \dimen0=\@@FLOWheight
+ \edef\FLOWshapeheight{\the\dimen0}%
+ \dimen2=\@@FLOWdy
+ \advance\dimen0 2\dimen2
+ \edef\FLOWgridheight{\the\dimen0}%
+ \scratchdimen=\@@FLOSrulethickness
+ \edef\@@FLOSrulethickness{\the\scratchdimen}%
+ \scratchdimen=\@@FLOFrulethickness
+ \edef\@@FLOFrulethickness{\the\scratchdimen}%
+ \scratchdimen=\@@FLOLrulethickness
+ \edef\@@FLOLrulethickness{\the\scratchdimen}%
+ \ifdim\@@FLOLradius<2.5\scratchdimen
+ \scratchdimen=2.5\scratchdimen
+ \edef\@@FLOLradius{\the\scratchdimen}%
+ \ifdim\@@FLOLradius>\@@FLOWdx
+ \scratchdimen=\@@FLOWdx
+ \edef\@@FLOLradius{\the\scratchdimen}%
+ \fi
+ \ifdim\@@FLOLradius>\@@FLOWdy
+ \scratchdimen=\@@FLOWdy
+ \edef\@@FLOLradius{\the\scratchdimen}%
+ \fi
+ \else
+ \scratchdimen=\@@FLOLradius
+ \edef\@@FLOLradius{\the\scratchdimen}%
+ \fi
+ \processaction % magic 2.5
+ [\@@FLOWoffset]
+ [ \v!none=>\scratchdimen=-2.5\scratchdimen,
+ \v!overlay=>\scratchdimen=-2.5\scratchdimen,
+ \v!standard=>\scratchdimen=\scratchdimen,
+ \s!unknown=>\scratchdimen=\@@FLOWoffset,
+ \s!default=>\scratchdimen=-2.5\scratchdimen]%
+ \edef\@@FLOW@@offset{\the\scratchdimen}%
+ \forgetall
+ \offinterlineskip
+ \resetMPdrawing
+ \doglobal\newcounter\FLOWcomment
+ \startMPdrawing
+ if unknown context_char : input mp-char.mp ; fi ;
+ grid_width := \FLOWgridwidth ;
+ grid_height := \FLOWgridheight ;
+ shape_width := \FLOWshapewidth ;
+ shape_height := \FLOWshapeheight ;
+ connection_line_width := \@@FLOLrulethickness ;
+ connection_smooth_size := \@@FLOLradius ;
+ connection_arrow_size := \@@FLOLradius ;
+ connection_dash_size := \@@FLOLradius ;
+ currentpicture := nullpicture ;
+ begin_chart(0,\FLOWwidth,\FLOWheight);
+ reverse_y := true ;
+ chart_offset := \@@FLOW@@offset ;
+ \stopMPdrawing
+ \doifelsenothing\@@FLOWbackgroundcolor
+ {\startMPdrawing
+ chart_background_color := white ;
+ \stopMPdrawing}
+ {\startMPdrawing
+ chart_background_color := \MPcolor{\@@FLOWbackgroundcolor} ;
+ \stopMPdrawing}%
+ \doif\@@FLOWoption\v!test
+ {\startMPdrawing
+ show_con_points := true ;
+ show_mid_points := true ;
+ show_all_points := true ;
+ \stopMPdrawing}%
+ \processaction % private
+ [\@@FLOWdot]
+ [ \v!yes=>\startMPdrawing
+ show_con_points := true ;
+ show_mid_points := true ;
+ show_all_points := true ;
+ \stopMPdrawing,
+ \s!unknown=>\startMPdrawing
+ show_\@@FLOWdot_points := true ;
+ \stopMPdrawing]%
+\doglobal\newcounter\FLOWcomment
+ \let\startFLOWcell\startFLOWcellB
+ \resetFLOWlocation
+ \processFLOWbuffer\currentFLOWnumber
+\doglobal\newcounter\FLOWcomment
+ \let\startFLOWcell\startFLOWcellC
+ \resetFLOWlocation
+ \processFLOWbuffer\currentFLOWnumber
+ \startMPdrawing
+ clip_chart(\@@FLOWx,\@@FLOWy,\@@FLOWnx,\@@FLOWny) ;
+ end_chart ;
+ \stopMPdrawing
+ \MPdrawingdonetrue
+ \setbox0\hbox
+ {\MPstaticgraphictrue
+ \MPshiftdrawingfalse
+ \getMPdrawing}%
+ \def\MPmessage##1%
+ {\writestatus{MP charts}{##1}}%
+ \def\MPposition##1##2##3%
+ {\setvalue{\@@MPx##1}{##2}\setvalue{\@@MPy##1}{##3}}%
+ \def\MPclippath##1##2##3##4%
+ {\def\clipMPllx{##1bp}\def\clipMPlly{##2bp}%
+ \def\clipMPurx{##3bp}\def\clipMPury{##4bp}}%
+ \def\MPareapath##1##2##3##4%
+ {\def\areaMPllx{##1bp}\def\areaMPlly{##2bp}%
+ \def\areaMPurx{##3bp}\def\areaMPury{##4bp}}%
+ \getMPdata
+ \doglobal\newcounter\FLOWcomment
+ \let\startFLOWcell\startFLOWcellD
+ \setbox2\vbox to \ht0
+ {\forgetall % \offinterlineskip
+ \resetFLOWlocation
+ \processFLOWbuffer\currentFLOWnumber\vss}%
+ \setbox2\hbox
+ {\hskip\@@FLOW@@offset\lower\@@FLOW@@offset\box2}%
+ \wd2\wd0\ht2\ht0\dp2\dp0
+ \let\startFLOWcell\startFLOWcellE
+ \setbox4\vbox to \ht0
+ {\forgetall % \offinterlineskip
+ \resetFLOWlocation
+ \processFLOWbuffer\currentFLOWnumber\vss}%
+ \setbox4\hbox
+ {\hskip\@@FLOW@@offset\lower\@@FLOW@@offset\box4}%
+ \wd4\wd0\ht4\ht0\dp4\dp0
+ \doifelse\@@FLOWoption\v!test
+ {\setbox6\vbox
+ {\forgetall
+ \vskip\@@FLOW@@offset
+ \hskip\@@FLOW@@offset
+ \basegrid
+ [\c!x=\@@FLOWx,\c!nx=\@@FLOWnx,\c!dx=\withoutpt\FLOWgridwidth,
+ \c!y=\@@FLOWy,\c!ny=\@@FLOWny,\c!dy=\withoutpt\FLOWgridheight,
+ \c!xstep=1,\c!ystep=1,
+ \c!unit=pt,\c!location=\v!middle]}%
+ \wd6\wd0\ht6\ht0\dp6\dp0
+ \setbox8\vbox
+ {\forgetall
+ \offinterlineskip
+ \vskip\@@FLOW@@offset
+ \dostepwiserecurse\@@FLOWy\@@FLOWny\plusone
+ {\vbox to \FLOWgridheight
+ {\vfill
+ \hskip\@@FLOW@@offset
+ \hbox
+ {\dostepwiserecurse\@@FLOWx\@@FLOWnx\plusone
+ {\hbox to \FLOWgridwidth
+ {\hfill
+ \framed
+ [\c!framecolor=red,
+ \c!width=\FLOWshapewidth,
+ \c!height=\FLOWshapeheight]
+ {}%
+ \hfill}}}
+ \vfill}}}%
+ \wd8\wd0\ht8\ht0\dp8\dp0
+ \framed
+ [\c!offset=\v!overlay,\c!framecolor=green]
+ {\hbox{\box4\hskip-\wd0\box0\hskip-\wd2\box2\hskip-\wd6\box6\hskip-\wd8\box8}}}
+ {\framed
+ [\c!offset=\v!overlay,
+ \c!frame=\@@FLOWframe,
+ \c!rulethickness=\@@FLOWrulethickness,
+ \c!framecolor=\@@FLOWframecolor,
+ \c!background=\@@FLOWbackground,
+ \c!backgroundcolor=\@@FLOWbackgroundcolor]
+ {\hbox{\box4\hskip-\wd0\box0\hskip-\wd2\box2}}}%
+ %\message{[\FLOWcells]}\wait
+ \egroup}
+
+% Pass A
+
+\long\def\startFLOWcellA#1\stopFLOWcell%
+ {\resetFLOWcell
+ \ignorespaces#1\unskip
+ \expandafter\getFLOWlocationA\FLOWlocation\end
+ \ignorespaces}
+
+\def\getFLOWlocationA#1,#2\end
+ {\ifnum0#1>\FLOWwidth \xdef\FLOWwidth {#1}\fi
+ \ifnum0#2>\FLOWheight\xdef\FLOWheight{#2}\fi}
+
+% Pass B
+%
+% beware: the - after \@FLOC@ is needed since name can be
+% empty and we don't want to redefine \@FLOC@ itself by
+% mistake
+
+\long\def\startFLOWcellB#1\stopFLOWcell
+ {\resetFLOWcell\ignorespaces#1\unskip
+ \setxvalue{\@FLOC@-\FLOWname}{\FLOWlocation}% kost veel cs's
+ \ifx\FLOWshape\empty
+ \global\let\FLOWshape\@@FLOSdefault
+ \fi
+ \doifnot\FLOWshape{none} % {\v!none}
+ {\ExpandBothAfter\doifinsetelse{\FLOWshape}{\FLOWshapes}
+ {\edef\FLOWshapetag{shape_\FLOWshape}% beter \expanded
+ \@EA\setFLOWname\@EA\FLOWshapetag\@EA{\FLOWshapetag}}
+ {\doifnumberelse\FLOWshape
+ {\let\FLOWshapetag\FLOWshape}
+ {\let\FLOWshapetag\empty}}%
+ \ifx\FLOWshapetag\empty \else
+ \ExpandBothAfter\doifinsetelse{\FLOWshape}{\FLOWlines}
+ {\chardef\FLOWstate0 }
+ {\ExpandBothAfter\doifcommonelse{\FLOWcell,\FLOWfocus}{\@@FLOWfocus}
+ {\chardef\FLOWstate1 }
+ {\chardef\FLOWstate2 }}%
+ \startMPdrawing
+ begin_sub_chart ;
+ \ifcase\FLOWstate
+ shape_line_color := \MPcolor{\@@FLOLcolor} ;
+ shape_fill_color := \MPcolor{\@@FLOLcolor} ;
+ shape_line_width := \@@FLOLrulethickness ;
+ \or
+ shape_line_color := \MPcolor{\@@FLOFframecolor} ;
+ shape_fill_color := \MPcolor{\@@FLOFbackgroundcolor} ;
+ shape_line_width := \@@FLOFrulethickness ;
+ \or
+ shape_line_color := \MPcolor{\@@FLOSframecolor} ;
+ shape_fill_color := \MPcolor{\@@FLOSbackgroundcolor} ;
+ shape_line_width := \@@FLOSrulethickness ;
+ \fi
+ %\ifx\FLOWoverlay\empty
+ % peepshape := false ;
+ %\else
+ % peepshape := true ;
+ %\fi
+ peepshape := \ifx\FLOWoverlay\empty false \else true \fi ;
+ new_shape(\FLOWlocation,\FLOWshapetag) ;
+ end_sub_chart ;
+ \stopMPdrawing
+ \fi}%
+ \ignorespaces}
+
+% Pass C
+
+\long\def\startFLOWcellC#1\stopFLOWcell%
+ {\resetFLOWcell
+\pushmacro\lastFLOWx
+\pushmacro\lastFLOWy
+ \ignorespaces#1\unskip % makes sure that vars are set
+\popmacro\lastFLOWy
+\popmacro\lastFLOWx
+ \let\connection\doFLOWconnectionC
+ \ignorespaces#1\unskip}
+
+\def\FLOWorigin{0,0}
+
+\def\doFLOWdisplace[#1,#2,#3]% experiment
+ {dsp_x := #1 ; dsp_y := #2 ;}
+
+\def\doFLOWconnectionC
+ {\dodoubleempty\dodoFLOWconnectionC}
+
+\def\dodoFLOWconnectionC[#1][#2]#3%
+ {\doglobal\increment\FLOWcomment
+ \setFLOWname\otherFLOWname{name_#3}%
+ \doifdefinedelse{\@FLOC@-\FLOWname}
+ {\edef\FLOWfrom{\getvalue{\@FLOC@-\FLOWname}}}
+ {\let \FLOWfrom \FLOWorigin}%
+ \ifx\FLOWfrom\FLOWorigin \else
+ \doifdefinedelse{\@FLOC@-\otherFLOWname}
+ {\edef\FLOWto {\getvalue{\@FLOC@-\otherFLOWname}}}
+ {\let \FLOWto \FLOWorigin}%
+ \ifx\FLOWto\FLOWorigin \else
+ \FLOWsetconnect{#1}%
+ \ifx\cFLOWfrom\empty \else
+ \doifelse\@@FLOLcorner\v!round
+ {\startMPdrawing smooth := true ; \stopMPdrawing}
+ {\startMPdrawing smooth := false ; \stopMPdrawing}%
+ \doifelse\@@FLOLdash\v!yes
+ {\startMPdrawing dashline := true ; \stopMPdrawing}
+ {\startMPdrawing dashline := false ; \stopMPdrawing}%
+ \doifelse\@@FLOLarrow\v!yes
+ {\startMPdrawing arrowtip := true ; \stopMPdrawing}
+ {\startMPdrawing arrowtip := false ; \stopMPdrawing}%
+ \doifelse\@@FLOLoffset\v!none
+ {\startMPdrawing touchshape := true ; \stopMPdrawing}
+ {\startMPdrawing touchshape := false ; \stopMPdrawing}%
+%\doifsomething{#2}
+% {\startMPdrawing
+% \doFLOWdisplace[0#2,0,0]%
+% \stopMPdrawing}%
+ \startMPdrawing
+\doFLOWdisplace[0#2,0,0]%
+ connection_line_color := \MPcolor{\@@FLOLcolor} ;
+ connection_line_width := \@@FLOLrulethickness ;
+ connect_\cFLOWfrom_\cFLOWto (\FLOWfrom,\zFLOWfrom) (\FLOWto,\zFLOWto) ;
+\doFLOWdisplace[0,0,0]%
+ \stopMPdrawing
+ \fi
+ \fi
+ \fi
+ \ignorespaces}
+
+% Pass D
+
+\long\def\startFLOWcellD#1\stopFLOWcell
+ {\resetFLOWcell
+\pushmacro\lastFLOWx
+\pushmacro\lastFLOWy
+ \ignorespaces#1\unskip % presets vars
+\popmacro\lastFLOWy
+\popmacro\lastFLOWx
+ \let\doprocessFLOWcell\doprocessFLOWcellD
+ \expandafter\doprocessFLOWcellD\FLOWlocation\end
+ \let\connection\doFLOWconnectionD
+ \let\comment\doFLOWcommentD
+ \ignorespaces#1\unskip\ignorespaces}
+
+\def\doFLOWconnectionD
+ {\dodoubleempty\dodoFLOWconnectionD}
+
+\def\dodoFLOWconnectionD[#1][#2]#3%
+ {\doglobal\increment\FLOWcomment
+ \ignorespaces}
+
+\def\doFLOWcommentD[#1]#2%
+ {\bgroup
+ \let\FLOW \middlebox
+ \let\FLOWb \bottombox
+ \let\FLOWbl\bottomleftbox
+ \let\FLOWbr\bottomrightbox
+ \let\FLOWt \topbox
+ \let\FLOWtl\topleftbox
+ \let\FLOWtr\toprightbox
+ \let\FLOWl \leftbox
+ \let\FLOWlt\lefttopbox
+ \let\FLOWlb\leftbottombox
+ \let\FLOWr \rightbox
+ \let\FLOWrt\righttopbox
+ \let\FLOWrb\rightbottombox
+ \let\FLOWc \middlebox
+%\ifdefined{FLOW#1}%
+ \ifcase0\getvalue{\@@MPx\FLOWcomment}\getvalue{\@@MPy\FLOWcomment}\relax
+ \else
+ \ifdim\getvalue{\@@MPx\FLOWcomment}\s!bp<\areaMPllx\relax\else
+ \ifdim\getvalue{\@@MPx\FLOWcomment}\s!bp>\areaMPurx\relax\else
+ \ifdim\getvalue{\@@MPy\FLOWcomment}\s!bp<\areaMPlly\relax\else
+ \ifdim\getvalue{\@@MPy\FLOWcomment}\s!bp>\areaMPury\relax\else
+ \dimen0=\getvalue{\@@MPx\FLOWcomment}\s!bp
+ \advance\dimen0 -\@@FLOW@@offset
+ \advance\dimen0 -\clipMPllx
+ \dimen2=\clipMPury
+ \advance\dimen2 -\@@FLOW@@offset
+ \advance\dimen2 -\getvalue{\@@MPy\FLOWcomment}\s!bp
+ \setbox\scratchbox\hbox{\strut#2}%
+ \boxoffset.5\bodyfontsize
+ \setbox\scratchbox\hbox{\hskip\dimen0\lower\dimen2\getvalue{FLOW#1}{\box\scratchbox}}%
+ \smashbox\scratchbox
+ \box\scratchbox
+ \boxoffset\zeropoint
+ \nointerlineskip % really needed
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+%\fi
+ \egroup
+ \ignorespaces}
+
+% pass D
+
+\def\dophaseoneFLOWcellX#1#2%
+ {\!!counta#1\relax
+ \!!countb#2\relax
+ \!!countc\@@FLOWx
+ \!!countd\@@FLOWy
+ \advance\!!countc \@@FLOWnx
+ \advance\!!countd \@@FLOWny
+ \advance\!!countc \minusone
+ \advance\!!countd \minusone
+ \ifnum\!!counta<\@@FLOWx\relax \donefalse
+ \else\ifnum\!!counta>\!!countc \donefalse
+ \else\ifnum\!!countb<\@@FLOWy\relax \donefalse
+ \else\ifnum\!!countb>\!!countd \donefalse
+ \else \donetrue
+ \fi\fi\fi\fi}
+
+\def\dophasetwoFLOWcellX
+ {\advance\!!counta -\@@FLOWx
+ \advance\!!counta \plusone
+ \advance\!!countb -\@@FLOWy
+ \advance\!!countb \plusone
+ \dimen0=\FLOWgridwidth
+ \dimen0=\!!counta\dimen0
+ \advance\dimen0 -\FLOWgridwidth
+ \dimen4=\FLOWgridwidth
+ \advance\dimen4 -\FLOWshapewidth
+ \advance\dimen0 .5\dimen4
+ \dimen2=\FLOWgridheight
+ \dimen2=\!!countb\dimen2
+ \dimen4=\FLOWgridheight
+ \advance\dimen4 -\FLOWshapeheight
+ \advance\dimen2 -.5\dimen4
+ \edef\FLOWdx{\the\dimen0}%
+ \edef\FLOWdy{\the\dimen2}}
+
+\def\positionFLOWzero% assumes \FLOWdx and \FLOWdy are set
+ {\setbox0\hbox{\hskip\FLOWdx\lower\FLOWdy\box0}%
+ \smashbox0\box0
+ \nointerlineskip} % new, needed since we somehow reset that
+
+\def\doFLOWtlabel#1#2#3%
+ {\scratchdimen\ifcase#2 \zeropoint\else\@@FLOWdy\fi
+ \setbox0\hbox{\hskip\dimen2\raise\scratchdimen
+ \hbox{\raise\dimen4\hbox{#1{\strut#3}}}}%
+ \positionFLOWzero}%
+
+\def\doFLOWblabel#1#2#3%
+ {\scratchdimen\ifcase#2 \zeropoint\else\@@FLOWdy\fi
+ \setbox0\hbox{\hskip\dimen2\raise-\scratchdimen
+ \hbox{#1{\strut#3}}}%
+ \positionFLOWzero}%
+
+\def\doFLOWllabel#1#2#3%
+ {\scratchdimen\ifcase#2 \zeropoint\else\@@FLOWdx\fi
+ \setbox0\hbox{\hskip-\scratchdimen\raise\dimen6
+ \hbox{#1{\strut#3}}}%
+ \positionFLOWzero}%
+
+\def\doFLOWrlabel#1#2#3%
+ {\scratchdimen\ifcase#2 \zeropoint\else\@@FLOWdx\fi
+ \setbox0\hbox{\hskip\dimen0\hskip\scratchdimen
+ \hbox{\raise\dimen6\hbox{#1{\strut#3}}}}%
+ \positionFLOWzero}
+
+\def\doprocessFLOWcellD#1,#2\end
+ {\dophaseoneFLOWcellX{#1}{#2}%
+ \ifdone
+ \dophasetwoFLOWcellX
+ \doglobal\addtocommalist\FLOWcell\FLOWcells
+ \def\FLOWx{#1}%
+ \def\FLOWy{#2}%
+ \directsetup{flowcell}%
+ \setbox0\hbox
+ {\ifx\FLOWalign\empty\else
+ \setupframed
+ [\c!align=\v!normal,\c!bottom=\vfill,\c!top=\vfill]%
+ \@EA\processallactionsinset\@EA
+ [\FLOWalign]
+ [t=>{\setupframed[\c!bottom=\vfill,\c!top=]},
+ b=>{\setupframed[\c!bottom=,\c!top=\vfill]},
+ l=>{\setupframed[\c!align=\v!right]},
+ r=>{\setupframed[\c!align=\v!left]},
+ m=>{\setupframed[\c!align=\v!middle]},
+ c=>{\setupframed[\c!align=\v!middle]}]%
+ \fi
+ \doifelse\FLOWshape{none} % {\v!none}
+ {\setupframed[\c!offset=\v!overlay]}
+ {\setupframed[\c!offset=\@@FLOSoffset]}%
+ \framed
+ [\c!frame=\v!off,\c!background=flowcell,
+ \c!width=\FLOWshapewidth,\c!height=\FLOWshapeheight]
+ {\FLOWtext}}%
+ \showFLOWhelp0
+ \ifx\FLOWdestination\empty\else
+ \setbox0\hbox
+ {\setupinteraction[\c!color=,\c!contrastcolor=]%
+ \gotobox{\box0}[\FLOWdestination]}%
+ \fi
+ \positionFLOWzero
+ \dimen0=\FLOWshapewidth \dimen2=.5\dimen0
+ \dimen4=\FLOWshapeheight\dimen6=.5\dimen4
+ \boxoffset.5\bodyfontsize
+ \doFLOWtlabel \righttopbox0\tFLOWlabel
+ \doFLOWblabel\rightbottombox0\bFLOWlabel
+ \doFLOWllabel \lefttopbox0\lFLOWlabel
+ \doFLOWrlabel \righttopbox0\rFLOWlabel
+ \doFLOWtlabel \topbox0\tcFLOWlabel % for me only
+ \doFLOWblabel \bottombox0\bcFLOWlabel % for me only
+ \doFLOWllabel \leftbox0\lcFLOWlabel % for me only
+ \doFLOWrlabel \rightbox0\rcFLOWlabel % for me only
+ \ifnum#1=\@@FLOWx\relax \doFLOWllabel \leftbox1\lFLOWexit \fi
+ \ifnum#1=\!!countc \doFLOWrlabel \rightbox1\rFLOWexit \fi
+ \ifnum#2=\@@FLOWy\relax \doFLOWtlabel \topbox1\tFLOWexit \fi
+ \ifnum#2=\!!countd \doFLOWblabel \bottombox1\bFLOWexit \fi
+ \boxoffset\zeropoint
+ \fi}
+
+% For Willy Egger:
+%
+% \startsetups flowcell
+% \definelayer
+% [flowcell]
+% [width=\FLOWshapewidth,
+% height=\FLOWshapeheight]
+% \setlayerframed
+% [flowcell]
+% [preset=rightbottom,offset=1ex]
+% [frame=off]
+% {\tx(\FLOWx,\FLOWy)}
+% \stopsetups
+
+% Pass E
+
+\long\def\startFLOWcellE#1\stopFLOWcell
+ {\resetFLOWcell
+ \ignorespaces#1\unskip
+ \let\doprocessFLOWcell\doprocessFLOWcellE
+ \expandafter\doprocessFLOWcell\FLOWlocation\end}
+
+\def\doprocessFLOWcellE#1,#2\end % redundant
+ {\ifx\FLOWoverlay\empty \else
+ \dophaseoneFLOWcellX{#1}{#2}%
+ \ifdone
+ \dophasetwoFLOWcellX
+ \edef\FLOWdx{\the\dimen0}%
+ \edef\FLOWdy{\the\dimen2}%
+ \setbox0\hbox
+ {\framed
+ [%\c!frame=\v!off,
+ \c!background={\@@FLOWbackground,\FLOWoverlay},
+ \c!backgroundcolor=\@@FLOSbackgroundcolor,
+ \c!width=\FLOWshapewidth,\c!height=\FLOWshapeheight]
+ {}}%
+ \positionFLOWzero
+ \fi
+ \fi}
+
+% Pass F
+
+\def\checkFLOWautofocus
+ {\def\@@FLOWminx{100}\let\@@FLOWminy\@@FLOWminx
+ \def\@@FLOWmaxx {0}\let\@@FLOWmaxy\@@FLOWmaxx
+ \def\@@FLOWabsx {0}\let\@@FLOWabsy\@@FLOWabsx
+ \let\startFLOWcell\startFLOWcellF
+ \resetFLOWlocation
+ \processFLOWbuffer\currentFLOWnumber
+ %\message{AUTOSHAPE 1: (\@@FLOWminx,\@@FLOWminy)->(\@@FLOWmaxx,\@@FLOWmaxy)}%
+ \ifnum\@@FLOWabsx<\@@FLOWmaxx\let\@@FLOWmaxx\@@FLOWabsx\fi
+ \ifnum\@@FLOWabsy<\@@FLOWmaxy\let\@@FLOWmaxy\@@FLOWabsy\fi
+ %\message{AUTOSHAPE 2: (\@@FLOWminx,\@@FLOWminy)->(\@@FLOWmaxx,\@@FLOWmaxy)}%
+ \donetrue
+ \ifnum\@@FLOWminx=100 \donefalse\fi
+ \ifnum\@@FLOWminy=100 \donefalse\fi
+ \ifnum\@@FLOWmaxx=0 \donefalse\fi
+ \ifnum\@@FLOWmaxy=0 \donefalse\fi
+ \doFLOWcheckF\@@FLOWx\@@FLOWminx\@@FLOWmaxx\@@FLOWnx
+ \doFLOWcheckF\@@FLOWy\@@FLOWminy\@@FLOWmaxy\@@FLOWny}
+
+\def\startFLOWcellF#1\stopFLOWcell%
+ {\resetFLOWcell
+ \ignorespaces#1\unskip
+ \expandafter\doFLOWlocationF\FLOWlocation\end}%
+
+\def\doFLOWlocationF#1,#2\end%
+ {\ifnum#1>\@@FLOWabsx\def\@@FLOWabsx{#1}\fi
+ \ifnum#2>\@@FLOWabsy\def\@@FLOWabsy{#2}\fi
+ \ExpandBothAfter\doifinset{\FLOWcell}{\@@FLOWautofocus}
+ {\dodoFLOWlocationF{#1}<-\@@FLOWminx
+ \dodoFLOWlocationF{#1}>+\@@FLOWmaxx
+ \dodoFLOWlocationF{#2}<-\@@FLOWminy
+ \dodoFLOWlocationF{#2}>+\@@FLOWmaxy}}
+
+\def\dodoFLOWlocationF#1#2#3#4%
+ {\ifnum#1#2#4\relax
+ \!!counta=#1\advance\!!counta #31\relax
+ \edef#4{\ifnum\!!counta<1 1\else\the\!!counta\fi}%
+ \fi}
+
+\def\doFLOWcheckF#1#2#3#4%
+ {\ifdone
+ \let#1=#2%
+ \!!counta=#3%
+ \advance\!!counta \plusone\advance\!!counta -#2\relax
+ \ifnum\!!counta<1 \!!counta=1 \fi
+ \edef#4{\the\!!counta}%
+ \else
+ \let#1\!!plusone
+ \let#4\!!zerocount % no {1}
+ \fi}
+
+% \useFLOWchart[name][parent][setting,setting][additional settings]
+% \useFLOWchart[name][parent][additional settings]
+
+\let\currentFLOWchart\empty
+
+\def\useFLOWchart
+ {\doquadrupleempty\douseFLOWchart}
+
+\def\douseFLOWchart[#1][#2][#3][#4]% name parent sets mainsettings
+ {\iffourthargument
+ \setvalue{\@FLOW@--#1}[##1]{\setgetFLOWchart[#2][#3][#4,##1]}%
+ \else
+ \checkparameters[#3]%
+ \ifparameters
+ \setvalue{\@FLOW@--#1}[##1]{\setgetFLOWchart[#2][][#3,##1]}%
+ \else
+ \setvalue{\@FLOW@--#1}[##1]{\setgetFLOWchart[#2][#3][##1]}%
+ \fi
+ \fi}
+
+\def\setgetFLOWchart[#1][#2][#3]%
+ {\def\docommand##1{}% cell line focus ?
+ \processcommalist[#2]\docommand
+ \getFLOWchart[#1][#3]}
+
+\def\doFLOWchart[#1][#2]%
+ {\hbox\bgroup\vbox\bgroup % vmode suppresses spaces
+\def\currentFLOWchart{#1}%
+ \doifundefinedelse{\@FLOW@--#1}
+ {\getFLOWchart[#1][#2]}
+ {\getvalue{\@FLOW@--#1}[#2]}%
+ \egroup\egroup}
+
+\def\FLOWchart%
+ {\dodoubleempty\doFLOWchart}
+
+%D A hook into the help system.
+
+\def\showFLOWhelp#1%
+ {\doifhelpinfo\FLOWhelp
+ {\setbox#1=\hbox
+ {\setbox\scratchbox=\hbox{\lower\@@FLOWdy\hbox
+ {\helpbutton
+ [\c!width=\wd0,\c!color=,\c!height=\@@FLOWdy,\c!frame=\v!no]%
+ [\FLOWhelp]}}%
+ \smashbox\scratchbox
+ \setbox#1=\vbox
+ {\forgetall\offinterlineskip\box#1\box\scratchbox}%
+ \box#1}}}
+
+%D The next section is dedicated to splitting up charts.
+
+\def\getFLOWsize[#1]%
+ {\bgroup\let\dodogetFLOWchart\dogetFLOWsize\FLOWchart[#1]\egroup}
+
+\def\dogetFLOWsize[#1][#2]%
+ {\setbox\scratchbox=\vbox
+ {\globallet\FLOWmaxwidth \!!zerocount
+ \globallet\FLOWmaxheight\!!zerocount
+ \def\getFLOWlocation##1,##2\end
+ {\ifnum0##1>\FLOWmaxwidth \xdef\FLOWmaxwidth {##1}\fi
+ \ifnum0##2>\FLOWmaxheight\xdef\FLOWmaxheight{##2}\fi}%
+ \resetFLOWcell
+ \long\def\startFLOWcell##1\stopFLOWcell
+ {{##1\expandafter\getFLOWlocation\FLOWlocation\end}}%
+ \def\dohandleflowchart[##1][##2]%
+ {\resetFLOWlocation
+ \processFLOWbuffer{##1}}%
+ \getvalue{\@FLOW@-#1}}}
+
+\def\setupFLOWsplit%
+ {\dodoubleargument\getparameters[\@@FLOT]}
+
+\setupFLOWsplit%
+ [\c!nx=3,\c!ny=3,
+ \c!dx=1,\c!dy=1,
+ \c!command=,
+ \c!marking=\v!on,
+ \c!before=,\c!after=]
+
+\def\FLOWsplitx {1}
+\def\FLOWsplity {1}
+\def\FLOWsplitnx{1}
+\def\FLOWsplitny{1}
+
+\def\FLOWcharts%
+ {\dodoubleempty\doFLOWcharts}
+
+%D While splitting, the following variables are available:
+%D
+%D \starttyping
+%D \FLOWsplitnx \FLOWsplitny \FLOWsplitx \FLOWsplity
+%D \stoptyping
+
+\def\doFLOWcharts[#1][#2]%
+ {\bgroup
+ \getFLOWsize[#1]%
+ \dodoFLOWcharts\relax
+ \global\let\FLOWsplitnx\FLOWsplitx
+ \global\let\FLOWsplitny\FLOWsplity
+ \dodoFLOWcharts{\dododoFLOWcharts[#1][#2]}%
+ \egroup}
+
+\def\dodoFLOWcharts#1%
+ {\def\@@FLOTx{1}%
+ \global\let\FLOWsplitx\@@FLOTx
+ \doloop
+ {\def\@@FLOTy{1}%
+ \global\let\FLOWsplity\@@FLOTy
+ \doloop
+ {\bgroup
+ \scratchcounter\FLOWmaxwidth
+ \advance\scratchcounter -\@@FLOTx
+ \advance\scratchcounter \plusone
+ \ifnum\scratchcounter<\@@FLOTnx\edef\@@FLOTnx{\the\scratchcounter}\fi
+ \scratchcounter\FLOWmaxheight
+ \advance\scratchcounter -\@@FLOTy
+ \advance\scratchcounter \plusone
+ \ifnum\scratchcounter<\@@FLOTny\edef\@@FLOTny{\the\scratchcounter}\fi
+ #1% does something with the float, or not
+ \egroup
+ \increment(\@@FLOTy,\@@FLOTny)%
+ \ifnum\@@FLOTy>\FLOWmaxheight
+ \exitloop
+ \else
+ \doglobal\increment\FLOWsplity
+ \decrement(\@@FLOTy,\@@FLOTdy)%
+ \fi}%
+ \increment(\@@FLOTx,\@@FLOTnx)%
+ \ifnum\@@FLOTx>\FLOWmaxwidth
+ \exitloop
+ \else
+ \doglobal\increment\FLOWsplitx
+ \decrement(\@@FLOTx,\@@FLOTdx)%
+ \fi}}
+
+\def\dododoFLOWcharts[#1][#2]%
+ {\bgroup
+ \@@FLOTbefore
+ \doifnot\@@FLOTmarking\v!on{\let\cuthbox\hbox}%
+ \cuthbox
+ {\@@FLOTcommand
+ {\FLOWchart[#1][#2,
+ \c!x=\@@FLOTx,\c!nx=\@@FLOTnx,
+ \c!y=\@@FLOTy,\c!ny=\@@FLOTny]}}%
+ \@@FLOTafter
+ \egroup}
+
+%D An example of splitting is given below:
+%D
+%D \starttyping
+%D \setupFLOWsplit
+%D [nx=5,ny=10,
+%D dx=0,dy=0,
+%D before=,
+%D after=\page]
+%D
+%D \FLOWcharts[mybigflow]
+%D \stoptyping
+%D
+%D Or, one can say:
+%D
+%D \starttyping
+%D \splitfloat
+%D {\placefigure{What a big flowchart this is!}}
+%D {\FLOWcharts[mybigflow]}
+%D \stoptyping
+
+%D \macros
+%D {typeFLOWchart}
+%D
+%D For documentation purposes the following macro is
+%D provided. Watch the use of the first and last line hooks,
+%D which is needed because the start and stop commands are
+%D not part of the buffer.
+
+\def\typeFLOWchart[#1]%
+ {\bgroup
+ \def\dohandleflowchart[##1][##2]{\typeFLOWbuffer{##1}}%
+ \defconvertedargument\firstverbatimfileline{\startFLOWchart[#1]}%
+ \defconvertedargument\lastverbatimfileline {\stopFLOWchart}%
+ \getvalue{\@FLOW@-#1}
+ \egroup}
+
+%D New:
+%D
+%D \starttyping
+%D \setupFLOWcharts[command=\Whow]
+%D
+%D \startFLOWset[convert-en] % [tag][convert-en]
+%D \subFLOWchart[a][x=1,y=1,nx=3,ny=3]
+%D \subFLOWchart[b][x=1,y=2,nx=3,ny=3]
+%D \subFLOWchart[c][x=2,y=1,nx=3,ny=3]
+%D \stopFLOWset
+%D
+%D \def\Whow#1%
+%D {\ifnum\currentFLOWset=1 \framed{Some Chart}\fi}
+%D
+%D \FLOWset[convert-en] % [tag]
+%D
+%D \def\Whow#1%
+%D {\setuphead[state=high]
+%D \startstandardmakeup
+%D \centerbox{#1}
+%D \stopstandardmakeup}
+%D
+%D \FLOWset[convert-en] % [tag]
+%D \stoptyping
+
+\def\startFLOWset
+ {\dodoubleempty\dostartFLOWset}
+
+\def\dostartFLOWset[#1][#2]#3\stopFLOWset % tag name data
+ {\ifsecondargument
+ \long\setvalue{\@FLOX@#1}{\dohandleFLOWset{#1}{#2}{#3}}%
+ \else
+ \long\setvalue{\@FLOX@#1}{\dohandleFLOWset{#1}{#1}{#3}}%
+ \fi}
+
+\long\def\dohandleFLOWset#1#2#3% tag name data
+ {\bgroup
+ \def\subFLOWchart
+ {\dodoubleempty\dosubFLOWchart}%
+ \def\dosubFLOWchart[##1][##2]% subtag settings
+ {\ifsecondargument
+ \dodohandleFLOWset{#1}{##1}{#2}{##2}%
+ \else
+ \subFLOWchart[][##1]%
+ \fi}%
+ #3%
+ \egroup}
+
+\def\dodohandleFLOWset#1#2#3#4% tag subtag name settings
+ {\increment\currentFLOWset
+ \bgroup
+ \@@FLOXcommand
+ {\ifnum\currentFLOWset=1 \pagereference[#1]\fi
+ \doifsomething{#2}
+ {\setupreferencing[\c!prefix=]%
+ \pagereference[#1:#2]% -:#1:#2
+ \setupreferencing[\c!prefix=#1:#2]}%
+ \FLOWchart[#3][#4]}%
+ \egroup}
+
+\def\FLOWset[#1]%
+ {\newcounter\currentFLOWset
+ \doifdefinedelse{\@FLOX@#1}
+ {\getvalue{\@FLOX@#1}}
+ {\dodohandleFLOWset{#1}{}{#1}{}}}
+
+\newcounter\currentFLOWset
+
+\setupFLOWsets
+ [\c!command=]
+
+%D This will be an option:
+
+% \def\startFLOWchart%
+% {\dodoubleempty\dostartFLOWchart}
+%
+% \long\def\dostartFLOWchart[#1][#2]#3\stopFLOWchart
+% {\preparenextFLOWchart{#1}{#2}%
+% \long\setgvalue{\FLOWbufferprefix\nofFLOWcharts}{#3}}
+%
+% \long\def\dodefineFLOWchart[#1][#2]#3%
+% {\preparenextFLOWchart{#1}{#2}%
+% \long\setgvalue{\FLOWbufferprefix\nofFLOWcharts}{#3}}
+%
+% \def\processFLOWbuffer#1{\getvalue{\FLOWbufferprefix#1}}
+% \def\typeFLOWbuffer #1{[Sorry, no verbatim chart #1 available.]}
+
+\loadmarkfile{m-chart}
+
+\protect \endinput
diff --git a/tex/context/base/m-chemic.mkii b/tex/context/base/m-chemic.mkii
new file mode 100644
index 000000000..e6980e1ff
--- /dev/null
+++ b/tex/context/base/m-chemic.mkii
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=ppchtex (m-chemic),
+%D version=1997.03.19,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PPCHTEX\ (Plain Pictex Context cHemie \TEX),
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten},
+%D suggestions={Tobias Burnus, Dirk Kuypers \& 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.
+
+\ifx\psaxes\undefined \ifx\beginpicture\undefined
+ \usemodule[pictex]
+\fi \fi
+
+\input ppchtex.mkii \relax
+
+\endinput
diff --git a/tex/context/base/m-chemic.mkiv b/tex/context/base/m-chemic.mkiv
new file mode 100644
index 000000000..bd4cb093e
--- /dev/null
+++ b/tex/context/base/m-chemic.mkiv
@@ -0,0 +1,20 @@
+%D \module
+%D [ file=ppchtex (m-chemic),
+%D version=1997.03.19,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PPCHTEX\ (Plain Pictex Context cHemie \TEX),
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten},
+%D suggestions={Tobias Burnus, Dirk Kuypers \& 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{ppchtex}{not loaded as support for chemistry in now built in}
+
+% \usemodule[pictex] % we will get rid of this
+% \input ppchtex.mkiv \relax
+
+\endinput
diff --git a/tex/context/base/m-chemic.tex b/tex/context/base/m-chemic.tex
new file mode 100644
index 000000000..7bacf4a90
--- /dev/null
+++ b/tex/context/base/m-chemic.tex
@@ -0,0 +1,17 @@
+%D \module
+%D [ file=ppchtex (m-chemic),
+%D version=1997.03.19,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PPCHTEX\ (Plain Pictex Context cHemie \TEX),
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten},
+%D suggestions={Tobias Burnus, Dirk Kuypers \& 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.
+
+\loadmarkfile{m-chemic}
+
+\endinput
diff --git a/tex/context/base/m-cweb.tex b/tex/context/base/m-cweb.tex
new file mode 100644
index 000000000..c416c9b36
--- /dev/null
+++ b/tex/context/base/m-cweb.tex
@@ -0,0 +1,1371 @@
+%D \module
+%D [ file=m-cweb,
+%D version=1997.01.15,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\CWEB\ Pretty Printing Macros,
+%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.
+
+%D First some auxiliary stuff, to be moved to system module.
+
+\def\dodofindfirstcharacter#1%
+ {\ifx#1\relax
+ \let\next=\egroup
+ \else
+ \handlecase
+ {\expandafter\ifnum\expandafter\catcode\expandafter`#1=11
+ \def\next##1\relax{\egroup\def\firstcharacter{#1}}%
+ \fi}%
+ \fi
+ \next}
+
+\def\dofindfirstcharacter#1#2%
+ {\def\firstcharacter{}%
+ \bgroup
+ \defconvertedargument\ascii{#2}%
+ \let\next\dodofindfirstcharacter
+ \let\handlecase#1%
+ \expandafter\next\ascii\relax}
+
+\def\normalcase#1%
+ {#1}
+
+\def\findfirstcharacter%
+ {\dofindfirstcharacter\lowercase}
+
+\def\FindFirstCharacter%
+ {\dofindfirstcharacter\normalcase}
+
+\def\FINDFIRSTCHARACTER%
+ {\dofindfirstcharacter\uppercase}
+
+% nog doen:
+%
+% \deactivateCWEB in output routine
+% status info
+% gelinkte entries
+% parskip en parindent
+
+%D \gdef\CWEBquote#1.{{\em Quote :}\ #1.} % checks the .
+
+%D This module (re)implements the \CWEB\ macros as defined in
+%D the file \type{cwebmac.tex}.
+%D
+%D \CWEB\ uses short, often one character long, names for
+%D macros. This is no real problem because no one is supposed
+%D to read and understand the files generated by \CWEB. The
+%D standard macros are meant for \PLAIN\ \TEX\ users. In
+%D \CONTEXT\ and other macro packages however, there is a
+%D potential conflict with format specific or user defined
+%D commands. Furthermore, the \CWEB\ macros implement their own
+%D output routines. When integrating \CWEB\ documents in
+%D another environment, the \CWEB\ specific macros have to be
+%D made local. The first part of this module is dedicated to
+%D this feature.
+%D
+%D Instead of using \type{\def} and \type{\let} for defining
+%D macros, we use:
+%D
+%D \starttyping
+%D \defCEBmacro arguments {meaning}
+%D \letCEBmacro arguments {meaning}
+%D \stoptyping
+%D
+%D \CWEB files contain implicit calls to macros that generate
+%D the table of contents, the lists of sections and the index.
+%D Because we want to be much more flexible, we implemented our
+%D own alternatives, and therefore have to bypass the original
+%D ones. The next macro is used for defining these obsolete
+%D \CWEB\ macros. The dummies take care of arguments.
+%D
+%D \starttyping
+%D \defCEBdummy arguments {meaning}
+%D \stoptyping
+%D
+%D The list of \CWEB\ specific macro names is saved in a
+%D \TOKENLIST. This serves two purposes. First it enables us to
+%D activate the \CWEB\ macros, which are saved under a
+%D different name, second it can be used to temporary restore
+%D the meanings, for instance when the output routine builds
+%D the page.
+
+\newtoks\CWEBmacros
+
+%D Activating and deactivating is done by means of:
+%D
+%D \starttyping
+%D \activateCWEB
+%D \deactivateCWEB
+%D \stoptyping
+%D
+%D Which are implemented as:
+
+\def\activateCWEB%
+ {\let\doCWEB=\activateCWEBmacro
+ \the\CWEBmacros}
+
+\def\deactivateCWEB%
+ {\let\doCWEB=\deactivateCWEBmacro
+ \the\CWEBmacros}
+
+%D The three definition macros append the name of the macro to
+%D the list. The first two macros save the meaning, the last one
+%D assigns \type{{}} to the macro and gobbles original meaning.
+
+\long\def\defCWEBmacro#1%
+ {\appendtoks\doCWEB#1\to\CWEBmacros
+ \setvalue{newCWEB\string#1}}
+
+\long\def\letCWEBmacro#1%
+ {\appendtoks\doCWEB#1\to\CWEBmacros
+ \letvalue{newCWEB\string#1}}
+
+\long\def\defCWEBdummy#1#2#%
+ {\appendtoks\doCWEB#1\to\CWEBmacros
+ \setvalue{newCWEB\string#1}#2{}%
+ \gobbleoneargument}
+
+%D The macro \type{\defCWEBdummy} of course takes care of the
+%D argument. This leaves the two (de|)|activating macros:
+
+\def\CWEBmacro#1%
+ {\getvalue{newCWEB\string#1}}
+
+\def\activateCWEBmacro#1%
+ {\letvalue{oldCWEB\string#1}=#1%
+ \def#1{\CWEBmacro#1}}
+
+\def\deactivateCWEBmacro#1%
+ {\expandafter\let\expandafter#1\expandafter=\csname oldCWEB\string#1\endcsname}
+
+%D I did consider loading the \CWEB\ macros using temporary
+%D substitutes of \type{\def}, \type{\font}, \type{\newbox} etc.
+%D The main problem is that the file contains more than
+%D definitions and taking all kind of assignments into account
+%D too would not make things easier. So I decided to stick to
+%D the method as just described.
+
+%D Now we're ready for the real job. What follows is a partial
+%D adaption of the file \type{cwebmac.tex}, version 3.1, dated
+%D September 1994 and written by Levy and Knuth. When possible
+%D we kept the original meaning, but we've granted ourselves
+%D the freedom to reformat the macro's for readibility.
+%D
+%D We'll only present the macros we actually use. The source
+%D however contains the original implementation.
+
+% standard macros for CWEB listings (in addition to plain.tex)
+% Version 3.1 --- September 1994.
+%
+% \ifx\documentstyle\undefined\else\endinput\fi % LaTeX will use other macros
+%
+% \xdef\fmtversion{\fmtversion+CWEB3.1}
+
+%D \macros{.}{}
+%D
+%D \CWEBquote preserve a way to get the dot accent (all
+%D other accents will still work as usual).
+
+\letCWEBmacro\: = \.
+
+% \parskip = 0pt % no stretch between paragraphs
+% \parindent = 1em % for paragraphs and for the first line of C text
+
+% \font\ninerm = cmr9
+% \let\mc = \ninerm % medium caps
+% \font\eightrm = cmr8
+% \let\sc = \eightrm % small caps (NOT a caps-and-small-caps font)
+% \let\mainfont = \tenrm
+% \let\cmntfont = \tenrm
+% \font\tenss = cmss10
+% \let\cmntfont = \tenss % alternative comment font
+% \font\titlefont = cmr7 scaled \magstep4 % title on the contents page
+% \font\ttitlefont = cmtt10 scaled \magstep2 % typewriter type in title
+% \font\tentex = cmtex10 % TeX extended character set (used in strings)
+% \fontextraspace\tentex = 0pt % no double space after sentences
+
+%D \macros{mc,sc,cmntfont,eightrm}{}
+%D
+%D The naming of the fonts in in line with those in \PLAIN\
+%D \TEX. Although \CONTEXT\ implements its own scheme, there is
+%D still support for the \PLAIN\ ones. We keep the original
+%D names, but change their meaning. That way the macros obey
+%D switching to other sizes or styles.
+
+\defCWEBmacro\mc {\tx}
+\defCWEBmacro\sc {\txx}
+\defCWEBmacro\cmntfont {\ss}
+\defCWEBmacro\eightrm {\tx}
+
+%D \macros{tentex,sevenrm,sevensy,teni}{}
+%D
+%D The next one uses a temporary solution. The \type{cmtex10}
+%D font is not part of the default mechanism. We make use of
+%D the \CONTEXT\ variables \type{\textface}, \type{\scriptface}
+%D and \type{\scriptscriptface}, which hold the current
+%D sizes.
+
+\defCWEBmacro\tentex%
+ {\font\next=cmtex10 at \textface
+ \fontextraspace\next\zeropoint
+ \next}
+
+\defCWEBmacro\sevenrm {\getvalue{\scriptface rmtf}}
+\defCWEBmacro\sevensy {\getvalue{\scriptface mmsy}}
+\defCWEBmacro\teni {\getvalue{\textface mmmi}}
+
+%D \macros{CWEBpt}{}
+%D
+%D The original macros are based on a 10~point bodyfont size. We
+%D therefore have to specify dimension in points a bit
+%D different. Specifications like .6pt are changed to
+%D \type{.06} times \type{\bodyfontsize}.
+
+\defCWEBmacro\CWEBpt {\bodyfontsize} % still dutch
+
+%D \macros{CEE,UNIX,TEX,CPLUSPLUS}{}
+%D
+%D Next come some logo's. It does not make much sense to use
+%D the \CONTEXT\ logo mechanism here, so we simply say:
+
+\defCWEBmacro \CEE/{{\mc C\spacefactor1000}}
+\defCWEBmacro \UNIX/{{\mc U\kern-.05emNIX\spacefactor1000}}
+\defCWEBmacro \TEX/{\TeX}
+\defCWEBmacro\CPLUSPLUS/{{\mc C\PP\spacefactor1000}}
+\defCWEBmacro \Cee{\CEE/} % for backward compatibility
+
+%D \macros{\ }{}
+%D
+%D Now we come to the real work: the short commands that make
+%D up the typography.
+%D
+%D \CWEBquote italic type for identifiers.
+
+\defCWEBmacro\\#1%
+ {\leavevmode\hbox{\it#1\/\kern.05em}}
+
+%D \macros{\string|}{}
+%D
+%D \CWEBquote one letter identifiers look better this way.
+
+\defCWEBmacro\|#1%
+ {\leavevmode\hbox{$#1$}}
+
+%D \macros{\string\&}{}
+%D
+%D \CWEBquote boldface type for reserved words.
+
+\defCWEBmacro\%
+ {\leavevmode
+ \hbox
+ {\def\_%
+ {\kern.04em
+ \vbox{\hrule width.3em height .06\CWEBpt}% .6pt}%
+ \kern.08em}%
+ \bf#1\/\kern.05em}}
+
+%D \macros{.}{}
+%D
+%D Here we use the previously saved period. This macro
+%D takes care of special characters in strings.
+
+\defCWEBmacro\.#1%
+ {\leavevmode
+ \hbox
+ {\tentex % typewriter type for strings
+ \let\\=\BS % backslash in a string
+ \let\{=\LB % left brace in a string
+ \let\}=\RB % right brace in a string
+ \let\~=\TL % tilde in a string
+ \let\ =\SP % space in a string
+ \let\_=\UL % underline in a string
+ \let\&=\AM % ampersand in a string
+ \let\^=\CF % circumflex in a string
+ #1\kern.05em}}
+
+%D \macros{)}{}
+%D
+%D Some discretionary hack.
+
+\defCWEBmacro\)%
+ {\discretionary{\hbox{\tentex\BS}}{}{}}
+
+%D \macros{AT}{}
+%D
+%D \CWEBquote at sign for control text (not needed in versions
+%D $>=$ 2.9).
+
+\defCWEBmacro\AT{@}
+
+%D \macros{ATL,postATL,NOATL}{}
+%D
+%D A two step macro that handles whatever.
+
+\defCWEBmacro\ATL%
+ {\par
+ \noindent
+ \bgroup
+ \catcode`\_=12
+ \postATL}
+
+\defCWEBmacro\postATL#1 #2 %
+ {\bf letter \\{\uppercase{\char"#1}} tangles as \tentex "#2"%
+ \egroup
+ \par}
+
+\defCWEBmacro\noATL#1 #2 %
+ {}
+
+%D \macros{noatl}{}
+%D
+%D \CWEBquote suppress output from \type{@l}.
+
+\defCWEBmacro\noatl%
+ {\let\ATL=\noATL}
+
+% \defCWEBmacro\ATH%
+% {\X\kern-.5em:Preprocessor definitions\X}
+
+%D \macros{PB}
+%D
+%D \CWEBquote hook for program brackets {\tttf\string|...\string|}
+%D in TeX part or section name.
+
+\defCWEBmacro\PB%
+ {\relax}
+
+% \chardef\AM = `\& % ampersand character in a string
+% \chardef\BS = `\\ % backslash in a string
+% \chardef\LB = `\{ % left brace in a string
+% \chardef\RB = `\} % right brace in a string
+% \chardef\TL = `\~ % tilde in a string
+% \chardef\UL = `\_ % underline character in a string
+% \chardef\CF = `\^ % circumflex character in a string
+
+\defCWEBmacro\AM {\char`\&} % ampersand character in a string
+\defCWEBmacro\BS {\char`\\} % backslash in a string
+\defCWEBmacro\LB {\char`\{} % left brace in a string
+\defCWEBmacro\RB {\char`\}} % right brace in a string
+\defCWEBmacro\TL {\char`\~} % tilde in a string
+\defCWEBmacro\UL {\char`\_} % underline character in a string
+\defCWEBmacro\CF {\char`\^} % circumflex character in a string
+
+\defCWEBmacro\SP {{\tt\char`\ }} % (visible) space in a string
+
+% \newbox\PPbox \setbox\PPbox=\hbox
+% {\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt}
+% \newbox\MMbox \setbox\MMbox=\hbox
+% {\kern.5pt\raise1pt\hbox{\sevensy\char0\kern-1pt\char0}\kern.5pt}
+% \newbox\MGbox \setbox\MGbox=\hbox % symbol for ->
+% {\kern-2pt\lower3pt\hbox{\teni\char'176}\kern1pt}
+% \newbox\MODbox \setbox\MODbox=\hbox
+% {\eightrm\%}
+%
+% \def\PP {\copy\PPbox}
+% \def\MM {\copy\MMbox}
+% \def\MG {\copy\MGbox}
+% \def\MOD {\mathbin{\copy\MODbox}}
+
+\defCWEBmacro\PP% symbol for ++
+ {\kern.05\CWEBpt
+ \raise.1\CWEBpt\hbox{\sevenrm+\kern-.1\CWEBpt+}%
+ \kern.05\CWEBpt}
+
+\defCWEBmacro\MM%
+ {\kern.05\CWEBpt
+ \raise.1\CWEBpt\hbox{\sevensy\char0\kern-.1\CWEBpt\char0}%
+ \kern.05\CWEBpt}
+
+\defCWEBmacro\MG%
+ {\kern-.2\CWEBpt
+ \lower.3\CWEBpt\hbox{\teni\char'176}%
+ \kern .1\CWEBpt}
+
+\defCWEBmacro\MRL#1%
+ {\mathrel{\let\K==#1}}
+
+% \def\MRL#1%
+% {\KK#1}
+% \def\KK#1#2%
+% {\buildrel\;#1\over{#2}}
+
+\letCWEBmacro\GG = \gg
+\letCWEBmacro\LL = \ll
+\letCWEBmacro\NULL = \Lambda
+
+% \mathchardef\AND = "2026 % bitwise and; also \& (unary operator)
+
+\defCWEBmacro\AND% redefines itself (funny)
+ {\mathchardef\AND="2026 \AND} % bitwise and; also \& (unary operator)
+
+\letCWEBmacro\OR = \mid % bitwise or
+\letCWEBmacro\XOR = \oplus % bitwise exclusive or
+\defCWEBmacro\CM {{\sim}} % bitwise complement
+\defCWEBmacro\MOD {\mathbin{\eightrm\%}}
+\defCWEBmacro\DC {\kern.1em{::}\kern.1em} % symbol for ::
+\defCWEBmacro\PA {\mathbin{.*}} % symbol for .*
+\defCWEBmacro\MGA {\mathbin{\MG*}} % symbol for ->*
+\defCWEBmacro\this {\&{this}}
+
+% \newbox \bak % backspace one em
+% \newbox \bakk % backspace two ems
+%
+% \setbox\bak =\hbox to -1em{}
+% \setbox\bakk=\hbox to -2em{}
+
+\newcount\CWEBind % current indentation in ems
+
+\defCWEBmacro\1% indent one more notch
+ {\global\advance\CWEBind by 1
+ \hangindent\CWEBind em}
+
+\defCWEBmacro\2% indent one less notch
+ {\global\advance\CWEBind by -1 }
+
+\defCWEBmacro\3#1% optional break within a statement
+ {\hfil
+ \penalty#10
+ \hfilneg}
+
+\defCWEBmacro\4% backspace one notch
+ {\hbox to -1em{}}
+
+\defCWEBmacro\5% optional break
+ {\hfil
+ \penalty-1
+ \hfilneg
+ \kern2.5em
+ \hbox to -2em{}%
+ \ignorespaces}
+
+\defCWEBmacro\6% forced break
+ {\ifmmode
+ \else
+ \par
+ \hangindent\CWEBind em
+ \noindent
+ \kern\CWEBind em
+ \hbox to -2em{}%
+ \ignorespaces
+ \fi}
+
+\defCWEBmacro\7% forced break and a little extra space
+ {\Y
+ \6}
+
+\defCWEBmacro\8% no indentation
+ {\hskip-\CWEBind em
+ \hskip 2em}
+
+\defCWEBmacro\9#1%
+ {}
+
+\newcount\gdepth % depth of current major group, plus one
+\newcount\secpagedepth
+\secpagedepth=3 % page breaks will occur for depths -1, 0, and 1
+
+% \newtoks\gtitle % title of current major group
+% \newskip\intersecskip
+% \intersecskip=12pt minus 3pt % space between sections
+
+% \let\yskip=\smallskip
+
+\defCWEBmacro\?%
+ {\mathrel?}
+
+% \def\note#1#2.%
+% {\Y\noindent
+% {\hangindent2em\baselineskip10pt\eightrm#1~#2.\par}}
+
+\defCWEBmacro\lapstar%
+ {\rlap{*}}
+
+% \def\stsec%
+% {\rightskip=0pt % get out of C mode (cf. \B)
+% \sfcode`;=1500
+% \pretolerance 200
+% \hyphenpenalty 50
+% \exhyphenpenalty 50
+% \noindent{\let\*=\lapstar\bf\secstar.\quad}}
+%
+% \let\startsection=\stsec
+
+\defCWEBmacro\defin#1%
+ {\global\advance\CWEBind by 2 \1\&{#1 } } % begin `define' or `format'
+
+% \def\A% xref for doubly defined section name
+% {\note{See also section}}
+%
+% \def\As% xref for multiply defined section name
+% {\note{See also sections}}
+
+\defCWEBmacro\B%
+ {\rightskip=0pt plus 100pt minus 10pt % go into C mode
+ \sfcode`;=3000
+ \pretolerance 10000
+ \hyphenpenalty 1000 % so strings can be broken (discretionary \ is inserted)
+ \exhyphenpenalty 10000
+ \global\CWEBind=2 \1\ \unskip}
+
+\defCWEBmacro\C#1%
+ {\5\5\quad$/\ast\,${\cmntfont #1}$\,\ast/$}
+
+% \let\SHC\C % "// short comments" treated like "/* ordinary comments */"
+
+\defCWEBmacro\SHC#1%
+ {\5\5\quad$//\,${\cmntfont#1}}
+
+% \def\C#1{\5\5\quad$\triangleright\,${\cmntfont#1}$\,\triangleleft$}
+% \def\SHC#1{\5\5\quad$\diamond\,${\cmntfont#1}}
+
+\defCWEBmacro\D% macro definition
+ {\defin{\#define}}
+
+\letCWEBmacro\E=\equiv % equivalence sign
+
+% \def\ET% conjunction between two section numbers
+% { and~}
+%
+% \def\ETs% conjunction between the last two of several section numbers
+% {, and~}
+
+\defCWEBmacro\F% format definition
+ {\defin{format}}
+
+\letCWEBmacro\G = \ge % greater than or equal sign
+
+% \H is long Hungarian umlaut accent
+
+\letCWEBmacro\I = \ne % unequal sign
+
+\defCWEBmacro\J% TANGLE's join operation
+ {\.{@\&}}
+
+% \let\K== % assignment operator
+
+\letCWEBmacro\K = \leftarrow % "honest" alternative to standard assignment operator
+
+% \L is Polish letter suppressed-L
+
+% \outer\def\M#1%
+% {\MN{#1}%
+% \ifon
+% \vfil
+% \penalty-100
+% \vfilneg % beginning of section
+% \vskip\intersecskip
+% \startsection
+% \ignorespaces}
+%
+% \outer\def\N#1#2#3.%
+% {\gdepth=#1%
+% \gtitle={#3}%
+% \MN{#2}% beginning of starred section
+% \ifon
+% \ifnum#1<\secpagedepth
+% \vfil
+% \eject % force page break if depth is small
+% \else
+% \vfil
+% \penalty-100
+% \vfilneg
+% \vskip\intersecskip
+% \fi
+% \fi
+% \message{*\secno}% progress report
+% \edef\next%
+% {\write\cont % write to contents file
+% {\ZZ{#3}{#1}{\secno}{\noexpand\the\pageno}}}%
+% \next % \ZZ{title}{depth}{sec}{page}
+% \ifon
+% \startsection
+% {\bf#3.\quad}%
+% \ignorespaces}
+%
+% \def\MN#1%
+% {\par % common code for \M, \N
+% {\xdef\secstar{#1}%
+% \let\*=\empty
+% \xdef\secno{#1}}% remove \* from section name
+% \ifx\secno\secstar
+% \onmaybe
+% \else
+% \ontrue
+% \fi
+% \mark{{{\tensy x}\secno}{\the\gdepth}{\the\gtitle}}}
+%
+% each \mark is {section reference or null}{depth plus 1}{group title}
+
+% \O is Scandinavian letter O-with-slash
+% \P is paragraph sign
+
+\defCWEBmacro\Q {\note{This code is cited in section}} % xref for mention of a section
+\defCWEBmacro\Qs {\note{This code is cited in sections}} % xref for mentions of a section
+
+% \S is section sign
+
+\defCWEBmacro\T#1%
+ {\leavevmode % octal, hex or decimal constant
+ \hbox
+ {$\def\?{\kern.2em}%
+ \def\$##1{\egroup_{\,\rm##1}\bgroup}% suffix to constant
+ \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick)
+ \let\~=\oct
+ \let\^=\hex
+ {#1}$}}
+
+\defCWEBmacro\U {\note{This code is used in section}} % xref for use of a section
+\defCWEBmacro\Us {\note{This code is used in sections}} % xref for uses of a section
+
+\letCWEBmacro\R = \lnot % logical not
+\letCWEBmacro\V = \lor % logical or
+\letCWEBmacro\W = \land % logical and
+
+% defined later on
+%
+% \def\X#1:#2\X%
+% {\ifmmode
+% \gdef\XX{\null$\null}%
+% \else
+% \gdef\XX{}%
+% \fi % section name
+% \XX$\langle\,${#2\eightrm\kern.5em#1}$\,\rangle$\XX}
+
+\unprotect
+
+\def\theCWEByskip {\blank[\v!small]}
+\def\theCWEBvskip {\blank[\v!big]}
+
+\protect
+
+\defCWEBmacro\Y%
+ {\par
+ \yskip}
+
+\defCWEBmacro\yskip%
+ {\theCWEByskip}
+
+\letCWEBmacro\Z = \le
+% \letCWEBmacro\ZZ = \let % now you can \write the control sequence \ZZ
+\letCWEBmacro\* = *
+
+\defCWEBmacro\oct%
+ {\hbox{$^\circ$\kern-.1em\it\aftergroup\?\aftergroup}}
+
+\defCWEBmacro\hex%
+ {\hbox{$^{\scriptscriptstyle\#}$\tt\aftergroup}}
+
+\defCWEBmacro\vb#1%
+ {\leavevmode
+ \hbox
+ {\kern.2\CWEBpt
+ \vrule
+ \vtop
+ {\vbox
+ {\hrule
+ \hbox{\strut\kern.2\CWEBpt\.{#1}\kern.2\CWEBpt}}
+ \hrule}%
+ \vrule
+ \kern.2\CWEBpt}} % verbatim string
+
+\def\onmaybe%
+ {\let\ifon=\maybe}
+
+\let\maybe=\iftrue
+
+\newif\ifon
+
+% \newif\iftitle
+% \newif\ifpagesaved
+%
+% \def\lheader%
+% {\mainfont
+% \the\pageno
+% \eightrm
+% \qquad
+% \grouptitle
+% \hfill
+% \title
+% \qquad
+% \mainfont
+% \topsecno} % top line on left-hand pages
+%
+% \def\rheader%
+% {\mainfont
+% \topsecno
+% \eightrm
+% \qquad
+% \title
+% \hfill
+% \grouptitle
+% \qquad
+% \mainfont
+% \the\pageno} % top line on right-hand pages
+%
+% \def\grouptitle
+% {\let\i=I
+% \let\j=J
+% \uppercase\expandafter{\expandafter\takethree\topmark}}
+%
+% \def\topsecno%
+% {\expandafter\takeone\topmark}
+%
+% \def\takeone #1#2#3{#1}
+% \def\taketwo #1#2#3{#2}
+% \def\takethree #1#2#3{#3}
+%
+% \def\nullsec%
+% {\eightrm
+% \kern-2em} % the \kern-2em cancels \qquad in headers
+%
+% \let\page=\pagebody % \def\page {\box255 }
+% \raggedbottom % \normalbottom % faster, but loses plain TeX footnotes
+%
+% \def\normaloutput#1#2#3%
+% {\shipout\vbox
+% {\ifodd
+% \pageno
+% \hoffset=\pageshift
+% \fi
+% \vbox to \fullpageheight
+% {\iftitle
+% \global\titlefalse
+% \else
+% \hbox to \pagewidth
+% {\vbox to 10pt{}%
+% \ifodd\pageno #3\else#2\fi}
+% \fi
+% \vfill#1}} % parameter #1 is the page itself
+% \global\advance\pageno by 1}
+%
+% \gtitle={\.{CWEB} output} % this running head is reset by starred sections
+%
+% \mark{\noexpand\nullsec0{\the\gtitle}}
+%
+% \def\title%
+% {\expandafter\uppercase\expandafter{\jobname}}
+%
+% \def\topofcontents%
+% {\centerline{\titlefont\title}
+% \vskip.7in
+% \vfill} % this material will start the table of contents page
+
+\def\botofcontents%
+ {\vfill
+ \centerline{\covernote}} % this material will end the table of contents page
+
+\def\covernote%
+ {}
+
+% some leftover
+
+\defCWEBmacro\contentspagenumber{0} % default page number for table of contents
+
+% \newdimen\pagewidth \pagewidth = 158mm % the width of each page
+% \newdimen\pageheight \pageheight = 223mm % the height of each page
+% \newdimen\fullpageheight \fullpageheight = 240mm % page height including headlines
+% \newdimen\pageshift \pageshift = 0in % shift righthand pages wrt lefthand ones
+%
+% \def\magnify#1%
+% {\mag=#1
+% \pagewidth=6.5truein
+% \pageheight=8.7truein
+% \fullpageheight=9truein
+% \setpage}
+%
+% \def\setpage%
+% {\hsize\pagewidth
+% \vsize\pageheight} % use after changing page size
+%
+% \def\contentsfile {\jobname.toc} % file that gets table of contents info
+% \def\readcontents {\input \contentsfile}
+% \def\readindex {\input \jobname.idx}
+% \def\readsections {\input \jobname.scn}
+%
+% \newwrite\cont
+% \output{\setbox0=\page % the first page is garbage
+% \openout\cont=\contentsfile
+% \write\cont{\catcode `\noexpand\@=11\relax} % \makeatletter
+% \global\output{\normaloutput\page\lheader\rheader}}
+% \setpage
+% \vbox to \vsize{} % the first \topmark won't be null
+
+\defCWEBdummy\magnify#1% magnify the page
+ {}
+
+\defCWEBmacro\ch%
+ {\note{The following sections were changed by the change file:}
+ \let\*=\relax}
+
+% \newbox\sbox % saved box preceding the index
+% \newbox\lbox % lefthand column in the index
+%
+% \def\inx%
+% {\par\vskip6pt plus 1fil % we are beginning the index
+% \def\page{\box255 }
+% \normalbottom
+% \write\cont{} % ensure that the contents file isn't empty
+% \write\cont{\catcode `\noexpand\@=12\relax} % \makeatother
+% \closeout\cont % the contents information has been fully gathered
+% \output
+% {\ifpagesaved
+% \normaloutput{\box\sbox}\lheader\rheader
+% \fi
+% \global\setbox\sbox=\page
+% \global\pagesavedtrue}
+% \pagesavedfalse
+% \eject % eject the page-so-far and predecessors
+% \setbox\sbox\vbox{\unvbox\sbox} % take it out of its box
+% \vsize=\pageheight
+% \advance\vsize by -\ht\sbox % the remaining height
+% \hsize=.5\pagewidth
+% \advance\hsize by -10pt
+% % column width for the index (20pt between cols)
+% \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
+% \def\lr{L} % this tells whether the left or right column is next
+% \output
+% {\if L\lr
+% \global\setbox\lbox=\page
+% \gdef\lr{R}
+% \else
+% \normaloutput
+% {\vbox to\pageheight
+% {\box\sbox
+% \vss
+% \hbox to\pagewidth{\box\lbox\hfil\page}}}
+% \lheader
+% \rheader
+% \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi}
+% \message{Index:}
+% \parskip 0pt plus .5pt
+% \outer\def\I##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry
+% \def\[##1]{$\underline{##1}$} % underlined index item
+% \rm
+% \rightskip0pt plus 2.5em
+% \tolerance 10000
+% \let\*=\lapstar
+% \hyphenpenalty 10000
+% \parindent0pt
+% \readindex}
+%
+% \def\fin%
+% {\par\vfill\eject % this is done when we are ending the index
+% \ifpagesaved\null\vfill\eject\fi % output a null index column
+% \if L\lr\else\null\vfill\eject\fi % finish the current page
+% \parfillskip 0pt plus 1fil
+% \def\grouptitle{NAMES OF THE SECTIONS}
+% \let\topsecno=\nullsec
+% \message{Section names:}
+% \output={\normaloutput\page\lheader\rheader}
+% \setpage
+% \def\note##1##2.{\quad{\eightrm##1~##2.}}
+% \def\Q{\note{Cited in section}} % crossref for mention of a section
+% \def\Qs{\note{Cited in sections}} % crossref for mentions of a section
+% \def\U{\note{Used in section}} % crossref for use of a section
+% \def\Us{\note{Used in sections}} % crossref for uses of a section
+% \def\I{\par\hangindent 2em}\let\*=*
+% \readsections}
+%
+% \def\con%
+% {\par\vfill\eject % finish the section names
+% %\ifodd\pageno\else\titletrue\null\vfill\eject\fi % for duplex printers
+% \rightskip = 0pt
+% \hyphenpenalty = 50
+% \tolerance = 200
+% \setpage
+% \output={\normaloutput\page\lheader\rheader}
+% \titletrue % prepare to output the table of contents
+% \pageno=\contentspagenumber
+% \def\grouptitle{TABLE OF CONTENTS}
+% \message{Table of contents:}
+% \topofcontents
+% \line{\hfil Section\hbox to3em{\hss Page}}
+% \let\ZZ=\contentsline
+% \readcontents\relax % read the contents info
+% \botofcontents
+% \end} % print the contents page(s) and terminate
+%
+% \def\contentsline#1#2#3#4%
+% {\ifnum#2=0
+% \smallbreak
+% \fi
+% \line{\consetup{#2}#1
+% \rm\leaders\hbox to .5em{.\hfil}\hfil\ #3\hbox to3em{\hss#4}}}
+%
+
+\defCWEBmacro\consetup#1%
+ {\ifcase#1 \bf % depth -1 (@**)
+ \or % depth 0 (@*)
+ \or \hskip2em % depth 1 (@*1)
+ \or \hskip4em % depth 2 (@*2)
+ \or \hskip6em % depth 3 (@*3)
+ \or \hskip8em % depth 4 (@*4)
+ \or \hskip10em % depth 5 (@*5)
+ \else \hskip12em
+ \fi} % depth 6 or more
+
+\defCWEBdummy \inx {} % index
+\defCWEBdummy \fin {} % finish
+\defCWEBdummy \con {} % table of contents and finish
+
+\defCWEBdummy \noinx {} % no indexes or table of contents
+\defCWEBdummy \nosecs {} % no index of section names or table of contents
+\defCWEBdummy \nocon {} % no table of contents
+
+\defCWEBmacro\,%
+ {\relax
+ \ifmmode
+ \mskip\thinmuskip
+ \else
+ \thinspace
+ \fi}
+
+% \def\noinx%
+% {\let\inx=\end}
+%
+% \def\nosecs%
+% {\let\FIN=\fin
+% \def\fin%
+% {\let\parfillskip=\end
+% \FIN}}
+%
+% \def\nocon%
+% {\let\con=\end}
+%
+% \newcount\twodigits
+%
+% \def\hours%
+% {\twodigits=\time
+% \divide\twodigits by 60
+% \printtwodigits
+% \multiply\twodigits by -60
+% \advance\twodigits by \time
+% :\printtwodigits}
+%
+% \def\gobbleone1{}
+%
+% \def\printtwodigits%
+% {\advance\twodigits by 100
+% \expandafter\gobbleone\number\twodigits
+% \advance\twodigits by -100 }
+%
+% \def\today%
+% {\ifcase\month
+% \or January\or February\or March\or April\or May\or June%
+% \or July\or August\or September\or October\or November\or December%
+% \fi
+% \space
+% \number\day, \number\year}
+%
+% \def\datethis%
+% {\def\startsection%
+% {\leftline{\sc\today\ at \hours}
+% \bigskip
+% \let\startsection=\stsec
+% \stsec}}
+%
+% \def\datecontentspage%
+% {\def\topofcontents%
+% {\leftline{\sc\today\ at \hours}
+% \bigskip
+% \centerline{\titlefont\title}
+% \vfill}}
+
+\defCWEBdummy\datethis {} % say `\datethis' in limbo, to get your listing timestamped before section 1
+\defCWEBdummy\datecontentspage {} % timestamps the contents page
+
+\defCWEBmacro\TeX%
+ {{\ifmmode\it\fi
+ \leavevmode
+ \hbox{T\kern-.1667em\lower.424ex\hbox{E}\hskip-.125em X}}}
+
+% alternative implementation
+
+\newif\ifCWEBnotes
+
+\defCWEBmacro\Q {\CWEBnotesfalse \note{This code is cited in section}} % xref for mention of a section
+\defCWEBmacro\Qs {\CWEBnotestrue \note{This code is cited in sections}} % xref for mentions of a section
+
+\defCWEBmacro\U {\CWEBnotesfalse \note{This code is used in section}} % xref for use of a section
+\defCWEBmacro\Us {\CWEBnotestrue \note{This code is used in sections}} % xref for uses of a section
+
+\defCWEBmacro\A {\CWEBnotesfalse \note{See also section}} % xref for doubly defined section name
+\defCWEBmacro\As {\CWEBnotestrue \note{See also sections}} % xref for multiply defined section name
+
+\defCWEBmacro\ET% conjunction between two section numbers
+ { and~}
+
+\defCWEBmacro\ETs% conjunction between the last two of several section numbers
+ {, and~}
+
+%\def\processCWEBsectionnumbers[#1]%
+% {\bgroup
+% \def\CWEBcomma%
+% {\def\CWEBcomma{, }}%
+% \def\docommand##1%
+% {\bgroup
+% \def\[####1]{####1}%
+% \xdef\CWEBreference{##1}%
+% \egroup
+% \CWEBcomma{\naar{\donottest{##1}}[web:\CWEBreference]}}%
+% \processcommalist[{#1}]\docommand
+% \egroup}
+
+% \def\processCWEBsectionnumbers[#1]%
+% {\bgroup
+% \def\CWEBcomma%
+% {\def\CWEBcomma{, }}%
+% \def\docommand##1%
+% {\bgroup
+% \def\(####1){####1}%
+% \xdef\CWEBreference{##1}%
+% \egroup
+% \CWEBcomma
+% {\localcolortrue\naar{\donottest{##1}}[web:\CWEBreference]}}%
+% \bgroup
+% \def\[##1]{\(##1)}\let\(=\relax\xdef\CWEBreferences{#1}%
+% \egroup
+% \unexpanded\def\(##1){\[##1]}%
+% \processcommacommand[\CWEBreferences]\docommand
+% \egroup}
+
+\def\processCWEBsectionnumbers[#1]%
+ {\bgroup
+ \def\CWEBcomma%
+ {\def\CWEBcomma{, }}%
+ \def\docommand##1%
+ {\bgroup
+ \def\[####1]{####1}%
+ \xdef\CWEBreference{##1}%
+ \egroup
+ \CWEBcomma{\localcolortrue\goto{\donottest{##1}}[web:\CWEBreference]}}%
+ \processlist{(}{)}{,}\docommand(#1)
+ \egroup}
+
+\def\processCWEBsectionnotes%
+ {\catcode`\s=12
+ \doprocessCWEBsectionnotes}
+
+\def\doprocessCWEBsectionnotes#1.%
+ {\ifCWEBnotes
+ \def\next##1\ET##2##3.%
+ {\processCWEBsectionnumbers[##1]%
+ \if##2s%
+ {, and~\goto{##3}[web:##3]}%
+ \else
+ { and~\goto{##2##3}[web:##2##3]}%
+ \fi}%
+ \next#1.%
+ \else
+ \goto{#1}[web:#1]%
+ \fi
+ \afterCWEBnote % inside group!
+ \egroup}
+
+\let\afterCWEBnote=\relax
+
+\defCWEBmacro\note#1%
+ {\bgroup
+ \Y\noindent
+ \def\afterCWEBnote{\par}%
+ \hangindent2em
+ %\baselineskip10pt
+ \eightrm#1~\processCWEBsectionnotes}
+
+\def\oldCWEBmacroX#1:#2\X% original
+ {\ifmmode
+ \gdef\XX{\null$\null}%
+ \else
+ \gdef\XX{}%
+ \fi % section name
+ \XX$\langle\,${#2\eightrm\kern.5em#1}$\,\rangle$\XX}
+
+\defCWEBmacro\ATH%
+ {\oldCWEBmacroX\kern-.5em:Preprocessor definitions\X}
+
+\def\newCWEBmacroX#1:#2\X% original
+ {\ifmmode
+ \gdef\XX{\null$\null}%
+ \else
+ \gdef\XX{}%
+ \fi % section name
+ \XX$\langle\,$%
+ {#2\eightrm\kern.5em\processCWEBsectionnumbers[{#1}]}%
+ $\,\rangle$\XX}
+
+\defCWEBmacro\X#1:#2\X%
+ {\newCWEBmacroX#1:#2\X}
+
+\definemarking[CWEBfilename]
+\definemarking[CWEBsectiontitle]
+\definemarking[CWEBsectionnumber]
+\definemarking[CWEBsectiondepth]
+
+\defCWEBmacro\M#1%
+ {\MN{#1}%
+ \ifon
+ \vfil
+ \penalty-100
+ \vfilneg % beginning of section
+ \theCWEBvskip
+ \startsection
+ \pagereference[web:#1]%
+ \expanded{\marking[CWEBsectionnumber]{\secno}}%
+ \expanded{\marking[CWEBsectiondepth]{\the\gdepth}}%
+ \ignorespaces}
+
+\defCWEBmacro\N#1#2#3.%
+ {\gdepth=#1%
+ \MN{#2}% beginning of starred section
+ \ifon
+ \ifnum#1<\secpagedepth
+ \vfil
+ \eject % force page break if depth is small
+ \else
+ \vfil
+ \penalty-100
+ \vfilneg
+ \theCWEBvskip
+ \fi
+ \fi
+ \message{*\secno}% progress report
+ \makesectionformat % context
+ \defconvertedargument\ascii{#3}%
+ \edef\next%
+ {\write\CWEBcont % write to contents file
+ {\string\ZZ{\ascii}{#1}{\secno}%
+ {\sectionformat::\noexpand\userfolio}{\noexpand\realfolio}}}%
+ \next % \ZZ{title}{depth}{sec}{page}
+ \ifon
+ \startsection
+ \pagereference[web:#2]%
+ \marking[CWEBsectiontitle] {#3}%
+ \expanded{\marking[CWEBsectionnumber]{\secno}}%
+ \expanded{\marking[CWEBsectiondepth]{\the\gdepth}}%
+ {\bf#3.\quad}%
+ \ignorespaces}
+
+\defCWEBmacro\MN#1%
+ {\par % common code for \M, \N
+ {\xdef\secstar{#1}%
+ \let\*=\empty
+ \xdef\secno{#1}}% remove \* from section name
+ \ifx\secno\secstar
+ \onmaybe
+ \else
+ \ontrue
+ \fi}
+
+\newif\iflinktoCWEBfile
+
+\def\setCWEBlinkfile#1%
+ {\linktoCWEBfiletrue
+ \def\otherCWEBfile{#1}}
+
+\unprotect
+
+\def\gotoCWEBsection#1[#2]%
+ {\iflinktoCWEBfile
+ \bgroup
+ \setupinteraction[\c!color=,\c!style=]%
+ \let\savedreferenceprefix=\referenceprefix
+ \localcolortrue
+ \goto{#1}[\otherCWEBfile::\savedreferenceprefix web:#2]%
+ \egroup
+ \else
+ #1%
+ \fi}
+
+\protect
+
+\defCWEBmacro\startsection%
+ {\rightskip=0pt % get out of C mode (cf. \B)
+ \sfcode`;=1500
+ \pretolerance 200
+ \hyphenpenalty 50
+ \exhyphenpenalty 50
+ \noindent
+ \bgroup
+ \let\*=\lapstar
+ \gotoCWEBsection{\bf\secstar.\quad}[\secno]%
+ \egroup}
+
+\def\ignoreCWEBinput%
+ {\let\normalinput=\input
+ \def\input ##1 %
+ {\let\input=\normalinput}}
+
+\def\loadCWEBmacros#1%
+ {\let\oldN=\N
+ \def\N{\bgroup\setbox0=\vbox\bgroup\endinput}%
+ \ignoreCWEBinput
+ \ReadFile{#1.tex}%
+ \egroup\egroup
+ \let\N=\oldN}
+
+\def\resetCWEBcontext%
+ {\catcode`\|=12 % used in context discretionaries
+ \everypar{} % used for context indentation and floats
+ \parskip=0pt % no stretch between cweb paragraphs
+ \parindent=1em} % is related to cweb backspace etc
+
+\newwrite\CWEBcont
+
+\def\processCWEBsource #1 %
+ {\bgroup
+ \resetCWEBcontext
+ \activateCWEB
+ \ignoreCWEBinput
+ \immediate\openout\CWEBcont=#1.toc
+ \write\CWEBcont{\noexpand\unprotect}
+ \message{Source:}
+ \marking[CWEBfilename]{#1}
+ \ReadFile{#1.tex}\relax
+ \write\CWEBcont{\noexpand\protect}
+ \closeout\CWEBcont
+ \par
+ \egroup}
+
+\def\resetCWEBindexentry%
+ {\xdef\currentCWEBindexentry{}}
+
+\def\showCWEBindexentry#1% can be redefined
+ {\theCWEBvskip
+ \vskip3\lineheight
+ \goodbreak
+ \vskip-3\lineheight
+ {\pagereference[web:#1]\bf#1}%
+ \theCWEBvskip}
+
+\def\checkCWEBindexentry#1%
+ {\bgroup
+ \def\\##1{##1}% a dummy that also removes the {}
+ \def\|##1{##1}% another dummy
+ \def\.##1{*##1}% and another (the typewriter one)
+ \def\#1{##1}% and a last one
+ \def\9##1{##1}% hold this one
+ \catcode`*=11
+ \expandafter\def\expandafter\entry\expandafter{#1}%
+ \defconvertedcommand\ascii\entry
+ \expanded{\FINDFIRSTCHARACTER{\ascii}}%
+ \doifnot{\currentCWEBindexentry}{\firstcharacter}
+ {\doifnot{\firstcharacter}{*} % signal for \firstbunch
+ {\global\let\currentCWEBindexentry=\firstcharacter
+ \showCWEBindexentry{\currentCWEBindexentry}}}%
+ \egroup}
+
+\def\theCWEBbeforeindex {\startcolumns}
+\def\theCWEBafterindex {\stopcolumns}
+
+\def\processCWEBindex #1 %
+ {\bgroup
+ \resetCWEBcontext
+ \activateCWEB
+ \resetCWEBindexentry
+ \def\I##1, %
+ {\par
+ \checkCWEBindexentry{##1}%
+ \hangindent2em
+ \noindent##1:\kern1em%
+ \def\next####1.%
+ {\processCWEBsectionnumbers[{####1}]}%
+ \next}%
+ \def\[##1]%
+ {$\underline{##1}$}%
+ \let\*=\lapstar
+ \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
+% \parskip 0pt plus .5pt
+ \rightskip0pt plus 2.5em
+ \tolerance 10000
+ \hyphenpenalty 10000
+ \parindent0pt
+ \message{Index:}
+ \marking[CWEBfilename] {#1}
+ \marking[CWEBsectiontitle] {index}
+ \marking[CWEBsectionnumber]{}
+ \marking[CWEBsectiondepth]{}
+ \loadCWEBmacros{#1}
+ \theCWEBbeforeindex
+ \ReadFile{#1.idx}\relax
+ \theCWEBafterindex
+ \par
+ \egroup}
+
+\def\processCWEBsections #1 %
+ {\bgroup
+ \resetCWEBcontext
+ \activateCWEB
+ \loadCWEBmacros{#1}
+ \parfillskip = 0pt plus 1fil
+ \parindent = 0pt
+ \let\topsecno=\nullsec
+ \def\note##1%
+ {\quad
+ \bgroup
+ \eightrm
+ ##1~\processCWEBsectionnotes}
+ \def\Q {\CWEBnotesfalse \note{Cited in section}} % crossref for mention of a section
+ \def\Qs{\CWEBnotestrue \note{Cited in sections}} % crossref for mentions of a section
+ \def\U {\CWEBnotesfalse \note{Used in section}} % crossref for use of a section
+ \def\Us{\CWEBnotestrue \note{Used in sections}} % crossref for uses of a section
+ \def\I {\par\hangindent 2em}%
+ \let\*=*
+ \message{Section names:}
+ \marking[CWEBfilename] {#1}
+ \marking[CWEBsectiontitle] {sections}
+ \marking[CWEBsectionnumber]{}
+ \marking[CWEBsectiondepth]{}
+ \loadCWEBmacros{#1}
+ \ReadFile{#1.scn}\relax
+ \par
+ \botofcontents
+ \par
+ \egroup}
+
+\def\processCWEBcontents #1 %
+ {\bgroup
+ \resetCWEBcontext
+ \activateCWEB
+ \loadCWEBmacros{#1}
+ \rightskip = 0pt
+ \hyphenpenalty = 50
+ \tolerance = 200
+ \parindent = 0pt
+ \line{\hfil Section\hbox to3em{\hss Page}}
+ \let\ZZ=\contentsline
+ \message{Table of contents:}
+ \marking[CWEBfilename] {#1}
+ \marking[CWEBsectiontitle] {table of contents}
+ \marking[CWEBsectionnumber]{}
+ \marking[CWEBsectiondepth]{}
+ \loadCWEBmacros{#1}
+ \ReadFile{#1.toc}\relax
+ \par
+ \egroup}
+
+\defCWEBmacro\contentsline#1#2#3#4#5%
+ {\ifnum#2=0
+ \smallbreak
+ \fi
+ \line{\consetup{#2}#1
+ \rm
+ \leaders\hbox to .5em{.\hfil}\hfil\
+ {\localcolortrue\goto{#3}[web:#3]}% below: \gotorealpage ? should be changed
+ \hbox to3em{\localcolortrue\hss\gotorealpage{}{}{#5}{\translatednumber[#4]\presetgoto}}}}
+
+%D A last hack, needed because a file can overload of the
+%D above. (Some day: a check like \type{\ifx#1\CWEBdefined}.)
+
+\def\outer#1#2%
+ {\ifx#2\undefined
+ \expandafter#1\expandafter#2%
+ \else
+ \expandafter#1\expandafter\ThrowAway
+ \fi}
+
+\endinput
diff --git a/tex/context/base/m-database.tex b/tex/context/base/m-database.tex
new file mode 100644
index 000000000..3bb050f14
--- /dev/null
+++ b/tex/context/base/m-database.tex
@@ -0,0 +1,421 @@
+%D \module
+%D [ file=m-database,
+%D version=2006.04.23,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Database Thingies,
+%D author=Hans Hagen\& Taco Hoekwater,
+%D date=\currentdate,
+%D copyright=PRAGMA
+%D ]
+
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+% % % to be added to mult-* files
+%
+% % % todo: \dontcollectseparatedlist via k/v
+
+\definesystemvariable{ls}
+
+\def\c!first {first}
+\def\c!last {last}
+\def\c!quotechar {quotechar}
+
+\let\@NX\noexpand
+
+%D {processquotedlist}
+%D
+%D An even more general list processing macro is the
+%D following one:
+%D
+%D \starttyping
+%D \processquotedlist{beginsym}{endsym}{separator}\docommand list
+%D \stoptyping
+%D
+%D This one supports arbitrary open and close symbols as well
+%D as user defined separators.
+%D
+%D \starttyping
+%D \processquotedlist(){,}{"}\docommand(a=>b=>c=>d)
+%D \stoptyping
+
+\def\processquotedlist#1#2#3#4#5%
+ {\def\csvquotechar{#4}%
+ \edef\doconvertcsvquoteditem#4##1#4##2%
+ {\@NX\ifx##2#3%
+ \let\@NX\next\@NX\doconvertcsvlist
+ \def\@NX\arg{#3}%
+ \edef\@NX\temp{##1}%
+ \@NX\expanded{\@NX#5{\@NX\temp}}%
+ \@NX\else
+ \let\@NX\next\@NX\redoconvertcsvquoteditem
+ \def\@NX\arg{##1\@NX\csvquotechar}%
+ \@NX\fi
+ \@NX\expandafter\@NX\next\@NX\arg}%
+ \edef\redoconvertcsvquoteditem##1#4##2%
+ {\@NX\ifx##2#3%
+ \let\@NX\next\@NX\doconvertcsvlist
+ \def\@NX\arg{#3}%
+ \edef\@NX\temp{##1}%
+ \@NX\expanded{\@NX#5{\@NX\temp}}%
+ \@NX\else
+ \let\@NX\next\@NX\redoconvertcsvquoteditem
+ \def\@NX\arg{##1\@NX\csvquotechar}%
+ \@NX\fi
+ \@NX\expandafter\@NX\next\@NX\arg}%
+ \edef\doconvertcsvitem##1#3%
+ {\edef\@NX\temp{##1}%
+ \@NX\expanded{\@NX#5{\@NX\temp}}%
+ \@NX\doconvertcsvlist#3}%
+ \edef\doconvertcsvlist#3##1%
+ {\@NX\ifx##1\@NX#2%
+ \let\@NX\next \@NX\gobbleoneargument
+ \@NX\else\@NX\ifx##1#4%
+ \let\@NX\next \@NX\doconvertcsvquoteditem
+ \@NX\else
+ \let\@NX\next \@NX\doconvertcsvitem
+ \@NX\fi\@NX\fi \@NX\next##1}%
+ \doconvertcsvitem}
+
+\gdef\doprocessseparatedquoteditem#1%
+ {\appendseparatedlistparameter\c!left%
+ \appendseparatedlistcontent{#1}%
+ \appendseparatedlistparameter\c!right}
+
+% a version more robust with regard to {a a} b c d situations:
+
+\edef\detokenizedrelax{\detokenize{\relax}}
+
+\edef\processseplistseparator{\detokenize{,}}%
+
+\def\dodefineprocessseplist#1#2% separator \docommand
+ {\edef\processseplistseparator{\detokenize{#1}}%
+ \def\dodoprocessseplist##1##2#1%
+ {\edef\!!stringa{\detokenize{##1}}%
+ \ifx\detokenizedrelax\!!stringa
+ \expandafter\nodoprocessseplist
+ % \else\ifx\!!stringa#1%
+ \else\ifx\!!stringa\processseplistseparator
+ #2{}%
+ #2{##2}%
+ \expandafter\expandafter\expandafter\dodoprocessseplist
+ \else
+ #2{##1##2}%
+ \expandafter\expandafter\expandafter\dodoprocessseplist
+ \fi\fi}%
+ \def\doprocessseplist##1\relax
+ {\dodoprocessseplist##1#1\relax#1\relax\relax\end}}
+
+\def\nodoprocessseplist#1\end
+ {}
+
+\long\def\processseplist#1#2#3\relax raw version
+ {\dodefineprocessseplist{#1}{#2}%
+ \dodoprocessseplist#3#1\relax#1\relax\relax\end}
+
+% \dodefineprocessseplist{,}\test
+% \dodoprocessseplist{,}a,b,c\relax,\relax\relax\end
+% \doprocessseplista,b,c\relax
+
+% \def\test#1{[#1]}
+% \startlines
+% \processseplist{,}\test ,2,,\relax
+% \processseplist{,}\test ,,,44\relax
+% \processseplist{,}\test ,,33,44\relax
+% \processseplist{,}\test 11,,33,44\relax
+% \processseplist{,}\test 1,2,3,4\relax
+% \stoplines
+
+\newtoks\separatedlistdata
+
+\def\appendseparatedlistparameter#1%
+ {\@EAEAEA\appendtoks\csname\??ls\currentseparatedlist#1\endcsname\to\separatedlistdata}
+
+\def\appendseparatedlistcontent#1%
+ {\appendtoks#1\to\separatedlistdata}
+
+\def\flushseparatedlistdata
+ {\the\separatedlistdata
+ \separatedlistdata\emptytoks}
+
+\def\initializeseparatedlistdata
+ {\separatedlistdata{\egroup}}
+
+\def\dontcollectseparatedlist
+ {\def\dodoprocessseparatedfileline
+ {\the\separatedlistdata
+ \separatedlistdata\emptytoks
+ \doprocessseparatedfileline}%
+ \def\dodoprocessseparatedline
+ {\the\separatedlistdata
+ \separatedlistdata\emptytoks
+ \doprocessseparatedline}%
+ \let\flushseparatedlistdata\egroup
+ \let\initializeseparatedlistdata\donothing}
+
+\chardef\separatedlistmode\zerocount
+
+\def\setcurrentlistseparator
+ {\edef\currentlistseparator
+ {\executeifdefined
+ {\??ls::\csname\??ls\currentseparatedlist\c!separator\endcsname}%
+ {\csname\??ls\currentseparatedlist\c!separator\endcsname}}%
+ \doifvalue{\??ls\currentseparatedlist\c!separator}{tab}
+ {\catcode`\^^I=12\relax}%
+ \ifx\currentlistseparator\empty\def\currentlistseparator{,}\fi}
+
+\bgroup \catcode`\^^I=12
+ \setgvalue{\??ls::tab}{ }
+ \setgvalue{\??ls::space}{ }
+ \setgvalue{\??ls::comma}{,}
+\egroup
+
+\def\doprocessseparatedfileline
+ {\ifeof\scratchread
+ \ifcase\separatedlistmode\appendseparatedlistparameter\c!after\fi
+ \immediate\closein\scratchread
+ \expandafter\flushseparatedlistdata
+ \else\ifx\line\empty
+ % skip, can be comment
+ \read\scratchread to\line
+ \@EA\dodoprocessseparatedfileline
+ \else
+ \appendseparatedlistparameter{\ifcase\separatedlistmode\c!first\else\c!command\fi}%
+ \ifx\currentlistquotechar\empty%
+ \expandafter\doprocessseplist\line\relax
+ \else
+ \expanded{\processquotedlist{}{\noexpand\end}%
+ {\currentlistseparator}{\currentlistquotechar}%
+ \noexpand\doprocessseparatedquoteditem \line\currentlistseparator\noexpand\end}%
+ \fi
+ \ifcase\separatedlistmode\appendseparatedlistparameter\c!last\fi
+ \read\scratchread to\line
+ \@EAEAEA\dodoprocessseparatedfileline
+ \fi\fi}
+
+\def\dodoprocessseparatedfileline
+ {\doprocessseparatedfileline}
+
+\def\doprocessseparatedfile[#1][#2]%
+ {\bgroup
+ \edef\currentseparatedlist{#1}%
+ \doifdefined{\??ls\currentseparatedlist\c!command}{\chardef\separatedlistmode\plusone}%
+ \setcurrentlistseparator
+ \edef\currentlistquotechar{\csname\??ls\currentseparatedlist\c!quotechar\endcsname}%
+ \expandafter\dodefineprocessseplist\expandafter{\currentlistseparator}\doprocessseparateditem
+ \initializeseparatedlistdata
+ \directsetup{\currentseparatedlist:\executeifdefined{\??ls\currentseparatedlist\c!setups}\s!default}%
+ \ifcase\separatedlistmode\appendseparatedlistparameter\c!before\fi
+ \endlinechar\minusone
+ \ignorelines
+ \catcode`\#\@@comment
+ \immediate\openin\scratchread=#2\relax % todo: \doopenin
+ \read\scratchread to\line
+ \doprocessseparatedfileline}
+
+\def\dostartseparatedlist#1[#2]%
+ {\bgroup
+ \edef\currentseparatedlist{#2}%
+ \doifdefined{\??ls\currentseparatedlist\c!command}{\chardef\separatedlistmode\plusone}%
+ \obeylines
+ \let#1\relax
+ \def\separateslistend{#1}%
+ \setcurrentlistseparator
+ \edef\currentlistquotechar{\csname\??ls\currentseparatedlist\c!quotechar\endcsname}%
+ \expandafter\dodefineprocessseplist\expandafter{\currentlistseparator}\doprocessseparateditem
+ \directsetup{\currentseparatedlist:\executeifdefined{\??ls\currentseparatedlist\c!setups}\s!default}%
+ \initializeseparatedlistdata
+ \ifcase\separatedlistmode\appendseparatedlistparameter\c!before\fi
+ \dodostartseparatedlist}
+
+\def\redoprocessseparatedline#1%
+ {\def\!!stringa{#1}%
+ \ifx\!!stringa\separateslistend
+ \ifcase\separatedlistmode\appendseparatedlistparameter\c!after\fi
+ \expandafter\flushseparatedlistdata
+ \else%
+ \appendseparatedlistparameter{\ifcase\separatedlistmode\c!first\else\c!command\fi}%
+ \ifx\currentlistquotechar\empty%
+ \doprocessseplist#1\relax
+ \else%
+ \defconvertedargument\csvdata{#1}%
+ \expanded{\processquotedlist{}{\noexpand\end}%
+ {\currentlistseparator}{\currentlistquotechar}%
+ \noexpand\doprocessseparatedquoteditem \csvdata\currentlistseparator\noexpand\end}%
+ \fi
+ \ifcase\separatedlistmode\appendseparatedlistparameter\c!last\fi
+ \expandafter\dodoprocessseparatedline
+ \fi}
+
+\def\doprocessseparatedline
+ {\doifnextbgroupelse\xdoprocessseparatedline\ydoprocessseparatedline}
+
+\def\dodoprocessseparatedline
+ {\doprocessseparatedline}
+
+\def\doprocessseparateditem#1%
+ {\ifcase\separatedlistmode
+ \appendseparatedlistparameter\c!left
+ \appendseparatedlistcontent{#1}%
+ \appendseparatedlistparameter\c!right
+ \else
+ \appendseparatedlistcontent{{#1}}%
+ \fi}
+
+
+\bgroup \obeylines
+
+ \gdef\dodostartseparatedlist#1
+ {\doprocessseparatedline}
+
+ \gdef\xdoprocessseparatedline#1#2
+ {\redoprocessseparatedline{{{#1}}#2}}
+
+ \gdef\ydoprocessseparatedline#1
+ {\redoprocessseparatedline{#1}}
+
+\egroup
+
+\startsetups CSV:unix
+ \catcode`\#=\@@comment
+\stopsetups
+
+\def\defineseparatedlist
+ {\dodoubleempty\dodefineseparatedlist}
+
+\def\dodefineseparatedlist[#1][#2]%
+ {\setvalue{\e!start#1}{\expandafter\dostartseparatedlist\csname\e!stop#1\endcsname[#1]}%
+ \getparameters
+ [\??ls#1]
+ [\c!separator=,
+ \c!quotechar=,
+ \c!first=,
+ \c!left=,
+ \c!before=,
+ \c!right=,
+ \c!last=,
+ \c!after=,
+% \c!command=,
+ #2]}
+
+\def\setupseparatedlist
+ {\dodoubleempty\dosetupseparatedlist}
+
+\def\dosetupseparatedlist[#1]% [#2]
+ {\getparameter[\??ls#1]} % [#2]
+
+\def\startseparatedlist[#1]%
+ {\dostartseparatedlist\stopseparatedlist[#1]}
+
+\def\processseparatedfile
+ {\dodoubleargument\doprocessseparatedfile}
+
+\protect \doifnotmode{demo}{\endinput}
+
+\defineseparatedlist
+ [CSV]
+ [separator={,},
+ first=\bTR,last=\eTR,
+ left=\bTD,right=\eTD,
+ before=\bTABLE,after=\eTABLE]
+
+\startseparatedlist[CSV]
+a,b,c
+d,e,f
+\stopseparatedlist
+
+\startCSV
+a,b,c
+d,e,f
+\stopCSV
+
+\defineseparatedlist
+ [CSV]
+ [separator={,},
+ quotechar={"},
+ first=\NC,last=\NR,
+ left=,right=\NC,
+ before={\starttabulate[|l|l|l|]},after=\stoptabulate]
+
+\startCSV
+a,b,"c,d"
+d,"""",f
+\stopCSV
+
+\defineseparatedlist
+ [CSV]
+ [separator={ },
+ first=\NC,last=\NR,
+ left=,right=\NC,
+ before={\starttabulate[|l|l|l|]},after=\stoptabulate]
+
+\startCSV
+a b c
+d e f
+\stopCSV
+
+\defineseparatedlist
+ [CSV]
+ [setups=unix,
+ first=\NC,last=\NR,
+ left=,right=\NC,
+ before={\starttabulate[|l|l|l|]},after=\stoptabulate]
+
+% \startsetups CSV:unix
+% \catcode`\#=\@@comment
+% \stopsetups
+
+% %1,2,3
+% 1,2,3
+% # 4,5,6
+% 4,5,6
+
+\processseparatedfile[CSV][test.dat]
+
+\defineseparatedlist
+ [CSVX]
+ [command=\Whatever,
+ separator={,},
+ first=\bTR,last=\eTR,
+ left=\bTD,right=\eTD,
+ before=\bTABLE,after=\eTABLE]
+
+\def\Whatever#1#2#3{[#1][#2][#3]\endgraf}
+
+\startseparatedlist[CSVX]
+a,b,c
+d,e,f
+\stopseparatedlist
+
+\defineseparatedlist[CSV]
+ [separator=comma,
+ before=\bTABLE, after=\eTABLE,
+ first=\bTR, last=\eTR,
+ left=\bTD, right=\eTD]
+
+\startCSV
+a,b,c,č
+d,e,f,š
+\stopCSV
+
+\enableregime[utf]
+
+\defineseparatedlist[X][separator=X,left=(,right=),first=\endgraf,last=\endgraf]
+\defineseparatedlist[Y][separator=Y,left=(,right=),first=\endgraf,last=\endgraf]
+
+\startX
+aXb
+Xc
+čXš
+\stopX
+
+\startY
+aYb
+Yc
+čYš
+\stopY
+
+\stoptext
diff --git a/tex/context/base/m-datastrc.tex b/tex/context/base/m-datastrc.tex
new file mode 100644
index 000000000..4a6faa66b
--- /dev/null
+++ b/tex/context/base/m-datastrc.tex
@@ -0,0 +1,228 @@
+%D \module
+%D [ file=m-datastrc, % was: core-dat % was core-02a
+%D version=1999.08.10, % 1997.03.31,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Database Support, % 2A
+%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 Core Macros / Database Support}
+
+\unprotect
+
+%D This module is a (limited) rewrite of the original \type
+%D {core-02a} module, the module that dealt with managing a
+%D database of addresses. The principles and methods have not
+%D changed; they are only generalized.
+%D
+%D A database file |<|in most cases such a base is generated
+%D from another one|>| is structured as follows:
+%D
+%D \starttyping
+%D \startrecord{tag}
+%D \memberofgroup{grouplist}
+%D \setrecordentry{name}{...}
+%D ....
+%D \stoprecord
+%D \stoptyping
+%D
+%D The interface to such a database is defined as follows:
+%D
+%D \starttyping
+%D \definerecord[class][settings]
+%D \setuprecord[class][settings]
+%D \definerecordentry[class][name]
+%D \stoptyping
+%D
+%D and processed by
+%D
+%D \starttyping
+%D \processrecords[file list][tag and/or group list]
+%D \stoptyping
+%D
+%D The actual processing is done by a macro assigned to \type
+%D {command}:
+%D
+%D \starttyping
+%D \setuprecord[class][command=\DoWithRecord]
+%D \stoptyping
+%D
+%D Given that one can ask for a field with
+%D
+%D \starttyping
+%D \getrecordentry{name}
+%D \stoptyping
+%D
+%D such a command can look like:
+%D
+%D \starttyping
+%D \def\DoWithRecord#1%
+%D {\startpacked
+%D \let\\=\quad
+%D name: \getrecordentry{name}~\getrecordentry{family name}\par
+%D address: \getrecordentry{postal address}\par
+%D \stoppacked}
+%D \stoptyping
+%D
+%D The argument passed is the tag. The database can look like:
+%D
+%D \starttyping
+%D \startrecord{hagenj}
+%D \memberofgroup{a,b}
+%D \setrecordentry{naam}{Hans}
+%D \setrecordentry{family name}{Hagen}
+%D \setrecordentry{postal address}{J. Hagen\\Ridderstraat 29\\Hasselt NL}
+%D \stoprecord
+%D
+%D \startrecord{ottenaf}
+%D \memberofgroup{a}
+%D \setrecordentry{name}{Ton}
+%D \setrecordentry{family name}{Otten}
+%D \setrecordentry{postal address}{A.F. Otten\\Prinsengracht 17\\Hasselt NL}
+%D \stoprecord
+%D \stoptyping
+%D
+%D The definition of this database looks like:
+%D
+%D \starttyping
+%D \definerecord[address][command=\DoWithRecord]
+%D
+%D \definerecordentry[address][name]
+%D \definerecordentry[address][family name]
+%D \definerecordentry[address][postal address]
+%D \stoptyping
+%D
+%D The actual processing is now done by (for instance):
+%D
+%D \starttyping
+%D \processrecords[datafile][hagenj]
+%D \processrecords[datafile][hagenj,offenaf]
+%D \processrecords[datafile][all]
+%D \processrecords[datafile][a]
+%D \processrecords[datafile][b]
+%D \stoptyping
+%D
+%D Of course one can reassign the command used to handle the
+%D records in between.
+
+% \??kt ->
+% \??kw ->
+
+\def\??db {@@db}
+\def\c!velden{velden}
+
+%\newevery \everyrecord \EveryRecord
+
+\def\definerecord
+ {\dodoubleempty\dodefinerecord}
+
+\def\dodefinerecord[#1][#2]%
+ {\getparameters
+ [\??db#1]
+ [\c!velden=,
+ \c!command=\gobbleoneargument,
+ #2]}
+
+\def\setuprecord
+ {\dodoubleargument\dosetuprecord}
+
+\def\dosetuprecord[#1][#2]%
+ {\getparameters[\??db#1][#2]}%
+
+\def\definerecordentry[#1][#2]%
+ {\edef\recordentries{\getvalue{\??db#1\c!velden}}%
+ \addtocommalist{#2}\recordentries
+ \letvalue{\??db#1\c!velden}\recordentries}
+
+%D Watch out: the entries are defined global! While
+%D processing a record, no grouping is applied.
+
+\def\getrecordentry #1{\getvalue {\??db:#1}}
+\def\resetrecordentry #1{\letgvalueempty{\??db:#1}}
+\def\assignrecordentry#1{\setgvalue {\??db:#1}}
+
+\long\def\skiprecord#1\stoprecord
+ {\egroup}
+
+\newif\ifrecordok
+
+\newtoks\resetrecordlist
+
+\def\processrecords
+ {\dotripleargument\doprocessrecords}
+
+\def\doprocessrecords[#1][#2][#3]%
+ {\bgroup
+ \ifx\\\undefined\let\\\relax\fi
+ \def\docommand##1%
+ {\resetrecordentry{##1}%
+ \appendtoks\resetrecordentry{##1}\to\resetrecordlist}%
+ \processcommacommand[\getvalue{\??db#1\c!velden}]\docommand
+ \let\setrecordentry\skiprecord
+ \the\resetrecordlist
+ \doifelse{#2}\v!all % 't Is nu eenmaal alles
+ \recordoktrue
+ {\doifelsenothing{#2} % of niets
+ \recordoktrue
+ \recordokfalse}% % zullen we maar zeggen.
+ \ifrecordok
+ \let\askedrecords\v!all
+ \else
+ \makerawcommalist[#2]\askedrecords
+ \fi
+ \def\checkrecord##1%
+ {\rawdoifinsetelse{##1}{\askedrecords}{\recordoktrue}{}}%
+ \def\presetrecord##1%
+ {\let\setrecordentry\assignrecordentry
+ \let\memberofgroup\gobbleoneargument
+ \the\resetrecordlist
+ \def\stoprecord{\dostoprecord{##1}}}%
+ \def\memberofgroup##1%
+ {\doifsomething{##1}
+ {\rawprocesscommalist[##1]\checkrecord}%
+ \ifrecordok
+ \presetrecord{##1}%
+ \else
+ \expandafter\skiprecord
+ \fi}%
+ \def\startrecord##1%
+ {\bgroup
+ \ifrecordok
+ \presetrecord{##1}%
+ \else
+ \checkrecord{##1}%
+ \ifrecordok
+ \presetrecord{##1}%
+ \fi
+ \fi}%
+ \def\dostoprecord##1%
+ {\relax
+ \egroup
+ %\the\everyrecord
+ \getvalue{\??db#1\c!command}{##1}}%
+ \showmessage\m!databases1\askedrecords
+ \def\doprocessrecords##1%
+ {\readjobfile{##1}
+ {\showmessage\m!databases2{(job)}}
+ {\readsysfile{##1}
+ {\showmessage\m!databases3{(sys)}}
+ {\showmessage\m!databases4{}}}}%
+ \processcommalist[#3]\doprocessrecords
+ \egroup}
+
+%D While writing the original implementation, I did some
+%D experiments with \type {%} before each entry and changing
+%D the category code of the comment char. Because \TEX\ scans
+%D the line anyway |<|this is needed because the end of line
+%D character can be non standard|>| this is not faster.
+%D
+%D Although this mechanism could have been combined with the
+%D block moving mechanism, the current implementation is
+%D prefered out of speed reasons.
+
+\protect \endinput
diff --git a/tex/context/base/m-directives.tex b/tex/context/base/m-directives.tex
new file mode 100644
index 000000000..c958f6cad
--- /dev/null
+++ b/tex/context/base/m-directives.tex
@@ -0,0 +1,5 @@
+\doifnotmode{mkiv} {\endinput}
+
+\starttext
+ \showdirectives
+\stoptext
diff --git a/tex/context/base/m-dratex.tex b/tex/context/base/m-dratex.tex
new file mode 100644
index 000000000..6c088daf9
--- /dev/null
+++ b/tex/context/base/m-dratex.tex
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=m-dratex,
+%D version=2005.11.25,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\DRATEX\ Loading Macros,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details
+
+\readfile{DraTex.sty}{}{\readfile{dratex.sty}{}{\endinput}}
+
+\letvalue{:NewCount}\newcount
+\letvalue{:NewDimen}\newdimen
+
+\readfile{AlDraTex.sty}{}{\readfile{aldratex.sty}{}{\endinput}}
+
+\endinput
diff --git a/tex/context/base/m-edtsnc.tex b/tex/context/base/m-edtsnc.tex
new file mode 100644
index 000000000..0926f4488
--- /dev/null
+++ b/tex/context/base/m-edtsnc.tex
@@ -0,0 +1,207 @@
+%D \module
+%D [ file=m-editsnc,
+%D version=2003.12.23,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Editor Synchronization,
+%D author={Hans Hagen \& Ton Otten},
+%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.edit for
+%C details.
+
+% \enablemode[demo]
+
+% This file is a variation of the file m-pdfsync. This time we do it
+% in a more abstract way and prepare ourselves for support in dvi
+% output.
+
+% \enableeditsync
+% \disableeditsync
+% \editsync
+% \editsynctext {string}
+% \editsyncnode {char}
+% \editsynctracemode [chardef: 0-4]
+
+\writestatus{editsync}{loading and enabling editor synchronization support}
+
+\unprotect % not really needed
+
+\ifx\pdfoutput\undefined
+ \donefalse
+\else\ifcase\pdfoutput
+ \donefalse
+\else\ifx\pdfsavepos\undefined
+ \donefalse
+\else
+ \donetrue
+\fi\fi\fi
+
+\chardef \editsyncstate \zerocount
+\chardef \editsynctracemode \zerocount
+\newcount \editsynccounter
+\newwrite \editsyncwrite
+
+\def\enableeditsync {\chardef\editsyncstate\plusone}
+\def\disableeditsync{\chardef\editsyncstate\zerocount}
+
+% The following definitions can go into the special drivers, but
+% for the moment we do it this way.
+
+\ifdone
+
+ \def\dostarteditsync
+ {\immediate\openout\editsyncwrite\jobname.pdfsync
+ \immediate\write\editsyncwrite{\jobname}%
+ \immediate\write\editsyncwrite{version 0}}
+
+ \def\dostopeditsync
+ {\closeout\editsyncwrite}
+
+ \def\doeditsyncregisterpage#1{\immediate\write\editsyncwrite{s\space\number#1}}
+ \def\doeditsyncopenfile #1{\immediate\write\editsyncwrite{(\space#1}}
+ \def\doeditsyncclosefile #1{\immediate\write\editsyncwrite{)}}
+
+ \def\doregistereditsyncnode#1#2#3% tag counter linenumber
+ {\pdfsavepos
+ \immediate\write\editsyncwrite{l\space\number#2\space\number#3}%
+ \expanded{\write\editsyncwrite{p\ifnum#1=\plusone*\fi\space\number#2\space\noexpand\the\pdflastxpos\space\noexpand\the\pdflastypos}}}
+
+\else
+
+ \let\dostarteditsync \relax
+ \let\dostopeditsync \relax
+
+ \let\doeditsyncregisterpage\gobbleoneargument
+ \let\doeditsyncopenfile \gobbleoneargument
+ \let\doeditsyncclosefile \gobbleoneargument
+ \let\doregistereditsyncnode\gobblethreearguments
+
+ % These specials could be filtered by a dvitopdf backend and
+ % written to a jobname.pdfsync file. In that case, the x and
+ % y coordinates have to be to be resolved by driver.
+
+ % \def\doeditsyncregisterpage#1{\special{pdfsync: s\space\number#1}}
+ % \def\doeditsyncopenfile #1{\special{pdfsync: ( #1}}
+ % \def\doeditsyncclosefile #1{\special{pdfsync: )}}
+
+ % \def\doregistereditsyncnode#1#2#3%
+ % {\special{pdfsync: l the\editsynccounter\space\number#3}%
+ % \special{pdfsync: p\ifnum#1=\plusone*\fi\space\number#2}}
+
+\fi
+
+\let\editsynctracer\gobbleoneargument
+
+\editsynccounter\minusone % counting starts at zero and we increment beforehand
+
+\def\registereditsyncnode#1% we assume #1 is one token
+ {\ifcase\editsyncstate
+ \expandafter\gobbleoneargument
+ \else
+ \global\advance\editsynccounter\plusone
+ \doregistereditsyncnode#1\editsynccounter\inputlineno
+ \expandafter\editsynctracer
+ \fi}
+
+\def\editsync {\registereditsyncnode\plusone *}
+\def\editsyncnode{\registereditsyncnode\zerocount}
+\def\editsynctext{\registereditsyncnode\plusone }
+
+\appendtoks \dostarteditsync \to \everystarttext
+%appendtoks \dostopeditsync \to \everystoptext
+\appendtoks \doeditsyncregisterpage\realfolio \to \everyshipout
+\appendtoks \doeditsyncopenfile\readfilename \to \everybeforereadfile
+\appendtoks \doeditsyncclosefile\readfilename \to \everyafterreadfile
+
+\appendtoks \enableeditsync \to \everystarttext
+\appendtoks \disableeditsync \to \everypagebody
+
+\def\editsynctracer#1%
+ {\ifcase\editsynctracemode\else
+ \begingroup
+ \forgetall
+ \disableeditsync
+ \ifcase\editsynctracemode\or % could be done more efficient, box around ifcase
+ \setbox\scratchbox\hbox to \zeropoint{\hss\infofont#1\hss}% 1
+ \else
+ \setbox\scratchbox\hbox to \zeropoint{\hss\traceboxplacementtrue\boxcursor\hss}% 2/3/4
+ \fi
+ \smashbox\scratchbox\box\scratchbox
+ \ifcase\editsynctracemode\or\or\or
+ \setbox\scratchbox\hbox to \zeropoint{\hss\raise1.25ex\hbox{\infofont#1}\hss}% 3
+ \smashbox\scratchbox\box\scratchbox
+ \or
+ \setbox\scratchbox\hbox to \zeropoint{\hss\lower1.25ex\hbox{\infofont#1}\hss}% 4
+ \smashbox\scratchbox\box\scratchbox
+ \fi
+ \endgroup
+ \fi}
+
+% \def\editsynctracer#1% more efficient but unreadable
+% {\ifcase\editsynctracemode\else
+% \ifcase\editsyncstate\else
+% \begingroup
+% \forgetall
+% \disableeditsync
+% \setbox\scratchbox\hbox to \zeropoint
+% {\hss
+% \ifcase\editsynctracemode\or
+% \infofont#1% 1
+% \else
+% \traceboxplacementtrue\boxcursor% 2/3/4
+% \fi
+% \hss}%
+% \smashbox\scratchbox\box\scratchbox
+% \setbox\scratchbox\hbox to \zeropoint
+% {\hss
+% \ifcase\editsynctracemode\or\or\or
+% \raise1.25ex\hbox{\infofont#1}% 3
+% \or
+% \lower1.25ex\hbox{\infofont#1}% 4
+% \fi
+% \hss}%
+% \smashbox\scratchbox\box\scratchbox
+% \endgroup
+% \fi
+% \fi}
+
+% beware, adding nodes this way will interfere with the typesetting
+
+\appendtoks \editsyncnode p\to \everypar
+\appendtoks \editsyncnode m\to \everymath
+\appendtoks \editsyncnode d\to \everydisplay
+\appendtoks \editsyncnode h\to \everyhbox
+
+% For compatibility with 'pdfsync4context' we provide:
+
+\let\pdfsyncstart\enableeditsync
+\let\pdfsyncstop \disablepdfsync
+\let\pdfsync \editsync
+
+\protect
+
+\doifnotmode{demo}{\endinput}
+
+\chardef\editsynctracemode=3
+
+\starttext
+
+\chapter{Test}
+
+\processfile{tufte}
+
+\startitemize
+\item first
+\item second
+\stopitemize
+
+\processfile{tufte}
+
+\startlines
+some local \editsync sync and \editsynctext{here}a marked point
+some local \editsync sync and \editsyncnode{here}a marked point
+\stoplines
+
+\stoptext
diff --git a/tex/context/base/m-educat.tex b/tex/context/base/m-educat.tex
new file mode 100644
index 000000000..ddfb72ff4
--- /dev/null
+++ b/tex/context/base/m-educat.tex
@@ -0,0 +1,217 @@
+%D \module
+%D [ file=m-educat,
+%D version=2003.03.05,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Educational Extras,
+%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.
+
+%D This module will collect a few macros cq.\ definitions
+%D meant for educational use. Most of the code has been laying
+%D around for some time and has been (or is still) used in
+%D \PRAGMA\ projects.
+
+\unprotect
+
+\definesystemvariable{iv}
+
+\definecolor [answerareacolor] [s=.90]
+\definecolor [answerlinecolor] [white]
+
+\definetextbackground
+ [\v!answerarea]
+ [\c!location=\v!text,
+ \c!n=0,
+ \c!frame=\v!off,
+ \c!framecolor=answerlinecolor,
+ \c!rulethickness=2pt,
+ \c!background=\v!color,
+ \c!backgroundcolor=answerareacolor,
+ \c!alternative=2] % betweenline
+
+% n=gedwongen
+% m=extra auto
+
+\def\setupanswerarea
+ {\setuptextbackground[\v!answerarea]}
+
+\setvalue\e!answerspace
+ {\dosingleempty\doanswerspace}
+
+\def\doanswerspace[#1]%
+ {\begingroup
+ \dontcomplain
+ \setupanswerarea
+ [\c!n=0,\c!m=,#1,\c!location=\v!text]%
+ \doifelsenothing{\backgroundvariable\c!m}
+ {\expandafter\donoanswerspace}
+ {\expandafter\dodoanswerspace}%
+ [#1]}
+
+\def\donoanswerspace[#1]#2%
+ {\setupthinrules
+ [\c!alternative=\backgroundvariable\c!alternative,
+ \c!color=\backgroundvariable\c!framecolor,
+ \c!background=\backgroundvariable\c!background,
+ \c!backgroundcolor=\backgroundvariable\c!backgroundcolor,
+ \c!rulethickness=\backgroundvariable\c!rulethickness]%
+ \doifelse{\backgroundvariable\c!n}{*}
+ {\thinrule
+ \par}
+ {\scratchcounter0\backgroundvariable\c!n\relax
+ % tricky, guess
+ \def\processisolatedword##1%
+ {\setbox\scratchbox=\hbox{##1}%
+ \vbox{\hsize\wd\scratchbox\thinrule
+ \ifcase\scratchcounter\else
+ \setbox\scratchbox=\hbox{\space}%
+ \nobreak\hskip\zeropoint \!!minus \wd\scratchbox
+ \vbox{\hsize\wd\scratchbox\thinrule}%
+ \fi}}%
+ \processisolatedwords{#2}\processisolatedword
+ % so far
+ \ifcase\scratchcounter \else \ifnum\scratchcounter<3
+ \nobreak \vbox{\hsize\scratchcounter em\thinrule}%
+ \else % more
+ \advance \scratchcounter -2
+ \dorecurse\scratchcounter{\allowbreak\vbox{\hsize1em\thinrule}}%
+ \nobreak \vbox{\hsize2em\thinrule}%
+ \fi \fi}%
+ \endgroup}
+
+\def\dodoanswerspace[#1]#2% m case
+ {\getvalue{\e!start\v!answerarea}%
+ #2%
+ \doifelse{\backgroundvariable\c!m}{*}
+ {\hfill\strut
+ \getvalue{\e!stop\v!answerarea}%
+ \par}
+ {\scratchcounter0\backgroundvariable\c!m\relax
+ \ifcase\scratchcounter \else \ifnum\scratchcounter<3
+ \nobreak \hbox to \scratchcounter em{\strut\hss}%
+ \else % more
+ \advance \scratchcounter -2
+ \dorecurse\scratchcounter{\allowbreak\hbox to 1em{\strut\hss}}%
+ \nobreak \hbox to 2em{\strut\hss}%
+ \fi \fi
+ \getvalue{\e!stop\v!answerarea}}%
+ \endgroup}
+
+\setvalue{\e!start\e!answerlines}%
+ {\dosingleempty\dostartanswerlines}
+
+\def\dostartanswerlines[#1]%
+ {\begingroup
+ \dontcomplain
+ \setupanswerarea
+ [\c!n=0,\c!m=,#1,\c!location=\v!text]%
+ \doifnot{\backgroundvariable\c!option}\v!joinedup\softbreak
+ \doifelsenothing{\backgroundvariable\c!m}
+ {\expandafter\donostartanswerlines}
+ {\expandafter\dodostartanswerlines}%
+ [#1]}
+
+\def\donostartanswerlines[#1]%
+ {\setupthinrules
+ [\c!alternative=\backgroundvariable\c!alternative,
+ \c!color=\backgroundvariable\c!framecolor,
+ \c!background=\backgroundvariable\c!background,
+ \c!backgroundcolor=\backgroundvariable\c!backgroundcolor,
+ \c!rulethickness=\backgroundvariable\c!rulethickness]%
+ \thinrules[\c!n=\backgroundvariable\c!n]\par
+ \endgroup
+ \grabuntil{\e!stop\e!answerlines}}
+
+\def\dodostartanswerlines[#1]%
+ {\begingroup
+ \getvalue{\e!start\v!answerarea}%
+ \ignorespaces}
+
+\setvalue{\e!stop\e!answerlines}%
+ {\scratchcounter0\backgroundvariable\c!m\relax
+ % a \softbreak is more efficient in pos dan \par
+ \ifcase\scratchcounter
+ % nothing
+ \or
+ \softbreak
+ \else
+ \softbreak
+ \advance \scratchcounter \minusone
+ \dorecurse\scratchcounter{\strut\hfill\strut\softbreak}%
+ \fi
+ \strut\hfill\strut
+ \getvalue{\e!stop\v!answerarea}%
+ \par\endgroup\endgroup}
+
+\setvalue\e!answerlines
+ {\dosingleempty\doanswerlines}
+
+\def\doanswerlines[#1]#2%
+ {\getvalue{\e!start\e!answerlines}[#1]%
+ #2%
+ \getvalue{\e!stop\e!answerlines}}
+
+\protect \doifnotmode{demo}{\endinput}
+
+%D Test materiaal.
+
+\starttext
+
+\startnotmode[answers]
+
+ \setupanswerarea[level=+1]
+
+\stopnotmode
+
+\setupcolors[state=start]
+
+test test test \answerspace [n=10] {Whow}. test test test
+test tets test test \answerspace [n=10] {Whow}. test test
+test test tets test test \answerspace [n=10] {Whow}. test
+test test test tets test test \answerspace [n=10] {Whow}.
+test test test test test test \answerspace [n=*] {Whow.}
+
+test test test test test test test \startanswerlines
+[n=3] What A Junk Answer \stopanswerlines
+
+test test test test test test test \startanswerlines
+[n=3,alternative=0] What A Junk Answer \stopanswerlines
+
+test test test test test test test \startanswerlines
+[n=3,alternative=1] What A Junk Answer \stopanswerlines
+
+test test test test test test test \startanswerlines
+[n=3,alternative=2] What A Junk Answer \stopanswerlines
+
+\startitemize[paragraph]
+\item \startanswerlines [option=seried,n=2] xxx \stopanswerlines
+\stopitemize
+
+test test test \answerspace [m=10] {Whow}. test test test
+test tets test test \answerspace [m=10] {Whow}. test test
+test test tets test test \answerspace [m=10] {Whow}. test
+test test test tets test test \answerspace [m=10] {Whow}.
+test test test test test test \answerspace [m=*] {Whow.}
+
+test test test test test test test \startanswerlines
+[m=2] What A Junk Answer \stopanswerlines
+
+test test test test test test test \startanswerlines
+[m=2,alternative=0] What A Junk Answer \stopanswerlines
+
+test test test test test test test \startanswerlines
+[m=2,alternative=1] What A Junk Answer \stopanswerlines
+
+test test test test test test test \startanswerlines
+[m=2,alternative=2] What A Junk Answer \stopanswerlines
+
+\startitemize[paragraph]
+\item \startanswerlines [option=seried,m=2] xxx \stopanswerlines
+\stopitemize
+
+\stoptext
diff --git a/tex/context/base/m-format.tex b/tex/context/base/m-format.tex
new file mode 100644
index 000000000..0f274b236
--- /dev/null
+++ b/tex/context/base/m-format.tex
@@ -0,0 +1,409 @@
+%D \module
+%D [ file=m-formay,
+%D version=ancient,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Ancient Formatting Code,
+%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.
+
+%D Here is some code that I had laying around and had forgotten
+%D about. Let's make it a module and see if there is interest in
+%D such things.
+
+% \defineformatblock [poem]
+% \defineformatsegment [verse] % [poem]
+% \defineformatline [line] % [verse]
+%
+% \startpoem [title] [author]
+% \startverse [ref]
+% \startline [ref]
+%
+% block : voor na tussen *tekstletter *tekstkleur
+%
+% segment : voor na tussen *tekstletter *tekstkleur
+% : links rechts linkeroffset rechteroffset
+% : ?marge *evenmarge *onevenmarge breedte
+% : nummer *nummercommando *conversie
+% : nummerletter nummerkleur *label
+%
+% line : voor na tussen *tekstletter *tekstkleur
+% : nummer *nummercommando *conversie
+% : nummerletter nummerkleur *label
+%
+% * = todo
+
+\unprotect
+
+\definesystemvariable {fx} % format block
+\definesystemvariable {fy} % format segment
+\definesystemvariable {fz} % format line
+
+\def\defineformatblock
+ {\dodoubleempty\dodefineformatblock}
+
+\def\dodefineformatblock[#1][#2]%
+ {\setupformatblock
+ [#1]
+ [\c!before=\blank,\c!after=\blank,\c!inbetween=\blank,
+ \c!textstyle=,\c!textcolor=,#2]%
+ \setvalue{\e!start#1}{\startformatblock[#1]}%
+ \setvalue{\e!stop #1}{\stopformatblock}}
+
+\def\setupformatblock
+ {\dodoubleempty\dosetupformatblock}
+
+\def\setupformatblock[#1]%
+ {\getparameters[\??fx#1]}
+
+\def\startformatblock[#1]%
+ {\dotriplegroupempty\dostartformatblock{#1}}
+
+\def\dostartformatblock#1#2#3
+ {\bgroup
+ \getvalue{\??fx#1\c!before}
+ \doglobal\newcounter\formatsegmentcounter
+ \doglobal\newcounter\formatlinecounter
+ \doglobal\newcounter\formatlinesubcounter
+ \doglobal\newcounter\formatlinemaxcounter
+ \doifsomething{#2}{\leftaligned{#2}\getvalue{\??fx#1\c!inbetween}}
+ \def\stopformatblock%
+ {\doifsomething{#3}{\getvalue{\??fx#1\c!inbetween}\leftaligned{#3}}
+ \getvalue{\??fx#1\c!after}
+ \egroup}}
+
+\def\defineformatsegment
+ {\dodoubleempty\dodefineformatsegment}
+
+\def\dodefineformatsegment[#1][#2]%
+ {\setupformatsegment
+ [#1]
+ [\c!before=\blank,\c!after=\blank,\c!inbetween=\blank,
+ \c!textstyle=,\c!textcolor=,\c!left=,\c!right=,
+ \c!leftoffset=\!!zeropoint,\c!rightoffset=\!!zeropoint,
+ %\c!margin=\!!zeropoint,\c!evenmargin=\!!zeropoint,\c!oddmargin=\hsize,
+ \c!width=\hsize,\c!numberstyle=,\c!numbercolor=,\c!number=\v!no,
+ \c!numbercommand=,\c!conversion=,\c!label=,
+ #2]%
+ \setvalue{\e!start#1}{\startformatsegment[#1]}%
+ \setvalue{\e!stop #1}{\stopformatsegment}}
+
+\def\setupformatsegment
+ {\dodoubleempty\dosetupformatsegment}
+
+\def\setupformatsegment[#1]%
+ {\getparameters[\??fy#1]}
+
+\def\placeformatsegmentcounter
+ {\formatsegmentcounter\quad\hphantom{\placeformatlinecounter}}
+
+\def\placeformatlinecounter
+ {\formatlinecounter}
+
+\def\startformatsegment[#1]%
+ {\bgroup
+ \doifelsevalue{\??fy#1\c!number}\v!yes
+ {\def\doplaceformatsegmentcounter
+ {\inleftmargin
+ {\doattributes{\??fy#1}\c!numberstyle\c!numbercolor
+ {\placeformatsegmentcounter}}}}
+ {\let\doplaceformatsegmentcounter\relax}%
+ \getvalue{\??fy#1\c!before}
+ \doglobal\increment\formatsegmentcounter
+ \def\formatrightoffset{\getvalue{\??fy#1\c!rightoffset}}
+ \def\formatleftoffset {\getvalue{\??fy#1\c!leftoffset}}
+ \def\formatminwidth {\getvalue{\??fy#1\c!minwidth}}
+ \def\formatwidth {\getvalue{\??fy#1\c!width}}
+ %\def\formatmargin {\getvalue{\??fy#1\c!margin}}
+ \def\formatbefore {\getvalue{\??fy#1\c!before}}
+ \def\formatinbetween {\getvalue{\??fy#1\c!inbetween}}
+ \def\formatafter {\getvalue{\??fy#1\c!after}}
+ \def\formatleft {\getvalue{\??fy#1\c!left}}
+ \def\formatright {\getvalue{\??fy#1\c!right}}
+ \@@segmentvarianta
+ \getvalue{@@segmentvariant\getvalue{\??fy#1\c!alternative}}
+ \def\stopformatsegment
+ {\getvalue{\??fy#1\c!after}
+ \egroup}}
+
+\newif\iftraceformatblock
+
+\def\@@segmentvarianta % ragged right, symbols
+ {\let\formatraggedness\raggedright
+ \let\dostartformatline\dostartformatlineab
+ \let\formatleftfirst\relax \let\formatrightfirst\hfill
+ \let\formatleftnext \hfill \let\formatrightnext \relax}
+
+\def\@@segmentvariantb % ragged right, equal parts, symbols
+ {\let\formatraggedness\raggedcenter
+ \let\dostartformatline\dostartformatlineab
+ \let\formatleftfirst\relax \let\formatrightfirst\hfill
+ \let\formatleftnext \hfill \let\formatrightnext \relax}
+
+\def\@@segmentvariantc % ragged right
+ {\let\formatraggedness\veryraggedright
+ \let\dostartformatline\dostartformatlinecde
+ \let\formatleftnext\relax \let\formatrightnext\hfill}
+
+\def\@@segmentvariantd % ragged center
+ {\let\formatraggedness\veryraggedcenter
+ \let\dostartformatline\dostartformatlinecde
+ \let\formatleftnext\hfill \let\formatrightnext\hfill}
+
+\def\@@segmentvariante % ragged left
+ {\let\formatraggedness\veryraggedleft
+ \let\dostartformatline\dostartformatlinecde
+ \let\formatleftnext\hfill \let\formatrightnext\relax}
+
+\def\defineformatline
+ {\dodoubleempty\dodefineformatline}
+
+\def\dodefineformatline[#1][#2]%
+ {\setupformatline
+ [#1]
+ [\c!before=\blank,\c!after=\blank,\c!inbetween=\blank,
+ \c!textstyle=,\c!textcolor=,
+ \c!number=\v!no,\c!numbercommand=,\c!conversion=,
+ \c!numberstyle=,\c!numbercolor=,\c!label=,
+ #2]%
+ \setvalue{\e!start#1}{\startformatline[#1]}%
+ \setvalue{\e!stop #1}{\stopformatline}}
+
+\def\setupformatline
+ {\dodoubleempty\dosetupformatline}
+
+\def\setupformatline[#1]%
+ {\getparameters[\??fz#1]}
+
+\newconditional\formatforcedbreak
+
+\def\startformatline[#1]%
+ {\bgroup
+ \doifelsevalue{\??fz#1\c!number}\v!yes
+ {\def\doplaceformatlinecounter
+ {\inleftmargin
+ {\doattributes{\??fz#1}\c!numberstyle\c!numbercolor
+ {\placeformatlinecounter}}}}
+ {\let\doplaceformatlinecounter\relax}%
+ \global\setfalse\formatforcedbreak
+ \def\\{\break\global\settrue\formatforcedbreak}%
+ \hsize\formatwidth
+ \doglobal\increment\formatlinecounter
+ \par
+ \nobreak
+ \def\stopformatline
+ {\unskip\unskip\unskip\unskip\unskip\egroup
+ \let\doplaceformatsegmentcounter\relax}
+ \postponenotes
+ \dowithnextbox{\dostartformatline}\hbox\bgroup\ignorespaces}
+
+\def\dostartformatlineab
+ {%\dosetleftskipadaption\formatmargin
+ %\advance\hsize-\leftskipadaption\relax
+ \ifdim\nextboxwd>\hsize
+ \beginofshapebox
+ \forgetall
+ \hangafter\plusone
+ \hangindent\formatleftoffset
+ \formatraggedness
+ \hskip\formatrightoffset
+ \unhbox\nextbox\par
+ \endofshapebox
+ %\advance\hsize \leftskipadaption
+ \doglobal\newcounter\formatlinesubcounter
+ \reshapebox
+ {\doglobal\increment\formatlinesubcounter}
+ \global\let\formatlinemaxcounter\formatlinesubcounter
+ \reshapebox
+ {\doglobal\decrement\formatlinesubcounter
+ \ifnum\formatlinesubcounter=\zerocount
+ \doplaceformatsegmentcounter
+ \doplaceformatlinecounter
+ \hskip-\formatrightoffset
+ %\hskip\leftskipadaption
+ \formatleftfirst
+ \unhbox\shapebox
+ \ifnum\formatlinemaxcounter>\plusone
+ \ifx\formatright\empty\else
+ \shapedhbox to \zeropoint{\formatright\hss}%
+ \fi
+ \fi
+ \formatrightfirst
+ \iftraceformatblock
+ \ruledhskip\formatrightoffset\hskip-\formatrightoffset
+ \fi
+ \else
+ %\hskip\leftskipadaption
+ \iftraceformatblock
+ \ruledhskip\formatleftoffset\hskip-\formatleftoffset
+ \fi
+ \formatleftnext
+ \ifx\formatleft\empty\else
+ \shapedhbox to \zeropoint{\hss\formatleft}%
+ \fi
+ \unhbox\shapebox
+ \formatrightnext
+ \fi}
+ \flushshapebox
+ \else
+ \dontleavehmode\hbox
+ {\doplaceformatsegmentcounter
+ \doplaceformatlinecounter
+ %\hskip\leftskipadaption
+ \formatleftfirst
+ \unhbox\nextbox
+ \formatrightfirst}
+ \fi
+ \par
+ \egroup}
+
+\def\dostartformatlinecde
+ {%\dosetleftskipadaption\formatmargin
+ %\advance\hsize -\leftskipadaption\relax
+ \dimen0=\hsize
+ \ifconditional\formatforcedbreak\else
+ \ifdim\formatminwidth>\zeropoint\relax
+ \ifdim\nextboxwd>\hsize
+ \doloop
+ {\global\dimen1=\dimen0
+ \beginofshapebox
+ \hsize\dimen0
+ \forgetall
+ \formatraggedness
+ \unhcopy\nextbox\par
+ \endofshapebox
+ \reshapebox
+ {\setbox\scratchbox=\hbox{\unhbox\shapebox}%
+ \ifdim\wd\scratchbox<\dimen1
+ \global\dimen1=\wd\scratchbox
+ \fi}
+ \ifdim\dimen1<\formatminwidth\relax
+ \advance\dimen0 by -.25em
+ \else
+ \exitloop
+ \fi
+ \ifdim\dimen0<10em
+ \dimen0=\hsize
+ \exitloop
+ \fi}
+ \fi
+ \fi
+ \fi
+ \beginofshapebox
+ \hsize\dimen0
+ \forgetall
+ \formatraggedness
+ \unhcopy\nextbox\par
+ \endofshapebox
+ %\advance\hsize \leftskipadaption
+ \doglobal\newcounter\formatlinesubcounter
+ \reshapebox
+ {\doglobal\increment\formatlinesubcounter}%
+ \global\let\formatlinemaxcounter\formatlinesubcounter
+ \reshapebox
+ {\doglobal\decrement\formatlinesubcounter
+ \ifnum\formatlinesubcounter=\zerocount
+ \doplaceformatsegmentcounter
+ \doplaceformatlinecounter
+ \fi
+ %\hskip\leftskipadaption
+ \formatleftnext
+ \unhbox\shapebox
+ \formatrightnext\strut}% strut prevents unskip
+ \flushshapebox
+ \par
+ \egroup}
+
+\defineformatblock[poem]
+ [\c!before=\blank,
+ \c!inbetween={\blank[\v!medium]},
+ \c!after=\blank]
+
+\defineformatsegment[verse]
+ [\c!alternative=\v!left,
+ \c!width=\hsize,
+ %\c!margin=\!!zeropoint,
+ \c!before={\blank[\v!medium]},
+ \c!after={\blank[\v!medium]},
+ \c!inbetween={\blank[\v!medium]},
+ \c!leftoffset=3em,
+ \c!rightoffset=2em,
+ \c!minwidth=5em,
+ \c!left={$[$\enspace},
+ \c!right={\enspace$]$}]
+
+\defineformatline[line]
+ []
+
+\protect \doifnotmode{demo} {\endinput}
+
+% evt defineblank[formatbefore,formatinbetween,formatafter]
+
+%\showframe \traceformatblocktrue
+
+\usemodule[visual]
+
+\setuplayout[height=middle,topspace=1cm,header=0pt,footer=0pt]
+\setupbodyfont[10pt]
+
+% All interfaces supported, but testing with english; todo:
+% more options, more alternatives, inheritance and mixed
+% definitions, and so.
+
+\starttext
+
+\startbuffer
+\startbuffer[poem]
+\startpoem{A Random Poem}{Hans Hagen}
+ \startverse
+ \startline \fakewords{4}{8} \stopline
+ \startline \fakewords{4}{8} \stopline
+ \startline \fakewords{4}{8} \stopline
+ \startline \fakewords{4}{8} \stopline
+ \stopverse
+ \startverse
+ \startline \fakewords{4}{8} \stopline
+ \startline \fakewords{4}{8} \stopline
+ \startline \fakewords{4}{8} \stopline
+ \startline \fakewords{4}{8} \stopline
+ \stopverse
+\stoppoem
+\stopbuffer
+
+\setupformatsegment[verse][width=.4\hsize,number=yes,numberstyle=slanted]
+\setupformatline [line] [number=yes,numberstyle=smallslanted]
+
+\startbuffer[x]
+\setupformatsegment[verse][leftoffset=0pt,rightoffset=0pt,left=,right=]
+\stopbuffer
+
+\section{Alternative A}
+
+\setupformatsegment[verse][alternative=a] {\getbuffer[poem]}
+\setupformatsegment[verse][alternative=a] {\getbuffer[x,poem]}
+
+\section{Alternative B}
+
+\setupformatsegment[verse][alternative=b] {\getbuffer[poem]}
+\setupformatsegment[verse][alternative=b] {\getbuffer[x,poem]}
+
+\section{Alternative C}
+
+\setupformatsegment[verse][alternative=c] {\getbuffer[poem]}
+
+\section{Alternative D}
+
+\setupformatsegment[verse][alternative=d] {\getbuffer[poem]}
+
+\section{Alternative E}
+
+\setupformatsegment[verse][alternative=e] {\getbuffer[poem]}
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\stoptext
diff --git a/tex/context/base/m-graph.mkii b/tex/context/base/m-graph.mkii
new file mode 100644
index 000000000..db7538e98
--- /dev/null
+++ b/tex/context/base/m-graph.mkii
@@ -0,0 +1,72 @@
+%D \module
+%D [ file=m-graph,
+%D version=2000.08.06,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\METAPOST\ graph module 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.
+
+%D I finally finished graph support, if only because I could
+%D not stand the idea that Karel Wesseling would revert to
+%D \PiCTeX.
+
+% pre 2000.08.06 version
+%
+% \forceMPTEXgraphictrue
+%
+% \startMPinitializations
+% initialize_numbers ; % make sure that pseudo typesetting is set up
+% input graph ; % load the graph package
+% Autoform := "@g" ; % change the % template char into @
+% \stopMPinitializations
+
+%D The latest version does things more automatically (and
+%D efficiently when no text processing is needed). For
+%D definitions embedded in your document, you need to
+%D use \type {@} as template character, in external files,
+%D \type {%} is also supported.
+
+\startMPinclusions
+ input graph ;
+\stopMPinclusions
+
+%D Graphics that have \type {begingraph} in them are
+%D recognized as such and force handling of embedded \TEX\
+%D code.
+
+\forceMPTEXcheck{begingraph}
+
+%D If you run into troubles, try:
+%D
+%D \starttyping
+%D \forceMPTEXgraphictrue
+%D \stoptyping
+%D
+%D A demo can be run with:
+%D
+%D \starttyping
+%D texexec --mode=demo --pdf m-graph
+%D \stoptyping
+
+\startMPinclusions
+ % @# is X_ or Y_; $ is Gxcvlin_ or Gycvlin_; l and h are numeric or string
+ % It would not be OK to set (@#low,@#high) to a pair expression because $ might
+ % try to rescale @#low when evaluating the right-hand side for @#high.
+ vardef Gsetr_@\#(suffix $)(expr l, h) =
+ Gclbnds_@\# ;
+ if @\#ctyp>0 :
+ @\#low = if abs @\#ctyp<>log: $ fi Mlog_Str l ;
+ @\#high = if abs @\#ctyp<>log: $ fi Mlog_Str h ;
+ else :
+ -@\#high = if abs @\#ctyp<>log: $ fi Mlog_Str l ;
+ -@\#low = if abs @\#ctyp<>log: $ fi Mlog_Str h ;
+ fi
+ enddef ;
+\stopMPinclusions
+
+\endinput
diff --git a/tex/context/base/m-graph.mkiv b/tex/context/base/m-graph.mkiv
new file mode 100644
index 000000000..c92234884
--- /dev/null
+++ b/tex/context/base/m-graph.mkiv
@@ -0,0 +1,63 @@
+%D \module
+%D [ file=m-graph,
+%D version=2008.09.08,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\METAPOST\ graph module 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.
+
+% We just assume lua specification instead of the graph ones that
+% are limited by what mp can do. We support @ as replacement for
+% the percent symbol. We also add a specifier when no one is given.
+
+\startluacode
+ local function strip(s)
+ return "\\times10^{"..(s:gsub("%+*0*","")).."}"
+ end
+ function metapost.format_n(fmt,str)
+ fmt = fmt:gsub("@","%%")
+ local initial, format, final = fmt:match("^(.-)(%%.-[%a])(.-)$")
+ if format then
+ str = fmt:format(str)
+ str = str:gsub("e(.-)$",strip)
+ str = ("%s\\mathematics{%s}%s"):format(initial,str,final)
+ elseif not fmt:find("%%") then
+ str = ("%"..fmt):format(str)
+ str = str:gsub("e(.-)$",strip)
+ str = ("\\mathematics{%s}"):format(str)
+ end
+ tex.sprint(str)
+ end
+\stopluacode
+
+\unexpanded\long\def\MPgraphformat#1#2{\ctxlua{metapost.format_n("#1","#2")}}
+
+\startMPinclusions
+ input graph.mp ;
+ vardef escaped_format(expr s) =
+ "" for n=1 upto length(s) : &
+ if ASCII substring (n,n+1) of s = 37 :
+ "@"
+ else :
+ substring (n,n+1) of s
+ fi
+ endfor
+ enddef ;
+ vardef dofmt_@\#(expr f, x) =
+ textext("\MPgraphformat{"&escaped_format(f)&"}{"&(if string x : x else: decimal x fi)&"}")
+ enddef ;
+
+ % vardef format(expr f, x) =
+ % textext("\MPgraphformatN{"&escaped_format(f)&"}{"&(if string x : x else: decimal x fi)&"}")
+ % enddef;
+ % vardef Mformat(expr f, x) =
+ % format(f,x)
+ % enddef;
+\stopMPinclusions
+
+\endinput
diff --git a/tex/context/base/m-graph.tex b/tex/context/base/m-graph.tex
new file mode 100644
index 000000000..6f71cca3c
--- /dev/null
+++ b/tex/context/base/m-graph.tex
@@ -0,0 +1,175 @@
+%D \module
+%D [ file=m-graph,
+%D version=2000.08.06,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\METAPOST\ graph module 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.
+
+\loadmarkfile{m-graph}
+
+\doifnotmode {demo} {\endinput}
+
+%D You need to have the data files in your path,
+%D otherwise the run is aborted.
+
+\doiffileelse {agepop91.d} {} {\writestatus{graph}{no data files found}\wait\end}
+
+%D The test:
+
+\starttext
+
+\startMPpage
+draw begingraph(3in,2in);
+ gdraw "agepop91.d";
+ endgraph;
+\stopMPpage
+
+\startMPpage
+draw begingraph(3in,2in);
+ gdraw "agepop91.d" plot btex$\bullet$etex;
+ endgraph;
+\stopMPpage
+
+\startMPpage
+draw begingraph(3in,2in);
+ glabel.lft(btex \vbox{\hbox{Population} \hbox{in millions}} etex, OUT);
+ glabel.bot(btex Age in years etex, OUT);
+ gdraw "agepopm.d";
+ endgraph;
+\stopMPpage
+
+\startMPpage
+draw begingraph(3in,2in);
+ glabel.lft(btex \vbox{\hbox{Population} \hbox{in millions}} etex, OUT);
+ glabel.bot(btex Age in years etex, OUT);
+ setrange(origin, whatever,whatever);
+ gdraw "agepopm.d";
+ endgraph;
+\stopMPpage
+
+\startMPpage
+draw begingraph(2.3in,2in);
+ setcoords(log,log);
+ glabel.lft(btex Seconds etex,OUT);
+ glabel.bot(btex Matrix size etex,
+ OUT);
+ gdraw "matmul.d" dashed evenly;
+ glabel.ulft(btex Standard etex,8);
+ gdraw "matmul.d";
+ glabel.lrt(btex Strassen etex,7);
+ endgraph;
+\stopMPpage
+
+\startMPpage
+draw begingraph(6.5cm,4.5cm);
+ setrange(80,0, 90,whatever);
+ glabel.bot(btex Year etex, OUT);
+ glabel.lft(btex \vbox{\hbox{Emissions in} \hbox{thousands of}
+ \hbox{metric tons} \hbox{(heavy line)}}etex, OUT);
+ gdraw "lead.d" withpen pencircle scaled 1.5pt;
+ autogrid(,otick.lft);
+ setcoords(linear,linear);
+ setrange(80,0, 90,whatever);
+ glabel.rt(btex \vbox{\hbox{Micrograms} \hbox{per cubic}
+ \hbox{meter of air} \hbox{(thin line)}}etex, OUT);
+ gdraw "lead.d";
+ autogrid(otick.bot,otick.rt);
+ endgraph;
+\stopMPpage
+
+\stoptext
+
+% No longer needed, since John will fix it.
+%
+% %D For the moment we need the following patch. Adam T. Lindsay
+% %D found out that the following code produced an error:
+% %D
+% %D \starttyping
+% %D \startMPcode
+% %D draw begingraph(130mm,35mm);
+% %D setrange(0,0,10,22000);
+% %D glabel.lft(btex {correct 0--22000} etex rotated 90, OUT);
+% %D autogrid(itick.bot,grid.lft) withcolor .75white ;
+% %D endgraph;
+% %D \stopMPcode
+% %D
+% %D \startMPcode
+% %D draw begingraph(130mm,35mm);
+% %D setrange(0,50,10,22000);
+% %D glabel.lft(btex {wrong 50--22000} etex rotated 90, OUT);
+% %D autogrid(itick.bot,grid.lft) withcolor .75white ;
+% %D endgraph;
+% %D \stopMPcode
+% %D
+% %D \startMPcode
+% %D draw begingraph(130mm,35mm);
+% %D setrange(0,110,10,30000);
+% %D glabel.lft(btex {failed 110--22000} etex rotated 90, OUT);
+% %D autogrid(itick.bot,grid.lft) withcolor .75white ;
+% %D endgraph;
+% %D \stopMPcode
+% %D \stoptyping
+% %D
+% %D The bug is a rather nasty one and needs some tweaking in
+% %D the low level graph code. John Hobby suggested for the
+% %D moment to initialize \type {setrange} as follows:
+% %D
+% %D \starttyping
+% %D setrange(0,0,"22000","22000")
+% %D \stoptyping
+% %D
+% %D Folowing this suggesion, I provide the following
+% %D extension:
+
+% def begingraph(expr w, h) =
+% begingroup
+% save X_, Y_, Gfin_, Gcur_, Gcbb_, Gneedgr_, Gneedfr_, Gdidsc_;
+% save Gdpic_, Gppic_, Ggl_, Garw_;
+% picture Gfin_, Gcur_, Gcbb_, Gdpic_, Gppic_, Ggl_[];
+% boolean Gneedgr_, Gneedfr_, Gdidsc_;
+% Gfin_ = nullpicture;
+% Gcur_ = nullpicture;
+% Gcbb_ = nullpicture;
+% X_.ctyp = Y_.ctyp = linear;
+% Z_.gdim = (w,h);
+% X_.sc = Y_.sc = 0;
+% Gneedgr_ = true;
+% Gneedfr_ = true;
+% Gdidsc_ = false;
+% Gdpic_ = nullpicture;
+% Garw_ = 0;
+% scantokens everybegingraph ;
+% enddef;
+%
+% boolean fixsetrange ; fixsetrange := true ;
+%
+% vardef dosetrange(text t) =
+% interim warningcheck:=0;
+% save r_; r_=0;
+% string r_[]s;
+% for x_=
+% for p_=t: if pair p_: xpart p_, ypart fi p_, endfor:
+% r_[incr r_] if string x_: s fi = x_;
+% if r_>2:
+% Gsetr_ if r_=3: X_(Gxcvlin_) else: Y_(Gycvlin_) fi(
+% r_[r_-2] if unknown r_[r_-2]: s fi, x_);
+% fi
+% exitif r_=4;
+% endfor
+% enddef;
+%
+% vardef setrange(text t) =
+% if fixsetrange : dosetrange(0,0,20000,20000) ; fi ;
+% dosetrange(t) ;
+% enddef ;
+%
+% if unknown everybegingraph :
+% string everybegingraph ;
+% % everybegingraph := "setrange(0,0,20000,20000)" ;
+% fi ;
diff --git a/tex/context/base/m-layout.tex b/tex/context/base/m-layout.tex
new file mode 100644
index 000000000..0ee71da47
--- /dev/null
+++ b/tex/context/base/m-layout.tex
@@ -0,0 +1,102 @@
+%D \module
+%D [ file=m-layout,
+%D version=2004.01.16,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Additional Layouts,
+%D author={Hans Hagen \& Ton Otten},
+%D date=\currentdate,
+%D copyright={PRAGMA ADE/ 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.
+
+% layout-preset - thf th tf
+
+%D This is a preliminary module, don't depend on these dimensions yet.
+
+\readsysfile{lang-frq}\donothing\donothing
+\readsysfile{lang-frd}\donothing\donothing
+
+\unprotect
+
+% \def\layouthwratio{\withoutpt\the\dimexpr8\paperheight/\dimexpr(\paperwidth/ 8192)\relax}
+% \def\layouthwratio{\withoutpt\the\dimexpr4\paperheight/\dimexpr(\paperwidth/16384)\relax}
+% \def\layouthwratio{\withoutpt\the\dimexpr2\paperheight/\dimexpr(\paperwidth/32768)\relax}
+
+\def\layouthwratio
+ {\withoutpt\the\dimexpr2\paperheight/(\paperwidth/32768)\relax}
+
+\def\layouthfheight
+ {\dimexpr\layoutparameter\c!header+\layoutparameter\c!headerdistance+
+ \layoutparameter\c!footer+\layoutparameter\c!footerdistance\relax}
+
+\startsetups[preset-1]
+
+ \xdef\layoutwidth {\dimexpr\layoutparameter\c!width\relax}
+ \gdef\layoutheight{\dimexpr\layouthwratio\dimexpr\layoutwidth\relax+\layouthfheight\relax}
+
+\stopsetups
+
+\definelayout
+ [preset-1-1]
+ [\c!preset=preset-1,
+ \c!backspace=\dimexpr(\paperwidth-\layoutwidth)/2\relax,
+ \c!width=\dimexpr2\paperwidth/3\relax,
+ \c!cutspace=\dimexpr(\paperwidth-\layoutwidth)/2\relax,
+ \c!margin=\dimexpr(\paperwidth-\layoutwidth)/3\relax,
+ \c!header=2\lineheight,
+ \c!headerdistance=\lineheight,
+ \c!height=\v!middle, % \layoutheight
+ \c!footerdistance=\layoutparameter\c!headerdistance, % \lineheight,
+ \c!footer=\layoutparameter\c!header, % 2\lineheight,
+ \c!topspace=\dimexpr1\dimexpr\paperheight-(\layoutheight+\layouthfheight)\relax/3\relax,
+ \c!bottomspace=\dimexpr2\dimexpr\paperheight-(\layoutheight+\layouthfheight)\relax/3\relax]
+
+\startsetups[preset-2]
+
+ \gdef\layouthstep{\dimexpr\paperwidth /\layoutparameter\c!columns\relax}
+ \gdef\layoutvstep{\dimexpr\paperheight/\layoutparameter\c!columns\relax}
+
+\stopsetups
+
+\definelayout
+ [preset-2-1]
+ [\c!preset=preset-2,
+ \c!columns=12,
+ \c!backspace=\layouthstep,
+ \c!width=\v!middle,
+ \c!cutspace=2\layouthstep,
+ \c!margin=\layouthstep,
+ \c!header=2\lineheight,
+ \c!headerdistance=\lineheight,
+ \c!height=\v!middle, % \layoutheight
+ \c!footerdistance=\layoutparameter\c!headerdistance,
+ \c!footer=\layoutparameter\c!header,
+ \c!topspace=\dimexpr\layoutvstep-\layoutparameter\c!header-\layoutparameter\c!headerdistance\relax,
+ \c!bottomspace=\dimexpr(2\layoutvstep)-\layoutparameter\c!header-\layoutparameter\c!headerdistance\relax]
+
+\definelayout
+ [preset-2-2]
+ [\c!preset=preset-2,
+ \c!columns=12,
+ \c!backspace=\layouthstep,
+ \c!width=\v!middle,
+ \c!cutspace=2\layouthstep,
+ \c!margin=\layouthstep,
+ \c!header=2\lineheight,
+ \c!headerdistance=\lineheight,
+ \c!height=\v!middle, % \layoutheight
+ \c!footerdistance=\layoutparameter\c!headerdistance,
+ \c!footer=\layoutparameter\c!header,
+ \c!topspace=\layoutvstep,
+ \c!bottomspace=\layoutvstep] % maybe 1.5
+
+% \setuplayout[preset-1-1] test \showframe \page
+% \setuplayout[preset-1-1][width=65\averagecharwidth] \setuplayout[preset-1-1] test \showframe \page
+% \setuplayout[preset-2-1] test \showframe \page
+% \setuplayout[preset-2-1][columns=10] \setuplayout[preset-2-1] test \showframe \page
+% \setuplayout[preset-2-2] test \showframe \page
+% \setuplayout[preset-2-2][columns=10] \setuplayout[preset-2-2] test \showframe \page
+
+\protect \endinput
diff --git a/tex/context/base/m-level.tex b/tex/context/base/m-level.tex
new file mode 100644
index 000000000..67d598733
--- /dev/null
+++ b/tex/context/base/m-level.tex
@@ -0,0 +1,94 @@
+%D \module
+%D [ file=level,
+%D version=2002.10.20,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Catching Nesting Errors,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\newcount\currentnesting
+
+\def\startnesting#1%
+ {\global\advance\currentnesting\plusone
+ \setxvalue{level::\number\currentnesting}{#1}}
+
+\def\stopnesting#1%
+ {\edef\nestingstring{#1}%
+ \relax\ifnum\currentnesting>\zerocount
+ \doifelsevalue{level::\number\currentnesting}\nestingstring
+ {\global\advance\currentnesting\minusone}
+ {\@EA\reportnestingerror\@EA\stoptext}
+ \else
+ \@EA\reportnestingerror\@EA\stoptext
+ \fi}
+
+\def\checknesting
+ {\relax\ifnum\currentnesting>\zerocount
+ \def\nestingstring{end of document}%
+ \@EA\reportnestingerror
+ \fi}
+
+\def\reportnestingerror
+ {\endgraf
+ \global\let\checknesting\relax
+ \bgroup \definedfont[Mono at 18pt]\incolortrue
+ \setupinterlinespace
+ \raggedright
+ \bgroup \red
+ \ifnum\currentnesting>\plusone
+ wrong end level
+ \else
+ too many end levels
+ \fi
+ at \nestingstring\space in line \number\inputlineno
+ \ifnum\currentnesting>\zerocount, stack:\fi\endgraf
+ \egroup
+ \dostepwiserecurse\currentnesting\plusone\minusone
+ {\space\getvalue{level::\recurselevel}}
+ \endgraf
+ \egroup
+ \writestatus\m!systems{quitting due to level error}\wait
+ \batchmode}
+
+\prependtoks
+ \checknesting
+\to \everystoptext
+
+\protect \doifnotmode{demo}{\endinput}
+
+\starttext
+
+% \startnesting{eerste}
+% \startnesting{tweede}
+% \startnesting{derde}
+% \startnesting{vierde}
+% test
+% \stopnesting{vierde}
+% \stopnesting{eerste}
+
+% \startnesting{eerste}
+% \startnesting{tweede}
+% test
+% \stopnesting{vierde}
+% \stopnesting{derde}
+% \stopnesting{tweede}
+% \stopnesting{eerste}
+
+\startnesting{eerste}
+ \startnesting{tweede}
+ \startnesting{derde}
+ \startnesting{vierde}
+ test
+ \stopnesting{vierde}
+ \stopnesting{derde}
+ \stopnesting{tweede}
+\stopnesting{eerste}
+
+\stoptext
diff --git a/tex/context/base/m-mkii.mkiv b/tex/context/base/m-mkii.mkiv
new file mode 100644
index 000000000..cb0da6fcb
--- /dev/null
+++ b/tex/context/base/m-mkii.mkiv
@@ -0,0 +1,21 @@
+% todo
+
+\unprotect
+
+\writestatus\m!systems{loading some mkii compatibility hacks}
+
+% Compatibility for font-ini
+
+\let\normalxi=\xi
+
+\definebodyfontswitch [xii] [\!!twelvepoint]
+\definebodyfontswitch [xi] [\!!elevenpoint]
+\definebodyfontswitch [x] [\!!tenpoint]
+\definebodyfontswitch [ix] [\!!ninepoint]
+\definebodyfontswitch [viii] [\!!eightpoint]
+\definebodyfontswitch [vii] [\!!sevenpoint]
+\definebodyfontswitch [vi] [\!!sixpoint]
+
+\unexpanded\def\xi{\ifmmode\normalxi\else\elevenpoint\fi}
+
+\protect \endinput
diff --git a/tex/context/base/m-mkivhacks.tex b/tex/context/base/m-mkivhacks.tex
new file mode 100644
index 000000000..f47658739
--- /dev/null
+++ b/tex/context/base/m-mkivhacks.tex
@@ -0,0 +1,52 @@
+%D \module
+%D [ file=m-mkivhacks,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Temporary Compatilibility Hacks,
+%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.
+
+\doifnotmode{mkiv}{\endinput}
+
+%D For Aditya, who needed it for his thesis.
+
+\startluacode
+ -- -- a lot or work
+ --
+ -- mathematics.slots.euler = {
+ -- [0x03B1] = { "mr", 0x0B }, -- alpha
+ -- }
+ --
+ -- mathematics.slots.euler = table.merge(mathematics.slots.traditional,mathematics.slots.euler)
+ --
+ -- versus a quick hack
+
+ document.hacks = document.hacks or { }
+
+ function document.hacks()
+ mathematics.families.lcgreek = mathematics.families.mr
+ mathematics.families.ucgreek = mathematics.families.mr
+ mathematics.families.vargreek = mathematics.families.mr
+
+ mathematics.define(mathematics.slots.euler)
+ end
+\stopluacode
+
+% \usemodule[mkivhacks] \setups{eulermath}
+% \definetypeface[modern][mm][math][euler][default]
+% \usemathcollection[eul]
+% \switchtobodyfont[modern,11pt]
+% \starttext
+% $\alpha$
+% \stoptext
+
+\startsetups eulermath
+ \ctxlua{document.hacks()}
+\stopsetups
+
+\endinput
diff --git a/tex/context/base/m-narrowtt.tex b/tex/context/base/m-narrowtt.tex
new file mode 100644
index 000000000..2e11b99ad
--- /dev/null
+++ b/tex/context/base/m-narrowtt.tex
@@ -0,0 +1,39 @@
+%D \module
+%D [ file=m-narrowtt,
+%D version=2005.09.08,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Narrow Verbatim,
+%D author={Hans Hagen \& Ton Otten},
+%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.
+
+%D Test file
+%D
+%D \starttyping
+%D \startTEX
+%D \usemodule[narrowtt]
+%D \starttext
+%D \starttyping
+%D Test test test.
+%D \stoptyping
+%D test \type {test} test \type{test} test
+%D \starttyping
+%D Test test test.
+%D \stoptyping
+%D \stoptext
+%D \stopTEX
+
+\unprotect
+
+\definetypeface
+ [narrowtt] [tt]
+ [mono] [modern-condensed] [default] [encoding=\defaultencoding]
+
+\definetyping[n\v!typing] \setuptyping[n\v!typing][style=\narrowtt]
+\definetype [n\v!type] \setuptype [n\v!type] [style=\narrowtt]
+
+\protect \endinput
diff --git a/tex/context/base/m-newmat.tex b/tex/context/base/m-newmat.tex
new file mode 100644
index 000000000..08ce33b4c
--- /dev/null
+++ b/tex/context/base/m-newmat.tex
@@ -0,0 +1,337 @@
+%D \module
+%D [ file=m-newmat,
+%D version=2000.11.16,
+%D title=\CONTEXT\ Math Module,
+%D subtitle=AMS-like math extensions,
+%D author={Taco Hoekwater \& Hans Hagen},
+%D date=\currentdate,
+%D copyright={PRAGMA / Taco Hoekwater}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+%D This module collects macros that \TEX\ users kind of expect
+%D to be available when typesetting math. Most of them
+%D originate in the \AMS\ macro packages. We have taken the
+%D freedom to adapt them to \CONTEXT. This module is derived
+%D from the \type {m-math} module by Taco Hoekwater (partially
+%D derived from AMS math modules) and adapted|/|extended by
+%D Hans Hagen.
+
+%D Here we will add code on demand. So, just let us know what
+%D should go in here.
+
+%M \usemodule[newmat]
+
+\unprotect
+
+%D \macros
+%D {qedsymbol}
+%D
+%D [HH] The general Quod Erat Domonstrandum symbol is defined
+%D in such a way that we can configure it. Because this symbol
+%D is also used in text mode, we make it a normal text symbol
+%D with special behavior.
+
+\def\qedsymbol#1%
+ {\ifhmode
+ \unskip~\hfill#1\par
+ \else\ifmmode
+ \eqno#1\relax % Do we really need the \eqno here?
+ \else
+ \leavevmode\hbox{}\hfill#1\par
+ \fi\fi}
+
+\definesymbol [qed] [\qedsymbol{\mathematics{\square}}]
+
+%D \macros
+%D {QED}
+%D
+%D [HH] For compatbility reasons we also provide the \type
+%D {\QED} command. In case this command is overloaded, we still
+%D have the symbol available. \symbol[qed]
+
+\def\QED{\symbol[qed]}
+
+%D \macros
+%D {genfrac}
+%D
+%D [TH] The definition of \type {\genfrac} \& co. is not
+%D trivial, because it allows some flexibility. This is
+%D supposed to be a user||level command, but will fail quite
+%D desparately if called outside math mode (\CONTEXT\ redefines
+%D \type {\over})
+%D
+%D [HH] We clean up this macro a bit and (try) to make it
+%D understandable. The expansion is needed for generating
+%D the second argument to \type {\dogenfrac}, which is to
+%D be a control sequence like \type {\over}.
+
+\unexpanded\def\genfrac#1#2#3#4%
+ {\edef\!!stringa
+ {#1#2}%
+ \expanded
+ {\dogenfrac{#4}%
+ \csname
+ \ifx @#3@%
+ \ifx\!!stringa\empty
+ \strippedcsname\normalover
+ \else
+ \strippedcsname\normaloverwithdelims
+ \fi
+ \else
+ \ifx\!!stringa\empty
+ \strippedcsname\normalabove
+ \else
+ \strippedcsname\normalabovewithdelims
+ \fi
+ \fi
+ \endcsname}%
+ {#1#2#3}}
+
+\def\dogenfrac#1#2#3#4#5%
+ {{#1{\begingroup#4\endgroup#2#3\relax#5}}}
+
+%D \macros
+%D {dfrac, tfrac, frac, dbinom, tbinom, binom}
+%D
+%D [TH] No need to make these \type {\unexpanded} as well.
+
+%\def\dfrac {\genfrac\empty\empty\empty\displaystyle}
+%\def\tfrac {\genfrac\empty\empty\empty\textstyle}
+%\def\frac {\genfrac\empty\empty\empty\donothing}
+
+\def\dfrac {\genfrac\empty\empty{}\displaystyle}
+\def\tfrac {\genfrac\empty\empty{}\textstyle}
+\def\frac {\genfrac\empty\empty{}\donothing}
+
+\def\dbinom{\genfrac()\zeropoint\displaystyle}
+\def\tbinom{\genfrac()\zeropoint\textstyle}
+\def\binom {\genfrac()\zeropoint\donothing}
+
+\def\xfrac {\genfrac\empty\empty{}\scriptstyle}
+\def\xxfrac{\genfrac\empty\empty{}\scriptscriptstyle}
+
+%D Better:
+
+\unexpanded\def\frac#1#2{\mathematics{\genfrac\empty\empty{}\donothing{#1}{#2}}}
+
+%D [HH] This shows up as:
+%D
+%D \startbuffer
+%D $\dfrac {1}{2} \tfrac {1}{2} \frac {1}{2}$
+%D $\dbinom{1}{2} \tbinom{1}{2} \binom{1}{2}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+%D \macros
+%D {text}
+%D
+%D [TH] \type {\text} is a command to typeset more or less
+%D ordinary text inside of super- and sub|-|scripts. It has to
+%D do a full font switch to get the sides right, so it will be
+%D quite slow. \type {\text} kind of replaces \CONTEXT's \type
+%D {\mathstyle} command.
+
+%D [HH] This macro is now also moved to the core, but we
+%D keep it here as well for completeness.
+%D
+%D \starttyping
+%D \unexpanded\def\mathtext
+%D {\mathortext\domathtext\hbox} % {\ifmmode\@EA\dotext\else\@EA\hbox\fi}
+%D
+%D \def\domathtext#1%
+%D {\mathchoice
+%D {\dodomathtext\displaystyle\textface {#1}}%
+%D {\dodomathtext\textstyle \textface {#1}}%
+%D {\dodomathtext\textstyle \scriptface {#1}}%
+%D {\dodomathtext\textstyle \scriptscriptface{#1}}}
+%D
+%D \def\dodomathtext#1#2#3% no \everymath !
+%D %{\hbox{\everymath{#1}\switchtobodyfont [#2]#3}} % 15 sec
+%D {\hbox{\everymath{#1}\setcurrentfontbody{#2}#3}} % 3 sec (no math)
+%D \stoptyping
+
+%D [HH] We use the following indirectness because \type {\text}
+%D is a natural candidate for user macros (actually, it is
+%D used in some modules).
+%D
+%D \starttyping
+%D \let\text\mathtext
+%D \stoptyping
+
+%D [HH] Actually, the font switch is not that slow when
+%D typefaces are used. If needed this macro can be sped up.
+%D
+%D \startbuffer
+%D ordinary text $x^{\text{extra ordinary text}}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+%D \macros
+%D {mathhexbox}
+%D
+%D [TH] \type {\mathhexbox} is also user||level (already
+%D defined in Plain \TEX). It allows to get a math character
+%D inserted as if it was a text character.
+
+\gdef\mathhexbox#1#2#3{\mathtext{$\mathsurround\zeropoint\mathchar"#1#2#3$}}
+
+%D \macros
+%D {boxed}
+%D
+%D [HH] Another macro that users expect (slightly adapted):
+
+\def\boxed
+ {\ifmmode\expandafter\mframed\else\expandafter\framed\fi}
+
+%D \macros
+%D {cfrac}
+%D
+%D [HH] Now let us see what this one does:
+%D
+%D \startbuffer
+%D $\cfrac{12}{3} \cfrac[l]{12}{3} \cfrac[c]{12}{3} \cfrac[r]{12}{3}$
+%D $\cfrac{1}{23} \cfrac[l]{1}{23} \cfrac[c]{1}{23} \cfrac[r]{1}{23}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+\definecomplexorsimple\cfrac
+
+\def\simplecfrac
+ {\complexcfrac[c]}
+
+\def\complexcfrac[#1]#2#3%
+ {{\displaystyle
+ \frac
+ {\strut\ifx r#1\hfill\fi#2\ifx l#1\hfill\fi}%
+ {#3}}%
+ \kern-\nulldelimiterspace}
+
+%D [HH] The next alternative is nicer:
+
+\def\simplecfrac {\docfrac[cc]}
+\def\complexcfrac[#1]{\docfrac[#1cc]}
+
+\def\docfrac[#1#2#3]#4#5%
+ {{\displaystyle
+ \frac
+ {\strut
+ \ifx r#1\hfill\fi#4\ifx l#1\hfill\fi}%
+ {\ifx r#2\hfill\fi#5\ifx l#2\hfill\fi}%
+ \kern-\nulldelimiterspace}}
+
+%D [HH] Now we can align every combination we want:
+%D
+%D \startbuffer
+%D $\cfrac{12}{3} \cfrac[l]{12}{3} \cfrac[c]{12}{3} \cfrac[r]{12}{3}$
+%D $\cfrac{1}{23} \cfrac[l]{1}{23} \cfrac[c]{1}{23} \cfrac[r]{1}{23}$
+%D $\cfrac[cl]{12}{3} \cfrac[cc]{12}{3} \cfrac[cr]{12}{3}$
+%D $\cfrac[lc]{1}{23} \cfrac[cc]{1}{23} \cfrac[rc]{1}{23}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+%D \macros
+%D {splitfrac, splitdfrac}
+%D
+%D Occasionally one needs to typeset multi||line fractions.
+%D These commands use \tex{genfrac} to create such fractions.
+%D
+%D \startbuffer
+%D \startformula
+%D a=\frac{
+%D \splitfrac{xy + xy + xy + xy + xy}
+%D {+ xy + xy + xy + xy}
+%D }
+%D {z}
+%D =\frac{
+%D \splitdfrac{xy + xy + xy + xy + xy}
+%D {+ xy + xy + xy + xy}
+%D }
+%D {z}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D These macros are based on Michael J.~Downes posting on
+%D comp.text.tex on 2001/12/06
+
+\def\splitfrac#1#2%
+ {\genfrac\empty\empty\zeropoint\textstyle%
+ {\textstyle#1\quad\hfill}%
+ {\textstyle\hfill\quad\mathstrut#2}}
+
+\def\splitdfrac#1#2%
+ {\genfrac\empty\empty\zeropoint\displaystyle%
+ {#1\quad\hfill}
+ {\hfill\quad\mathstrut #2}}
+
+\protect \endinput
+
+%D \macros
+%D {startsubarray,substack,startsmallmatrix}
+%D
+%D [HH] I wonder what these are supposed to do. An example
+%D will be inserted later. Contrary to the original we
+%D support an optional argument between either \type {{}} or
+%D \type {[]}.
+
+\def\startsubarray
+ {\doifnextcharelse\bgroup
+ \simplestartsubarray{\dosingleempty\complexstartsubarray}}
+
+\def\complexstartsubarray[#1]%
+ {\simplestartsubarray{#1}}
+
+\def\simplestartsubarray#1%
+ {\vcenter\bgroup
+ \baselineskip\fontdimen10 \scriptfont\plustwo
+ \advance\baselineskip\fontdimen12 \scriptfont\plustwo
+ \lineskip\plusthree\fontdimen8 \scriptfont\plusthree
+ \lineskiplimit\lineskip
+ \ialign\bgroup\ifx c#1\hfil\fi$\mathsurround\zeropoint\scriptstyle##$\hfil\crcr}
+
+\def\stopsubarray
+ {\crcr\egroup
+ \egroup}
+
+\def\startsubstack
+ {\doifnextcharelse\bgroup
+ \simplestartsubstack{\dosingleempty\complexstartsubstack}}
+
+\def\complexstartsubstack[#1]%
+ {\simplestartsubstack{#1}}
+
+\def\simplesubstack#1%
+ {\startsubarray[c]#1\stopsubarray}
+
+\def\startsmallmatrix
+ {\null
+ \,%
+ \vcenter\bgroup
+ \baselineskip6\ex@
+ \lineskip1.5\ex@
+ \lineskiplimit\lineskip
+ \ialign\bgroup\hfil$\mathsurround\zeropoint\scriptstyle##$\hfil&&\thickspace\hfil
+ $\mathsurround\zeropoint\scriptstyle##$\hfil\crcr}
+
+\def\stopsmallmatrix
+ {\crcr\egroup
+ \egroup
+ \,}
+
+\protect \endinput
diff --git a/tex/context/base/m-obsolete.tex b/tex/context/base/m-obsolete.tex
new file mode 100644
index 000000000..a97002cf6
--- /dev/null
+++ b/tex/context/base/m-obsolete.tex
@@ -0,0 +1,5 @@
+\unprotect
+
+\writestatus\m!systems{skipping obsolete module}
+
+\protect \endinput
diff --git a/tex/context/base/m-pdfsnc.tex b/tex/context/base/m-pdfsnc.tex
new file mode 100644
index 000000000..da59ab5d8
--- /dev/null
+++ b/tex/context/base/m-pdfsnc.tex
@@ -0,0 +1,200 @@
+%D \module
+%D [ file=m-pdfsnc,
+%D version=2003.12.23,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Editor Synchronization,
+%D author={Hans Hagen \& Ton Otten},
+%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.
+
+% \enablemode[demo]
+
+% This file is a variation of the file pdfsync4context.tex that ships
+% with the pdfsync package (used by iTeXMac and TeXShop) by Piero
+% D'Ancona and Jrme Laurens. I made the macros a bit more efficient
+% and added some basic tracing options as well as a few more options.
+% I made this one while playing a bit with the Mac and TeX). Maybe I'll
+% add a bit of support to the kernel in in order to get rid of redundant
+% markers. Also, this had better be rewritten in a bit less \pdf
+% dependent way so that it can also be supported by dvipdfmx. I could
+% write a generic file as well, but since there is already support for
+% other packages I'll not do that (now).
+
+% compatible commands:
+%
+% \pdfsyncstart \pdfsyncstop \pdfsync
+%
+% extra commands:
+%
+% \enablepdfsync \disablepdfsync \pdfsynctext \pdfsyncnode \pdfsynctracemode
+
+\ifx\pdfoutput\undefined
+ \donefalse
+\else\ifcase\pdfoutput
+ \donefalse
+\else\ifx\pdfsavepos\undefined
+ \donefalse
+\else
+ \donetrue
+\fi\fi\fi
+
+\chardef \pdfsyncstate \zerocount
+\chardef \pdfsynctracemode \zerocount
+
+\ifdone
+
+ \writestatus{pdfsync}{loading and enabling synchronization support}
+
+\else
+
+ \writestatus{pdfsync}{synchronization is only available with pdftex}
+
+ \let \pdfsyncstart \relax % brr, not per se symmetrically used, so
+ \let \pdfsyncstop \relax % enable and disable are better names
+ \let \pdfsync \relax
+
+ \let \pdfsynctext \gobbleoneargument
+ \let \pdfsyncnode \gobbleoneargument
+
+ \let \enablepdfsync \pdfsyncstart
+ \let \disablepdfsync \pdfsyncstop
+
+ \expandafter\endinput
+\fi
+
+\unprotect % not really needed
+
+\newcount \pdfsynccounter
+\newwrite \pdfsyncwrite
+
+\def\pdfsyncstart{\chardef\pdfsyncstate\plusone} \let\enablepdfsync \pdfsyncstart
+\def\pdfsyncstop {\chardef\pdfsyncstate\zerocount} \let\disablepdfsync\pdfsyncstop
+
+\def\dostartpdfsync
+ {\immediate\openout\pdfsyncwrite\jobname.pdfsync
+ \immediate\write\pdfsyncwrite{\jobname}%
+ \immediate\write\pdfsyncwrite{version 0}}
+
+\def\dostoppdfsync
+ {\immediate\closeout\pdfsyncwrite}
+
+\def\doregisterpdfsyncpage
+ {\immediate\write\pdfsyncwrite{s\space\realfolio}}
+
+\def\dopdfsyncopenfile
+ {\immediate\write\pdfsyncwrite{(\space\readfilename}}
+
+\def\dopdfsyncclosefile
+ {\immediate\write\pdfsyncwrite{)}}
+
+\def\doregisterpdfsyncnode#1%
+ {\ifcase\pdfsyncstate\else
+ \pdfsavepos
+ \immediate\write\pdfsyncwrite{l\space\the\pdfsynccounter\space\the\inputlineno}%
+ \expanded{\write\pdfsyncwrite{p\ifnum#1=\plusone*\fi\space\the\pdfsynccounter\space\noexpand\the\pdflastxpos\space\noexpand\the\pdflastypos}}%
+ \global\advance\pdfsynccounter\plusone
+ \fi}
+
+\let\pdfsynctracer\gobbleoneargument
+
+\def\pdfsync {\doregisterpdfsyncnode\plusone \pdfsynctracer*}
+\def\pdfsyncnode{\doregisterpdfsyncnode\zerocount\pdfsynctracer}
+\def\pdfsynctext{\doregisterpdfsyncnode\plusone \pdfsynctracer}
+
+\appendtoks \dostartpdfsync \to \everystarttext
+%appendtoks \dostoppdfsync \to \everystoptext
+\appendtoks \doregisterpdfsyncpage \to \everyshipout
+\appendtoks \dopdfsyncopenfile \to \everybeforereadfile
+\appendtoks \dopdfsyncclosefile \to \everyafterreadfile
+
+\appendtoks \enablepdfsync \to \everystarttext
+\appendtoks \disablepdfsync \to \everypagebody
+
+% beware, adding nodes this way will interfere with the typesetting
+
+\appendtoks \pdfsyncnode p\to \everypar
+\appendtoks \pdfsyncnode m\to \everymath
+\appendtoks \pdfsyncnode h\to \everyhbox
+
+% just for fun
+
+\def\pdfsynctracer#1%
+ {\ifcase\pdfsynctracemode\else
+ \ifcase\pdfsyncstate\else
+ \begingroup
+ \forgetall
+ \disablepdfsync
+ \ifcase\pdfsynctracemode\or % could be done more efficient, box around ifcase
+ \setbox\scratchbox\hbox to \zeropoint{\hss\infofont#1\hss}% 1
+ \else
+ \setbox\scratchbox\hbox to \zeropoint{\hss\traceboxplacementtrue\boxcursor\hss}% 2/3/4
+ \fi
+ \smashbox\scratchbox\box\scratchbox
+ \ifcase\pdfsynctracemode\or\or\or
+ \setbox\scratchbox\hbox to \zeropoint{\hss\raise1.25ex\hbox{\infofont#1}\hss}% 3
+ \smashbox\scratchbox\box\scratchbox
+ \or
+ \setbox\scratchbox\hbox to \zeropoint{\hss\lower1.25ex\hbox{\infofont#1}\hss}% 4
+ \smashbox\scratchbox\box\scratchbox
+ \fi
+ \endgroup
+ \fi
+ \fi}
+
+% \def\pdfsynctracer#1% more efficient but unreadable
+% {\ifcase\pdfsynctracemode\else
+% \ifcase\pdfsyncstate\else
+% \begingroup
+% \forgetall
+% \disablepdfsync
+% \setbox\scratchbox\hbox to \zeropoint
+% {\hss
+% \ifcase\pdfsynctracemode\or
+% \infofont#1% 1
+% \else
+% \traceboxplacementtrue\boxcursor% 2/3/4
+% \fi
+% \hss}%
+% \smashbox\scratchbox\box\scratchbox
+% \setbox\scratchbox\hbox to \zeropoint
+% {\hss
+% \ifcase\pdfsynctracemode\or\or\or
+% \raise1.25ex\hbox{\infofont#1}% 3
+% \or
+% \lower1.25ex\hbox{\infofont#1}% 4
+% \fi
+% \hss}%
+% \smashbox\scratchbox\box\scratchbox
+% \endgroup
+% \fi
+% \fi}
+
+\protect
+
+\doifnotmode{demo}{\endinput}
+
+\chardef\pdfsynctracemode=3
+
+\starttext
+
+\chapter{Test}
+
+\processfile{tufte}
+
+\startitemize
+\item first
+\item second
+\stopitemize
+
+\processfile{tufte}
+
+\startlines
+some local \pdfsync sync and \pdfsynctext{here}a marked point
+some local \pdfsync sync and \pdfsyncnode{here}a marked point
+\stoplines
+
+\stoptext
diff --git a/tex/context/base/m-pictex.tex b/tex/context/base/m-pictex.tex
new file mode 100644
index 000000000..abb81b76e
--- /dev/null
+++ b/tex/context/base/m-pictex.tex
@@ -0,0 +1,255 @@
+%D \module
+%D [ file=m-pictex,
+%D version=1997.01.15,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PICTEX\ Loading Macros,
+%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.
+
+%D This module is one big hack. This hack is not needed when
+%D using \ETEX, so there we simply load \PICTEX\ and quit.
+
+%D Not every package defines \type{\fiverm}, \PICTEX's pixel,
+%D so let's take care of that omision here. The actual loading
+%D of \PICTEX\ depends on the package. For \LATEX\ users we
+%D take care of loading the auxiliary ones too.
+
+\def\loadpictex
+ {\ifx\grid\undefined \else \let\normalgrid\grid \fi
+ \ifx\axis\undefined \else \let\normalaxis\axis \fi
+ \ifx\undefined\fiverm
+ \font\fiverm=cmr5
+ \fi
+ \ifx\beginpicture\undefined
+ \ifx\newenvironment\undefined
+ \readfile{thrd-pic.tex}{}{}
+ \else
+ \input prepictex.tex \relax
+ \input pictex.tex \relax
+ \input postpictex.tex \relax
+ \fi
+ \fi
+ \ifx\normalgrid\undefined \else
+ \let\pictexgrid\grid
+ \let\grid\normalgrid
+ \fi
+ \ifx\normalaxis\undefined \else
+ \let\pictexaxis\axis
+ \let\axis\normalaxis
+ \fi}
+
+\ifx\eTeXversion\undefined \else \loadpictex \expandafter \endinput \fi
+
+%D When not in \ETEX\ and not in \CONTEXT, we load a few
+%D auxiliary macros.
+
+\ifx \undefined \writestatus \input supp-mis.tex \relax \fi
+
+\unprotect
+
+%D \TEX\ provides 256 \DIMENSIONS\ and 256 \SKIPS. In \CONTEXT\
+%D this is no problem, but in packages that have many
+%D authors, one can be quite sure that a lot of \DIMENSIONS\ are
+%D allocated. Packages that use \PICTEX\ can therefore run out
+%D of \DIMENSIONS\ quite fast. This module was written as a
+%D reaction to persistent problems with loading \PPCHTEX\ in
+%D \LATEX\ and \PICTEX\ deserves a solution. I therefore
+%D dedicate this module to Tobias Burnus and Dirk Kuypers, who
+%D use \PPCHTEX\ in a \LATEX\ environment and suggested a lot
+%D of extensions to the repertoire of \PPCHTEX\ commands.
+%D
+%D This module presents a solution that is quite effective: all
+%D \DIMENSIONS\ are drawn from the pool of \DIMENSIONS\ and
+%D \SKIPS, depending on the availability. This is possible
+%D because \DIMENSIONS\ are \SKIPS\ without a glue component.
+%D Therefore we can use \SKIPS\ as \DIMENSIONS. However, some
+%D incompatibility can result from assignments that look like:
+%D
+%D \starttyping
+%D \somedimen=\someskip
+%D \stoptyping
+%D
+%D In such cases the \DIMENSION\ equals the fixed part of the
+%D \SKIP\ or in other words: this assignment strips off the
+%D glue. Because \PICTEX\ uses no glue components, I thought
+%D I could interchange both register types without problems,
+%D but alas, this didn't hold for all \DIMENSIONS.
+
+%D In \PLAIN\ \TEX\ the allocation macros are defined with (as)
+%D \type{\outer}. This means that they cannot appear inside
+%D macros, not even in an indirect way. We therefore have to
+%D redefine both \type{\newdimen} and \type{\newskip} to
+%D non||\type{\outer} alternatives. In most macro packages this
+%D redefinition already took place. We save the original
+%D meanings, so we can restores them afterwards.
+
+% \def\temporarynewdimen {\alloc@1\dimen\dimendef\insc@unt}
+% \def\temporarynewskip {\alloc@2\skip \skipdef \insc@unt}
+
+\let\normalnewdimen \newdimen
+\let\normalnewskip \newskip
+
+\let\temporarynewdimen\newdimen
+\let\temporarynewskip \newskip
+
+%D Here comes the trick. Depending on how many \DIMENSIONS\ and
+%D \SKIPS\ are allocated, the \type{\newdimen} assigns a
+%D \DIMENSIONS\ or \SKIP. \PLAIN\ \TEX\ allocates 15 \DIMENSIONS\
+%D and 17 \SKIPS. After loading \PICTEX, 71 \DIMENSIONS\ and
+%D and 71 \SKIPS\ are allocated. Indeed, \PICTEX\ needs 110
+%D \DIMENSIONS !
+%D
+%D \starttyping
+%D \def\newdimen
+%D {\ifnum\count11>\count12
+%D \let\next\temporarynewskip
+%D \else
+%D \let\next\temporarynewdimen
+%D \fi
+%D \next}
+%D \stoptyping
+%D
+%D When I was testing a new version of \PPCHTEX\ in \PLAIN\
+%D \TEX\ I had to find out that this exchange of registers
+%D sometimes leads to unwanted results. It took me some hours
+%D to find out that the source of errors originated in
+%D constructions like:
+%D
+%D \starttyping
+%D \ifdim\DimenOne<\DimenTwo whatever you want \else or not \fi
+%D \stoptyping
+%D
+%D When \type{\DimenOne} is a \SKIP\ and \type{\DimenTwo} is a
+%D \DIMENSION, \TEX\ scans for some optional glue component,
+%D like in:
+%D
+%D \starttyping
+%D \skip0=\dimen0 plus 10pt minus 5pt
+%D \stoptyping
+%D
+%D The most robust solution to this problem is:
+%D
+%D \starttyping
+%D \ifdim\DimenOne<\DimenTwo\relax right \else wrong \fi
+%D \stoptyping
+%D
+%D Some close reading of the \PICTEX\ source however learned me
+%D that this problem could be solved best by just honoring the
+%D allocation of \DIMENSIONS\ when the name of the macro
+%D explictly stated the character sequence \type{dimen}. A next
+%D implementation therefore automatically declared all
+%D \DIMENSIONS\ with this sequence in their names with
+%D \type{\dimen}. Again I was too optimistic, so now we do it
+%D this way (the comments are from \PICTEX, which like \TABLE,
+%D is an example of a well documented package):
+
+\temporarynewdimen\!dimenA %.AW.X.DVEUL..OYQRST
+\temporarynewdimen\!dimenB %....X.DVEU...O.QRS.
+\temporarynewdimen\!dimenC %..W.X.DVEU......RS.
+\temporarynewdimen\!dimenD %..W.X.DVEU....Y.RS.
+\temporarynewdimen\!dimenE %..W........G..YQ.S.
+\temporarynewdimen\!dimenF %...........G..YQ.S.
+\temporarynewdimen\!dimenG %...........G..YQ.S.
+\temporarynewdimen\!dimenH %...........G..Y..S.
+\temporarynewdimen\!dimenI %...BX.........Y....
+\temporarynewdimen\!dxpos %..W......U..P....S.
+\temporarynewdimen\!dypos %..WB.....U..P......
+\temporarynewdimen\!xloc %..WB.....U.......S.
+\temporarynewdimen\!xpos %..........L.P..Q.ST
+\temporarynewdimen\!yloc %..WB.....U.......S.
+\temporarynewdimen\!ypos %..........L.P..Q.ST
+\temporarynewdimen\!zpt %.AWBX.DVEULGP.YQ.ST
+
+%D Tobias tested this module in all kind of \LATEX\ dialects
+%D so we were able to find out that we also needed to declare:
+
+\temporarynewdimen\linethickness
+
+%D After all, the new definition of \type{\newdimen} became:
+
+\def\newdimen#1%
+ {\ifx#1\undefined
+ \ifnum\count11>\count12\relax
+ \temporarynewskip#1\relax
+ \else
+ \temporarynewdimen#1\relax
+ \fi
+ %\edef\ascii{\meaning#1}%
+ %\immediate\write20{\string#1 becomes \ascii}%
+ \else
+ %\edef\ascii{\meaning#1}%
+ %\immediate\write20{\string#1 already is \ascii}%
+ \fi}
+
+% \def\newdimen#1%
+% {\bgroup
+% \escapechar=-1
+% \def\next##1##2%
+% {\def\next####1##1####2####3\next%
+% {\egroup
+% \if####2@
+% \temporarynewdimen#1\relax
+% \ifnum\count11>\count12
+% \temporarynewskip#1\relax
+% \else
+% \temporarynewdimen#1\relax
+% \fi\fi}%
+% \expandafter\next\string##2##1@@\next}%
+% \expandafter\next\expandafter{\string\dimen}#1}
+%
+% This macro is as unreadable, inefficient and as compact as
+% can be, but uses no extra hash entries, which sometimes are
+% scarce too. A more readable alternative, that also takes
+% explicit \SKIPS\ into account, is included in the source.
+%
+% \def\doifregisterpreferenceelse#1#2#3#4%
+% {\def\dodoifregisterpreferenceelse##1#1##2##3\war{\if##2@}%
+% \expandafter\dodoifregisterpreferenceelse\string#2#1@@\war
+% #4%
+% \else
+% #3%
+% \fi}
+%
+% \def\newdimen#1%
+% {\bgroup
+% \escapechar=-1
+% \expandafter\doifregisterpreferenceelse\expandafter{\string\dimen}#1
+% {\egroup
+% \temporarynewdimen#1}
+% {\expandafter\doifregisterpreferenceelse\expandafter{\string\skip}#1
+% {\egroup
+% \temporarynewskip#1}
+% {\egroup
+% \ifnum\count11>\count12
+% \temporarynewskip#1\relax
+% \else
+% \temporarynewdimen#1\relax
+% \fi}}}
+
+%D Curious readers can still find the previous solution in
+%D the source. The next macro is used instead of
+%D \type{\input}. This macro also reports some statistics.
+
+\def\dimeninput#1 %
+ {\message{[before: d=\the\count11,s=\the\count12]}%
+ \input #1 \relax
+ \message{[after: d=\the\count11,s=\the\count12]}}%
+
+%D Now we can load \PICTEX:
+
+\loadpictex
+
+%D Finally we restore the old definitions of \type{\newdimen}
+%D and \type{\newskip}:
+
+\let\newdimen=\normalnewdimen
+\let\newskip =\normalnewskip
+
+%D and just hope for the best.
+
+\protect \endinput
diff --git a/tex/context/base/m-plus.tex b/tex/context/base/m-plus.tex
new file mode 100644
index 000000000..312d9f931
--- /dev/null
+++ b/tex/context/base/m-plus.tex
@@ -0,0 +1,30 @@
+%D \module
+%D [ file=m-plus,
+%D version=2003.03.16,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Loading extra features,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Somewhere in 2001 I started collecting new functionality
+%D in a module \type {m-yesno}. As the name suggests, I was
+%D not entirely sure if this functionality belonged in the
+%D kernel. When (again) on the \CONTEXT\ list a request for
+%D side bars was posted, I decided to move such code to plus
+%D modules. Users who want this additional functionality can
+%D put the following call in their \type {cont-sys.tex} file:
+%D
+%D \starttyping
+%D \usemodule[plus]
+%D \stoptyping
+
+% \readfile {plus-rul} \donothing \donothing
+% \readfile {page-str} \donothing \donothing
+% \readfile {page-plg} \donothing \donothing
+
+\endinput
diff --git a/tex/context/base/m-pstricks.lua b/tex/context/base/m-pstricks.lua
new file mode 100644
index 000000000..35cae93f6
--- /dev/null
+++ b/tex/context/base/m-pstricks.lua
@@ -0,0 +1,73 @@
+if not modules then modules = { } end modules ['m-pstricks'] = {
+ version = 1.001,
+ comment = "companion to m-pstricks.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- The following will be done when I need ps tricks figures
+-- in large quantities:
+--
+-- + hash graphics and only process them once
+-- + save md5 checksums in tuc file
+--
+-- It's no big deal but has a low priority.
+
+local format, lower, concat, gmatch = string.format, string.lower, table.concat, string.gmatch
+local variables = interfaces.variables
+
+plugins = plugins or { }
+plugins.pstricks = plugins.pstricks or { }
+
+local template = [[
+\starttext
+ \pushcatcodetable
+ \setcatcodetable\texcatcodes
+ \usemodule[pstric]
+ %s
+ \popcatcodetable
+ \startTEXpage
+ \hbox\bgroup
+ \ignorespaces
+ %s
+ \removeunwantedspaces
+ \egroup
+ \obeydepth %% temp hack as we need to figure this out
+ \stopTEXpage
+\stoptext
+]]
+
+local modules = { }
+local graphics = 0
+
+function plugins.pstricks.usemodule(names)
+ for name in gmatch(names,"([^%s,]+)") do
+ modules[#modules+1] = format([[\readfile{%s}{}{}]],name)
+ end
+end
+
+function plugins.pstricks.process(n)
+ graphics = graphics + 1
+ local name = string.format("%s-pstricks-%04i",tex.jobname,graphics)
+ local data = buffers.collect("def-"..n)
+ local tmpfile = name .. ".tmp"
+ local epsfile = name .. ".ps"
+ local pdffile = name .. ".pdf"
+ local modules = concat(modules,"\n")
+ os.remove(epsfile)
+ os.remove(pdffile)
+ io.savedata(tmpfile,format(template,modules,data))
+ os.execute(format("mtxrun --script texexec %s --once --dvips",tmpfile))
+ if lfs.isfile(epsfile) then
+ os.execute(format("ps2pdf %s %s",epsfile,pdffile))
+ -- todo: direct call but not now
+ if lfs.isfile(pdffile) then
+ context.externalfigure( { pdffile }, { object = variables.no } )
+ else
+ logs.report("plugins","pstricks run failed, no pdf file")
+ end
+ else
+ logs.report("plugins","pstricks run failed, no ps file")
+ end
+end
diff --git a/tex/context/base/m-pstricks.mkii b/tex/context/base/m-pstricks.mkii
new file mode 100644
index 000000000..3ada9e07e
--- /dev/null
+++ b/tex/context/base/m-pstricks.mkii
@@ -0,0 +1,127 @@
+%D \module
+%D [ file=m-pstricks,
+%D version=1997.01.15,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PSTRICKS\ Connections,
+%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.
+
+% pstricks is not supported in context mkii (it's no problem doing that
+% but as we also need to support latex it would become quite messy so for
+% context we use metapost and for latex pstricks)
+
+%M \usemodule[pstric]
+
+\letvalue{@unused}\plussixteen
+\letvalue{alloc@}\gobblefivearguments
+
+\chardef\oldbarcode\the\catcode`\| \catcode`\|=12
+
+\def\loadpstrickscolors#1%
+ {\pushmacro\dodefinecolor
+ \pushmacro\dodefinepalet
+ \pushmacro\dodefinecolorgroup
+ \def\dodefinecolor[##1][##2]%
+ {\doifassignmentelse{##2}
+ {\getparameters[pstricks][r=0,g=0,b=0,##2]%
+ \expanded{\newrgbcolor{##1}{{\pstricksr} {\pstricksg} {\pstricksb}}}}%
+ {}}%
+ \def\dodefinepalet [##1][##2]{}%
+ \def\dodefinecolorgroup[##1][##2][##3]{}%
+ \writestatus{pstricks}{loading colors from #1}%
+ \input #1 \relax
+ \popmacro\dodefinecolorgroup
+ \popmacro\dodefinepalet
+ \popmacro\dodefinecolor}
+
+\doifelse{\jobsuffix}{dvi}
+ {\input multido \relax
+ \input pstricks \relax
+ \input pst-plot \relax
+ \loadpstrickscolors{colo-rgb}}
+ {\writestatus{pstricks}{using indirect method; enable write18}}
+
+\catcode`\|=\oldbarcode
+
+\def\loadpstricksmodule[#1]%
+ {\chardef\oldbarcode\the\catcode`\|
+ \catcode`\|=12
+ \readfile{#1}{}{}%
+ \catcode`\|=\oldbarcode}
+
+%D The next piece of code is for John Culleton who suggested to
+%D handle \PSTRICKS\ in a similar fashion as \METAPOST, i.e.\
+%D using a child process. For the moment there is no support
+%D for passing environments, so these should be called
+%D explicitly inside this environment.
+
+\unprotect
+
+%D \startPSTRICKS[offset=2pt] ... \stopPSTRICKS
+%D
+%D works in both dvi and pdf mode
+%D
+%D % \usemodule[pstric]
+%D
+%D \startPSTRICKS
+%D \pspicture(0,0)(10,10)
+%D \dorecurse{10}{\psline(0,0)(\recurselevel,10)}
+%D \dorecurse{10}{\psline(0,0)(10,\recurselevel)}
+%D \endpspicture
+%D \stopPSTRICKS
+
+\def\startPSTRICKS
+ {\dosingleempty\dostartPSTRICKS}
+
+% \ifx\startTEXapplication\undefined
+%
+% \long\def\dostartPSTRICKS[#1]#2\stopPSTRICKS
+% {\doifelse{\jobsuffix}{dvi}
+% {#2}
+% {\bgroup
+% \setbuffer[pstricks]%
+% \usemodule[pstric]%
+% \setbox\scratchbox\hbox{#2}%
+% % There is probably a nicer way to handle this
+% \immediate\openout\scratchwrite=\bufferprefix dim.tmp
+% \immediate\write\scratchwrite{\dimen0=\the\ht\scratchbox}%
+% \immediate\write\scratchwrite{\dimen2=\the\wd\scratchbox}%
+% \immediate\closeout\scratchwrite
+% % Quick and dirty
+% \startTEXpage[#1]\box\scratchbox\stopTEXpage
+% \endbuffer
+% % Here we go!
+% %\immediate\write18{texexec \bufferprefix pstricks.tmp --once --batch}%
+% %\immediate\write18{dvips -G0 -Ppdf \bufferprefix pstricks -o}%
+% %\immediate\write18{ps2pdf \bufferprefix pstricks.ps \bufferprefix pstricks.pdf}%
+% \executesystemcommand{texexec \bufferprefix pstricks.tmp --once --batch}%
+% \executesystemcommand{dvips -G0 -Ppdf \bufferprefix pstricks -o}%
+% \executesystemcommand{texmfstart pstopdf \bufferprefix pstricks.ps \bufferprefix pstricks.pdf}%
+% % We pick up the dimensions from the scratch file.
+% \readlocfile{\bufferprefix pstricks-dim.tmp}{}{}%
+% % Since the graphic is put on a page (sigh) by dvips/gs
+% % we need to shift it around a bit.
+% \setbox\scratchbox\hbox
+% {\externalfigure[\bufferprefix pstricks.pdf][\c!object=\v!no]}%
+% \setbox\scratchbox\hbox
+% {\lower\ht\scratchbox\hbox{\raise\dimen2\box\scratchbox}}%
+% \wd\scratchbox\dimen0
+% \ht\scratchbox\dimen2
+% \dp\scratchbox\zeropoint
+% \box\scratchbox
+% \egroup}}
+%
+% \fi
+
+\long\def\dostartPSTRICKS[#1]#2\stopPSTRICKS
+ {\doifelse{\jobsuffix}{dvi} % will some day move to app as switch
+ {\hbox{#2}}
+% {\startTEXapplication[#1]{\usemodule[pstric]}#2\stopTEXapplication}}
+ {\startTEXapplication[#1]{}#2\stopTEXapplication}}
+
+\protect \endinput
diff --git a/tex/context/base/m-pstricks.mkiv b/tex/context/base/m-pstricks.mkiv
new file mode 100644
index 000000000..c800ec199
--- /dev/null
+++ b/tex/context/base/m-pstricks.mkiv
@@ -0,0 +1,66 @@
+%D \module
+%D [ file=m-pstricks,
+%D version=2010.03.14,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PSTRICKS\ Connections,
+%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.
+
+\ctxloadluafile{m-pstricks}{}
+
+%D \startbuffer
+%D \usePSTRICKSmodule[pst-barcode]
+%D
+%D \startPSTRICKS
+%D \pspicture(-4mm,-1mm)(38mm,26mm)
+%D \psbarcode{9781860742712}{includetext guardwhitespace}{ean13}%
+%D \endpspicture
+%D \stopPSTRICKS
+%D \stopbuffer
+%D
+%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection
+
+\unprotect
+
+% best we can make a special colors module
+%
+% \let\@unused\plussixteen
+% \let\alloc@ \gobblefivearguments
+%
+% \def\loadpstrickscolors#1%
+% {\pushmacro\dodefinecolor
+% \pushmacro\dodefinepalet
+% \pushmacro\dodefinecolorgroup
+% \def\dodefinecolor[##1][##2]%
+% {\doifassignmentelse{##2}
+% {\getparameters[pstricks][r=0,g=0,b=0,##2]%
+% \expanded{\newrgbcolor{##1}{{\pstricksr} {\pstricksg} {\pstricksb}}}}%
+% {}}%
+% \def\dodefinepalet [##1][##2]{}%
+% \def\dodefinecolorgroup[##1][##2][##3]{}%
+% \writestatus{pstricks}{loading colors from #1}%
+% \input #1 \relax
+% \popmacro\dodefinecolorgroup
+% \popmacro\dodefinepalet
+% \popmacro\dodefinecolor}
+%
+% \input multido \relax
+% \input pstricks \relax
+% \input pst-plot \relax
+%
+% \loadpstrickscolors{colo-rgb}
+
+\definebuffer[PSTRICKS]
+
+\unexpanded\def\processPSTRICKS {\ctxlua{plugins.pstricks.process(\thebuffernumber{PSTRICKS})}}
+\unexpanded\def\usePSTRICKSmodule[#1]{\ctxlua{plugins.pstricks.usemodule("#1")}}
+\unexpanded\def\setPSTRICKS #1{\setbuffer[def-\thebuffernumber{PSTRICKS}]#1\endbuffer}
+
+\let\stopPSTRICKS\processPSTRICKS
+
+\protect \endinput
diff --git a/tex/context/base/m-pstricks.tex b/tex/context/base/m-pstricks.tex
new file mode 100644
index 000000000..28bc9f30f
--- /dev/null
+++ b/tex/context/base/m-pstricks.tex
@@ -0,0 +1,16 @@
+%D \module
+%D [ file=m-pstricks,
+%D version=1997.01.15,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PSTRICKS\ Connections,
+%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.
+
+\loadmarkfile{m-pstricks}
+
+\endinput
diff --git a/tex/context/base/m-punk.mkiv b/tex/context/base/m-punk.mkiv
new file mode 100644
index 000000000..65bf03974
--- /dev/null
+++ b/tex/context/base/m-punk.mkiv
@@ -0,0 +1,243 @@
+%D \module
+%D [ file=m-punk,
+%D version=2008.04.15,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Punk Support,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\ifx\luaversion\undefined \endinput \fi
+
+% At some point the font generation code will move into the
+% ConTeXt MkIV kernel.
+
+\startluacode
+do
+ local concat = table.concat
+ local chardata = characters.data
+ local fontdata = fonts.ids
+
+ fonts.mp = fonts.mp or { }
+
+ fonts.mp.version = fonts.mp.version or 1.11
+ fonts.mp.inline = true
+ fonts.mp.cache = containers.define("fonts", "mp", fonts.mp.version, true)
+
+ metapost.characters = metapost.characters or { }
+
+-- todo: use table share as in otf
+
+ local characters, descriptions = { }, { }
+ local factor, l, n, w, h, d, total, variants = 100, { }, 0, 0, 0, 0, 0, 0, true
+
+ -- A next version of mplib will provide the tfm font information which
+ -- gives better glyph dimensions, plus additional kerning information.
+
+ local flusher = {
+ startfigure = function(chrnum,llx,lly,urx,ury)
+ l, n = { }, chrnum
+ w, h, d = urx - llx, ury, -lly
+ total = total + 1
+ inline = fonts.mp.inline
+ end,
+ flushfigure = function(t)
+ for i=1, #t do
+ l[#l+1] = t[i]
+ end
+ end,
+ stopfigure = function()
+ local cd = chardata[n]
+ if inline then
+ descriptions[n] = {
+ -- unicode = n,
+ name = cd and cd.adobename,
+ width = w*100,
+ height = h*100,
+ depth = d*100,
+ boundingbox = { 0, -d, w, h },
+ }
+ characters[n] = {
+ commands = { -- todo: xforms, should happen in backend
+ { "special", "pdf: " .. concat(l," ") },
+ }
+ }
+ else
+ descriptions[n] = {
+ -- unicode = n,
+ name = cd and cd.adobename,
+ width = w*100,
+ height = h*100,
+ depth = d*100,
+ boundingbox = { 0, -d, w, h },
+ }
+ characters[n] = {
+ commands = {
+ { "image", { stream = concat(l," "), bbox = { 0, -d*65536, w*65536, h*65536 } } },
+ }
+ }
+ end
+ end
+ }
+
+ metapost.characters.instances = metapost.characters.instances or 10
+
+ function metapost.characters.process(mpxformat, name, instances, scalefactor)
+ statistics.starttiming(metapost.characters)
+ scalefactor = scalefactor or 1
+ instances = instances or metapost.characters.instances or 10
+ local fontname = file.removesuffix(file.basename(name))
+ local hash = file.robustname(string.format("%s %05i %03i", fontname, scalefactor*1000, instances))
+ local lists = containers.read(fonts.mp.cache(), hash)
+ if not lists then
+ statistics.starttiming(flusher)
+ -- we can use a format per font
+ local data = io.loaddata(resolvers.find_file(name))
+ metapost.reset(mpxformat)
+ metapost.set_outer_color(2) -- no outer color and no reset either
+ lists = { }
+ for i=1,instances do
+ list = { }
+ characters, descriptions = { }, { }
+ metapost.process(
+ mpxformat,
+ {
+ "randomseed := " .. i*10 .. ";",
+ "scale_factor := " .. scalefactor .. " ;",
+ data
+ },
+ false,
+ flusher
+ )
+ lists[i] = {
+ designsize = 655360,
+ name = string.format("%s-%03i",hash,i),
+ parameters = {
+ slant = 0,
+ space = 333 * scalefactor,
+ space_stretch = 166.5 * scalefactor,
+ space_shrink = 111 * scalefactor,
+ x_height = 431 * scalefactor,
+ quad =1000 * scalefactor,
+ extra_space = 0
+ },
+ ["type"] = "virtual",
+ characters = characters,
+ descriptions = descriptions,
+ -- embedding = "subset",
+ -- mkiv:
+ spacer = "space",
+ unit = 1000,
+ shared = { },
+ unique = { },
+ }
+ end
+ metapost.reset(mpxformat) -- saves memory
+ lists = containers.write(fonts.mp.cache(), hash, lists)
+ statistics.stoptiming(flusher)
+ end
+ variants = variants + #lists
+ statistics.stoptiming(metapost.characters)
+ return lists
+ end
+
+ function fonts.vf.aux.combine.commands.metafont(g,v)
+ local size = g.specification.size
+ local data = metapost.characters.process(v[2],v[3],v[4],size/655360)
+ local list, t = { }, { }
+ for d=1,#data do
+ t = data[d]
+ t = fonts.tfm.scale(t, -1000)
+ local id = font.nextid()
+ t.fonts = { { id = id } }
+ fontdata[id] = t
+ fonts.vf.aux.compose_characters(t)
+ list[d] = font.define(t)
+ end
+ for k=1,#t do
+ g[k] = t[k] -- kind of replace, when not present, make nil
+ end
+ g.virtualized = true
+ g.variants = list
+ end
+
+ fonts.define.methods.install( "punk", {
+ { "metafont", "mfplain", "punkfont.mp", 10 },
+ } )
+
+ cases.actions[99] = function(current)
+ local used = fontdata[current.font].variants
+ if used then
+ local f = math.random(1,#used)
+ current.font = used[f]
+ return current, true
+ else
+ return current, false
+ end
+ end
+
+ metapost.characters.flusher = flusher
+
+ statistics.register("metapost font generation", function()
+ local time = statistics.elapsedtime(flusher)
+ if total > 0 then
+ return string.format("%i glyphs, %.3f seconds runtime, %i glyphs/second", total, time, total/time)
+ else
+ return string.format("%i glyphs, %.3f seconds runtime", total, time)
+ end
+ end)
+
+ statistics.register("metapost font loading",function()
+ local time = statistics.elapsedtime(metapost.characters)
+ if variants > 0 then
+ return string.format("%.3f seconds, %i instances, %0.3f instances/second", time, variants, variants/time)
+ else
+ return string.format("%.3f seconds, %i instances", time, variants)
+ end
+ end)
+
+end
+\stopluacode
+
+\unexpanded\def\EnableRandomPunk {\setcharactercasing[99]}
+\unexpanded\def\RandomPunk {\groupedcommand\EnableRandomPunk\donothing}
+\unexpanded\def\StartRandomPunk {\begingroup\EnableRandomPunk}
+\unexpanded\def\StopRandomPunk {\endgroup}
+
+\starttypescript [serif] [punk] [default]
+ \setups[font:fallback:serif] % no style variants yet
+ \definefontsynonym [Serif] [demo@punk]
+\stoptypescript
+
+\starttypescript [punk]
+ \definetypeface [punk] [rm] [serif] [punk] [default]
+\stoptypescript
+
+\definefontfeature[punknova][mode=node,script=latn,rand=yes,kern=yes,liga=yes,tlig=yes]
+
+\starttypescript [serif] [punknova]
+ \setups[font:fallback:serif] % no style variants yet, actually it's a sans
+ \definefontsynonym [Serif] [file:punknova] [features=punknova]
+\stoptypescript
+
+\starttypescript [punknova]
+ \definetypeface [punknova] [rm] [serif] [punknova] [default]
+\stoptypescript
+
+\endinput
+
+\usetypescript[punk]
+
+\setupbodyfont[punk,14pt]
+
+\starttext
+ \definedfont[demo@punk at 10pt]hello world\par
+ \definedfont[demo@punk at 12pt]hello world\par
+ \definedfont[demo@punk at 16pt]hello world\par
+ \definedfont[demo@punk at 20pt]hello world\par
+\stoptext
+
diff --git a/tex/context/base/m-punk.tex b/tex/context/base/m-punk.tex
new file mode 100644
index 000000000..fe7ec85cc
--- /dev/null
+++ b/tex/context/base/m-punk.tex
@@ -0,0 +1,3 @@
+% this file will disasppear but we need it as it is still in tex live
+
+\loadmarkfile{m-punk}
diff --git a/tex/context/base/m-quest.tex b/tex/context/base/m-quest.tex
new file mode 100644
index 000000000..d20c86c93
--- /dev/null
+++ b/tex/context/base/m-quest.tex
@@ -0,0 +1,232 @@
+%D \module
+%D [ file=m-invull,
+%D version=1995.01.10,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Exercise,
+%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.
+
+%I Invuloefeningen kunnen worden vormgegeven met het
+%I de commando's:
+%I
+%I \definieerinvulwoord[trefwoord]{woord,woord}
+%I \invulwoord[trefwoord]
+%I \invulwoord{woord,woord,...}
+%I
+%I Daarbij kan het een en ander worden ingesteld met
+%I
+%I \stelinvullenin[status=,nummer=,links=,rechts=,letter=]
+%P
+%I Er zijn drie manieren om woorden in te vullen. De meest
+%I eenvoudige is die waarbij de in te vullen woorden in de
+%I tekst staan.
+%I
+%I bla bla \invulwoord{een,alfa} bla bla bla bla bla bla
+%I bla bla bla bla bla bla bla bla \invulwoord{twee,beta}.
+%I
+%I De gezette tekst hangt af van de instellingen:
+%I
+%I [status=leeg] ________
+%I [status=vol,nummer=1] 'een' respectievelijk 'twee'
+%I [status=vol,nummer=2] 'alfa' respectievelijk 'beta'
+%I
+%I Het nummer heeft dus betrekking op het volgnummer in de
+%I opgegeven reeks.
+%P
+%I Bij de tweede manier worden eerste de alternatieven
+%I gedefinieerd:
+%I
+%I \definieerinvulwoord{een,alfa}
+%I \definieerinvulwoord{twee,beta}
+%I
+%I die vervolgens worden opgeroepen:
+%I
+%I bla \invulwoord[+] bla bla bla bla bla bla bla bla bla
+%I bla bla bla bla bla bla bla bla bla bla \invulwoord[+].
+%I
+%I De mogelijke instellingen komen overeen met die van de
+%I eerste manier.
+%P
+%I De derde manier is een variant op de tweede. Bij grote
+%I teksten kan men het overzicht kwijtraken. Het is daarom
+%I mogelijk 'logische' namen toe te kennen aan woorden.
+%I
+%I \definieerinvulwoord[a]{een,alfa}
+%I \definieerinvulwoord[b]{twee,beta}
+%I
+%I die vervolgens worden opgeroepen:
+%I
+%I bla \invulwoord[a] bla bla bla bla bla bla bla bla bla
+%I bla bla bla bla bla bla bla bla bla bla \invulwoord[b].
+%I
+%I Dit maakt het bovendien mogelijk woorden meerdere malen
+%I (in een willekeurige volgorde op te roepen:
+%I
+%I bla \invulwoord[a] bla \invulwoord[b] bla bla bla bla
+%I bla bla bla bla \invulwoord[b] bla bla \invulwoord[a].
+%P
+%I Bij [status=leeg] wordt een streep gezet die in breedte
+%I overeenkomt met het woord dat er eigenlijk hoort te
+%I staan. De ingevulde tekst komt visueel daardoor overeen
+%I met de in te vullen tekst, wat vergelijken vereenvoudigd.
+%I
+%I Met [status=reset] worden enkele tellers weer op 0 gezet.
+%I Dit kan nodig zijn als meerdere invuloefeningen in een
+%I tekst worden gezet.
+%I
+%I Als \versie[voorlopig] is ingesteld, worden bij invullers
+%I zonder logische namen tussen haakjes de volgnummers
+%I getoond.
+
+%S \startsetup
+%S \command
+%S [stelinvullenin]
+%S \type
+%S [\c!vars!]
+%S \variable
+%S [\c!letter]
+%S [\v!normaal,\v!vet,\v!schuin,\v!vetschuin,\v!type,\v!kap,
+%S \v!klein...,\c!command!]
+%S [\v!vet]
+%S \variable
+%S [\c!links]
+%S [\c!text!]
+%S []
+%S \variable
+%S [\c!rechts]
+%S [\c!text!]
+%S []
+%S \variable
+%S [\c!status]
+%S [\v!leeg,\v!vol,\v!reset]
+%S [\v!vol]
+%S \variable
+%S [\c!nummer]
+%S [\c!number!]
+%S [1]
+%S \variable
+%S [\c!lijn]
+%S [\v!aan,\v!uit]
+%S [\v!aan]
+%S \stopsetup
+
+%S \startsetup
+%S \command
+%S [invulwoord]
+%S \type
+%S [\c!ref!,\c!opt!\c!val!\c!opt!\c!args!]
+%S \value
+%S [\c!text!]
+%S \stopsetup
+
+%S \startsetup
+%S \command
+%S [definieerinvulwoord]
+%S \type
+%S [\c!ref!,\c!opt!\c!val!\c!args!]
+%S \value
+%S [\c!text!]
+%S \stopsetup
+
+% Mogelijke uitbreidingen
+%
+% - [breedte=,passend,ruim]
+% - invullijst met nummers
+% - weergeven lijst tijdens definitie blokkeren
+% - door elkaar definieren
+
+\unprotect
+
+\definesystemvariable {iv}
+
+\definereferenceconstant {fillin} {:iv:}
+
+\newcount\invulteller \newcount\invulput \newcount\invulget
+
+\def\stelinvullenin
+ {\dosingleargument\dostelinvullenin}
+
+\def\dostelinvullenin[#1]%
+ {\getparameters[\??iv][#1]%
+ \doif\@@ivstate\v!reset
+ {\global\invulput\zerocount
+ \global\invulget\zerocount
+ \let\@@ivstate\empty}}
+
+\def\definieerinvulwoord
+ {\dosingleempty\dodefinieerinvulwoord}
+
+\def\dodefinieerinvulwoord[#1]#2%
+ {\iffirstargument
+ \setgvalue{\r!fillin#1}{\simpleinvulwoord{#2}}%
+ \else
+ \global\advance\invulput \plusone
+ \setgvalue{\r!fillin\the\invulput}{\simpleinvulwoord{#2}}%
+ \fi
+ \doifconcepttracing
+ {\ifnum\invulput>\zerocount
+ \setbox\scratchbox\hbox{~\ttx(\the\invulput)}%
+ \wd\scratchbox\zeropoint
+ \box\scratchbox
+ \par
+ \fi}}
+
+\def\dosimpleinvulwoord#1%
+ {\ifnum\@@ivnumber>\zerocount \advance\invulteller \plusone \fi
+ \ifnum\invulteller=\@@ivnumber\relax
+ \bgroup
+ \doconvertfont\@@ivstyle
+ {\@@ivleft
+ \doifelse\@@ivstate\v!empty
+ {\doifelse\@@ivrule\v!on\leeginvulwoord\geeninvulwoord}
+ {\doifelse\@@ivrule\v!on\underbar \firstofoneargument}%
+ {#1}%
+ \@@ivright}%
+ \egroup
+ \fi}%
+
+\def\simpleinvulwoord#1%
+ {\ifnum\@@ivnumber>0
+ \invulteller\zerocount
+ \processcommalist[#1]\dosimpleinvulwoord
+ \else
+ \dosimpleinvulwoord{#1}%
+ \fi}
+
+\def\complexinvulwoord[#1]%
+ {\bgroup
+ \doifsomething{#1}
+ {\global\advance\invulget \plusone
+ \doconvertfont\@@ivstyle
+ {\@@ivleft\getvalue{\r!fillin\the\invulget}\@@ivright}}
+ {\doconvertfont\@@ivstyle
+ {\@@ivleft\getvalue{\r!fillin #1}\@@ivright}}%
+ \egroup}
+
+\definecomplexorsimple\invulwoord
+
+\def\leeginvulwoord#1%
+ {{\let\redounderbar\dodounderbar
+ \def\dodounderbar##1{\redounderbar{\hphantom{##1}}}%
+ \underbar{#1}}}
+
+\def\geeninvulwoord#1%
+ {{\def\dodounderbar##1{\hphantom{##1}}%
+ \underbar{#1}}}
+
+% when nummer > 0, then commalist processing; beware of $(1,2)$, use { } there
+
+\stelinvullenin
+ [\c!number=0,
+ \c!style=\v!bold,
+ \c!rule=\v!on,
+ \c!left=,
+ \c!right=,
+ \c!state=]
+
+\protect \endinput
diff --git a/tex/context/base/m-r.tex b/tex/context/base/m-r.tex
new file mode 100644
index 000000000..bf7b07a14
--- /dev/null
+++ b/tex/context/base/m-r.tex
@@ -0,0 +1,174 @@
+%D \module
+%D [ file=m-r,
+%D version=2006.06.06,
+%D title=\CONTEXT\ Modules,
+%D subtitle=R Support,
+%D author={Johan Sandblom \& Hans Hagen},
+%D date=\currentdate,
+%D copyright={PRAGMA / Johan Sandblom}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+%D The following R-processor is a variation on Johan Sandblom's
+%D prototype.
+%D
+%D We can combine both variants in one macro definition. Also, we
+%D can minimize the number of runs by checking for a change.
+
+%D JS: The call to R has \type {-q} in order to prevent banner,
+%D \type {--save} to make sure it saves the workspace after the run,
+%D \type {--restore} to make sure it reads any workspace from a
+%D previous session.
+
+%D An easier and better solution is to use the buffering mechanisms:
+
+\def\Rbufferprefix{r-}
+
+\newcounter\nofRfiles
+
+\def\Rfile{\TEXbufferfile{\Rbufferprefix\nofRfiles}}%
+
+\def\startR
+ {\doglobal\increment\nofRfiles
+ \dostartbuffer[\Rbufferprefix\nofRfiles][startR][stopR]}
+
+\def\stopR
+ {\doifmode{*\v!first}\runR
+ \typefile{\Rfile.out}}
+
+\def\startRhidden
+ {\doglobal\increment\nofRfiles
+ \dostartbuffer[\Rbufferprefix\nofRfiles][startRhidden][stopRhidden]}
+
+\def\stopRhidden
+ {\doifmode{*\v!first}\runR}
+
+\def\runR
+ {\executesystemcommand{texmfstart
+ --ifchanged=\Rfile\space --direct R
+ CMD BATCH -q --save --restore \Rfile\space \Rfile.out}}
+
+\protect \doifnotmode{demo}{\endinput}
+
+% Johan's test file:
+
+\usemodule[r]
+
+\def\R{R}
+
+\setupcolors[state=start]
+
+\setuptyping
+ [Rtype]
+ [color=darkgreen]
+
+\starttext
+
+First a test of whether the workspace is persistent:
+bla
+
+\startR
+a <- "bla"
+b <- "blabla"
+ls()
+\stopR
+
+One \R run ends, another begins.
+
+\startR
+ls()
+\stopR
+
+Now follows a hidden \R run which cleans the R workspace
+
+\startRhidden
+rm(list=ls())
+save.image()
+\stopRhidden
+
+What is in the workspace now?
+
+\startR
+ls()
+\stopR
+
+Then a small test of generating a graphic, in this case a pdf
+\startR
+ushape <- c(rexp(500000), 12-rexp(500000))
+pdf("ushape.pdf")
+par(mfrow=c(1,2))
+hist(ushape)
+plot(density(ushape), main="Density")
+dev.off()
+\stopR
+
+The graphic \type{ushape.pdf} can be included in the standard \CONTEXT\ way
+\startbuffer
+\placefigure{An ugly distribution}{\externalfigure[ushape]}
+\stopbuffer
+\typebuffer
+\getbuffer
+
+\startR
+x <- rnorm(900)
+y <- rexp(900)
+# test comment
+f <- gl(9,9,900)
+summary(aov(y~x+Error(f)))
+library(lattice)
+pdf("lattice.pdf")
+xyplot(y~x|f)
+dev.off()
+\stopR
+
+With \type{Sweave} lattice graphics calls must be enclosed in
+\type{print()} statements but that is not necessary here.
+
+\startbuffer
+\placefigure[here]{Lattice graphics}{\externalfigure[lattice]}
+\stopbuffer
+\typebuffer
+\getbuffer
+
+A test string with nasty characters. In \R, the result of a statement
+is not printed by default. Enclosing the statement in parentheses,
+however causes the parser to see only the value of the statement and
+applying the \type{print()} method.
+\startR
+(test <- ".*\\\\ [[{[{]{[{[{}\]\}=?!+%#|<|>@$")
+cat(test)
+\stopR
+
+A combination
+\startbuffer
+\placefigure{A combination of two previously used graphics}{
+\startcombination[2*1]
+ {\externalfigure[ushape][width=.4\textwidth]}{The first graphic, rescaled}
+ {\externalfigure[lattice][width=.4\textwidth]}{The second graphic, rescaled}}
+\stopcombination
+\stopbuffer
+\typebuffer
+\getbuffer
+
+Testing a function definition.
+
+\startR
+a.df <- data.frame(a=1:2, b=rnorm(2))
+a.df$a
+testfunction <- function(a=NULL, ...) {
+ for(i in 1:length(a)) {
+ gsub(a[[i]], "([a-r]|[A-R])", "bla")}
+ print(a)}
+\stopR
+
+What is in the workspace now?
+
+\startR
+ls()
+\stopR
+
+\stoptext
diff --git a/tex/context/base/m-steps.mkii b/tex/context/base/m-steps.mkii
new file mode 100644
index 000000000..3e1f86312
--- /dev/null
+++ b/tex/context/base/m-steps.mkii
@@ -0,0 +1,83 @@
+%D \module
+%D [ file=m-steps,
+%D version=2001.05.28,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Step Charts \& Tables,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE / 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.
+
+%D The \XML\ interface:
+
+\unprotect
+
+\defineXMLdirective [stepchart] [charts] \setupSTEPcharts
+\defineXMLdirective [stepchart] [cells] \setupSTEPcells
+\defineXMLdirective [stepchart] [texts] \setupSTEPtexts
+\defineXMLdirective [stepchart] [lines] \setupSTEPlines
+
+\defineXMLdirective [steptable] [tables] \setupSTEPtables
+\defineXMLdirective [steptable] [cells] \setupSTEPcells
+\defineXMLdirective [steptable] [texts] \setupSTEPtexts
+\defineXMLdirective [steptable] [lines] \setupSTEPlines
+
+\defineXMLpickup[stepchart][@@STPC]
+ {\bgroup
+ \defineXMLpush[top]%
+ \defineXMLpush[bot]%
+ \defineXMLenvironment[lines][@@STEL]
+ {\expanded{\startlines[\theXMLarguments{@@STEL}]}}
+ {\stoplines}%
+ \defineXMLenvironment[cells][@@STEC]
+ {\XMLerase{top}\XMLerase{bot}}
+ {\expanded{\cells[\theXMLarguments{@@STEC}]{\XMLpop{top}}{\XMLpop{bot}}}}%
+ \defineXMLenvironment[texts][@@STET]
+ {\XMLerase{top}\XMLerase{bot}}
+ {\expanded{\texts[\theXMLarguments{@@STET}]{\XMLpop{top}}{\XMLpop{bot}}}}%
+ \defineXMLenvironmentpush[cell][@@STEC]
+ {\XMLerase{cell}}
+ {\expanded{\cell [\theXMLarguments{@@STEC}]{\XMLpop{cell}}}}%
+ \defineXMLenvironmentpush [text] [@@STET]
+ {\XMLerase{text}}
+ {\expanded{\text [\theXMLarguments{@@STET}]{\XMLpop{text}}}}%
+ \expanded{\startSTEPchart[\theXMLarguments{@@STPC}]}}
+ {\stopSTEPchart
+ \egroup}
+
+\defineXMLpickup[steptable][@@STPT]
+ {\bgroup
+ \defineXMLenvironment[lines][@@STEL]
+ {\expanded{\startlines[\theXMLarguments{@@STEL}]}}
+ {\stoplines}%
+ \defineXMLargument[cell][@@STEC]
+ {\expanded{\cell[\theXMLarguments{@@STEC}]}}%
+ \defineXMLargument[text][@@STET]
+ {\expanded{\text[\theXMLarguments{@@STET}]}}%
+ \defineXMLargument[prep]
+ {\prep}%
+ \expanded{\startSTEPtable[\theXMLarguments{@@STPT}]}}
+ {\stopSTEPtable
+ \egroup}
+
+\defineXMLpickup[stepaligntable][@@STPT]
+ {\bgroup
+ \defineXMLenvironment[lines][@@STEL]
+ {\expanded{\setupSTEPlines[\theXMLarguments{@@STEL}]}}
+ {}%
+ \defineXMLpush[c1]\defineXMLpush[c2]\defineXMLpush[c3]%
+ \defineXMLenvironment[cells][@@STEC]
+ {\XMLerase{c1}\XMLerase{c1}\XMLerase{c3}}
+ {\expanded{\cells[\theXMLarguments{@@STEC}]{\XMLpop{c1}}{\XMLpop{c2}}{\XMLpop{c3}}}}%
+ \defineXMLargument[text][@@STET]
+ {\expanded{\text[\theXMLarguments{@@STET}]}}%
+ \defineXMLargument[prep]
+ {\prep}%
+ \expanded{\startSTEPaligntable[\theXMLarguments{@@STPT}]}}
+ {\stopSTEPaligntable
+ \egroup}
+
+\protect \endinput
diff --git a/tex/context/base/m-steps.mkiv b/tex/context/base/m-steps.mkiv
new file mode 100644
index 000000000..9bb56c532
--- /dev/null
+++ b/tex/context/base/m-steps.mkiv
@@ -0,0 +1,20 @@
+%D \module
+%D [ file=m-steps,
+%D version=2001.05.28,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Step Charts \& Tables,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE / 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.
+
+%D The \XML\ interface:
+
+\unprotect
+
+\writestatus\m!systems{The steps mkiv xml interface is not yet defined!}
+
+\protect \endinput
diff --git a/tex/context/base/m-steps.tex b/tex/context/base/m-steps.tex
new file mode 100644
index 000000000..1f6a37403
--- /dev/null
+++ b/tex/context/base/m-steps.tex
@@ -0,0 +1,835 @@
+%D \module
+%D [ file=m-steps,
+%D version=2001.05.28,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Step Charts \& Tables,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE / 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.
+
+%D When I need this module, I will reimplement it by using the new
+%D sometxt macro. Anyhow, it reflects the state of 2001.
+
+\unprotect
+
+% temp hack :
+
+% \ifx\v!kleinkorps\undefined \let\v!kleinkorps\setsmallbodyfont \fi
+
+% end of hack
+
+\definecolor [STEPlinecolor] [s=.5]
+\definecolor [STEPframecolor] [s=.7]
+\definecolor [STEPbackgroundcolor] [s=.9]
+
+\def\@@STPF{@@STPF} % frames
+
+\def\@@STPC{@@STPC} % charts
+\def\@@STPT{@@STPT} % tables
+
+\def\@@STEC{@@STEC} % cells
+\def\@@STET{@@STET} % tables
+\def\@@STEL{@@STEL} % lines
+
+\def\setupSTEPcharts{\dodoubleargument\getparameters[\@@STPC]}
+\def\setupSTEPtables{\dodoubleargument\getparameters[\@@STPT]}
+\def\setupSTEPcells {\dodoubleargument\getparameters[\@@STEC]}
+\def\setupSTEPtexts {\dodoubleargument\getparameters[\@@STET]}
+\def\setupSTEPlines {\dodoubleargument\getparameters[\@@STEL]}
+
+\setupSTEPcharts
+ [\c!before=\blank,
+ \c!after=\blank,
+ %\c!distance=.25em, % nvt
+ \c!hoffset=1em,
+ \c!voffset=1ex,
+ \c!method=1,
+ \c!height=2ex,
+ \c!offset=.15\bodyfontsize]
+
+\setupSTEPtables
+ [\c!before=\blank,
+ \c!after=\blank,
+ \c!distance=.25em,
+ %\c!hoffset=1em, % nvt
+ \c!voffset=1ex,
+ \c!method=1,
+ \c!width=4em,
+ \c!offset=.15\bodyfontsize]
+
+\setupSTEPcells
+ [\c!alternative=24,
+ \c!background=\v!color,
+ \c!backgroundcolor=STEPbackgroundcolor,
+ \c!rulethickness=.1\bodyfontsize,
+ \c!framecolor=STEPframecolor,
+ \c!offset=.25\bodyfontsize,
+ \c!style=,
+ \c!color=]
+
+\setupSTEPtexts
+ [\c!alternative=24,
+ \c!background=\v!color,
+ \c!backgroundcolor=STEPbackgroundcolor,
+ \c!rulethickness=.1\bodyfontsize,
+ \c!framecolor=STEPframecolor,
+ \c!offset=.25\bodyfontsize,
+ \c!style=\v!smallbodyfont,
+ \c!color=]
+
+\setupSTEPlines
+ [\c!alternative=1,
+ \c!rulethickness=.15\bodyfontsize,
+ \c!color=STEPlinecolor]
+
+\def\initializeSTEP
+ {\initializeSTET \initializeSTEC \initializeSTEL}
+
+\def\initializeSTPC
+ {\freezedimenmacro\@@STPCoffset
+ \startMPdrawing
+ line_v_offset := \@@STPCoffset ;
+ line_method := \@@STPCmethod ; % only charts
+ \stopMPdrawing}
+
+\def\initializeSTPT
+ {\freezedimenmacro\@@STPToffset
+ \startMPdrawing
+ line_h_offset := \@@STPToffset ;
+ line_method := \@@STPTmethod ; % only charts
+ \stopMPdrawing}
+
+\def\initializeSTET
+ {\freezedimenmacro\@@STETrulethickness
+ \freezedimenmacro\@@STEToffset}
+
+\def\initializeSTEC
+ {\freezedimenmacro\@@STECrulethickness
+ \freezedimenmacro\@@STECoffset}
+
+\def\initializeSTEL
+ {\freezedimenmacro\@@STELrulethickness}
+
+%D ...
+
+\presetlocalframed[\@@STPF]
+
+\def\@@stepcell#1%
+ {\doattributes\@@STEC\c!style\c!color
+ {\localframed
+ [\@@STPF][\c!offset=\@@STECoffset,\c!frame=\v!off]
+ {\ignorespaces#1\unskip}}}
+
+\def\@@stepfake#1%
+ {\doattributes\@@STEC\c!style\c!color
+ {\ignorespaces#1\unskip}}
+
+\def\@@steptext#1%
+ {\doattributes\@@STET\c!style\c!color
+ {\localframed
+ [\@@STPF][\c!offset=\@@STEToffset,\c!frame=\v!off]
+ {\ignorespaces#1\unskip}}}
+
+%D The first attempt was purely \METAPOST\ based and spawned
+%D the typesetting to the \METAFUN\ handler. This method
+%D collects the cells, and directly passes them on to
+%D \METAPOST. This method is the cleanest, but has the
+%D disadvantage that one cannot embed hyperlinks or document
+%D dependent definitions in the cells. The implementation
+%D roughly looks as follows:
+%D
+%D \starttyping
+%D \def\startSTEPchart%
+%D {\bgroup
+%D \startMPdrawing
+%D input mp-step ; begin_step_chart ;
+%D \stopMPdrawing
+%D \initializeSTEP
+%D \let\cells\stepchartcells \def\cell{\cells{}}%
+%D \let\texts\stepcharttexts \def\text{\texts{}}}
+%D
+%D \def\stepchartcells#1#2%
+%D {\setMPtext{tdummy}{\strut\ignorespaces#1\unskip}% beter etex/btex
+%D \setMPtext{bdummy}{\strut\ignorespaces#2\unskip}% beter etex/btex
+%D \startMPdrawing
+%D set_step_chart_cells(\MPstring{tdummy},\MPstring{bdummy}) ;
+%D \stopMPdrawing}
+%D
+%D \def\stepcharttexts#1#2%
+%D {\setMPtext{tdummy}{\strut\ignorespaces#1\unskip}% beter etex/btex
+%D \setMPtext{bdummy}{\strut\ignorespaces#2\unskip}% beter etex/btex
+%D \startMPdrawing
+%D set_step_chart_texts(\MPstring{tdummy},\MPstring{bdummy}) ;
+%D \stopMPdrawing}
+%D
+%D \def\stopSTEPchart
+%D {\startMPdrawing
+%D end_step_chart ;
+%D \stopMPdrawing
+%D \MPdrawingdonetrue
+%D \getMPdrawing
+%D \resetMPdrawing
+%D \egroup}
+%D \stoptyping
+%D
+%D This method has the advantage that it does the job in
+%D (virtually) one pass, while the next methods need multiple
+%D passes: one to build the table, another to synchronize the
+%D positions, and a third one beause the dimensions may have
+%D changed. The last pass is a result from the fact that
+%D positions are related to the page.
+%D
+%D The second attempt was based on tabulations and used the
+%D build in position tracking mechanism, which uses two
+%D position nodes per cell.
+%D
+%D This method collects the content in token list registers
+%D and build a table from them. In the collecting pass, the
+%D graphics are build stepwise. We need to collect because the
+%D order of definitions is not the same as the order of
+%D typesetting. We show this alternative too because it
+%D demonstrates how to apply backgrounds to table cells.
+%D
+%D \starttyping
+%D \newtoks\stepsonetop \newtoks\stepstwotop
+%D \newtoks\stepsonebot \newtoks\stepstwobot
+%D \stoptyping
+%D
+%D During the collecting phase, we temporarily have to
+%D increment the name space counter.
+%D
+%D \starttyping
+%D \def\startSTEPchart%
+%D {\bgroup
+%D \resetMPdrawing
+%D \advance\noftabpositions\plusone % begin of preroll
+%D \startMPdrawing
+%D input mp-step ;
+%D begin_step_chart ;
+%D \stopMPdrawing
+%D \initializeSTEP
+%D \newcounter\cellcounter
+%D \stepsonetop\emptytoks \chardef\somesteponetop=1
+%D \stepsonebot\emptytoks \chardef\somesteponebot=1
+%D \stepstwotop\emptytoks \chardef\somesteptwotop=1
+%D \stepstwobot\emptytoks \chardef\somesteptwobot=1
+%D \let\cells\stepchartcells \def\cell{\cells{}}%
+%D \let\texts\stepcharttexts \def\text{\texts{}}}
+%D \stoptyping
+%D
+%D Now we collect the steps and texts, and in the process the
+%D graphic is built. Then we continue with building the table.
+%D
+%D Watch how we anchor the graphic to the main table box. This
+%D is needed since the graphic may be larger than the table
+%D itself. Actually, these small point took me the most time to
+%D digest, even with the right tools (anchors) already in
+%D place.
+%D
+%D \starttyping
+%D \def\stopSTEPchart
+%D {\splittabulatefalse
+%D \insidefloattrue
+%D \startMPdrawing
+%D nofcells := \cellcounter ;
+%D end_step_chart ;
+%D anchor_box(\MPpos{\tbPOSprefix origin}) ;
+%D \stopMPdrawing
+%D \MPdrawingdonetrue
+%D \advance\noftabpositions\minusone % end of preroll
+%D \setbox0=\vbox
+%D {\getMPdrawing}
+%D \resetMPdrawing
+%D \increment(\cellcounter,\cellcounter)\decrement\cellcounter
+%D \setbox2=\vbox
+%D {\definetabulate[chart][|*{\cellcounter}{ck0|}] % k0 nills space
+%D \startchart
+%D \ifcase\somesteptwotop \the\stepstwotop \NC \NR \noalign{\kern2ex} \fi
+%D \ifcase\somesteponetop \the\stepsonetop \NC \NR \noalign{\kern2ex} \fi
+%D \ifcase\somesteponebot \the\stepsonebot \NC \NR \noalign{\kern2ex} \fi
+%D \ifcase\somesteptwobot \the\stepstwobot \NC \NR \noalign{\kern2ex} \fi
+%D \noalign{\kern-2ex}%
+%D \stopchart}
+%D \hbox
+%D {\scratchdimen\wd0
+%D \advance\scratchdimen \MPllx bp
+%D \raise\MPlly bp\box0
+%D \hskip-\scratchdimen
+%D \hpos{\tbPOSprefix origin}{\box2}}
+%D \egroup}
+%D \stoptyping
+%D
+%D The steps and texts fill the (at most 4) lines that make up
+%D the table. We also feed the (automatically registerd) cell
+%D dimensions to the graphic backend.
+%D
+%D \starttyping
+%D \newcounter\cellcounter
+%D \newcounter\textcounter
+%D
+%D \def\stepchartcells#1#2%
+%D {\doloop
+%D {\ifnum\cellcounter>\textcounter
+%D \stepcharttexts{}{}%
+%D \else
+%D \exitloop
+%D \fi}%
+%D \increment\cellcounter
+%D \doifelsenothing{#1}
+%D {\startMPdrawing
+%D cells[t][\cellcounter] := origin ;
+%D \stopMPdrawing
+%D \appendtoks\NC\NC\to\stepsonetop}
+%D {\chardef\somesteponetop=0
+%D \edef\stepidentifier{\cellcounter-t-c}%
+%D \startMPdrawing
+%D initialize_area(\MPpos{b:\tbPOSprefix\stepidentifier},
+%D \MPpos{e:\tbPOSprefix\stepidentifier}) ;
+%D cells[t][\cellcounter] := pxy ;
+%D \stopMPdrawing
+%D \@EA\appendtoks\@EA\stepidentifierposition\@EA{\stepidentifier}#1\NC\to\stepsonetop}%
+%D \doifelsenothing{#2}
+%D {\startMPdrawing
+%D cells[b][\cellcounter] := origin ;
+%D \stopMPdrawing
+%D \appendtoks\NC\NC\to\stepsonebot}
+%D {\chardef\somesteponebot=0
+%D \edef\stepidentifier{\cellcounter-b-c}%
+%D \startMPdrawing
+%D initialize_area(\MPpos{b:\tbPOSprefix\stepidentifier},
+%D \MPpos{e:\tbPOSprefix\stepidentifier}) ;
+%D cells[b][\cellcounter] := pxy ;
+%D \stopMPdrawing
+%D \@EA\appendtoks\@EA\stepidentifierposition\@EA{\stepidentifier}#2\NC\to\stepsonebot}}
+%D
+%D \def\stepcharttexts#1#2% \cellcounter = nofcells
+%D {\increment\textcounter
+%D \doifelsenothing{#1}
+%D {\startMPdrawing
+%D texts[t][\cellcounter][\textcounter] := origin ;
+%D \stopMPdrawing
+%D \appendtoks\NC\NC\to\stepstwotop}
+%D {\chardef\somesteptwotop=0
+%D \edef\stepidentifier{\cellcounter-\textcounter-t-t}%
+%D \startMPdrawing
+%D initialize_area(\MPpos{b:\tbPOSprefix\stepidentifier},
+%D \MPpos{e:\tbPOSprefix\stepidentifier}) ;
+%D texts[t][\cellcounter][\textcounter] := pxy ;
+%D \stopMPdrawing
+%D \@EA\appendtoks\@EA\NC\@EA\textcellposition\@EA{\stepidentifier}#1\to\stepstwotop}%
+%D \doifelsenothing{#2}
+%D {\startMPdrawing
+%D texts[b][\cellcounter][\textcounter] := origin ;
+%D \stopMPdrawing
+%D \appendtoks\NC\NC\to\stepstwobot}
+%D {\chardef\somesteptwobot=0
+%D \edef\stepidentifier{\cellcounter-\textcounter-b-t}%
+%D \startMPdrawing
+%D initialize_area(\MPpos{b:\tbPOSprefix\stepidentifier},
+%D \MPpos{e:\tbPOSprefix\stepidentifier}) ;
+%D texts[b][\cellcounter][\textcounter] := pxy ;
+%D \stopMPdrawing
+%D \@EA\appendtoks\@EA\NC\@EA\textcellposition\@EA{\stepidentifier}#2\to\stepstwobot}}
+%D \stoptyping
+%D
+%D Here are the hooks that take care of calculating the cell
+%D dimensions.
+%D
+%D \starttyping
+%D \def\textcellposition#1{\GSC[#1:text]}
+%D \def\stepidentifierposition#1{\GSC[#1:step]}
+%D \stoptyping
+%D
+%D We abandoned this method after some testing and went for
+%D a third one. It was this third method that evolved into the
+%D current mechanism.
+%D
+%D Since this method was not that efficient, a third one was
+%D implemented, which used one position per cell. So,
+%D
+%D \blank {\bf Here starts the real implementation!} \blank
+%D
+%D Because we want to build one graphic only we need to store
+%D the graphic directives. We also need to collect the cells,
+%D which are not defined in the order they show up. This
+%D solution uses multiple passes over the definitions. First
+%D the cells and texts are processed and the associated
+%D graphics are defined in the \METAPOST\ file. Next the
+%D lines are flushed. We need to do that in a second pass,
+%D because in order to determine the nature of the line,
+%D \METAPOST\ needs to know if the start and end cells exist.
+%D This need comes from the fact that we store the shapes
+%D and lines kind of directly with their associated colors and
+%D types, so that we can change the settings in between. So,
+%D changing for instance the line color, can take place
+%D locally.
+
+\newbox\stepboxone \newbox\stepboxtwo
+\newbox\textboxone \newbox\textboxtwo
+
+%D We need to define a dedicated name space counter.
+
+\newcounter\currentstepchart
+
+\def\stepchartprefix{@sc@-\currentstepchart-}
+
+%D Next we define the initialization part of the macros.
+
+\newcounter\cellcounter
+\newcounter\textcounter
+
+\def\startSTEPchart
+ {\dosingleempty\dostartSTEPchart}
+
+\long\def\dostartSTEPchart[#1]#2\stopSTEPchart
+ {\ifinsidefloat
+ \else
+ \whitespace
+ \@@STPCbefore
+ \startbaselinecorrection
+ \setlocalhsize
+ \noindent
+ \fi
+ \vbox\bgroup
+ \setupSTEPcharts[#1]%
+ \forgetall
+ \pushMPdrawing
+ \resetMPdrawing
+ \doglobal\increment\currentstepchart
+ \startMPdrawing
+ input mp-step ;
+ begin_step_chart ;
+ \stopMPdrawing
+ \initializeSTEP
+ \initializeSTPC
+ \global\chardef\somestepboxone\plusone
+ \global\chardef\sometextboxone\plusone
+ \global\chardef\somestepboxtwo\somestepboxone
+ \global\chardef\sometextboxtwo\sometextboxone
+ \def\startlines{\bgroup\setupSTEPlines}%
+ \def\stoplines {\egroup}%
+ \def\cells{\dosingleempty\dostepchartcells}
+ \def\texts{\dosingleempty\dostepcharttexts}
+ \def\cell {\dosingleempty\docell}%
+ \def\text {\dosingleempty\dotext}%
+ \def\docell[##1]{\dostepchartcells[##1]{}}%
+ \def\dotext[##1]{\dostepcharttexts[##1]{}}
+ \doglobal\newcounter\cellcounter
+ \doglobal\newcounter\textcounter
+ \let\dostepchartcells\doSTEPchartcellsA
+ \let\dostepcharttexts\doSTEPcharttextsA
+ {#2} % pass one: cells and texts {} keeps setting local
+ \startMPdrawing
+ nofcells := \cellcounter ;
+ analyze_step_chart ;
+ \stopMPdrawing
+ \doglobal\newcounter\cellcounter
+ \doglobal\newcounter\textcounter
+ \let\dostepchartcells\doSTEPchartcellsB
+ \let\dostepcharttexts\doSTEPcharttextsB
+ {#2} % pass two: lines
+ \startMPdrawing
+ end_step_chart ;
+ % if box_found(\MPpos{\stepchartprefix origin}) :
+ % initialize_box(\MPpos{\stepchartprefix origin}) ;
+ % draw pxy ;
+ % fi ;
+ anchor_box(\MPpos{\stepchartprefix origin}) ;
+ \stopMPdrawing
+ \MPdrawingdonetrue
+ \doifelse\@@STPCmethod{0}
+ {\setbox0\null}
+ {\setbox0\vbox{\MPstaticgraphictrue\getMPdrawing}}%
+ \resetMPdrawing
+ \setbox2\vbox
+ {\offinterlineskip
+ \scratchdimen\@@STPCheight
+ \advance\scratchdimen\@@STPCoffset
+ \advance\scratchdimen\@@STPCoffset
+ \ifcase\sometextboxone \box\textboxone \vskip\scratchdimen \fi
+ \ifcase\somestepboxone \box\stepboxone \vskip\@@STPCvoffset \fi
+ \ifcase\somestepboxtwo \box\stepboxtwo \vskip\scratchdimen \fi
+ \ifcase\sometextboxtwo \box\textboxtwo \vskip\@@STPCvoffset \fi
+ \global\resetbox\stepboxone \global\resetbox\stepboxtwo % needed indeed
+ \global\resetbox\textboxone \global\resetbox\textboxtwo % needed indeed
+ %\kern-\scratchdimen % no, instead:
+ \vskip-\lastskip}
+ \hbox
+ {\scratchdimen\wd0
+ \advance\scratchdimen \MPllx bp
+ \raise\MPlly bp\box0
+ \hskip-\scratchdimen
+ \hpos{\stepchartprefix origin}{\box2}}%
+ \popMPdrawing
+ \egroup
+ \ifinsidefloat \else \stopbaselinecorrection \@@STPCafter \fi}
+
+%D The next macro looks more complicated than it is. We collect
+%D the cells in boxes. Before adding a new step cell, we padd
+%D the text rows. After adding the step cells, we flush text
+%D cells that are defined but not yet processed.
+
+\def\doSTEPchartcellsA[#1]#2#3%
+ {% synchronize texts
+ \doSTEPchartcellsAB[#1]{#2}{#3}%
+ % package steps
+ \setbox0\hbox{\doifsomething{#2}{\@@stepcell{#2}}}%
+ \setbox2\hbox{\doifsomething{#3}{\@@stepcell{#3}}}%
+ \ifdim\wd0>\zeropoint \!!doneafalse \else \!!doneatrue \fi
+ \ifdim\wd2>\zeropoint \!!donebfalse \else \!!donebtrue \fi
+ \ifdim\wd0>\wd2
+ \setbox2\hbox to \wd0{\hss\box2\hss}%
+ \else
+ \setbox0\hbox to \wd2{\hss\box0\hss}%
+ \fi
+ \if!!donea
+ \startMPdrawing
+ cells[t][\cellcounter] := nullpicture ;
+ \stopMPdrawing
+ \else
+ \global\chardef\somestepboxone\zerocount
+ \edef\stepidentifier{\stepchartprefix\cellcounter-t-c}%
+ \setbox0\hbox{\hpos{\stepidentifier}{\box0}}%
+ \bgroup
+ \iffirstargument\setupSTEPcells[#1]\fi\initializeSTEC
+ \startMPdrawing
+ initialize_box(\MPpos{\stepidentifier}) ;
+ cells[t][\cellcounter] := \MPcellsgraphic ;
+ \stopMPdrawing
+ \egroup
+ \fi
+ \if!!doneb
+ \startMPdrawing
+ cells[b][\cellcounter] := nullpicture ;
+ \stopMPdrawing
+ \else
+ \global\chardef\somestepboxtwo\zerocount
+ \edef\stepidentifier{\stepchartprefix\cellcounter-b-c}%
+ \setbox2\hbox{\hpos{\stepidentifier}{\box2}}%
+ \bgroup
+ \iffirstargument\setupSTEPcells[#1]\fi\initializeSTEC
+ \startMPdrawing
+ initialize_box(\MPpos{\stepidentifier}) ;
+ cells[b][\cellcounter] := \MPcellsgraphic ;
+ \stopMPdrawing
+ \egroup
+ \fi
+ \global\setbox\stepboxone\hbox
+ {\ifdim\wd\stepboxone>\zeropoint
+ \box\stepboxone\hskip\@@STPChoffset\else
+ \fi\box0}%
+ \global\setbox\stepboxtwo\hbox
+ {\ifdim\wd\stepboxtwo>\zeropoint
+ \box\stepboxtwo\hskip\@@STPChoffset\else
+ \fi\box2}%
+ % flush saved texts
+ \doSTEPchartcellsBA}
+
+\def\doSTEPchartcellsB[#1]#2#3%
+ {\doSTEPchartcellsAB[#1]{#2}{#3}%
+ \doSTEPchartcellsBA}
+
+\def\doSTEPchartcellsAB[#1]#2#3%
+ {\doloop
+ {\ifnum\cellcounter>\textcounter
+ \texts{}{}\else\exitloop
+ \fi}%
+ \doglobal\increment\cellcounter}
+
+\def\doSTEPchartcellsBA
+ {\scratchtoks\stepchartbuffer
+ \stepchartbuffer\emptytoks
+ \the\scratchtoks}
+
+\def\MPcellsgraphic
+ {image ( drawshape (
+ \@@STECalternative, pxy enlarged (-.5*\@@STECoffset),
+ \@@STECrulethickness, \MPcolor{\@@STECframecolor},
+ \MPcolor{\@@STECbackgroundcolor} ) )}
+
+%D Although each step can have only one associated text, the
+%D place where the text is defined determines the starting
+%D point of the connecting arrow. Although several methods are
+%D possible, we've chosen a funny collector that flushes one
+%D step text at a time.
+
+\newtoks\stepchartbuffer
+
+\def\doSTEPcharttextsA[#1]% #2 #3
+ {\dodoSTEPcharttextsA{\cellcounter}{#1}}
+
+\def\dodoSTEPcharttextsA#1#2#3#4% #1=number #2=setup
+ {\dodoSTEPcharttextsAB{#1}{#2}{#3}{#4}\dodoSTEPcharttextsA
+ \ifnum\textcounter>\cellcounter\relax
+ \doglobal\decrement\textcounter\relax
+ \else
+ \setbox0\hbox{\doifsomething{#3}{\@@steptext{#3}}}%
+ \setbox2\hbox{\doifsomething{#4}{\@@steptext{#4}}}%
+ \ifdim\wd0>\zeropoint \!!doneafalse \else \!!doneatrue \fi
+ \ifdim\wd2>\zeropoint \!!donebfalse \else \!!donebtrue \fi
+ \if!!donea
+ \setbox0\hbox to \@@STPChoffset{\hss}%
+ \startMPdrawing
+ texts[t][#1][\textcounter] := nullpicture ;
+ \stopMPdrawing
+ \else
+ \global\chardef\sometextboxone\zerocount
+ \edef\stepidentifier{\stepchartprefix#1-\textcounter-t-t}%
+ \setbox0\hbox to \@@STPChoffset
+ {\hss\hpos{\stepidentifier}{\box0}\hss}%
+ \bgroup
+ \setupSTEPtexts[#2]\initializeSTET
+ \startMPdrawing
+ initialize_box(\MPpos{\stepidentifier}) ;
+ texts[t][#1][\textcounter] := \MPtextsgraphic ;
+ \stopMPdrawing
+ \egroup
+ \fi
+ \if!!doneb
+ \setbox2\hbox to \@@STPChoffset{\hss}%
+ \startMPdrawing
+ texts[b][#1][\textcounter] := nullpicture ;
+ \stopMPdrawing
+ \else
+ \global\chardef\sometextboxtwo\zerocount
+ \edef\stepidentifier{\stepchartprefix#1-\textcounter-b-t}%
+ \setbox2\hbox to \@@STPChoffset
+ {\hss\hpos{\stepidentifier}{\box2}\hss}%
+ \bgroup
+ \setupSTEPtexts[#2]\initializeSTET
+ \startMPdrawing
+ initialize_box(\MPpos{\stepidentifier}) ;
+ texts[b][#1][\textcounter] := \MPtextsgraphic ;
+ \stopMPdrawing
+ \egroup
+ \fi
+ \global\setbox\textboxone\hbox
+ {\hbox to \wd\stepboxone{\box\textboxone\hss}\box0}
+ \global\setbox\textboxtwo\hbox
+ {\hbox to \wd\stepboxtwo{\box\textboxtwo\hss}\box2}
+ \fi}
+
+\def\doSTEPcharttextsB[#1]% #2 #3
+ {\dodoSTEPcharttextsB{\cellcounter}{#1}}
+
+\def\dodoSTEPcharttextsB#1#2#3#4% #1=number #2=setup
+ {\dodoSTEPcharttextsAB{#1}{#2}{#3}{#4}\dodoSTEPcharttextsB
+ \ifnum\textcounter>\cellcounter\relax
+ \doglobal\decrement\textcounter\relax
+ \else
+ \bgroup
+ \initializeSTEL
+ \startMPdrawing
+ lines[t][#1][\textcounter] := \MPcharttoplinesgraphic{#1}\textcounter ;
+ lines[b][#1][\textcounter] := \MPchartbotlinesgraphic{#1}\textcounter ;
+ \stopMPdrawing
+ \egroup
+ \fi}
+
+\def\dodoSTEPcharttextsAB#1#2#3#4#5% #1=number #2=setup
+ {\doglobal\increment\textcounter\relax
+ \ifnum\textcounter>\cellcounter\relax
+ \@EA\appendtoks\@EA#5\@EA{#1}{#2}{#3}{#4}\to\stepchartbuffer
+ \fi}
+
+\def\MPtextsgraphic
+ {image(drawshape(
+ \@@STETalternative, pxy enlarged (-.5*\@@STEToffset),
+ \@@STETrulethickness, \MPcolor{\@@STETframecolor},
+ \MPcolor{\@@STETbackgroundcolor} ) )}
+
+\def\MPcharttoplinesgraphic#1#2%
+ {image(drawline(
+ \@@STELalternative, get_step_chart_top_line(#1,#2),
+ \@@STELrulethickness, \MPcolor{\@@STELcolor} ) )}
+
+\def\MPchartbotlinesgraphic#1#2%
+ {image(drawline(
+ \@@STELalternative, get_step_chart_bot_line(#1,#2),
+ \@@STELrulethickness, \MPcolor{\@@STELcolor} ) )}
+
+%D Step tables are the vertical counterpart of stepcharts.
+
+\newcounter\currentsteptable
+
+\def\steptableprefix{@st@-\currentsteptable-}
+
+\def\startSTEPtable
+ {\dosingleempty\dostartSTEPtable}
+
+\def\dostartSTEPtable[#1]#2\stopSTEPtable
+ {\dostartSTEPaligntable[0][#1]#2\stopSTEPaligntable}
+
+\def\startSTEPaligntable
+ {\dodoubleempty\dostartSTEPaligntable[1]}
+
+\def\dostartSTEPaligntable[#1][#2]#3\stopSTEPaligntable % flag settings data
+ {\ifinsidefloat
+ \else
+ \whitespace
+ \@@STPTbefore
+ \startbaselinecorrection
+ \setlocalhsize
+ \noindent
+ \fi
+ \vbox\bgroup
+ \setupSTEPtables[#2]%
+ \forgetall
+ \pushMPdrawing
+ \doglobal\increment\currentsteptable
+ \startMPdrawing
+ input mp-step ;
+ begin_step_table ;
+ \stopMPdrawing
+ \initializeSTEP
+ \initializeSTPT
+ \def\startlines{\bgroup\setupSTEPlines}%
+ \def\stoplines {\egroup}%
+ \def\prep##1{\ignorespaces##1\unskip\enspace\ignorespaces}%
+ \def\cell {\dosingleempty\docell}%
+ \def\cells {\dosingleempty\docells}%
+ \def\text {\dosingleempty\dotext}%
+ % first graphic pass, also trial pass
+ \global\dimen1\zeropoint
+ \global\dimen3\zeropoint
+ \global\dimen5\zeropoint
+ \def\docell[##1]%
+ {\docells[##1]{}{}}%
+ \def\docells[##1]##2##3##4%
+ {\doglobal\increment\cellcounter
+ \bgroup
+ \iffirstargument\setupSTEPcells[##1]\fi
+ \initializeSTEC
+ \startMPdrawing
+ if box_found(\MPpos{\steptableprefix\cellcounter-c}) :
+ initialize_box(\MPpos{\steptableprefix\cellcounter-c}) ;
+ cells[\cellcounter] := \MPcellsgraphic ;
+ fi ;
+ \stopMPdrawing
+ \egroup
+ \def\do####1####2%
+ {\setbox\scratchbox\hbox{\@@stepfake{####2}}%
+ \ifdim\wd\scratchbox>\dimen####1\global\dimen####1=\wd\scratchbox\fi}%
+ \ifcase#1\else\do1{##2}\do3{##3}\fi\do5{##4}}%
+ \def\dotext[##1]##2%
+ {\bgroup
+ \iffirstargument\setupSTEPtexts[##1]\fi
+ \initializeSTET
+ \startMPdrawing
+ if box_found(\MPpos{\steptableprefix\cellcounter-t}) :
+ initialize_box(\MPpos{\steptableprefix\cellcounter-t}) ;
+ texts[\cellcounter] := \MPtextsgraphic ;
+ fi ;
+ \stopMPdrawing
+ \egroup}
+ \doglobal\newcounter\cellcounter#3
+ % second graphic pass pass, drawing lines
+ \def\docells[##1]##2##3##4%
+ {\doglobal\increment\cellcounter}
+ \def\dotext[##1]##2%
+ {\bgroup
+ \initializeSTEL
+ \startMPdrawing
+ lines[\cellcounter] := \MPtablelinesgraphic ;
+ \stopMPdrawing
+ \egroup}
+ \doglobal\newcounter\cellcounter#3
+ % finishing graphic touch
+ \startMPdrawing
+ nofcells := \cellcounter ;
+ end_step_table ;
+ anchor_box(\MPpos{\steptableprefix origin}) ;
+ \stopMPdrawing
+ \MPdrawingdonetrue
+ \doifelse\@@STPTmethod{0}
+ {\setbox0\null}
+ {\setbox0\vbox{\MPstaticgraphictrue\getMPdrawing}}%
+ \resetMPdrawing
+ % typesetting pass
+ \dimen6=\@@STPTdistance \dimen6=2\dimen6
+ % cell width
+ \dimen8=\dimen1
+ \advance\dimen8\dimen3
+ \advance\dimen8\dimen5
+ % offset width
+ \ifcase#1\else \advance\dimen8 \dimen6 \fi
+ % arrow width
+ \advance\dimen8 \@@STPTwidth
+ \advance\dimen8 \@@STPToffset
+ \advance\dimen8 \@@STPToffset
+ \def\docells[##1]##2##3##4%
+ {\doglobal\increment\cellcounter
+ \def\do####1####2####3####4% % strut really needed there !
+ {\hbox to \dimen####1{####2\@@stepfake{####3}\strut####4}}%
+ \setbox8\hbox
+ {\ifcase#1\else
+ \do1\hss{##2}\relax \hskip\@@STPTdistance
+ \do3\hss{##3}\hss \hskip\@@STPTdistance
+ \fi
+ \do5\relax{##4}\hss}%
+ \hpos{\steptableprefix\cellcounter-c}{\@@stepcell{\box8}}
+ \endgraf
+ \nointerlineskip
+ \kern\@@STPTvoffset}
+ \def\dotext[##1]##2%
+ {\bgroup
+ \hskip\dimen8
+ \advance\hsize-\dimen8
+ \advance\hsize-\dimen6 % twice the offset
+ \setbox0\hbox{\@@steptext{##2}}%
+% to do
+% \ifdim\wd0>\hsize
+% \setbox0=\vbox{\@@steptext{##2}}%
+% \fi
+% align
+ \hpos{\steptableprefix\cellcounter-t}{\box0}%
+ \endgraf
+ \egroup
+ \nointerlineskip
+ \kern\@@STPTvoffset}
+ \setbox2\vbox
+ {\doglobal\newcounter\cellcounter
+ #3\kern-\@@STPTvoffset}
+ \hbox
+ {\scratchdimen\wd0
+ \advance\scratchdimen \MPllx bp
+ \raise\MPlly bp\box0
+ \hskip-\scratchdimen
+ \hpos{\steptableprefix origin}{\box2}}
+ \popMPdrawing
+ \egroup
+ \ifinsidefloat \else \stopbaselinecorrection \@@STPTafter \fi}
+
+\def\MPtablelinesgraphic
+ {image ( drawline (
+ \@@STELalternative, get_step_table_line(\cellcounter),
+ \@@STELrulethickness, \MPcolor{\@@STELcolor} ) )}
+
+\protect \endinput
+
+% A simple paragraph-flow test:
+
+\starttext
+
+\startbuffer
+\startSTEPchart
+\cells {A} {B}
+\cells {one} {five} \texts{$+2$}{$-2$}
+\cells {two} {four} \texts{$+3$}{$-3$}
+\cells {three} {three} \texts{$+4$}{$-4$}
+\cells {four} {two} \texts{$+5$}{$-5$}
+\cells {five} {one}
+\stopSTEPchart
+\stopbuffer
+
+\getbuffer
+
+\startnarrower \getbuffer \stopnarrower
+
+\placefigure[left]{}{} \getbuffer
+
+\stoptext
diff --git a/tex/context/base/m-streams.tex b/tex/context/base/m-streams.tex
new file mode 100644
index 000000000..9d7e8d7dd
--- /dev/null
+++ b/tex/context/base/m-streams.tex
@@ -0,0 +1,446 @@
+%D \module
+%D [ file=m-streams,
+%D version=2006.03.21,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Streams,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D First we implement a simple left||right synchronization
+%D mechanism, which we may perfect and extend over time.
+
+\unprotect
+
+\defineoutputstream [\v!left]
+\defineoutputstream [\v!right]
+
+\definemarknote[\v!left]
+\definemarknote[\v!right]
+
+\startsetups stream:\v!left:bottom
+ \flushmarknotes[\v!left]
+\stopsetups
+\startsetups stream:\v!right:bottom
+ \flushmarknotes[\v!right]
+\stopsetups
+\startsetups stream:\v!left:reset
+ \erasemarknotes[\v!left]
+\stopsetups
+\startsetups stream:\v!right:reset
+ \erasemarknotes[\v!right]
+\stopsetups
+
+\def\LeftNote {\setmarknote [\v!left]} % {#1}
+\def\RightNote {\setmarknote [\v!right]} % {#1}
+\def\SwitchToLeft {\enableoutputstream [\v!left]}
+\def\SwitchToRight {\enableoutputstream [\v!right]}
+\def\SwitchToNormal {\enableoutputstream [\s!default]}
+\def\SynchronizeLeftAndRight{\synchronizeoutputstreams[\v!left,\v!right]}
+\def\FlushLeftAndRight {\flushoutputstreampages [\v!left,\v!right]}
+
+\protect
+
+% \topskip \strutheight
+% \splittopskip\strutheight
+
+%D Example of usage:
+%D
+%D \starttyping
+%D \nopenalties \setupinterlinespace[top=height] \setupcolors[state=start]
+%D
+%D \showgrid \showstruts
+%D
+%D \starttext
+%D
+%D \title{Whatever} \page
+%D
+%D \dorecurse {5} {
+%D \let\RecurseLevel\recurselevel
+%D \SwitchToLeft \dorecurse{10}{\dontleavehmode{\tf\RecurseLevel:l \begstrut \input tufte \endstrut \endgraf}}
+%D \SwitchToRight \dorecurse{10}{\dontleavehmode{\sl\RecurseLevel:r \begstrut \input knuth \endstrut \endgraf}}
+%D \SwitchToNormal \SynchronizeLeftAndRight
+%D \SwitchToLeft \dorecurse{10}{\dontleavehmode{\bf\RecurseLevel:l \begstrut \input zapf \endstrut \endgraf}}
+%D \SwitchToRight \dorecurse{10}{\dontleavehmode{\bs\RecurseLevel:r \begstrut \input davis \endstrut \endgraf}}
+%D \SwitchToNormal \SynchronizeLeftAndRight
+%D }
+%D
+%D \FlushLeftAndRight
+%D
+%D \stoptext
+%D \stoptyping
+%D
+%D Another example:
+%D
+%D \starttyping
+%D \nopenalties \setupinterlinespace[top=height] \setupcolors[state=start]
+%D
+%D \showgrid \showstruts
+%D
+%D \starttext
+%D
+%D \SwitchToNormal \FlushLeftAndRight \page
+%D
+%D \def\StartCouple{\page\SwitchToNormal}
+%D \def\StopCouple {\SwitchToNormal \SynchronizeLeftAndRight \FlushLeftAndRight}
+%D
+%D \def\Original {\SwitchToNormal\SynchronizeLeftAndRight\SwitchToLeft}
+%D \def\Translation{\SwitchToRight}
+%D
+%D \StartCouple
+%D \dorecurse{10} {
+%D \Original o: \begstrut \inright{\blackrule}\input tufte \endstrut \LeftNote {tufte} \endgraf
+%D \Translation t: \begstrut \inleft {\blackrule}\input zapf \endstrut \RightNote{zapf} \endgraf
+%D \Original o: \begstrut \inright{\blackrule}\input knuth \endstrut \LeftNote {knuth} \endgraf
+%D \Translation t: \begstrut \inleft {\blackrule}\input davis \endstrut \RightNote{davis} \endgraf
+%D \Original o: \begstrut \inright{\blackrule}\input douglas \endstrut \LeftNote {douglas} \endgraf
+%D \Translation t: \begstrut \inleft {\blackrule}\input bryson \endstrut \RightNote{bryson} \endgraf
+%D }
+%D \StopCouple
+%D \stoptext
+%D \stoptyping
+
+%D Next we implement stream layers.
+
+\unprotect
+
+\def\overloadtextwidth#1%
+ {\makeupwidth#1\relax
+ \textwidth\makeupwidth
+ \hsize\makeupwidth}
+
+\startsetups streamlayer:default:settings
+ % set hsize etc, like \overloadtextwidth{12cm}
+\stopsetups
+
+\startsetups streamlayer:default:extras
+ % flush goodies, like local floats
+\stopsetups
+
+\startsetups streamlayer:default:place
+ \setlayer
+ [\currentstreamlayer]
+ [\c!preset=\v!left\v!top]
+ {\outputstreambox[\currentstreamlayer]}%
+\stopsetups
+
+\startsetups streamlayer:default:copy
+ \setlayer
+ [\currentstreamlayer]
+ [\c!preset=\v!left\v!top]
+ {\outputstreamcopy[\currentstreamlayer]}%
+\stopsetups
+
+\startsetups streamlayer:default:reset
+ \outputstreambox[\currentstreamlayer]
+\stopsetups
+
+\startsetups streamlayer:default:flush
+ \tightlayer[\currentstreamlayer]
+\stopsetups
+
+\def\definestreamlayer
+ {\dodoubleempty\dodefinestreamlayer}
+
+\def\dodefinestreamlayer[#1][#2]%
+ {\defineoutputstream[#1]%
+ \defineoutputstream[main]%
+ \definelayer[#1][\c!method=\v!fit,\c!width=\textwidth,#2]}
+
+\def\dostreamsetups#1%
+ {\doifsetupselse{streamlayer:\currentstreamlayer:#1}
+ {\directsetup{streamlayer:\currentstreamlayer:#1}}
+ {\directsetup{streamlayer:\s!default:#1}}}
+
+\def\startstreamlayer[#1]%
+ {\bgroup
+% \def\startstreamlayer[##1]{\bgroup\let\stopstreamlayer\egroup}%
+ \edef\currentstreamlayer{#1}%
+ \enableoutputstream[main]%
+ \synchronizeoutput
+ \enableoutputstream[\currentstreamlayer]%
+ \bgroup
+ \dostreamsetups{settings}}
+
+\def\stopstreamlayer
+ {\endgraf
+ \egroup
+ \disableoutputstream % \enableoutputstream[\s!default]%
+ \outputstreambox[main]%
+% \dostreamsetups{place}%
+% \dostreamsetups{extras}%
+% \dostreamsetups{flush}%
+ \egroup}
+
+\def\preparestreamlayer{\dosingleempty\dopreparestreamlayer}
+\def\flushstreamlayer {\dosingleempty\doflushstreamlayer }
+\def\placestreamlayer {\dosingleempty\doplacestreamlayer }
+
+\def\dopreparestreamlayer[#1]%
+ {\bgroup
+ \edef\currentstreamlayer{\iffirstargument#1\else\currentstreamlayer\fi}%
+ \dostreamsetups{place}%
+ \dostreamsetups{extras}%
+% \dostreamsetups{flush}%
+ \egroup}
+
+\def\doflushstreamlayer[#1]%
+ {\bgroup
+ \edef\currentstreamlayer{\iffirstargument#1\else\currentstreamlayer\fi}%
+ \dostreamsetups{flush}%
+ \egroup}
+
+\def\doplacestreamlayer[#1]%
+ {\preparestreamlayer[#1]%
+ \flushstreamlayer[#1]}
+
+\protect
+
+%D Usage:
+
+%D \starttyping
+%D \setupinterlinespace[top=height]
+%D
+%D \setupcolors[state=start]
+%D
+%D \definestreamlayer[block]
+%D
+%D \definemeasure[localtextwidth] [\dimexpr.7\textwidth\relax]
+%D \definemeasure[localfloatwidth][\dimexpr.3\textwidth-2\bodyfontsize\relax]
+%D
+%D \startsetups streamlayer:block:settings
+%D \hsize=\measure{localtextwidth}
+%D \setupfloat[figure][maxwidth=\measure{localfloatwidth}]
+%D \stopsetups
+%D
+%D \startsetups streamlayer:block:extras
+%D \setuplocalfloats
+%D [before=\blank,
+%D after=\blank,
+%D inbetween=\blank]
+%D \setbox\scratchbox\vbox{\hsize\measure{localfloatwidth}\getlocalfloats}
+%D \ifdim\ht\scratchbox>\thelayerheight\currentstreamlayer\relax
+%D % more float than text
+%D \setlayerframed
+%D [\currentstreamlayer]
+%D [preset=righttop]
+%D [frame=off,
+%D offset=overlay]
+%D {\box\scratchbox}
+%D \else
+%D % more text than float
+%D \setuplocalfloats
+%D [before=\vfill,
+%D after=\removedepth\vfill,
+%D inbetween=\removedepth\vfill]
+%D \setlayerframed
+%D [\currentstreamlayer]
+%D [preset=righttop]
+%D [frame=off,
+%D offset=overlay]
+%D {\vbox to \thelayerheight\currentstreamlayer {\hsize\measure{localfloatwidth}\getlocalfloats}}
+%D \fi
+%D \resetlocalfloats
+%D \stopsetups
+%D
+%D \startsetups streamlayer:block:place
+%D \setlayerframed
+%D [\currentstreamlayer]
+%D [preset=lefttop]
+%D [frame=off,
+%D offset=overlay]
+%D {\outputstreambox[\currentstreamlayer]}%
+%D \stopsetups
+%D
+%D \startsetups streamlayer:block:flush
+%D \framed
+%D [offset=overlay,
+%D frame=off,
+%D background=color,
+%D backgroundcolor=red]
+%D {\tightlayer[\currentstreamlayer]}
+%D \stopsetups
+%D
+%D \setupbodyfont[small]
+%D
+%D \starttext
+%D
+%D \dorecurse {10} {
+%D \startstreamlayer[block]
+%D \title{Sample \recurselevel}
+%D \input tufte \endgraf
+%D \placefigure[local]{}{}
+%D \placefigure[local]{}{}
+%D \ifodd\recurselevel\relax \placefigure[local]{}{} \fi
+%D \startitemize[columns]
+%D \item xxx
+%D \item xxx
+%D \item xxx
+%D \item xxx
+%D \item xxx
+%D \stopitemize
+%D \stopstreamlayer
+%D \placestreamlayer[block]
+%D }
+%D
+%D \dorecurse {10} {
+%D \startstreamlayer[block]
+%D \title{Sample \recurselevel}
+%D \startcolumns
+%D \input tufte
+%D \stopcolumns
+%D \stopstreamlayer
+%D \placestreamlayer[block]
+%D }
+%D
+%D \stoptext
+%D \stoptyping
+
+\def\starttextstreamlayer
+ {\startstreamlayer}
+
+\def\stoptextstreamlayer
+ {\endgraf
+ % maybe depth if no proper depth and no skip
+ \removelastskip
+ \stopstreamlayer}
+
+\def\placetextstreamlayer{\placestreamlayer}
+
+%D \starttyping
+%D \definestreamlayer[whatever][width=12cm]
+%D
+%D \startstreamlayer[whatever]
+%D \startitemize[columns,two][after=]
+%D \item one
+%D \item two
+%D \item three
+%D \item four
+%D \stopitemize
+%D \stopstreamlayer
+%D
+%D \framed[strut=no,align=normal]{\placestreamlayer[whatever]\obeydepth}
+%D
+%D \starttextstreamlayer[whatever]
+%D \startitemize[columns,two]
+%D \item one
+%D \item two
+%D \item three
+%D \item four
+%D \stopitemize
+%D \stoptextstreamlayer
+%D
+%D \framed[strut=no]{\placetextstreamlayer[whatever]}
+%D \stoptyping
+
+\endinput
+
+\setupinterlinespace[top=height]
+
+\setupcolors[state=start]
+
+\definestreamlayer[block]
+
+\definemeasure[localtextwidth] [\dimexpr.7\textwidth\relax]
+\definemeasure[localfloatwidth][\dimexpr.3\textwidth-2\bodyfontsize\relax]
+
+\startsetups streamlayer:block:settings
+ \hsize=\measure{localtextwidth}
+ \setupfloat[figure][maxwidth=\measure{localfloatwidth}]
+\stopsetups
+
+\startsetups streamlayer:block:extras
+ \setuplocalfloats
+ [before=\whitespace\blank,
+ after=\whitespace\blank,
+ inbetween=\whitespace\blank]
+ \setbox\scratchbox\vbox{\hsize\measure{localfloatwidth}\getlocalfloats}
+ \ifdim\ht\scratchbox>\thelayerheight\currentstreamlayer\relax
+ % more float than text
+ \setlayerframed
+ [\currentstreamlayer]
+ [preset=righttop]
+ [frame=off,
+ offset=overlay]
+ {\box\scratchbox}
+ \else
+ % more text than float
+ \setuplocalfloats
+ [before=\vfill,
+ after=\removedepth\vfill,
+ inbetween=\removedepth\vfill]
+ \setlayerframed
+ [\currentstreamlayer]
+ [preset=righttop]
+ [frame=off,
+ offset=overlay]
+ {\vbox to \thelayerheight\currentstreamlayer {\hsize\measure{localfloatwidth}\getlocalfloats}}
+ \fi
+ \resetlocalfloats
+\stopsetups
+
+\startsetups streamlayer:block:place
+ \setlayerframed
+ [\currentstreamlayer]
+ [preset=lefttop]
+ [frame=off,
+ offset=overlay]
+ {\outputstreambox[\currentstreamlayer]}%
+\stopsetups
+
+\startsetups streamlayer:block:flush
+ \framed
+ [offset=overlay,
+ frame=off,
+ background=color,
+ backgroundcolor=red]
+ {\tightlayer[\currentstreamlayer]}
+\stopsetups
+
+\setupbodyfont[small]
+
+\starttext
+
+% \definestreamlayer[block]
+%
+% \startstreamlayer[block]
+% \title{Sample \recurselevel}
+% \startcolumns
+% \dorecurse{4}{\input tufte \par}
+% \stopcolumns
+% \stopstreamlayer
+% \placestreamlayer[block]
+
+\dorecurse {10} {
+ \startstreamlayer[block]
+ \title{Sample \recurselevel}
+ \input tufte \endgraf
+ \placefigure[local]{}{}
+ \placefigure[local]{}{}
+ \ifodd\recurselevel\relax \placefigure[local]{}{} \fi
+ \startitemize[columns]
+ \item xxx
+ \item xxx
+ \item xxx
+ \item xxx
+ \item xxx
+ \stopitemize
+ \stopstreamlayer
+ \placestreamlayer[block]
+}
+
+\dorecurse {10} {
+ \startstreamlayer[block]
+ \title{Sample \recurselevel}
+ \startcolumns
+ \input tufte
+ \stopcolumns
+ \stopstreamlayer
+ \placestreamlayer[block]
+}
+
+\stoptext
diff --git a/tex/context/base/m-subsub.tex b/tex/context/base/m-subsub.tex
new file mode 100644
index 000000000..4395ded8a
--- /dev/null
+++ b/tex/context/base/m-subsub.tex
@@ -0,0 +1,76 @@
+%D \module
+%D [ file=m-subsub,
+%D version=2000.12.14,
+%D title=\CONTEXT\ Private Modules,
+%D subtitle=More Section Levels,
+%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. This module is not public.
+
+\unprotect
+
+\definesection[\s!section-8]
+\definesection[\s!section-9]
+\definesection[\s!section-10]
+\definesection[\s!section-11]
+\definesection[\s!section-12]
+
+\definehead
+ [\v!subsubsubsubsubsection]
+ [\c!section=\s!section-8,
+ \c!default=\v!subsubsubsubsection]
+
+\definehead
+ [\v!subsubsubsubsubsubsection]
+ [\c!section=\s!section-9,
+ \c!default=\v!subsubsubsubsubsection]
+
+\definehead
+ [\v!subsubsubsubsubsubsubsection]
+ [\c!section=\s!section-10,
+ \c!default=\v!subsubsubsubsubsubsection]
+
+\definehead
+ [\v!subsubsubsubsubsubsubsubsection]
+ [\c!section=\s!section-11,
+ \c!default=\v!subsubsubsubsubsubsubsection]
+
+\definehead
+ [\v!subsubsubsubsubsubsubsubsubsection]
+ [\c!section=\s!section-12,
+ \c!default=\v!subsubsubsubsubsubsubsubsection]
+
+\definehead
+ [\v!subsubsubsubsubsubject]
+ [\c!coupling=\v!subsubsubsubsubsection,
+ \c!default=\v!subsubsubsubsubsection,
+ \c!incrementnumber=\v!no]
+
+\definehead
+ [\v!subsubsubsubsubsubsubject]
+ [\c!coupling=\v!subsubsubsubsubsubsection,
+ \c!default=\v!subsubsubsubsubsubsection,
+ \c!incrementnumber=\v!no]
+
+\definehead
+ [\v!subsubsubsubsubsubsubsubject]
+ [\c!coupling=\v!subsubsubsubsubsubsubsection,
+ \c!default=\v!subsubsubsubsubsubsubsection,
+ \c!incrementnumber=\v!no]
+
+\definehead
+ [\v!subsubsubsubsubsubsubsubsubject]
+ [\c!coupling=\v!subsubsubsubsubsubsubsubsection,
+ \c!default=\v!subsubsubsubsubsubsubsubsection,
+ \c!incrementnumber=\v!no]
+
+\definehead
+ [\v!subsubsubsubsubsubsubsubsubsubject]
+ [\c!coupling=\v!subsubsubsubsubsubsubsubsubsection,
+ \c!default=\v!subsubsubsubsubsubsubsubsubsection,
+ \c!incrementnumber=\v!no]
+
+\protect \endinput
diff --git a/tex/context/base/m-tex4ht.tex b/tex/context/base/m-tex4ht.tex
new file mode 100644
index 000000000..8a3dc9dbb
--- /dev/null
+++ b/tex/context/base/m-tex4ht.tex
@@ -0,0 +1,9 @@
+%D Preliminaty module
+
+\input tex4ht.sty
+
+\appendtoks
+ \Preamble{\env{ht-1},\env{ht-2},html}\EndPreamble
+\to \everystarttext
+
+\endinput
\ No newline at end of file
diff --git a/tex/context/base/m-timing.tex b/tex/context/base/m-timing.tex
new file mode 100644
index 000000000..f02a90087
--- /dev/null
+++ b/tex/context/base/m-timing.tex
@@ -0,0 +1,102 @@
+%D \module
+%D [ file=m-timing,
+%D version=2007.12.23,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Timing,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\doifnotmode{mkiv}{\endinput}
+
+\ifx\ShowNamedUsage\undefined \else \endinput \fi
+
+%D Written at the end of 2007, this module is dedicated to Taco. Reaching this
+%D point in \LUATEX\ was a non trivial effort. By visualizing a bit what happens
+%D when pages come out of \LUATEX, you may get an idea what is involved. It took
+%D much time an dedication to reach this point in the development. Add to that
+%D those daily Skype intense discussion, testing and debugging moments. Time flies
+%D but progress is impressive. The motto of this module could be: what you see
+%D is what you get. An there is much more to come \unknown.
+
+% \usemodule[timing]
+% \setupcolors[state=start]
+% \starttext
+% \dorecurse{200}{\input tufte \par} \ShowUsage{}
+% \stoptext
+
+\definecolor[usage:line] [darkred]
+\definecolor[usage:time] [darkblue]
+\definecolor[usage:frame][darkgray]
+
+\ctxloadluafile{trac-tim}{}
+
+\startluacode
+local progress = plugins.progress
+
+function progress.show(filename,parameters,nodes,other)
+ for n, name in pairs(parameters or progress.parameters(filename)) do
+ tex.sprint(tex.ctxcatcodes,string.format("\\ShowNamedUsage{%s}{%s}{%s}",filename or progress.defaultfilename,name,other or ""))
+ end
+ for n, name in pairs(nodes or progress.nodes(filename)) do
+ tex.sprint(tex.ctxcatcodes,string.format("\\ShowNamedUsage{%s}{%s}{%s}",filename or progress.defaultfilename,name,other or ""))
+ end
+end
+\stopluacode
+
+% \everyfirstshipout
+
+\startnotmode[no-timing]
+ \appendtoks\ctxlua{plugins.progress.store()}\to\everystarttext
+ \appendtoks\ctxlua{plugins.progress.store()}\to\everyshipout
+ \ctxlua{main.register_stop_actions(function() plugins.progress.save() end)}
+\stopnotmode
+
+\def\ShowNamedUsage#1#2#3%
+ {\setbox\scratchbox\vbox\bgroup\startMPcode
+ begingroup ; save p, q, b, h, w ;
+ path p, q, b ; numeric h, w ;
+ p := \ctxlua{tex.sprint(plugins.progress.path("#1","#2"))} ;
+% p := p shifted -llcorner p ;
+ if bbwidth(p) > 1 :
+ h := 100 ; w := 2 * h ;
+ w := \the\textwidth-3pt ; % correct for pen
+ p := p xstretched w ;
+ b := boundingbox (llcorner p -- llcorner p shifted (w,h)) ;
+ pickup pencircle scaled 3pt ; linecap := butt ;
+ draw b withcolor \MPcolor{usage:frame} ;
+ draw p withcolor \MPcolor{usage:line} ;
+ if ("#3" <> "") and ("#3" <> "#2") :
+ q := \ctxlua{tex.sprint(plugins.progress.path("#1","#3"))} ;
+% q := q shifted -llcorner q ;
+ if bbwidth(q) > 1 :
+ q := q xstretched w ;
+ pickup pencircle scaled 1.5pt ; linecap := butt ;
+ draw q withcolor \MPcolor{usage:time} ;
+ fi ;
+ fi ;
+ fi ;
+ endgroup ;
+ \stopMPcode\egroup
+ \scratchdimen\wd\scratchbox
+ \ifdim\scratchdimen>\zeropoint
+ \startlinecorrection
+ \box\scratchbox \endgraf
+ \hbox to \scratchdimen{\tttf\strut\detokenize{#2}\hss
+ min:\ctxlua{tex.sprint(plugins.progress.bot("#1","\detokenize{#2}"))}, %
+ max:\ctxlua{tex.sprint(plugins.progress.top("#1","\detokenize{#2}"))}, %
+ pages:\ctxlua{tex.sprint(plugins.progress.pages("#1"))}%
+ }%
+ \stoplinecorrection
+ \fi}
+
+\def\LoadUsage #1{\ctxlua{plugins.progress.convert("#1")}}
+\def\ShowUsage #1{\ctxlua{plugins.progress.show("#1",nil,nil,"elapsed_time")}}
+\def\ShowMemoryUsage#1{\ctxlua{plugins.progress.show("#1",nil,{}, "elapsed_time")}}
+\def\ShowNodeUsage #1{\ctxlua{plugins.progress.show("#1",{},nil, "elapsed_time")}}
+
+\endinput
diff --git a/tex/context/base/m-trackers.tex b/tex/context/base/m-trackers.tex
new file mode 100644
index 000000000..cfcbbabff
--- /dev/null
+++ b/tex/context/base/m-trackers.tex
@@ -0,0 +1,5 @@
+\doifnotmode{mkiv} {\endinput}
+
+\starttext
+ \showtrackers
+\stoptext
diff --git a/tex/context/base/m-translate.tex b/tex/context/base/m-translate.tex
new file mode 100644
index 000000000..9c550eca7
--- /dev/null
+++ b/tex/context/base/m-translate.tex
@@ -0,0 +1,88 @@
+%D \module
+%D [ file=m-translate,
+%D version=2008.10.09,
+%D title=\CONTEXT\ Modules,
+%D subtitle=Translations,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\doifnotmode{mkiv}{\endinput}
+
+%D We can make this module more clever (wildcards and such) but since
+%D it's only a demo we stick to the simple case for now. After all, it's
+%D better to fix your source.
+
+\startluacode
+ translators = { }
+
+ local compiled, list = nil, nil
+
+ function translators.register(from,to)
+ local l = lpeg.P(from)/to
+ if not list then
+ list = l
+ else
+ list = list + l
+ end
+ compiled = nil
+ end
+
+ function translators.translate(s)
+ if list then
+ if not compiled then
+ compiled = lpeg.Cs((list + lpeg.P(1))^0)
+ end
+ return compiled:match(s)
+ else
+ return s
+ end
+ end
+
+ function translators.reset(s)
+ resolvers.install_text_filter("user",nil)
+ list, compiled = nil, nil
+ end
+ function translators.enable(s)
+ resolvers.install_text_filter("user",translators.translate)
+ end
+ function translators.disable(s)
+ resolvers.install_text_filter("user",nil)
+ end
+\stopluacode
+
+\unprotect
+
+\def\translateinput{\dodoubleargument\dotranslateinput}
+
+\def\dotranslateinput[#1][#2]{\ctxlua{translators.register(\!!bs#1\!!es,\!!bs#2\!!es)}}
+
+\def\resetinputtranslation {\ctxlua{translators.reset()}}
+\def\enableinputtranslation {\ctxlua{translators.enable()}}
+\def\disableinputtranslation{\ctxlua{translators.disable()}}
+
+\def\readtranslatedfile#1%
+ {\enableinputtranslation
+ \readfile{#1}\donothing\donothing
+ \disableinputtranslation}
+
+\protect
+
+\doifnotmode{demo}{\endinput}
+
+\starttext
+
+ \translateinput[Moica][Mojca]
+ \translateinput[Idris][Idris (aka ادريس)]
+
+ \enableinputtranslation
+
+ Well, it's not that hard to satisfy Idris and Moica.
+
+ \readtranslatedfile{tufte}
+
+\stoptext
diff --git a/tex/context/base/m-tryout.tex b/tex/context/base/m-tryout.tex
new file mode 100644
index 000000000..4aa50376d
--- /dev/null
+++ b/tex/context/base/m-tryout.tex
@@ -0,0 +1,55 @@
+%D \module
+%D [ file=m-tryout,
+%D version=2002.05.10,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Tryout Features,
+%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.
+
+\endinput
+
+\unprotect
+
+%D The following macros make sure that active colons work well
+%D in French, a feature enabled with:
+%D
+%D \starttyping
+%D \useencoding[ffr] \mainlanguage[fr]
+%D \stoptyping
+%D
+%D This trick will disappear when proved robust.
+
+\startmode[activecolon]
+
+% this is now default
+
+\gdef\sectionseparator{-}
+
+\gdef\@@filterfirstpart [#1--#2]{#1}
+\gdef\@@filtersecondpart [#1--#2]{#2}
+
+\gdef\@@filterblockpart [#1--#2--#3]{#1}
+\gdef\@@filternumberpart [#1--#2--#3]{#2}
+\gdef\@@filterpagepart [#1--#2--#3]{#3}
+\gdef\@@filterblocknumberpart[#1--#2--#3]{#1--#2}
+
+\gdef\@@filterheadpart[#1]{\@EA\@@dofilterheadpart\@EA[#1-0]}
+\gdef\@@filtertailpart[#1]{\@EA\@@dofiltertailpart\@EA[#1-0]}
+
+\gdef\@@dofilterheadpart[#1-#2]{#1}
+\gdef\@@dofiltertailpart[#1-#2]{#2}
+
+\gdef\@@filterlevelpart[#1--#2--#3]{\@@dofilterlevelpart[#2-0-0-0-0]}
+
+\gdef\@@dofilterlevelpart[#1-0-0-0-#2]{#1}
+
+\reopenutilities
+
+\stopmode
+
+\protect \endinput
diff --git a/tex/context/base/m-units.tex b/tex/context/base/m-units.tex
new file mode 100644
index 000000000..d186c542b
--- /dev/null
+++ b/tex/context/base/m-units.tex
@@ -0,0 +1,825 @@
+%D \module
+%D [ file=m-units,
+%D version=1997.03.19,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Scientific Units,
+%D author={Hans Hagen \& Ton Otten},
+%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.
+
+%D Scientific units can be typeset in math mode pretty well,
+%D but occasionally one has to take care of spacing.
+%D Furthermore, entering these units is not that natural as
+%D wanted. Therefore this module presents a more natural way of
+%D doing things, like:
+%D
+%D \starttyping
+%D 1.23 \Cubic \Meter \Per \Second
+%D \stoptyping
+%D
+%D This example shows that we use the order in which we say
+%D things, instead of typeset things. There is a separate
+%D manual for this module.
+
+%D Message number~1 deals with overruling the \type {\Degrees}
+%D macro defined in the core modules. Let's say that this is
+%D an upward compatibility issue.
+
+\startmessages dutch library: units
+ title: eenheden
+ 1: gebruik \string\Degrees\space\string\Celsius\space in plaats van \string\Celsius !
+\stopmessages
+
+\startmessages english library: units
+ title: units
+ 1: use \string\Degrees\space\string\Celsius\space instead of \string\Celsius !
+\stopmessages
+
+\startmessages german library: units
+ title: Einheiten
+ 1: Verwende \string\Degrees\space\string\Celsius\space statt \string\Celsius !
+\stopmessages
+
+\startmessages italian library: units
+ title: unita
+ 1: usare \string\Degrees\space\string\Celsius\space invece di \string\Celsius !
+\stopmessages
+
+\startmessages norwegian library: units
+ title: enheter
+ 1: bruk \string\Degrees\space\string\Celsius\space istedenfor \string\Celsius !
+\stopmessages
+
+\startmessages romanian library: units
+ title: unitati
+ 1: folositi \string\Degrees\space\string\Celsius\space in locul \string\Celsius !
+\stopmessages
+
+\startmessages french library: units
+ title: unitas
+ 1: utilisez \string\Degrees\space\string\Celsius\space A la place de \string\Celsius !
+\stopmessages
+
+\unprotect
+
+%D This runtime loadable module implements a way of defining
+%D units. The core macro is \type {\dimension}, a rather clever
+%D one that is able to cooperate with some other dimension
+%D related macros. As said, this module enables user to enter:
+%D
+%D \startbuffer
+%D some 10 \Square \Meter \Per \Second or more
+%D \stopbuffer
+%D
+%D \getbuffer
+%D
+%D as:
+%D
+%D \typebuffer
+%D
+%D The units itself are implemented as synonyms.
+%D
+%D \starttyping
+%D \definesynonyms [unit] [units] [\unitmeaning]
+%D \setupsynonyms [unit] [textstyle=\dimension]
+%D \stoptyping
+%D
+%D This definition means that we can ask for the meaning of a
+%D unit using \type {\unitmeaning} and get a list of used
+%D units by saying \type {\placelistofunits}
+%D
+%D We have to use the command \type {\unitmeaning} instead
+%D of \type {\meaning}, simply because the latter is a \TEX\
+%D primitive we don't want to loose. We use the label text
+%D mechanism for translations.
+
+%D \macros
+%D {dimension}
+%D
+%D The core of this module is the low level macro \type
+%D {\dimension}. Before presenting this macro, it's best to
+%D look at some applications, because it's supposed to show
+%D some intelligence that can beter be understood from the
+%D context.
+%D
+%D The next useless examples show some of the cases we want
+%D to handle in a proper way.
+%D
+%D \startbuffer
+%D ... 10 \Square \Meter \Per \Volt \
+%D ... 10 \Square \Meter \Volt \
+%D ... 10 \Meter \Volt \
+%D ... 10 \Milli \Square \Meter \Per \Volt \
+%D ... 10 \Square \Milli \Meter \Per \Volt \
+%D ... 10 \Meter \Times \Meter \
+%D ... 10 \Square \Meter \Times \Meter \
+%D ... 10 \Square \Milli \Meter \Times \Meter \
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Becomes:
+%D
+%D \getbuffer
+
+%D \macros
+%D {mathematicstypeface, dimensiontypeface,
+%D dimensionhalfspace, dimensionbackspace}
+%D
+%D There are some low level constants, that can be changed
+%D when needed. Some day I will write a decent setup command.
+
+\def\mathematicstypeface{\rm}
+\def\dimensiontypeface {\tf}
+
+\def\dimensionhalfspace {\ifmmode\,\else\hskip+.1em\relax\fi}
+\def\dimensionbackspace {\ifmmode\!\else\hskip-.1em\relax\fi}
+
+%D \macros
+%D {smashdimensionpower}
+%D
+%D Sometimes the baseline distance is not enough to provide
+%D for superscripts, so we smash their height by default.
+
+\newif\ifsmashdimensionpower \smashdimensionpowertrue
+
+%D The dimension mechanism uses a lot of signals to keep
+%D track if the current state.
+
+\newsignal\dimensionsignal
+\newsignal\dimensionpowersignal
+\newsignal\dimensionmidfixsignal
+\newsignal\dimensionaddfixsignal
+
+\let\thedimensionprefix = \empty
+\let\thedimensionpower = \empty
+
+%D \macros
+%D {spaceddimensions,textdimensions}
+%D
+%D The actual definition of \type {\dimension} overruled the
+%D one in the core modules. The boolean can be used to
+%D force spacing between units. Vergelijk {\Newton \Meter}
+%D eens met {\spaceddimensionstrue \Newton \Meter}. The
+%D rather ugly test prevents problems with nested dimensions.
+
+\newif\ifspaceddimensions \spaceddimensionsfalse % user switch
+\newif\iftextdimensions \textdimensionsfalse % user switch
+
+%D You can see the consequence of forcing text dimensions
+%D when you compare the following code:
+%D
+%D \starttyping
+%D {\rm test \Square \Meter \Per \Second\ ziezo\Degrees} \par
+%D {\ss test \Square \Meter \Per \Second\ ziezo} \par
+%D {\tt test \Square \Meter \Per \Second\ ziezo}
+%D
+%D \textdimensionstrue
+%D
+%D {\rm test \Square \Meter \Per \Second\ ziezo} \par
+%D {\ss test \Square \Meter \Per \Second\ ziezo} \par
+%D {\tt test \Square \Meter \Per \Second\ ziezo}
+%D \stoptyping
+
+\newif\ifnesteddimension \nesteddimensionfalse % local switch
+
+\def\dodimensionpower#1%
+ {\iftextdimensions\expandafter\high\else\expandafter^\fi{#1}}
+
+\def\ustartmathmode {\iftextdimensions\else\expandafter\startmathmode \fi}
+\def\ustopmathmode {\iftextdimensions\else\expandafter\stopmathmode \fi}
+\def\umathematicstypeface{\iftextdimensions\else\expandafter\mathematicstypeface\fi}
+
+%D In forced text mode, we ignore spacing in monospaced fonts.
+
+\def\udimensionhalfspace {\dodimensionspace\dimensionhalfspace}
+\def\udimensionbackspace {\dodimensionspace\dimensionbackspace}
+
+\def\dodimensionspace
+ {\iftextdimensions
+ \begingroup
+ \setbox0\hbox{i}%
+ \setbox2\hbox{m}%
+ \ifdim\wd0=\wd2
+ \endgroup
+ \@EAEAEA\gobbleoneargument
+ \else
+ \endgroup
+ \fi
+ \fi}
+
+\unexpanded\def\dimension#1%
+ {\begingroup
+ \global\let\savedthedimensionprefix\thedimensionprefix
+ \global\let\savedthedimensionpower\thedimensionpower
+ \unexpanded\def\dimension##1{\global\nesteddimensiontrue}%
+ \let\dimensionprefix\dimension
+ \let\dimensionmidfix\dimension
+ \let\dimensionsuffix\dimension
+ \let\dimensionpower \dimension
+ \global\nesteddimensionfalse
+ \setbox\scratchbox\hbox{\ustartmathmode#1\ustopmathmode}% pre-roll
+ \global\let\thedimensionprefix\savedthedimensionprefix
+ \global\let\thedimensionpower \savedthedimensionpower
+ \endgroup
+ \ifnesteddimension#1\else\dodimension{#1}\fi}
+
+\def\dodimension#1%
+ {\dontbreakdimension
+ \ifdim\scratchdimen=\zeropoint\relax
+ \ifmmode
+ \udimensionhalfspace
+ \udimensionhalfspace
+ \fi
+ \ustartmathmode\dimensiontypeface
+ \else
+ \ustartmathmode\dimensiontypeface
+ \ifspaceddimensions
+ \ifdim\scratchdimen=\dimensionsignal\relax
+ \udimensionhalfspace
+ \else\ifdim\scratchdimen=\dimensionpowersignal\relax
+ \udimensionhalfspace
+ \fi
+ \fi
+ \fi
+ \fi
+ \umathematicstypeface\thedimensionprefix#1%
+ \ifx\thedimensionpower\empty
+ \else\ifsmashdimensionpower
+ \setbox\scratchbox=\hbox
+ {\iftextdimensions
+ \tx\thedimensionpower
+ \else
+ $\scriptstyle\thedimensionpower$%
+ \fi}%
+ \ht\scratchbox=\zeropoint
+ \dodimensionpower{\box\scratchbox}%
+ \else
+ \dodimensionpower{\thedimensionpower}%
+ \fi\fi
+ \ustopmathmode
+ % otherwise nobreak before space in 2 \Milli \Meter\ blabla
+ \doifnotmode{atpragma}{\nobreak}% this was always \nobreak
+ % only test this at pragma
+ \ifx\thedimensionpower\empty
+ \hskip\dimensionsignal
+ \else
+ \hskip\dimensionpowersignal
+ \fi
+ \global\let\thedimensionprefix\empty
+ \global\let\thedimensionpower\empty}
+
+%D \macros
+%D {dontbreakdimension,
+%D dimensionprefix, dimensionaddfix,
+%D dimensionnopfix, dimensionmidfix,
+%D dimensionpower}
+%D
+%D Here are some auxilliary macros.
+
+\def\dontbreakdimension
+ {\scratchdimen\lastskip
+ \unskip
+ \nobreak
+ \hskip\scratchdimen
+ \nobreak}
+
+\def\dimensionprefix#1%
+ {\gdef\thedimensionprefix{#1}}
+
+\def\dimensionaddfix#1%
+ {\unskip
+ %\mathematics{\umathematicstypeface#1}%
+ \ustartmathmode\umathematicstypeface#1\ustopmathmode
+ \nobreak
+ \hskip\dimensionaddfixsignal}
+
+\def\dimensionnopfix#1%
+ {\dontbreakdimension
+ \ifdim\scratchdimen=\dimensionpowersignal\relax
+ \ustartmathmode
+ \else
+ \ustartmathmode
+ \udimensionhalfspace
+ \nobreak
+ \fi
+ \umathematicstypeface#1%
+ \ustopmathmode
+ \nobreak
+ \hskip\dimensionsignal}
+
+\def\dimensionmidfix#1%
+ {\dontbreakdimension
+ \ifdim\scratchdimen=\dimensionpowersignal\relax
+ \ustartmathmode
+ \udimensionbackspace
+ \nobreak
+ \else
+ \ustartmathmode
+ \fi
+ \umathematicstypeface#1%
+ \ustopmathmode
+ \nobreak
+ \hskip\dimensionmidfixsignal}
+
+\def\dimensionpower#1%
+ {\gdef\thedimensionpower{#1}}
+
+%D \macros
+%D {SIunits, noSI, doSI}
+%D
+%D Some low level unit switching macros:
+
+\newif\ifSIunits \SIunitstrue
+
+\def\noSI#1{\begingroup\SIunitsfalse#1\endgroup}
+\def\doSI#1{\begingroup\SIunitstrue #1\endgroup}
+
+%D \macros
+%D {Degrees}
+%D
+%D We can fake the degrees symbol with:
+
+\def\Degrees{\dimensionaddfix{\mathematics{^\circ}}}
+
+%D \macros
+%D {Unit, NoUnit}
+%D
+%D When a dimension has no leading number, we can use \type
+%D {\Unit}, and when no unit is appended, \type {\NoUnit} is
+%D to be used, just to prevent the prefix migrating to the
+%D next occasion.
+
+\def\Unit {\hskip\dimensionsignal}
+\def\NoUnit {\dimension{}}
+
+%D The mechanism described at the top of this module, depends
+%D on several dimensional components, like prefixes:
+
+\def\Atto {\dimensionprefix{a}}
+\def\Femto {\dimensionprefix{f}}
+\def\Pico {\dimensionprefix{p}}
+\def\Nano {\dimensionprefix{n}}
+\def\Micro {\dimensionprefix{\iftextdimensions u\else\mu\fi}}
+\def\Milli {\dimensionprefix{m}}
+\def\Centi {\dimensionprefix{c}}
+\def\Deci {\dimensionprefix{d}}
+\def\Hecto {\dimensionprefix{h}}
+\def\Kilo {\dimensionprefix{k}}
+\def\Mega {\dimensionprefix{M}}
+\def\Giga {\dimensionprefix{G}}
+\def\Terra {\dimensionprefix{T}} % for old times sake
+\def\Tera {\dimensionprefix{T}}
+\def\Peta {\dimensionprefix{P}}
+\def\Exa {\dimensionprefix{E}}
+
+%D and operators:
+
+\def\Times {\dimensionnopfix{\iftextdimensions.\else\cdot\fi}}
+\def\Solidus {\dimensionmidfix{/}}
+\def\Per {\dimensionmidfix{/}}
+\def\OutOf {\dimensionnopfix{:}}
+
+%D and suffixes:
+
+\def\Linear {\dimensionpower{1}}
+\def\Square {\dimensionpower{2}}
+\def\Cubic {\dimensionpower{3}}
+
+\def\Inverse {\dimensionpower{-1}}
+\def\ILinear {\dimensionpower{-1}}
+\def\ISquare {\dimensionpower{-2}}
+\def\ICubic {\dimensionpower{-3}}
+
+%D Apart from these components, the units themselves are
+%D defined using the synonym mechanism. First we define some
+%D length and volume related units.
+
+\getvalue{\v!unit} [Meter] {m} {meter}
+\getvalue{\v!unit} [pMeter] {\Pico \Meter} {picometer}
+\getvalue{\v!unit} [nMeter] {\Nano \Meter} {nanometer}
+\getvalue{\v!unit} [uMeter] {\Micro \Meter} {micrometer}
+\getvalue{\v!unit} [mMeter] {\Milli \Meter} {millimeter}
+\getvalue{\v!unit} [cMeter] {\Centi \Meter} {centimeter}
+\getvalue{\v!unit} [dMeter] {\Deci \Meter} {decimeter}
+\getvalue{\v!unit} [hMeter] {\Hecto \Meter} {hectometer}
+\getvalue{\v!unit} [kMeter] {\Kilo \Meter} {kilometer}
+
+%D After some discussion on the \CONTEXT\ mailing list in
+%D february 2002 it was decided to go from L to l for liters
+%D (Karel Wesselings alternative: \mathematics{\ell}).
+
+\getvalue{\v!unit} [Liter] {l} {liter}
+\getvalue{\v!unit} [mLiter] {\Milli \Liter} {milliliter}
+\getvalue{\v!unit} [cLiter] {\Centi \Liter} {centiliter}
+\getvalue{\v!unit} [dLiter] {\Deci \Liter} {deciliter}
+
+%D Next we define time related units (\type {\ifSI} still dutch only).
+
+\getvalue{\v!unit} [Sec] {s} {\labeltext{u:sec}}
+\getvalue{\v!unit} [fSec] {\Femto \Sec} {\labeltext{u:fsec}}
+\getvalue{\v!unit} [pSec] {\Pico \Sec} {\labeltext{u:psec}}
+\getvalue{\v!unit} [nSec] {\Nano \Sec} {\labeltext{u:nsec}}
+\getvalue{\v!unit} [uSec] {\Micro \Sec} {\labeltext{u:usec}}
+\getvalue{\v!unit} [mSec] {\Milli \Sec} {\labeltext{u:msec}}
+\getvalue{\v!unit} [Year] {\ifSIunits a \else j\fi} {\labeltext{u:year}}
+\getvalue{\v!unit} [Month] {m} {\labeltext{u:month}}
+\getvalue{\v!unit} [Week] {w} {\labeltext{u:week}}
+\getvalue{\v!unit} [Day] {d} {\labeltext{u:day}}
+\getvalue{\v!unit} [Hour] {\ifSIunits h \else u\fi} {\labeltext{u:hour}}
+\getvalue{\v!unit} [Min] {min} {\labeltext{u:min}}
+
+\setuplabeltext
+ [\s!nl]
+ [u:sec=seconde,
+ u:psec=picoseconde,
+ u:fsec=femtoseconde,
+ u:nsec=nanoseconde,
+ u:usec=microseconde,
+ u:msec=milliseconde,
+ u:year=jaar,
+ u:month=maand,
+ u:week=week,
+ u:day=dag,
+ u:hour=uur,
+ u:min=minuten]
+
+\setuplabeltext
+ [\s!en]
+ [u:sec=second,
+ u:fsec=femtosecond,
+ u:psec=picosecond,
+ u:nsec=nanosecond,
+ u:usec=microsecond,
+ u:msec=millisecond,
+ u:year=year,
+ u:month=month,
+ u:week=week,
+ u:day=day,
+ u:hour=hour,
+ u:min=minutes]
+
+\setuplabeltext
+ [\s!de]
+ [u:sec=Sekunde,
+ u:fsec=Femtosekunde,
+ u:psec=Picosekunde,
+ u:nsec=Nanosekunde,
+ u:usec=Microsekunde,
+ u:msec=Millisekunde,
+ u:year=Jahr,
+ u:month=Monat,
+ u:week=Woche,
+ u:day=Tag,
+ u:hour=Stunde,
+ u:min=Minuten]
+
+\setuplabeltext
+ [\s!it]
+ [u:sec=secondo,
+ u:fsec=femtosecondo,
+ u:psec=picosecondo,
+ u:nsec=nanosecondo,
+ u:usec=microsecondo,
+ u:msec=millisecondo,
+ u:year=anno,
+ u:month=mese,
+ u:week=settimana,
+ u:day=giorno,
+ u:hour=ora,
+ u:min=minuti]
+
+%D Then we define some angles.
+
+\getvalue{\v!unit} [Rad] {rad} {\labeltext{u:rad}}
+\getvalue{\v!unit} [Deg] {{\mathematics{^\circ}}} {\labeltext{u:deg}}
+
+\setuplabeltext
+ [\s!nl]
+ [u:rad=hoek radialen,
+ u:deg=hoek graden]
+
+\setuplabeltext
+ [\s!en]
+ [u:rad=angle radians,
+ u:deg=angle degrees]
+
+\setuplabeltext
+ [\s!de]
+ [u:rad=Bogenma\SS,
+ u:deg=Gradma\SS]
+
+\setuplabeltext
+ [\s!it]
+ [u:rad=radianti,
+ u:deg=angoli sessagesimali]
+
+%D Rotation and frequency related units are defined by:
+
+\getvalue{\v!unit} [Hertz] {Hz} {Hertz}
+\getvalue{\v!unit} [kHertz] {\Kilo \Hertz} {kilo Hertz}
+\getvalue{\v!unit} [MHertz] {\Mega \Hertz} {mega Hertz}
+\getvalue{\v!unit} [GHertz] {\Giga \Hertz} {giga Hertz}
+\getvalue{\v!unit} [THertz] {\Tera \Hertz} {tera Hertz}
+\getvalue{\v!unit} [mHertz] {\Milli \Hertz} {milli Hertz}
+
+\getvalue{\v!unit} [RevPerSec] {RPS} {\labeltext{u:rps}}
+\getvalue{\v!unit} [RevPerMin] {RPM} {\labeltext{u:rpm}}
+
+\setuplabeltext
+ [\s!nl]
+ [u:rps=omwentelingen per seconde,
+ u:rpm=omwentelingen per minuut]
+
+\setuplabeltext
+ [\s!en]
+ [u:rps=revolutions per second,
+ u:rpm=revolutions per minute]
+
+\setuplabeltext
+ [\s!de]
+ [u:rps=Umdrehungen pro Sekunde,
+ u:rpm=Umdrehungen pro Minute]
+
+\setuplabeltext
+ [\s!it]
+ [u:rps=giri al secondo,
+ u:rpm=giri al minuto]
+
+%D Mass and force:
+
+\getvalue{\v!unit} [Gram] {g} {gram}
+\getvalue{\v!unit} [uGram] {\Micro \Gram} {microgram}
+\getvalue{\v!unit} [mGram] {\Milli \Gram} {milligram}
+\getvalue{\v!unit} [kGram] {\Kilo \Gram} {kilogram}
+\getvalue{\v!unit} [Atom] {u} {\labeltext{u:u}}
+
+\getvalue{\v!unit} [Newton] {N} {Newton}
+\getvalue{\v!unit} [kNewton] {\Kilo \Newton} {kilo Newton}
+
+\getvalue{\v!unit} [Pascal] {Pa} {Pascal}
+\getvalue{\v!unit} [mPascal] {\Milli \Pascal} {milli Pascal}
+\getvalue{\v!unit} [kPascal] {\Kilo \Pascal} {kilo Pascal}
+
+\setuplabeltext
+ [\s!nl]
+ [u:u=atomaire massa eenheid]
+
+\setuplabeltext
+ [\s!en]
+ [u:u=atom mass unit]
+
+\setuplabeltext
+ [\s!de]
+ [u:u=Atomare Masseneinheit]
+
+\setuplabeltext
+ [\s!it]
+ [u:u=unit\`a di massa atomica]
+
+%D Energy units comes in two alternatives:
+
+\getvalue{\v!unit} [Joule] {J} {Joule}
+\getvalue{\v!unit} [mJoule] {\Milli \Joule} {milli Joule}
+\getvalue{\v!unit} [kJoule] {\Kilo \Joule} {kilo Joule}
+\getvalue{\v!unit} [MJoule] {\Mega \Joule} {mega Joule}
+\getvalue{\v!unit} [GJoule] {\Giga \Joule} {giga Joule}
+
+\getvalue{\v!unit} [Watt] {W} {Watt}
+\getvalue{\v!unit} [mWatt] {\Milli \Watt} {milli Watt}
+\getvalue{\v!unit} [kWatt] {\Kilo \Watt} {kilo Watt}
+\getvalue{\v!unit} [MWatt] {\Mega \Watt} {mega Watt}
+\getvalue{\v!unit} [GWatt] {\Giga \Watt} {giga Watt}
+\getvalue{\v!unit} [TWatt] {\Tera \Watt} {tera Watt}
+
+%D Although Celsius is no longer permitted, we define it by
+%D saying:
+
+\getvalue{\v!unit} [Celsius] {C} {Celsius}
+\getvalue{\v!unit} [Kelvin] {K} {Kelvin}
+\getvalue{\v!unit} [Fahrenheit] {F} {Fahrenheit}
+
+%D Some chemic related units are:
+
+\getvalue{\v!unit} [Mol] {mol} {mol}
+\getvalue{\v!unit} [mMol] {\Milli \Mol} {millimol}
+\getvalue{\v!unit} [kMol] {\Kilo \Mol} {kilomol}
+\getvalue{\v!unit} [Molair] {M} {molair (\Mol \Per \Liter)}
+\getvalue{\v!unit} [Equivalent] {eq} {equivalent}
+\getvalue{\v!unit} [mEquivalent] {\Milli \Equivalent} {milli equivalent}
+
+%D There are quite a lot units related to electricity and
+%D magnetism:
+
+\getvalue{\v!unit} [Farad] {F} {Farad}
+\getvalue{\v!unit} [pFarad] {\Pico \Farad} {pico Farad}
+\getvalue{\v!unit} [nFarad] {\Nano \Farad} {nano Farad}
+\getvalue{\v!unit} [uFarad] {\Micro \Farad} {micro Farad}
+\getvalue{\v!unit} [mFarad] {\Milli \Farad} {milli Farad}
+
+\getvalue{\v!unit} [Ohm] {\Omega} {Ohm}
+\getvalue{\v!unit} [kOhm] {\Kilo \Ohm} {kilo Ohm}
+
+\getvalue{\v!unit} [Siemens] {S} {Siemens}
+
+\getvalue{\v!unit} [Ampere] {A} {Amp\`ere}
+\getvalue{\v!unit} [mAmpere] {\Milli \Ampere} {milli Amp\`ere}
+
+\getvalue{\v!unit} [Coulomb] {C} {Coulomb}
+
+\getvalue{\v!unit} [Volt] {V} {Volt}
+\getvalue{\v!unit} [mVolt] {\Milli \Volt} {milli Volt}
+\getvalue{\v!unit} [kVolt] {\Kilo \Volt} {kilo Volt}
+\getvalue{\v!unit} [eVolt] {eV} {electronvolt}
+\getvalue{\v!unit} [keVolt] {\Kilo \eVolt} {kilo electronvolt}
+\getvalue{\v!unit} [MeVolt] {\Mega \eVolt} {mega electronvolt}
+
+\getvalue{\v!unit} [Tesla] {T} {Tesla}
+
+\getvalue{\v!unit} [VoltAC] {V_{\xbox{ac}}} {\labeltext{u:vac}}
+\getvalue{\v!unit} [VoltDC] {V_{\xbox{dc}}} {\labeltext{u:vdc}}
+
+\setuplabeltext
+ [\s!nl]
+ [u:vac=wisselspanning,
+ u:vdc=gelijkspanning]
+
+\setuplabeltext
+ [\s!en]
+ [u:vac=alternating current,
+ u:vdc=direct current]
+
+\setuplabeltext
+ [\s!de]
+ [u:vac=Wechselspannung,
+ u:vdc=Gleichspannung]
+
+\setuplabeltext
+ [\s!it]
+ [u:vac=corrente alternata,
+ u:vdc=corrente continua]
+
+%D Computer memory is specified in Bytes:
+
+\getvalue{\v!unit} [Baud] {Baud} {Baud (Bit/s)}
+\getvalue{\v!unit} [Bit] {Bit} {Bit}
+
+\getvalue{\v!unit} [Byte] {Byte} {Byte}
+\getvalue{\v!unit} [kByte] {\Kilo \Byte} {kilo Byte}
+\getvalue{\v!unit} [MByte] {\Mega \Byte} {mega Byte}
+\getvalue{\v!unit} [GByte] {\Giga \Byte} {giga Byte}
+\getvalue{\v!unit} [TByte] {\Tera \Byte} {tera Byte}
+
+%D Some radiation related units:
+
+\getvalue{\v!unit} [Bequerel] {Bq} {Bequerel}
+\getvalue{\v!unit} [MBequerel] {\Mega \Bequerel} {Bequerel}
+\getvalue{\v!unit} [Sievert] {Sv} {Sievert}
+\getvalue{\v!unit} [mSievert] {\Milli \Sievert} {milli Sievert}
+
+%D Light:
+
+\getvalue{\v!unit} [Candela] {cd} {Candela}
+
+%D and some sound ones:
+
+\getvalue{\v!unit} [Bell] {B} {Bell}
+\getvalue{\v!unit} [dBell] {\Deci \Bell} {decibel}
+
+%D We also define some non||regular, sometimes even forbidden,
+%D units:
+
+\getvalue{\v!unit} [At] {at} {\labeltext{u:at}}
+\getvalue{\v!unit} [Atm] {atm} {\labeltext{u:atm}}
+\getvalue{\v!unit} [Bar] {bar} {bar (100 \Kilo \Pascal)}
+\getvalue{\v!unit} [EVolt] {eV} {electronvolt}
+\getvalue{\v!unit} [Foot] {ft} {\labeltext{u:ft}}
+\getvalue{\v!unit} [Inch] {inch} {inch}
+\getvalue{\v!unit} [Cal] {cal} {\labeltext{u:cal}}
+\getvalue{\v!unit} [Force] {f} {\labeltext{u:f}}
+\getvalue{\v!unit} [kCal] {\Kilo \Cal} {\labeltext{u:kcal}}
+\getvalue{\v!unit} [Lux] {lux} {lux}
+
+
+\def\xPercent {\dimensionaddfix{\percent }}
+\def\xPromille{\dimensionaddfix{\promille}}
+
+\getvalue{\v!unit} [Percent] {\xPercent } {percent}
+\getvalue{\v!unit} [Permille] {\xPromille} {promille}
+\getvalue{\v!unit} [Promille] {\xPromille} {promille}
+
+%D Some more, thanks to Tobias:
+
+\getvalue{\v!unit} [Gray] {Gr} {Gray}
+\getvalue{\v!unit} [Weber] {Wb} {Weber}
+\getvalue{\v!unit} [Henry] {H} {Henry}
+\getvalue{\v!unit} [Sterant] {sr} {Sterant}
+\getvalue{\v!unit} [Angstrom] {\hbox{\Aring}} {\Aring ngstr\"om}
+\getvalue{\v!unit} [Gauss] {G} {Gauss}
+
+\setuplabeltext
+ [\s!nl]
+ [u:at=technische atmosfeer,
+ u:atm=fysische atmosfeer,
+ u:ft=voet,
+ u:cal=calorie,
+ u:f=kracht (force),
+ u:kcal=kilocalorie]
+
+\setuplabeltext
+ [\s!en]
+ [u:at=technical atmosferic pressure,
+ u:atm=physical atmosferic pressure,
+ u:ft=foot,
+ u:cal=calory,
+ u:f=force,
+ u:kcal=kilocalory]
+
+\setuplabeltext
+ [\s!de]
+ [u:at=Technischer atmosph\"arischer Druck,
+ u:atm=physkalischer atmosph\"arischer Druck
+ u:ft=Fu\SS,
+ u:cal=Kalorien,
+ u:f=Force,
+ u:kcal=Kilokalorien]
+
+\setuplabeltext
+ [\s!it]
+ [u:at=pressione atmosferica tecnica,
+ u:atm=pressione atmosfera fisica,
+ u:ft=piede,
+ u:cal=caloria,
+ u:f=forza,
+ u:kcal=chilocaloria]
+
+%D Here are some old ones, still there for compatibility
+%D reasons. These will probably be obsolete in a few years.
+
+\def\MeterTwee {\Square \Meter}
+\def\mMeterTwee {\Square \Milli \Meter}
+\def\cMeterTwee {\Square \Centi \Meter}
+\def\dMeterTwee {\Square \Deci \Meter}
+\def\kMeterTwee {\Square \Kilo \Meter}
+
+\def\MeterDrie {\Cubic \Meter}
+\def\mMeterDrie {\Cubic \Milli \Meter}
+\def\cMeterDrie {\Kubic \Centi \Meter}
+\def\dMeterDrie {\Cubic \Deci \Meter}
+\def\kMeterDrie {\Cubic \Kilo \Meter}
+
+\def\LiterTwee {\Square \Liter}
+\def\SecTwee {\Square \Sec}
+\def\SecMinEen {\Inverse \Sec}
+
+%D To make ourselves happy, we define some dutch specific
+%D units:
+
+\startinterface dutch
+
+ \getvalue{\v!unit} [PaardenKracht] {pk} {paardenkracht}
+ \getvalue{\v!unit} [Duits] {D} {duits}
+ \getvalue{\v!unit} [Kwik] {Hg} {kwikkolom}
+ \getvalue{\v!unit} [Hectare] {ha} {hectare}
+ \getvalue{\v!unit} [kGramForce] {\Kilo \Gram \Force} {kilogramforce}
+ \getvalue{\v!unit} [kWattUur] {\Kilo \Watt \Uur} {kilowattuur}
+ \getvalue{\v!unit} [MeterKwik] {\Meter \Kwik} {meter kwikkolom}
+ \getvalue{\v!unit} [Waterkolom] {WK} {waterkolom}
+ \getvalue{\v!unit} [MeterWater] {\Meter \Waterkolom} {meter waterkolom}
+ \getvalue{\v!unit} [DrogeStof] {ds} {droge stof}
+ \getvalue{\v!unit} [Normaal] {N} {normaal}
+
+ \getvalue{\v!unit} [Ton] {t} {ton}
+ \getvalue{\v!unit} [kTon] {\Kilo \Ton} {kiloton}
+
+ \let \OmwPerSec \RevPerSec
+ \let \OmwPerMin \RevPerMin
+ \let \Graden \Deg
+ \let \PaardeKracht \PaardenKracht
+ \let \Atoom \Atom
+ \let \Heure \Hour
+ \let \Jaar \Year
+ \let \Maand \Month
+ \let \Dag \Day
+ \let \Uur \Hour
+
+\stopinterface
+
+%D Finally we define some equivalents. By using \type {\let}
+%D we can be sure that they don't end up double in the lists of
+%D units.
+
+\let \Second \Sec
+\let \Kubic \Cubic
+\let \IKubic \ICubic
+
+%D Option:
+
+% \def\Micro{\dimensionprefix{\iftextdimensions\mathematics\mu \else\mu \fi}}
+% \def\Times{\dimensionnopfix{\iftextdimensions\mathematics\cdot\else\cdot\fi}}
+
+\protect \endinput
diff --git a/tex/context/base/m-visual.tex b/tex/context/base/m-visual.tex
new file mode 100644
index 000000000..d78455190
--- /dev/null
+++ b/tex/context/base/m-visual.tex
@@ -0,0 +1,316 @@
+%D \module
+%D [ file=m-visual,
+%D version=2000.01.10,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Visualization and Faking,
+%D author={Hans Hagen \& Ton Otten},
+%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.
+
+\unprotect
+
+%D This module collect a few more visual debugger features. I
+%D needed them for manuals and styles. The macros are documented
+%D in a my way document.
+
+%D For Mojca:
+%D
+%D \starttyping
+%D \def\simplethesis
+%D {\setupsystem[random=1234]
+%D \title{\fakewords{3}{4}}
+%D \placelist[chapter,section]
+%D \dorecurse{6}
+%D {\chapter{\fakewords{5}{10}}
+%D \dorecurse{5}
+%D {\section{\fakewords{2}{5}}
+%D \dorecurse{2}
+%D {\dorecurse{3}{\fakewords{100}{200}\endgraf}
+%D \placefigure{\fakewords{8}{15}}{\fakefigure{5cm}{3cm}{10cm}{5cm}}
+%D \dorecurse{2}{\fakewords{100}{200}\endgraf}}}}}
+%D
+%D \starttext
+%D \simplethesis
+%D \stoptext
+%D \stoptyping
+
+\definecolor[fakerulecolor] [black]
+\definecolor[fakebaselinecolor] [green]
+\definecolor[fakeparindentcolor][blue]
+
+\newif\iffakebaseline \fakebaselinetrue
+
+\def\fakerule#1%
+ {\strut
+ \startcolor[fakerulecolor]%
+ \iffakebaseline
+ \vrule\!!height1.25ex\!!depth-.05ex\!!width#1%
+ \kern-#1%
+ \vrule\!!height-.05ex\!!depth .25ex\!!width#1%
+ \else
+ \vrule\!!height1.25ex\!!depth .25ex\!!width#1%
+ \fi
+ \stopcolor
+ \allowbreak}
+
+\def\dorandomrecurse#1%
+ {\getrandomcount\scratchcounter{1}{#1}%
+ \dorecurse\scratchcounter}
+
+% can be used in hbox, so %'s are really needed
+
+\unexpanded\def\fakelines#1#2% min max / 3 10
+ {\fakeparindent
+ \scratchdimen\hsize
+ \ifindentation
+ \advance\scratchdimen -\parindent
+ \fi
+ \fakerule\scratchdimen\break
+ \getrandomcount\scratchcounter{\ifcase0#1 3\else#1\fi}{\ifcase0#2 10\else#2\fi}%
+ \dorecurse\scratchcounter{\fakerule\hsize}%
+ \getrandomdimen\scratchdimen{.25\hsize}\hsize
+ \fakerule\scratchdimen
+ \par} % indeed
+
+\unexpanded\def\fakewords
+ {\ifvmode\fakeparindent\fi\onlyfakewords}
+
+\definepalet
+ [fakerule]
+ [fr1c=darkred,
+ fr2c=darkgreen,
+ fr3c=darkblue,
+ fr4c=darkyellow,
+ fr5c=darkgray]
+
+\unexpanded\def\onlyfakewords#1#2% min max / 10 40
+ {\getrandomcount\scratchcounter{\ifcase0#1 10\else#1\fi}{\ifcase0#2 40\else#2\fi}%
+ \dofakewords\scratchcounter
+ } % no \par
+
+\unexpanded\def\fakenwords#1#2% words seed
+ {\fakeparindent
+ \getrandomseed\fakedwordseed
+ \setrandomseed{\ifcase0#2 #1\else#2\fi}%
+ \dofakewords{#1}%
+ \setrandomseed\fakedwordseed
+ } % no \par
+
+\def\dofakewords#1%
+ {\bgroup
+ \dorecurse{#1}
+ {\getrandomcount\scratchcounter{1}{5}%
+ \dorecurse\scratchcounter
+ {\getrandomdimen\scratchdimen{.5em}{1.25em}%
+ \fakerule\scratchdimen}%
+ \space}%
+ \removeunwantedspaces
+ \egroup}
+
+\def\doshowfakewords#1%
+ {\bgroup
+ \setuppalet[fakerule]%
+ \definecolor[fakerulecolor]%
+ \dorecurse{#1}
+ {\getrandomcount\scratchcounter{1}{5}%
+ \dorecurse\scratchcounter
+ {\getrandomdimen\scratchdimen{.5em}{1.25em}%
+ \color[fr\recurselevel c]{\fakerule\scratchdimen}}%
+ \space}%
+ \removeunwantedspaces
+ \egroup}
+
+\def\showfakewords{\let\dofakewords\doshowfakewords}
+
+\def\fakeword
+ {\fakewords{1}{1}} % no \plusone
+
+\def\fakeparindent
+ {\noindent
+ \ifindentation
+ \ifx\dofakedroppedcaps\relax
+ {\fakeparindentcolor
+ \vrule
+ \!!height \strutheight % not longer .5ex
+ \!!depth \strutdepth % not longer 0pt
+ \!!width \parindent}%
+ \else
+ \dofakedroppedcaps \let\dofakedroppedcaps\relax
+ \fi
+% \else
+% \dontleavehmode
+ \fi}
+
+\let\dofakedroppedcaps\relax
+
+\unexpanded\def\fakedroppedcaps#1%
+ {\ifnum#1>0
+ \def\dofakedroppedcaps
+ {\setbox\scratchbox\hbox
+ {\setbox\scratchbox\hbox{W}%
+ \scratchdimen#1\lineheight
+ \advance\scratchdimen -\lineheight
+ \advance\scratchdimen \dp\strutbox
+ \vrule
+ \!!width#1\wd\scratchbox
+ \!!height\ht\scratchbox
+ \!!depth\scratchdimen}%
+ \ht\scratchbox\ht\strutbox
+ \dp\scratchbox\dp\strutbox
+ \hangindent\wd\scratchbox
+ \advance\hangindent .5em
+ \wd\scratchbox\hangindent
+ \hangafter-#1\noindent
+ \llap{\fakeparindentcolor\box\scratchbox}}%
+ \fi}
+
+\newcounter\noffakedfigures
+
+\unexpanded\def\showfakefigure
+ {\donetrue\dodoubleempty\dofakefigure}
+
+\unexpanded\def\fakefigure
+ {\donefalse\dodoubleempty\dofakefigure}
+
+\def\dofakefigure[#1][#2]#3#4#5#6% [] [] minwidth maxwidth minheight maxheight
+ {\doglobal\increment\noffakedfigures
+ \ifdone
+ \endgraf
+ \hbox to \hsize
+ {\hss\fakeparindentcolor
+ \strut\bf Figure \noffakedfigures
+ \doifsomething{#1}{\space(#1)}%
+ \hss}
+ \endgraf
+ \fi
+ \getvalue{\e!place\v!figure}
+ [#1][#2]%
+ {\freezerandomseed
+ \let\endstrut\relax
+ \let\begstrut\relax
+ \doifinsetelse{#1}{\v!left,\v!right}
+ {\fakewords{2}{4}}
+ {\fakewords{4}{10}}}%
+ {\getrandomdimen{\dimen0}{#3}{#4}%
+ \getrandomdimen{\dimen2}{#5}{#6}%
+ \doifinset{#1}{\v!left,\v!right}
+ {\dimen0=.75\dimen0
+ \ifdim\dimen0>.6\hsize \dimen0=.5\hsize\fi
+ \ifdim\dimen0<.3\hsize \dimen0=.3\hsize\fi}%
+ \framed
+ [\c!width=\dimen0,
+ \c!height=\dimen2,
+ \c!frame=\ifincolor\v!off\else\v!on\fi,
+ \c!background=\v!color,
+ \c!backgroundcolor=fakeparindentcolor]
+ {\bf\white#1}}%
+ \defrostrandomseed}
+
+\def\fakeformula
+ {\dimen0\zeropoint
+ \getrandomcount\scratchcounter{3}{6}%
+ \dorecurse\scratchcounter
+ {\getrandomdimen\scratchdimen{1em}{3em}%
+ \mathinner{\red\fakerule\scratchdimen}%
+ \ifnum\recurselevel<\scratchcounter+\fi
+ \advance\scratchdimen\dimen0}%
+ =\mathinner{\red\fakerule\scratchdimen}}
+
+\def\fakespacingformula
+ {\color[fakebaselinecolor]{\ruledbaseline}\fakeformula}
+
+%D test \type{\bodyfontgrid}\space test
+%D test \type{\emexgrid} \space test
+
+
+\def\smashedgrid
+ {\dosingleempty\dosmashedgrid}
+
+\def\dosmashedgrid[#1]%
+ {\hsmashed
+ {\setbox\scratchbox=\hbox
+ {\basegrid
+ [\c!nx=10,\c!ny=10,\c!dx=1,\c!dy=1,
+ \c!unit=\bodyfontsize,#1]}%
+ \hbox to \zeropoint
+ {\hss\lower.5\ht\scratchbox\box\scratchbox\hss}%
+ \hbox to \zeropoint
+ {\hss
+ \black\vrule\!!width6\linewidth\!!height3\linewidth\!!depth3\linewidth
+ \hss}}}
+
+\def\bodyfontgrid
+ {\hbox
+ {{\linewidth.1pt\yellow\smashedgrid[\c!nx=30,\c!ny=30,\c!scale=.3333]}%
+ {\linewidth.2pt\green \smashedgrid[\c!nx=20,\c!ny=20,\c!scale=.5]}%
+ {\linewidth.3pt\red \smashedgrid[\c!nx=10,\c!ny=10,\c!scale=1]}}}
+
+\def\emexgrid
+ {\hbox
+ {{\linewidth.15pt\green\smashedgrid[\c!nx=20,\c!ny=20,\c!unit=ex]}%
+ {\linewidth.15pt\red \smashedgrid[\c!nx=10,\c!ny=10,\c!unit=em]}}}
+
+%D The next few macros are not really public and kind of low
+%D level. They are obscure and a bit perverse.
+
+\definecolor[llblack][s=0.01]
+
+\def\lowlevelstream#1#2#3%
+ {\ifinotr \else
+ \dontleavehmode
+ \prewordbreak
+ \bgroup\bgroup % make sure aftergroup stuff is handled
+ %\let#1#2\optimizetransparencyfalse\black
+ \infofont\clap{\vl}\ignorespaces#3\unskip\clap{\vl}%
+ \egroup\egroup
+ \prewordbreak
+ \fi
+ #2{#3}}
+
+\let\normalPDFcode\PDFcode
+
+\def\showlowlevelstream
+ {\def\PDFcode{\lowlevelstream\PDFcode\normalPDFcode}%
+ \def\special{\lowlevelstream\special\normalspecial}}
+
+\def\showlowlevelstreamonly
+ {\def\PDFcode{\lowlevelstream\PDFcode\gobbleoneargument}%
+ \def\special{\lowlevelstream\special\gobbleoneargument}}
+
+\startnotmode[mkiv]
+
+ \let\normaldostartgraymode \dostartgraymode
+ \let\normaldostartgraycolormode\dostartgraycolormode
+ \let\normaldostartrgbcolormode \dostartrgbcolormode
+ \let\normaldostartcmykcolormode\dostartcmykcolormode
+ \let\normaldostartspotcolormode\dostartspotcolormode
+
+ \def\traceddostartgraymode#1%
+ {#1\normaldostartgraymode{#1}}
+
+ \def\traceddostartgraycolormode#1%
+ {#1\normaldostartgraycolormode{#1}}
+
+ \def\traceddostartrgbcolormode#1#2#3%
+ {#1 #2 #3\normaldostartrgbcolormode{#1}{#2}{#3}}
+
+ \def\traceddostartcmykcolormode#1#2#3#4%
+ {#1 #2 #3 #4\normaldostartcmykcolormode{#1}{#2}{#3}{#4}}
+
+ \def\traceddostartspotcolormode#1#2%
+ {#1 #2\normaldostartspotcolormode{#1}{#2}}
+
+ \def\showcolormodes
+ {\let\dostartgraymode \traceddostartgraymode
+ \let\dostartgraycolormode\traceddostartgraycolormode
+ \let\dostartrgbcolormode \traceddostartrgbcolormode
+ \let\dostartcmykcolormode\traceddostartcmykcolormode
+ \let\dostartspotcolormode\traceddostartspotcolormode}
+
+\stopnotmode
+
+\protect \endinput
diff --git a/tex/context/base/math-ali.mkiv b/tex/context/base/math-ali.mkiv
new file mode 100644
index 000000000..31f71219a
--- /dev/null
+++ b/tex/context/base/math-ali.mkiv
@@ -0,0 +1,1296 @@
+%D \module
+%D [ file=math-ali,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Math Alignments,
+%D author={Hans Hagen, Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%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 Math Macros / Math Alignments}
+
+\unprotect
+
+%D The code here has been moved from other files. Beware: the \MKII\ and
+%D \MKIV\ code is not gathered in files with the same name.
+
+%D \macros
+%D {definemathalignment, setupmathalignment, startmathalignment}
+%D
+%D Modules may provide additional alignment features. The following
+%D mechanisms are provided by the core.
+
+% n>1 #### needed, strange # interaction in recurse
+
+\def\presetdisplaymath{\displ@y} % some day i will relocate the plain stuff
+
+\def\buildeqalign
+ {\scratchtoks\emptytoks
+ \dorecurse{\mathalignmentparameter\c!m}
+ {\ifnum\recurselevel>\plusone
+ \appendtoks
+ \tabskip\mathalignmentparameter\c!distance&\tabskip\zeropoint
+ \to\scratchtoks
+ \fi
+ \normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksa}}%
+ \dorecurse{\numexpr\mathalignmentparameter\c!n-\plusone\relax}
+ {\normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksb}}}}%
+ \normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksc}}}
+
+\def\forgetalign
+ {\tabskip\zeropoint\everycr\emptytoks}
+
+\let\firstineqalign\empty
+\let\nextineqalign \empty
+\let\leftofeqalign \empty
+\let\rightofeqalign\empty
+
+\def\mathineqalign#1{$\forgetalign\displaystyle{{}#1{}}$}
+\def\textineqalign#1{$\forgetalign#1$}
+
+\def\eqalign#1% why no halign here, probably because of displaywidth
+ {\null\,\vcenter
+ {\openup.25\bodyfontsize% was: \openup\jot
+ \mathsurround\zeropoint
+ \ialign{\strut\hfil$\displaystyle{##}$&$\displaystyle{{}##{}}$\hfil\crcr#1\crcr}%
+ }\,}
+
+% preamble is scanned for tabskips so we need the span to prevent an error message
+
+\chardef\eqalignmode\plusone
+
+\def\preparereqalignno
+ {\!!toksa{\strut\firstineqalign\hfil\leftofeqalign\span\mathineqalign{##}\rightofeqalign\tabskip\zeropoint}%
+ \!!toksb{&\nextineqalign\leftofeqalign\span\mathineqalign{##}\rightofeqalign\tabskip\zeropoint}%
+ \ifnum\mathraggedstatus=\plusone
+ \!!toksc{\hfil&\span\textineqalign{##}\tabskip\zeropoint}%
+ \else\ifnum\mathraggedstatus=\plusthree
+ \!!toksc{\hfil\tabskip\zeropoint\!!plus 1\!!fill&\span\textineqalign{##}\tabskip\zeropoint}%
+ \else
+ \!!toksc{\hfil\tabskip\centering&\llap{\span\textineqalign{##}}\tabskip\zeropoint}%
+ \fi\fi
+ \global\chardef\mathnumberstatus\zerocount
+ \buildeqalign
+ \presetdisplaymath
+ \tabskip\centering}
+
+\def\prepareleqalignno
+ {\!!toksa{\strut\firstineqalign\hfil\leftofeqalign\span\mathineqalign{##}\rightofeqalign\tabskip\zeropoint}%
+ \!!toksb{&\nextineqalign\leftofeqalign\span\mathineqalign{##}\rightofeqalign\tabskip\zeropoint}%
+ % problem: number is handled after rest and so ends up in the margin
+ \ifnum\mathraggedstatus=\plusone
+ \!!toksc{\hfil&\kern-\displaywidth\rlap{\span\textineqalign{##}}\tabskip\displaywidth}%
+ \else\ifnum\mathraggedstatus=\plusthree
+ \!!toksc{\hfil\tabskip\zeropoint\!!plus 1\!!fill&\kern-\displaywidth\span\mrlap{\span\textineqalign{##}}\tabskip\displaywidth}%
+ \else
+ \!!toksc{\hfil\tabskip\centering&\kern-\displaywidth\rlap{\span\textineqalign{##}}\tabskip\displaywidth}%
+ \fi\fi
+ \global\chardef\mathnumberstatus\zerocount
+ \buildeqalign
+ \presetdisplaymath
+ \tabskip\centering}
+
+\def\dobotheqalignno#1#2%
+ {\ifmmode
+ \displ@y % \let\doplaceformulanumber\relax % strange hack
+ \vcenter\bgroup
+ \let\finishalignno\egroup
+ \else
+ \let\finishalignno\relax
+ \fi
+ #1%
+ \halign \ifcase\eqalignmode \or to \displaywidth \fi \@EA {\the\scratchtoks\crcr#2\crcr}%
+ \finishalignno}
+
+\def\dobothaligneqalignno#1%
+ {\ifmmode
+ \displ@y
+ \global\chardef\mathnumberstatus\plusone
+ \ifcase\mathraggedstatus
+ \def\finishalignno{\crcr\egroup}%
+ \else
+ % we're in a mathbox
+ \vcenter\bgroup
+ \def\finishalignno{\crcr\egroup\egroup}%
+ \fi
+ \fi
+ #1%
+ \halign \ifcase\eqalignmode \or to \displaywidth \fi \@EA \bgroup\the\scratchtoks\crcr}
+
+\def\mrlap#1%
+ {\setbox\scratchbox\hbox{#1}%
+ \ifdim\wd\scratchbox>\mathnumbercorrection
+ \xdef\mathnumbercorrection{\the\wd\scratchbox}%
+ \fi
+ \box\scratchbox
+ \global\chardef\mathnumberstatus\plustwo}
+
+% \def\dobothaligneqalignno#1%
+% {\ifmmode
+% \displ@y
+% \global\chardef\mathnumberstatus\plusone
+% we're in a mathbox
+% \vcenter\bgroup
+% \def\finishalignno{\crcr\egroup\egroup}%
+% \else
+% \def\finishalignno{\crcr\egroup}%
+% \fi
+% #1%
+% \halign \ifcase\eqalignmode \or to \displaywidth \fi \@EA \bgroup\the\scratchtoks\crcr}
+
+\def\reqalignno {\dobotheqalignno \preparereqalignno}
+\def\leqalignno {\dobotheqalignno \prepareleqalignno}
+\def\alignreqalignno{\dobothaligneqalignno\preparereqalignno}
+\def\alignleqalignno{\dobothaligneqalignno\prepareleqalignno}
+\def\finishalignno {\crcr\egroup}
+
+\let \equalignno \reqalignno
+\let\aligneqalignno\alignreqalignno
+
+%D Here we implement the user interface part.
+
+\unexpanded\def\setupmathalignment
+ {\dodoubleempty\dosetupmathalignment}
+
+\def\dosetupmathalignment[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??eq#1][#2]%
+ \else
+ \getparameters[\??eq][#1]%
+ \fi}
+
+\let\currentmathalignment\empty
+
+\def\mathalignmentparameter#1%
+ {\executeifdefined{\??eq\currentmathalignment#1}{\executeifdefined{\??eq#1}\empty}}
+
+\setupmathalignment
+ [\c!n=2,
+ \c!m=1,
+ \c!distance=1em]
+
+\def\numberedeqalign
+ {\doifelse{\formulaparameter\c!location}\v!left\alignleqalignno\alignreqalignno}
+
+\def\doxxdoubleempty#1#2%
+ {\ifx#2[\expandafter\dodoxxdoubleempty\else\expandafter\noxxdoubleempty\fi#1#2}
+
+\def\dodoxxdoubleempty#1[#2]#3%
+ {\ifx#3[\else\expandafter\nonoxxdoubleempty\fi#1[#2]#3}
+
+\def\noxxdoubleempty #1{#1[][]}
+\def\nonoxxdoubleempty#1[#2]{#1[#2][]}
+
+\newcount\eqaligncolumn
+
+\def\firstineqalign{\global\eqaligncolumn\plusone}
+\def\nextineqalign {\global\advance\eqaligncolumn\plusone}
+\def\leftofeqalign {\getvalue{\??eq:\v!left :\number\eqaligncolumn}}
+\def\rightofeqalign{\getvalue{\??eq:\v!right:\number\eqaligncolumn}}
+
+\def\doseteqaligncolumn#1%
+ {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\empty
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\empty
+ \doif{#1}\v!left {\letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfill}%
+ \doif{#1}\v!right {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfill}%
+ \doif{#1}\v!middle{\letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfill
+ \letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfill}}
+
+\def\dodoalignNC
+ {\gdef\doalignNC##1{#1}}
+
+\def\doalignNR[#1][#2]%
+ {\donestedformulanumber{#1}{#2}\crcr}
+
+%D \starttyping
+%D \placeformula[eqn0]\startformula \startalign[n=1] a\NR \stopalign \stopformula See \in[eqn0]
+%D \placeformula[eqn1]\startformula \startalign[n=1] a\NR \stopalign \stopformula See \in[eqn1]
+%D \placeformula \startformula \startalign[n=1] a\NR[eqn2] \stopalign \stopformula See \in[eqn2]
+%D \placeformula[eqn3]\startformula \startalign[n=1] a\NR[+] \stopalign \stopformula See \in[eqn3]
+%D \stoptyping
+
+% todo: pop in cell
+
+\def\dostartmathalignment[#1][#2]%
+ {% \begingroup not permitted ($$...assignments...\halign... )
+ \pushmacro\doalignNC
+ \edef\currentmathalignment{#1}%
+ \doifassignmentelse{#2}{\setupmathalignment[#1][#2]}\donothing
+ \def\NC{\doalignNC}%
+ \global\let\doalignNC\dodoalignNC
+ \def\EQ{&=}%
+ \def\NR{&\global\let\doalignNC\dodoalignNC\doxxdoubleempty\doalignNR}%
+ % amstex compatibility mode: (ugly, will disappear)
+ \def\notag{\def\\{&\crcr}}%
+ \doifelse{#2}{*}{\def\\{&\crcr}}{\def\\{&\doalignNR[+][]\crcr}}%
+ % end of compatibility mode
+ \eqaligncolumn\zerocount
+ \processcommacommand
+ [\mathalignmentparameter\c!align]
+ {\advance\eqaligncolumn\plusone\doseteqaligncolumn}% takes argument
+ % the real action
+ \global\eqaligncolumn\plusone
+ \numberedeqalign}
+
+\def\dostopmathalignment
+ {\finishalignno
+ \popmacro\doalignNC}
+
+\unexpanded\def\definemathalignment
+ {\dodoubleempty\dodefinemathalignment}
+
+\def\dodefinemathalignment[#1]% [#2]%
+ {\setvalue{\e!start#1}{\dodoubleempty\dostartmathalignment[#1]}%
+ \setvalue{\e!stop #1}{\dostopmathalignment}%
+ \setupmathalignment[#1]}% [#2]
+
+%D For the moment we only provide english commands.
+
+\definemathalignment[align] % default case (this is what amstex users expect)
+\definemathalignment[\v!mathalignment] % prefered case (this is cleaner, less clashing)
+
+%D \startbuffer
+%D \placeformula \startformula \eqalignno {
+%D a &= b & \formulanumber \cr
+%D c &= d \cr
+%D &= e \cr
+%D &= f & \formulanumber
+%D } \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D \NC a \EQ b \NR[+]
+%D \NC c \EQ d \NR
+%D \NC \EQ f \NR[for:demo-a-1]
+%D \NC \EQ g \NR[for:demo-a-2][a]
+%D \NC \EQ h \NR[for:demo-a-3][b]
+%D \NC \EQ i \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D \NC a \EQ b \NR[+]
+%D \NC c \EQ d \NR
+%D \NC \EQ f \NR
+%D \NC \EQ g \NR
+%D \NC \EQ h \NR
+%D \NC \EQ i \NR[+]
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D a &= b \\
+%D c &= d \notag \\
+%D &= e \notag \\
+%D &= f \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D \NC a \NC \eq b \NR[+]
+%D \NC c \NC \neq d \NR
+%D \NC \NC \neq f \NR[for:demo-b-1]
+%D \NC \NC \geq g \NR[for:demo-b-2][a]
+%D \NC \NC \leq h \NR[for:demo-b-3][b]
+%D \NC \NC \neq i \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[*]
+%D a &= b \\
+%D c &= d \\
+%D &= e \\
+%D &= f \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D x &= y \\
+%D a &= b \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[m=3]
+%D x &= y & x &= y & z &= t \\
+%D a &= b & p &= q & w &= s \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[m=3,distance=0pt]
+%D x &= y &= x &= y &= z &= t \\
+%D a &= b &= p &= q &= w &= s \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[n=5,distance=0pt]
+%D x &= yy &= xx &= yy &= zz \\
+%D a &= b &= p &= q &= w \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[n=3,align={left,middle,right}]
+%D \NC l \NC = \NC r \NR
+%D \NC left \NC = \NC right \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[n=3,align={right,middle,left}]
+%D \NC l \NC = \NC r \NR
+%D \NC left \NC = \NC right \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[n=3,align={middle,middle,middle}]
+%D \NC l \NC = \NC r \NR
+%D \NC left \NC = \NC right \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula
+%D \startformula
+%D \startalign[n=3,align={middle,middle,middle}]
+%D \NC a \NC = \NC b \NR[+]
+%D \NC 2a \NC = \NC 2b \NR
+%D \stopalign
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula
+%D \startformulas
+%D \setupmathalignment[n=3,align={middle,middle,middle}]%
+%D \startformula
+%D \startalign
+%D \NC a \NC = \NC b \NR[+]
+%D \NC 2a \NC = \NC 2b \NR
+%D \stopalign
+%D \stopformula
+%D \startformula
+%D \startalign
+%D \NC a \NC = \NC b \NR[+]
+%D \NC 2a \NC = \NC 2b \NR
+%D \stopalign
+%D \stopformula
+%D \stopformulas
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula
+%D \startformulas
+%D \dorecurse{5}{\startformula
+%D \startalign[n=3,align={middle,middle,middle}]
+%D \NC a \NC = \NC b \NR[+]
+%D \NC 2a \NC = \NC 2b \NR
+%D \stopalign
+%D \stopformula}
+%D \stopformulas
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {definemathcases, setupmathcases, startmathcases}
+%D
+%D Another wish \unknown
+
+\unexpanded\def\setupmathcases
+ {\dodoubleempty\dosetupmathcases}
+
+\def\dosetupmathcases[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??ce#1][#2]%
+ \else
+ \getparameters[\??ce][#1]%
+ \fi}
+
+\let\currentmathcases\empty
+
+\def\mathcasesparameter#1%
+ {\executeifdefined{\??ce\currentmathcases#1}{\executeifdefined{\??ce#1}\empty}}
+
+\setupmathcases
+ [\c!distance=1em,
+ \c!numberdistance=2.5em,
+ \c!left={\left\{\,},
+ \c!right={\right.}]
+
+\def\dodocasesNC
+ {\gdef\docasesNC{\endmath&}}
+
+\let\docasesNR\doalignNR
+
+\def\dostartmathcases[#1][#2]%
+ {\begingroup
+ \edef\currentmathcases{#1}%
+ \doifassignmentelse{#2}{\setupmathcases[#1][#2]}\donothing
+ \mathcasesparameter\c!left
+ \vcenter\bgroup
+ \pushmacro\docasesNC
+ \let\endmath\relax
+ \def\NC{\docasesNC}%
+ \def\MC{\docasesNC\ifmmode\else$\def\endmath{$}\fi}%
+ \global\let\docasesNC\dodocasesNC
+ \def\NR{\unskip\endmath&\global\let\docasesNC\dodocasesNC\doxxdoubleempty\docasesNR}%
+ \normalbaselines
+ \mathsurround\zeropoint
+ \everycr\emptytoks
+ \tabskip\zeropoint
+ \global\eqaligncolumn\plusone
+ \halign\bgroup
+ $\mathcasesparameter\c!style##$\hfil
+ &\hskip\mathcasesparameter\c!distance\relax
+ \popmacro\docasesNC##\hfil
+ &\hskip\mathcasesparameter\c!numberdistance\relax
+ \let\formuladistance\!!zeropoint
+ \span\textineqalign{##}%
+ \crcr} % todo: number
+
+\def\dostopmathcases
+ {\crcr
+ \egroup
+ \popmacro\docasesNC
+ \egroup
+ \mathcasesparameter\c!right
+ \endgroup}
+
+\unexpanded\def\definemathcases
+ {\dodoubleempty\dodefinemathcases}
+
+\def\dodefinemathcases[#1]% [#2]%
+ {\setvalue{\e!start#1}{\dodoubleempty\dostartmathcases[#1]}%
+ \setvalue{\e!stop #1}{\dostopmathcases}%
+ \setupmathcases[#1]}% [#2]
+
+\definemathcases[cases]
+\definemathcases[\v!mathcases]
+
+%D \startbuffer
+%D \placeformula \startformula \startcases
+%D \NC 2 \NC $ y > 0 $ \NR
+%D \NC 7 \NC $ x = 7 $ \NR[+]
+%D \NC 4 \NC otherwise \NR
+%D \stopcases \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula x \startcases
+%D \NC 2 \NC $ y > 0 $ \NR[+]
+%D \NC 7 \NC $ x = 7 $ \NR
+%D \NC 4 \NC otherwise \NR
+%D \stopcases \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startcases
+%D \NC 2 \NC $ y > 0 $ \NR
+%D \NC 7 \NC $ x = 7 $ \NR
+%D \NC 4 \NC otherwise \NR
+%D \stopcases \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula x \startcases
+%D \NC 2 \NC $ y > 0 $ \NR
+%D \NC 7 \NC $ x = 7 $ \NR
+%D \NC 4 \NC otherwise \NR
+%D \stopcases \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {definemathmatrix, setupmathmatrix, startmathmatrix}
+%D
+%D Yet another one \unknown
+
+\unexpanded\def\setupmathmatrix
+ {\dodoubleempty\dosetupmathmatrix}
+
+\def\dosetupmathmatrix[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??mx#1][#2]%
+ \else
+ \getparameters[\??mx][#1]%
+ \fi}
+
+\let\currentmathmatrix\empty
+
+\def\mathmatrixparameter#1%
+ {\executeifdefined{\??mx\currentmathmatrix#1}{\executeifdefined{\??mx#1}\empty}}
+
+\setupmathmatrix
+ [\c!distance=1em,
+ \c!left=,
+ \c!right=,
+ \c!align=\v!middle]
+
+\def\dosetmatrixcolumn#1% hh: todo: \definematrixalign
+ {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfil
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfil
+ \doif{#1}\v!left {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\relax
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfil}%
+ \doif{#1}\v!right {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfil
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\relax }%
+ \doif{#1}\v!middle{\letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfil
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfil}}
+
+\def\buildmathmatrix % beware: etex only
+ {\scratchtoks\emptytoks
+ \normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksa}}%
+ \dorecurse{\numexpr\scratchcounter-\plusone\relax}
+ {\normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksb}}}%
+ \normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksc }}}
+
+\def\preparemathmatrix
+ {\!!toksa{\strut \firstineqalign\leftofeqalign \span
+ \textineqalign{\mathmatrixparameter\c!style ##}\rightofeqalign}%
+ \!!toksb{&\hskip\mathmatrixparameter\c!distance
+ \nextineqalign\leftofeqalign \span
+ \textineqalign{\mathmatrixparameter\c!style ##}\rightofeqalign}%
+ \!!toksc{&&\hskip\mathmatrixparameter\c!distance
+ \leftofeqalign \span
+ \textineqalign{\mathmatrixparameter\c!style ##}\rightofeqalign}%
+ \buildmathmatrix
+ \halign \@EA \bgroup\the\scratchtoks \crcr}
+
+\unexpanded\def\definemathmatrix
+ {\dodoubleempty\dodefinemathmatrix}
+
+\def\dodefinemathmatrix[#1]% [#2]%
+ {\setuvalue{\e!start#1}{\dodoubleempty\dostartmathmatrix[#1]}%
+ \setuvalue{\e!stop #1}{\dostopmathmatrix}%
+ \setupmathmatrix[#1]}% [#2]
+
+\definemathmatrix[matrix]
+\definemathmatrix[\v!mathmatrix]
+
+\unexpanded\def\dodomatrixNC
+ {\gdef\domatrixNC{\endmath&}}
+
+\def\installmathmatrixhandler#1#2%
+ {\setvalue{\??mx:#1}{#2}}
+
+% First alternative:
+%
+% \def\processlowhighmathmatrix#1%
+% {\def\mathmatrixleft
+% {\setbox\nextbox}
+% \def\mathmatrixright
+% {#1.5\dimexpr\nextboxdp-\nextboxht\relax
+% \hbox{$\mathmatrixparameter\c!left
+% \vcenter{\unvbox\nextbox}%
+% \mathmatrixparameter\c!right$}}%
+% \let\mathmatrixbox\vbox}
+%
+% \installmathmatrixhandler\v!high {\processlowhighmathmatrix\raise}
+% \installmathmatrixhandler\v!low {\processlowhighmathmatrix\lower}
+%
+% \installmathmatrixhandler\v!top {\processlowhighmathmatrix\raise}
+% \installmathmatrixhandler\v!bottom{\processlowhighmathmatrix\lower}
+%
+% \installmathmatrixhandler\v!lohi
+% {\def\mathmatrixleft {\mathmatrixparameter\c!left}%
+% \def\mathmatrixright{\mathmatrixparameter\c!right}%
+% \let\mathmatrixbox\vcenter}
+%
+% An alternative
+%
+% \let\mathmatrixleft \empty
+% \let\mathmatrixright\empty
+%
+% \def\processlowhighmathmatrix#1%
+% {\dowithnextbox
+% {#1.5\dimexpr\nextboxdp-\nextboxht\relax
+% \hbox{$\mathmatrixparameter\c!left
+% \vcenter{\unvbox\nextbox}%
+% \mathmatrixparameter\c!right$}}%
+% \vbox}
+%
+% \def\processlohimathmatrix
+% {\dowithnextbox
+% {\mathmatrixparameter\c!left
+% \vcenter{\unvbox\nextbox}%
+% \mathmatrixparameter\c!right}%
+% \vbox}
+%
+% \installmathmatrixhandler\v!high {\def\mathmatrixbox{\processlowhighmathmatrix\raise}}
+% \installmathmatrixhandler\v!low {\def\mathmatrixbox{\processlowhighmathmatrix\lower}}
+% \installmathmatrixhandler\v!top {\def\mathmatrixbox{\processlowhighmathmatrix\raise}}
+% \installmathmatrixhandler\v!bottom{\def\mathmatrixbox{\processlowhighmathmatrix\lower}}
+% \installmathmatrixhandler\v!lohi {\let\mathmatrixbox \processlohimathmatrix}
+%
+% Final version
+
+\let\mathmatrixleft \empty % experimental hook
+\let\mathmatrixright\empty % experimental hook
+
+\def\processlowhighmathmatrix#1#2%
+ {\dowithnextbox
+ {\scratchdimen\dimexpr(\nextboxdp-\nextboxht)/2 \ifcase#2\or+\mathaxisheight\textfont2\fi\relax
+ \ifcase#1\relax\or\lower\scratchdimen\or\or\raise\scratchdimen\fi
+ \hbox{$\mathmatrixparameter\c!left
+ \vcenter{\unvbox\nextbox}%
+ \mathmatrixparameter\c!right$}}%
+ \vbox}
+
+\installmathmatrixhandler\v!top {\def\mathmatrixbox{\processlowhighmathmatrix\plusthree\plusone }}
+\installmathmatrixhandler\v!high {\def\mathmatrixbox{\processlowhighmathmatrix\plusthree\zerocount}}
+\installmathmatrixhandler\v!lohi {\def\mathmatrixbox{\processlowhighmathmatrix\plustwo \zerocount}}
+\installmathmatrixhandler\v!low {\def\mathmatrixbox{\processlowhighmathmatrix\plusone \zerocount}}
+\installmathmatrixhandler\v!bottom{\def\mathmatrixbox{\processlowhighmathmatrix\plusone \plusone }}
+
+\def\dostartmathmatrix[#1][#2]%
+ {\begingroup
+ \edef\currentmathmatrix{#1}%
+ \doifassignmentelse{#2}{\setupmathmatrix[#1][#2]}\donothing
+ \null
+ \executeifdefined{\??mx:\mathmatrixparameter\c!location}{\getvalue{\??mx:\v!lohi}}%
+ \mathmatrixleft
+ \mathmatrixbox\bgroup
+ \pushmacro\domatrixNC
+ \let\endmath\relax
+ \def\NC{\domatrixNC}%
+ \def\MC{\domatrixNC\ifmmode\else$\def\endmath{$}\fi}%
+ \global\let\domatrixNC\dodomatrixNC
+ \def\NR{\endmath\global\let\domatrixNC\dodomatrixNC\crcr}%
+ \normalbaselines
+ \mathsurround\zeropoint
+ \everycr\emptytoks
+ \tabskip\zeropoint
+ \eqaligncolumn\zerocount % could be \scratchcounter
+ \processcommacommand[\mathmatrixparameter\c!align]{\advance\eqaligncolumn\plusone\dosetmatrixcolumn}%
+ \scratchcounter=\ifnum\eqaligncolumn>\zerocount \eqaligncolumn \else \plusone \fi
+ \global\eqaligncolumn\plusone
+ \preparemathmatrix } % uses scratchcounter
+
+\def\dostopmathmatrix
+ {\crcr
+ \mathstrut\crcr
+ \noalign{\kern-\baselineskip}%
+ \egroup
+ \popmacro\domatrixNC
+ \egroup
+ \mathmatrixright
+ \endgroup}
+
+%D \startbuffer
+%D \placeformula \startformula[-] \startmatrix
+%D \NC 1 \NC x \NC a \NR
+%D \NC 2 \NC y \NC b \NR
+%D \NC 3 \NC z \NC c \NR
+%D \stopmatrix \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \definemathmatrix[bmatrix][left={\left[\,},right={\,\right]}]
+%D
+%D \startbuffer
+%D \placeformula \startformula[-] \startbmatrix
+%D \NC 1 \NC x \NC a \NR
+%D \NC 2 \NC y \NC b \NR
+%D \NC 3 \NC z \NC c \NR
+%D \stopbmatrix \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D Taco added some code (dedicated to Aditya Mahajan) that gives more
+%D control over aligments:
+
+%D \startbuffer
+%D \startformula
+%D \startmatrix
+%D \NC a + x \NC = \NC a + d \NR
+%D \NC y \NC = \NC d \NR
+%D \stopmatrix
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \startbuffer
+%D \startformula
+%D \startmatrix [distance=3pt,align={right,left}]
+%D \NC a + x \NC = a + d \NR
+%D \NC y \NC = d \NR
+%D \stopmatrix
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \startbuffer
+%D \startformula
+%D \startmatrix [left=\left(,right=\right)]
+%D \NC a + x \NR
+%D \NC y \NR
+%D \stopmatrix
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D A bit more complex code:
+%D
+%D \startbuffer
+%D \startformula
+%D \text{Let }{\cal R} = \bigcup_{P_{X_1},P_{X_2}}
+%D \left\{ (R_1, R_2) :
+%D \startmatrix[distance=1em,align={left,left,right}]
+%D \NC R_1 \NC < I(X_1 ; Y \mid X_2) \NC R_1 \NR
+%D \NC \hfill Q_2 \NC < I(X_2 ; Y \mid X_1) \NC R_2 \NR
+%D \NC R_1 + R_2 \NC < I(X_1 ; Y) \NC R_1 + R_2 \NR
+%D \stopmatrix
+%D \right\}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {startmatrices}
+%D
+%D Just a handy keystroke safer:
+
+\unexpanded\def\startmatrices
+ {\begingroup
+ \setupmathmatrix}
+
+\unexpanded\def\stopmatrices
+ {\endgroup}
+
+%D \startbuffer
+%D \startformula
+%D \startmatrix[left={\left(},right={\right)}]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D =
+%D \startmatrix[left={\left(},right={\right)},location=low]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D =
+%D \startmatrix[left={\left(},right={\right)},location=high]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \startformula
+%D \startmatrices[left={\left(},right={\right)}]
+%D \startmatrix
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D =
+%D \startmatrix[location=bottom]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D =
+%D \startmatrix[location=top]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D \stopmatrices
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer % does not run well: \getbuffer
+
+%D \macros
+%D {startintertext}
+%D
+%D Preliminary feature:
+%D
+%D {\em example code}
+
+\unexpanded\def\startintertext#1\stopintertext
+ {\noalign{\dointertext{#1}}}
+
+\def\intertext#1%
+ {\noalign{\dointertext{#1}}}
+
+\unexpanded\def\dointertext#1%
+ {\penalty\postdisplaypenalty
+ \afterdisplayspace
+ \vbox{\forgetall\noindent#1\par}%
+ \penalty\predisplaypenalty
+ \beforedisplayspace}
+
+% %D \macros
+% %D {substack}
+% %D
+% %D Preliminary code:
+% %D
+% %D \starttyping
+% %D \startformula
+% %D \sum_{%
+% %D \startsubstack
+% %D i = 1 \NR
+% %D i \neq n \NR
+% %D i \neq m
+% %D \stopsubstack
+% %D }a_i
+% %D \stopformula
+% %D \stoptyping
+
+% \unexpanded\def\startsubstack
+% {\begingroup
+% \null
+% \vcenter\bgroup
+% \pushmacro\domatrixNC
+% \let\stopmathmode\relax
+% \def\NC{\domatrixNC}%
+% \def\MC{\domatrixNC\startmathmode}%
+% \global\let\domatrixNC\dodomatrixNC
+% \def\NR
+% {\stopmathmode
+% \global\let\domatrixNC\dodomatrixNC
+% \crcr\noalign{\nointerlineskip}}%
+% \mathsurround\zeropoint
+% \everycr\emptytoks
+% \halign\bgroup\hfil$\scriptstyle\mathstrut##$\hfil\crcr}
+
+% \unexpanded\def\stopsubstack
+% {\crcr
+% \egroup
+% \popmacro\domatrixNC
+% \egroup
+% \endgroup}
+
+%D \macros
+%D {substack}
+%D
+%D Preliminary code:
+%D
+%D \startbuffer
+%D \startformula
+%D \sum_{%
+%D \startsubstack
+%D i = 1 \NR
+%D i \neq n \NR
+%D i \neq m
+%D \stopsubstack
+%D }a_i
+%D \stopformula
+%D \stopbuffer
+%D
+%D \getbuffer which was typed as \typebuffer
+%D
+%D Notice that these macros give the correct spacing for
+%D subscripts. Compare for example
+%D
+%D \startbuffer
+%D \startformula
+%D \sum_{\startsubstack a \NR b \NR \stopsubstack}
+%D \text{ and }
+%D \sum_{\scriptstyle a \atop \scriptstyle}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer which gives \getbuffer
+
+\unexpanded\def\startsubstack
+ {\begingroup
+ \vcenter\bgroup
+ \baselineskip\mathstacktotal
+ \lineskip\mathstackvgap
+ \lineskiplimit\lineskip
+ \let\stopmathmode\relax
+ \def\NC{\domatrixNC}%
+ \def\MC{\domatrixNC\startmathmode}%
+ \global\let\domatrixNC\dodomatrixNC
+ \def\NR
+ {\stopmathmode
+ \global\let\domatrixNC\dodomatrixNC
+ \crcr}%
+ \mathsurround\zeropoint
+ \everycr\emptytoks
+ \halign\bgroup\hfil$\scriptstyle##$\hfil\crcr}
+
+\unexpanded\def\stopsubstack
+ {\crcr
+ \egroup
+ \egroup
+ \endgroup}
+
+%D \macros
+%D {bordermatrix}
+%D
+%D In \PLAIN\ \TEX\ the width of a parenthesis is stored in
+%D the \DIMENSION\ \type{\mathparentwd}. This value is derived from
+%D the width of \type{\tenrm B}, so let's take care of it now:
+
+\ifx\mathparentwd\undefined \newdimen\mathparentwd \fi
+
+\let\normalbordermatrix\bordermatrix
+
+\def\bordermatrix
+ {\begingroup
+ \setbox\scratchbox\hbox{\mr\char"239C}%
+ \global\mathparentwd\wd\scratchbox\relax
+ \endgroup
+ \normalbordermatrix}
+
+% to be tested
+%
+% \def\bordermatrix
+% {\begingroup\mr\global\mathparentwd\fontcharwd\font"239C\relax\endgroup
+% \normalbordermatrix}
+
+%D \macros{overset, underset}
+%D
+%D The macros \type{\overset} and \type{\underset} are provided by
+%D \AMS\ packages in \LATEX. These macro allows you to place a symbol
+%D above or below another symbol, irrespective of whether the other
+%D symbol is a relation or something else, and without influencing the
+%D spacing. For most cases there is a better way to do such things
+%D (declaring a math command with limop option, or using accents), but
+%D occasionally these macros can be useful, for example:
+%D
+%D \startbuffer
+%D \startformula
+%D \overset{*}{X} \underset{*}{X}
+%D \stopformula
+%D \stopbuffer
+%D \typebuffer \getbuffer
+%D
+%D Use these macros sparingly. Remember, \TEX\ was designed for
+%D mathematics, so there is usually a proper method for typesetting
+%D common math notation.
+
+%D These macros are a clearer version of \type{\binrel@} and
+%D \type{\binrel@@} macros in \AMSTEX\ packages.
+
+\def\preparebinrel#1%
+ {\begingroup
+ \setbox\scratchbox\hbox
+ {\thinmuskip 0mu
+ \medmuskip -1mu
+ \thickmuskip -1mu
+ \setbox\scratchbox\hbox{$#1\mathsurround\zeropoint$}%
+ \kern-\wd\scratchbox
+ ${}#1{}\mathsurround\zeropoint$}%
+ \normalexpanded
+ {\endgroup
+ \let\noexpand\currentbinrel
+ \ifdim\wd\scratchbox<\zeropoint
+ \mathbin
+ \else\ifdim\wd\scratchbox>\zeropoint
+ \mathrel
+ \else
+ \relax
+ \fi\fi}}
+
+\unexpanded\def\overset#1#2%
+ {\preparebinrel{#2}%
+ \currentbinrel{\mathop{\kern\zeropoint#2}\limits^{#1}}}
+
+\unexpanded\def\underset#1#2%
+ {\preparebinrel{#2}%
+ \currentbinrel{\mathop{\kern\zeropoint#2}\limits_{#1}}}
+
+%D The following code comes from \type {math-str.mkiv}.
+
+%D Here we implement a basic math alignment mechanism. Numbers
+%D are also handled. The macros \type {\startinnermath} and
+%D \type {\stopinnermath} can be overloaded in specialized
+%D modules.
+
+\unexpanded\def\startinnermath
+ {\getvalue{\e!start\??fm\formulaparameter\c!align}}
+
+\unexpanded\def\stopinnermath
+ {\getvalue{\e!stop \??fm\formulaparameter\c!align}}
+
+\def\mathinnerstrut
+ {\doif{\formulaparameter\c!strut}\v!yes\strut}
+
+\long\unexpanded\def\defineinnermathhandler#1#2#3%
+ {\setvalue{\e!start\??fm#1}{#2}%
+ \setvalue{\e!stop \??fm#1}{#3}}
+
+\newif\iftracemath
+
+\def\mathhbox
+ {\iftracemath\ruledhbox\else\hbox\fi}
+
+\chardef\mathraggedstatus=0 % normal left center right
+\chardef\mathnumberstatus=0 % nothing normal shift_right
+\let\mathnumbercorrection\!!zeropoint
+
+\unexpanded\def\startmathbox#1%
+ {\hsize\displaywidth
+ \global\chardef\mathnumberstatus\plusone
+ \chardef\mathraggedstatus#1\relax
+ \let\mathnumbercorrection\!!zeropoint
+ \global\let\@eqno \empty \def\eqno {\gdef\@eqno }%
+ \global\let\@leqno\empty \def\leqno{\gdef\@leqno}%
+ % added
+ \let\normalreqno\eqno
+ \let\normalleqno\leqno
+ % added
+ \doplaceformulanumber
+ \setbox\scratchbox\mathhbox to \displaywidth\bgroup
+ \mathinnerstrut
+ $%
+ \displaystyle
+ \ifcase\mathraggedstatus\or\hfill\or\hfill\fi}
+
+\def\llappedmathno
+ {\ifcase\mathraggedstatus\or
+ \@eqno
+ \or
+ \llap{\@eqno}%
+ \or
+ \llap{\@eqno}%
+ \fi}
+
+\def\rlappedmathno
+ {\ifcase\mathraggedstatus\or
+ \rlap{\@leqno}%
+ \or
+ \rlap{\@leqno}%
+ \or
+ \@leqno
+ \fi}
+
+\unexpanded\def\stopmathbox
+ {$%
+ \ifcase\mathraggedstatus\or\or\hfill\or\hfill\fi
+ \egroup
+ \setbox0\hbox{\unhcopy\scratchbox}%
+ \scratchdimen\wd0
+ \ifdim\scratchdimen>\displaywidth
+ \donetrue
+ \else
+ \donefalse
+ \fi
+ \hbox to \displaywidth\bgroup
+ \ifcase\mathnumberstatus
+ \box\scratchbox
+ \or
+ \ifx\@leqno\empty
+ \ifx\@eqno\empty
+ \box\scratchbox
+ \else
+ \ifdone
+ \vbox{\box\scratchbox\hbox to \displaywidth{\hss\llappedmathno}}%
+ \else
+ \hss\box\scratchbox\llappedmathno % hss makes room for number
+ \fi
+ \fi
+ \else
+ \ifdone
+ \vbox{\hbox to \displaywidth{\rlappedmathno\hss}\box\scratchbox}%
+ \else
+ \rlappedmathno\box\scratchbox\hss % hss makes room for number
+ \fi
+ \fi
+ \or
+ \hskip\mathnumbercorrection
+ \box\scratchbox
+ \hss
+ \else
+ \box\scratchbox
+ \fi
+ \egroup}
+
+\defineinnermathhandler\v!left {\startmathbox\plusone }{\stopmathbox}
+\defineinnermathhandler\v!middle {\startmathbox\plustwo }{\stopmathbox}
+\defineinnermathhandler\v!right {\startmathbox\plusthree}{\stopmathbox}
+\defineinnermathhandler\v!flushleft {\startmathbox\plusthree}{\stopmathbox}
+\defineinnermathhandler\v!center {\startmathbox\plustwo }{\stopmathbox}
+\defineinnermathhandler\v!flushright{\startmathbox\plusone }{\stopmathbox}
+
+%D [The examples below are in english and don't process in the
+%D documentation style, which will be english some day.]
+%D
+%D Normally a formula is centered, but in case you want to
+%D align it left or right, you can set up formulas to behave
+%D that way. Normally a formula will adapt is left indentation
+%D to the environment:
+%D
+%D \startbuffer
+%D \fakewords{20}{40}\epar
+%D \startitemize
+%D \item \fakewords{20}{40}\epar
+%D \placeformula \startformula \fakeformula \stopformula
+%D \item \fakewords{20}{40}\epar
+%D \stopitemize
+%D \fakewords{20}{40}\epar
+%D \stopbuffer
+%D
+%D % \getbuffer
+%D
+%D In the next examples we explicitly align formulas to the
+%D left (\type {\raggedleft}), center and right (\type
+%D {\raggedright}):
+%D
+%D \startbuffer
+%D \setupformulas[align=left]
+%D \startformula\fakeformula\stopformula
+%D \setupformulas[align=middle]
+%D \startformula\fakeformula\stopformula
+%D \setupformulas[align=right]
+%D \startformula\fakeformula\stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Or in print:
+%D
+%D % {\getbuffer}
+%D
+%D With formula numbers these formulas look as follows:
+%D
+%D \startbuffer
+%D \setupformulas[align=left]
+%D \placeformula \startformula\fakeformula\stopformula
+%D \setupformulas[align=middle]
+%D \placeformula \startformula\fakeformula\stopformula
+%D \setupformulas[align=right]
+%D \placeformula \startformula\fakeformula\stopformula
+%D \stopbuffer
+%D
+%D % {\getbuffer}
+%D
+%D This was keyed in as:
+%D
+%D \typebuffer
+%D
+%D When tracing is turned on (\type {\tracemathtrue}) you can
+%D visualize the bounding box of the formula,
+%D
+%D % {\tracemathtrue\getbuffer}
+%D
+%D As you can see, the dimensions are the natural ones, but if
+%D needed you can force a normalized line:
+%D
+%D \startbuffer
+%D \setupformulas[strut=yes]
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D This time we get a more spacy result.
+%D
+%D % {\tracemathtrue\getbuffer}
+%D
+%D We will now show a couple of more settings and combinations
+%D of settings. In centered formulas, the number takes no space
+%D
+%D \startbuffer
+%D \setupformulas[align=middle]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer % {\tracemathtrue\getbuffer}
+%D
+%D You can influence the placement of the whole box with the
+%D parameters \type {leftmargin} and \type {rightmargin}.
+%D
+%D \startbuffer
+%D \setupformulas[align=right,leftmargin=3em]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D
+%D \setupformulas[align=left,rightmargin=1em]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer % {\tracemathtrue\getbuffer}
+%D
+%D You can also inherit the margin from the environment.
+%D
+%D \startbuffer
+%D \setupformulas[align=right,margin=standard]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer % {\tracemathtrue\getbuffer}
+%D
+%D The distance between the formula and the number is only
+%D applied when the formula is left or right aligned.
+%D
+%D \startbuffer
+%D \setupformulas[align=left,distance=2em]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer % {\tracemathtrue\getbuffer}
+
+\protect \endinput
+
+% \placeformula \startformula[-] \startmatrix
+% \NC 1 \NC x \NC a \NR
+% \NC 2 \NC y \NC b \NR
+% \NC 3 \NC z \NC c \NR
+% \stopmatrix \stopformula
+
+% \definemathmatrix[bordermatrix][left={\left[\,},right={\,\right]}]
+
+% \placeformula \startformula[-] \startbordermatrix
+% \NC 1 \NC x \NC a \NR
+% \NC 2 \NC y \NC b \NR
+% \NC 3 \NC z \NC c \NR
+% \stopbordermatrix \stopformula
diff --git a/tex/context/base/math-ams.mkii b/tex/context/base/math-ams.mkii
new file mode 100644
index 000000000..83070d01a
--- /dev/null
+++ b/tex/context/base/math-ams.mkii
@@ -0,0 +1,336 @@
+%D \module
+%D [ file=math-ams,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=AMS Specials,
+%D author={Hans Hagen \& Taco Hoekwater},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+% maybe we should just include these into the default tex one
+
+\definefamilysynonym [default] [blackboard] [mb]
+
+\startmathcollection [default]
+
+\definemathsymbol [varGamma] [ord] [letters] ["00]
+\definemathsymbol [varDelta] [ord] [letters] ["01]
+\definemathsymbol [varTheta] [ord] [letters] ["02]
+\definemathsymbol [varLambda] [ord] [letters] ["03]
+\definemathsymbol [varXi] [ord] [letters] ["04]
+\definemathsymbol [varPi] [ord] [letters] ["05]
+\definemathsymbol [varSigma] [ord] [letters] ["06]
+\definemathsymbol [varUpsilon] [ord] [letters] ["07]
+\definemathsymbol [varPhi] [ord] [letters] ["08]
+\definemathsymbol [varPsi] [ord] [letters] ["09]
+\definemathsymbol [varOmega] [ord] [letters] ["0A]
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathsymbol [internalAnd] [rel] [operators] ["26]
+
+\stopmathcollection
+
+\startmathcollection [default]
+
+\definemathsymbol [boxdot] [bin] [ma] ["00]
+\definemathsymbol [boxplus] [bin] [ma] ["01]
+\definemathsymbol [boxtimes] [bin] [ma] ["02]
+\definemathsymbol [square] [ord] [ma] ["03]
+\definemathsymbol [Box] [ord] [ma] ["03] % square
+\definemathsymbol [blacksquare] [ord] [ma] ["04]
+\definemathsymbol [centerdot] [bin] [ma] ["05]
+\definemathsymbol [Diamond] [ord] [ma] ["06]
+\definemathsymbol [lozenge] [ord] [ma] ["06] % Diamond
+\definemathsymbol [blacklozenge] [ord] [ma] ["07]
+\definemathsymbol [circlearrowright] [rel] [ma] ["08]
+\definemathsymbol [circlearrowleft] [rel] [ma] ["09]
+\definemathsymbol [rightleftharpoons] [rel] [ma] ["0A]
+\definemathsymbol [leftrightharpoons] [rel] [ma] ["0B]
+\definemathsymbol [boxminus] [bin] [ma] ["0C]
+\definemathsymbol [Vdash] [rel] [ma] ["0D]
+\definemathsymbol [Vvdash] [rel] [ma] ["0E]
+\definemathsymbol [vDash] [rel] [ma] ["0F]
+\definemathsymbol [twoheadrightarrow] [rel] [ma] ["10]
+\definemathsymbol [twoheadleftarrow] [rel] [ma] ["11]
+\definemathsymbol [leftleftarrows] [rel] [ma] ["12]
+\definemathsymbol [rightrightarrows] [rel] [ma] ["13]
+\definemathsymbol [upuparrows] [rel] [ma] ["14]
+\definemathsymbol [downdownarrows] [rel] [ma] ["15]
+\definemathsymbol [upharpoonright] [rel] [ma] ["16]
+\definemathsymbol [restriction] [rel] [ma] ["16]
+\definemathsymbol [downharpoonright] [rel] [ma] ["17]
+\definemathsymbol [upharpoonleft] [rel] [ma] ["18]
+\definemathsymbol [downharpoonleft] [rel] [ma] ["19]
+\definemathsymbol [rightarrowtail] [rel] [ma] ["1A]
+\definemathsymbol [leftarrowtail] [rel] [ma] ["1B]
+\definemathsymbol [leftrightarrows] [rel] [ma] ["1C]
+\definemathsymbol [rightleftarrows] [rel] [ma] ["1D]
+\definemathsymbol [Lsh] [rel] [ma] ["1E]
+\definemathsymbol [Rsh] [rel] [ma] ["1F]
+\definemathsymbol [rightsquigarrow] [rel] [ma] ["20]
+\definemathsymbol [leadsto] [rel] [ma] ["20] % rightsquigarrow
+\definemathsymbol [leftrightsquigarrow] [rel] [ma] ["21]
+\definemathsymbol [looparrowleft] [rel] [ma] ["22]
+\definemathsymbol [looparrowright] [rel] [ma] ["23]
+\definemathsymbol [circeq] [rel] [ma] ["24]
+\definemathsymbol [succsim] [rel] [ma] ["25]
+\definemathsymbol [gtrsim] [rel] [ma] ["26]
+\definemathsymbol [gtrapprox] [rel] [ma] ["27]
+\definemathsymbol [multimap] [rel] [ma] ["28]
+\definemathsymbol [therefore] [rel] [ma] ["29]
+\definemathsymbol [because] [rel] [ma] ["2A]
+\definemathsymbol [doteqdot] [rel] [ma] ["2B]
+\definemathsymbol [Doteq] [rel] [ma] ["2B] % doteqdot
+\definemathsymbol [triangleq] [rel] [ma] ["2C]
+\definemathsymbol [precsim] [rel] [ma] ["2D]
+\definemathsymbol [lesssim] [rel] [ma] ["2E]
+\definemathsymbol [lessapprox] [rel] [ma] ["2F]
+\definemathsymbol [eqslantless] [rel] [ma] ["30]
+\definemathsymbol [eqslantgtr] [rel] [ma] ["31]
+\definemathsymbol [curlyeqprec] [rel] [ma] ["32]
+\definemathsymbol [curlyeqsucc] [rel] [ma] ["33]
+\definemathsymbol [preccurlyeq] [rel] [ma] ["34]
+\definemathsymbol [leqq] [rel] [ma] ["35]
+\definemathsymbol [leqslant] [rel] [ma] ["36]
+\definemathsymbol [lessgtr] [rel] [ma] ["37]
+\definemathsymbol [backprime] [ord] [ma] ["38]
+\definemathsymbol [dabar@] [ord] [ma] ["39] % @
+\definemathsymbol [risingdotseq] [rel] [ma] ["3A]
+\definemathsymbol [fallingdotseq] [rel] [ma] ["3B]
+\definemathsymbol [succcurlyeq] [rel] [ma] ["3C]
+\definemathsymbol [geqq] [rel] [ma] ["3D]
+\definemathsymbol [geqslant] [rel] [ma] ["3E]
+\definemathsymbol [gtrless] [rel] [ma] ["3F]
+\definemathsymbol [sqsubset] [rel] [ma] ["40]
+\definemathsymbol [sqsupset] [rel] [ma] ["41]
+\definemathsymbol [vartriangleright] [rel] [ma] ["42]
+\definemathsymbol [rhd] [bin] [ma] ["42]
+\definemathsymbol [lhd] [bin] [ma] ["43]
+\definemathsymbol [vartriangleleft] [rel] [ma] ["43]
+\definemathsymbol [trianglerighteq] [rel] [ma] ["44]
+\definemathsymbol [unrhd] [bin] [ma] ["44] % trianglerighteq
+\definemathsymbol [trianglelefteq] [rel] [ma] ["45]
+\definemathsymbol [unlhd] [bin] [ma] ["45] % trianglelefteq
+\definemathsymbol [bigstar] [ord] [ma] ["46]
+\definemathsymbol [between] [rel] [ma] ["47]
+\definemathsymbol [blacktriangledown] [ord] [ma] ["48]
+\definemathsymbol [blacktriangleright] [rel] [ma] ["49]
+\definemathsymbol [blacktriangleleft] [rel] [ma] ["4A]
+\definemathsymbol [vartriangle] [rel] [ma] ["4D]
+\definemathsymbol [triangleup] [ord] [ma] ["4D] % vartriangle
+\definemathsymbol [blacktriangle] [ord] [ma] ["4E]
+\definemathsymbol [triangledown] [ord] [ma] ["4F]
+\definemathsymbol [eqcirc] [rel] [ma] ["50]
+\definemathsymbol [lesseqgtr] [rel] [ma] ["51]
+\definemathsymbol [gtreqless] [rel] [ma] ["52]
+\definemathsymbol [lesseqqgtr] [rel] [ma] ["53]
+\definemathsymbol [gtreqqless] [rel] [ma] ["54]
+\definemathsymbol [Rrightarrow] [rel] [ma] ["56]
+\definemathsymbol [Lleftarrow] [rel] [ma] ["57]
+\definemathsymbol [veebar] [bin] [ma] ["59]
+\definemathsymbol [barwedge] [bin] [ma] ["5A]
+\definemathsymbol [doublebarwedge] [bin] [ma] ["5B]
+\definemathsymbol [angle] [ord] [ma] ["5C]
+\definemathsymbol [measuredangle] [ord] [ma] ["5D]
+\definemathsymbol [sphericalangle] [ord] [ma] ["5E]
+\definemathsymbol [varpropto] [rel] [ma] ["5F]
+\definemathsymbol [smallsmile] [rel] [ma] ["60]
+\definemathsymbol [smallfrown] [rel] [ma] ["61]
+\definemathsymbol [Subset] [rel] [ma] ["62]
+\definemathsymbol [Supset] [rel] [ma] ["63]
+\definemathsymbol [Cup] [bin] [ma] ["64]
+\definemathsymbol [doublecup] [bin] [ma] ["64] % Cup
+\definemathsymbol [Cap] [bin] [ma] ["65]
+\definemathsymbol [doublecap] [bin] [ma] ["65]
+\definemathsymbol [curlywedge] [bin] [ma] ["66]
+\definemathsymbol [curlyvee] [bin] [ma] ["67]
+\definemathsymbol [leftthreetimes] [bin] [ma] ["68]
+\definemathsymbol [rightthreetimes] [bin] [ma] ["69]
+\definemathsymbol [subseteqq] [rel] [ma] ["6A]
+\definemathsymbol [supseteqq] [rel] [ma] ["6B]
+\definemathsymbol [bumpeq] [rel] [ma] ["6C]
+\definemathsymbol [Bumpeq] [rel] [ma] ["6D]
+\definemathsymbol [llless] [rel] [ma] ["6E]
+\definemathsymbol [lll] [rel] [ma] ["6E] % llless
+\definemathsymbol [gggtr] [rel] [ma] ["6F]
+\definemathsymbol [ggg] [rel] [ma] ["6F] % gggtr
+\definemathsymbol [ulcorner] [open] [ma] ["70] [ma] ["70]
+\definemathsymbol [urcorner] [close] [ma] ["71] [ma] ["71]
+\definemathsymbol [circledS] [ord] [ma] ["73]
+\definemathsymbol [pitchfork] [rel] [ma] ["74]
+\definemathsymbol [dotplus] [bin] [ma] ["75]
+\definemathsymbol [backsim] [rel] [ma] ["76]
+\definemathsymbol [backsimeq] [rel] [ma] ["77]
+\definemathsymbol [llcorner] [open] [ma] ["78] [ma] ["78]
+\definemathsymbol [lrcorner] [close] [ma] ["79] [ma] ["79]
+\definemathsymbol [complement] [ord] [ma] ["7B]
+\definemathsymbol [intercal] [bin] [ma] ["7C]
+\definemathsymbol [circledcirc] [bin] [ma] ["7D]
+\definemathsymbol [circledast] [bin] [ma] ["7E]
+\definemathsymbol [circleddash] [bin] [ma] ["7F]
+
+\stopmathcollection
+
+\startmathcollection [default]
+
+\definemathcommand [integers] {\blackboard{Z}}
+\definemathcommand [reals] {\blackboard{R}}
+\definemathcommand [rationals] {\blackboard{Q}}
+\definemathcommand [naturalnumbers] {\blackboard{N}}
+\definemathcommand [complexes] {\blackboard{C}}
+\definemathcommand [primes] {\blackboard{P}}
+
+\stopmathcollection
+
+\startmathcollection [default]
+
+\definemathsymbol [lvertneqq] [rel] [mb] ["00]
+\definemathsymbol [gvertneqq] [rel] [mb] ["01]
+\definemathsymbol [nleq] [rel] [mb] ["02]
+\definemathsymbol [ngeq] [rel] [mb] ["03]
+\definemathsymbol [nless] [rel] [mb] ["04]
+\definemathsymbol [ngtr] [rel] [mb] ["05]
+\definemathsymbol [nprec] [rel] [mb] ["06]
+\definemathsymbol [nsucc] [rel] [mb] ["07]
+\definemathsymbol [lneqq] [rel] [mb] ["08]
+\definemathsymbol [gneqq] [rel] [mb] ["09]
+\definemathsymbol [nleqslant] [rel] [mb] ["0A]
+\definemathsymbol [ngeqslant] [rel] [mb] ["0B]
+\definemathsymbol [lneq] [rel] [mb] ["0C]
+\definemathsymbol [gneq] [rel] [mb] ["0D]
+\definemathsymbol [npreceq] [rel] [mb] ["0E]
+\definemathsymbol [nsucceq] [rel] [mb] ["0F]
+\definemathsymbol [precnsim] [rel] [mb] ["10]
+\definemathsymbol [succnsim] [rel] [mb] ["11]
+\definemathsymbol [lnsim] [rel] [mb] ["12]
+\definemathsymbol [gnsim] [rel] [mb] ["13]
+\definemathsymbol [nleqq] [rel] [mb] ["14]
+\definemathsymbol [ngeqq] [rel] [mb] ["15]
+\definemathsymbol [precneqq] [rel] [mb] ["16]
+\definemathsymbol [succneqq] [rel] [mb] ["17]
+\definemathsymbol [precnapprox] [rel] [mb] ["18]
+\definemathsymbol [succnapprox] [rel] [mb] ["19]
+\definemathsymbol [lnapprox] [rel] [mb] ["1A]
+\definemathsymbol [gnapprox] [rel] [mb] ["1B]
+\definemathsymbol [nsim] [rel] [mb] ["1C]
+\definemathsymbol [ncong] [rel] [mb] ["1D]
+\definemathsymbol [diagup] [ord] [mb] ["1E]
+\definemathsymbol [diagdown] [ord] [mb] ["1F]
+\definemathsymbol [varsubsetneq] [rel] [mb] ["20]
+\definemathsymbol [varsupsetneq] [rel] [mb] ["21]
+\definemathsymbol [nsubseteqq] [rel] [mb] ["22]
+\definemathsymbol [nsupseteqq] [rel] [mb] ["23]
+\definemathsymbol [subsetneqq] [rel] [mb] ["24]
+\definemathsymbol [supsetneqq] [rel] [mb] ["25]
+\definemathsymbol [varsubsetneqq] [rel] [mb] ["26]
+\definemathsymbol [varsupsetneqq] [rel] [mb] ["27]
+\definemathsymbol [subsetneq] [rel] [mb] ["28]
+\definemathsymbol [supsetneq] [rel] [mb] ["29]
+\definemathsymbol [nsubseteq] [rel] [mb] ["2A]
+\definemathsymbol [nsupseteq] [rel] [mb] ["2B]
+\definemathsymbol [nparallel] [rel] [mb] ["2C]
+\definemathsymbol [nmid] [rel] [mb] ["2D]
+\definemathsymbol [nshortmid] [rel] [mb] ["2E]
+\definemathsymbol [nshortparallel] [rel] [mb] ["2F]
+\definemathsymbol [nvdash] [rel] [mb] ["30]
+\definemathsymbol [nVdash] [rel] [mb] ["31]
+\definemathsymbol [nvDash] [rel] [mb] ["32]
+\definemathsymbol [nVDash] [rel] [mb] ["33]
+\definemathsymbol [ntrianglerighteq] [rel] [mb] ["34]
+\definemathsymbol [ntrianglelefteq] [rel] [mb] ["35]
+\definemathsymbol [ntriangleleft] [rel] [mb] ["36]
+\definemathsymbol [ntriangleright] [rel] [mb] ["37]
+\definemathsymbol [nleftarrow] [rel] [mb] ["38]
+\definemathsymbol [nrightarrow] [rel] [mb] ["39]
+\definemathsymbol [nLeftarrow] [rel] [mb] ["3A]
+\definemathsymbol [nRightarrow] [rel] [mb] ["3B]
+\definemathsymbol [nLeftrightarrow] [rel] [mb] ["3C]
+\definemathsymbol [nleftrightarrow] [rel] [mb] ["3D]
+\definemathsymbol [divideontimes] [bin] [mb] ["3E]
+\definemathsymbol [varnothing] [ord] [mb] ["3F]
+\definemathsymbol [nexists] [ord] [mb] ["40]
+\definemathsymbol [Finv] [ord] [mb] ["60]
+\definemathsymbol [Game] [ord] [mb] ["61]
+\definemathsymbol [mho] [ord] [mb] ["66]
+\definemathsymbol [eth] [ord] [mb] ["67]
+\definemathsymbol [eqsim] [rel] [mb] ["68]
+\definemathsymbol [beth] [ord] [mb] ["69]
+\definemathsymbol [gimel] [ord] [mb] ["6A]
+\definemathsymbol [daleth] [ord] [mb] ["6B]
+\definemathsymbol [lessdot] [bin] [mb] ["6C]
+\definemathsymbol [gtrdot] [bin] [mb] ["6D]
+\definemathsymbol [ltimes] [bin] [mb] ["6E]
+\definemathsymbol [rtimes] [bin] [mb] ["6F]
+\definemathsymbol [shortmid] [rel] [mb] ["70]
+\definemathsymbol [shortparallel] [rel] [mb] ["71]
+\definemathsymbol [smallsetminus] [bin] [mb] ["72]
+\definemathsymbol [thicksim] [rel] [mb] ["73]
+\definemathsymbol [thickapprox] [rel] [mb] ["74]
+\definemathsymbol [approxeq] [rel] [mb] ["75]
+\definemathsymbol [succapprox] [rel] [mb] ["76]
+\definemathsymbol [precapprox] [rel] [mb] ["77]
+\definemathsymbol [curvearrowleft] [rel] [mb] ["78]
+\definemathsymbol [curvearrowright] [rel] [mb] ["79]
+\definemathsymbol [digamma] [ord] [mb] ["7A]
+\definemathsymbol [varkappa] [ord] [mb] ["7B]
+\definemathsymbol [Bbbk] [ord] [mb] ["7C]
+\definemathsymbol [hslash] [ord] [mb] ["7D]
+\definemathsymbol [hbar] [ord] [mb] ["7E]
+\definemathsymbol [backepsilon] [rel] [mb] ["7F]
+
+\stopmathcollection
+
+\startmathcollection [default]
+
+\definemathcommand [yen] [nothing] {\mathhexbox{\hexmafam}55}
+\definemathcommand [checkmark] [nothing] {\mathhexbox{\hexmafam}58}
+\definemathcommand [circledR] [nothing] {\mathhexbox{\hexmafam}72}
+\definemathcommand [maltese] [nothing] {\mathhexbox{\hexmafam}7A}
+
+\stopmathcollection
+
+\startmathcollection [default]
+
+\definemathcommand [dashrightarrow] [rel] {\dabar@\dabar@ \mathchar"0C4B}
+\definemathcommand [dashleftarrow] [rel] {\mathchar"0C4C\dabar@ \dabar@}
+\definemathcommand [dasharrow] [rel] {\dabar@\dabar@ \mathchar"0C4B}
+\definemathcommand [Join] [rel] {\mathchar"0D6F\mkern-13.8mu\mathchar"0D6E}
+\definemathcommand [implies] [rel] {\;\Longrightarrow\;}
+\definemathcommand [impliedby] [rel] {\;\Longleftarrow\;}
+\definemathcommand [And] [rel] {\;\internalAnd\;}
+
+\stopmathcollection
+
+\def\AMSwidehat#1%
+ {\setbox\scratchbox\hbox{$\mathsurround\zeropoint#1$}%
+ \ifdim\wd\scratchbox>2em
+ \mathaccent"0\purefamilyhex{mb}5B{#1}%
+ \else
+ \mathaccent"0\purefamilyhex{ex}62{#1}%
+ \fi}
+
+\def\AMSwidetilde#1%
+ {\setbox\scratchbox\hbox{$\mathsurround\zeropoint#1$}%
+ \ifdim\wd\scratchbox>2em
+ \mathaccent"0\purefamilyhex{mb}5D{#1}%
+ \else
+ \mathaccent"0\purefamilyhex{ex}65{#1}%
+ \fi}
+
+\startmathcollection [default]
+
+\definemathcommand [widehat] {\AMSwidehat}
+\definemathcommand [widetilde] {\AMSwidetilde}
+
+\stopmathcollection
+
+\protect \endinput
diff --git a/tex/context/base/math-arr.mkii b/tex/context/base/math-arr.mkii
new file mode 100644
index 000000000..3b9abaa91
--- /dev/null
+++ b/tex/context/base/math-arr.mkii
@@ -0,0 +1,391 @@
+%D \module
+%D [ file=math-ext,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Arrows,
+%D author={Hans Hagen \& Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Math Macros / Arrows}
+
+\unprotect
+
+%D These will be generalized! Is it still needed in \MKIV?
+
+%D We next define extensible arrows. Extensible arrows are arrows that
+%D change their length according to the width of the text to be placed
+%D above and below the arrow. Since we need to define a lot of arrows,
+%D we first define some helper macros. The basic idea is to measure
+%D the width of the box to be placed above and below the arrow, and
+%D make the \quotation{body} of the arrow as long as the bigger of the
+%D two widths.
+
+\def\mtharrfactor{1}
+\def\mtharrextra {0}
+
+\def\domthxarr#1#2#3#4#5% hm, looks like we do a double mathrel
+ {\begingroup
+ \def\mtharrfactor{1}%
+ \def\mtharrextra {0}%
+ \processaction[#1] % will be sped up
+ [ \v!none=>\def\mtharrfactor{0},
+ \v!small=>\def\mtharrextra{10},
+ \v!medium=>\def\mtharrextra{15},
+ \v!big=>\def\mtharrextra{20},
+ \v!normal=>,
+ \v!default=>,
+ \v!unknown=>\doifnumberelse{#1}{\def\mtharrextra{#1}}\donothing]%
+ \mathsurround\zeropoint
+ \muskip0=\thirdoffourarguments #2mu
+ \muskip2=\fourthoffourarguments #2mu
+ \muskip4=\firstoffourarguments #2mu
+ \muskip6=\secondoffourarguments #2mu
+ \muskip0=\mtharrfactor\muskip0 \advance\muskip0 \mtharrextra mu
+ \muskip2=\mtharrfactor\muskip2 \advance\muskip2 \mtharrextra mu
+ \setbox0\hbox{$\scriptstyle
+ \mkern\muskip4\relax
+ \mkern\muskip0\relax
+ #5\relax
+ \mkern\muskip2\relax
+ \mkern\muskip6\relax
+ $}%
+ \setbox4\hbox{#3\displaystyle}%
+ \dimen0\wd0
+ \ifdim\wd4>\dimen0 \dimen0\wd4 \fi
+ \setbox2\hbox{$\scriptstyle
+ \mkern\muskip4\relax
+ \mkern\muskip0\relax
+ #4\relax
+ \mkern\muskip2\relax
+ \mkern\muskip6\relax
+ $}%
+ \ifdim\wd2>\dimen0 \dimen0\wd2 \fi
+ \setbox4\hbox to \dimen0{#3\displaystyle}%
+ \mathrel{\mathop{\hbox to \dimen0{\hss\copy4\hss}}\limits^{\box0}_{\box2}}
+ \endgroup}
+
+\let\domthxarrsingle\domthxarr
+
+%D There are some arrows which are created by stacking two arrows. The next
+%D macro helps in defining such \quotation{double arrows}.
+
+\def\domthxarrdouble#1#2#3#4#5#6#7% opt l r sp rs top bot
+ {\mathrel
+ {\scratchdimen.32ex\relax % was .22, todo: make configurable
+ \setbox0\hbox{$\domthxarr{#1}{#2}{#4}{\phantom{#6}}{#7}$}%
+ \setbox2\hbox{$\domthxarr{#1}{#3}{#5}{#6}{\phantom{#7}}$}%
+ \raise\scratchdimen\box0
+ \kern-\wd2
+ \lower\scratchdimen\box2}}
+
+%D \macros{definematharrow}
+%D
+%D Macro for defining new arrows. We can define two types of
+%D arrows|<|single arrows and double arrows. Single arrows are defined
+%D as
+%D
+%D \starttyping
+%D \definematharrow [xrightarrow] [0359] [\rightarrowfill]
+%D \stoptyping
+%D
+%D The first argument is the name of the arrow (\tex{xrightarrow} in
+%D this case.) The second argument consists of a set of 4 numbers and
+%D specify the spacing correction in math units~\type{mu}. These
+%D numbers define:
+%D
+%D \startlines
+%D 1st number: arrow||tip correction
+%D 2nd number: arrow||tip correction
+%D 3rd number: space (multiplied by \tex{matharrfactor} and advanced by \tex{matharrextra})
+%D 4th number: space (multiplied by \tex{matharrfactor} and advanced by \tex{matharrextra})
+%D \stoplines
+%D
+%D The third argument is the name of the extensible fill. The third
+%D argument is optional when the arrow is redefined later (this is
+%D useful for font specific tweaking of the skips.) For example,
+%D
+%D \startbuffer
+%D \math{\xrightarrow{above}}
+%D \definematharrow[xrightarrow][0000]
+%D \math{\xrightarrow{above}}
+%D \definematharrow[xrightarrow][55{50}{50}]
+%D \math{\xrightarrow{above}}
+%D \stopbuffer
+%D \typebuffer gives {\getbuffer}
+%D
+%D The double arrows are defined as follows
+%D
+%D \starttyping
+%D \definematharrow [xrightleftharpoons] [3095,0359]
+%D [\rightharpoonupfill,\leftharpoondownfill]
+%D \stoptyping
+%D
+%D The second and the third set of arguments consist of comma
+%D separated values. The first element of the second argument
+%D (\type{3095}) corresponds to the spacing correction of top arrow
+%D fill (\tex{rightarrowupfill}). Similarly, \type{0359} corresponds
+%D to bottom arrow fill \tex{leftharpoondownfill}). Stacking them on
+%D top of each other we get $\xrightleftharpoons[big]{above}{below}$.
+%D The following math arrows are defined
+%D
+%D \placetable[none]{}{\starttable[|l|m|]
+%D \NC \tex{xrightarrow } \NC \xrightarrow [big] \NC \NR
+%D \NC \tex{xleftarrow } \NC \xleftarrow [big] \NC \NR
+%D \NC \tex{xequal } \NC \xequal [big] \NC \NR
+%D \NC \tex{xRightarrow } \NC \xRightarrow [big] \NC \NR
+%D \NC \tex{xLeftarrow } \NC \xLeftarrow [big] \NC \NR
+%D \NC \tex{xLeftrightarrow } \NC \xLeftrightarrow [big] \NC \NR
+%D \NC \tex{xleftrightarrow } \NC \xleftrightarrow [big] \NC \NR
+%D \NC \tex{xmapsto } \NC \xmapsto [big] \NC \NR
+%D \NC \tex{xtwoheadrightarrow } \NC \xtwoheadrightarrow [big] \NC \NR
+%D \NC \tex{xtwoheadleftarrow } \NC \xtwoheadleftarrow [big] \NC \NR
+%D \NC \tex{xrightharpoondown } \NC \xrightharpoondown [big] \NC \NR
+%D \NC \tex{xrightharpoonup } \NC \xrightharpoonup [big] \NC \NR
+%D \NC \tex{xleftharpoondown } \NC \xleftharpoondown [big] \NC \NR
+%D \NC \tex{xleftharpoonup } \NC \xleftharpoonup [big] \NC \NR
+%D \NC \tex{xhookleftarrow } \NC \xhookleftarrow [big] \NC \NR
+%D \NC \tex{xhookrightarrow } \NC \xhookrightarrow [big] \NC \NR
+%D \NC \tex{xleftrightharpoons } \NC \xleftrightharpoons [big] \NC \NR
+%D \NC \tex{xrightleftharpoons } \NC \xrightleftharpoons [big] \NC \NR
+%D \stoptable}
+
+\def\definematharrow
+ {\doquadrupleargument\dodefinematharrow}
+
+\def\dodefinematharrow[#1][#2][#3][#4]% name type[none|both] template command
+ {\iffourthargument
+ \executeifdefined{dodefine#2arrow}\gobblethreearguments{#1}{#3}{#4}%
+ \else\ifthirdargument
+ \dodefinebotharrow{#1}{#2}{#3}%
+ \else\ifsecondargument
+ \redefinebotharrow{#1}{#2}{#3}%
+ \fi\fi\fi}
+
+\def\redefinebotharrow#1#2#3% real dirty, this overload!
+ {\doifdefined{#1}
+ {\pushmacro\dohandlemtharrow
+ \def\dohandlemtharrow[##1][##2]{\setvalue{#1}{\dohandlemtharrow[#2][##2]}}%
+ % == \def\dohandlemtharrow[##1][##2]{\dodefinebotharrow{#1}{#2}{##2}}%
+ \getvalue{#1}%
+ \popmacro\dohandlemtharrow}}
+
+\def\dodefinebotharrow#1#2#3%
+ {\setvalue{#1}{\dohandlemtharrow[#2][#3]}}
+
+\def\dohandlemtharrow
+ {\dotripleempty\doxmtharrow}
+
+\def\doxmtharrow[#1][#2][#3]% #3 == optional arg
+ {\def\dodoxmtharrow{\dododoxmtharrow[#1,\empty,\empty][#2,\empty,\empty][#3]}% {##1}{##2}
+ \dodoublegroupempty\dodoxmtharrow}
+
+\def\dododoxmtharrow[#1,#2,#3][#4,#5,#6][#7]#8#9% [3] is the optional arg
+ {\edef\!!stringa{#2}%
+ \ifx\!!stringa\empty
+ \ifsecondargument
+ \mathrel{\domthxarrsingle{#7}{#1}{#4}{#8}{#9}}%
+ \else
+ \mathrel{\domthxarrsingle{#7}{#1}{#4}{}{#8}}%
+ \fi
+ \else
+ \ifsecondargument
+ \mathrel{\domthxarrdouble{#7}{#1}{#2}{#4}{#5}{#8}{#9}}%
+ \else
+ \mathrel{\domthxarrdouble{#7}{#1}{#2}{#4}{#5}{}{#8}}%
+ \fi
+ \fi}
+
+% Adapted from amsmath.
+
+%D \macros{mtharrowfill,defaultmtharrowfill}
+%D
+%D To extend the arrows we need to define a \quotation{math arrow
+%D fill}. This command takes 8 arguments: the first four correspond
+%D the second argument of \tex{definematharrow} explained above. The
+%D other three specify the tail, body and head of the arrow. The last
+%D argument specifies the math-mode in which the arrow is drawn.
+%D \tex{defaultmtharrowfill} has values tweaked to match Latin Modern
+%D fonts. For fonts that are significantly different (e.g. cows) a
+%D different set of values need to be determined.
+
+\def\mtharrowfill#1#2#3#4#5#6#7#8%
+ {$\mathsurround 0pt
+ \thickmuskip0mu\medmuskip\thickmuskip\thinmuskip\thickmuskip
+ \relax#8#5%
+ \mkern-#1mu
+ \cleaders\hbox{$#8\mkern -#2mu#6\mkern -#3mu$}\hfill
+ \mkern-#4mu#7$}
+
+\def\defaultmtharrowfill{\mtharrowfill 7227}
+
+%D We now define some arrow fills that will be used for defining the
+%D arrows. Plain \TEX\ already defines \tex{leftarrowfill} and
+%D \tex{rightarrowfill}. The \tex{defaultmtharrowfill} command defines an
+%D arrowfill that takes an argument (so that it can also be used
+%D with over and under arrows). However the Plain \TEX\ definitions of
+%D \tex{leftarrowfill} and \tex{rightarrowfill} do not take this extra
+%D argument. To be backward compatible with Plain \TEX, we define two
+%D arrowfills: \tex{specrightarrowfill} which takes an extra argument, and
+%D \tex{rightarrowfill} which does not.
+
+\def\specrightarrowfill {\defaultmtharrowfill \relbar \relbar \rightarrow}
+\def\specleftarrowfill {\defaultmtharrowfill \leftarrow \relbar \relbar}
+
+\def\rightarrowfill {\specrightarrowfill \textstyle}
+\def\leftarrowfill {\specleftarrowfill \textstyle}
+
+\def\equalfill {\defaultmtharrowfill \Relbar \Relbar \Relbar}
+\def\Rightarrowfill {\defaultmtharrowfill \Relbar \Relbar \Rightarrow}
+\def\Leftarrowfill {\defaultmtharrowfill \Leftarrow \Relbar \Relbar}
+\def\Leftrightarrowfill {\defaultmtharrowfill \Leftarrow \Relbar \Rightarrow}
+\def\leftrightarrowfill {\defaultmtharrowfill \leftarrow \relbar \rightarrow}
+\def\mapstofill {\defaultmtharrowfill{\mapstochar\relbar} \relbar \rightarrow}
+\def\twoheadrightarrowfill{\defaultmtharrowfill \relbar \relbar \twoheadrightarrow}
+\def\twoheadleftarrowfill {\defaultmtharrowfill \twoheadleftarrow \relbar \relbar}
+\def\rightharpoondownfill {\defaultmtharrowfill \relbar \relbar \rightharpoondown}
+\def\rightharpoonupfill {\defaultmtharrowfill \relbar \relbar \rightharpoonup}
+\def\leftharpoondownfill {\defaultmtharrowfill \leftharpoondown \relbar \relbar}
+\def\leftharpoonupfill {\defaultmtharrowfill \leftharpoonup \relbar \relbar}
+\def\hookleftfill {\defaultmtharrowfill \leftarrow \relbar{\relbar\joinrel\rhook}}
+\def\hookrightfill {\defaultmtharrowfill{\lhook\joinrel\relbar}\relbar \rightarrow}
+\def\relfill {\defaultmtharrowfill \relbar \relbar \relbar}
+
+\def\triplerelbar {\mathrel\equiv}
+\def\triplerelfill{\defaultmtharrowfill\triplerelbar\triplerelbar\triplerelbar}
+
+\def\singlebond{{\xrel}} % or \def\singlebond{{\xrel[2]}}
+\def\doublebond{{\xequal}}
+\def\triplebond{{\xtriplerel}}
+
+%D Now we define most commonly used arrows. These include arrows
+%D defined in \filename{amsmath.sty}, \filename{extarrows.sty},
+%D \filename{extpfel.sty} and \filename{mathtools.sty} packages for
+%D \LATEX\ (plus a few more).
+
+\definematharrow [xrightarrow] [0359] [\specrightarrowfill]
+\definematharrow [xleftarrow] [3095] [\specleftarrowfill]
+\definematharrow [xequal] [0099] [\equalfill]
+\definematharrow [xRightarrow] [0359] [\Rightarrowfill]
+\definematharrow [xLeftarrow] [3095] [\Leftarrowfill]
+\definematharrow [xLeftrightarrow] [0099] [\Leftrightarrowfill]
+\definematharrow [xleftrightarrow] [0099] [\leftrightarrowfill]
+\definematharrow [xmapsto] [3599] [\mapstofill]
+\definematharrow [xtwoheadrightarrow] [5009] [\twoheadrightarrowfill]
+\definematharrow [xtwoheadleftarrow] [0590] [\twoheadleftarrowfill]
+\definematharrow [xrightharpoondown] [0359] [\rightharpoondownfill]
+\definematharrow [xrightharpoonup] [0359] [\rightharpoonupfill]
+\definematharrow [xleftharpoondown] [3095] [\leftharpoondownfill]
+\definematharrow [xleftharpoonup] [3095] [\leftharpoonupfill]
+\definematharrow [xhookleftarrow] [3095] [\hookleftfill]
+\definematharrow [xhookrightarrow] [0395] [\hookrightfill]
+\definematharrow [xrel] [0099] [\relfill]
+\definematharrow [xtriplerel] [0099] [\triplerelfill]
+\definematharrow [xrightoverleftarrow] [0359,3095] [\specrightarrowfill,\specleftarrowfill]
+\definematharrow [xleftrightharpoons] [3399,3399] [\leftharpoonupfill,\rightharpoondownfill]
+\definematharrow [xrightleftharpoons] [3399,3399] [\rightharpoonupfill,\leftharpoondownfill]
+
+%D These arrows can be used as follows:
+%D
+%D \startbuffer
+%D \startformula \xrightarrow{stuff on top}\stopformula
+%D \startformula \xrightarrow{}{stuff on top}\stopformula
+%D \startformula \xrightarrow{stuff below}{}\stopformula
+%D \startformula \xrightarrow{stuff below}{stuff on top}\stopformula
+%D
+%D \startformula \xleftarrow [none]{stuff below}{stuff on top}\stopformula
+%D \startformula \xleftarrow [small]{stuff below}{stuff on top}\stopformula
+%D \startformula \xleftarrow [medium]{stuff below}{stuff on top}\stopformula
+%D \startformula \xleftarrow [big]{stuff below}{stuff on top}\stopformula
+%D \stopbuffer
+%D
+%D \typebuffer which gives \getbuffer
+
+%D \macros{definemathoverarrow,defineunderarrow}
+%D
+%D These macros for define math-overarrows are adapted from
+%D \filename{amsmath.sty}
+
+\def\definemathoverarrow
+ {\dotripleargument\dodefinemathoverarrow}
+
+\def\dodefinemathoverarrow[#1][#2][#3]%
+ {\ifthirdargument
+ \setvalue{#1}{\dohandlemathoverarrow[#2][#3]}%
+ \else
+ \setvalue{#1}{\dohandlemathoverarrow[\zeropoint][#2]}%
+ \fi}
+
+\def\dohandlemathoverarrow[#1][#2]%
+ {\mathpalette{\dodohandlemathoverarrow{#1}{#2}}}
+
+%D Note: \filename{math-pln.tex} has \type{\kern-\onepoint} and
+%D \filename{amsmath.sty} does not. We keep the kern amount
+%D configurable. This is useful for harpoons.
+
+\def\dodohandlemathoverarrow#1#2#3#4%
+ {\vbox{\ialign{##\crcr
+ #2#3\crcr
+ \noalign{\kern#1\nointerlineskip}%
+ $\mathsurround\zeropoint\hfil#3#4\hfil$\crcr}}}
+
+%D Now the under arrows
+
+\def\definemathunderarrow
+ {\dotripleargument\dodefinemathunderarrow}
+
+%D For underarrows the default kern is 0.3ex
+
+\def\dodefinemathunderarrow[#1][#2][#3]%
+ {\ifthirdargument
+ \setvalue{#1}{\dohandlemathunderarrow[#2][#3]}%
+ \else
+ \setvalue{#1}{\dohandlemathunderarrow[0.3ex][#2]}%
+ \fi}
+
+\def\dohandlemathunderarrow[#1][#2]%
+ {\mathpalette{\dodohandlemathunderarrow{#1}{#2}}}
+
+\def\dodohandlemathunderarrow#1#2#3#4%
+ {\vtop{\ialign{##\crcr
+ $\mathsurround\zeropoint\hfil#3#4\hfil$\crcr
+ \noalign{\nointerlineskip\kern#1}%
+ #2#3\crcr}}}
+
+%D Now we define the arrows
+
+\definemathoverarrow [overleftarrow] [\specleftarrowfill]
+\definemathoverarrow [overrightarrow] [\specrightarrowfill]
+\definemathoverarrow [overleftrightarrow] [\leftrightarrowfill]
+\definemathoverarrow [overtwoheadrightarrow] [\twoheadrightarrowfill]
+\definemathoverarrow [overtwoheadleftarrow] [\twoheadleftarrowfill]
+\definemathoverarrow [overrightharpoondown] [1pt] [\rightharpoondownfill]
+\definemathoverarrow [overrightharpoonup] [\rightharpoonupfill]
+\definemathoverarrow [overleftharpoondown] [1pt] [\leftharpoondownfill]
+\definemathoverarrow [overleftharpoonup] [\leftharpoonupfill]
+
+\definemathunderarrow [underleftarrow] [\specleftarrowfill]
+\definemathunderarrow [underrightarrow] [\specrightarrowfill]
+\definemathunderarrow [underleftrightarrow] [\leftrightarrowfill]
+\definemathunderarrow [undertwoheadrightarrow][\twoheadrightarrowfill]
+\definemathunderarrow [undertwoheadleftarrow] [\twoheadleftarrowfill]
+\definemathunderarrow [underrightharpoondown] [\rightharpoondownfill]
+\definemathunderarrow [underrightharpoonup] [\rightharpoonupfill]
+\definemathunderarrow [underleftharpoondown] [\leftharpoondownfill]
+\definemathunderarrow [underleftharpoonup] [\leftharpoonupfill]
+
+%D These can be used as follows:
+%D
+%D \startbuffer
+%D $\overleftarrow{A}$ $\overleftarrow{ABC}$
+%D $a_{\overleftarrow{A}}$ $b_{\overleftarrow{ABC}}$
+%D \stopbuffer
+%D \typebuffer which gives \getbuffer
+
+%D TODO: Possibly have a single arrow command define all the arrows.
+
+\protect \endinput
diff --git a/tex/context/base/math-arr.mkiv b/tex/context/base/math-arr.mkiv
new file mode 100644
index 000000000..389112b16
--- /dev/null
+++ b/tex/context/base/math-arr.mkiv
@@ -0,0 +1,439 @@
+%D \module
+%D [ file=math-arr,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Arrows,
+%D author={Hans Hagen \& Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Math Macros / Arrows}
+
+\unprotect
+
+%D These will be generalized! Is it still needed in \MKIV?
+
+\def\exmthfont#1{\symbolicsizedfont#1\plusone{MathExtension}}
+
+\def\domthfrac#1#2#3#4#5#6#7%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #6$}%
+ \setbox2\hbox{$#1 #7$}%
+ \dimen0\wd0
+ \ifdim\wd2>\dimen0 \dimen0\wd2 \fi
+ \setbox4\hbox to \dimen0{\exmthfont#2#3\leaders\hbox{#4}\hss#5}%
+ \mathord{\vcenter{{\offinterlineskip
+ \hbox to \dimen0{\hss\box0\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\copy4\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\box2\hss}}}}%
+ \endgroup}
+
+\def\domthsqrt#1#2#3#4#5%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #5$}%
+ \dimen0=1.05\ht0 \advance\dimen0 1pt \ht0 \dimen0
+ \dimen0=1.05\dp0 \advance\dimen0 1pt \dp0 \dimen0
+ \dimen0\wd0
+ \setbox4\hbox to \dimen0{\exmthfont#2\leaders\hbox{#3}\hfill#4}%
+ \delimitershortfall=0pt
+ \nulldelimiterspace=0pt
+ \setbox2\hbox{$\left\delimiter"0270370 \vrule height\ht0 depth \dp0 width0pt
+ \right.$}%
+ \mathord{\vcenter{\hbox{\copy2
+ \rlap{\raise\dimexpr\ht2-\ht4\relax\copy4}\copy0}}}%
+ \endgroup}
+
+\def\mthfrac#1#2#3#4#5{\mathchoice
+ {\domthfrac\displaystyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\textstyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptstyle \scriptface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptscriptstyle\scriptscriptface{#1}{#2}{#3}{#4}{#5}}}
+
+\def\mthsqrt#1#2#3{\mathchoice
+ {\domthsqrt\displaystyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\textstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptscriptstyle\textface {#1}{#2}{#3}}}
+
+% temp here
+
+%D We next define extensible arrows. Extensible arrows are arrows that
+%D change their length according to the width of the text to be placed
+%D above and below the arrow. Since we need to define a lot of arrows,
+%D we first define some helper macros. The basic idea is to measure
+%D the width of the box to be placed above and below the arrow, and
+%D make the \quotation{body} of the arrow as long as the bigger of the
+%D two widths.
+
+\def\mtharrfactor{1}
+\def\mtharrextra {0}
+
+\def\domthxarr#1#2#3#4#5% hm, looks like we do a double mathrel
+ {\begingroup
+ \def\mtharrfactor{1}%
+ \def\mtharrextra {0}%
+ \processaction[#1] % will be sped up
+ [ \v!none=>\def\mtharrfactor{0},
+ \v!small=>\def\mtharrextra{10},
+ \v!medium=>\def\mtharrextra{15},
+ \v!big=>\def\mtharrextra{20},
+ \v!normal=>,
+ \v!default=>,
+ \v!unknown=>\doifnumberelse{#1}{\def\mtharrextra{#1}}\donothing]%
+ \mathsurround\zeropoint
+ \muskip0=\thirdoffourarguments #2mu
+ \muskip2=\fourthoffourarguments #2mu
+ \muskip4=\firstoffourarguments #2mu
+ \muskip6=\secondoffourarguments #2mu
+ \muskip0=\mtharrfactor\muskip0 \advance\muskip0 \mtharrextra mu
+ \muskip2=\mtharrfactor\muskip2 \advance\muskip2 \mtharrextra mu
+ \setbox0\hbox{$\scriptstyle
+ \mkern\muskip4\relax
+ \mkern\muskip0\relax
+ #5\relax
+ \mkern\muskip2\relax
+ \mkern\muskip6\relax
+ $}%
+ \setbox4\hbox{#3\displaystyle}%
+ \dimen0\wd0
+ \ifdim\wd4>\dimen0 \dimen0\wd4 \fi
+ \setbox2\hbox{$\scriptstyle
+ \mkern\muskip4\relax
+ \mkern\muskip0\relax
+ #4\relax
+ \mkern\muskip2\relax
+ \mkern\muskip6\relax
+ $}%
+ \ifdim\wd2>\dimen0 \dimen0\wd2 \fi
+ \setbox4\hbox to \dimen0{#3\displaystyle}%
+ \mathrel{\mathop{\hbox to \dimen0{\hss\copy4\hss}}\limits^{\box0}_{\box2}}
+ \endgroup}
+
+\let\domthxarrsingle\domthxarr
+
+%D There are some arrows which are created by stacking two arrows. The next
+%D macro helps in defining such \quotation{double arrows}.
+
+\def\domthxarrdouble#1#2#3#4#5#6#7% opt l r sp rs top bot
+ {\mathrel
+ {\scratchdimen.32ex\relax % was .22, todo: make configurable
+ \setbox0\hbox{$\domthxarr{#1}{#2}{#4}{\phantom{#6}}{#7}$}%
+ \setbox2\hbox{$\domthxarr{#1}{#3}{#5}{#6}{\phantom{#7}}$}%
+ \raise\scratchdimen\box0
+ \kern-\wd2
+ \lower\scratchdimen\box2}}
+
+%D \macros{definematharrow}
+%D
+%D Macro for defining new arrows. We can define two types of
+%D arrows|<|single arrows and double arrows. Single arrows are defined
+%D as
+%D
+%D \starttyping
+%D \definematharrow [xrightarrow] [0359] [\rightarrowfill]
+%D \stoptyping
+%D
+%D The first argument is the name of the arrow (\tex{xrightarrow} in
+%D this case.) The second argument consists of a set of 4 numbers and
+%D specify the spacing correction in math units~\type{mu}. These
+%D numbers define:
+%D
+%D \startlines
+%D 1st number: arrow||tip correction
+%D 2nd number: arrow||tip correction
+%D 3rd number: space (multiplied by \tex{matharrfactor} and advanced by \tex{matharrextra})
+%D 4th number: space (multiplied by \tex{matharrfactor} and advanced by \tex{matharrextra})
+%D \stoplines
+%D
+%D The third argument is the name of the extensible fill. The third
+%D argument is optional when the arrow is redefined later (this is
+%D useful for font specific tweaking of the skips.) For example,
+%D
+%D \startbuffer
+%D \math{\xrightarrow{above}}
+%D \definematharrow[xrightarrow][0000]
+%D \math{\xrightarrow{above}}
+%D \definematharrow[xrightarrow][55{50}{50}]
+%D \math{\xrightarrow{above}}
+%D \stopbuffer
+%D \typebuffer gives {\getbuffer}
+%D
+%D The double arrows are defined as follows
+%D
+%D \starttyping
+%D \definematharrow [xrightleftharpoons] [3095,0359]
+%D [\rightharpoonupfill,\leftharpoondownfill]
+%D \stoptyping
+%D
+%D The second and the third set of arguments consist of comma
+%D separated values. The first element of the second argument
+%D (\type{3095}) corresponds to the spacing correction of top arrow
+%D fill (\tex{rightarrowupfill}). Similarly, \type{0359} corresponds
+%D to bottom arrow fill \tex{leftharpoondownfill}). Stacking them on
+%D top of each other we get $\xrightleftharpoons[big]{above}{below}$.
+%D The following math arrows are defined
+%D
+%D \placetable[none]{}{\starttable[|l|m|]
+%D \NC \tex{xrightarrow } \NC \xrightarrow [big] \NC \NR
+%D \NC \tex{xleftarrow } \NC \xleftarrow [big] \NC \NR
+%D \NC \tex{xequal } \NC \xequal [big] \NC \NR
+%D \NC \tex{xRightarrow } \NC \xRightarrow [big] \NC \NR
+%D \NC \tex{xLeftarrow } \NC \xLeftarrow [big] \NC \NR
+%D \NC \tex{xLeftrightarrow } \NC \xLeftrightarrow [big] \NC \NR
+%D \NC \tex{xleftrightarrow } \NC \xleftrightarrow [big] \NC \NR
+%D \NC \tex{xmapsto } \NC \xmapsto [big] \NC \NR
+%D \NC \tex{xtwoheadrightarrow } \NC \xtwoheadrightarrow [big] \NC \NR
+%D \NC \tex{xtwoheadleftarrow } \NC \xtwoheadleftarrow [big] \NC \NR
+%D \NC \tex{xrightharpoondown } \NC \xrightharpoondown [big] \NC \NR
+%D \NC \tex{xrightharpoonup } \NC \xrightharpoonup [big] \NC \NR
+%D \NC \tex{xleftharpoondown } \NC \xleftharpoondown [big] \NC \NR
+%D \NC \tex{xleftharpoonup } \NC \xleftharpoonup [big] \NC \NR
+%D \NC \tex{xhookleftarrow } \NC \xhookleftarrow [big] \NC \NR
+%D \NC \tex{xhookrightarrow } \NC \xhookrightarrow [big] \NC \NR
+%D \NC \tex{xleftrightharpoons } \NC \xleftrightharpoons [big] \NC \NR
+%D \NC \tex{xrightleftharpoons } \NC \xrightleftharpoons [big] \NC \NR
+%D \stoptable}
+
+\unexpanded\def\definematharrow
+ {\doquadrupleargument\dodefinematharrow}
+
+\def\dodefinematharrow[#1][#2][#3][#4]% name type[none|both] template command
+ {\iffourthargument
+ \executeifdefined{dodefine#2arrow}\gobblethreearguments{#1}{#3}{#4}%
+ \else\ifthirdargument
+ \dodefinebotharrow{#1}{#2}{#3}%
+ \else\ifsecondargument
+ \redefinebotharrow{#1}{#2}{#3}%
+ \fi\fi\fi}
+
+\def\redefinebotharrow#1#2#3% real dirty, this overload!
+ {\doifdefined{#1}
+ {\pushmacro\dohandlemtharrow
+ \def\dohandlemtharrow[##1][##2]{\setuvalue{#1}{\dohandlemtharrow[#2][##2]}}%
+ % == \def\dohandlemtharrow[##1][##2]{\dodefinebotharrow{#1}{#2}{##2}}%
+ \getvalue{#1}%
+ \popmacro\dohandlemtharrow}}
+
+\def\dodefinebotharrow#1#2#3%
+ {\setuvalue{#1}{\dohandlemtharrow[#2][#3]}}
+
+\def\dohandlemtharrow
+ {\dotripleempty\doxmtharrow}
+
+\def\doxmtharrow[#1][#2][#3]% #3 == optional arg
+ {\def\dodoxmtharrow{\dododoxmtharrow[#1,\empty,\empty][#2,\empty,\empty][#3]}% {##1}{##2}
+ \dodoublegroupempty\dodoxmtharrow}
+
+\def\dododoxmtharrow[#1,#2,#3][#4,#5,#6][#7]#8#9% [3] is the optional arg
+ {\edef\!!stringa{#2}%
+ \ifx\!!stringa\empty
+ \ifsecondargument
+ \mathrel{\domthxarrsingle{#7}{#1}{#4}{#8}{#9}}%
+ \else
+ \mathrel{\domthxarrsingle{#7}{#1}{#4}{}{#8}}%
+ \fi
+ \else
+ \ifsecondargument
+ \mathrel{\domthxarrdouble{#7}{#1}{#2}{#4}{#5}{#8}{#9}}%
+ \else
+ \mathrel{\domthxarrdouble{#7}{#1}{#2}{#4}{#5}{}{#8}}%
+ \fi
+ \fi}
+
+% Adapted from amsmath.
+
+%D \macros{mtharrowfill,defaultmtharrowfill}
+%D
+%D To extend the arrows we need to define a \quotation{math arrow
+%D fill}. This command takes 8 arguments: the first four correspond
+%D the second argument of \tex{definematharrow} explained above. The
+%D other three specify the tail, body and head of the arrow. The last
+%D argument specifies the math-mode in which the arrow is drawn.
+%D \tex{defaultmtharrowfill} has values tweaked to match Latin Modern
+%D fonts. For fonts that are significantly different (e.g. cows) a
+%D different set of values need to be determined.
+
+\def\mtharrowfill#1#2#3#4#5#6#7#8%
+ {$\mathsurround 0pt
+ \thickmuskip0mu\medmuskip\thickmuskip\thinmuskip\thickmuskip
+ \relax#8#5%
+ \mkern-#1mu
+ \cleaders\hbox{$#8\mkern -#2mu#6\mkern -#3mu$}\hfill
+ \mkern-#4mu#7$}
+
+\def\defaultmtharrowfill{\mtharrowfill 7227}
+
+%D We now define some arrow fills that will be used for defining the
+%D arrows. Plain \TEX\ already defines \tex{leftarrowfill} and
+%D \tex{rightarrowfill}. The \tex{defaultmtharrowfill} command defines an
+%D arrowfill that takes an argument (so that it can also be used
+%D with over and under arrows). However the Plain \TEX\ definitions of
+%D \tex{leftarrowfill} and \tex{rightarrowfill} do not take this extra
+%D argument. To be backward compatible with Plain \TEX, we define two
+%D arrowfills: \tex{specrightarrowfill} which takes an extra argument, and
+%D \tex{rightarrowfill} which does not.
+
+\unexpanded\def\specrightarrowfill {\defaultmtharrowfill \relbar \relbar \rightarrow}
+\unexpanded\def\specleftarrowfill {\defaultmtharrowfill \leftarrow \relbar \relbar}
+
+\unexpanded\def\rightarrowfill {\specrightarrowfill \textstyle}
+\unexpanded\def\leftarrowfill {\specleftarrowfill \textstyle}
+
+\unexpanded\def\equalfill {\defaultmtharrowfill \Relbar \Relbar \Relbar}
+\unexpanded\def\Rightarrowfill {\defaultmtharrowfill \Relbar \Relbar \Rightarrow}
+\unexpanded\def\Leftarrowfill {\defaultmtharrowfill \Leftarrow \Relbar \Relbar}
+\unexpanded\def\Leftrightarrowfill {\defaultmtharrowfill \Leftarrow \Relbar \Rightarrow}
+\unexpanded\def\leftrightarrowfill {\defaultmtharrowfill \leftarrow \relbar \rightarrow}
+\unexpanded\def\mapstofill {\defaultmtharrowfill{\mapstochar\relbar} \relbar \rightarrow}
+\unexpanded\def\twoheadrightarrowfill{\defaultmtharrowfill \relbar \relbar \twoheadrightarrow}
+\unexpanded\def\twoheadleftarrowfill {\defaultmtharrowfill \twoheadleftarrow \relbar \relbar}
+\unexpanded\def\rightharpoondownfill {\defaultmtharrowfill \relbar \relbar \rightharpoondown}
+\unexpanded\def\rightharpoonupfill {\defaultmtharrowfill \relbar \relbar \rightharpoonup}
+\unexpanded\def\leftharpoondownfill {\defaultmtharrowfill \leftharpoondown \relbar \relbar}
+\unexpanded\def\leftharpoonupfill {\defaultmtharrowfill \leftharpoonup \relbar \relbar}
+\unexpanded\def\hookleftfill {\defaultmtharrowfill \leftarrow \relbar{\relbar\joinrel\rhook}}
+\unexpanded\def\hookrightfill {\defaultmtharrowfill{\lhook\joinrel\relbar}\relbar \rightarrow}
+\unexpanded\def\relfill {\defaultmtharrowfill \relbar \relbar \relbar}
+
+\unexpanded\def\triplerelbar {\mathrel\equiv}
+\unexpanded\def\triplerelfill{\defaultmtharrowfill\triplerelbar\triplerelbar\triplerelbar}
+
+\unexpanded\def\singlebond{{\xrel}} % or \def\singlebond{{\xrel[2]}}
+\unexpanded\def\doublebond{{\xequal}}
+\unexpanded\def\triplebond{{\xtriplerel}}
+
+%D Now we define most commonly used arrows. These include arrows
+%D defined in \filename{amsmath.sty}, \filename{extarrows.sty},
+%D \filename{extpfel.sty} and \filename{mathtools.sty} packages for
+%D \LATEX\ (plus a few more).
+
+\definematharrow [xrightarrow] [0359] [\specrightarrowfill]
+\definematharrow [xleftarrow] [3095] [\specleftarrowfill]
+\definematharrow [xequal] [0099] [\equalfill]
+\definematharrow [xRightarrow] [0359] [\Rightarrowfill]
+\definematharrow [xLeftarrow] [3095] [\Leftarrowfill]
+\definematharrow [xLeftrightarrow] [0099] [\Leftrightarrowfill]
+\definematharrow [xleftrightarrow] [0099] [\leftrightarrowfill]
+\definematharrow [xmapsto] [3599] [\mapstofill]
+\definematharrow [xtwoheadrightarrow] [5009] [\twoheadrightarrowfill]
+\definematharrow [xtwoheadleftarrow] [0590] [\twoheadleftarrowfill]
+\definematharrow [xrightharpoondown] [0359] [\rightharpoondownfill]
+\definematharrow [xrightharpoonup] [0359] [\rightharpoonupfill]
+\definematharrow [xleftharpoondown] [3095] [\leftharpoondownfill]
+\definematharrow [xleftharpoonup] [3095] [\leftharpoonupfill]
+\definematharrow [xhookleftarrow] [3095] [\hookleftfill]
+\definematharrow [xhookrightarrow] [0395] [\hookrightfill]
+\definematharrow [xrel] [0099] [\relfill]
+\definematharrow [xtriplerel] [0099] [\triplerelfill]
+\definematharrow [xrightoverleftarrow] [0359,3095] [\specrightarrowfill,\specleftarrowfill]
+\definematharrow [xleftrightharpoons] [3399,3399] [\leftharpoonupfill,\rightharpoondownfill]
+\definematharrow [xrightleftharpoons] [3399,3399] [\rightharpoonupfill,\leftharpoondownfill]
+
+%D These arrows can be used as follows:
+%D
+%D \startbuffer
+%D \startformula \xrightarrow{stuff on top}\stopformula
+%D \startformula \xrightarrow{}{stuff on top}\stopformula
+%D \startformula \xrightarrow{stuff below}{}\stopformula
+%D \startformula \xrightarrow{stuff below}{stuff on top}\stopformula
+%D
+%D \startformula \xleftarrow [none]{stuff below}{stuff on top}\stopformula
+%D \startformula \xleftarrow [small]{stuff below}{stuff on top}\stopformula
+%D \startformula \xleftarrow [medium]{stuff below}{stuff on top}\stopformula
+%D \startformula \xleftarrow [big]{stuff below}{stuff on top}\stopformula
+%D \stopbuffer
+%D
+%D \typebuffer which gives \getbuffer
+
+%D \macros{definemathoverarrow,defineunderarrow}
+%D
+%D These macros for define math-overarrows are adapted from
+%D \filename{amsmath.sty}
+
+\unexpanded\def\definemathoverarrow
+ {\dotripleargument\dodefinemathoverarrow}
+
+\def\dodefinemathoverarrow[#1][#2][#3]%
+ {\ifthirdargument
+ \setuvalue{#1}{\dohandlemathoverarrow[#2][#3]}%
+ \else
+ \setuvalue{#1}{\dohandlemathoverarrow[\zeropoint][#2]}%
+ \fi}
+
+\def\dohandlemathoverarrow[#1][#2]%
+ {\mathpalette{\dodohandlemathoverarrow{#1}{#2}}}
+
+%D Note: \filename{math-pln.tex} has \type{\kern-\onepoint} and
+%D \filename{amsmath.sty} does not. We keep the kern amount
+%D configurable. This is useful for harpoons.
+
+\def\dodohandlemathoverarrow#1#2#3#4%
+ {\vbox{\ialign{##\crcr
+ #2#3\crcr
+ \noalign{\kern#1\nointerlineskip}%
+ $\mathsurround\zeropoint\hfil#3#4\hfil$\crcr}}}
+
+%D Now the under arrows
+
+\unexpanded\def\definemathunderarrow
+ {\dotripleargument\dodefinemathunderarrow}
+
+%D For underarrows the default kern is 0.3ex
+
+\def\dodefinemathunderarrow[#1][#2][#3]%
+ {\ifthirdargument
+ \setuvalue{#1}{\dohandlemathunderarrow[#2][#3]}%
+ \else
+ \setuvalue{#1}{\dohandlemathunderarrow[0.3ex][#2]}%
+ \fi}
+
+\def\dohandlemathunderarrow[#1][#2]%
+ {\mathpalette{\dodohandlemathunderarrow{#1}{#2}}}
+
+\def\dodohandlemathunderarrow#1#2#3#4%
+ {\vtop{\ialign{##\crcr
+ $\mathsurround\zeropoint\hfil#3#4\hfil$\crcr
+ \noalign{\nointerlineskip\kern#1}%
+ #2#3\crcr}}}
+
+%D Now we define the arrows
+
+\definemathoverarrow [overleftarrow] [\specleftarrowfill]
+\definemathoverarrow [overrightarrow] [\specrightarrowfill]
+\definemathoverarrow [overleftrightarrow] [\leftrightarrowfill]
+\definemathoverarrow [overtwoheadrightarrow] [\twoheadrightarrowfill]
+\definemathoverarrow [overtwoheadleftarrow] [\twoheadleftarrowfill]
+\definemathoverarrow [overrightharpoondown] [1pt] [\rightharpoondownfill]
+\definemathoverarrow [overrightharpoonup] [\rightharpoonupfill]
+\definemathoverarrow [overleftharpoondown] [1pt] [\leftharpoondownfill]
+\definemathoverarrow [overleftharpoonup] [\leftharpoonupfill]
+
+\definemathunderarrow [underleftarrow] [\specleftarrowfill]
+\definemathunderarrow [underrightarrow] [\specrightarrowfill]
+\definemathunderarrow [underleftrightarrow] [\leftrightarrowfill]
+\definemathunderarrow [undertwoheadrightarrow][\twoheadrightarrowfill]
+\definemathunderarrow [undertwoheadleftarrow] [\twoheadleftarrowfill]
+\definemathunderarrow [underrightharpoondown] [\rightharpoondownfill]
+\definemathunderarrow [underrightharpoonup] [\rightharpoonupfill]
+\definemathunderarrow [underleftharpoondown] [\leftharpoondownfill]
+\definemathunderarrow [underleftharpoonup] [\leftharpoonupfill]
+
+%D These can be used as follows:
+%D
+%D \startbuffer
+%D $\overleftarrow{A}$ $\overleftarrow{ABC}$
+%D $a_{\overleftarrow{A}}$ $b_{\overleftarrow{ABC}}$
+%D \stopbuffer
+%D \typebuffer which gives \getbuffer
+
+%D TODO: Possibly have a single arrow command define all the arrows.
+
+\protect \endinput
diff --git a/tex/context/base/math-cow.mkii b/tex/context/base/math-cow.mkii
new file mode 100644
index 000000000..f0fc811c8
--- /dev/null
+++ b/tex/context/base/math-cow.mkii
@@ -0,0 +1,31 @@
+%D \module
+%D [ file=math-cow,
+%D version=2006.06.23,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Cow Math,
+%D author={Hans Hagen \& Taco Hoekwater},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\def\COWsqrt {\mthsqrt{\char"7A}{\char"7B}}
+\def\COWfrac {\mthfrac{\char"7C}{\char"7A}{\char"7B}}
+\def\COWarrowfill{\mtharrowfill 1001}
+
+\startmathcollection [cow]
+ % todo
+\stopmathcollection
+
+\startrawmathcollection[cow]
+ \definemathcommand [frac] {\COWfrac}
+ \definemathcommand [sqrt] {\COWsqrt}
+ %definemathcommand [r@@t] {\COWroot}
+ %definemathcommand [matrix] {\COWmatrix}
+\stoprawmathcollection
+
+\protect \endinput
diff --git a/tex/context/base/math-def.mkiv b/tex/context/base/math-def.mkiv
new file mode 100644
index 000000000..50c9902dd
--- /dev/null
+++ b/tex/context/base/math-def.mkiv
@@ -0,0 +1,374 @@
+%D \module
+%D [ file=math-tex,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Definitions,
+%D author={Hans Hagen, Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Math Macros / Definitions}
+
+\unprotect
+
+\ifx\mrfam\undefined \chardef\mrfam\plusone \fi
+
+\startluacode
+ mathematics.define()
+ mathematics.register_xml_entities()
+\stopluacode
+
+% special .. todo
+
+\mathcode`\ ="8000 \mathcode`\_="8000 \mathcode`\'="8000
+
+% will be attributes
+
+\setfalse \automathpunctuation
+
+\def\enablemathpunctuation {\settrue \automathpunctuation}
+\def\disablemathpunctuation{\setfalse\automathpunctuation}
+
+\def\v!autopunctuation{autopunctuation}
+
+\appendtoks
+ \doifelse{\mathematicsparameter\v!autopunctuation}\v!yes\enablemathpunctuation\disablemathpunctuation
+\to \everysetupmathematics
+
+% \appendtoks
+% \ifconditional\automathpunctuation\attribute\mathpunctuationattribute\plusone\fi
+% \to \everymathematics
+
+\setupmathematics[\v!autopunctuation=\v!yes]
+
+% will go to math-ext
+
+\Umathchardef\braceld=0 \mrfam "FF07A
+\Umathchardef\bracerd=0 \mrfam "FF07B
+\Umathchardef\bracelu=0 \mrfam "FF07C
+\Umathchardef\braceru=0 \mrfam "FF07D
+
+% ctx specific
+
+\def\|{|} % still letter
+
+% The \mfunction macro is an alternative for \hbox with a
+% controlable font switch.
+
+\definemathcommand [arccos] [nolop] {\mfunctionlabeltext{arccos}}
+\definemathcommand [arcsin] [nolop] {\mfunctionlabeltext{arcsin}}
+\definemathcommand [arctan] [nolop] {\mfunctionlabeltext{arctan}}
+\definemathcommand [arg] [nolop] {\mfunctionlabeltext{arg}}
+\definemathcommand [cosh] [nolop] {\mfunctionlabeltext{cosh}}
+\definemathcommand [cos] [nolop] {\mfunctionlabeltext{cos}}
+\definemathcommand [coth] [nolop] {\mfunctionlabeltext{coth}}
+\definemathcommand [cot] [nolop] {\mfunctionlabeltext{cot}}
+\definemathcommand [csc] [nolop] {\mfunctionlabeltext{csc}}
+\definemathcommand [deg] [nolop] {\mfunctionlabeltext{deg}}
+\definemathcommand [det] [limop] {\mfunctionlabeltext{det}}
+\definemathcommand [dim] [nolop] {\mfunctionlabeltext{dim}}
+\definemathcommand [exp] [nolop] {\mfunctionlabeltext{exp}}
+\definemathcommand [gcd] [limop] {\mfunctionlabeltext{gcd}}
+\definemathcommand [hom] [nolop] {\mfunctionlabeltext{hom}}
+\definemathcommand [inf] [limop] {\mfunctionlabeltext{inf}}
+\definemathcommand [injlim] [limop] {\mfunctionlabeltext{injlim}}
+\definemathcommand [ker] [nolop] {\mfunctionlabeltext{ker}}
+\definemathcommand [lg] [nolop] {\mfunctionlabeltext{lg}}
+\definemathcommand [liminf] [limop] {\mfunctionlabeltext{liminf}}
+\definemathcommand [limsup] [limop] {\mfunctionlabeltext{limsup}}
+\definemathcommand [lim] [limop] {\mfunctionlabeltext{lim}}
+\definemathcommand [ln] [nolop] {\mfunctionlabeltext{ln}}
+\definemathcommand [log] [nolop] {\mfunctionlabeltext{log}}
+\definemathcommand [median] [limop] {\mfunctionlabeltext{median}}
+\definemathcommand [max] [limop] {\mfunctionlabeltext{max}}
+\definemathcommand [min] [limop] {\mfunctionlabeltext{min}}
+\definemathcommand [mod] [limop] {\mfunctionlabeltext{mod}}
+%definemathcommand [div] [limop] {\mfunctionlabeltext{div}} % overloads \div symbol
+\definemathcommand [projlim] [limop] {\mfunctionlabeltext{projlim}}
+\definemathcommand [Pr] [limop] {\mfunctionlabeltext{Pr}}
+\definemathcommand [sec] [nolop] {\mfunctionlabeltext{sec}}
+\definemathcommand [sinh] [nolop] {\mfunctionlabeltext{sinh}}
+\definemathcommand [sin] [nolop] {\mfunctionlabeltext{sin}}
+\definemathcommand [sup] [limop] {\mfunctionlabeltext{sup}}
+\definemathcommand [tanh] [nolop] {\mfunctionlabeltext{tanh}}
+\definemathcommand [tan] [nolop] {\mfunctionlabeltext{tan}}
+
+\definemathcommand [integers] {{\mathblackboard Z}}
+\definemathcommand [reals] {{\mathblackboard R}}
+\definemathcommand [rationals] {{\mathblackboard Q}}
+\definemathcommand [naturalnumbers]{{\mathblackboard N}}
+\definemathcommand [complexes] {{\mathblackboard C}}
+\definemathcommand [primes] {{\mathblackboard P}}
+
+\let\normalmatharg\arg % todo: maybe automatically
+
+% using attributes
+
+\chardef\bigmathdelimitermethod\plusone
+
+\def\plainbigdelimiters % traditional method
+ {\chardef\bigmathdelimitermethod\plustwo}
+
+\def\doplainbigmath#1#2%
+ {{\hbox{$%
+ \nulldelimiterspace\zeropoint\relax
+ \mathsurround\zeropoint
+ $}}}
+
+\def\doleftbigmath #1{\ifx#1\relax\else\left#1\expandafter\doleftbigmath \fi}
+\def\dorightbigmath#1{\ifx#1\relax\else\right.\expandafter\dorightbigmath\fi}
+
+\def\choosemathbig#1#2% so we accent \big{||} as well
+ {{\hbox{$%
+ \ifcase\bigmathdelimitermethod
+ \doleftbigmath#2\relax
+ \dorightbigmath#2\relax
+ \or
+ \attribute\mathsizeattribute#1\relax
+ \doleftbigmath#2\relax
+ \dorightbigmath#2\relax
+ \else
+ \doleftbigmath#2\relax
+ \vbox\!!to\getvalue{\??mm:b:\number#1}\bodyfontsize{}%
+ \dorightbigmath#2\relax
+ \fi
+ \nulldelimiterspace\zeropoint\relax
+ \mathsurround\zeropoint
+ $}}}
+
+\definemathcommand [big] {\choosemathbig\plusone } \setvalue{\??mm:b:1}{0.85}
+\definemathcommand [Big] {\choosemathbig\plustwo } \setvalue{\??mm:b:2}{1.15}
+\definemathcommand [bigg] {\choosemathbig\plusthree} \setvalue{\??mm:b:3}{1.45}
+\definemathcommand [Bigg] {\choosemathbig\plusfour } \setvalue{\??mm:b:4}{1.75}
+
+\definemathcommand [bigl] [open] [one] {\big}
+\definemathcommand [bigm] [rel] [one] {\big}
+\definemathcommand [bigr] [close] [one] {\big}
+\definemathcommand [Bigl] [open] [one] {\Big}
+\definemathcommand [Bigm] [rel] [one] {\Big}
+\definemathcommand [Bigr] [close] [one] {\Big}
+\definemathcommand [biggl] [open] [one] {\bigg}
+\definemathcommand [biggm] [rel] [one] {\bigg}
+\definemathcommand [biggr] [close] [one] {\bigg}
+\definemathcommand [Biggl] [open] [one] {\Bigg}
+\definemathcommand [Biggm] [rel] [one] {\Bigg}
+\definemathcommand [Biggr] [close] [one] {\Bigg}
+
+% special
+
+%AM: Optimize this! Add similar options for sums.
+
+\def\setoperatorlimits#1#2% operator limits
+ {\savenormalmeaning{#1}%
+ \def#1{\csname normal\strippedcsname#1\endcsname#2}}
+
+\setoperatorlimits\int \intlimits
+\setoperatorlimits\iint \intlimits
+\setoperatorlimits\iiint \intlimits
+\setoperatorlimits\oint \intlimits
+\setoperatorlimits\oiint \intlimits
+\setoperatorlimits\oiiint \intlimits
+\setoperatorlimits\intclockwise \intlimits
+\setoperatorlimits\ointclockwise \intlimits
+\setoperatorlimits\ointctrclockwise \intlimits
+
+%D This is a temporary hack until we figure out how to do this correctly.
+
+\unexpanded\def\implies {\mathrel{\;\Longrightarrow\;}}
+\unexpanded\def\impliedby{\mathrel{\;\Longleftarrow\;}}
+\unexpanded\def\And {\mathrel{\;\internalAnd\;}}
+\unexpanded\def\iff {\;\Longleftrightarrow\;}
+
+% todo: virtual in math-vfu
+
+% \definemathcommand [mapsto] {\mapstochar\rightarrow}
+% \definemathcommand [hookrightarrow] {\lhook\joinrel\rightarrow}
+% \definemathcommand [hookleftarrow] {\leftarrow\joinrel\rhook}
+% \definemathcommand [bowtie] {\mathrel\triangleright\joinrel\mathrel\triangleleft}
+% \definemathcommand [models] {\mathrel|\joinrel=}
+% \definemathcommand [iff] {\;\Longleftrightarrow\;}
+
+% hm
+
+% ldots = 2026
+% vdots = 22EE
+% cdots = 22EF
+% ddots = 22F1
+% udots = 22F0
+
+% \def\PLAINldots{\ldotp\ldotp\ldotp}
+% \def\PLAINcdots{\cdotp\cdotp\cdotp}
+
+% \def\PLAINvdots
+% {\vbox{\baselineskip.4\bodyfontsize\lineskiplimit\zeropoint\kern.6\bodyfontsize\hbox{.}\hbox{.}\hbox{.}}}
+
+% \def\PLAINddots
+% {\mkern1mu%
+% \raise.7\bodyfontsize\vbox{\kern.7\bodyfontsize\hbox{.}}%
+% \mkern2mu%
+% \raise.4\bodyfontsize\relax\hbox{.}%
+% \mkern2mu%
+% \raise.1\bodyfontsize\hbox{.}%
+% \mkern1mu}
+
+% \definemathcommand [ldots] [inner] {\PLAINldots}
+% \definemathcommand [cdots] [inner] {\PLAINcdots}
+% \definemathcommand [vdots] [nothing] {\PLAINvdots}
+% \definemathcommand [ddots] [inner] {\PLAINddots}
+
+%D \starttyping
+%D $\sqrt[3]{10}$
+%D \stoptyping
+
+\def\rootradical{\Uroot 0 "221A } % can be done in char-def
+
+\def\root#1\of{\rootradical{#1}} % #2
+
+\unexpanded\def\sqrt{\doifnextoptionalelse\rootwithdegree\rootwithoutdegree}
+
+\def\rootwithdegree [#1]{\rootradical{#1}}
+\def\rootwithoutdegree {\rootradical {}}
+
+\def\PLAINmatrix#1%
+ {\null\,\vcenter{\normalbaselines\mathsurround\zeropoint
+ \ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
+ \mathstrut\crcr\noalign{\kern-\baselineskip}
+ #1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}\,}
+
+\definemathcommand [mathstrut] {\vphantom{(}}
+\definemathcommand [joinrel] {\mathrel{\mkern-3mu}}
+
+% \definemathcommand [matrix] {\PLAINmatrix}
+% \definemathcommand [over] {\normalover} % hack, to do
+
+\unexpanded\def\{{\mathortext\lbrace\letterleftbrace }
+\unexpanded\def\}{\mathortext\rbrace\letterrightbrace}
+
+%D The following colon related definitions are provided by Aditya
+%D Mahajan who derived them from \type {mathtools.sty} and \type
+%D {colonequals.sty}.
+
+%D \macros
+%D {centercolon, colonminus, minuscolon, colonequals, equalscolon,
+%D colonapprox, approxcolon, colonsim, simcolon, coloncolon,
+%D coloncolonminus, minuscoloncolon, coloncolonequals,
+%D equalscoloncolon, coloncolonapprox, approxcoloncolon,
+%D colonsim, simcoloncolon}
+%D
+%D In $a := b$ the colon is not vertically centered with the equal
+%D to. Also the distance between colon and equal to is a bit large.
+%D So, we define a vertically centered colon \tex {centercolon} and
+%D a few macros for colon and double colon relation symbols.
+%D
+%D \startlines
+%D \formula {A \centercolon B}
+%D \formula {A \colonminus B}
+%D \formula {A \minuscolon B}
+%D \formula {A \colonequals B}
+%D \formula {A \equalscolon B}
+%D \formula {A \colonapprox B}
+%D \formula {A \approxcolon B}
+%D \formula {A \colonsim B}
+%D \formula {A \simcolon B}
+%D \formula {A \coloncolon B}
+%D \formula {A \coloncolonminus B}
+%D \formula {A \minuscoloncolon B}
+%D \formula {A \coloncolonequals B}
+%D \formula {A \equalscoloncolon B}
+%D \formula {A \coloncolonapprox B}
+%D \formula {A \approxcoloncolon B}
+%D \formula {A \colonsim B}
+%D \formula {A \simcoloncolon B}
+%D \stoplines
+
+%D The next macros take care of the space between the colon and the
+%D relation symbol.
+
+\definemathcommand [colonsep] {\mkern-1.2mu}
+\definemathcommand [doublecolonsep] {\mkern-0.9mu}
+
+%D The next macro vertically centeres its contents.
+
+\def\@center@math#1%
+ {\vcenter{\hbox{$\mathsurround\zeropoint#1$}}}
+
+\def\@center@colon
+ {\mathpalette\@center@math{\colon}}
+
+%D Now we define all the colon relations.
+
+\definemathcommand [centercolon] [rel] {\@center@colon}
+\definemathcommand [colonminus] [rel] {\centercolon\colonsep\mathrel{-}}
+\definemathcommand [minuscolon] [rel] {\mathrel{-}\colonsep\centercolon}
+\definemathcommand [colonequals] [rel] {\centercolon\colonsep=}
+\definemathcommand [equalscolon] [rel] {=\centercolon\colonsep}
+\definemathcommand [colonapprox] [rel] {\centercolon\colonsep\approx}
+\definemathcommand [approxcolon] [rel] {\approx\centercolon\colonsep}
+\definemathcommand [colonsim] [rel] {\centercolon\colonsep\sim}
+\definemathcommand [simcolon] [rel] {\sim\centercolon\colonsep}
+
+\definemathcommand [coloncolon] [rel] {\centercolon\doublecolonsep\centercolon}
+\definemathcommand [coloncolonminus] [rel] {\coloncolon\colonsep\mathrel{-}}
+\definemathcommand [minuscoloncolon] [rel] {\mathrel{-}\colonsep\coloncolon}
+\definemathcommand [coloncolonequals] [rel] {\coloncolon\colonsep=}
+\definemathcommand [equalscoloncolon] [rel] {=\coloncolon\colonsep}
+\definemathcommand [coloncolonapprox] [rel] {\coloncolon\colonsep\approx}
+\definemathcommand [approxcoloncolon] [rel] {\approx\coloncolon\colonsep}
+\definemathcommand [colonsim] [rel] {\coloncolon\colonsep\sim}
+\definemathcommand [simcoloncolon] [rel] {\sim\coloncolon\colonsep}
+
+%D Goodies. We might move this elsewhere.
+
+\def\underleftarrow #1{\mathop{\Uunderdelimiter 0 "2190 {#1}}}
+\def\overleftarrow #1{\mathop{\Uoverdelimiter 0 "2190 {#1}}}
+\def\underrightarrow#1{\mathop{\Uunderdelimiter 0 "2192 {#1}}}
+\def\overrightarrow #1{\mathop{\Uoverdelimiter 0 "2192 {#1}}}
+
+% todo: \Udelimiterover, \Udelimiterunder
+
+\def\normaldoublebrace {\Umathaccents 0 0 "23DE 0 0 "23DF }
+\def\normaldoubleparent{\Umathaccents 0 0 "23DC 0 0 "23DD }
+
+\let\normaloverbrace \overbrace
+\let\normalunderbrace \underbrace
+\let\normaloverparent \overparent
+\let\normalunderparent \underparent
+\let\normalunderleftarrow \underleftarrow
+\let\normaloverleftarrow \overleftarrow
+\let\normalunderrightarrow\underrightarrow
+\let\normaloverrightarrow \overrightarrow
+
+\unexpanded\def\mathopwithlimits#1#2{\mathop{#1{#2}}\limits}
+\unexpanded\def\stackrel #1#2{\mathrel{\mathop{#2}\limits^{#1}}}
+
+\unexpanded\def\overbrace {\mathopwithlimits\normaloverbrace }
+\unexpanded\def\underbrace {\mathopwithlimits\normalunderbrace }
+\unexpanded\def\doublebrace {\mathopwithlimits\normaldoublebrace }
+\unexpanded\def\overparent {\mathopwithlimits\normaloverparent }
+\unexpanded\def\underparent {\mathopwithlimits\normalunderparent }
+\unexpanded\def\doubleparent {\mathopwithlimits\normaldoubleparent }
+\unexpanded\def\underleftarrow {\mathopwithlimits\normalunderleftarrow }
+\unexpanded\def\overleftarrow {\mathopwithlimits\normaloverleftarrow }
+\unexpanded\def\underrightarrow{\mathopwithlimits\normalunderrightarrow}
+\unexpanded\def\overrightarrow {\mathopwithlimits\normaloverrightarrow }
+
+\let\normalsurd\surd
+
+\unexpanded\def\surd{\normalsurd{}}
+
+% todo mathclass=punctuation ord
+
+% \Umathcode"02C="6 "0 "02C
+% \Umathcode"02E="0 "0 "02E
+
+% tricky .. todo
+
+% \appendtoks
+% \def\over{\primitive\over}%
+% \to \everymathematics
+
+\protect \endinput
diff --git a/tex/context/base/math-del.mkiv b/tex/context/base/math-del.mkiv
new file mode 100644
index 000000000..5ffda1919
--- /dev/null
+++ b/tex/context/base/math-del.mkiv
@@ -0,0 +1,63 @@
+%D \module
+%D [ file=math-del,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Delimiters,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Math Macros / Delimiters}
+
+\unprotect
+
+%D \macros
+%D {checkdelimiters, fakeleftdelimiter, fakerightdelimiter}
+%D
+%D Handy for non matching situations (as with mathml):
+%D
+%D \starttyping
+%D \checkdelimiters{... bla bla ...}
+%D \fakeleftdelimiter
+%D ... bla bla ...
+%D \fakerightdelimiter
+%D \stoptyping
+
+\newcount\delimitercount
+
+\def\leftfakedelimiter {\advance\delimitercount\minusone\gobbleoneargument}%
+\def\rightfakedelimiter{\advance\delimitercount\plusone \gobbleoneargument}%
+
+\def\checkdelimiters#1%
+ {\delimitercount\zerocount
+ \setbox\scratchbox\hbox\bgroup
+ \let\left \leftfakedelimiter
+ \let\right\rightfakedelimiter
+ $#1\expandafter$\expandafter
+ \egroup
+ \expandafter\delimitercount\the\delimitercount\relax}
+
+\def\fakeleftdelimiter {\ifnum\delimitercount>\zerocount\left .\fi}
+\def\fakerightdelimiter{\ifnum\delimitercount<\zerocount\right.\fi}
+
+%D The following macros are used in the MathML interpreter, so
+%D there is a good change of them never being documented for
+%D other usage.
+
+\let\normalordelimiter\secondoftwoarguments
+\let\normalorfiller \firstoftwoarguments
+
+\def\enabledelimiter {\let\normalordelimiter\secondoftwoarguments}
+\def\disabledelimiter{\let\normalordelimiter\firstoftwoarguments}
+
+\def\enablefiller {\let\normalorfiller\secondoftwoarguments}
+\def\disablefiller {\let\normalorfiller\firstoftwoarguments}
+
+\def\mathopnolimits#1{\mathop{\mr#1}\nolimits} % was \rm, which follows text fonts (used in mml parser)
+\def\mathopdolimits#1{\mathop{\mr#1}} % was \rm, which follows text fonts (used in mml parser)
+
+\protect \endinput
diff --git a/tex/context/base/math-dim.lua b/tex/context/base/math-dim.lua
new file mode 100644
index 000000000..62d805126
--- /dev/null
+++ b/tex/context/base/math-dim.lua
@@ -0,0 +1,313 @@
+if not modules then modules = { } end modules ['math-dim'] = {
+ version = 1.001,
+ comment = "companion to math-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Beware: only Taco really understands in depth what these dimensions do so
+-- if you run into problems ...
+
+local abs, next = math.abs, next
+
+mathematics = mathematics or { }
+
+local defaults = {
+ ['axis']={
+ ['default']={ "AxisHeight", "axis_height" },
+ },
+ ['accent_base_height']={
+ ['default']={ "AccentBaseHeight", "x_height" },
+ },
+ ['fraction_del_size']={
+ ['default']={ "FractionDelimiterSize", "delim2" },
+ ['cramped_display_style']={ "FractionDelimiterDisplayStyleSize", "delim1" },
+ ['display_style']={ "FractionDelimiterDisplayStyleSize", "delim1" },
+ },
+ ['fraction_denom_down']={
+ ['default']={ "FractionDenominatorShiftDown", "denom2" },
+ ['cramped_display_style']={ "FractionDenominatorDisplayStyleShiftDown", "denom1" },
+ ['display_style']={ "FractionDenominatorDisplayStyleShiftDown", "denom1" },
+ },
+ ['fraction_denom_vgap']={
+ ['default']={ "FractionDenominatorGapMin", "default_rule_thickness" },
+ ['cramped_display_style']={ "FractionDenominatorDisplayStyleGapMin", "3*default_rule_thickness" },
+ ['display_style']={ "FractionDenominatorDisplayStyleGapMin", "3*default_rule_thickness" },
+ },
+ ['fraction_num_up']={
+ ['default']={ "FractionNumeratorShiftUp", "num2" },
+ ['cramped_display_style']={ "FractionNumeratorDisplayStyleShiftUp", "num1" },
+ ['display_style']={ "FractionNumeratorDisplayStyleShiftUp", "num1" },
+ },
+ ['fraction_num_vgap']={
+ ['default']={ "FractionNumeratorGapMin", "default_rule_thickness" },
+ ['cramped_display_style']={ "FractionNumeratorDisplayStyleGapMin", "3*default_rule_thickness" },
+ ['display_style']={ "FractionNumeratorDisplayStyleGapMin", "3*default_rule_thickness" },
+ },
+ ['fraction_rule']={
+ ['default']={ "FractionRuleThickness", "default_rule_thickness" },
+ },
+ ['limit_above_bgap']={
+ ['default']={ "UpperLimitBaselineRiseMin", "big_op_spacing3" },
+ },
+ ['limit_above_kern']={
+ ['default']={ "0", "big_op_spacing5" },
+ },
+ ['limit_above_vgap']={
+ ['default']={ "UpperLimitGapMin", "big_op_spacing1" },
+ },
+ ['limit_below_bgap']={
+ ['default']={ "LowerLimitBaselineDropMin", "big_op_spacing4" },
+ },
+ ['limit_below_kern']={
+ ['default']={ "0", "big_op_spacing5" },
+ },
+ ['limit_below_vgap']={
+ ['default']={ "LowerLimitGapMin", "big_op_spacing2" },
+ },
+
+--~ ['....']={
+--~ ['default']={ "DisplayOperatorMinHeight", "....." },
+--~ },
+
+ ['overbar_kern']={
+ ['default']={ "OverbarExtraAscender", "default_rule_thickness" },
+ },
+ ['overbar_rule']={
+ ['default']={ "OverbarRuleThickness", "default_rule_thickness" },
+ },
+ ['overbar_vgap']={
+ ['default']={ "OverbarVerticalGap", "3*default_rule_thickness" },
+ },
+ ['quad']={
+ ['default']={ "font_size(f)", "math_quad" },
+ },
+ ['radical_kern']={
+ ['default']={ "RadicalExtraAscender", "default_rule_thickness" },
+ },
+ ['radical_rule']={
+ ['default']={ "RadicalRuleThickness", "" },
+ },
+ ['radical_vgap']={
+ ['default']={ "RadicalVerticalGap", "default_rule_thickness+(abs(default_rule_thickness)/4)" },
+ ['display_style']={ "RadicalDisplayStyleVerticalGap", "default_rule_thickness+(abs(math_x_height)/4)" },
+ },
+ ['space_after_script']={
+ ['default']={ "SpaceAfterScript", "script_space" },
+ },
+ ['stack_denom_down']={
+ ['default']={ "StackBottomShiftDown", "denom2" },
+ ['cramped_display_style']={ "StackBottomDisplayStyleShiftDown", "denom1" },
+ ['display_style']={ "StackBottomDisplayStyleShiftDown", "denom1" },
+ },
+ ['stack_num_up']={
+ ['default']={ "StackTopShiftUp", "num3" },
+ ['cramped_display_style']={ "StackTopDisplayStyleShiftUp", "num1" },
+ ['display_style']={ "StackTopDisplayStyleShiftUp", "num1" },
+ },
+ ['stack_vgap']={
+ ['default']={ "StackGapMin", "3*default_rule_thickness" },
+ ['cramped_display_style']={ "StackDisplayStyleGapMin", "7*default_rule_thickness" },
+ ['display_style']={ "StackDisplayStyleGapMin", "7*default_rule_thickness" },
+ },
+ ['sub_shift_down']={
+ ['default']={ "SubscriptShiftDown", "sub1" },
+ },
+ ['sub_shift_drop']={
+ ['default']={ "SubscriptBaselineDropMin", "sub_drop" },
+ },
+ ['sub_sup_shift_down']={
+ ['default']={ "SubscriptShiftDown", "sub2" }, -- todo
+ },
+ ['sub_top_max']={
+ ['default']={ "SubscriptTopMax", "abs(math_x_height*4)/5" },
+ },
+ ['subsup_vgap']={
+ ['default']={ "SubSuperscriptGapMin", "4*default_rule_thickness" },
+ },
+ ['sup_bottom_min']={
+ ['default']={ "SuperscriptBottomMin", "abs(math_x_height)/4" },
+ },
+ ['sup_shift_drop']={
+ ['default']={ "SuperscriptBaselineDropMax", "sup_drop" },
+ },
+ ['sup_shift_up']={
+ ['cramped_display_style']={ "SuperscriptShiftUpCramped", "sup3" },
+ ['cramped_script_script_style']={ "SuperscriptShiftUpCramped", "sup3" },
+ ['cramped_script_style']={ "SuperscriptShiftUpCramped", "sup3" },
+ ['cramped_text_style']={ "SuperscriptShiftUpCramped", "sup3" },
+ ['display_style']={ "SuperscriptShiftUp", "sup1" },
+ ['script_script_style']={ "SuperscriptShiftUp", "sup2" },
+ ['script_style']={ "SuperscriptShiftUp", "sup2" },
+ ['text_style']={ "SuperscriptShiftUp", "sup2" },
+ },
+ ['sup_sub_bottom_max']={
+ ['default']={ "SuperscriptBottomMaxWithSubscript", "abs(math_x_height*4)/5" },
+ },
+ ['underbar_kern']={
+ ['default']={ "UnderbarExtraDescender", "0" },
+ },
+ ['underbar_rule']={
+ ['default']={ "UnderbarRuleThickness", "default_rule_thickness" },
+ },
+ ['underbar_vgap']={
+ ['default']={ "UnderbarVerticalGap", "3*default_rule_thickness" },
+ },
+ ['connector_overlap_min']={
+ ['default']={ "MinConnectorOverlap", "0.25*default_rule_thickness" },
+ },
+ ['over_delimiter_vgap']={
+ ['default']={ "StretchStackGapBelowMin", "big_op_spacing1" },
+ },
+ ['over_delimiter_bgap']={
+ ['default']={ "StretchStackTopShiftUp", "big_op_spacing3" },
+ },
+ ['under_delimiter_vgap']={
+ ['default']={ "StretchStackGapAboveMin", "big_op_spacing2" },
+ },
+ ['under_delimiter_bgap']={
+ ['default']={ "StretchStackBottomShiftDown", "big_op_spacing4" },
+ },
+ ['radical_degree_before']={
+ ['default']={ "RadicalKernBeforeDegree", "(5/18)*quad" },
+ },
+ ['radical_degree_after']={
+ ['default']={ "RadicalKernAfterDegree", "(-10/18)*quad" },
+ },
+ ['radical_degree_raise']={
+ ['default']={ "RadicalDegreeBottomRaisePercent", "60" },
+ },
+}
+
+local styles = {
+ 'cramped_display_style',
+ 'cramped_script_script_style',
+ 'cramped_script_style',
+ 'cramped_text_style',
+ 'display_style',
+ 'script_script_style',
+ 'script_style',
+ 'text_style',
+}
+
+for k, v in next, defaults do
+ for _, s in next, styles do
+ if not v[s] then
+ v[s] = v.default
+ end
+ end
+end
+
+-- we cannot use a metatable because we do a copy (takes a bit more work)
+--
+-- local mt = { } setmetatable(defaults,mt)
+--
+-- mt.__index = function(t,s)
+-- return t.default or t.text_style or 0
+-- end
+
+function mathematics.dimensions(dimens)
+ if dimens.SpaceAfterScript then
+ dimens.SubscriptShiftDownWithSuperscript = dimens.SubscriptShiftDown * 1.5
+ return { }, table.fastcopy(dimens)
+ elseif dimens.AxisHeight or dimens.axis_height then
+ local t = { }
+ local math_x_height = dimens.x_height or 10*65526
+ local math_quad = dimens.quad or 10*65526
+ local default_rule_thickness = dimens.FractionDenominatorGapMin or dimens.default_rule_thickness or 0.4*65526
+ dimens["0"] = 0
+ dimens["60"] = 60
+ dimens["0.25*default_rule_thickness"] = default_rule_thickness / 4
+ dimens["3*default_rule_thickness"] = 3 * default_rule_thickness
+ dimens["4*default_rule_thickness"] = 4 * default_rule_thickness
+ dimens["7*default_rule_thickness"] = 7 * default_rule_thickness
+ dimens["(5/18)*quad"] = (math_quad * 5) / 18
+ dimens["(-10/18)*quad"] = - (math_quad * 10) / 18
+ dimens["abs(math_x_height*4)/5"] = abs(math_x_height * 4) / 5
+ dimens["default_rule_thickness+(abs(default_rule_thickness)/4)"] = default_rule_thickness+(abs(default_rule_thickness) / 4)
+ dimens["default_rule_thickness+(abs(math_x_height)/4)"] = default_rule_thickness+(abs(math_x_height) / 4)
+ dimens["abs(math_x_height)/4"] = abs(math_x_height) / 4
+ dimens["abs(math_x_height*4)/5"] = abs(math_x_height * 4) / 5
+ dimens[""] = false
+ dimens["script_space"] = false -- at macro level
+ for variable, styles in next, defaults do
+ local tt = { }
+ for style, default in next, styles do
+ local one, two = default[1], default[2]
+ local value = dimens[one]
+ if value then
+ tt[style] = value
+ else
+ value = dimens[two]
+ if value == false then
+ tt[style] = nil
+ else
+ tt[style] = value or 0
+ end
+ end
+ end
+ t[variable] = tt
+ end
+--~ logs.report("warning", "version 0.47 is needed for proper delimited math")
+ local d = {
+ AxisHeight = t . axis . text_style,
+ AccentBaseHeight = t . accent_base_height . text_style,
+ FractionDenominatorDisplayStyleGapMin = t . fraction_denom_vgap . display_style,
+ FractionDenominatorDisplayStyleShiftDown = t . fraction_denom_down . display_style,
+ FractionDenominatorGapMin = t . fraction_denom_vgap . text_style,
+ FractionDenominatorShiftDown = t . fraction_denom_down . text_style,
+ FractionNumeratorDisplayStyleGapMin = t . fraction_num_vgap . display_style,
+ FractionNumeratorDisplayStyleShiftUp = t . fraction_num_up . display_style,
+ FractionNumeratorGapMin = t . fraction_num_vgap . text_style,
+ FractionNumeratorShiftUp = t . fraction_num_up . text_style,
+ FractionRuleThickness = t . fraction_rule . text_style,
+ FractionDelimiterSize = t . fraction_del_size . text_style,
+ FractionDelimiterDisplayStyleSize = t . fraction_del_size . display_style,
+ LowerLimitBaselineDropMin = t . limit_below_bgap . text_style,
+ LowerLimitGapMin = t . limit_below_vgap . text_style,
+ OverbarExtraAscender = t . overbar_kern . text_style,
+ OverbarRuleThickness = t . overbar_rule . text_style,
+ OverbarVerticalGap = t . overbar_vgap . text_style,
+ RadicalDisplayStyleVerticalGap = t . radical_vgap . display_style,
+ RadicalExtraAscender = t . radical_kern . text_style,
+ RadicalRuleThickness = t . radical_rule . text_style,
+ RadicalVerticalGap = t . radical_vgap . text_style,
+ RadicalKernBeforeDegree = t . radical_degree_before . display_style,
+ RadicalKernAfterDegree = t . radical_degree_after . display_style,
+ RadicalDegreeBottomRaisePercent = t . radical_degree_raise . display_style,
+ SpaceAfterScript = t . space_after_script . text_style,
+ StackBottomDisplayStyleShiftDown = t . stack_denom_down . display_style,
+ StackBottomShiftDown = t . stack_denom_down . text_style,
+ StackDisplayStyleGapMin = t . stack_vgap . display_style,
+ StackGapMin = t . stack_vgap . text_style,
+ StackTopDisplayStyleShiftUp = t . stack_num_up . display_style,
+ StackTopShiftUp = t . stack_num_up . text_style,
+ SubscriptBaselineDropMin = t . sub_shift_drop . text_style,
+ SubscriptShiftDown = t . sub_shift_down . text_style,
+ SubscriptShiftDownWithSuperscript = t . sub_sup_shift_down . text_style,
+ SubscriptTopMax = t . sub_top_max . text_style,
+ SubSuperscriptGapMin = t . subsup_vgap . text_style,
+ SuperscriptBaselineDropMax = t . sup_shift_drop . text_style,
+ SuperscriptBottomMaxWithSubscript = t . sup_sub_bottom_max . text_style,
+ SuperscriptBottomMin = t . sup_bottom_min . text_style,
+ SuperscriptShiftUp = t . sup_shift_up . text_style,
+ SuperscriptShiftUpCramped = t . sup_shift_up . cramped_text_style,
+ UnderbarExtraDescender = t . underbar_kern . text_style,
+ UnderbarRuleThickness = t . underbar_rule . text_style,
+ UnderbarVerticalGap = t . underbar_vgap . text_style,
+ UpperLimitBaselineRiseMin = t . limit_above_bgap . text_style,
+ UpperLimitGapMin = t . limit_above_vgap . text_style,
+ MinConnectorOverlap = t . connector_overlap_min . text_style,
+ StretchStackGapBelowMin = t . over_delimiter_vgap . text_style,
+ StretchStackTopShiftUp = t . over_delimiter_bgap . text_style,
+ StretchStackGapAboveMin = t . under_delimiter_vgap . text_style,
+ StretchStackBottomShiftDown = t . under_delimiter_bgap . text_style,
+ }
+ d.AccentBaseHeight = 0
+ return t, d -- this might change
+ else
+ return { }, { }
+ end
+end
+
diff --git a/tex/context/base/math-dis.mkiv b/tex/context/base/math-dis.mkiv
new file mode 100644
index 000000000..3eed2b162
--- /dev/null
+++ b/tex/context/base/math-dis.mkiv
@@ -0,0 +1,20 @@
+%D \module
+%D [ file=math-ali,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Display,
+%D author={Hans Hagen, Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%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 Math Macros / Display}
+
+\unprotect
+
+% display spacing code will move here
+
+\protect \endinput
diff --git a/tex/context/base/math-ent.lua b/tex/context/base/math-ent.lua
new file mode 100644
index 000000000..e5e5b98f0
--- /dev/null
+++ b/tex/context/base/math-ent.lua
@@ -0,0 +1,2102 @@
+if not modules then modules = { } end modules ['math-ent'] = {
+ version = 1.001,
+ comment = "companion to math-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "derived from the mathml 2.0 specification",
+}
+
+mathematics.entities={
+ ["Aacute"]=0x000C1,
+ ["aacute"]=0x000E1,
+ ["Abreve"]=0x00102,
+ ["abreve"]=0x00103,
+ ["ac"]=0x0223E,
+ ["acd"]=0x0223F,
+ ["acE"]=0x0223E,
+ ["Acirc"]=0x000C2,
+ ["acirc"]=0x000E2,
+ ["acute"]=0x000B4,
+ ["Acy"]=0x00410,
+ ["acy"]=0x00430,
+ ["AElig"]=0x000C6,
+ ["aelig"]=0x000E6,
+ ["af"]=0x02061,
+ ["Afr"]=0x1D504,
+ ["afr"]=0x1D51E,
+ ["Agrave"]=0x000C0,
+ ["agrave"]=0x000E0,
+ ["aleph"]=0x02135,
+ ["alpha"]=0x003B1,
+ ["Amacr"]=0x00100,
+ ["amacr"]=0x00101,
+ ["amalg"]=0x02A3F,
+ ["amp"]=0x00026,
+ ["And"]=0x02A53,
+ ["and"]=0x02227,
+ ["andand"]=0x02A55,
+ ["andd"]=0x02A5C,
+ ["andslope"]=0x02A58,
+ ["andv"]=0x02A5A,
+ ["ang"]=0x02220,
+ ["ange"]=0x029A4,
+ ["angle"]=0x02220,
+ ["angmsd"]=0x02221,
+ ["angmsdaa"]=0x029A8,
+ ["angmsdab"]=0x029A9,
+ ["angmsdac"]=0x029AA,
+ ["angmsdad"]=0x029AB,
+ ["angmsdae"]=0x029AC,
+ ["angmsdaf"]=0x029AD,
+ ["angmsdag"]=0x029AE,
+ ["angmsdah"]=0x029AF,
+ ["angrt"]=0x0221F,
+ ["angrtvb"]=0x022BE,
+ ["angrtvbd"]=0x0299D,
+ ["angsph"]=0x02222,
+ ["angst"]=0x0212B,
+ ["angzarr"]=0x0237C,
+ ["Aogon"]=0x00104,
+ ["aogon"]=0x00105,
+ ["Aopf"]=0x1D538,
+ ["aopf"]=0x1D552,
+ ["ap"]=0x02248,
+ ["apacir"]=0x02A6F,
+ ["apE"]=0x02A70,
+ ["ape"]=0x0224A,
+ ["apid"]=0x0224B,
+ ["apos"]=0x00027,
+ ["ApplyFunction"]=0x02061,
+ ["approx"]=0x02248,
+ ["approxeq"]=0x0224A,
+ ["Aring"]=0x000C5,
+ ["aring"]=0x000E5,
+ ["Ascr"]=0x1D49C,
+ ["ascr"]=0x1D4B6,
+ ["Assign"]=0x02254,
+ ["ast"]=0x0002A,
+ ["asymp"]=0x02248,
+ ["asympeq"]=0x0224D,
+ ["Atilde"]=0x000C3,
+ ["atilde"]=0x000E3,
+ ["Auml"]=0x000C4,
+ ["auml"]=0x000E4,
+ ["awconint"]=0x02233,
+ ["awint"]=0x02A11,
+ ["backcong"]=0x0224C,
+ ["backepsilon"]=0x003F6,
+ ["backprime"]=0x02035,
+ ["backsim"]=0x0223D,
+ ["backsimeq"]=0x022CD,
+ ["Backslash"]=0x02216,
+ ["Barv"]=0x02AE7,
+ ["barvee"]=0x022BD,
+ ["Barwed"]=0x02306,
+ ["barwed"]=0x02305,
+ ["barwedge"]=0x02305,
+ ["bbrk"]=0x023B5,
+ ["bbrktbrk"]=0x023B6,
+ ["bcong"]=0x0224C,
+ ["Bcy"]=0x00411,
+ ["bcy"]=0x00431,
+ ["becaus"]=0x02235,
+ ["Because"]=0x02235,
+ ["because"]=0x02235,
+ ["bemptyv"]=0x029B0,
+ ["bepsi"]=0x003F6,
+ ["bernou"]=0x0212C,
+ ["Bernoullis"]=0x0212C,
+ ["beta"]=0x003B2,
+ ["beth"]=0x02136,
+ ["between"]=0x0226C,
+ ["Bfr"]=0x1D505,
+ ["bfr"]=0x1D51F,
+ ["bigcap"]=0x022C2,
+ ["bigcirc"]=0x025EF,
+ ["bigcup"]=0x022C3,
+ ["bigodot"]=0x02A00,
+ ["bigoplus"]=0x02A01,
+ ["bigotimes"]=0x02A02,
+ ["bigsqcup"]=0x02A06,
+ ["bigstar"]=0x02605,
+ ["bigtriangledown"]=0x025BD,
+ ["bigtriangleup"]=0x025B3,
+ ["biguplus"]=0x02A04,
+ ["bigvee"]=0x022C1,
+ ["bigwedge"]=0x022C0,
+ ["bkarow"]=0x0290D,
+ ["blacklozenge"]=0x029EB,
+ ["blacksquare"]=0x025AA,
+ ["blacktriangle"]=0x025B4,
+ ["blacktriangledown"]=0x025BE,
+ ["blacktriangleleft"]=0x025C2,
+ ["blacktriangleright"]=0x025B8,
+ ["blank"]=0x02423,
+ ["blk12"]=0x02592,
+ ["blk14"]=0x02591,
+ ["blk34"]=0x02593,
+ ["block"]=0x02588,
+ ["bne"]=0x0003D,
+ ["bnequiv"]=0x02261,
+ ["bNot"]=0x02AED,
+ ["bnot"]=0x02310,
+ ["Bopf"]=0x1D539,
+ ["bopf"]=0x1D553,
+ ["bot"]=0x022A5,
+ ["bottom"]=0x022A5,
+ ["bowtie"]=0x022C8,
+ ["boxbox"]=0x029C9,
+ ["boxDL"]=0x02557,
+ ["boxDl"]=0x02556,
+ ["boxdL"]=0x02555,
+ ["boxdl"]=0x02510,
+ ["boxDR"]=0x02554,
+ ["boxDr"]=0x02553,
+ ["boxdR"]=0x02552,
+ ["boxdr"]=0x0250C,
+ ["boxH"]=0x02550,
+ ["boxh"]=0x02500,
+ ["boxHD"]=0x02566,
+ ["boxHd"]=0x02564,
+ ["boxhD"]=0x02565,
+ ["boxhd"]=0x0252C,
+ ["boxHU"]=0x02569,
+ ["boxHu"]=0x02567,
+ ["boxhU"]=0x02568,
+ ["boxhu"]=0x02534,
+ ["boxminus"]=0x0229F,
+ ["boxplus"]=0x0229E,
+ ["boxtimes"]=0x022A0,
+ ["boxUL"]=0x0255D,
+ ["boxUl"]=0x0255C,
+ ["boxuL"]=0x0255B,
+ ["boxul"]=0x02518,
+ ["boxUR"]=0x0255A,
+ ["boxUr"]=0x02559,
+ ["boxuR"]=0x02558,
+ ["boxur"]=0x02514,
+ ["boxV"]=0x02551,
+ ["boxv"]=0x02502,
+ ["boxVH"]=0x0256C,
+ ["boxVh"]=0x0256B,
+ ["boxvH"]=0x0256A,
+ ["boxvh"]=0x0253C,
+ ["boxVL"]=0x02563,
+ ["boxVl"]=0x02562,
+ ["boxvL"]=0x02561,
+ ["boxvl"]=0x02524,
+ ["boxVR"]=0x02560,
+ ["boxVr"]=0x0255F,
+ ["boxvR"]=0x0255E,
+ ["boxvr"]=0x0251C,
+ ["bprime"]=0x02035,
+ ["Breve"]=0x002D8,
+ ["breve"]=0x002D8,
+ ["brvbar"]=0x000A6,
+ ["Bscr"]=0x0212C,
+ ["bscr"]=0x1D4B7,
+ ["bsemi"]=0x0204F,
+ ["bsim"]=0x0223D,
+ ["bsime"]=0x022CD,
+ ["bsol"]=0x0005C,
+ ["bsolb"]=0x029C5,
+ ["bsolhsub"]=0x0005C,
+ ["bull"]=0x02022,
+ ["bullet"]=0x02022,
+ ["bump"]=0x0224E,
+ ["bumpE"]=0x02AAE,
+ ["bumpe"]=0x0224F,
+ ["Bumpeq"]=0x0224E,
+ ["bumpeq"]=0x0224F,
+ ["Cacute"]=0x00106,
+ ["cacute"]=0x00107,
+ ["Cap"]=0x022D2,
+ ["cap"]=0x02229,
+ ["capand"]=0x02A44,
+ ["capbrcup"]=0x02A49,
+ ["capcap"]=0x02A4B,
+ ["capcup"]=0x02A47,
+ ["capdot"]=0x02A40,
+ ["CapitalDifferentialD"]=0x02145,
+ ["caps"]=0x02229,
+ ["caret"]=0x02041,
+ ["caron"]=0x002C7,
+ ["Cayleys"]=0x0212D,
+ ["ccaps"]=0x02A4D,
+ ["Ccaron"]=0x0010C,
+ ["ccaron"]=0x0010D,
+ ["Ccedil"]=0x000C7,
+ ["ccedil"]=0x000E7,
+ ["Ccirc"]=0x00108,
+ ["ccirc"]=0x00109,
+ ["Cconint"]=0x02230,
+ ["ccups"]=0x02A4C,
+ ["ccupssm"]=0x02A50,
+ ["Cdot"]=0x0010A,
+ ["cdot"]=0x0010B,
+ ["cedil"]=0x000B8,
+ ["Cedilla"]=0x000B8,
+ ["cemptyv"]=0x029B2,
+ ["cent"]=0x000A2,
+ ["CenterDot"]=0x000B7,
+ ["centerdot"]=0x000B7,
+ ["Cfr"]=0x0212D,
+ ["cfr"]=0x1D520,
+ ["CHcy"]=0x00427,
+ ["chcy"]=0x00447,
+ ["check"]=0x02713,
+ ["checkmark"]=0x02713,
+ ["chi"]=0x003C7,
+ ["cir"]=0x025CB,
+ ["circ"]=0x002C6,
+ ["circeq"]=0x02257,
+ ["circlearrowleft"]=0x021BA,
+ ["circlearrowright"]=0x021BB,
+ ["circledast"]=0x0229B,
+ ["circledcirc"]=0x0229A,
+ ["circleddash"]=0x0229D,
+ ["CircleDot"]=0x02299,
+ ["circledR"]=0x000AE,
+ ["circledS"]=0x024C8,
+ ["CircleMinus"]=0x02296,
+ ["CirclePlus"]=0x02295,
+ ["CircleTimes"]=0x02297,
+ ["cirE"]=0x029C3,
+ ["cire"]=0x02257,
+ ["cirfnint"]=0x02A10,
+ ["cirmid"]=0x02AEF,
+ ["cirscir"]=0x029C2,
+ ["ClockwiseContourIntegral"]=0x02232,
+ ["CloseCurlyDoubleQuote"]=0x0201D,
+ ["CloseCurlyQuote"]=0x02019,
+ ["clubs"]=0x02663,
+ ["clubsuit"]=0x02663,
+ ["Colon"]=0x02237,
+ ["colon"]=0x0003A,
+ ["Colone"]=0x02A74,
+ ["colone"]=0x02254,
+ ["coloneq"]=0x02254,
+ ["comma"]=0x0002C,
+ ["commat"]=0x00040,
+ ["comp"]=0x02201,
+ ["compfn"]=0x02218,
+ ["complement"]=0x02201,
+ ["complexes"]=0x02102,
+ ["cong"]=0x02245,
+ ["congdot"]=0x02A6D,
+ ["Congruent"]=0x02261,
+ ["Conint"]=0x0222F,
+ ["conint"]=0x0222E,
+ ["ContourIntegral"]=0x0222E,
+ ["Copf"]=0x02102,
+ ["copf"]=0x1D554,
+ ["coprod"]=0x02210,
+ ["Coproduct"]=0x02210,
+ ["copy"]=0x000A9,
+ ["copysr"]=0x02117,
+ ["CounterClockwiseContourIntegral"]=0x02233,
+ ["Cross"]=0x02A2F,
+ ["cross"]=0x02717,
+ ["Cscr"]=0x1D49E,
+ ["cscr"]=0x1D4B8,
+ ["csub"]=0x02ACF,
+ ["csube"]=0x02AD1,
+ ["csup"]=0x02AD0,
+ ["csupe"]=0x02AD2,
+ ["ctdot"]=0x022EF,
+ ["cudarrl"]=0x02938,
+ ["cudarrr"]=0x02935,
+ ["cuepr"]=0x022DE,
+ ["cuesc"]=0x022DF,
+ ["cularr"]=0x021B6,
+ ["cularrp"]=0x0293D,
+ ["Cup"]=0x022D3,
+ ["cup"]=0x0222A,
+ ["cupbrcap"]=0x02A48,
+ ["CupCap"]=0x0224D,
+ ["cupcap"]=0x02A46,
+ ["cupcup"]=0x02A4A,
+ ["cupdot"]=0x0228D,
+ ["cupor"]=0x02A45,
+ ["cups"]=0x0222A,
+ ["curarr"]=0x021B7,
+ ["curarrm"]=0x0293C,
+ ["curlyeqprec"]=0x022DE,
+ ["curlyeqsucc"]=0x022DF,
+ ["curlyvee"]=0x022CE,
+ ["curlywedge"]=0x022CF,
+ ["curren"]=0x000A4,
+ ["curvearrowleft"]=0x021B6,
+ ["curvearrowright"]=0x021B7,
+ ["cuvee"]=0x022CE,
+ ["cuwed"]=0x022CF,
+ ["cwconint"]=0x02232,
+ ["cwint"]=0x02231,
+ ["cylcty"]=0x0232D,
+ ["Dagger"]=0x02021,
+ ["Dagger"]=0x02021,
+ ["dagger"]=0x02020,
+ ["dagger"]=0x02020,
+ ["daleth"]=0x02138,
+ ["Darr"]=0x021A1,
+ ["dArr"]=0x021D3,
+ ["darr"]=0x02193,
+ ["dash"]=0x02010,
+ ["Dashv"]=0x02AE4,
+ ["dashv"]=0x022A3,
+ ["dbkarow"]=0x0290F,
+ ["dblac"]=0x002DD,
+ ["Dcaron"]=0x0010E,
+ ["dcaron"]=0x0010F,
+ ["Dcy"]=0x00414,
+ ["dcy"]=0x00434,
+ ["DD"]=0x02145,
+ ["dd"]=0x02146,
+ ["ddagger"]=0x02021,
+ ["ddarr"]=0x021CA,
+ ["DDotrahd"]=0x02911,
+ ["ddotseq"]=0x02A77,
+ ["deg"]=0x000B0,
+ ["Del"]=0x02207,
+ ["Delta"]=0x00394,
+ ["delta"]=0x003B4,
+ ["demptyv"]=0x029B1,
+ ["dfisht"]=0x0297F,
+ ["Dfr"]=0x1D507,
+ ["dfr"]=0x1D521,
+ ["dHar"]=0x02965,
+ ["dharl"]=0x021C3,
+ ["dharr"]=0x021C2,
+ ["DiacriticalAcute"]=0x000B4,
+ ["DiacriticalDot"]=0x002D9,
+ ["DiacriticalDoubleAcute"]=0x002DD,
+ ["DiacriticalGrave"]=0x00060,
+ ["DiacriticalTilde"]=0x002DC,
+ ["diam"]=0x022C4,
+ ["Diamond"]=0x022C4,
+ ["diamond"]=0x022C4,
+ ["diamondsuit"]=0x02666,
+ ["diams"]=0x02666,
+ ["die"]=0x000A8,
+ ["DifferentialD"]=0x02146,
+ ["digamma"]=0x003DD,
+ ["disin"]=0x022F2,
+ ["div"]=0x000F7,
+ ["divide"]=0x000F7,
+ ["divideontimes"]=0x022C7,
+ ["divonx"]=0x022C7,
+ ["DJcy"]=0x00402,
+ ["djcy"]=0x00452,
+ ["dlcorn"]=0x0231E,
+ ["dlcrop"]=0x0230D,
+ ["dollar"]=0x00024,
+ ["Dopf"]=0x1D53B,
+ ["dopf"]=0x1D555,
+ ["Dot"]=0x000A8,
+ ["dot"]=0x002D9,
+ ["DotDot"]=0x020DC,
+ ["doteq"]=0x02250,
+ ["doteqdot"]=0x02251,
+ ["DotEqual"]=0x02250,
+ ["dotminus"]=0x02238,
+ ["dotplus"]=0x02214,
+ ["dotsquare"]=0x022A1,
+ ["doublebarwedge"]=0x02306,
+ ["DoubleContourIntegral"]=0x0222F,
+ ["DoubleDot"]=0x000A8,
+ ["DoubleDownArrow"]=0x021D3,
+ ["DoubleLeftArrow"]=0x021D0,
+ ["DoubleLeftRightArrow"]=0x021D4,
+ ["DoubleLeftTee"]=0x02AE4,
+ ["DoubleLongLeftArrow"]=0x027F8,
+ ["DoubleLongLeftRightArrow"]=0x027FA,
+ ["DoubleLongRightArrow"]=0x027F9,
+ ["DoubleRightArrow"]=0x021D2,
+ ["DoubleRightTee"]=0x022A8,
+ ["DoubleUpArrow"]=0x021D1,
+ ["DoubleUpDownArrow"]=0x021D5,
+ ["DoubleVerticalBar"]=0x02225,
+ ["DownArrow"]=0x02193,
+ ["Downarrow"]=0x021D3,
+ ["downarrow"]=0x02193,
+ ["DownArrowBar"]=0x02913,
+ ["DownArrowUpArrow"]=0x021F5,
+ ["DownBreve"]=0x00311,
+ ["downdownarrows"]=0x021CA,
+ ["downharpoonleft"]=0x021C3,
+ ["downharpoonright"]=0x021C2,
+ ["DownLeftRightVector"]=0x02950,
+ ["DownLeftTeeVector"]=0x0295E,
+ ["DownLeftVector"]=0x021BD,
+ ["DownLeftVectorBar"]=0x02956,
+ ["DownRightTeeVector"]=0x0295F,
+ ["DownRightVector"]=0x021C1,
+ ["DownRightVectorBar"]=0x02957,
+ ["DownTee"]=0x022A4,
+ ["DownTeeArrow"]=0x021A7,
+ ["drbkarow"]=0x02910,
+ ["drcorn"]=0x0231F,
+ ["drcrop"]=0x0230C,
+ ["Dscr"]=0x1D49F,
+ ["dscr"]=0x1D4B9,
+ ["DScy"]=0x00405,
+ ["dscy"]=0x00455,
+ ["dsol"]=0x029F6,
+ ["Dstrok"]=0x00110,
+ ["dstrok"]=0x00111,
+ ["dtdot"]=0x022F1,
+ ["dtri"]=0x025BF,
+ ["dtrif"]=0x025BE,
+ ["duarr"]=0x021F5,
+ ["duhar"]=0x0296F,
+ ["dwangle"]=0x029A6,
+ ["DZcy"]=0x0040F,
+ ["dzcy"]=0x0045F,
+ ["dzigrarr"]=0x027FF,
+ ["Eacute"]=0x000C9,
+ ["eacute"]=0x000E9,
+ ["easter"]=0x02A6E,
+ ["Ecaron"]=0x0011A,
+ ["ecaron"]=0x0011B,
+ ["ecir"]=0x02256,
+ ["Ecirc"]=0x000CA,
+ ["ecirc"]=0x000EA,
+ ["ecolon"]=0x02255,
+ ["Ecy"]=0x0042D,
+ ["ecy"]=0x0044D,
+ ["eDDot"]=0x02A77,
+ ["Edot"]=0x00116,
+ ["eDot"]=0x02251,
+ ["edot"]=0x00117,
+ ["ee"]=0x02147,
+ ["efDot"]=0x02252,
+ ["Efr"]=0x1D508,
+ ["efr"]=0x1D522,
+ ["eg"]=0x02A9A,
+ ["Egrave"]=0x000C8,
+ ["egrave"]=0x000E8,
+ ["egs"]=0x02A96,
+ ["egsdot"]=0x02A98,
+ ["el"]=0x02A99,
+ ["Element"]=0x02208,
+ ["elinters"]=0x0FFFD,
+ ["ell"]=0x02113,
+ ["els"]=0x02A95,
+ ["elsdot"]=0x02A97,
+ ["Emacr"]=0x00112,
+ ["emacr"]=0x00113,
+ ["empty"]=0x02205,
+ ["emptyset"]=0x02205,
+ ["EmptySmallSquare"]=0x025FB,
+ ["emptyv"]=0x02205,
+ ["EmptyVerySmallSquare"]=0x025AB,
+ ["emsp"]=0x02003,
+ ["emsp13"]=0x02004,
+ ["emsp14"]=0x02005,
+ ["ENG"]=0x0014A,
+ ["eng"]=0x0014B,
+ ["ensp"]=0x02002,
+ ["Eogon"]=0x00118,
+ ["eogon"]=0x00119,
+ ["Eopf"]=0x1D53C,
+ ["eopf"]=0x1D556,
+ ["epar"]=0x022D5,
+ ["eparsl"]=0x029E3,
+ ["eplus"]=0x02A71,
+ ["epsi"]=0x003F5,
+ ["epsiv"]=0x003B5,
+ ["eqcirc"]=0x02256,
+ ["eqcolon"]=0x02255,
+ ["eqsim"]=0x02242,
+ ["eqslantgtr"]=0x02A96,
+ ["eqslantless"]=0x02A95,
+ ["Equal"]=0x02A75,
+ ["equals"]=0x0003D,
+ ["EqualTilde"]=0x02242,
+ ["equest"]=0x0225F,
+ ["Equilibrium"]=0x021CC,
+ ["equiv"]=0x02261,
+ ["equivDD"]=0x02A78,
+ ["eqvparsl"]=0x029E5,
+ ["erarr"]=0x02971,
+ ["erDot"]=0x02253,
+ ["Escr"]=0x02130,
+ ["escr"]=0x0212F,
+ ["esdot"]=0x02250,
+ ["Esim"]=0x02A73,
+ ["esim"]=0x02242,
+ ["eta"]=0x003B7,
+ ["ETH"]=0x000D0,
+ ["eth"]=0x000F0,
+ ["Euml"]=0x000CB,
+ ["euml"]=0x000EB,
+ ["excl"]=0x00021,
+ ["exist"]=0x02203,
+ ["Exists"]=0x02203,
+ ["expectation"]=0x02130,
+ ["ExponentialE"]=0x02147,
+ ["exponentiale"]=0x02147,
+ ["fallingdotseq"]=0x02252,
+ ["Fcy"]=0x00424,
+ ["fcy"]=0x00444,
+ ["female"]=0x02640,
+ ["ffilig"]=0x0FB03,
+ ["fflig"]=0x0FB00,
+ ["ffllig"]=0x0FB04,
+ ["Ffr"]=0x1D509,
+ ["ffr"]=0x1D523,
+ ["filig"]=0x0FB01,
+ ["FilledSmallSquare"]=0x025FC,
+ ["FilledVerySmallSquare"]=0x025AA,
+ ["flat"]=0x0266D,
+ ["fllig"]=0x0FB02,
+ ["fltns"]=0x025B1,
+ ["fnof"]=0x00192,
+ ["Fopf"]=0x1D53D,
+ ["fopf"]=0x1D557,
+ ["ForAll"]=0x02200,
+ ["forall"]=0x02200,
+ ["fork"]=0x022D4,
+ ["forkv"]=0x02AD9,
+ ["Fouriertrf"]=0x02131,
+ ["fpartint"]=0x02A0D,
+ ["frac12"]=0x000BD,
+ ["frac13"]=0x02153,
+ ["frac14"]=0x000BC,
+ ["frac15"]=0x02155,
+ ["frac16"]=0x02159,
+ ["frac18"]=0x0215B,
+ ["frac23"]=0x02154,
+ ["frac25"]=0x02156,
+ ["frac34"]=0x000BE,
+ ["frac35"]=0x02157,
+ ["frac38"]=0x0215C,
+ ["frac45"]=0x02158,
+ ["frac56"]=0x0215A,
+ ["frac58"]=0x0215D,
+ ["frac78"]=0x0215E,
+ ["frown"]=0x02322,
+ ["Fscr"]=0x02131,
+ ["fscr"]=0x1D4BB,
+ ["gacute"]=0x001F5,
+ ["Gamma"]=0x00393,
+ ["gamma"]=0x003B3,
+ ["Gammad"]=0x003DC,
+ ["gammad"]=0x003DD,
+ ["gap"]=0x02A86,
+ ["Gbreve"]=0x0011E,
+ ["gbreve"]=0x0011F,
+ ["Gcedil"]=0x00122,
+ ["Gcirc"]=0x0011C,
+ ["gcirc"]=0x0011D,
+ ["Gcy"]=0x00413,
+ ["gcy"]=0x00433,
+ ["Gdot"]=0x00120,
+ ["gdot"]=0x00121,
+ ["gE"]=0x02267,
+ ["ge"]=0x02265,
+ ["gEl"]=0x02A8C,
+ ["gel"]=0x022DB,
+ ["geq"]=0x02265,
+ ["geqq"]=0x02267,
+ ["geqslant"]=0x02A7E,
+ ["ges"]=0x02A7E,
+ ["gescc"]=0x02AA9,
+ ["gesdot"]=0x02A80,
+ ["gesdoto"]=0x02A82,
+ ["gesdotol"]=0x02A84,
+ ["gesl"]=0x022DB,
+ ["gesles"]=0x02A94,
+ ["Gfr"]=0x1D50A,
+ ["gfr"]=0x1D524,
+ ["Gg"]=0x022D9,
+ ["gg"]=0x0226B,
+ ["ggg"]=0x022D9,
+ ["gimel"]=0x02137,
+ ["GJcy"]=0x00403,
+ ["gjcy"]=0x00453,
+ ["gl"]=0x02277,
+ ["gla"]=0x02AA5,
+ ["glE"]=0x02A92,
+ ["glj"]=0x02AA4,
+ ["gnap"]=0x02A8A,
+ ["gnapprox"]=0x02A8A,
+ ["gnE"]=0x02269,
+ ["gne"]=0x02A88,
+ ["gneq"]=0x02A88,
+ ["gneqq"]=0x02269,
+ ["gnsim"]=0x022E7,
+ ["Gopf"]=0x1D53E,
+ ["gopf"]=0x1D558,
+ ["grave"]=0x00060,
+ ["GreaterEqual"]=0x02265,
+ ["GreaterEqualLess"]=0x022DB,
+ ["GreaterFullEqual"]=0x02267,
+ ["GreaterGreater"]=0x02AA2,
+ ["GreaterLess"]=0x02277,
+ ["GreaterSlantEqual"]=0x02A7E,
+ ["GreaterTilde"]=0x02273,
+ ["Gscr"]=0x1D4A2,
+ ["gscr"]=0x0210A,
+ ["gsim"]=0x02273,
+ ["gsime"]=0x02A8E,
+ ["gsiml"]=0x02A90,
+ ["Gt"]=0x0226B,
+ ["gt"]=0x0003E,
+ ["gtcc"]=0x02AA7,
+ ["gtcir"]=0x02A7A,
+ ["gtdot"]=0x022D7,
+ ["gtlPar"]=0x02995,
+ ["gtquest"]=0x02A7C,
+ ["gtrapprox"]=0x02A86,
+ ["gtrarr"]=0x02978,
+ ["gtrdot"]=0x022D7,
+ ["gtreqless"]=0x022DB,
+ ["gtreqqless"]=0x02A8C,
+ ["gtrless"]=0x02277,
+ ["gtrsim"]=0x02273,
+ ["gvertneqq"]=0x02269,
+ ["gvnE"]=0x02269,
+ ["Hacek"]=0x002C7,
+ ["hairsp"]=0x0200A,
+ ["half"]=0x000BD,
+ ["hamilt"]=0x0210B,
+ ["HARDcy"]=0x0042A,
+ ["hardcy"]=0x0044A,
+ ["hArr"]=0x021D4,
+ ["harr"]=0x02194,
+ ["harrcir"]=0x02948,
+ ["harrw"]=0x021AD,
+ ["Hat"]=0x0005E,
+ ["hbar"]=0x0210F,
+ ["Hcirc"]=0x00124,
+ ["hcirc"]=0x00125,
+ ["hearts"]=0x02665,
+ ["heartsuit"]=0x02665,
+ ["hellip"]=0x02026,
+ ["hercon"]=0x022B9,
+ ["Hfr"]=0x0210C,
+ ["hfr"]=0x1D525,
+ ["HilbertSpace"]=0x0210B,
+ ["hksearow"]=0x02925,
+ ["hkswarow"]=0x02926,
+ ["hoarr"]=0x021FF,
+ ["homtht"]=0x0223B,
+ ["hookleftarrow"]=0x021A9,
+ ["hookrightarrow"]=0x021AA,
+ ["Hopf"]=0x0210D,
+ ["hopf"]=0x1D559,
+ ["horbar"]=0x02015,
+ ["HorizontalLine"]=0x02500,
+ ["Hscr"]=0x0210B,
+ ["hscr"]=0x1D4BD,
+ ["hslash"]=0x0210F,
+ ["Hstrok"]=0x00126,
+ ["hstrok"]=0x00127,
+ ["HumpDownHump"]=0x0224E,
+ ["HumpEqual"]=0x0224F,
+ ["hybull"]=0x02043,
+ ["hyphen"]=0x02010,
+ ["Iacute"]=0x000CD,
+ ["iacute"]=0x000ED,
+ ["ic"]=0x02063,
+ ["Icirc"]=0x000CE,
+ ["icirc"]=0x000EE,
+ ["Icy"]=0x00418,
+ ["icy"]=0x00438,
+ ["Idot"]=0x00130,
+ ["IEcy"]=0x00415,
+ ["iecy"]=0x00435,
+ ["iexcl"]=0x000A1,
+ ["iff"]=0x021D4,
+ ["Ifr"]=0x02111,
+ ["ifr"]=0x1D526,
+ ["Igrave"]=0x000CC,
+ ["igrave"]=0x000EC,
+ ["ii"]=0x02148,
+ ["iiiint"]=0x02A0C,
+ ["iiint"]=0x0222D,
+ ["iinfin"]=0x029DC,
+ ["iiota"]=0x02129,
+ ["IJlig"]=0x00132,
+ ["ijlig"]=0x00133,
+ ["Im"]=0x02111,
+ ["Imacr"]=0x0012A,
+ ["imacr"]=0x0012B,
+ ["image"]=0x02111,
+ ["ImaginaryI"]=0x02148,
+ ["imagline"]=0x02110,
+ ["imagpart"]=0x02111,
+ ["imath"]=0x00131,
+ ["imof"]=0x022B7,
+ ["imped"]=0x001B5,
+ ["Implies"]=0x021D2,
+ ["in"]=0x02208,
+ ["incare"]=0x02105,
+ ["infin"]=0x0221E,
+ ["infintie"]=0x029DD,
+ ["inodot"]=0x00131,
+ ["Int"]=0x0222C,
+ ["int"]=0x0222B,
+ ["intcal"]=0x022BA,
+ ["integers"]=0x02124,
+ ["Integral"]=0x0222B,
+ ["intercal"]=0x022BA,
+ ["Intersection"]=0x022C2,
+ ["intlarhk"]=0x02A17,
+ ["intprod"]=0x02A3C,
+ ["InvisibleComma"]=0x02063,
+ ["InvisibleTimes"]=0x02062,
+ ["IOcy"]=0x00401,
+ ["iocy"]=0x00451,
+ ["Iogon"]=0x0012E,
+ ["iogon"]=0x0012F,
+ ["Iopf"]=0x1D540,
+ ["iopf"]=0x1D55A,
+ ["iota"]=0x003B9,
+ ["iprod"]=0x02A3C,
+ ["iquest"]=0x000BF,
+ ["Iscr"]=0x02110,
+ ["iscr"]=0x1D4BE,
+ ["isin"]=0x02208,
+ ["isindot"]=0x022F5,
+ ["isinE"]=0x022F9,
+ ["isins"]=0x022F4,
+ ["isinsv"]=0x022F3,
+ ["isinv"]=0x02208,
+ ["it"]=0x02062,
+ ["Itilde"]=0x00128,
+ ["itilde"]=0x00129,
+ ["Iukcy"]=0x00406,
+ ["iukcy"]=0x00456,
+ ["Iuml"]=0x000CF,
+ ["iuml"]=0x000EF,
+ ["Jcirc"]=0x00134,
+ ["jcirc"]=0x00135,
+ ["Jcy"]=0x00419,
+ ["jcy"]=0x00439,
+ ["Jfr"]=0x1D50D,
+ ["jfr"]=0x1D527,
+ ["jmath"]=0x0006A,
+ ["Jopf"]=0x1D541,
+ ["jopf"]=0x1D55B,
+ ["Jscr"]=0x1D4A5,
+ ["jscr"]=0x1D4BF,
+ ["Jsercy"]=0x00408,
+ ["jsercy"]=0x00458,
+ ["Jukcy"]=0x00404,
+ ["jukcy"]=0x00454,
+ ["kappa"]=0x003BA,
+ ["kappav"]=0x003F0,
+ ["Kcedil"]=0x00136,
+ ["kcedil"]=0x00137,
+ ["Kcy"]=0x0041A,
+ ["kcy"]=0x0043A,
+ ["Kfr"]=0x1D50E,
+ ["kfr"]=0x1D528,
+ ["kgreen"]=0x00138,
+ ["KHcy"]=0x00425,
+ ["khcy"]=0x00445,
+ ["KJcy"]=0x0040C,
+ ["kjcy"]=0x0045C,
+ ["Kopf"]=0x1D542,
+ ["kopf"]=0x1D55C,
+ ["Kscr"]=0x1D4A6,
+ ["kscr"]=0x1D4C0,
+ ["lAarr"]=0x021DA,
+ ["Lacute"]=0x00139,
+ ["lacute"]=0x0013A,
+ ["laemptyv"]=0x029B4,
+ ["lagran"]=0x02112,
+ ["Lambda"]=0x0039B,
+ ["lambda"]=0x003BB,
+ ["Lang"]=0x0300A,
+ ["lang"]=0x02329,
+ ["langd"]=0x02991,
+ ["langle"]=0x02329,
+ ["lap"]=0x02A85,
+ ["Laplacetrf"]=0x02112,
+ ["laquo"]=0x000AB,
+ ["Larr"]=0x0219E,
+ ["lArr"]=0x021D0,
+ ["larr"]=0x02190,
+ ["larrb"]=0x021E4,
+ ["larrbfs"]=0x0291F,
+ ["larrfs"]=0x0291D,
+ ["larrhk"]=0x021A9,
+ ["larrlp"]=0x021AB,
+ ["larrpl"]=0x02939,
+ ["larrsim"]=0x02973,
+ ["larrtl"]=0x021A2,
+ ["lat"]=0x02AAB,
+ ["lAtail"]=0x0291B,
+ ["latail"]=0x02919,
+ ["late"]=0x02AAD,
+ ["lates"]=0x02AAD,
+ ["lBarr"]=0x0290E,
+ ["lbarr"]=0x0290C,
+ ["lbbrk"]=0x03014,
+ ["lbrace"]=0x0007B,
+ ["lbrack"]=0x0005B,
+ ["lbrke"]=0x0298B,
+ ["lbrksld"]=0x0298F,
+ ["lbrkslu"]=0x0298D,
+ ["Lcaron"]=0x0013D,
+ ["lcaron"]=0x0013E,
+ ["Lcedil"]=0x0013B,
+ ["lcedil"]=0x0013C,
+ ["lceil"]=0x02308,
+ ["lcub"]=0x0007B,
+ ["Lcy"]=0x0041B,
+ ["lcy"]=0x0043B,
+ ["ldca"]=0x02936,
+ ["ldquo"]=0x0201C,
+ ["ldquor"]=0x0201E,
+ ["ldrdhar"]=0x02967,
+ ["ldrushar"]=0x0294B,
+ ["ldsh"]=0x021B2,
+ ["lE"]=0x02266,
+ ["le"]=0x02264,
+ ["LeftAngleBracket"]=0x02329,
+ ["LeftArrow"]=0x02190,
+ ["Leftarrow"]=0x021D0,
+ ["leftarrow"]=0x02190,
+ ["LeftArrowBar"]=0x021E4,
+ ["LeftArrowRightArrow"]=0x021C6,
+ ["leftarrowtail"]=0x021A2,
+ ["LeftCeiling"]=0x02308,
+ ["LeftDoubleBracket"]=0x0301A,
+ ["LeftDownTeeVector"]=0x02961,
+ ["LeftDownVector"]=0x021C3,
+ ["LeftDownVectorBar"]=0x02959,
+ ["LeftFloor"]=0x0230A,
+ ["leftharpoondown"]=0x021BD,
+ ["leftharpoonup"]=0x021BC,
+ ["leftleftarrows"]=0x021C7,
+ ["LeftRightArrow"]=0x02194,
+ ["Leftrightarrow"]=0x021D4,
+ ["leftrightarrow"]=0x02194,
+ ["leftrightarrows"]=0x021C6,
+ ["leftrightharpoons"]=0x021CB,
+ ["leftrightsquigarrow"]=0x021AD,
+ ["LeftRightVector"]=0x0294E,
+ ["LeftTee"]=0x022A3,
+ ["LeftTeeArrow"]=0x021A4,
+ ["LeftTeeVector"]=0x0295A,
+ ["leftthreetimes"]=0x022CB,
+ ["LeftTriangle"]=0x022B2,
+ ["LeftTriangleBar"]=0x029CF,
+ ["LeftTriangleEqual"]=0x022B4,
+ ["LeftUpDownVector"]=0x02951,
+ ["LeftUpTeeVector"]=0x02960,
+ ["LeftUpVector"]=0x021BF,
+ ["LeftUpVectorBar"]=0x02958,
+ ["LeftVector"]=0x021BC,
+ ["LeftVectorBar"]=0x02952,
+ ["lEg"]=0x02A8B,
+ ["leg"]=0x022DA,
+ ["leq"]=0x02264,
+ ["leqq"]=0x02266,
+ ["leqslant"]=0x02A7D,
+ ["les"]=0x02A7D,
+ ["lescc"]=0x02AA8,
+ ["lesdot"]=0x02A7F,
+ ["lesdoto"]=0x02A81,
+ ["lesdotor"]=0x02A83,
+ ["lesg"]=0x022DA,
+ ["lesges"]=0x02A93,
+ ["lessapprox"]=0x02A85,
+ ["lessdot"]=0x022D6,
+ ["lesseqgtr"]=0x022DA,
+ ["lesseqqgtr"]=0x02A8B,
+ ["LessEqualGreater"]=0x022DA,
+ ["LessFullEqual"]=0x02266,
+ ["LessGreater"]=0x02276,
+ ["lessgtr"]=0x02276,
+ ["LessLess"]=0x02AA1,
+ ["lesssim"]=0x02272,
+ ["LessSlantEqual"]=0x02A7D,
+ ["LessTilde"]=0x02272,
+ ["lfisht"]=0x0297C,
+ ["lfloor"]=0x0230A,
+ ["Lfr"]=0x1D50F,
+ ["lfr"]=0x1D529,
+ ["lg"]=0x02276,
+ ["lgE"]=0x02A91,
+ ["lHar"]=0x02962,
+ ["lhard"]=0x021BD,
+ ["lharu"]=0x021BC,
+ ["lharul"]=0x0296A,
+ ["lhblk"]=0x02584,
+ ["LJcy"]=0x00409,
+ ["ljcy"]=0x00459,
+ ["Ll"]=0x022D8,
+ ["ll"]=0x0226A,
+ ["llarr"]=0x021C7,
+ ["llcorner"]=0x0231E,
+ ["Lleftarrow"]=0x021DA,
+ ["llhard"]=0x0296B,
+ ["lltri"]=0x025FA,
+ ["Lmidot"]=0x0013F,
+ ["lmidot"]=0x00140,
+ ["lmoust"]=0x023B0,
+ ["lmoustache"]=0x023B0,
+ ["lnap"]=0x02A89,
+ ["lnapprox"]=0x02A89,
+ ["lnE"]=0x02268,
+ ["lne"]=0x02A87,
+ ["lneq"]=0x02A87,
+ ["lneqq"]=0x02268,
+ ["lnsim"]=0x022E6,
+ ["loang"]=0x03018,
+ ["loarr"]=0x021FD,
+ ["lobrk"]=0x0301A,
+ ["LongLeftArrow"]=0x027F5,
+ ["Longleftarrow"]=0x027F8,
+ ["longleftarrow"]=0x027F5,
+ ["LongLeftRightArrow"]=0x027F7,
+ ["Longleftrightarrow"]=0x027FA,
+ ["longleftrightarrow"]=0x027F7,
+ ["longmapsto"]=0x027FC,
+ ["LongRightArrow"]=0x027F6,
+ ["Longrightarrow"]=0x027F9,
+ ["longrightarrow"]=0x027F6,
+ ["looparrowleft"]=0x021AB,
+ ["looparrowright"]=0x021AC,
+ ["lopar"]=0x02985,
+ ["Lopf"]=0x1D543,
+ ["lopf"]=0x1D55D,
+ ["loplus"]=0x02A2D,
+ ["lotimes"]=0x02A34,
+ ["lowast"]=0x02217,
+ ["lowbar"]=0x0005F,
+ ["LowerLeftArrow"]=0x02199,
+ ["LowerRightArrow"]=0x02198,
+ ["loz"]=0x025CA,
+ ["lozenge"]=0x025CA,
+ ["lozf"]=0x029EB,
+ ["lpar"]=0x00028,
+ ["lparlt"]=0x02993,
+ ["lrarr"]=0x021C6,
+ ["lrcorner"]=0x0231F,
+ ["lrhar"]=0x021CB,
+ ["lrhard"]=0x0296D,
+ ["lrtri"]=0x022BF,
+ ["Lscr"]=0x02112,
+ ["lscr"]=0x1D4C1,
+ ["Lsh"]=0x021B0,
+ ["lsh"]=0x021B0,
+ ["lsim"]=0x02272,
+ ["lsime"]=0x02A8D,
+ ["lsimg"]=0x02A8F,
+ ["lsqb"]=0x0005B,
+ ["lsquo"]=0x02018,
+ ["lsquor"]=0x0201A,
+ ["Lstrok"]=0x00141,
+ ["lstrok"]=0x00142,
+ ["Lt"]=0x0226A,
+ ["lt"]=0x0003C,
+ ["ltcc"]=0x02AA6,
+ ["ltcir"]=0x02A79,
+ ["ltdot"]=0x022D6,
+ ["lthree"]=0x022CB,
+ ["ltimes"]=0x022C9,
+ ["ltlarr"]=0x02976,
+ ["ltquest"]=0x02A7B,
+ ["ltri"]=0x025C3,
+ ["ltrie"]=0x022B4,
+ ["ltrif"]=0x025C2,
+ ["ltrPar"]=0x02996,
+ ["lurdshar"]=0x0294A,
+ ["luruhar"]=0x02966,
+ ["lvertneqq"]=0x02268,
+ ["lvnE"]=0x02268,
+ ["macr"]=0x000AF,
+ ["male"]=0x02642,
+ ["malt"]=0x02720,
+ ["maltese"]=0x02720,
+ ["Map"]=0x02905,
+ ["map"]=0x021A6,
+ ["mapsto"]=0x021A6,
+ ["mapstodown"]=0x021A7,
+ ["mapstoleft"]=0x021A4,
+ ["mapstoup"]=0x021A5,
+ ["marker"]=0x025AE,
+ ["mcomma"]=0x02A29,
+ ["Mcy"]=0x0041C,
+ ["mcy"]=0x0043C,
+ ["mdash"]=0x02014,
+ ["mDDot"]=0x0223A,
+ ["measuredangle"]=0x02221,
+ ["MediumSpace"]=0x0205F,
+ ["Mellintrf"]=0x02133,
+ ["Mfr"]=0x1D510,
+ ["mfr"]=0x1D52A,
+ ["mho"]=0x02127,
+ ["micro"]=0x000B5,
+ ["mid"]=0x02223,
+ ["midast"]=0x0002A,
+ ["midcir"]=0x02AF0,
+ ["middot"]=0x000B7,
+ ["minus"]=0x02212,
+ ["minusb"]=0x0229F,
+ ["minusd"]=0x02238,
+ ["minusdu"]=0x02A2A,
+ ["MinusPlus"]=0x02213,
+ ["mlcp"]=0x02ADB,
+ ["mldr"]=0x02026,
+ ["mnplus"]=0x02213,
+ ["models"]=0x022A7,
+ ["Mopf"]=0x1D544,
+ ["mopf"]=0x1D55E,
+ ["mp"]=0x02213,
+ ["Mscr"]=0x02133,
+ ["mscr"]=0x1D4C2,
+ ["mstpos"]=0x0223E,
+ ["mu"]=0x003BC,
+ ["multimap"]=0x022B8,
+ ["mumap"]=0x022B8,
+ ["nabla"]=0x02207,
+ ["Nacute"]=0x00143,
+ ["nacute"]=0x00144,
+ ["nang"]=0x02220,
+ ["nap"]=0x02249,
+ ["napE"]=0x02A70,
+ ["napid"]=0x0224B,
+ ["napos"]=0x00149,
+ ["napprox"]=0x02249,
+ ["natur"]=0x0266E,
+ ["natural"]=0x0266E,
+ ["naturals"]=0x02115,
+ ["nbsp"]=0x000A0,
+ ["nbump"]=0x0224E,
+ ["nbumpe"]=0x0224F,
+ ["ncap"]=0x02A43,
+ ["Ncaron"]=0x00147,
+ ["ncaron"]=0x00148,
+ ["Ncedil"]=0x00145,
+ ["ncedil"]=0x00146,
+ ["ncong"]=0x02247,
+ ["ncongdot"]=0x02A6D,
+ ["ncup"]=0x02A42,
+ ["Ncy"]=0x0041D,
+ ["ncy"]=0x0043D,
+ ["ndash"]=0x02013,
+ ["ne"]=0x02260,
+ ["nearhk"]=0x02924,
+ ["neArr"]=0x021D7,
+ ["nearr"]=0x02197,
+ ["nearrow"]=0x02197,
+ ["nedot"]=0x02250,
+ ["NegativeMediumSpace"]=0x0200B,
+ ["NegativeThickSpace"]=0x0200B,
+ ["NegativeThinSpace"]=0x0200B,
+ ["NegativeVeryThinSpace"]=0x0200B,
+ ["nequiv"]=0x02262,
+ ["nesear"]=0x02928,
+ ["nesim"]=0x02242,
+ ["NestedGreaterGreater"]=0x0226B,
+ ["NestedLessLess"]=0x0226A,
+ ["NewLine"]=0x0000A,
+ ["nexist"]=0x02204,
+ ["nexists"]=0x02204,
+ ["Nfr"]=0x1D511,
+ ["nfr"]=0x1D52B,
+ ["ngE"]=0x02267,
+ ["nge"]=0x02271,
+ ["ngeq"]=0x02271,
+ ["ngeqq"]=0x02267,
+ ["ngeqslant"]=0x02A7E,
+ ["nges"]=0x02A7E,
+ ["nGg"]=0x022D9,
+ ["ngsim"]=0x02275,
+ ["nGt"]=0x0226B,
+ ["ngt"]=0x0226F,
+ ["ngtr"]=0x0226F,
+ ["nGtv"]=0x0226B,
+ ["nhArr"]=0x021CE,
+ ["nharr"]=0x021AE,
+ ["nhpar"]=0x02AF2,
+ ["ni"]=0x0220B,
+ ["nis"]=0x022FC,
+ ["nisd"]=0x022FA,
+ ["niv"]=0x0220B,
+ ["NJcy"]=0x0040A,
+ ["njcy"]=0x0045A,
+ ["nlArr"]=0x021CD,
+ ["nlarr"]=0x0219A,
+ ["nldr"]=0x02025,
+ ["nlE"]=0x02266,
+ ["nle"]=0x02270,
+ ["nLeftarrow"]=0x021CD,
+ ["nleftarrow"]=0x0219A,
+ ["nLeftrightarrow"]=0x021CE,
+ ["nleftrightarrow"]=0x021AE,
+ ["nleq"]=0x02270,
+ ["nleqq"]=0x02266,
+ ["nleqslant"]=0x02A7D,
+ ["nles"]=0x02A7D,
+ ["nless"]=0x0226E,
+ ["nLl"]=0x022D8,
+ ["nlsim"]=0x02274,
+ ["nLt"]=0x0226A,
+ ["nlt"]=0x0226E,
+ ["nltri"]=0x022EA,
+ ["nltrie"]=0x022EC,
+ ["nLtv"]=0x0226A,
+ ["nmid"]=0x02224,
+ ["NoBreak"]=0x02060,
+ ["NonBreakingSpace"]=0x000A0,
+ ["Nopf"]=0x02115,
+ ["nopf"]=0x1D55F,
+ ["Not"]=0x02AEC,
+ ["not"]=0x000AC,
+ ["NotCongruent"]=0x02262,
+ ["NotCupCap"]=0x0226D,
+ ["NotDoubleVerticalBar"]=0x02226,
+ ["NotElement"]=0x02209,
+ ["NotEqual"]=0x02260,
+ ["NotEqualTilde"]=0x02242,
+ ["NotExists"]=0x02204,
+ ["NotGreater"]=0x0226F,
+ ["NotGreaterEqual"]=0x02271,
+ ["NotGreaterFullEqual"]=0x02266,
+ ["NotGreaterGreater"]=0x0226B,
+ ["NotGreaterLess"]=0x02279,
+ ["NotGreaterSlantEqual"]=0x02A7E,
+ ["NotGreaterTilde"]=0x02275,
+ ["NotHumpDownHump"]=0x0224E,
+ ["NotHumpEqual"]=0x0224F,
+ ["notin"]=0x02209,
+ ["notindot"]=0x022F5,
+ ["notinE"]=0x022F9,
+ ["notinva"]=0x02209,
+ ["notinvb"]=0x022F7,
+ ["notinvc"]=0x022F6,
+ ["NotLeftTriangle"]=0x022EA,
+ ["NotLeftTriangleBar"]=0x029CF,
+ ["NotLeftTriangleEqual"]=0x022EC,
+ ["NotLess"]=0x0226E,
+ ["NotLessEqual"]=0x02270,
+ ["NotLessGreater"]=0x02278,
+ ["NotLessLess"]=0x0226A,
+ ["NotLessSlantEqual"]=0x02A7D,
+ ["NotLessTilde"]=0x02274,
+ ["NotNestedGreaterGreater"]=0x02AA2,
+ ["NotNestedLessLess"]=0x02AA1,
+ ["notni"]=0x0220C,
+ ["notniva"]=0x0220C,
+ ["notnivb"]=0x022FE,
+ ["notnivc"]=0x022FD,
+ ["NotPrecedes"]=0x02280,
+ ["NotPrecedesEqual"]=0x02AAF,
+ ["NotPrecedesSlantEqual"]=0x022E0,
+ ["NotReverseElement"]=0x0220C,
+ ["NotRightTriangle"]=0x022EB,
+ ["NotRightTriangleBar"]=0x029D0,
+ ["NotRightTriangleEqual"]=0x022ED,
+ ["NotSquareSubset"]=0x0228F,
+ ["NotSquareSubsetEqual"]=0x022E2,
+ ["NotSquareSuperset"]=0x02290,
+ ["NotSquareSupersetEqual"]=0x022E3,
+ ["NotSubset"]=0x02282,
+ ["NotSubsetEqual"]=0x02288,
+ ["NotSucceeds"]=0x02281,
+ ["NotSucceedsEqual"]=0x02AB0,
+ ["NotSucceedsSlantEqual"]=0x022E1,
+ ["NotSucceedsTilde"]=0x0227F,
+ ["NotSuperset"]=0x02283,
+ ["NotSupersetEqual"]=0x02289,
+ ["NotTilde"]=0x02241,
+ ["NotTildeEqual"]=0x02244,
+ ["NotTildeFullEqual"]=0x02247,
+ ["NotTildeTilde"]=0x02249,
+ ["NotVerticalBar"]=0x02224,
+ ["npar"]=0x02226,
+ ["nparallel"]=0x02226,
+ ["nparsl"]=0x02AFD,
+ ["npart"]=0x02202,
+ ["npolint"]=0x02A14,
+ ["npr"]=0x02280,
+ ["nprcue"]=0x022E0,
+ ["npre"]=0x02AAF,
+ ["nprec"]=0x02280,
+ ["npreceq"]=0x02AAF,
+ ["nrArr"]=0x021CF,
+ ["nrarr"]=0x0219B,
+ ["nrarrc"]=0x02933,
+ ["nrarrw"]=0x0219D,
+ ["nRightarrow"]=0x021CF,
+ ["nrightarrow"]=0x0219B,
+ ["nrtri"]=0x022EB,
+ ["nrtrie"]=0x022ED,
+ ["nsc"]=0x02281,
+ ["nsccue"]=0x022E1,
+ ["nsce"]=0x02AB0,
+ ["Nscr"]=0x1D4A9,
+ ["nscr"]=0x1D4C3,
+ ["nshortmid"]=0x02224,
+ ["nshortparallel"]=0x02226,
+ ["nsim"]=0x02241,
+ ["nsime"]=0x02244,
+ ["nsimeq"]=0x02244,
+ ["nsmid"]=0x02224,
+ ["nspar"]=0x02226,
+ ["nsqsube"]=0x022E2,
+ ["nsqsupe"]=0x022E3,
+ ["nsub"]=0x02284,
+ ["nsubE"]=0x02AC5,
+ ["nsube"]=0x02288,
+ ["nsubset"]=0x02282,
+ ["nsubseteq"]=0x02288,
+ ["nsubseteqq"]=0x02AC5,
+ ["nsucc"]=0x02281,
+ ["nsucceq"]=0x02AB0,
+ ["nsup"]=0x02285,
+ ["nsupE"]=0x02AC6,
+ ["nsupe"]=0x02289,
+ ["nsupset"]=0x02283,
+ ["nsupseteq"]=0x02289,
+ ["nsupseteqq"]=0x02AC6,
+ ["ntgl"]=0x02279,
+ ["Ntilde"]=0x000D1,
+ ["ntilde"]=0x000F1,
+ ["ntlg"]=0x02278,
+ ["ntriangleleft"]=0x022EA,
+ ["ntrianglelefteq"]=0x022EC,
+ ["ntriangleright"]=0x022EB,
+ ["ntrianglerighteq"]=0x022ED,
+ ["nu"]=0x003BD,
+ ["num"]=0x00023,
+ ["numero"]=0x02116,
+ ["numsp"]=0x02007,
+ ["nvap"]=0x0224D,
+ ["nVDash"]=0x022AF,
+ ["nVdash"]=0x022AE,
+ ["nvDash"]=0x022AD,
+ ["nvdash"]=0x022AC,
+ ["nvge"]=0x02265,
+ ["nvgt"]=0x0003E,
+ ["nvHarr"]=0x02904,
+ ["nvinfin"]=0x029DE,
+ ["nvlArr"]=0x02902,
+ ["nvle"]=0x02264,
+ ["nvlt"]=0x0003C,
+ ["nvltrie"]=0x022B4,
+ ["nvrArr"]=0x02903,
+ ["nvrtrie"]=0x022B5,
+ ["nvsim"]=0x0223C,
+ ["nwarhk"]=0x02923,
+ ["nwArr"]=0x021D6,
+ ["nwarr"]=0x02196,
+ ["nwarrow"]=0x02196,
+ ["nwnear"]=0x02927,
+ ["Oacute"]=0x000D3,
+ ["oacute"]=0x000F3,
+ ["oast"]=0x0229B,
+ ["ocir"]=0x0229A,
+ ["Ocirc"]=0x000D4,
+ ["ocirc"]=0x000F4,
+ ["Ocy"]=0x0041E,
+ ["ocy"]=0x0043E,
+ ["odash"]=0x0229D,
+ ["Odblac"]=0x00150,
+ ["odblac"]=0x00151,
+ ["odiv"]=0x02A38,
+ ["odot"]=0x02299,
+ ["odsold"]=0x029BC,
+ ["OElig"]=0x00152,
+ ["oelig"]=0x00153,
+ ["ofcir"]=0x029BF,
+ ["Ofr"]=0x1D512,
+ ["ofr"]=0x1D52C,
+ ["ogon"]=0x002DB,
+ ["Ograve"]=0x000D2,
+ ["ograve"]=0x000F2,
+ ["ogt"]=0x029C1,
+ ["ohbar"]=0x029B5,
+ ["ohm"]=0x02126,
+ ["oint"]=0x0222E,
+ ["olarr"]=0x021BA,
+ ["olcir"]=0x029BE,
+ ["olcross"]=0x029BB,
+ ["olt"]=0x029C0,
+ ["Omacr"]=0x0014C,
+ ["omacr"]=0x0014D,
+ ["Omega"]=0x003A9,
+ ["omega"]=0x003C9,
+ ["omid"]=0x029B6,
+ ["ominus"]=0x02296,
+ ["Oopf"]=0x1D546,
+ ["oopf"]=0x1D560,
+ ["opar"]=0x029B7,
+ ["OpenCurlyDoubleQuote"]=0x0201C,
+ ["OpenCurlyQuote"]=0x02018,
+ ["operp"]=0x029B9,
+ ["oplus"]=0x02295,
+ ["Or"]=0x02A54,
+ ["or"]=0x02228,
+ ["orarr"]=0x021BB,
+ ["ord"]=0x02A5D,
+ ["order"]=0x02134,
+ ["orderof"]=0x02134,
+ ["ordf"]=0x000AA,
+ ["ordm"]=0x000BA,
+ ["origof"]=0x022B6,
+ ["oror"]=0x02A56,
+ ["orslope"]=0x02A57,
+ ["orv"]=0x02A5B,
+ ["oS"]=0x024C8,
+ ["Oscr"]=0x1D4AA,
+ ["oscr"]=0x02134,
+ ["Oslash"]=0x000D8,
+ ["oslash"]=0x000F8,
+ ["osol"]=0x02298,
+ ["Otilde"]=0x000D5,
+ ["otilde"]=0x000F5,
+ ["Otimes"]=0x02A37,
+ ["otimes"]=0x02297,
+ ["otimesas"]=0x02A36,
+ ["Ouml"]=0x000D6,
+ ["ouml"]=0x000F6,
+ ["ovbar"]=0x0233D,
+ ["OverBar"]=0x000AF,
+ ["OverBrace"]=0x0FE37,
+ ["OverBracket"]=0x023B4,
+ ["OverParenthesis"]=0x0FE35,
+ ["par"]=0x02225,
+ ["para"]=0x000B6,
+ ["parallel"]=0x02225,
+ ["parsim"]=0x02AF3,
+ ["parsl"]=0x02AFD,
+ ["part"]=0x02202,
+ ["PartialD"]=0x02202,
+ ["Pcy"]=0x0041F,
+ ["pcy"]=0x0043F,
+ ["percnt"]=0x00025,
+ ["period"]=0x0002E,
+ ["permil"]=0x02030,
+ ["perp"]=0x022A5,
+ ["pertenk"]=0x02031,
+ ["Pfr"]=0x1D513,
+ ["pfr"]=0x1D52D,
+ ["Phi"]=0x003A6,
+ ["phi"]=0x003D5,
+ ["phiv"]=0x003C6,
+ ["phmmat"]=0x02133,
+ ["phone"]=0x0260E,
+ ["Pi"]=0x003A0,
+ ["pi"]=0x003C0,
+ ["pitchfork"]=0x022D4,
+ ["piv"]=0x003D6,
+ ["planck"]=0x0210F,
+ ["planckh"]=0x0210E,
+ ["plankv"]=0x0210F,
+ ["plus"]=0x0002B,
+ ["plusacir"]=0x02A23,
+ ["plusb"]=0x0229E,
+ ["pluscir"]=0x02A22,
+ ["plusdo"]=0x02214,
+ ["plusdu"]=0x02A25,
+ ["pluse"]=0x02A72,
+ ["PlusMinus"]=0x000B1,
+ ["plusmn"]=0x000B1,
+ ["plussim"]=0x02A26,
+ ["plustwo"]=0x02A27,
+ ["pm"]=0x000B1,
+ ["Poincareplane"]=0x0210C,
+ ["pointint"]=0x02A15,
+ ["Popf"]=0x02119,
+ ["popf"]=0x1D561,
+ ["pound"]=0x000A3,
+ ["Pr"]=0x02ABB,
+ ["pr"]=0x0227A,
+ ["prap"]=0x02AB7,
+ ["prcue"]=0x0227C,
+ ["prE"]=0x02AB3,
+ ["pre"]=0x02AAF,
+ ["prec"]=0x0227A,
+ ["precapprox"]=0x02AB7,
+ ["preccurlyeq"]=0x0227C,
+ ["Precedes"]=0x0227A,
+ ["PrecedesEqual"]=0x02AAF,
+ ["PrecedesSlantEqual"]=0x0227C,
+ ["PrecedesTilde"]=0x0227E,
+ ["preceq"]=0x02AAF,
+ ["precnapprox"]=0x02AB9,
+ ["precneqq"]=0x02AB5,
+ ["precnsim"]=0x022E8,
+ ["precsim"]=0x0227E,
+ ["Prime"]=0x02033,
+ ["prime"]=0x02032,
+ ["primes"]=0x02119,
+ ["prnap"]=0x02AB9,
+ ["prnE"]=0x02AB5,
+ ["prnsim"]=0x022E8,
+ ["prod"]=0x0220F,
+ ["Product"]=0x0220F,
+ ["profalar"]=0x0232E,
+ ["profline"]=0x02312,
+ ["profsurf"]=0x02313,
+ ["prop"]=0x0221D,
+ ["Proportion"]=0x02237,
+ ["Proportional"]=0x0221D,
+ ["propto"]=0x0221D,
+ ["prsim"]=0x0227E,
+ ["prurel"]=0x022B0,
+ ["Pscr"]=0x1D4AB,
+ ["pscr"]=0x1D4C5,
+ ["Psi"]=0x003A8,
+ ["psi"]=0x003C8,
+ ["puncsp"]=0x02008,
+ ["Qfr"]=0x1D514,
+ ["qfr"]=0x1D52E,
+ ["qint"]=0x02A0C,
+ ["Qopf"]=0x0211A,
+ ["qopf"]=0x1D562,
+ ["qprime"]=0x02057,
+ ["Qscr"]=0x1D4AC,
+ ["qscr"]=0x1D4C6,
+ ["quaternions"]=0x0210D,
+ ["quatint"]=0x02A16,
+ ["quest"]=0x0003F,
+ ["questeq"]=0x0225F,
+ ["quot"]=0x00022,
+ ["rAarr"]=0x021DB,
+ ["race"]=0x029DA,
+ ["Racute"]=0x00154,
+ ["racute"]=0x00155,
+ ["radic"]=0x0221A,
+ ["raemptyv"]=0x029B3,
+ ["Rang"]=0x0300B,
+ ["rang"]=0x0232A,
+ ["rangd"]=0x02992,
+ ["range"]=0x029A5,
+ ["rangle"]=0x0232A,
+ ["raquo"]=0x000BB,
+ ["Rarr"]=0x021A0,
+ ["rArr"]=0x021D2,
+ ["rarr"]=0x02192,
+ ["rarrap"]=0x02975,
+ ["rarrb"]=0x021E5,
+ ["rarrbfs"]=0x02920,
+ ["rarrc"]=0x02933,
+ ["rarrfs"]=0x0291E,
+ ["rarrhk"]=0x021AA,
+ ["rarrlp"]=0x021AC,
+ ["rarrpl"]=0x02945,
+ ["rarrsim"]=0x02974,
+ ["Rarrtl"]=0x02916,
+ ["rarrtl"]=0x021A3,
+ ["rarrw"]=0x0219D,
+ ["rAtail"]=0x0291C,
+ ["ratail"]=0x0291A,
+ ["ratio"]=0x02236,
+ ["rationals"]=0x0211A,
+ ["RBarr"]=0x02910,
+ ["rBarr"]=0x0290F,
+ ["rbarr"]=0x0290D,
+ ["rbbrk"]=0x03015,
+ ["rbrace"]=0x0007D,
+ ["rbrack"]=0x0005D,
+ ["rbrke"]=0x0298C,
+ ["rbrksld"]=0x0298E,
+ ["rbrkslu"]=0x02990,
+ ["Rcaron"]=0x00158,
+ ["rcaron"]=0x00159,
+ ["Rcedil"]=0x00156,
+ ["rcedil"]=0x00157,
+ ["rceil"]=0x02309,
+ ["rcub"]=0x0007D,
+ ["Rcy"]=0x00420,
+ ["rcy"]=0x00440,
+ ["rdca"]=0x02937,
+ ["rdldhar"]=0x02969,
+ ["rdquo"]=0x0201D,
+ ["rdquor"]=0x0201D,
+ ["rdsh"]=0x021B3,
+ ["Re"]=0x0211C,
+ ["real"]=0x0211C,
+ ["realine"]=0x0211B,
+ ["realpart"]=0x0211C,
+ ["reals"]=0x0211D,
+ ["rect"]=0x025AD,
+ ["reg"]=0x000AE,
+ ["ReverseElement"]=0x0220B,
+ ["ReverseEquilibrium"]=0x021CB,
+ ["ReverseUpEquilibrium"]=0x0296F,
+ ["rfisht"]=0x0297D,
+ ["rfloor"]=0x0230B,
+ ["Rfr"]=0x0211C,
+ ["rfr"]=0x1D52F,
+ ["rHar"]=0x02964,
+ ["rhard"]=0x021C1,
+ ["rharu"]=0x021C0,
+ ["rharul"]=0x0296C,
+ ["rho"]=0x003C1,
+ ["rhov"]=0x003F1,
+ ["RightAngleBracket"]=0x0232A,
+ ["RightArrow"]=0x02192,
+ ["Rightarrow"]=0x021D2,
+ ["rightarrow"]=0x02192,
+ ["RightArrowBar"]=0x021E5,
+ ["RightArrowLeftArrow"]=0x021C4,
+ ["rightarrowtail"]=0x021A3,
+ ["RightCeiling"]=0x02309,
+ ["RightDoubleBracket"]=0x0301B,
+ ["RightDownTeeVector"]=0x0295D,
+ ["RightDownVector"]=0x021C2,
+ ["RightDownVectorBar"]=0x02955,
+ ["RightFloor"]=0x0230B,
+ ["rightharpoondown"]=0x021C1,
+ ["rightharpoonup"]=0x021C0,
+ ["rightleftarrows"]=0x021C4,
+ ["rightleftharpoons"]=0x021CC,
+ ["rightrightarrows"]=0x021C9,
+ ["rightsquigarrow"]=0x0219D,
+ ["RightTee"]=0x022A2,
+ ["RightTeeArrow"]=0x021A6,
+ ["RightTeeVector"]=0x0295B,
+ ["rightthreetimes"]=0x022CC,
+ ["RightTriangle"]=0x022B3,
+ ["RightTriangleBar"]=0x029D0,
+ ["RightTriangleEqual"]=0x022B5,
+ ["RightUpDownVector"]=0x0294F,
+ ["RightUpTeeVector"]=0x0295C,
+ ["RightUpVector"]=0x021BE,
+ ["RightUpVectorBar"]=0x02954,
+ ["RightVector"]=0x021C0,
+ ["RightVectorBar"]=0x02953,
+ ["ring"]=0x002DA,
+ ["risingdotseq"]=0x02253,
+ ["rlarr"]=0x021C4,
+ ["rlhar"]=0x021CC,
+ ["rmoust"]=0x023B1,
+ ["rmoustache"]=0x023B1,
+ ["rnmid"]=0x02AEE,
+ ["roang"]=0x03019,
+ ["roarr"]=0x021FE,
+ ["robrk"]=0x0301B,
+ ["ropar"]=0x02986,
+ ["Ropf"]=0x0211D,
+ ["ropf"]=0x1D563,
+ ["roplus"]=0x02A2E,
+ ["rotimes"]=0x02A35,
+ ["RoundImplies"]=0x02970,
+ ["rpar"]=0x00029,
+ ["rpargt"]=0x02994,
+ ["rppolint"]=0x02A12,
+ ["rrarr"]=0x021C9,
+ ["Rrightarrow"]=0x021DB,
+ ["Rscr"]=0x0211B,
+ ["rscr"]=0x1D4C7,
+ ["Rsh"]=0x021B1,
+ ["rsh"]=0x021B1,
+ ["rsqb"]=0x0005D,
+ ["rsquo"]=0x02019,
+ ["rsquor"]=0x02019,
+ ["rthree"]=0x022CC,
+ ["rtimes"]=0x022CA,
+ ["rtri"]=0x025B9,
+ ["rtrie"]=0x022B5,
+ ["rtrif"]=0x025B8,
+ ["rtriltri"]=0x029CE,
+ ["RuleDelayed"]=0x029F4,
+ ["ruluhar"]=0x02968,
+ ["rx"]=0x0211E,
+ ["Sacute"]=0x0015A,
+ ["sacute"]=0x0015B,
+ ["Sc"]=0x02ABC,
+ ["sc"]=0x0227B,
+ ["scap"]=0x02AB8,
+ ["Scaron"]=0x00160,
+ ["scaron"]=0x00161,
+ ["sccue"]=0x0227D,
+ ["scE"]=0x02AB4,
+ ["sce"]=0x02AB0,
+ ["Scedil"]=0x0015E,
+ ["scedil"]=0x0015F,
+ ["Scirc"]=0x0015C,
+ ["scirc"]=0x0015D,
+ ["scnap"]=0x02ABA,
+ ["scnE"]=0x02AB6,
+ ["scnsim"]=0x022E9,
+ ["scpolint"]=0x02A13,
+ ["scsim"]=0x0227F,
+ ["Scy"]=0x00421,
+ ["scy"]=0x00441,
+ ["sdot"]=0x022C5,
+ ["sdotb"]=0x022A1,
+ ["sdote"]=0x02A66,
+ ["searhk"]=0x02925,
+ ["seArr"]=0x021D8,
+ ["searr"]=0x02198,
+ ["searrow"]=0x02198,
+ ["sect"]=0x000A7,
+ ["semi"]=0x0003B,
+ ["seswar"]=0x02929,
+ ["setminus"]=0x02216,
+ ["setmn"]=0x02216,
+ ["sext"]=0x02736,
+ ["Sfr"]=0x1D516,
+ ["sfr"]=0x1D530,
+ ["sfrown"]=0x02322,
+ ["sharp"]=0x0266F,
+ ["SHCHcy"]=0x00429,
+ ["shchcy"]=0x00449,
+ ["SHcy"]=0x00428,
+ ["shcy"]=0x00448,
+ ["ShortDownArrow"]=0x02193,
+ ["ShortLeftArrow"]=0x02190,
+ ["shortmid"]=0x02223,
+ ["shortparallel"]=0x02225,
+ ["ShortRightArrow"]=0x02192,
+ ["ShortUpArrow"]=0x02191,
+ ["shy"]=0x000AD,
+ ["Sigma"]=0x003A3,
+ ["sigma"]=0x003C3,
+ ["sigmav"]=0x003C2,
+ ["sim"]=0x0223C,
+ ["simdot"]=0x02A6A,
+ ["sime"]=0x02243,
+ ["simeq"]=0x02243,
+ ["simg"]=0x02A9E,
+ ["simgE"]=0x02AA0,
+ ["siml"]=0x02A9D,
+ ["simlE"]=0x02A9F,
+ ["simne"]=0x02246,
+ ["simplus"]=0x02A24,
+ ["simrarr"]=0x02972,
+ ["slarr"]=0x02190,
+ ["SmallCircle"]=0x02218,
+ ["smallsetminus"]=0x02216,
+ ["smashp"]=0x02A33,
+ ["smeparsl"]=0x029E4,
+ ["smid"]=0x02223,
+ ["smile"]=0x02323,
+ ["smt"]=0x02AAA,
+ ["smte"]=0x02AAC,
+ ["smtes"]=0x02AAC,
+ ["SOFTcy"]=0x0042C,
+ ["softcy"]=0x0044C,
+ ["sol"]=0x0002F,
+ ["solb"]=0x029C4,
+ ["solbar"]=0x0233F,
+ ["Sopf"]=0x1D54A,
+ ["sopf"]=0x1D564,
+ ["spades"]=0x02660,
+ ["spadesuit"]=0x02660,
+ ["spar"]=0x02225,
+ ["sqcap"]=0x02293,
+ ["sqcaps"]=0x02293,
+ ["sqcup"]=0x02294,
+ ["sqcups"]=0x02294,
+ ["Sqrt"]=0x0221A,
+ ["sqsub"]=0x0228F,
+ ["sqsube"]=0x02291,
+ ["sqsubset"]=0x0228F,
+ ["sqsubseteq"]=0x02291,
+ ["sqsup"]=0x02290,
+ ["sqsupe"]=0x02292,
+ ["sqsupset"]=0x02290,
+ ["sqsupseteq"]=0x02292,
+ ["squ"]=0x025A1,
+ ["Square"]=0x025A1,
+ ["square"]=0x025A1,
+ ["SquareIntersection"]=0x02293,
+ ["SquareSubset"]=0x0228F,
+ ["SquareSubsetEqual"]=0x02291,
+ ["SquareSuperset"]=0x02290,
+ ["SquareSupersetEqual"]=0x02292,
+ ["SquareUnion"]=0x02294,
+ ["squarf"]=0x025AA,
+ ["squf"]=0x025AA,
+ ["srarr"]=0x02192,
+ ["Sscr"]=0x1D4AE,
+ ["sscr"]=0x1D4C8,
+ ["ssetmn"]=0x02216,
+ ["ssmile"]=0x02323,
+ ["sstarf"]=0x022C6,
+ ["Star"]=0x022C6,
+ ["star"]=0x02606,
+ ["starf"]=0x02605,
+ ["straightepsilon"]=0x003F5,
+ ["straightphi"]=0x003D5,
+ ["strns"]=0x000AF,
+ ["Sub"]=0x022D0,
+ ["sub"]=0x02282,
+ ["subdot"]=0x02ABD,
+ ["subE"]=0x02AC5,
+ ["sube"]=0x02286,
+ ["subedot"]=0x02AC3,
+ ["submult"]=0x02AC1,
+ ["subnE"]=0x02ACB,
+ ["subne"]=0x0228A,
+ ["subplus"]=0x02ABF,
+ ["subrarr"]=0x02979,
+ ["Subset"]=0x022D0,
+ ["subset"]=0x02282,
+ ["subseteq"]=0x02286,
+ ["subseteqq"]=0x02AC5,
+ ["SubsetEqual"]=0x02286,
+ ["subsetneq"]=0x0228A,
+ ["subsetneqq"]=0x02ACB,
+ ["subsim"]=0x02AC7,
+ ["subsub"]=0x02AD5,
+ ["subsup"]=0x02AD3,
+ ["succ"]=0x0227B,
+ ["succapprox"]=0x02AB8,
+ ["succcurlyeq"]=0x0227D,
+ ["Succeeds"]=0x0227B,
+ ["SucceedsEqual"]=0x02AB0,
+ ["SucceedsSlantEqual"]=0x0227D,
+ ["SucceedsTilde"]=0x0227F,
+ ["succeq"]=0x02AB0,
+ ["succnapprox"]=0x02ABA,
+ ["succneqq"]=0x02AB6,
+ ["succnsim"]=0x022E9,
+ ["succsim"]=0x0227F,
+ ["SuchThat"]=0x0220B,
+ ["Sum"]=0x02211,
+ ["sum"]=0x02211,
+ ["sung"]=0x0266A,
+ ["Sup"]=0x022D1,
+ ["sup"]=0x02283,
+ ["sup1"]=0x000B9,
+ ["sup2"]=0x000B2,
+ ["sup3"]=0x000B3,
+ ["supdot"]=0x02ABE,
+ ["supdsub"]=0x02AD8,
+ ["supE"]=0x02AC6,
+ ["supe"]=0x02287,
+ ["supedot"]=0x02AC4,
+ ["Superset"]=0x02283,
+ ["SupersetEqual"]=0x02287,
+ ["suphsol"]=0x02283,
+ ["suphsub"]=0x02AD7,
+ ["suplarr"]=0x0297B,
+ ["supmult"]=0x02AC2,
+ ["supnE"]=0x02ACC,
+ ["supne"]=0x0228B,
+ ["supplus"]=0x02AC0,
+ ["Supset"]=0x022D1,
+ ["supset"]=0x02283,
+ ["supseteq"]=0x02287,
+ ["supseteqq"]=0x02AC6,
+ ["supsetneq"]=0x0228B,
+ ["supsetneqq"]=0x02ACC,
+ ["supsim"]=0x02AC8,
+ ["supsub"]=0x02AD4,
+ ["supsup"]=0x02AD6,
+ ["swarhk"]=0x02926,
+ ["swArr"]=0x021D9,
+ ["swarr"]=0x02199,
+ ["swarrow"]=0x02199,
+ ["swnwar"]=0x0292A,
+ ["szlig"]=0x000DF,
+ ["Tab"]=0x00009,
+ ["target"]=0x02316,
+ ["tau"]=0x003C4,
+ ["tbrk"]=0x023B4,
+ ["Tcaron"]=0x00164,
+ ["tcaron"]=0x00165,
+ ["Tcedil"]=0x00162,
+ ["tcedil"]=0x00163,
+ ["Tcy"]=0x00422,
+ ["tcy"]=0x00442,
+ ["tdot"]=0x020DB,
+ ["telrec"]=0x02315,
+ ["Tfr"]=0x1D517,
+ ["tfr"]=0x1D531,
+ ["there4"]=0x02234,
+ ["Therefore"]=0x02234,
+ ["therefore"]=0x02234,
+ ["Theta"]=0x00398,
+ ["theta"]=0x003B8,
+ ["thetav"]=0x003D1,
+ ["thickapprox"]=0x02248,
+ ["thicksim"]=0x0223C,
+ ["ThickSpace"]=0x02009,
+ ["thinsp"]=0x02009,
+ ["ThinSpace"]=0x02009,
+ ["thkap"]=0x02248,
+ ["thksim"]=0x0223C,
+ ["THORN"]=0x000DE,
+ ["thorn"]=0x000FE,
+ ["Tilde"]=0x0223C,
+ ["tilde"]=0x002DC,
+ ["TildeEqual"]=0x02243,
+ ["TildeFullEqual"]=0x02245,
+ ["TildeTilde"]=0x02248,
+ ["times"]=0x000D7,
+ ["timesb"]=0x022A0,
+ ["timesbar"]=0x02A31,
+ ["timesd"]=0x02A30,
+ ["tint"]=0x0222D,
+ ["toea"]=0x02928,
+ ["top"]=0x022A4,
+ ["topbot"]=0x02336,
+ ["topcir"]=0x02AF1,
+ ["Topf"]=0x1D54B,
+ ["topf"]=0x1D565,
+ ["topfork"]=0x02ADA,
+ ["tosa"]=0x02929,
+ ["tprime"]=0x02034,
+ ["trade"]=0x02122,
+ ["triangle"]=0x025B5,
+ ["triangledown"]=0x025BF,
+ ["triangleleft"]=0x025C3,
+ ["trianglelefteq"]=0x022B4,
+ ["triangleq"]=0x0225C,
+ ["triangleright"]=0x025B9,
+ ["trianglerighteq"]=0x022B5,
+ ["tridot"]=0x025EC,
+ ["trie"]=0x0225C,
+ ["triminus"]=0x02A3A,
+ ["TripleDot"]=0x020DB,
+ ["triplus"]=0x02A39,
+ ["trisb"]=0x029CD,
+ ["tritime"]=0x02A3B,
+ ["trpezium"]=0x0FFFD,
+ ["Tscr"]=0x1D4AF,
+ ["tscr"]=0x1D4C9,
+ ["TScy"]=0x00426,
+ ["tscy"]=0x00446,
+ ["TSHcy"]=0x0040B,
+ ["tshcy"]=0x0045B,
+ ["Tstrok"]=0x00166,
+ ["tstrok"]=0x00167,
+ ["twixt"]=0x0226C,
+ ["twoheadleftarrow"]=0x0219E,
+ ["twoheadrightarrow"]=0x021A0,
+ ["Uacute"]=0x000DA,
+ ["uacute"]=0x000FA,
+ ["Uarr"]=0x0219F,
+ ["uArr"]=0x021D1,
+ ["uarr"]=0x02191,
+ ["Uarrocir"]=0x02949,
+ ["Ubrcy"]=0x0040E,
+ ["ubrcy"]=0x0045E,
+ ["Ubreve"]=0x0016C,
+ ["ubreve"]=0x0016D,
+ ["Ucirc"]=0x000DB,
+ ["ucirc"]=0x000FB,
+ ["Ucy"]=0x00423,
+ ["ucy"]=0x00443,
+ ["udarr"]=0x021C5,
+ ["Udblac"]=0x00170,
+ ["udblac"]=0x00171,
+ ["udhar"]=0x0296E,
+ ["ufisht"]=0x0297E,
+ ["Ufr"]=0x1D518,
+ ["ufr"]=0x1D532,
+ ["Ugrave"]=0x000D9,
+ ["ugrave"]=0x000F9,
+ ["uHar"]=0x02963,
+ ["uharl"]=0x021BF,
+ ["uharr"]=0x021BE,
+ ["uhblk"]=0x02580,
+ ["ulcorn"]=0x0231C,
+ ["ulcorner"]=0x0231C,
+ ["ulcrop"]=0x0230F,
+ ["ultri"]=0x025F8,
+ ["Umacr"]=0x0016A,
+ ["umacr"]=0x0016B,
+ ["uml"]=0x000A8,
+ ["UnderBar"]=0x00332,
+ ["UnderBrace"]=0x0FE38,
+ ["UnderBracket"]=0x023B5,
+ ["UnderParenthesis"]=0x0FE36,
+ ["Union"]=0x022C3,
+ ["UnionPlus"]=0x0228E,
+ ["Uogon"]=0x00172,
+ ["uogon"]=0x00173,
+ ["Uopf"]=0x1D54C,
+ ["uopf"]=0x1D566,
+ ["UpArrow"]=0x02191,
+ ["Uparrow"]=0x021D1,
+ ["uparrow"]=0x02191,
+ ["UpArrowBar"]=0x02912,
+ ["UpArrowDownArrow"]=0x021C5,
+ ["UpDownArrow"]=0x02195,
+ ["Updownarrow"]=0x021D5,
+ ["updownarrow"]=0x02195,
+ ["UpEquilibrium"]=0x0296E,
+ ["upharpoonleft"]=0x021BF,
+ ["upharpoonright"]=0x021BE,
+ ["uplus"]=0x0228E,
+ ["UpperLeftArrow"]=0x02196,
+ ["UpperRightArrow"]=0x02197,
+ ["Upsi"]=0x003D2,
+ ["upsi"]=0x003C5,
+ ["Upsilon"]=0x003A5,
+ ["upsilon"]=0x003C5,
+ ["UpTee"]=0x022A5,
+ ["UpTeeArrow"]=0x021A5,
+ ["upuparrows"]=0x021C8,
+ ["urcorn"]=0x0231D,
+ ["urcorner"]=0x0231D,
+ ["urcrop"]=0x0230E,
+ ["Uring"]=0x0016E,
+ ["uring"]=0x0016F,
+ ["urtri"]=0x025F9,
+ ["Uscr"]=0x1D4B0,
+ ["uscr"]=0x1D4CA,
+ ["utdot"]=0x022F0,
+ ["Utilde"]=0x00168,
+ ["utilde"]=0x00169,
+ ["utri"]=0x025B5,
+ ["utrif"]=0x025B4,
+ ["uuarr"]=0x021C8,
+ ["Uuml"]=0x000DC,
+ ["uuml"]=0x000FC,
+ ["uwangle"]=0x029A7,
+ ["vangrt"]=0x0299C,
+ ["varepsilon"]=0x003B5,
+ ["varkappa"]=0x003F0,
+ ["varnothing"]=0x02205,
+ ["varphi"]=0x003C6,
+ ["varpi"]=0x003D6,
+ ["varpropto"]=0x0221D,
+ ["vArr"]=0x021D5,
+ ["varr"]=0x02195,
+ ["varrho"]=0x003F1,
+ ["varsigma"]=0x003C2,
+ ["varsubsetneq"]=0x0228A,
+ ["varsubsetneqq"]=0x02ACB,
+ ["varsupsetneq"]=0x0228B,
+ ["varsupsetneqq"]=0x02ACC,
+ ["vartheta"]=0x003D1,
+ ["vartriangleleft"]=0x022B2,
+ ["vartriangleright"]=0x022B3,
+ ["Vbar"]=0x02AEB,
+ ["vBar"]=0x02AE8,
+ ["vBarv"]=0x02AE9,
+ ["Vcy"]=0x00412,
+ ["vcy"]=0x00432,
+ ["VDash"]=0x022AB,
+ ["Vdash"]=0x022A9,
+ ["vDash"]=0x022A8,
+ ["vdash"]=0x022A2,
+ ["Vdashl"]=0x02AE6,
+ ["Vee"]=0x022C1,
+ ["vee"]=0x02228,
+ ["veebar"]=0x022BB,
+ ["veeeq"]=0x0225A,
+ ["vellip"]=0x022EE,
+ ["Verbar"]=0x02016,
+ ["verbar"]=0x0007C,
+ ["Vert"]=0x02016,
+ ["vert"]=0x0007C,
+ ["VerticalBar"]=0x02223,
+ ["VerticalLine"]=0x0007C,
+ ["VerticalSeparator"]=0x02758,
+ ["VerticalTilde"]=0x02240,
+ ["VeryThinSpace"]=0x0200A,
+ ["Vfr"]=0x1D519,
+ ["vfr"]=0x1D533,
+ ["vltri"]=0x022B2,
+ ["vnsub"]=0x02282,
+ ["vnsup"]=0x02283,
+ ["Vopf"]=0x1D54D,
+ ["vopf"]=0x1D567,
+ ["vprop"]=0x0221D,
+ ["vrtri"]=0x022B3,
+ ["Vscr"]=0x1D4B1,
+ ["vscr"]=0x1D4CB,
+ ["vsubnE"]=0x02ACB,
+ ["vsubne"]=0x0228A,
+ ["vsupnE"]=0x02ACC,
+ ["vsupne"]=0x0228B,
+ ["Vvdash"]=0x022AA,
+ ["vzigzag"]=0x0299A,
+ ["Wcirc"]=0x00174,
+ ["wcirc"]=0x00175,
+ ["wedbar"]=0x02A5F,
+ ["Wedge"]=0x022C0,
+ ["wedge"]=0x02227,
+ ["wedgeq"]=0x02259,
+ ["weierp"]=0x02118,
+ ["Wfr"]=0x1D51A,
+ ["wfr"]=0x1D534,
+ ["Wopf"]=0x1D54E,
+ ["wopf"]=0x1D568,
+ ["wp"]=0x02118,
+ ["wr"]=0x02240,
+ ["wreath"]=0x02240,
+ ["Wscr"]=0x1D4B2,
+ ["wscr"]=0x1D4CC,
+ ["xcap"]=0x022C2,
+ ["xcirc"]=0x025EF,
+ ["xcup"]=0x022C3,
+ ["xdtri"]=0x025BD,
+ ["Xfr"]=0x1D51B,
+ ["xfr"]=0x1D535,
+ ["xhArr"]=0x027FA,
+ ["xharr"]=0x027F7,
+ ["Xi"]=0x0039E,
+ ["xi"]=0x003BE,
+ ["xlArr"]=0x027F8,
+ ["xlarr"]=0x027F5,
+ ["xmap"]=0x027FC,
+ ["xnis"]=0x022FB,
+ ["xodot"]=0x02A00,
+ ["Xopf"]=0x1D54F,
+ ["xopf"]=0x1D569,
+ ["xoplus"]=0x02A01,
+ ["xotime"]=0x02A02,
+ ["xrArr"]=0x027F9,
+ ["xrarr"]=0x027F6,
+ ["Xscr"]=0x1D4B3,
+ ["xscr"]=0x1D4CD,
+ ["xsqcup"]=0x02A06,
+ ["xuplus"]=0x02A04,
+ ["xutri"]=0x025B3,
+ ["xvee"]=0x022C1,
+ ["xwedge"]=0x022C0,
+ ["Yacute"]=0x000DD,
+ ["yacute"]=0x000FD,
+ ["YAcy"]=0x0042F,
+ ["yacy"]=0x0044F,
+ ["Ycirc"]=0x00176,
+ ["ycirc"]=0x00177,
+ ["Ycy"]=0x0042B,
+ ["ycy"]=0x0044B,
+ ["yen"]=0x000A5,
+ ["Yfr"]=0x1D51C,
+ ["yfr"]=0x1D536,
+ ["YIcy"]=0x00407,
+ ["yicy"]=0x00457,
+ ["Yopf"]=0x1D550,
+ ["yopf"]=0x1D56A,
+ ["Yscr"]=0x1D4B4,
+ ["yscr"]=0x1D4CE,
+ ["YUcy"]=0x0042E,
+ ["yucy"]=0x0044E,
+ ["Yuml"]=0x00178,
+ ["yuml"]=0x000FF,
+ ["Zacute"]=0x00179,
+ ["zacute"]=0x0017A,
+ ["Zcaron"]=0x0017D,
+ ["zcaron"]=0x0017E,
+ ["Zcy"]=0x00417,
+ ["zcy"]=0x00437,
+ ["Zdot"]=0x0017B,
+ ["zdot"]=0x0017C,
+ ["zeetrf"]=0x02128,
+ ["ZeroWidthSpace"]=0x0200B,
+ ["zeta"]=0x003B6,
+ ["Zfr"]=0x02128,
+ ["zfr"]=0x1D537,
+ ["ZHcy"]=0x00416,
+ ["zhcy"]=0x00436,
+ ["zigrarr"]=0x021DD,
+ ["Zopf"]=0x02124,
+ ["zopf"]=0x1D56B,
+ ["Zscr"]=0x1D4B5,
+ ["zscr"]=0x1D4CF,
+
+ ["plusminus"]=0x000B1,
+ ["minusplus"]=0x02213,
+ ["cdots"]=0x2026,
+
+}
diff --git a/tex/context/base/math-eul.mkii b/tex/context/base/math-eul.mkii
new file mode 100644
index 000000000..7552957a8
--- /dev/null
+++ b/tex/context/base/math-eul.mkii
@@ -0,0 +1,277 @@
+%D \module
+%D [ file=math-eul,
+%D version=2003.02.03,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Virtual Euler Specials,
+%D author={Hans Hagen \& Taco Hoekwater \& Adam Lindsay},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details. Further modified by Adam Lindsay.
+
+\unprotect
+
+%D We follow the following mappings from type-eul:
+%D
+%D mr [MathRoman] [Euler-Roman] [zeurm10]
+
+%D mi [MathItalic] [Euler-Italic] [eufm10]
+
+%D ex [MathExtension] [Euler-Extension] [zeuex10]
+%D sy [MathSymbol] [Euler-Symbol] [zeusm10]
+
+%D mb [MathBeta] [Charter-Roman] [bchr8r] XXX
+%D mc [MathGamma] [Euler-Fraktur] [eufm10] XXX
+%D
+%D The inclusion of Bitstream Charter was originally for the text accents.
+%D Obviously, it's not a proper ``MathBeta'' font.
+
+%D The varrho and varsigma characters don't exist in eulervm,
+%D so we point at the normal types.
+
+\definefamilysynonym [eul] [calligraphic] [sy]
+\definefamilysynonym [eul] [oldstyle] [mi]
+\definefamilysynonym [eul] [gothic] [mi]
+\definefamilysynonym [eul] [fraktur] [mi]
+
+\definefamilysynonym [eul] [lcgreek] [mr]
+\definefamilysynonym [eul] [ucgreek] [mr]
+\definefamilysynonym [eul] [vargreek] [mr]
+
+%% Well, you don't know until you try!
+%\definefamilysynonym [eul] [accents] [Serif]
+
+\startmathcollection [eul]
+
+\definemathsymbol [varrho] [nothing] [vargreek] ["1A]
+\definemathsymbol [varsigma] [nothing] [vargreek] ["1B]
+
+%D Changes necessitated by collapsing mr \& mi into one:
+\definemathsymbol [imath] [nothing] [mr] ["7B]
+\definemathsymbol [jmath] [nothing] [mr] ["7C]
+\definemathsymbol [ell] [nothing] [mr] ["60]
+\definemathsymbol [wp] [nothing] [mr] ["7D]
+\definemathsymbol [partial] [nothing] [mr] ["40]
+
+\definemathsymbol [flat] [ord] [mr] ["5B]
+\definemathsymbol [natural] [ord] [mr] ["5C]
+\definemathsymbol [sharp] [ord] [mr] ["5D]
+
+\definemathsymbol [triangleleft] [bin] [mr] ["2F]
+\definemathsymbol [triangleright][bin] [mr] ["2E]
+
+\definemathsymbol [star] [bin] [mr] ["3F]
+
+\definemathsymbol [smile] [rel] [mr] ["5E]
+\definemathsymbol [frown] [rel] [mr] ["5F]
+\definemathsymbol [leftharpoonup] [rel] [mr] ["28]
+\definemathsymbol [leftharpoondown] [rel] [mr] ["29]
+\definemathsymbol [rightharpoonup] [rel] [mr] ["2A]
+\definemathsymbol [rightharpoondown] [rel] [mr] ["2B]
+\definemathsymbol [lhook] [rel] [mr] ["2C]
+\definemathsymbol [rhook] [rel] [mr] ["2D]
+
+\definemathsymbol [mathperiod] [ord] [mr] ["3A]
+\definemathsymbol [textperiod] [punct] [mr] ["3A]
+
+\definemathsymbol [mathcomma] [ord] [mr] ["3B]
+\definemathsymbol [textcomma] [punct] [mr] ["3B]
+
+\definemathsymbol [ldotp] [punct] [mr] ["3A]
+
+% extras from AMS:
+\definemathsymbol [hslash] [ord] [mr] ["80] %beauty over truth
+
+\stopmathcollection
+
+\startmathcollection [eul]
+% Ugh. no way around this to keep it compact in the font defs.
+
+\definemathcharacter [a] [alpha] [mr] ["61]
+\definemathcharacter [b] [alpha] [mr] ["62]
+\definemathcharacter [c] [alpha] [mr] ["63]
+\definemathcharacter [d] [alpha] [mr] ["64]
+\definemathcharacter [e] [alpha] [mr] ["65]
+\definemathcharacter [f] [alpha] [mr] ["66]
+\definemathcharacter [g] [alpha] [mr] ["67]
+\definemathcharacter [h] [alpha] [mr] ["68]
+\definemathcharacter [i] [alpha] [mr] ["69]
+\definemathcharacter [j] [alpha] [mr] ["6A]
+\definemathcharacter [k] [alpha] [mr] ["6B]
+\definemathcharacter [l] [alpha] [mr] ["6C]
+\definemathcharacter [m] [alpha] [mr] ["6D]
+\definemathcharacter [n] [alpha] [mr] ["6E]
+\definemathcharacter [o] [alpha] [mr] ["6F]
+\definemathcharacter [p] [alpha] [mr] ["70]
+\definemathcharacter [q] [alpha] [mr] ["71]
+\definemathcharacter [r] [alpha] [mr] ["72]
+\definemathcharacter [s] [alpha] [mr] ["73]
+\definemathcharacter [t] [alpha] [mr] ["74]
+\definemathcharacter [u] [alpha] [mr] ["75]
+\definemathcharacter [v] [alpha] [mr] ["76]
+\definemathcharacter [w] [alpha] [mr] ["77]
+\definemathcharacter [x] [alpha] [mr] ["78]
+\definemathcharacter [y] [alpha] [mr] ["79]
+\definemathcharacter [z] [alpha] [mr] ["7A]
+
+\definemathcharacter [A] [alpha] [mr] ["41]
+\definemathcharacter [B] [alpha] [mr] ["42]
+\definemathcharacter [C] [alpha] [mr] ["43]
+\definemathcharacter [D] [alpha] [mr] ["44]
+\definemathcharacter [E] [alpha] [mr] ["45]
+\definemathcharacter [F] [alpha] [mr] ["46]
+\definemathcharacter [G] [alpha] [mr] ["47]
+\definemathcharacter [H] [alpha] [mr] ["48]
+\definemathcharacter [I] [alpha] [mr] ["49]
+\definemathcharacter [J] [alpha] [mr] ["4A]
+\definemathcharacter [K] [alpha] [mr] ["4B]
+\definemathcharacter [L] [alpha] [mr] ["4C]
+\definemathcharacter [M] [alpha] [mr] ["4D]
+\definemathcharacter [N] [alpha] [mr] ["4E]
+\definemathcharacter [O] [alpha] [mr] ["4F]
+\definemathcharacter [P] [alpha] [mr] ["50]
+\definemathcharacter [Q] [alpha] [mr] ["51]
+\definemathcharacter [R] [alpha] [mr] ["52]
+\definemathcharacter [S] [alpha] [mr] ["53]
+\definemathcharacter [T] [alpha] [mr] ["54]
+\definemathcharacter [U] [alpha] [mr] ["55]
+\definemathcharacter [V] [alpha] [mr] ["56]
+\definemathcharacter [W] [alpha] [mr] ["57]
+\definemathcharacter [X] [alpha] [mr] ["58]
+\definemathcharacter [Y] [alpha] [mr] ["59]
+\definemathcharacter [Z] [alpha] [mr] ["5A]
+
+\stopmathcollection
+
+\startmathcollection [eul]
+
+\definemathcharacter [!] [close] [sy] ["A1]
+\definemathcharacter [(] [open] [sy] ["A8]
+\definemathcharacter [)] [close] [sy] ["A9]
+\definemathcharacter [+] [bin] [sy] ["AB]
+\definemathcharacter [:] [rel] [sy] ["BA]
+\definemathcharacter [;] [punct] [sy] ["BB]
+\definemathcharacter [=] [rel] [sy] ["BD]
+\definemathcharacter [?] [close] [sy] ["BF]
+\definemathcharacter [91] [open] [sy] ["DB] % [
+\definemathcharacter [93] [close] [sy] ["DD] % ]
+
+\definemathcharacter [,] [punct] [mr] ["3B]
+\definemathcharacter [.] [ord] [mr] ["3A]
+\definemathcharacter [/] [ord] [mr] ["3D]
+\definemathcharacter [<] [rel] [mr] ["3C]
+\definemathcharacter [>] [rel] [mr] ["3E]
+
+\stopmathcollection
+
+\startmathcollection [eul]
+
+\definemathcharacter [(] [nothing] [sy] ["A8] [ex] ["00]
+\definemathcharacter [)] [nothing] [sy] ["A9] [ex] ["01]
+\definemathcharacter [91] [nothing] [sy] ["DB] [ex] ["02] % [
+\definemathcharacter [93] [nothing] [sy] ["DD] [ex] ["03] % ]
+\definemathcharacter [/] [nothing] [mr] ["3D] [ex] ["0E]
+
+\stopmathcollection
+
+\startmathcollection [eul]
+
+\definemathsymbol [hbar] [nothing] [mr] ["80]
+
+\stopmathcollection
+
+\startmathcollection [eul]
+
+\definemathsymbol [ddagger] [bin] [sy] ["7A]
+\definemathsymbol [dagger] [bin] [sy] ["79]
+
+\stopmathcollection
+
+\startmathcollection [eul]
+
+\definemathsymbol [colon] [punct] [sy] ["BA]
+
+\stopmathcollection
+
+%D This used to be very hackish; it brought in text
+%D accents from the well-matched Bitstream Charter.
+
+%D But now, these characters don't exist. I would prefer to pull
+%D them from the text font, but I don't know how.
+%D Instead, I'm just pointing to null characters!
+
+\startmathcollection [eul]
+
+\definemathsymbol [acute] [accent] [mr] ["90]
+\definemathsymbol [grave] [accent] [mr] ["91]
+\definemathsymbol [ddot] [accent] [mr] ["92]
+\definemathsymbol [tilde] [accent] [mr] ["93]
+\definemathsymbol [bar] [accent] [mr] ["94]
+\definemathsymbol [breve] [accent] [mr] ["95]
+\definemathsymbol [check] [accent] [mr] ["96]
+\definemathsymbol [hat] [accent] [mr] ["97]
+\definemathsymbol [dot] [accent] [mr] ["98]
+%\definemathsymbol [acute] [accent] [accents] ["B4]
+%\definemathsymbol [grave] [accent] [accents] ["1E]
+%\definemathsymbol [ddot] [accent] [accents] ["A8]
+%\definemathsymbol [tilde] [accent] [accents] ["98]
+%\definemathsymbol [bar] [accent] [accents] ["AF]
+%\definemathsymbol [breve] [accent] [accents] ["0B]
+%\definemathsymbol [check] [accent] [accents] ["10]
+%\definemathsymbol [hat] [accent] [accents] ["5E]
+%\definemathsymbol [dot] [accent] [accents] ["01]
+
+\definemathsymbol [vec] [accent] [mr] ["7E] % [ord]
+\definemathsymbol [hat] [accent] [sy] ["DE]
+
+\stopmathcollection
+
+\startmathcollection [eul]
+
+\definemathsymbol [lgroup] [open] [sy] ["A8] [ex] ["3A] % ?
+\definemathsymbol [rgroup] [close] [sy] ["A9] [ex] ["3B] % ?
+
+\stopmathcollection
+
+\startmathcollection [eul]
+
+\definemathsymbol [dag] [box] [sy] ["79]
+\definemathsymbol [ddag] [box] [sy] ["7A]
+\definemathsymbol [S] [box] [sy] ["78]
+\definemathsymbol [P] [box] [sy] ["7B]
+
+\stopmathcollection
+
+%D Aditya's additionl definitions:
+
+\startmathcollection[eul:texnansi]
+ \definemathsymbol [acute] [accent] [tf] ["13]
+ \definemathsymbol [grave] [accent] [tf] ["12]
+ \definemathsymbol [ddot] [accent] [tf] ["A8]
+ \definemathsymbol [tilde] [accent] [tf] ["98]
+ \definemathsymbol [bar] [accent] [tf] ["16]
+ \definemathsymbol [breve] [accent] [tf] ["15]
+ \definemathsymbol [check] [accent] [tf] ["14]
+ \definemathsymbol [hat] [accent] [tf] ["88]
+ \definemathsymbol [dot] [accent] [tf] ["5]
+ % Why is mathring not defined??
+ \definemathsymbol [mathring] [accent] [tf] ["17]
+\stopmathcollection
+
+\startmathcollection[eul:ec]
+ \definemathsymbol [acute] [accent] [tf] ["1]
+ \definemathsymbol [grave] [accent] [tf] ["0]
+ \definemathsymbol [ddot] [accent] [tf] ["4]
+ \definemathsymbol [tilde] [accent] [tf] ["3]
+ \definemathsymbol [bar] [accent] [tf] ["9]
+ \definemathsymbol [breve] [accent] [tf] ["8]
+ \definemathsymbol [check] [accent] [tf] ["7]
+ \definemathsymbol [hat] [accent] [tf] ["2]
+ \definemathsymbol [dot] [accent] [tf] ["A]
+ % Why is mathring not defined??
+ \definemathsymbol [mathring] [accent] [tf] ["6]
+\stopmathcollection
+
+\protect \endinput
diff --git a/tex/context/base/math-ext.lua b/tex/context/base/math-ext.lua
new file mode 100644
index 000000000..673103677
--- /dev/null
+++ b/tex/context/base/math-ext.lua
@@ -0,0 +1,154 @@
+if not modules then modules = { } end modules ['math-ext'] = {
+ version = 1.001,
+ comment = "companion to math-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local trace_virtual = false trackers.register("math.virtual", function(v) trace_virtual = v end)
+
+mathematics = mathematics or { }
+characters = characters or { }
+
+mathematics.extras = mathematics.extras or { }
+characters.math = characters.math or { }
+
+local chardata = characters.data
+local mathdata = characters.math
+
+function mathematics.extras.add(unicode,t)
+ local min, max = mathematics.extrabase, mathematics.privatebase - 1
+ if unicode >= min and unicode <= max then
+ mathdata[unicode], chardata[unicode] = t, t
+ else
+ logs.report("math extra","extra U+%04X should be in range U+%04X - U+%04X",unicode,min,max)
+ end
+end
+
+function mathematics.extras.copy(tfmdata)
+ local math_parameters = tfmdata.math_parameters
+ local MathConstants = tfmdata.MathConstants
+ if (math_parameters and next(math_parameters)) or (MathConstants and next(MathConstants)) then
+ local characters = tfmdata.characters
+ for unicode, extradesc in next, mathdata do
+ -- always, because in an intermediate step we can have a non math font
+ local extrachar = characters[unicode]
+ local nextinsize = extradesc.nextinsize
+ if nextinsize then
+ for i=1,#nextinsize do
+ local nextslot = nextinsize[i]
+ local nextbase = characters[nextslot]
+ if nextbase then
+ local nextnext = nextbase and nextbase.next
+ if nextnext then
+ local nextchar = characters[nextnext]
+ if nextchar then
+ if trace_virtual then
+ logs.report("math extra","extra U+%04X in %s at %s maps on U+%04X (class: %s, name: %s)",unicode,file.basename(tfmdata.fullname),tfmdata.size,nextslot,extradesc.mathclass or "?",extradesc.mathname or "?")
+ end
+ characters[unicode] = nextchar
+ break
+ end
+ end
+ end
+ end
+ if not characters[unicode] then
+ for i=1,#nextinsize do
+ local nextbase = characters[nextinsize[i]]
+ if nextbase then
+ characters[unicode] = nextchar
+ break
+ end
+ end
+ end
+ end
+ end
+ else
+ -- let's not waste time on non-math
+ end
+end
+
+table.insert(fonts.tfm.mathactions,mathematics.extras.copy)
+
+-- 0xFE302 -- 0xFE320 for accents
+
+mathematics.extras.add(0xFE302, {
+ category="mn",
+ description="WIDE MATHEMATICAL HAT",
+ direction="nsm",
+ linebreak="cm",
+ mathclass="accent",
+ mathname="widehat",
+ mathstretch="h",
+ unicodeslot=0xFE302,
+ nextinsize={ 0x00302, 0x0005E },
+} )
+
+mathematics.extras.add(0xFE303, {
+ category="mn",
+ cjkwd="a",
+ description="WIDE MATHEMATICAL TILDE",
+ direction="nsm",
+ linebreak="cm",
+ mathclass="accent",
+ mathname="widetilde",
+ mathstretch="h",
+ unicodeslot=0xFE303,
+ nextinsize={ 0x00303, 0x0007E },
+} )
+
+-- 0xFE321 -- 0xFE340 for missing characters
+
+mathematics.extras.add(0xFE321, {
+ category="sm",
+ description="MATHEMATICAL SHORT BAR",
+-- direction="on",
+-- linebreak="nu",
+ mathclass="relation",
+ mathname="mapstochar",
+ unicodeslot=0xFE321,
+} )
+
+mathematics.extras.add(0xFE322, {
+ category="sm",
+ description="MATHEMATICAL LEFT HOOK",
+ mathclass="relation",
+ mathname="lhook",
+ unicodeslot=0xFE322,
+} )
+
+mathematics.extras.add(0xFE323, {
+ category="sm",
+ description="MATHEMATICAL RIGHT HOOK",
+ mathclass="relation",
+ mathname="rhook",
+ unicodeslot=0xFE323,
+} )
+
+--~ mathematics.extras.add(0xFE304, {
+--~ category="sm",
+--~ description="TOP AND BOTTOM PARENTHESES",
+--~ direction="on",
+--~ linebreak="al",
+--~ mathclass="doubleaccent",
+--~ mathname="doubleparent",
+--~ unicodeslot=0xFE304,
+--~ accents={ 0x023DC, 0x023DD },
+--~ } )
+
+--~ mathematics.extras.add(0xFE305, {
+--~ category="sm",
+--~ description="TOP AND BOTTOM BRACES",
+--~ direction="on",
+--~ linebreak="al",
+--~ mathclass="doubleaccent",
+--~ mathname="doublebrace",
+--~ unicodeslot=0xFE305,
+--~ accents={ 0x023DE, 0x023DF },
+--~ } )
+
+--~ \Umathchardef\braceld="0 "1 "FF07A
+--~ \Umathchardef\bracerd="0 "1 "FF07B
+--~ \Umathchardef\bracelu="0 "1 "FF07C
+--~ \Umathchardef\braceru="0 "1 "FF07D
diff --git a/tex/context/base/math-for.mkiv b/tex/context/base/math-for.mkiv
new file mode 100644
index 000000000..e33276d53
--- /dev/null
+++ b/tex/context/base/math-for.mkiv
@@ -0,0 +1,79 @@
+%D \module
+%D [ file=strc-mat,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Math Numbering,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%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 Structure Macros / Math Formulas}
+
+%D This module only provides the code for defining formulas and
+%D fetching parameters. The action takes place later.
+
+\unprotect
+
+\let\currentformula\s!unknown
+
+\def\formulaparameter #1{\csname\doformulaparameter{\??fm\currentformula}#1\endcsname}
+\def\formulaparameterhash#1{\doformulaparameterhash {\??fm\currentformula}#1}
+
+\def\doformulaparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\doformulaparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\doformulaparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\doformulaparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\detokenizedformulaparameter#1{\detokenize\expandafter\expandafter\expandafter{\csname\??fm\currentformula#1\endcsname}}
+
+\def\doformulaparentparameter #1#2{\ifx#1\relax\s!empty\else\doformulaparameter #1#2\fi}
+\def\doformulaparentparameterhash#1#2{\ifx#1\relax \else\doformulaparameterhash#1#2\fi}
+
+\def\dosetformulaattributes#1#2% style color
+ {\edef\fontattributehash {\formulaparameterhash#1}%
+ \edef\colorattributehash{\formulaparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+\def\getformulaparameters{\getparameters[\??fm]}
+
+%D \macros
+%D {setupformulas}
+
+\newtoks \everysetupformulas
+
+\unexpanded\def\setupformulas
+ {\dodoubleempty\dosetupformulas}
+
+\def\dosetupformulas[#1][#2]%
+ {\ifsecondargument
+ \edef\currentformula{#1}%
+ \getparameters[\??fm#1][#2]%
+ \else
+% \let\currentformula\v!formula % hm
+ \let\currentformula\empty
+ \getparameters[\??fm][#1]%
+ \fi
+ \the\everysetupformulas
+ \let\currentformula\empty}
+
+%D Not yet cleanup up:
+
+%D \macros
+%D {setuptextformulas}
+%D
+%D This command sets up in||line math. Most features deals
+%D with grid snapping and are experimental.
+
+\newtoks \everysetuptextformulas
+
+\unexpanded\def\setuptextformulas
+ {\dosingleempty\dosetuptextformulas}
+
+\def\dosetuptextformulas[#1]%
+ {\getparameters[\??mt][#1]%
+ \the\everysetuptextformulas}
+
+\protect \endinput
diff --git a/tex/context/base/math-fou.mkii b/tex/context/base/math-fou.mkii
new file mode 100644
index 000000000..8a72f1288
--- /dev/null
+++ b/tex/context/base/math-fou.mkii
@@ -0,0 +1,196 @@
+%D \module
+%D [ file=math-fou,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Fourier Specials,
+%D author={Michel Biovani \& Hans Hagen},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% see end of file for todo
+
+\unprotect
+
+\startmathcollection [fou]
+
+ \definemathsymbol [Gamma] [alpha] [mi] ["00]
+ \definemathsymbol [Delta] [alpha] [mi] ["01]
+ \definemathsymbol [Theta] [alpha] [mi] ["02]
+ \definemathsymbol [Lambda] [alpha] [mi] ["03]
+ \definemathsymbol [Xi] [alpha] [mi] ["04]
+ \definemathsymbol [Pi] [alpha] [mi] ["05]
+ \definemathsymbol [Sigma] [alpha] [mi] ["06]
+ \definemathsymbol [Upsilon] [alpha] [mi] ["07]
+ \definemathsymbol [Phi] [alpha] [mi] ["08]
+ \definemathsymbol [Psi] [alpha] [mi] ["09]
+ \definemathsymbol [Omega] [alpha] [mi] ["0A]
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathcharacter [+] [bin] [sy] ["80]
+ \definemathcharacter [=] [rel] [sy] ["81]
+ \definemathcharacter [<] [rel] [sy] ["82]
+ \definemathcharacter [>] [rel] [sy] ["83]
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathsymbol [leqslant] [rel] [sy] ["84]
+ \definemathsymbol [geqslant] [rel] [sy] ["85]
+ \definemathsymbol [parallelslant] [rel] [sy] ["86]
+ \definemathsymbol [thething] [ord] [sy] ["87]
+ \definemathsymbol [vDash] [rel] [sy] ["88]
+ \definemathsymbol [blacktriangleleft] [rel] [sy] ["89]
+ \definemathsymbol [blacktriangleright] [rel] [sy] ["8A]
+ \definemathsymbol [nleqslant] [rel] [sy] ["8B]
+ \definemathsymbol [ngeqslant] [rel] [sy] ["8C]
+ \definemathsymbol [parallel] [rel] [sy] ["8D]
+ \definemathsymbol [nparallel] [rel] [sy] ["8E]
+ \definemathsymbol [nparallelslant] [rel] [sy] ["8F]
+ \definemathsymbol [nvDash] [rel] [sy] ["90]
+ \definemathsymbol [intercal] [bin] [sy] ["91]
+ \definemathsymbol [hslash] [ord] [sy] ["92]
+ \definemathsymbol [nexists] [ord] [sy] ["93]
+ \definemathsymbol [varsubsetneq] [rel] [sy] ["93]
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathcharacter [(] [nothing] [mr] ["28] [ex] ["A1]
+ \definemathcharacter [)] [nothing] [mr] ["29] [ex] ["A2]
+ \definemathcharacter [91] [nothing] [mr] ["5B] [ex] ["A3] % [
+ \definemathcharacter [93] [nothing] [mr] ["5D] [ex] ["A4] % ]
+ \definemathcharacter [/] [nothing] [mr] ["2F] [ex] ["B1]
+
+ \definemathcharacter [124] [nothing] [sy] ["6A] [ex] ["AF] % |
+ \definemathcharacter [92] [nothing] [sy] ["6E] [ex] ["B2] % \
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathsymbol [Vert] [nothing] [sy] ["6B] [ex] ["B0]
+ \definemathsymbol [vert] [nothing] [sy] ["6A] [ex] ["AF]
+ \definemathsymbol [VERT] [nothing] [sy] ["98] [ex] ["93]
+ \definemathsymbol [Downarrow] [rel] [sy] ["2B] [ex] ["C4]
+ \definemathsymbol [backslash] [nothing] [sy] ["6E] [ex] ["B2]
+ \definemathsymbol [rangle] [close] [sy] ["69] [ex] ["AE]
+ \definemathsymbol [langle] [open] [sy] ["68] [ex] ["AD]
+ \definemathsymbol [rbrace] [close] [sy] ["67] [ex] ["AA]
+ \definemathsymbol [lbrace] [open] [sy] ["66] [ex] ["A9]
+ \definemathsymbol [rceil] [close] [sy] ["65] [ex] ["A8]
+ \definemathsymbol [lceil] [open] [sy] ["64] [ex] ["A7]
+ \definemathsymbol [rfloor] [close] [sy] ["63] [ex] ["A6]
+ \definemathsymbol [lfloor] [open] [sy] ["62] [ex] ["A5]
+ \definemathsymbol [dblbrackleft] [open] [sy] ["99] [ex] ["85]
+ \definemathsymbol [dblbrackright] [close] [sy] ["9A] [ex] ["86]
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathsymbol [varkappa] [ord] [mi] ["80] % check this
+ \definemathsymbol [varvarrho] [ord] [mi] ["81] % check this
+ \definemathsymbol [xswordsup] [ord] [sy] ["96]
+ \definemathsymbol [xswordsdown] [ord] [sy] ["97]
+ \definemathsymbol [notowns] [rel] [sy] ["9C]
+ \definemathsymbol [hbar] [ord] [sy] ["9D]
+ \definemathsymbol [smallsetminus] [bin] [sy] ["9E]
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathsymbol [notin] [rel] [sy] ["9B]
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathsymbol [iintop] [op] [ex] ["CE]
+ \definemathsymbol [iiintop] [op] [ex] ["D0]
+ \definemathsymbol [oiintop] [op] [ex] ["D2]
+ \definemathsymbol [oiiintop] [op] [ex] ["D4]
+ \definemathsymbol [slashintop] [op] [ex] ["D6]
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathcommand [iint] {\iintop \nolimits}
+ \definemathcommand [iiint] {\iiintop \nolimits}
+ \definemathcommand [oiint] {\oiintop \nolimits}
+ \definemathcommand [oiiint] {\oiiintop \nolimits}
+ \definemathcommand [slashint] {\slashintop\nolimits}
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathsymbol [acute] [accent] [mr] ["1]
+ \definemathsymbol [grave] [accent] [mr] ["0]
+ \definemathsymbol [ddot] [accent] [mr] ["4]
+ \definemathsymbol [tilde] [accent] [mr] ["3]
+ \definemathsymbol [bar] [accent] [mr] ["9]
+ \definemathsymbol [breve] [accent] [mr] ["8]
+ \definemathsymbol [check] [accent] [mr] ["7]
+ \definemathsymbol [hat] [accent] [mr] ["2]
+ \definemathsymbol [dot] [accent] [mr] ["A]
+ \definemathsymbol [mathring] [accent] [mr] ["6]
+
+\stopmathcollection
+
+\startmathcollection [fou]
+
+ \definemathsymbol [otheralpha] [ord] [mi] ["0B]
+ \definemathsymbol [otherbeta] [ord] [mi] ["0C]
+ \definemathsymbol [othergamma] [ord] [mi] ["0D]
+ \definemathsymbol [otherdelta] [ord] [mi] ["0E]
+ \definemathsymbol [otherepsilon] [ord] [mi] ["0F]
+ \definemathsymbol [otherzeta] [ord] [mi] ["10]
+
+\stopmathcollection
+
+\protect \endinput
+
+% from a mail of Michel B / todo
+
+% \definemathsymbol [acute] [accent] [operators] ["1]
+% \definemathsymbol [grave] [accent] [operators] ["0]
+% \definemathsymbol [ddot] [accent] [operators] ["4]
+% \definemathsymbol [tilde] [accent] [operators] ["3]
+% \definemathsymbol [bar] [accent] [operators] ["9]
+% \definemathsymbol [breve] [accent] [operators] ["8]
+% \definemathsymbol [check] [accent] [operators] ["7]
+% \definemathsymbol [hat] [accent] [operators] ["2]
+% \definemathsymbol [dot] [accent] [operators] ["A]
+% \definemathsymbol [mathring] [accent] [operators] ["6]
+
+% \definemathsymbol [wideparen] [ord] [largesymbols] ["94]
+% \definemathsymbol [widearc] [accent] [largesymbols] ["D8]
+
+% check for definition of \overset (ams)
+
+% \def\FOUwidering#1%
+% {\overset{\smash{\vbox to .2ex{\hbox{$\mathring{}$}}}}{\wideparen{#1}}}
+
+% \startmathcollection [default] % [ams]
+%
+% \definemathcommand [widering] {\FOUwidering}
+%
+% \stopmathcollection
+
+% \definemathsymbol [otheralpha] [ord] [otherletters] ["0B]
+% \definemathsymbol [otherbeta] [ord] [otherletters] ["0C]
+% \definemathsymbol [othergamma] [ord] [otherletters] ["0D]
+% \definemathsymbol [otherdelta] [ord] [otherletters] ["0E]
+% \definemathsymbol [otherepsilon] [ord] [otherletters] ["0F]
+% \definemathsymbol [otherzeta] [ord] [otherletters] ["10]
diff --git a/tex/context/base/math-frc.mkii b/tex/context/base/math-frc.mkii
new file mode 100644
index 000000000..fa319bc4a
--- /dev/null
+++ b/tex/context/base/math-frc.mkii
@@ -0,0 +1,66 @@
+%D \module
+%D [ file=math-frc,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Fractions,
+%D author={Hans Hagen \& Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Math Macros / Fractions}
+
+\unprotect
+
+\def\exmthfont#1{\symbolicsizedfont#1\plusone{MathExtension}}
+
+\def\domthfrac#1#2#3#4#5#6#7%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #6$}%
+ \setbox2\hbox{$#1 #7$}%
+ \dimen0\wd0
+ \ifdim\wd2>\dimen0 \dimen0\wd2 \fi
+ \setbox4\hbox to \dimen0{\exmthfont#2#3\leaders\hbox{#4}\hss#5}%
+ \mathord{\vcenter{{\offinterlineskip
+ \hbox to \dimen0{\hss\box0\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\copy4\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\box2\hss}}}}%
+ \endgroup}
+
+\def\domthsqrt#1#2#3#4#5%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #5$}%
+ \dimen0=1.05\ht0 \advance\dimen0 1pt \ht0 \dimen0
+ \dimen0=1.05\dp0 \advance\dimen0 1pt \dp0 \dimen0
+ \dimen0\wd0
+ \setbox4\hbox to \dimen0{\exmthfont#2\leaders\hbox{#3}\hfill#4}%
+ \delimitershortfall=0pt
+ \nulldelimiterspace=0pt
+ \setbox2\hbox{$\left\delimiter"0270370 \vrule height\ht0 depth \dp0 width0pt
+ \right.$}%
+ \mathord{\vcenter{\hbox{\copy2
+ \rlap{\raise\dimexpr\ht2-\ht4\relax\copy4}\copy0}}}%
+ \endgroup}
+
+\def\mthfrac#1#2#3#4#5{\mathchoice
+ {\domthfrac\displaystyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\textstyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptstyle \scriptface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptscriptstyle\scriptscriptface{#1}{#2}{#3}{#4}{#5}}}
+
+\def\mthsqrt#1#2#3{\mathchoice
+ {\domthsqrt\displaystyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\textstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptscriptstyle\textface {#1}{#2}{#3}}}
+
+% temp here
+
+\protect \endinput
diff --git a/tex/context/base/math-frc.mkiv b/tex/context/base/math-frc.mkiv
new file mode 100644
index 000000000..2305cec30
--- /dev/null
+++ b/tex/context/base/math-frc.mkiv
@@ -0,0 +1,209 @@
+%D \module
+%D [ file=math-frc,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Fractions,
+%D author={Hans Hagen \& Taco Hoekwater},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Math Macros / Fractions}
+
+\unprotect
+
+%D \macros
+%D {frac, xfrac, xxfrac}
+%D
+%D This is another one Tobias asked for. It replaces the
+%D primitive \type {\over}. We also take the opportunity to
+%D handle math style restoring, which makes sure units and
+%D chemicals come out ok.
+%D The \type {\frac} macro kind of replaces the awkward \type
+%D {\over} primitive. Say that we have the following formulas:
+%D
+%D \startbuffer[sample]
+%D test $\frac {1}{2}$ test $$1 + \frac {1}{2} = 1.5$$
+%D test $\xfrac {1}{2}$ test $$1 + \xfrac {1}{2} = 1.5$$
+%D test $\xxfrac{1}{2}$ test $$1 + \xxfrac{1}{2} = 1.5$$
+%D \stopbuffer
+%D
+%D \typebuffer[sample]
+%D
+%D With the most straightforward definitions, we get:
+%D
+%D \startbuffer[code]
+%D \def\dofrac#1#2#3{\relax\mathematics{{{#1{#2}}\over{#1{#3}}}}}
+%D
+%D \def\frac {\dofrac\mathstyle}
+%D \def\xfrac {\dofrac\scriptstyle}
+%D \def\xxfrac{\dofrac\scriptscriptstyle}
+%D \stopbuffer
+%D
+%D \typebuffer[code] \getbuffer[code,sample]
+%D
+%D Since this does not work well, we can try:
+%D
+%D \startbuffer[code]
+%D \def\xfrac #1#2{\hbox{$\dofrac\scriptstyle {#1}{#2}$}}
+%D \def\xxfrac#1#2{\hbox{$\dofrac\scriptscriptstyle{#1}{#2}$}}
+%D \stopbuffer
+%D
+%D \typebuffer[code] \getbuffer[code,sample]
+%D
+%D This for sure looks better than:
+%D
+%D \startbuffer[code]
+%D \def\xfrac #1#2{{\scriptstyle \dofrac\relax{#1}{#2}}}
+%D \def\xxfrac#1#2{{\scriptscriptstyle\dofrac\relax{#1}{#2}}}
+%D \stopbuffer
+%D
+%D \typebuffer[code] \getbuffer[code,sample]
+%D
+%D So we stick to the next definitions (watch the local
+%D overloading of \type {\xfrac}).
+
+% \def\dofrac#1#2#3{\relax\mathematics{{{#1{#2}}\over{#1{#3}}}}}
+
+\def\dofrac#1#2#3{\relax\mathematics{\Ustack{{#1{#2}}\normalover{#1{#3}}}}}
+\def\nofrac #1#2{\relax\mathematics{\Ustack{{#1}\normalover{#2}}}}
+
+% \chardef\mathfracmode=0 $\frac{1}{2}$
+% \chardef\mathfracmode=1 $\frac{1}{2}$
+% \chardef\mathfracmode=2 $\frac{1}{2}$
+% \chardef\mathfracmode=3 $\frac{1}{2}$
+% \chardef\mathfracmode=4 $\frac{1}{2}$
+% \chardef\mathfracmode=5 $\frac{1}{2}$
+
+\chardef\mathfracmode=0 % 0=auto, 1=displaystyle, 2=textstyle, 3=scriptstyle, 4=scriptscriptstyle, 5=mathstyle
+
+\unexpanded\def\frac
+ {\ifcase\mathfracmode
+ \expandafter\nofrac
+ \or
+ \expandafter\dofrac\expandafter\displaystyle
+ \or
+ \expandafter\dofrac\expandafter\textstyle
+ \or
+ \expandafter\dofrac\expandafter\scriptstyle
+ \or
+ \expandafter\dofrac\expandafter\scriptscriptstyle
+ \else
+ \expandafter\dofrac\expandafter\mathstyle
+ \fi}
+
+\unexpanded\def\xfrac#1#2%
+ {\begingroup
+ \let\xfrac\xxfrac
+ \dofrac\scriptstyle{#1}{#2}%
+ \endgroup}
+
+\unexpanded\def\xxfrac#1#2%
+ {\begingroup
+ \dofrac\scriptscriptstyle{#1}{#2}%
+ \endgroup}
+
+%D The \type {xx} variant looks still ugly, so maybe it's
+%D best to say:
+
+\unexpanded\def\xxfrac#1#2%
+ {\begingroup
+ \dofrac\scriptscriptstyle{#1}{\raise.25ex\hbox{$\scriptscriptstyle#2$}}%
+ \endgroup}
+
+%D Something low level for scientific calculator notation:
+
+\unexpanded\def\scinot#1#2%
+ {#1\times10^{#2}}
+
+%D The next macro, \type {\ch}, is \PPCHTEX\ aware. In
+%D formulas one can therefore best use \type {\ch} instead of
+%D \type {\chemical}, especially in fractions.
+
+% let's see who complains ... \mathstyle is now a primitive
+%
+% \unexpanded\def\ch#1%
+% {\ifdefined\@@chemicalletter
+% \dosetsubscripts
+% \mathstyle{\@@chemicalletter{#1}}%
+% \doresetsubscripts
+% \else
+% \mathstyle{\rm#1}%
+% \fi}
+
+% \unexpanded\def\ch#1%
+% {\ifdefined\@@chemicalletter
+% \dosetsubscripts
+% \mathematics{\@@chemicalletter{#1}}%
+% \doresetsubscripts
+% \else
+% \mathematics{\rm#1}%
+% \fi}
+
+%D \macros
+%D {/}
+%D
+%D Just to be sure, we restore the behavior of some typical
+%D math characters.
+
+\bgroup
+
+\catcode`\/=\@@other \global \let\normalforwardslash/
+\catcode`\/=\@@active \doglobal\appendtoks\let/\normalforwardslash\to\everymathematics
+
+\egroup
+
+% to be checked:
+
+\def\exmthfont#1{\symbolicsizedfont#1\plusone{MathExtension}}
+
+\def\domthfrac#1#2#3#4#5#6#7%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #6$}%
+ \setbox2\hbox{$#1 #7$}%
+ \dimen0\wd0
+ \ifdim\wd2>\dimen0 \dimen0\wd2 \fi
+ \setbox4\hbox to \dimen0{\exmthfont#2#3\leaders\hbox{#4}\hss#5}%
+ \mathord{\vcenter{{\offinterlineskip
+ \hbox to \dimen0{\hss\box0\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\copy4\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\box2\hss}}}}%
+ \endgroup}
+
+\def\domthsqrt#1#2#3#4#5%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #5$}%
+ \dimen0=1.05\ht0 \advance\dimen0 1pt \ht0 \dimen0
+ \dimen0=1.05\dp0 \advance\dimen0 1pt \dp0 \dimen0
+ \dimen0\wd0
+ \setbox4\hbox to \dimen0{\exmthfont#2\leaders\hbox{#3}\hfill#4}%
+ \delimitershortfall=0pt
+ \nulldelimiterspace=0pt
+ \setbox2\hbox{$\left\delimiter"0270370 \vrule height\ht0 depth \dp0 width0pt
+ \right.$}%
+ \mathord{\vcenter{\hbox{\copy2
+ \rlap{\raise\dimexpr\ht2-\ht4\relax\copy4}\copy0}}}%
+ \endgroup}
+
+\def\mthfrac#1#2#3#4#5{\mathchoice
+ {\domthfrac\displaystyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\textstyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptstyle \scriptface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptscriptstyle\scriptscriptface{#1}{#2}{#3}{#4}{#5}}}
+
+\def\mthsqrt#1#2#3{\mathchoice
+ {\domthsqrt\displaystyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\textstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptscriptstyle\textface {#1}{#2}{#3}}}
+
+% temp here
+
+\protect \endinput
diff --git a/tex/context/base/math-ini.lua b/tex/context/base/math-ini.lua
new file mode 100644
index 000000000..63d7cad38
--- /dev/null
+++ b/tex/context/base/math-ini.lua
@@ -0,0 +1,340 @@
+if not modules then modules = { } end modules ['math-ext'] = {
+ version = 1.001,
+ comment = "companion to math-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- if needed we can use the info here to set up xetex definition files
+-- the "8000 hackery influences direct characters (utf) as indirect \char's
+
+local utf = unicode.utf8
+
+local texsprint, format, utfchar, utfbyte = tex.sprint, string.format, utf.char, utf.byte
+
+local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end)
+
+mathematics = mathematics or { }
+
+mathematics.extrabase = 0xFE000 -- here we push some virtuals
+mathematics.privatebase = 0xFF000 -- here we push the ex
+
+local families = {
+ tf = 0, it = 1, sl = 2, bf = 3, bi = 4, bs = 5, -- virtual fonts or unicode otf
+}
+
+local classes = {
+ ord = 0, -- mathordcomm mathord
+ op = 1, -- mathopcomm mathop
+ bin = 2, -- mathbincomm mathbin
+ rel = 3, -- mathrelcomm mathrel
+ open = 4, -- mathopencomm mathopen
+ close = 5, -- mathclosecomm mathclose
+ punct = 6, -- mathpunctcomm mathpunct
+ alpha = 7, -- mathalphacomm firstofoneargument
+ accent = 8, -- class 0
+ radical = 9,
+ xaccent = 10, -- class 3
+ topaccent = 11, -- class 0
+ botaccent = 12, -- class 0
+ under = 13,
+ over = 14,
+ delimiter = 15,
+ inner = 0, -- mathinnercomm mathinner
+ nothing = 0, -- mathnothingcomm firstofoneargument
+ choice = 0, -- mathchoicecomm @@mathchoicecomm
+ box = 0, -- mathboxcomm @@mathboxcomm
+ limop = 1, -- mathlimopcomm @@mathlimopcomm
+ nolop = 1, -- mathnolopcomm @@mathnolopcomm
+}
+
+mathematics.families = families
+mathematics.classes = classes
+
+classes.alphabetic = classes.alpha
+classes.unknown = classes.nothing
+classes.default = classes.nothing
+classes.punctuation = classes.punct
+classes.normal = classes.nothing
+classes.opening = classes.open
+classes.closing = classes.close
+classes.binary = classes.bin
+classes.relation = classes.rel
+classes.fence = classes.unknown
+classes.diacritic = classes.accent
+classes.large = classes.op
+classes.variable = classes.alphabetic
+classes.number = classes.alphabetic
+
+-- there will be proper functions soon (and we will move this code in-line)
+-- no need for " in class and family (saves space)
+
+local function delcode(target,family,slot)
+ return format('\\Udelcode%s="%X "%X ',target,family,slot)
+end
+local function mathchar(class,family,slot)
+ return format('\\Umathchar "%X "%X "%X ',class,family,slot)
+end
+local function mathaccent(class,family,slot)
+ return format('\\Umathaccent "%X "%X "%X ',0,family,slot) -- no class
+end
+local function delimiter(class,family,slot)
+ return format('\\Udelimiter "%X "%X "%X ',class,family,slot)
+end
+local function radical(family,slot)
+ return format('\\Uradical "%X "%X ',family,slot)
+end
+local function mathchardef(name,class,family,slot)
+ return format('\\Umathchardef\\%s "%X "%X "%X ',name,class,family,slot)
+end
+local function mathcode(target,class,family,slot)
+ return format('\\Umathcode%s="%X "%X "%X ',target,class,family,slot)
+end
+local function mathtopaccent(class,family,slot)
+ return format('\\Umathaccent "%X "%X "%X ',0,family,slot) -- no class
+end
+local function mathbotaccent(class,family,slot)
+ return format('\\Umathbotaccent "%X "%X "%X ',0,family,slot) -- no class
+end
+local function mathtopdelimiter(class,family,slot)
+ return format('\\Uoverdelimiter "%X "%X ',0,family,slot) -- no class
+end
+local function mathbotdelimiter(class,family,slot)
+ return format('\\Uunderdelimiter "%X "%X ',0,family,slot) -- no class
+end
+
+local escapes = characters.filters.utf.private.escapes
+
+local function setmathsymbol(name,class,family,slot)
+ if class == classes.accent then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathaccent(class,family,slot)))
+ elseif class == classes.topaccent then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathtopaccent(class,family,slot)))
+ elseif class == classes.botaccent then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathbotaccent(class,family,slot)))
+ elseif class == classes.over then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathtopdelimiter(class,family,slot)))
+ elseif class == classes.under then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathbotdelimiter(class,family,slot)))
+ elseif class == classes.open or class == classes.close then
+ texsprint(delcode(slot,family,slot))
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,delimiter(class,family,slot)))
+ elseif class == classes.delimiter then
+ texsprint(delcode(slot,family,slot))
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,delimiter(0,family,slot)))
+ elseif class == classes.radical then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,radical(family,slot)))
+ else
+ -- beware, open/close and other specials should not end up here
+--~ local ch = utfchar(slot)
+--~ if escapes[ch] then
+--~ texsprint(format("\\xdef\\%s{\\char%s }",name,slot))
+--~ else
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathchar(class,family,slot)))
+--~ end
+ end
+end
+
+local function setmathcharacter(class,family,slot,unicode,firsttime)
+ if not firsttime and class <= 7 then
+ texsprint(mathcode(slot,class,family,unicode or slot))
+ end
+end
+
+local function setmathsynonym(class,family,slot,unicode,firsttime)
+ if not firsttime and class <= 7 then
+ texsprint(mathcode(slot,class,family,unicode))
+ end
+ if class == classes.open or class == classes.close then
+ texsprint(delcode(slot,family,unicode))
+ end
+end
+
+local function report(class,family,unicode,name)
+ local nametype = type(name)
+ if nametype == "string" then
+ logs.report("mathematics","%s:%s %s U+%05X (%s) => %s",classname,class,family,unicode,utfchar(unicode),name)
+ elseif nametype == "number" then
+ logs.report("mathematics","%s:%s %s U+%05X (%s) => U+%05X",classname,class,family,unicode,utfchar(unicode),name)
+ else
+ logs.report("mathematics","%s:%s %s U+%05X (%s)", classname,class,family,unicode,utfchar(unicode))
+ end
+end
+
+-- there will be a combined \(math)chardef
+
+function mathematics.define(slots,family)
+ family = family or 0
+ family = families[family] or family
+ local data = characters.data
+ for unicode, character in next, data do
+ local symbol = character.mathsymbol
+ if symbol then
+ local other = data[symbol]
+ local class = other.mathclass
+ if class then
+ class = classes[class] or class -- no real checks needed
+ if trace_defining then
+ report(class,family,unicode,symbol)
+ end
+ setmathsynonym(class,family,unicode,symbol)
+ end
+ local spec = other.mathspec
+ if spec then
+ for i, m in next, spec do
+ local class = m.class
+ if class then
+ class = classes[class] or class -- no real checks needed
+ setmathsynonym(class,family,unicode,symbol,i)
+ end
+ end
+ end
+ end
+ local mathclass = character.mathclass
+ local mathspec = character.mathspec
+ if mathspec then
+ for i, m in next, mathspec do
+ local name = m.name
+ local class = m.class
+ if not class then
+ class = mathclass
+ elseif not mathclass then
+ mathclass = class
+ end
+ if class then
+ class = classes[class] or class -- no real checks needed
+ if name then
+ if trace_defining then
+ report(class,family,unicode,name)
+ end
+ setmathsymbol(name,class,family,unicode)
+ -- setmathcharacter(class,family,unicode,unicode,i)
+ else
+ name = class == classes.variable or class == classes.number and character.adobename
+ if name then
+ if trace_defining then
+ report(class,family,unicode,name)
+ end
+ -- setmathcharacter(class,family,unicode,unicode,i)
+ end
+ end
+ setmathcharacter(class,family,unicode,unicode,i)
+ end
+ end
+ end
+ if mathclass then
+ local name = character.mathname
+ local class = classes[mathclass] or mathclass -- no real checks needed
+ if name == false then
+ if trace_defining then
+ report(class,family,unicode,name)
+ end
+ setmathcharacter(class,family,unicode)
+ else
+ name = name or character.contextname
+ if name then
+ if trace_defining then
+ report(class,family,unicode,name)
+ end
+ setmathsymbol(name,class,family,unicode)
+ else
+ if trace_defining then
+ report(class,family,unicode,character.adobename)
+ end
+ end
+ setmathcharacter(class,family,unicode,unicode)
+ end
+ end
+ end
+end
+
+-- needed for mathml analysis
+
+function mathematics.utfmathclass(chr, default)
+ local cd = characters.data[utfbyte(chr)]
+ return (cd and cd.mathclass) or default or "unknown"
+end
+function mathematics.utfmathstretch(chr, default) -- "h", "v", "b", ""
+ local cd = characters.data[utfbyte(chr)]
+ return (cd and cd.mathstretch) or default or ""
+end
+function mathematics.utfmathcommand(chr, default)
+ local cd = characters.data[utfbyte(chr)]
+ local cmd = cd and cd.mathname
+ tex.sprint(cmd or default or "")
+end
+function mathematics.utfmathfiller(chr, default)
+ local cd = characters.data[utfbyte(chr)]
+ local cmd = cd and (cd.mathfiller or cd.mathname)
+ tex.sprint(cmd or default or "")
+end
+
+mathematics.entities = mathematics.entities or { }
+
+function mathematics.register_xml_entities()
+ local entities = xml.entities
+ for name, unicode in next, mathematics.entities do
+ if not entities[name] then
+ entities[name] = utfchar(unicode)
+ end
+ end
+end
+
+-- helpers
+
+function mathematics.big(tfmdata,unicode,n)
+ local t = tfmdata.characters
+ local c = t[unicode]
+ if c then
+ local vv = c.vert_variants or c.next and t[c.next].vert_variants
+ if vv then
+ local vvn = vv[n]
+ return vvn and vvn.glyph or vv[#vv].glyph or unicode
+ else
+ local next = c.next
+ while next do
+ if n <= 1 then
+ return next
+ else
+ n = n - 1
+ local tn = t[next].next
+ if tn then
+ next = tn
+ else
+ return next
+ end
+ end
+ end
+ end
+ end
+ return unicode
+end
+
+-- plugins
+
+local hvars = table.tohash {
+ --~ "RadicalKernBeforeDegree",
+ --~ "RadicalKernAfterDegree",
+}
+
+function mathematics.scaleparameters(t,tfmtable,delta,hdelta,vdelta)
+ local math_parameters = tfmtable.math_parameters
+ if math_parameters and next(math_parameters) then
+ delta = delta or 1
+ hdelta, vdelta = hdelta or delta, vdelta or delta
+ local _, mp = mathematics.dimensions(math_parameters)
+ for name, value in next, mp do
+ if name == "RadicalDegreeBottomRaisePercent" then
+ mp[name] = value
+ elseif hvars[name] then
+ mp[name] = hdelta * value
+ else
+ mp[name] = vdelta * value
+ end
+ end
+ t.MathConstants = mp
+ end
+end
+
+table.insert(fonts.tfm.mathactions,mathematics.scaleparameters)
diff --git a/tex/context/base/math-ini.mkii b/tex/context/base/math-ini.mkii
new file mode 100644
index 000000000..f9dd859c4
--- /dev/null
+++ b/tex/context/base/math-ini.mkii
@@ -0,0 +1,684 @@
+%D \module
+%D [ file=math-ini,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Initializations,
+%D author={Hans Hagen \& Taco Hoekwater},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Math Macros / Initializations}
+
+% todo: make all definitions global since file loaded only once
+
+%D This module provides namespaces for math fonts, thereby
+%D permitting mixed usage of math fonts. Although not strictly
+%D needed, we also provide a family name mapping mechanism as
+%D used in the (original) AMS math definition files, but here
+%D these names can recursively be remapped and if needed,
+%D dynamically be changed. We've tried to minimize the number
+%D of definition commands and use plain \TEX\ definitions as
+%D fallback. We've tried to follow a couple of conventions
+%D from plain and AMS math in order to achieve backward
+%D compatinility. We also kept an eye on future usage of these
+%D modules in the perspective of MathML and unicode fonts.
+
+\unprotect
+
+\def\@ml@{@ml@} % math list (used for collection)
+\def\@mf@{@mf@} % math family
+%def\@mh@{@mh@} % math handler (not used)
+\def\@mt@{@mt@} % math token
+\def\@mc@{@mc@} % math collection
+
+\def\@@mathlimopcomm#1{\mathop{#1}} %no \limits
+\def\@@mathnolopcomm#1{\mathop{#1}\nolimits}
+\def\@@mathboxcomm #1{\dontleavehmode\hbox{$\mathsurround\zeropoint#1$}}
+
+\chardef\mathordcode = 0 \let\mathordcomm \mathord
+\chardef\mathopcode = 1 \let\mathopcomm \mathop
+\chardef\mathbincode = 2 \let\mathbincomm \mathbin
+\chardef\mathrelcode = 3 \let\mathrelcomm \mathrel
+\chardef\mathopencode = 4 \let\mathopencomm \mathopen
+\chardef\mathclosecode = 5 \let\mathclosecomm \mathclose
+\chardef\mathpunctcode = 6 \let\mathpunctcomm \mathpunct
+\chardef\mathalphacode = 7 \let\mathalphacomm \firstofoneargument
+\chardef\mathinnercode = 0 \let\mathinnercomm \mathinner
+\chardef\mathnothingcode= 0 \let\mathnothingcomm \firstofoneargument
+\chardef\mathlimopcode = 1 \let\mathlimopcomm \@@mathlimopcomm
+\chardef\mathnolopcode = 1 \let\mathnolopcomm \@@mathnolopcomm
+\chardef\mathchoicecode = 0 \let\mathchoicecomm \@@mathchoicecomm
+\chardef\mathboxcode = 0 \let\mathboxcomm \@@mathboxcomm
+
+\chardef\mathaccentcode = 8
+\chardef\mathradicalcode= 9
+
+\def\@@mathchoicecomm#1{[todo #1]}
+
+\def\puremathcode#1{\the\csname math#1code\endcsname}
+\def\puremathcomm#1{\csname math#1comm\endcsname}
+
+\newif\iftracemathcollection
+
+% Simple variant:
+%
+% \def\dohandlemathtoken#1%
+% {\csname\@mt@
+% \ifcsname\@mt@\mathcollection#1\endcsname
+% \mathcollection
+% \else\ifcsname\@mt@\nomathcollection#1\endcsname
+% \nomathcollection
+% \fi\fi
+% #1\endcsname}
+
+%D Because a command can have a different meaning in math
+%D and in text mode, we provide a selector. We also provide
+%D the pure alternatives as \type {\mathcharacter} and \type
+%D {\textcharacter}.
+
+% \ifx\dohandlecommand\undefined \wait \fi % troubles ! but not in mkiv so ...
+
+\let\mathcharacter\dohandlemathtoken
+\let\textcharacter\dohandlecommand % better \dohandletexttoken
+
+% More clever layout:
+%
+% \def\dohandlemathtoken#1%
+% {\csname
+% \ifmmode
+% \ifcsname\@mt@\mathcollection#1\endcsname
+% \@mt@\mathcollection
+% \else\ifcsname\@mt@\nomathcollection#1\endcsname
+% \@mt@\nomathcollection
+% \else\ifcsname\characterencoding#1\endcsname
+% \characterencoding
+% \else
+% \nocharacterencoding
+% \fi\fi\fi
+% \else
+% \ifcsname\characterencoding#1\endcsname
+% \characterencoding
+% \else
+% \nocharacterencoding
+% \fi
+% \fi
+% #1\endcsname}
+%
+% fallback to math when in text mode (handy for unicode vectors)
+
+\def\dohandlemathtoken#1%
+ {\csname
+ \ifmmode
+ \ifcsname\@mt@\mathcollection#1\endcsname
+ \@mt@\mathcollection
+ \else\ifcsname\@mt@\nomathcollection#1\endcsname
+ \@mt@\nomathcollection
+ \else\ifcsname\characterencoding#1\endcsname
+ \characterencoding
+ \else
+ \nocharacterencoding
+ \fi\fi\fi
+ \else
+ \ifcsname\characterencoding#1\endcsname
+ \characterencoding
+ \else\ifcsname\nocharacterencoding#1\endcsname
+ \nocharacterencoding
+ \else\ifcsname\@mt@\mathcollection#1\endcsname
+ \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\mathcollection
+ \else\ifcsname\@mt@\nomathcollection#1\endcsname
+ \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\nomathcollection
+ \else
+ \nocharacterencoding
+ \fi\fi\fi\fi
+ \fi
+ #1\endcsname}
+
+%D Now we redefine the text encoding handler.
+
+%D A better fallback:
+
+% Just ETEX which is the default nowadays.
+
+\def\dohandlemathtoken#1%
+ {\csname
+ \ifmmode
+ \ifcsname\@mt@\mathcollection:\outerencoding#1\endcsname
+ \@mt@\mathcollection:\outerencoding
+ \else\ifcsname\@mt@\mathcollection#1\endcsname
+ \@mt@\mathcollection
+ \else\ifcsname\@mt@\nomathcollection#1\endcsname
+ \@mt@\nomathcollection
+ \else\ifcsname\characterencoding#1\endcsname
+ \characterencoding
+ \else
+ \nocharacterencoding
+ \fi\fi\fi\fi
+ \else
+ \ifcsname\characterencoding#1\endcsname
+ \characterencoding
+ \else\ifcsname\nocharacterencoding#1\endcsname
+ \nocharacterencoding
+ \else\ifcsname\@mt@\mathcollection:\outerencoding#1\endcsname
+ \@mt@\mathcollection:\outerencoding
+ \else\ifcsname\@mt@\mathcollection#1\endcsname
+ \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\mathcollection
+ \else\ifcsname\@mt@\nomathcollection#1\endcsname
+ \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\nomathcollection
+ \else
+ \nocharacterencoding
+ \fi\fi\fi\fi\fi
+ \fi
+ #1\endcsname}
+
+\let\dohandlecommand\dohandlemathtoken
+
+\def\definefamilysynonym
+ {\dotripleempty\dodefinefamilysynonym}
+
+\def\dodefinefamilysynonym[#1][#2][#3]% [mathcollection] [] []
+ {\ifthirdargument
+ \setvalue{\@mf@#1#2}{#3}%
+ \else
+ \setvalue{\@mf@ #1}{#2}%
+ \fi}
+
+\let\mathsubfamily\empty
+
+\def\purefamily #1{\csname \truefamily{#1}\mathsubfamily\s!fam\endcsname}
+\def\purefamilyhex#1{\csname hex\truefamily{#1}\mathsubfamily\s!fam\endcsname}
+
+\def\truefamily#1%
+ {\ifcsname\@mf@\mathcollection#1\endcsname
+ \@EA\truefamily\csname\@mf@\mathcollection#1\endcsname
+ \else\ifcsname\@mf@#1\endcsname
+ \@EA\truefamily\csname\@mf@#1\endcsname
+ \else\ifcsname\@mf@\nomathcollection#1\endcsname
+ \@EA\truefamily\csname\@mf@\nomathcollection#1\endcsname
+ \else
+ #1%
+ \fi\fi\fi}
+
+\newif\ifdynamicmathfamilies \dynamicmathfamiliestrue % true per 2003.11.25; needed for mixed bold math
+
+\let\normalpurefamilyhex\purefamilyhex
+
+% todo: reset collection (tok legen) en opnieuw laden met true
+
+\def\definemathsymbol
+ {\dosixtupleempty\dodefinemathsymbol}
+
+\def\dodefinemathsymbol[#1][#2][#3][#4][#5][#6]%
+ {\unexpanded\setgvalue{#1}{\dohandlemathtoken{#1}}%
+ \ifdynamicmathfamilies \let\purefamilyhex\relax \fi
+ \setevalue{\@mt@\mathcollection#1}%
+ {\ifsixthargument
+ \ifnum\puremathcode{#2}=\mathradicalcode
+ \radical"%
+ \else
+ \delimiter"%
+ \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+ \fi
+ \purefamilyhex{#3}\uchexnumbers{#4}%
+ \purefamilyhex{#5}\uchexnumbers{#6}\space
+ \else\iffourthargument
+ \ifnum\puremathcode{#2}=\mathaccentcode
+ \mathaccent\else\mathchar
+ \fi
+ "\ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+ \purefamilyhex{#3}\uchexnumbers{#4}\space
+ \fi\fi}%
+ \let\purefamilyhex\normalpurefamilyhex
+ \tracemathsymbol{#1}}
+
+\def\tracemathsymbol#1%
+ {\iftracemathcollection
+ {\endgraf
+ \hbox{\tex{#1}~:~{\mathematics{\getvalue{#1}{}}}}
+ \endgraf}%
+ \fi}
+
+\def\definemathcharacter
+ {\dosixtupleempty\dodefinemathcharacter}
+
+% \def\dodefinemathcharacter[#1][#2][#3][#4][#5][#6]%
+% {\setmathtoks
+% \ifdynamicmathfamilies \let\purefamilyhex\relax \fi
+% \doifnumberelse{#1}
+% {\scratchcounter#1}
+% {\scratchcounter\@EA`\string#1}%
+% \appendetoks
+% \ifsixthargument
+% \delcode\the\scratchcounter="%
+% \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+% \purefamilyhex{#3}\uchexnumbers{#4}%
+% \purefamilyhex{#5}\uchexnumbers{#6}\space
+% \else\iffourthargument
+% \mathcode\the\scratchcounter="%
+% \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+% \purefamilyhex{#3}\uchexnumbers{#4}\space
+% \fi\fi\to\mathtoks
+% \let\purefamilyhex\normalpurefamilyhex
+% \tracemathcharacter{#1}}
+
+\newtoks\mathscratchtoks
+
+\def\definemathcharacter
+ {\chardef\mathcharactermode\zerocount
+ \dosixtupleempty\dodefinemathcharacter}
+
+\def\redefinemathcharacter
+ {\chardef\mathcharactermode\plusone
+ \dosixtupleempty\dodefinemathcharacter}
+
+\def\dodefinemathcharacter[#1][#2][#3][#4][#5][#6]%
+ {\ifcase\mathcharactermode
+ \setmathtoks
+ \or
+ \let\mathtoks\mathscratchtoks \mathtoks\emptytoks
+ \fi
+ \ifdynamicmathfamilies \let\purefamilyhex\relax \fi
+ \doifnumberelse{#1}
+ {\scratchcounter#1}
+ {\scratchcounter\@EA`\string#1}%
+ \appendetoks
+ \ifsixthargument
+ \delcode\the\scratchcounter="%
+ \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+ \purefamilyhex{#3}\uchexnumbers{#4}%
+ \purefamilyhex{#5}\uchexnumbers{#6}\space
+ \else\iffourthargument
+ \mathcode\the\scratchcounter="%
+ \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+ \purefamilyhex{#3}\uchexnumbers{#4}\space
+ \fi\fi
+ \to \mathtoks
+ \let\purefamilyhex\normalpurefamilyhex
+ \ifcase\mathcharactermode
+ \expandafter\tracemathcharacter
+ \or
+ \the\mathtoks
+ \mathtoks\emptytoks
+ \expandafter\gobbleoneargument
+ \fi{#1}} % maybe lookahead
+
+\def\tracemathcharacter#1%
+ {\iftracemathcollection
+ {\endgraf
+ \doifnumberelse{#1}
+ {\hbox{\tttf\rawcharacter{#1}~:~{\mathematics{\rawcharacter{#1}}}}}
+ {\hbox{\type{#1}~:~{\mathematics{#1}}}}
+ \endgraf}%
+ \fi}
+
+\def\definemathcommand
+ {\dotripleempty\dodefinemathcommand}
+
+\def\dodefinemathcommand[#1][#2][#3]#4% command class args meaning
+ {\unexpanded\setgvalue{#1}{\dohandlemathtoken{#1}}%
+ \ifthirdargument
+ \processaction
+ [#3]
+ [one=>\setvalue{\@mt@\mathcollection#1}##1{\puremathcomm{#2}{#4{##1}}},
+ two=>\setvalue{\@mt@\mathcollection#1}##1##2{\puremathcomm{#2}{#4{##1}{##2}}}]%
+ \else\ifsecondargument
+ \setvalue{\@mt@\mathcollection#1}{\puremathcomm{#2}{#4}}%
+ \else
+ \setvalue{\@mt@\mathcollection#1}{\puremathcomm{nothing}{#4}}%
+ \fi\fi
+ \tracemathcommand{#1}}
+
+\def\tracemathcommand#1%
+ {\iftracemathcollection
+ \endgraf\hbox{\tex{#1}~:~{\mathematics{\getvalue{#1}{}}}}\endgraf
+ \fi}
+
+\def\startmathcollection[#1]%
+ {\pushmacro\mathcollection
+ \setmathcollection{#1}}
+
+\def\setmathcollection#1%
+ {\edef\mathcollection{#1}%
+ \doifundefined{\@ml@\mathcollection}
+ {\expandafter\newtoks\csname\@ml@\mathcollection\endcsname}}
+
+\def\stopmathcollection
+ {\popmacro\mathcollection}
+
+\def\startrawmathcollection
+ {\startmathcollection}
+
+\def\stoprawmathcollection
+ {\stopmathcollection}
+
+\newtoks\mathtoks
+
+\def\setmathtoks
+ {\@EA\let\@EA\mathtoks\csname\@ml@\mathcollection\endcsname}
+
+\def\currentmathcollection{\mathcollection}
+
+\let\nomathcollection\s!default
+
+\def\enablemathcollection[#1]%
+ {\doifnot{#1}\s!default
+ {\setmathcollection\s!default
+ \the\csname\@ml@\mathcollection\endcsname}%
+ \setmathcollection{#1}%
+ \the\csname\@ml@\mathcollection\endcsname}
+
+% hook 'm into the font mechanism
+
+\definefilesynonym[\f!mathprefix\s!default][\f!mathprefix tex]
+
+\def\usemathcollection
+ {\dodoubleempty\dousemathcollection}
+
+\def\dousemathcollection[#1][#2]%
+ {\pushmacro\fontclass
+ \pushmacro\mathclass
+ \ifsecondargument
+ \edef\fontclass{#1}%
+ \edef\mathclass{#2}%
+ \else
+ \edef\mathclass{#1}%
+ \fi
+ \doinputonce{\truefilename{\f!mathprefix\mathclass}.mkii}%
+ \doifsomething\fontclass{\setevalue{\@mc@\fontclass\@mc@}{\mathclass}}%
+ \popmacro\mathclass
+ \popmacro\fontclass}
+
+\let\mathclass\nomathcollection
+
+\letvalue{\@mc@\@mc@}\nomathcollection
+
+% \def\autoenablemathcollection
+% {\doifdefinedelse{\@mc@\fontclass\@mc@}
+% {\enablemathcollection[\getvalue{\@mc@\fontclass\@mc@}]}
+% {\enablemathcollection[\s!default]}} % ? ? ?
+
+\def\autoenablemathcollection
+ {\expanded{\enablemathcollection[\executeifdefined{\@mc@\fontclass\@mc@}\nomathcollection]}}
+
+\appendtoks\autoenablemathcollection\to\mathstrategies
+
+\fetchruntimecommand \showmathcharacters {\f!mathprefix\s!run.mkii}
+\fetchruntimecommand \showmathtoken {\f!mathprefix\s!run.mkii}
+
+\def\resetmathcollection[#1]%
+ {\def\mathcollection{#1}%
+ \forgetdoingonce{\f!mathprefix\mathcollection.mkii}%
+ \setmathtoks
+ \ifx\mathtoks\relax\else\mathtoks\emptytoks\fi}
+
+%D \macros
+%D {ifmathpunctuation, enablemathpunctuation,
+%D definemathpunctuation}
+%D
+%D This will replace periods by comma's:
+%D
+%D \starttyping
+%D \definemathpunctuation . textcomma textperiod
+%D \definemathpunctuation , textcomma textcomma
+%D
+%D \appendtoks
+%D \redefinemathcharacter [.] [ord] [mi] ["3B]%
+%D \to \everymathpunctuation
+%D \stoptyping
+
+% \newif\ifmathpunctuation
+%
+% \def\enablemathpunctuation{\mathpunctuationtrue}
+%
+% \def\definemathpunctuation #1 #2 #3 %
+% {\appendtoks
+% \initializemathpunctuation{#1}{#2}{#3}%
+% \to\everymathematics}
+%
+% \def\initializemathpunctuation#1#2#3% sloowww
+% {\ifmathpunctuation % hm move this test to everymath, or better a separate token list
+% \mathcode`#1="8000
+% \defineactivecharacter #1 {\dohandlemathpunctuation{#2}{#3}}%
+% \fi}
+%
+% \unexpanded\def\dohandlemathpunctuation#1#2% \if fails in mathml interval
+% {\def\next{\csname\ifx\space\nexttoken#2\else#1\fi\endcsname}%
+% \futurelet\nexttoken\next}
+
+\newtoks\everymathpunctuation
+
+\def\enablemathpunctuation % can be called inside math, so after \everymathematics
+ {\relax
+ \ifmmode
+ \the\everymathpunctuation
+ \fi
+ \appendtoksonce
+ \the\everymathpunctuation
+ \to\everymathematics}
+
+\def\definemathpunctuation #1 #2 #3 %
+ {\appendtoks
+ \initializemathpunctuation{#1}{#2}{#3}%
+ \to\everymathpunctuation}
+
+\def\initializemathpunctuation#1#2#3% sloowww
+ {\mathcode`#1="8000
+ \defineactivecharacter #1 {\dohandlemathpunctuation{#2}{#3}}}
+
+\unexpanded\def\dohandlemathpunctuation#1#2% \if fails in mathml interval
+ {\def\next{\csname\ifx\space\nexttoken#2\else#1\fi\endcsname}%
+ \futurelet\nexttoken\next}
+
+%D \startbuffer
+%D \enablemathpunctuation$(1,2) (1, 2) (1{,}2) \hbox{foo, not bar}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \blank{\getbuffer}\blank
+
+%D needed for sin, cos etc
+
+\def\mfunction #1{{\mr#1}}
+
+% \def\mlimitsfunction #1{\mathlimopcomm{{\mr#1}}
+% \def\mnolimitsfunction#1{\mathnolopcomm{{\mr#1}}
+
+%D Taco posted this solution as response to a mail by Olivier, so
+%D let's integrate it here.
+
+% \def\setmathfunctionstyle#1% rm ss tt
+% {\def\mfunction##1% no families, just scaling a la text
+% {\mathchoice
+% {\hbox{\csname#1\endcsname\tf ##1}}
+% {\hbox{\csname#1\endcsname\tf ##1}}
+% {\hbox{\csname#1\endcsname\tfx ##1}}
+% {\hbox{\csname#1\endcsname\tfxx##1}}}}
+
+\def\currentmscaledstyle{rm} % will be plugged into the typeface text=ss option
+
+\def\setmathfunctionstyle#1% rm ss tt
+ {\doifsomething{#1}
+ {\def\currentmscaledstyle{#1}%
+ \def\mathopnolimits##1{\mathop{\mscaledtext{##1}}\nolimits}%
+ \def\mfunction##1{\mscaledtext{##1}}}}
+
+\def\mscaledtext#1%
+ {\mathchoice
+ {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tfx #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tfxx#1}}}
+
+%D We can force the way functions are typeset by manipulating the text
+%D option:
+%D
+%D \starttyping
+%D \definetypeface[iwona][ss][sans][iwona][default][encoding=texnansi]
+%D \definetypeface[iwona][mm][math][iwona][default][encoding=texnansi,text=ss]
+%D \stoptyping
+%D
+%D This hooks into the math handler with:
+
+\appendtoks
+ \setmathfunctionstyle\currentmathtextstyle
+\to \everybodyfont
+
+%D Usage:
+%D
+%D \starttyping
+%D \setmathfunctionstyle\fontstyle % or {rm} or {ss} or ..
+%D \rm test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \ss test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \tt test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \stoptyping
+
+\edef\hexmrfam {0} \edef\hexbsfam {8}
+\edef\hexmifam {1} \edef\hexbifam {9}
+\edef\hexsyfam {2} \edef\hexscfam {A}
+\edef\hexexfam {3} \edef\hextffam {B}
+\edef\hexitfam {4} \edef\hexmafam {C}
+\edef\hexslfam {5} \edef\hexmbfam {D}
+\edef\hexbffam {6} \edef\hexmcfam {E}
+\edef\hexnnfam {7} \edef\hexmdfam {F}
+
+\definefamilysynonym [default] [letters] [mr]
+\definefamilysynonym [default] [operators] [sy]
+\definefamilysynonym [default] [lcgreek] [mi]
+\definefamilysynonym [default] [ucgreek] [mr]
+\definefamilysynonym [default] [vargreek] [mi]
+\definefamilysynonym [default] [mitfamily] [mi]
+\definefamilysynonym [default] [calfamily] [sy]
+
+\definefamilysynonym [default] [0] [mr]
+\definefamilysynonym [default] [1] [mi]
+\definefamilysynonym [default] [2] [sy]
+\definefamilysynonym [default] [3] [ex]
+
+\enablemathcollection[default]
+
+\usemathcollection [default] [tex]
+\usemathcollection [default] [ams]
+\usemathcollection [default] [uni]
+
+\enablemathcollection[default]
+
+%D Some goodies:
+
+\def\Angstrom{\nomathematics{\Aring}}
+
+%D Bold math:
+%D
+%D \starttyping
+%D \usetypescript [lucida] [texnansi]
+%D
+%D \definetypeface [boldmath] [rm] [serif]
+%D [lucida] [default] [encoding=texnansi]
+%D \definetypeface [boldmath] [tt] [mono]
+%D [lucida] [default] [encoding=texnansi]
+%D \definetypeface [boldmath] [ss] [sans]
+%D [lucida] [default] [encoding=texnansi]
+%D \definetypeface [boldmath] [mm] [boldmath]
+%D [lucida] [default] [encoding=texnansi]
+%D
+%D \switchtobodyfont[lucida,10pt]
+%D
+%D \showmathtoken{Gamma} $\Gamma \Delta \alpha \delta \zeta$
+%D
+%D \switchtobodyfont[boldmath,10pt]
+%D
+%D \showmathtoken{Gamma} $\Gamma \Delta \alpha \delta \zeta$
+%D \stoptyping
+
+%D \macros
+%D {nonknuthmode, donknuthmode}
+%D
+%D The underscore is frequently used in manuals but unfortunately \TEX\ prefers
+%D it to be a math specific character. And since computer modern fonts didn't
+%D have an underscore, one had to use commands to fake one. Nowadays we do
+%D have underscores in latin modern, and since all other fonts have them, we
+%D decided to get away from the restriction to use the underscore character in
+%D text mode.
+%D
+%D \starttyping
+%D \def\test#1{#1}
+%D
+%D \nonknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
+%D
+%D \donknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
+%D \stoptyping
+%D
+%D The result is as expected: the first line typesets ok, while the second
+%D one triggers an error message.
+
+\bgroup
+
+ \ifx\normalsuber\undefined \def\normalsuber{_} \fi
+ \ifx\normalsuper\undefined \def\normalsuper{^} \fi
+
+ \catcode`_=\active
+ \catcode`^=\active
+
+ \gdef\nonknuthmode
+ {\appendtoks\let_\normalsuber\let^\normalsuper\to\everymathematics
+ \mathcode`_="8000
+ \mathcode`^="8000
+ \catcode`_=\@@other
+ \catcode`^=\@@other
+ \let\nonknuthmode\relax}
+
+ \gdef\donknuthmode
+ {\catcode`_=\@@subscript
+ \catcode`^=\@@superscript}
+
+\egroup
+
+%D \macros
+%D {checkdelimiters, fakeleftdelimiter, fakerightdelimiter}
+%D
+%D Handy for non matching situations (as with mathml):
+%D
+%D \starttyping
+%D \checkdelimiters{... bla bla ...}
+%D \fakeleftdelimiter
+%D ... bla bla ...
+%D \fakerightdelimiter
+%D \stoptyping
+
+\newcount\delimitercount
+
+\def\leftfakedelimiter {\advance\delimitercount\minusone\gobbleoneargument}%
+\def\rightfakedelimiter{\advance\delimitercount\plusone \gobbleoneargument}%
+
+\def\checkdelimiters#1%
+ {\delimitercount\zerocount
+ \setbox\scratchbox\hbox\bgroup
+ \let\left \leftfakedelimiter
+ \let\right\rightfakedelimiter
+ $#1\expandafter$\expandafter
+ \egroup
+ \expandafter\delimitercount\the\delimitercount\relax}
+
+\def\fakeleftdelimiter {\ifnum\delimitercount>\zerocount\left .\fi}
+\def\fakerightdelimiter{\ifnum\delimitercount<\zerocount\right.\fi}
+
+%D Needed for unicode:
+
+\def\nulloperator{\mathortext{\mathop{\null}}{\null}}
+
+%D To be dealt with ...
+
+\mathcode`\ ="8000 % \space
+\mathcode`\'="8000 % ^\prime
+\mathcode`\_="8000 % \_
+
+\protect \endinput
+
+\tracemathcollectiontrue
+ \input math-tex \page
+\setupbodyfont[ams] \enablemathcollection[default] \input math-ams \page
+\setupbodyfont[lbr] \enablemathcollection[lbr] \input math-lbr \page
+\setupbodyfont[eul] \enablemathcollection[eul] \input math-eul \stoptext
diff --git a/tex/context/base/math-ini.mkiv b/tex/context/base/math-ini.mkiv
new file mode 100644
index 000000000..828a6eccb
--- /dev/null
+++ b/tex/context/base/math-ini.mkiv
@@ -0,0 +1,657 @@
+%D \module
+%D [ file=math-ini,
+%D version=2008.01.02,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Initializations,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 Math Macros / Initializations}
+
+%D This module provides namespaces for math fonts, thereby
+%D permitting mixed usage of math fonts. Although not strictly
+%D needed, we also provide a family name mapping mechanism as
+%D used in the (original) AMS math definition files, but here
+%D these names can recursively be remapped and if needed,
+%D dynamically be changed. We've tried to minimize the number
+%D of definition commands and use plain \TEX\ definitions as
+%D fallback. We've tried to follow a couple of conventions
+%D from plain and AMS math in order to achieve backward
+%D compatinility. We also kept an eye on future usage of these
+%D modules in the perspective of MathML and unicode fonts.
+
+\unprotect
+
+\ifx\v!compact\undefined \def\v!compact{compact} \fi
+
+%D New:
+
+\let\startimath\Ustartmath \let\stopimath \Ustopmath
+\let\startdmath\Ustartdisplaymath \let\stopdmath \Ustopmath
+
+%D We move these definitions into the format:
+
+% test [[\char948 \ctxlua{tex.sprint(utf.char(948))}]]
+% test $[[\char948 \ctxlua{tex.sprint(utf.char(948))}]]$
+
+\registerctxluafile{math-ini}{1.001}
+\registerctxluafile{math-dim}{1.001}
+\registerctxluafile{math-ent}{1.001}
+\registerctxluafile{math-ext}{1.001}
+\registerctxluafile{math-vfu}{1.001}
+\registerctxluafile{math-map}{1.001}
+\registerctxluafile{math-noa}{1.001}
+
+\definesystemattribute[mathalphabet] \chardef\mathalphabetattribute \dogetattributeid{mathalphabet}
+\definesystemattribute[mathsize] \chardef\mathsizeattribute \dogetattributeid{mathsize}
+\definesystemattribute[mathpunctuation] \chardef\mathpunctuationattribute \dogetattributeid{mathpunctuation}
+\definesystemattribute[mathgreek] \chardef\mathgreekattribute \dogetattributeid{mathgreek}
+
+% todo: only in mmode
+
+\unexpanded\def\mathgreekupright{\attribute\mathgreekattribute11 }
+\unexpanded\def\mathgreekitalic {\attribute\mathgreekattribute22 }
+\unexpanded\def\mathgreekdefault{\attribute\mathgreekattribute\attributeunsetvalue}
+
+\let\mathgreeknormal\mathgreekupright
+\let\mathgreeknone \mathgreekdefault
+
+\def\setmathattribute#1#2{\ifmmode\ctxlua{mathematics.sync_a_both ("#1","#2")}\fi}
+\def\setmathalphabet #1{\ifmmode\ctxlua{mathematics.sync_a_name ("#1")}\fi}
+\def\setmathstyle #1{\ifmmode\ctxlua{mathematics.sync_a_style("#1")}\fi}
+
+\unexpanded\def\mr {\setmathattribute{regular}{tf}}
+
+\unexpanded\def\mathdefault {\setmathattribute{regular}{it}}
+\unexpanded\def\mathscript {\setmathalphabet{script}}
+\unexpanded\def\mathfraktur {\setmathalphabet{fraktur}}
+\unexpanded\def\mathblackboard{\setmathalphabet{blackboard}}
+
+\unexpanded\def\mathrm{\setmathattribute{rm}{tf}}
+\unexpanded\def\mathss{\setmathattribute{ss}{tf}}
+\unexpanded\def\mathtt{\setmathattribute{tt}{tf}}
+
+\unexpanded\def\mathtf{\setmathstyle{tf}}
+\unexpanded\def\mathbf{\setmathstyle{bf}}
+\unexpanded\def\mathsl{\setmathstyle{sl}}
+\unexpanded\def\mathit{\setmathstyle{it}}
+\unexpanded\def\mathbs{\setmathstyle{bs}}
+\unexpanded\def\mathbi{\setmathstyle{bi}}
+
+\let\tfmath\mathtf % maybe a grouped command
+\let\bfmath\mathbf
+\let\slmath\mathsl
+\let\itmath\mathit
+\let\bsmath\mathbs
+\let\bimath\mathbi
+
+\let\Bbb\mathblackboard
+
+\unexpanded\def\frak {\ifmmode\expandafter\mathfraktur \fi}
+\unexpanded\def\cal {\ifmmode\expandafter\mathscript \fi}
+\unexpanded\def\bbd {\ifmmode\expandafter\mathblackboard\fi}
+\unexpanded\def\blackboard{\ifmmode\expandafter\mathblackboard\fi}
+\unexpanded\def\fraktur {\ifmmode\expandafter\mathfraktur \fi}
+\unexpanded\def\gothic {\ifmmode\expandafter\mathfraktur \fi}
+
+\unexpanded\def\mathcal #1{{\mathscript #1}} % for AMS compatibility
+\unexpanded\def\mathfrak#1{{\mathfraktur #1}} % for AMS compatibility
+\unexpanded\def\mathbb #1{{\mathblackboard#1}} % for AMS compatibility
+
+\let\normalmr\mr
+
+% \prependtoks
+% \let\mr\normalmr
+% \let\rm\mathrm \let\ss\mathss \let\tt\mathtt
+% \let\tf\mathtf \let\bf\mathbf \let\it\mathit \let\sl\mathsl \let\bi\mathbi \let\bs\mathbs
+% \let\frak\mathfraktur \let\cal\mathscript \let\bbd\mathblackboard
+% \mathdefault
+% \to \everymathematics
+
+\let\normaltf\tf \unexpanded\def\tf{\ifmmode\mathtf\else\normaltf\fi}
+\let\normalbf\bf \unexpanded\def\bf{\ifmmode\mathbf\else\normalbf\fi}
+\let\normalit\it \unexpanded\def\it{\ifmmode\mathit\else\normalit\fi}
+\let\normalsl\sl \unexpanded\def\sl{\ifmmode\mathsl\else\normalsl\fi}
+\let\normalbi\bi \unexpanded\def\bi{\ifmmode\mathbi\else\normalbi\fi}
+\let\normalbs\bs \unexpanded\def\bs{\ifmmode\mathbs\else\normalbs\fi}
+
+\let\normalrm\rm \unexpanded\def\rm{\ifmmode\mathrm\else\normalrm\fi}
+\let\normalss\ss \unexpanded\def\ss{\ifmmode\mathss\else\normalss\fi}
+\let\normaltt\tt \unexpanded\def\tt{\ifmmode\mathtt\else\normaltt\fi}
+ \unexpanded\def\mr{\ifmmode \normalmr\fi}
+
+\prependtoks
+% \let\mr\normalmr
+% \let\rm\mathrm \let\ss\mathss \let\tt\mathtt
+% \let\tf\mathtf \let\bf\mathbf \let\it\mathit \let\sl\mathsl \let\bi\mathbi \let\bs\mathbs
+% \let\frak\mathfraktur \let\cal\mathscript \let\bbd\mathblackboard
+ \mathdefault
+\to \everymathematics
+
+%D \macros
+%D {boldsymbol}
+%D
+%D To be done.
+
+\let\mathboldsymbol\relax % yet unsupported, will be
+
+\def\boldsymbol
+ {\mathortext\mathboldsymbol\bold}
+
+%D Helpers:
+
+\def\utfmathclass #1{\ctxlua{tex.sprint(mathematics.utfmathclass ("#1"))}}
+\def\utfmathstretch#1{\ctxlua{tex.sprint(mathematics.utfmathstretch("#1"))}}
+\def\utfmathcommand#1{\ctxlua{tex.sprint(mathematics.utfmathcommand("#1"))}}
+\def\utfmathfiller #1{\ctxlua{tex.sprint(mathematics.utfmathfiller ("#1"))}}
+
+% \def\utfmathclassdefault #1#2{\ctxlua{
+% tex.sprint(mathematics.utfmathclass("#1","#2"))
+% }}
+%
+% \def\utfmathcommanddefault#1#2#3{\ctxlua{
+% local cmd = mathematics.utfmathcommand("#1","") or ""
+% if cmd == "" then
+% commands.cs("#2","#3")
+% else
+% commands.cs(cmd)
+% end}}
+
+% % %
+
+\def\@@mathlimopcomm #1{\mathop{#1}} %no \limits
+\def\@@mathnolopcomm #1{\mathop{#1}\nolimits}
+\def\@@mathboxcomm #1{\dontleavehmode\hbox\Ustartmath\mathsurround\zeropoint#1\Ustopmath}
+\def\@@mathchoicecomm#1{[todo #1]}
+
+\chardef\mathordcode = 0 \let\mathordcomm \mathord
+\chardef\mathopcode = 1 \let\mathopcomm \mathop
+\chardef\mathbincode = 2 \let\mathbincomm \mathbin
+\chardef\mathrelcode = 3 \let\mathrelcomm \mathrel
+\chardef\mathopencode = 4 \let\mathopencomm \mathopen
+\chardef\mathclosecode = 5 \let\mathclosecomm \mathclose
+\chardef\mathpunctcode = 6 \let\mathpunctcomm \mathpunct
+\chardef\mathalphacode = 7 \let\mathalphacomm \firstofoneargument
+\chardef\mathinnercode = 0 \let\mathinnercomm \mathinner
+\chardef\mathnothingcode= 0 \let\mathnothingcomm \firstofoneargument
+\chardef\mathlimopcode = 1 \let\mathlimopcomm \@@mathlimopcomm
+\chardef\mathnolopcode = 1 \let\mathnolopcomm \@@mathnolopcomm
+\chardef\mathchoicecode = 0 \let\mathchoicecomm \@@mathchoicecomm
+\chardef\mathboxcode = 0 \let\mathboxcomm \@@mathboxcomm
+
+\chardef\mathaccentcode = 8
+\chardef\mathradicalcode= 9
+
+\def\puremathcode#1{\the\csname math#1code\endcsname}
+\def\puremathcomm#1{\csname math#1comm\endcsname}
+
+% \startlines
+% $\mathopnolimits{\rm d}x$
+% $\mathopnolimits{\kern\zeropoint \rm d}x$
+% $\puremathcomm{nolop}{\rm d}x$
+% $\puremathcomm{nolop}{\kern\zeropoint\rm d}x$
+% \blank
+% $\puremathcomm{nolop}{\mr d}x$
+% $\puremathcomm{nolop}{\kern\zeropoint\mr d}x$
+% $\mathop{\kern\zeropoint\mr d}x$
+% $\mathopnolimits{\kern\zeropoint d}x$
+% \stoplines
+
+% this will be sorted out:
+
+\let\mathcharacter \getvalue
+\let\textcharacter \getvalue
+\unexpanded\def\definefamilysynonym {\dotripleempty\dodefinefamilysynonym}
+\def\dodefinefamilysynonym [#1][#2][#3]{}
+\unexpanded\def\definemathsymbol {\dosixtupleempty\dodefinemathsymbol}
+\def\dodefinemathsymbol [#1][#2][#3][#4][#5][#6]{}
+\unexpanded\def\definemathcharacter {\dosixtupleempty\dodefinemathcharacter}
+\def\dodefinemathcharacter [#1][#2][#3][#4][#5][#6]{}
+
+\unexpanded\def\definemathcommand
+ {\dotripleempty\dodefinemathcommand}
+
+\def\dodefinemathcommand[#1][#2][#3]#4% command class args meaning
+ {\ifthirdargument
+ \processaction
+ [#3]
+ [one=>\setuvalue{#1}##1{\puremathcomm{#2}{#4{##1}}},
+ two=>\setuvalue{#1}##1##2{\puremathcomm{#2}{#4{##1}{##2}}}]%
+ \else\ifsecondargument
+ \setuvalue{#1}{\puremathcomm{#2}{#4}}%
+ \else
+ \setuvalue{#1}{\puremathcomm{nothing}{#4}}%
+ \fi\fi}
+
+%D Moved from font-ini.mkiv:
+%D
+%D \macros
+%D {mf,mbox,enablembox,mathop}
+%D
+%D Todo:
+
+\unexpanded\def\mf
+ {\csname\fontalternative\endcsname}
+
+\let\normalmathop\mathop
+
+\unexpanded\def\mathop
+ {\normalmathop
+ \bgroup
+ \let\rm\mf
+ \let\next=}
+
+\def\normalmbox
+ {\normalhbox\bgroup\mf
+ \dowithnextbox{\flushnextbox\egroup}\normalhbox}
+
+\def\mbox
+ {\ifmmode\normalmbox\else\normalhbox\fi}
+
+\def\enablembox
+ {\appendtoks
+ \ifx\normalhbox\undefined\let\normalhbox\hbox\fi
+ \let\hbox\mbox
+ \to\everymathematics}
+
+%D needed for sin, cos etc
+
+\let\mathfunction\firstofoneargument
+
+\def\mfunction #1{{\mr#1}}
+\def\mfunctionlabeltext#1{{\mr\mathlabeltext{#1}}}
+
+% \def\mlimitsfunction #1{\mathlimopcomm{{\mr#1}}
+% \def\mnolimitsfunction#1{\mathnolopcomm{{\mr#1}}
+
+%D Taco posted this solution as response to a mail by Olivier, so
+%D let's integrate it here.
+
+\def\currentmscaledstyle{rm} % will be plugged into the typeface text=ss option
+
+\unexpanded\def\do@mathopnolimits #1{\mathop{\mscaledtext{#1}}\nolimits}
+\unexpanded\def\do@mfunction #1{\mscaledtext{#1}}
+\unexpanded\def\do@mfunctionlabeltext#1{\mscaledtext{\mathlabeltext{#1}}}
+
+\def\setmathfunctionstyle#1% rm ss tt (can be made faster if needed)
+ {\doifsomething{#1}
+ {\def\currentmscaledstyle{#1}%
+ \let\mathopnolimits \do@mathopnolimits
+ \let\mfunction \do@mfunction
+ \let\mfunctionlabeltext\do@mfunctionlabeltext}}
+
+\def\mscaledtext#1%
+ {\mathchoice
+ {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tfx #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tfxx#1}}}
+
+%D We can force the way functions are typeset by manipulating the text
+%D option:
+%D
+%D \starttyping
+%D \definetypeface[iwona][ss][sans][iwona][default][encoding=texnansi]
+%D \definetypeface[iwona][mm][math][iwona][default][encoding=texnansi,text=ss]
+%D \stoptyping
+%D
+%D This hooks into the math handler with:
+
+% no longer supported this way, has to be done with \setupmathematics
+%
+% \appendtoks
+% \setmathfunctionstyle\currentmathtextstyle
+% \to \everybodyfont
+
+%D Usage:
+%D
+%D \starttyping
+%D \setmathfunctionstyle\fontstyle % or {rm} or {ss} or ..
+%D \rm test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \ss test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \tt test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \stoptyping
+
+%D Some goodies:
+
+\def\Angstrom{\nomathematics{\Aring}}
+
+%D \macros
+%D {nonknuthmode, donknuthmode}
+%D
+%D The underscore is frequently used in manuals but unfortunately \TEX\ prefers
+%D it to be a math specific character. And since computer modern fonts didn't
+%D have an underscore, one had to use commands to fake one. Nowadays we do
+%D have underscores in latin modern, and since all other fonts have them, we
+%D decided to get away from the restriction to use the underscore character in
+%D text mode.
+%D
+%D \starttyping
+%D \def\test#1{#1}
+%D
+%D \nonknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
+%D
+%D \donknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
+%D \stoptyping
+%D
+%D The result is as expected: the first line typesets ok, while the second
+%D one triggers an error message.
+
+\newtoks\everydonknuthmode
+\newtoks\everynonknuthmode
+
+\def\nonknuthmode{\the\everynonknuthmode\let\nonknuthmode\relax}
+\def\donknuthmode{\the\everydonknuthmode}
+
+\ifdefined\normalsuber\else \def\normalsuber{_} \fi
+\ifdefined\normalsuper\else \def\normalsuper{^} \fi
+\ifdefined\normalaltab\else \def\normalaltab{&} \fi
+
+\bgroup
+
+ \catcode`_=\active
+ \catcode`^=\active
+ \catcode`&=\active
+
+ \global \everynonknuthmode {\appendtoks
+ \let_\normalsuber
+ \let^\normalsuper
+ \let&\normalaltab
+ \to \everymathematics}
+
+\egroup
+
+\appendtoks
+ \mathcode`_="8000
+ \mathcode`^="8000
+ \mathcode`&="8000
+ \catcode`_=\@@other
+ \catcode`^=\@@other
+ \catcode`&=\@@other
+\to \everynonknuthmode
+
+\appendtoks
+ \catcode`_=\@@subscript
+ \catcode`^=\@@superscript
+ \catcode`&=\@@alignment
+\to \everydonknuthmode
+
+\appendtoks
+ \startextendcatcodetable\ctxcatcodes
+ \catcode`_=\@@other
+ \catcode`^=\@@other
+ \catcode`&=\@@other
+ \stopextendcatcodetable
+\to \everynonknuthmode
+
+\appendtoks
+ \startextendcatcodetable\ctxcatcodes
+ \catcode`_=\@@subscript
+ \catcode`^=\@@superscript
+ \catcode`&=\@@alignment
+ \stopextendcatcodetable
+\to \everydonknuthmode
+
+%D Needed for unicode:
+
+\def\nulloperator{\mathortext{\mathop{\null}}{\null}}
+
+%D To be dealt with ...
+
+\mathcode`\ ="8000 % \space
+\mathcode`\'="8000 % ^\prime
+\mathcode`\_="8000 % \_
+
+%D \macros
+%D {setupmathematics}
+%D
+%D Configuration for integrals. (If needed we can speed this up and make it
+%D installable; no processaction is needed then).
+
+\newtoks\everysetupmathematics
+
+\unexpanded\def\setupmathematics
+ {\dosingleargument\dosetupmathematics}
+
+\def\dosetupmathematics[#1]%
+ {\getparameters[\??mo][#1]%
+ \the\everysetupmathematics}
+
+\def\mathematicsparameter#1{\ifcsname\??mo#1\endcsname\csname\??mo#1\endcsname\fi}
+
+%D Memory saver:
+
+\appendtoks
+ \doifelse{\mathematicsparameter\v!compact}\v!yes
+ {\ctxlua{fonts.vf.math.optional=true}}
+ {\ctxlua{fonts.vf.math.optional=false}}%
+\to \everysetupmathematics
+
+\setupmathematics
+ [\v!compact=no]
+
+%D Delayed: greek.
+%D
+%D \starttyping
+%D \usetypescript[cambria]\setupbodyfont[cambria]
+%D \startTEXpage
+%D $\alpha \mathgreekupright \alpha \mathgreekitalic \alpha$
+%D \stopTEXpage
+%D \stoptyping
+
+% [lc uc] normal (upright) = 2, italic = 3, none = 0/1
+
+\setevalue{\??mo:greek:\v!normal :\v!normal}{\attribute\mathgreekattribute22 }
+\setevalue{\??mo:greek:\v!normal :\v!italic}{\attribute\mathgreekattribute23 }
+\setevalue{\??mo:greek:\v!normal :\v!none }{\attribute\mathgreekattribute21 }
+
+\setevalue{\??mo:greek:\v!italic :\v!normal}{\attribute\mathgreekattribute32 }
+\setevalue{\??mo:greek:\v!italic :\v!italic}{\attribute\mathgreekattribute33 }
+\setevalue{\??mo:greek:\v!italic :\v!none }{\attribute\mathgreekattribute31 }
+
+\setevalue{\??mo:greek:\v!none :\v!normal}{\attribute\mathgreekattribute12 }
+\setevalue{\??mo:greek:\v!none :\v!italic}{\attribute\mathgreekattribute13 }
+\setevalue{\??mo:greek:\v!none :\v!none }{\attribute\mathgreekattribute\attributeunsetvalue}
+
+\appendtoks
+ \csname\??mo:greek:\@@molcgreek:\@@moucgreek\endcsname
+\to \everymathematics
+
+\setupmathematics
+ [lcgreek=\v!italic,
+ ucgreek=\v!normal] % was: none
+
+%D \macros
+%D {enablemathpunctuation,disablemathpunctuation}
+%D
+%D \startbuffer
+%D \enablemathpunctuation$(1,2) (1, 2) (1{,}2) \hbox{foo, not bar}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \blank{\getbuffer}\blank
+
+\setfalse \automathpunctuation
+
+\def\enablemathpunctuation {\settrue \automathpunctuation}
+\def\disablemathpunctuation{\setfalse\automathpunctuation}
+
+\ifx\v!autopunctuation\undefined \def\v!autopunctuation{autopunctuation} \fi
+
+\appendtoks
+ \doifelse{\mathematicsparameter\v!autopunctuation}\v!yes\enablemathpunctuation\disablemathpunctuation
+\to \everysetupmathematics
+
+\appendtoks
+ \ifconditional\automathpunctuation\attribute\mathpunctuationattribute\plusone\fi
+\to \everymathematics
+
+\setupmathematics
+ [\v!autopunctuation=\v!no]
+
+%D \macros
+%D {mathstyle}
+%D
+%D If one want to be sure that something is typeset in the
+%D appropriate style, \type {\mathstyle} can be used:
+%D
+%D \starttyping
+%D \mathstyle{something}
+%D \stoptyping
+
+% \def\mathstyle#1%
+% {\mathchoice
+% {\displaystyle #1}%
+% {\textstyle #1}%
+% {\scriptstyle #1}%
+% {\scriptscriptstyle#1}}
+%
+% We now have a primitive operation for this. As the
+% macro overloads a new primitive introduced in \LUATEX,
+% we need to use \type {\normalmathstyle} when we consult
+% the current math style.
+%
+% \let \mathstyle \Ustack % spoils cramped
+%
+% \let \mathstyle \firstofoneargument
+%
+% 0 = display
+% 1 = crampeddisplay
+% 2 = text
+% 3 = crampedtext
+% 4 = script
+% 5 = crampedscript
+% 6 = scriptscript
+% 7 = crampedscriptscript
+
+\def\uncramped#1%
+ {{\ifcase\normalmathstyle
+ \or \displaystyle \or
+ \or \textstyle \or
+ \or \scriptstyle \or
+ \or \scriptscriptstyle \fi
+ #1}}
+
+\def\cramped#1%
+ {{\ifcase\normalmathstyle
+ \crampeddisplaystyle \or \or % 0 -> 1
+ \crampedtextstyle \or \or % 2 -> 3
+ \crampedscriptstyle \or \or % 4 -> 5
+ \crampedscriptscriptstyle \fi % 6 -> 7
+ #1}}
+
+\def\triggermathstyle#1% #1 is number
+ {\ifcase#1\relax
+ \displaystyle \or
+ \crampeddisplaystyle \or
+ \textstyle \or
+ \crampedtextstyle \or
+ \scriptstyle \or
+ \crampedscriptstyle \or
+ \scriptscriptstyle \or
+ \crampedscriptscriptstyle \else
+ % error
+ \fi}
+
+\def\cramped#1%
+ {{\ifcase\normalmathstyle
+ \crampeddisplaystyle \or \or % 0 -> 1
+ \crampedtextstyle \or \or % 2 -> 3
+ \crampedscriptstyle \or \or % 4 -> 5
+ \crampedscriptscriptstyle \fi % 6 -> 7
+ #1}}
+
+\def\mathstylefont#1% #1 is number (\normalmathstyle)
+ {\ifcase#1\relax
+ \textfont \or
+ \textfont \or
+ \textfont \or
+ \textfont \or
+ \scriptfont \or
+ \scriptfont \or
+ \scriptscriptfont \or
+ \scriptscriptfont \else
+ \textfont
+ \fi\zerocount}
+
+%D Something similar can be used in the (re|)|definition
+%D of \type {\text}. This version is a variation on the one
+%D in the math module (see \type{m-math} and|/|or \type
+%D {m-newmat}).
+
+\unexpanded\def\mathtext
+ {\mathortext\domathtext\hbox}
+
+\def\domathtext#1%
+ {\mathchoice
+ {\dodomathtext\displaystyle\textface {#1}}%
+ {\dodomathtext\textstyle \textface {#1}}%
+ {\dodomathtext\textstyle \scriptface {#1}}%
+ {\dodomathtext\textstyle \scriptscriptface{#1}}}
+
+\def\dodomathtext#1#2#3% no \everymath !
+ %{\hbox{\everymath{#1}\switchtobodyfont [#2]#3}} % 15 sec
+ {\hbox{\everymath{#1}\setcurrentfontbody{#2}#3}} % 3 sec (no math)
+
+%D Safeguard against redefinitions:
+
+\appendtoks
+ \let\_\normalunderscore % is textunderscore or fakeunderscore
+\to \everymathematics
+
+%D Because we may overload \type {\text} in other (structuring)
+%D macros, we say:
+
+\appendtoks \let\text\mathtext \to \everymathematics
+
+%D The next code is derived from plain \TEX.
+
+\newcount\interdisplaylinepenalty \interdisplaylinepenalty=100
+
+\newif\ifdt@p
+
+\def\displ@y
+ {\global\dt@ptrue
+ \openup\displayopenupvalue % was \openup\jot
+ \everycr
+ {\noalign
+ {\ifdt@p
+ \global\dt@pfalse
+ \ifdim\prevdepth>-\thousandpoint
+ \vskip-\lineskiplimit
+ \vskip\normallineskiplimit
+ \fi
+ \else
+ \penalty\interdisplaylinepenalty
+ \fi}}}
+
+\let\normaldispl@y\displ@y
+
+\def\displ@y{\resetdisplaymatheq\normaldispl@y}
+
+\def\m@th{\mathsurround\zeropoint} % obsolete
+
+%D Text in math:
+
+\def\mathortext
+ {\ifmmode
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+% \defineactivecharacter _ {\mathortext{_}{\_}} text_text $a^2$
+
+% force text mode, will be overloaded later
+
+\ifx\text\undefined \let\text\hbox \fi
+
+\def\mathoptext#1{\mathop{\text{#1}}}
+
+\protect \endinput
diff --git a/tex/context/base/math-inl.mkiv b/tex/context/base/math-inl.mkiv
new file mode 100644
index 000000000..89de0242b
--- /dev/null
+++ b/tex/context/base/math-inl.mkiv
@@ -0,0 +1,26 @@
+%D \module
+%D [ file=math-inl,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Inline,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%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 Math Macros / Inline}
+
+\unprotect
+
+% Obsolete, as we do snapping differently now.
+
+\def\snappedinlineformula {\dosingleempty\dosnappedinlineformula}
+\def\dosnappedinlineformula[#1]#2{\mathematics{#2}}
+\let\tform \mathematics
+\let\gform \snappedinlineformula
+\let\enableautomath \relax
+
+\protect \endinput
diff --git a/tex/context/base/math-int.mkiv b/tex/context/base/math-int.mkiv
new file mode 100644
index 000000000..2af471b5c
--- /dev/null
+++ b/tex/context/base/math-int.mkiv
@@ -0,0 +1,90 @@
+%D \module
+%D [ file=math-int,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Scripts,
+%D author={Hans Hagen \& Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Math Macros / Integrals}
+
+\unprotect
+
+%D \startbuffer
+%D $\int_a^b f(x) dx$ and also
+%D $\iint_a^b f(x,y) dxdy$, $\iiint_a^b f(x,y) dxdy$,
+%D $\iiiint_a^b f(x) dx$
+%D \startformula
+%D \int_a^b f(x) dx \quad
+%D \iint_a^b f(x) dx \quad
+%D \iiint_a^b f(x) dx \quad
+%D \iiiint_a^b f(x) dx \quad
+%D \stopformula
+%D \stopbuffer
+%D
+%D Default: \getbuffer
+%D
+%D Displaylimits: \setupmathematics[integral=displaylimits] \getbuffer
+%D
+%D Limits: \setupmathematics[integral=limits] \getbuffer
+
+\chardef\intlimitcode\zerocount % 0 nolimits 1 displaylimits 2 limits
+
+\def\intlimits
+ {\ifcase\intlimitcode \nolimits \or \displaylimits \or \limits \fi}
+
+\ifx\v!integral\undefined \def\v!integral{integral} \fi
+
+\appendtoks
+ \processaction
+ [\mathematicsparameter\v!integral]
+ [ nolimits=>\chardef\intlimitcode\zerocount,
+ displaylimits=>\chardef\intlimitcode\plusone,
+ limits=>\chardef\intlimitcode\plustwo]%
+\to \everysetupmathematics
+
+\setupmathematics
+ [\v!integral=nolimits]
+
+%D More integrals (AM):
+
+\definemathcommand [iint] {\repeatintegral\plusone }
+\definemathcommand [iiint] {\repeatintegral\plustwo }
+\definemathcommand [iiiint] {\repeatintegral\plusthree}
+
+%def\integralrepeatsymbol{\intop}
+\def\integralrepeatsymbol{{\int}}
+
+\def\repeatintegral#1%
+ {\scratchtoks\emptytoks
+ \let\dointlimits\donothing
+ \let\dodointlimits\intlimits
+ \dorecurse{#1}{\appendtoks \integralrepeatsymbol \dointkern \to \scratchtoks}
+ \appendtoks \intop \dointlimits \dodointlimits \to \scratchtoks
+ \edef\dodorepeatintegral{\the\scratchtoks}%
+ \futurelet\next\dorepeatintegral}
+
+%D If the \type{\limits} option is used after \type{\iint}, use
+%D \type{\mathop} and fudge the left hand space a bit to make the
+%D subscript visually centered.
+
+\def\dointkern
+ {\mkern-6mu\mathchoice{\mkern-3mu}{}{}{}}
+
+\def\dorepeatintegral
+ {\ifx\next\limits \dointlimitcorrection \else
+ \ifx\next\displaylimits \dointlimitcorrection \else
+ \ifx\next\nolimits \donothing \else
+ \ifcase\intlimitcode\else \dointlimitcorrection \fi\fi\fi\fi
+ \dodorepeatintegral}
+
+\def\dointlimitcorrection
+ {\mkern-7mu\mathchoice{\mkern-2mu}{}{}{}%
+ \mathop\bgroup\mkern7mu\mathchoice{\mkern2mu}{}{}{}\let\dointlimits\egroup}
+
+\protect \endinput
diff --git a/tex/context/base/math-lan.mkiv b/tex/context/base/math-lan.mkiv
new file mode 100644
index 000000000..1d3132578
--- /dev/null
+++ b/tex/context/base/math-lan.mkiv
@@ -0,0 +1,67 @@
+%D \module
+%D [ file=math-lan,
+%D version=2009.03.10,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Language Support,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 Math Macros / Language Support}
+
+\unprotect
+
+\setupmathlabeltext [\s!en] [arccos=arccos]
+\setupmathlabeltext [\s!en] [arcsin=arcsin]
+\setupmathlabeltext [\s!en] [arctan=arctan]
+\setupmathlabeltext [\s!en] [arg=arg]
+\setupmathlabeltext [\s!en] [cosh=cosh]
+\setupmathlabeltext [\s!en] [cos=cos]
+\setupmathlabeltext [\s!en] [coth=coth]
+\setupmathlabeltext [\s!en] [cot=cot]
+\setupmathlabeltext [\s!en] [csc=csc]
+\setupmathlabeltext [\s!en] [deg=deg]
+\setupmathlabeltext [\s!en] [det=det]
+\setupmathlabeltext [\s!en] [dim=dim]
+\setupmathlabeltext [\s!en] [exp=exp]
+\setupmathlabeltext [\s!en] [gcd=gcd]
+\setupmathlabeltext [\s!en] [hom=hom]
+\setupmathlabeltext [\s!en] [inf=inf]
+\setupmathlabeltext [\s!en] [injlim=inj\,lim]
+\setupmathlabeltext [\s!en] [ker=ker]
+\setupmathlabeltext [\s!en] [lg=lg]
+\setupmathlabeltext [\s!en] [liminf=lim\,inf]
+\setupmathlabeltext [\s!en] [limsup=lim\,sup]
+\setupmathlabeltext [\s!en] [lim=lim]
+\setupmathlabeltext [\s!en] [ln=ln]
+\setupmathlabeltext [\s!en] [log=log]
+\setupmathlabeltext [\s!en] [median=median]
+\setupmathlabeltext [\s!en] [max=max]
+\setupmathlabeltext [\s!en] [min=min]
+\setupmathlabeltext [\s!en] [mod=mod]
+\setupmathlabeltext [\s!en] [projlim=proj\,lim]
+\setupmathlabeltext [\s!en] [Pr=Pr]
+\setupmathlabeltext [\s!en] [sec=sec]
+\setupmathlabeltext [\s!en] [sinh=sinh]
+\setupmathlabeltext [\s!en] [sin=sin]
+\setupmathlabeltext [\s!en] [sup=sup]
+\setupmathlabeltext [\s!en] [tanh=tanh]
+\setupmathlabeltext [\s!en] [tan=tan]
+
+\setupmathlabeltext [\s!pl] [tg=tg]
+\setupmathlabeltext [\s!pl] [cot=ctg]
+\setupmathlabeltext [\s!pl] [ctg=ctg]
+\setupmathlabeltext [\s!pl] [arcsin=arc\,sin]
+\setupmathlabeltext [\s!pl] [arccos=arc\,cos]
+\setupmathlabeltext [\s!pl] [arctan=arc\,tg]
+\setupmathlabeltext [\s!pl] [arctg=arc\,tg]
+\setupmathlabeltext [\s!pl] [arcctg=arc\,ctg]
+
+\setupmathlabeltext [\s!nl] [gcd=ggd]
+\setupmathlabeltext [\s!nl] [lcm=kgv]
+
+\protect \endinput
diff --git a/tex/context/base/math-lbr.mkii b/tex/context/base/math-lbr.mkii
new file mode 100644
index 000000000..cf69eec1f
--- /dev/null
+++ b/tex/context/base/math-lbr.mkii
@@ -0,0 +1,481 @@
+%D \module
+%D [ file=math-lbr,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Lucida Specials,
+%D author={Hans Hagen \& Taco Hoekwater},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\definefamilysynonym [lbr] [calligraphy] [sy]
+\definefamilysynonym [lbr] [oldstyle] [mi]
+
+\definefamilysynonym [lbr] [blackboard] [ma]
+\definefamilysynonym [lbr] [ucgreek] [mb]
+\definefamilysynonym [lbr] [vargreek] [mi]
+
+\startmathcollection[lbr]
+
+\definemathsymbol [boxdot] [bin] [sy] ["ED]
+\definemathsymbol [boxplus] [bin] [sy] ["EA]
+\definemathsymbol [boxtimes] [bin] [sy] ["EC]
+\definemathsymbol [square] [ord] [ma] ["02]
+\definemathsymbol [Box] [ord] [ma] ["02] % square
+\definemathsymbol [blacksquare] [ord] [ma] ["03]
+\definemathsymbol [centerdot] [bin] [ma] ["E1] % [sy] ["01]
+\definemathsymbol [Diamond] [ord] [sy] ["05]
+\definemathsymbol [lozenge] [ord] [sy] ["05] % Diamond
+\definemathsymbol [blacklozenge] [ord] [ma] ["09]
+\definemathsymbol [circlearrowright] [rel] [ma] ["8C]
+\definemathsymbol [circlearrowleft] [rel] [ma] ["8B]
+\definemathsymbol [rightleftharpoons] [rel] [sy] ["8E]
+\definemathsymbol [leftrightharpoons] [rel] [sy] ["8D]
+\definemathsymbol [boxminus] [bin] [sy] ["EB]
+\definemathsymbol [Vdash] [rel] [sy] ["F0]
+\definemathsymbol [Vvdash] [rel] [mb] ["D3]
+\definemathsymbol [vDash] [rel] [mb] ["D6]
+\definemathsymbol [twoheadrightarrow] [rel] [ma] ["25]
+\definemathsymbol [twoheadleftarrow] [rel] [ma] ["23]
+\definemathsymbol [leftleftarrows] [rel] [ma] ["71]
+\definemathsymbol [rightrightarrows] [rel] [ma] ["73]
+\definemathsymbol [upuparrows] [rel] [ma] ["72]
+\definemathsymbol [downdownarrows] [rel] [ma] ["74]
+\definemathsymbol [upharpoonright] [rel] [ma] ["75]
+\definemathsymbol [restriction] [rel] [ma] ["77]
+\definemathsymbol [downharpoonright] [rel] [ma] ["77]
+\definemathsymbol [upharpoonleft] [rel] [ma] ["76]
+\definemathsymbol [downharpoonleft] [rel] [ma] ["78]
+\definemathsymbol [rightarrowtail] [rel] [ma] ["29]
+\definemathsymbol [leftarrowtail] [rel] [ma] ["28]
+\definemathsymbol [leftrightarrows] [rel] [ma] ["6E]
+\definemathsymbol [rightleftarrows] [rel] [ma] ["6D]
+\definemathsymbol [Lsh] [rel] [ma] ["7B]
+\definemathsymbol [Rsh] [rel] [ma] ["7D]
+\definemathsymbol [rightsquigarrow] [rel] [ma] ["8E]
+\definemathsymbol [leadsto] [rel] [ma] ["8E] % rightsquigarrow
+\definemathsymbol [leftrightsquigarrow] [rel] [ma] ["91]
+\definemathsymbol [looparrowleft] [rel] [ma] ["3F]
+\definemathsymbol [looparrowright] [rel] [ma] ["40]
+\definemathsymbol [circeq] [rel] [sy] ["D0]
+\definemathsymbol [succsim] [rel] [sy] ["E1]
+\definemathsymbol [gtrsim] [rel] [sy] ["DD]
+\definemathsymbol [gtrapprox] [rel] [mb] ["DB]
+\definemathsymbol [multimap] [rel] [mb] ["C7]
+\definemathsymbol [therefore] [rel] [sy] ["90]
+\definemathsymbol [because] [rel] [sy] ["91]
+\definemathsymbol [doteqdot] [rel] [sy] ["CA]
+\definemathsymbol [Doteq] [rel] [sy] ["CA] % doteqdot
+\definemathsymbol [triangleq] [rel] [sy] ["D5]
+\definemathsymbol [precsim] [rel] [sy] ["E0]
+\definemathsymbol [lesssim] [rel] [sy] ["DC]
+\definemathsymbol [lessapprox] [rel] [mb] ["DA]
+\definemathsymbol [eqslantless] [rel] [mb] ["E2]
+\definemathsymbol [eqslantgtr] [rel] [mb] ["E3]
+\definemathsymbol [curlyeqprec] [rel] [mb] ["E6]
+\definemathsymbol [curlyeqsucc] [rel] [mb] ["E7]
+\definemathsymbol [preccurlyeq] [rel] [mb] ["E4]
+\definemathsymbol [leqq] [rel] [sy] ["DA]
+\definemathsymbol [leqslant] [rel] [mb] ["E0]
+\definemathsymbol [lessgtr] [rel] [sy] ["DE]
+\definemathsymbol [backprime] [ord] [mb] ["C8]
+\definemathsymbol [dabar@] [ord] [ma] ["03] % !! @
+\definemathsymbol [risingdotseq] [rel] [sy] ["CC]
+\definemathsymbol [fallingdotseq] [rel] [sy] ["CB]
+\definemathsymbol [succcurlyeq] [rel] [mb] ["E5]
+\definemathsymbol [geqq] [rel] [sy] ["DB]
+\definemathsymbol [geqslant] [rel] [mb] ["E1]
+\definemathsymbol [gtrless] [rel] [sy] ["DF]
+\definemathsymbol [sqsubset] [rel] [sy] ["E4]
+\definemathsymbol [sqsupset] [rel] [sy] ["E5]
+\definemathsymbol [vartriangleright] [rel] [mb] ["2E]
+\definemathsymbol [rhd] [bin] [mb] ["2E]
+\definemathsymbol [lhd] [bin] [mb] ["2F]
+\definemathsymbol [vartriangleleft] [rel] [mb] ["2F]
+\definemathsymbol [trianglerighteq] [rel] [sy] ["F5]
+\definemathsymbol [unrhd] [bin] [sy] ["F5] % trianglerighteq
+\definemathsymbol [trianglelefteq] [rel] [sy] ["F4]
+\definemathsymbol [unlhd] [bin] [sy] ["F4] % trianglelefteq
+\definemathsymbol [bigstar] [ord] [ma] ["AB]
+\definemathsymbol [between] [rel] [mb] ["F2]
+\definemathsymbol [blacktriangledown] [ord] [ma] ["07]
+\definemathsymbol [blacktriangleright] [rel] [mb] ["F1]
+\definemathsymbol [blacktriangleleft] [rel] [mb] ["F0]
+\definemathsymbol [vartriangle] [rel] [ma] ["04]
+\definemathsymbol [triangleup] [ord] [ma] ["04] % vartriangle
+\definemathsymbol [blacktriangle] [ord] [ma] ["05]
+\definemathsymbol [triangledown] [ord] [ma] ["06]
+\definemathsymbol [eqcirc] [rel] [sy] ["CF]
+\definemathsymbol [lesseqgtr] [rel] [mb] ["E8]
+\definemathsymbol [gtreqless] [rel] [mb] ["E9]
+\definemathsymbol [lesseqqgtr] [rel] [mb] ["EA]
+\definemathsymbol [gtreqqless] [rel] [mb] ["EB]
+\definemathsymbol [Rrightarrow] [rel] [ma] ["6C]
+\definemathsymbol [Lleftarrow] [rel] [ma] ["6A]
+\definemathsymbol [veebar] [bin] [mb] ["D2]
+\definemathsymbol [barwedge] [bin] [sy] ["F6]
+\definemathsymbol [doublebarwedge] [bin] [sy] ["D4]
+\definemathsymbol [angle] [ord] [sy] ["8B]
+\definemathsymbol [measuredangle] [ord] [sy] ["8C]
+\definemathsymbol [sphericalangle] [ord] [sy] ["8D]
+\definemathsymbol [varpropto] [rel] [sy] ["2F]
+\definemathsymbol [smallsmile] [rel] [mb] ["5E]
+\definemathsymbol [smallfrown] [rel] [mb] ["5F]
+\definemathsymbol [Subset] [rel] [sy] ["F8]
+\definemathsymbol [Supset] [rel] [sy] ["F9]
+\definemathsymbol [Cup] [bin] [sy] ["FA]
+\definemathsymbol [doublecup] [bin] [sy] ["FA] % Cup
+\definemathsymbol [Cap] [bin] [sy] ["FB]
+\definemathsymbol [doublecap] [bin] [sy] ["FB]
+\definemathsymbol [curlywedge] [bin] [sy] ["84]
+\definemathsymbol [curlyvee] [bin] [sy] ["85]
+\definemathsymbol [leftthreetimes] [bin] [mb] ["D0]
+\definemathsymbol [rightthreetimes] [bin] [mb] ["D1]
+\definemathsymbol [subseteqq] [rel] [mb] ["EE]
+\definemathsymbol [supseteqq] [rel] [mb] ["EF]
+\definemathsymbol [bumpeq] [rel] [sy] ["C8]
+\definemathsymbol [Bumpeq] [rel] [sy] ["C7]
+\definemathsymbol [llless] [rel] [mb] ["DE]
+\definemathsymbol [lll] [rel] [mb] ["DE] % llless
+\definemathsymbol [gggtr] [rel] [mb] ["DF]
+\definemathsymbol [ggg] [rel] [mb] ["DF] % gggtr
+\definemathsymbol [ulcorner] [open] [ma] ["5B] [ma] ["5B]
+\definemathsymbol [urcorner] [close] [ma] ["5C] [ma] ["5C]
+\definemathsymbol [circledS] [ord] [mb] ["CA]
+\definemathsymbol [pitchfork] [rel] [ma] ["F3]
+\definemathsymbol [dotplus] [bin] [sy] ["89]
+\definemathsymbol [backsim] [rel] [sy] ["24]
+\definemathsymbol [backsimeq] [rel] [sy] ["27]
+\definemathsymbol [llcorner] [open] [ma] ["5D] [ma] ["5D]
+\definemathsymbol [lrcorner] [close] [ma] ["5E] [ma] ["5E]
+\definemathsymbol [complement] [ord] [mb] ["94]
+\definemathsymbol [intercal] [bin] [ma] ["03] % !!
+\definemathsymbol [circledcirc] [bin] [sy] ["E6]
+\definemathsymbol [circledast] [bin] [sy] ["E7]
+\definemathsymbol [circleddash] [bin] [mb] ["CC]
+
+\stopmathcollection
+
+\startmathcollection [lbr]
+
+\definemathsymbol [lvertneqq] [rel] [ma] ["DE]
+\definemathsymbol [gvertneqq] [rel] [ma] ["DE]
+\definemathsymbol [nleq] [rel] [ma] ["9C]
+\definemathsymbol [ngeq] [rel] [ma] ["9D]
+\definemathsymbol [nless] [rel] [ma] ["9A]
+\definemathsymbol [ngtr] [rel] [ma] ["9B]
+\definemathsymbol [nprec] [rel] [ma] ["E5]
+\definemathsymbol [nsucc] [rel] [ma] ["E6]
+\definemathsymbol [lneqq] [rel] [ma] ["DC]
+\definemathsymbol [gneqq] [rel] [ma] ["DE]
+\definemathsymbol [nleqslant] [rel] [ma] ["D6]
+\definemathsymbol [ngeqslant] [rel] [ma] ["D7]
+\definemathsymbol [lneq] [rel] [ma] ["DA]
+\definemathsymbol [gneq] [rel] [ma] ["DB]
+\definemathsymbol [npreceq] [rel] [ma] ["E7]
+\definemathsymbol [nsucceq] [rel] [ma] ["E8]
+\definemathsymbol [precnsim] [rel] [ma] ["EB]
+\definemathsymbol [succnsim] [rel] [ma] ["EC]
+\definemathsymbol [lnsim] [rel] [ma] ["E0]
+\definemathsymbol [gnsim] [rel] [ma] ["E2]
+\definemathsymbol [nleqq] [rel] [ma] ["D8]
+\definemathsymbol [ngeqq] [rel] [ma] ["D9]
+\definemathsymbol [precneqq] [rel] [ma] ["E9]
+\definemathsymbol [succneqq] [rel] [ma] ["EA]
+\definemathsymbol [precnapprox] [rel] [ma] ["ED]
+\definemathsymbol [succnapprox] [rel] [ma] ["EE]
+\definemathsymbol [lnapprox] [rel] [ma] ["E4]
+\definemathsymbol [gnapprox] [rel] [ma] ["E3]
+\definemathsymbol [nsim] [rel] [ma] ["96]
+\definemathsymbol [ncong] [rel] [ma] ["99]
+\definemathsymbol [diagup] [ord] [mb] ["CD]
+\definemathsymbol [diagdown] [ord] [mb] ["D8]
+\definemathsymbol [varsubsetneq] [rel] [ma] ["D0]
+\definemathsymbol [varsupsetneq] [rel] [ma] ["D1]
+\definemathsymbol [nsubseteqq] [rel] [ma] ["CA]
+\definemathsymbol [nsupseteqq] [rel] [ma] ["CB]
+\definemathsymbol [subsetneqq] [rel] [ma] ["CE]
+\definemathsymbol [supsetneqq] [rel] [ma] ["CF]
+\definemathsymbol [varsubsetneqq] [rel] [ma] ["D2]
+\definemathsymbol [varsupsetneqq] [rel] [ma] ["D3]
+\definemathsymbol [subsetneq] [rel] [ma] ["CC]
+\definemathsymbol [supsetneq] [rel] [ma] ["CD]
+\definemathsymbol [nsubseteq] [rel] [ma] ["C8]
+\definemathsymbol [nsupseteq] [rel] [ma] ["C9]
+\definemathsymbol [nparallel] [rel] [ma] ["F7]
+\definemathsymbol [nmid] [rel] [ma] ["F6]
+\definemathsymbol [nshortmid] [rel] [ma] ["F4]
+\definemathsymbol [nshortparallel] [rel] [ma] ["F5]
+\definemathsymbol [nvdash] [rel] [ma] ["F8]
+\definemathsymbol [nVdash] [rel] [ma] ["F9]
+\definemathsymbol [nvDash] [rel] [ma] ["FA]
+\definemathsymbol [nVDash] [rel] [ma] ["FB]
+\definemathsymbol [ntrianglerighteq] [rel] [ma] ["F2]
+\definemathsymbol [ntrianglelefteq] [rel] [ma] ["F1]
+\definemathsymbol [ntriangleleft] [rel] [ma] ["EF]
+\definemathsymbol [ntriangleright] [rel] [ma] ["F0]
+\definemathsymbol [nleftarrow] [rel] [ma] ["32]
+\definemathsymbol [nrightarrow] [rel] [ma] ["33]
+\definemathsymbol [nLeftarrow] [rel] [ma] ["66]
+\definemathsymbol [nRightarrow] [rel] [ma] ["68]
+\definemathsymbol [nLeftrightarrow] [rel] [ma] ["67]
+\definemathsymbol [nleftrightarrow] [rel] [ma] ["34]
+\definemathsymbol [divideontimes] [bin] [mb] ["F7]
+\definemathsymbol [varnothing] [ord] [sy] ["53]
+\definemathsymbol [nexists] [ord] [ma] ["20]
+\definemathsymbol [Finv] [ord] [mb] ["90]
+\definemathsymbol [Game] [ord] [mb] ["91]
+\definemathsymbol [mho] [ord] [mb] ["92]
+\definemathsymbol [eth] [ord] [ma] ["03] % !!
+\definemathsymbol [eqsim] [rel] [sy] ["99]
+\definemathsymbol [beth] [ord] [mb] ["95]
+\definemathsymbol [gimel] [ord] [mb] ["96]
+\definemathsymbol [daleth] [ord] [mb] ["97]
+\definemathsymbol [lessdot] [bin] [mb] ["DC]
+\definemathsymbol [gtrdot] [bin] [mb] ["DD]
+\definemathsymbol [ltimes] [bin] [mb] ["CF]
+\definemathsymbol [rtimes] [bin] [mb] ["CE]
+\definemathsymbol [shortmid] [rel] [mb] ["F4]
+\definemathsymbol [shortparallel] [rel] [mb] ["F5]
+\definemathsymbol [smallsetminus] [bin] [mb] ["D8]
+\definemathsymbol [thicksim] [rel] [sy] ["18] % not that thick
+\definemathsymbol [thickapprox] [rel] [sy] ["19] % not that thick
+\definemathsymbol [approxeq] [rel] [sy] ["9D]
+\definemathsymbol [succapprox] [rel] [mb] ["ED]
+\definemathsymbol [precapprox] [rel] [mb] ["EC]
+\definemathsymbol [curvearrowleft] [rel] [ma] ["87]
+\definemathsymbol [curvearrowright] [rel] [ma] ["88]
+\definemathsymbol [digamma] [ord] [ma] ["03] % !!
+\definemathsymbol [varkappa] [ord] [mb] ["9B]
+\definemathsymbol [Bbbk] [ord] [ma] ["6B]
+\definemathsymbol [hslash] [ord] [mb] ["9D]
+\definemathsymbol [hbar] [ord] [ma] ["1B]
+\definemathsymbol [backepsilon] [rel] [ma] ["03] % !!
+
+\stopmathcollection
+
+\startmathcollection [lbr]
+
+\definemathsymbol [yen] [nothing] [ma] ["03] % !!
+\definemathsymbol [checkmark] [nothing] [ma] ["AC]
+\definemathsymbol [circledR] [nothing] [mb] ["C9]
+\definemathsymbol [maltese] [nothing] [mb] ["CB]
+
+\stopmathcollection
+
+\startmathcollection [lbr]
+
+\definemathsymbol [dashrightarrow] [rel] [ma] ["3A]
+\definemathsymbol [dashleftarrow] [rel] [ma] ["38]
+\definemathcommand [dasharrow] [rel] {\dashleftarrow\mkern-15.8mu\dashrightarrow}
+%definemathcommand [Join] [rel] {\mathchar"0D6F\mkern-15.8mu\mathchar"0D6E} % !!
+
+\stopmathcollection
+
+\startmathcollection[lbr]
+
+\definemathcharacter [91] [open] [mi] ["86]
+\definemathcharacter [93] [close] [mi] ["87]
+\definemathcharacter [(] [open] [mi] ["84]
+\definemathcharacter [)] [close] [mi] ["85]
+\definemathcharacter [/] [nothing] [mi] ["3D]
+\definemathcharacter [=] [rel] [sy] ["83]
+\definemathcharacter [+] [bin] [sy] ["82]
+
+\definemathcharacter [91] [nothing] [mi] ["86] [ex] ["02]
+\definemathcharacter [93] [nothing] [mi] ["87] [ex] ["03]
+\definemathcharacter [(] [nothing] [mi] ["84] [ex] ["00]
+\definemathcharacter [)] [nothing] [mi] ["85] [ex] ["01]
+\definemathcharacter [/] [nothing] [mi] ["3D] [ex] ["0E]
+
+\stopmathcollection
+
+% \startmathcollection[lbr]
+%
+% \definemathcharacter [:] [punct] [tf] ["3A] % unbelievable
+% \definemathcharacter [;] [punct] [tf] ["3B] % unbelievable
+%
+% \stopmathcollection
+
+\startmathcollection[lbr]
+
+\definemathsymbol [ldbrack] [open] [mi] ["82] [ex] ["82]
+\definemathsymbol [rdbrack] [close] [mi] ["83] [ex] ["83]
+\definemathsymbol [surfintop] [op] [ex] ["90]
+\definemathsymbol [midintop] [op] [ex] ["92]
+\definemathsymbol [midointop] [op] [ex] ["93]
+\definemathsymbol [midsurfintop] [op] [ex] ["94]
+\definemathsymbol [largeint] [op] [ex] ["5A] [ex] ["95]
+
+% \definemathcommand [surfint] [nolop] {\surfintop}
+% \definemathcommand [midint] [nolop] {\midintop}
+% \definemathcommand [midoint] [nolop] {\midointop}
+% \definemathcommand [midsurfint] [nolop] {\midsurfintop}
+
+\definemathsymbol [surfint] [nolop] [ex] ["90]
+\definemathsymbol [midint] [nolop] [ex] ["92]
+\definemathsymbol [midoint] [nolop] [ex] ["93]
+\definemathsymbol [midsurfint] [nolop] [ex] ["94]
+
+\definemathsymbol [dblint] [ord] [mi] ["88]
+\definemathsymbol [trplint] [ord] [mi] ["89]
+\definemathsymbol [contint] [ord] [mi] ["8A]
+\definemathsymbol [surfint] [ord] [mi] ["8B]
+\definemathsymbol [volint] [ord] [mi] ["8C]
+\definemathsymbol [clwint] [ord] [mi] ["8D]
+\definemathsymbol [cclwcint] [ord] [mi] ["8E]
+\definemathsymbol [clwcint] [ord] [mi] ["8F]
+\definemathsymbol [bowtie] [rel] [mi] ["F6]
+\definemathsymbol [models] [rel] [sy] ["EE]
+\definemathsymbol [doteq] [rel] [sy] ["C9]
+\definemathsymbol [cong] [rel] [sy] ["9B]
+\definemathsymbol [hbar] [ord] [mi] ["9D]
+\definemathsymbol [neq] [rel] [ma] ["94]
+\definemathsymbol [rightleftharpoons] [rel] [ma] ["7A]
+\definemathsymbol [leftrightharpoons] [rel] [ma] ["79]
+\definemathsymbol [hookleftarrow] [rel] [ma] ["3C]
+\definemathsymbol [hookrightarrow] [rel] [ma] ["3E]
+\definemathsymbol [mapsto] [rel] [ma] ["2C]
+
+\definemathcommand [longmapsto] {\mapstochar\longrightarrow}
+
+\stopmathcollection
+
+\startmathcollection[lbr]
+
+\definemathsymbol [Gamma] [alpha] [ucgreek] ["00]
+\definemathsymbol [Delta] [alpha] [ucgreek] ["01]
+\definemathsymbol [Theta] [alpha] [ucgreek] ["02]
+\definemathsymbol [Lambda] [alpha] [ucgreek] ["03]
+\definemathsymbol [Xi] [alpha] [ucgreek] ["04]
+\definemathsymbol [Pi] [alpha] [ucgreek] ["05]
+\definemathsymbol [Sigma] [alpha] [ucgreek] ["06]
+\definemathsymbol [Upsilon] [alpha] [ucgreek] ["07]
+\definemathsymbol [Phi] [alpha] [ucgreek] ["08]
+\definemathsymbol [Psi] [alpha] [ucgreek] ["09]
+\definemathsymbol [Omega] [alpha] [ucgreek] ["0A]
+
+\definemathsymbol [varGamma] [ord] [vargreek] ["00]
+\definemathsymbol [varDelta] [ord] [vargreek] ["01]
+\definemathsymbol [varTheta] [ord] [vargreek] ["02]
+\definemathsymbol [varLambda] [ord] [vargreek] ["03]
+\definemathsymbol [varXi] [ord] [vargreek] ["04]
+\definemathsymbol [varPi] [ord] [vargreek] ["05]
+\definemathsymbol [varSigma] [ord] [vargreek] ["06]
+\definemathsymbol [varUpsilon] [ord] [vargreek] ["07]
+\definemathsymbol [varPhi] [ord] [vargreek] ["08]
+\definemathsymbol [varPsi] [ord] [vargreek] ["09]
+\definemathsymbol [varOmega] [ord] [vargreek] ["0A]
+
+\stopmathcollection
+
+% we define the whole lot, although only a few differ (esp dot)
+
+% \startmathcollection[lbr]
+%
+% \definemathsymbol [acute] [accent] [tf] ["13] % mr -> tf
+% \definemathsymbol [grave] [accent] [tf] ["12] % mr -> tf
+% \definemathsymbol [ddot] [accent] [tf] ["7F] % mr -> tf
+% \definemathsymbol [tilde] [accent] [tf] ["7E] % mr -> tf
+% \definemathsymbol [bar] [accent] [tf] ["16] % mr -> tf
+% \definemathsymbol [breve] [accent] [tf] ["15] % mr -> tf
+% \definemathsymbol [check] [accent] [tf] ["14] % mr -> tf
+% \definemathsymbol [hat] [accent] [tf] ["5E] % mr -> tf
+% \definemathsymbol [vec] [accent] [mi] ["7E] % [ord]
+% \definemathsymbol [dot] [accent] [tf] ["05] % mr -> tf, 5F -> 05
+% \definemathsymbol [widetilde] [accent] [ex] ["65] % [ord]
+% \definemathsymbol [widehat] [accent] [ex] ["62] % [ord]
+%
+% \stopmathcollection
+
+\startmathcollection[lbr:texnansi]
+ \definemathsymbol [acute] [accent] [tf] ["13]
+ \definemathsymbol [grave] [accent] [tf] ["12]
+ \definemathsymbol [ddot] [accent] [tf] ["7F]
+ %definemathsymbol [ddot] [accent] [tf] ["A8] % both is OK
+ \definemathsymbol [tilde] [accent] [tf] ["7E]
+ %definemathsymbol [tilde] [accent] [tf] ["98] % both is OK
+ \definemathsymbol [bar] [accent] [tf] ["16]
+ \definemathsymbol [breve] [accent] [tf] ["15]
+ \definemathsymbol [check] [accent] [tf] ["14]
+ \definemathsymbol [hat] [accent] [tf] ["5E]
+ %definemathsymbol [hat] [accent] [tf] ["88] % both is OK
+ \definemathsymbol [dot] [accent] [tf] ["05]
+ % Why is mathring not defined??
+ \definemathsymbol [mathring] [accent] [tf] ["17]
+\stopmathcollection
+
+\startmathcollection[lbr:ec]
+ \definemathsymbol [acute] [accent] [tf] ["01]
+ \definemathsymbol [grave] [accent] [tf] ["00]
+ \definemathsymbol [ddot] [accent] [tf] ["04]
+ \definemathsymbol [tilde] [accent] [tf] ["03]
+ \definemathsymbol [bar] [accent] [tf] ["09]
+ \definemathsymbol [breve] [accent] [tf] ["08]
+ \definemathsymbol [check] [accent] [tf] ["07]
+ \definemathsymbol [hat] [accent] [tf] ["02]
+ \definemathsymbol [dot] [accent] [tf] ["0A]
+ % Why is mathring not defined??
+ \definemathsymbol [mathring] [accent] [tf] ["06]
+\stopmathcollection
+
+\def\LBRroot#1#2%
+ {\setbox\zerocount\hbox{$\mathsurround\zeropoint#1\sqrt{#2}$}
+ \dimen@\ht\zerocount \advance\dimen@-\dp\zerocount
+ \mkern5mu\raise.6\dimen@\copy\rootbox \mkern-7.5mu \box\zerocount}
+
+\def\LBRmatrix#1%
+ {\null\,\vcenter{\normalbaselines\mathsurround\zeropoint
+ \ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
+ \mathstrut\crcr\noalign{\kern-0.9\baselineskip}
+ #1\crcr\mathstrut\crcr\noalign{\kern-0.9\baselineskip}}}\,}
+
+\startrawmathcollection[lbr]
+
+\definemathcommand [mathstrut] {\vphantom{f}}
+\definemathcommand [joinrel] {\mathrel{\mkern-4mu}}
+\definemathcommand [r@@t] {\LBRroot}
+\definemathcommand [matrix] {\LBRmatrix}
+
+\stoprawmathcollection
+
+\def\LBRbig {\@@dobig{8.20}}
+\def\LBRBig {\@@dobig{10.80}}
+\def\LBRbigg {\@@dobig{13.42}}
+\def\LBRBigg {\@@dobig{16.03}}
+\def\LBRbiggg{\@@dobig{17.72}}
+\def\LBRBiggg{\@@dobig{21.25}}
+
+% \def\LBRbig {\@@dobig{0.820}}
+% \def\LBRBig {\@@dobig{1.080}}
+% \def\LBRbigg {\@@dobig{1.342}}
+% \def\LBRBigg {\@@dobig{1.603}}
+% \def\LBRbiggg{\@@dobig{1.772}}
+% \def\LBRBiggg{\@@dobig{2.125}}
+
+\startrawmathcollection[lbr]
+
+\definemathcommand [big] {\LBRbig}
+\definemathcommand [Big] {\LBRBig}
+\definemathcommand [bigg] {\LBRbigg}
+\definemathcommand [Bigg] {\LBRBigg}
+\definemathcommand [biggg] {\LBRbiggg}
+\definemathcommand [Biggg] {\LBRBiggg}
+
+\stoprawmathcollection
+
+\startrawmathcollection[lbr]
+
+\definemathcommand [bigggl] [open] {\biggg}
+\definemathcommand [bigggr] [close] {\biggg}
+\definemathcommand [Bigggl] [open] {\Biggg}
+\definemathcommand [Bigggr] [close] {\Biggg}
+
+\stoprawmathcollection
+
+\protect \endinput
diff --git a/tex/context/base/math-map.lua b/tex/context/base/math-map.lua
new file mode 100644
index 000000000..2d34dc1c3
--- /dev/null
+++ b/tex/context/base/math-map.lua
@@ -0,0 +1,440 @@
+if not modules then modules = { } end modules ['math-map'] = {
+ version = 1.001,
+ comment = "companion to math-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+
Remapping mathematics alphabets.
+--ldx]]--
+
+-- oldstyle: not really mathematics but happened to be part of
+-- the mathematics fonts in cmr
+--
+-- persian: we will also provide mappers for other
+-- scripts
+
+-- todo: alphabets namespace
+-- maybe: script/scriptscript dynamic,
+
+local type, next = type, next
+local floor = math.floor
+
+local texattribute = tex.attribute
+
+local trace_greek = false trackers.register("math.greek", function(v) trace_greek = v end)
+
+mathematics = mathematics or { }
+
+-- we could use one level less and have tf etc be tables directly but the
+-- following approach permits easier remapping of a-a, A-Z and 0-9 to
+-- fallbacks; symbols is currently mostly greek
+
+mathematics.alphabets = {
+ regular = {
+ tf = {
+ digits = 0x00030,
+ ucletters = 0x00041,
+ lcletters = 0x00061,
+ ucgreek = {
+ [0x0391]=0x0391, [0x0392]=0x0392, [0x0393]=0x0393, [0x0394]=0x0394, [0x0395]=0x0395,
+ [0x0396]=0x0396, [0x0397]=0x0397, [0x0398]=0x0398, [0x0399]=0x0399, [0x039A]=0x039A,
+ [0x039B]=0x039B, [0x039C]=0x039C, [0x039D]=0x039D, [0x039E]=0x039E, [0x039F]=0x039F,
+ [0x03A0]=0x03A0, [0x03A1]=0x03A1, [0x03A3]=0x03A3, [0x03A4]=0x03A4, [0x03A5]=0x03A5,
+ [0x03A6]=0x03A6, [0x03A7]=0x03A7, [0x03A8]=0x03A8, [0x03A9]=0x03A9,
+ },
+ lcgreek = {
+ [0x03B1]=0x03B1, [0x03B2]=0x03B2, [0x03B3]=0x03B3, [0x03B4]=0x03B4, [0x03B5]=0x03B5,
+ [0x03B6]=0x03B6, [0x03B7]=0x03B7, [0x03B8]=0x03B8, [0x03B9]=0x03B9, [0x03BA]=0x03BA,
+ [0x03BB]=0x03BB, [0x03BC]=0x03BC, [0x03BD]=0x03BD, [0x03BE]=0x03BE, [0x03BF]=0x03BF,
+ [0x03C0]=0x03C0, [0x03C1]=0x03C1, [0x03C2]=0x03C2, [0x03C3]=0x03C3, [0x03C4]=0x03C4,
+ [0x03C5]=0x03C5, [0x03C6]=0x03C6, [0x03C7]=0x03C7, [0x03C8]=0x03C8, [0x03C9]=0x03C9,
+ [0x03D1]=0x03D1, [0x03D5]=0x03D5, [0x03D6]=0x03D6, [0x03F0]=0x03F0, [0x03F1]=0x03F1,
+ [0x03F4]=0x03F4, [0x03F5]=0x03F5,
+ },
+ symbols = {
+ [0x2202]=0x2202, [0x2207]=0x2207,
+ },
+ },
+ it = {
+ ucletters = 0x1D434,
+ lcletters = { -- H
+ [0x00061]=0x1D44E, [0x00062]=0x1D44F, [0x00063]=0x1D450, [0x00064]=0x1D451, [0x00065]=0x1D452,
+ [0x00066]=0x1D453, [0x00067]=0x1D454, [0x00068]=0x0210E, [0x00069]=0x1D456, [0x0006A]=0x1D457,
+ [0x0006B]=0x1D458, [0x0006C]=0x1D459, [0x0006D]=0x1D45A, [0x0006E]=0x1D45B, [0x0006F]=0x1D45C,
+ [0x00070]=0x1D45D, [0x00071]=0x1D45E, [0x00072]=0x1D45F, [0x00073]=0x1D460, [0x00074]=0x1D461,
+ [0x00075]=0x1D462, [0x00076]=0x1D463, [0x00077]=0x1D464, [0x00078]=0x1D465, [0x00079]=0x1D466,
+ [0x0007A]=0x1D467,
+ },
+ ucgreek = {
+ [0x0391]=0x1D6E2, [0x0392]=0x1D6E3, [0x0393]=0x1D6E4, [0x0394]=0x1D6E5, [0x0395]=0x1D6E6,
+ [0x0396]=0x1D6E7, [0x0397]=0x1D6E8, [0x0398]=0x1D6E9, [0x0399]=0x1D6EA, [0x039A]=0x1D6EB,
+ [0x039B]=0x1D6EC, [0x039C]=0x1D6ED, [0x039D]=0x1D6EE, [0x039E]=0x1D6EF, [0x039F]=0x1D6F0,
+ [0x03A0]=0x1D6F1, [0x03A1]=0x1D6F2, [0x03A3]=0x1D6F4, [0x03A4]=0x1D6F5, [0x03A5]=0x1D6F6,
+ [0x03A6]=0x1D6F7, [0x03A7]=0x1D6F8, [0x03A8]=0x1D6F9, [0x03A9]=0x1D6FA,
+ },
+ lcgreek = {
+ [0x03B1]=0x1D6FC, [0x03B2]=0x1D6FD, [0x03B3]=0x1D6FE, [0x03B4]=0x1D6FF, [0x03B5]=0x1D700,
+ [0x03B6]=0x1D701, [0x03B7]=0x1D702, [0x03B8]=0x1D703, [0x03B9]=0x1D704, [0x03BA]=0x1D705,
+ [0x03BB]=0x1D706, [0x03BC]=0x1D707, [0x03BD]=0x1D708, [0x03BE]=0x1D709, [0x03BF]=0x1D70A,
+ [0x03C0]=0x1D70B, [0x03C1]=0x1D70C, [0x03C2]=0x1D70D, [0x03C3]=0x1D70E, [0x03C4]=0x1D70F,
+ [0x03C5]=0x1D710, [0x03C6]=0x1D711, [0x03C7]=0x1D712, [0x03C8]=0x1D713, [0x03C9]=0x1D714,
+ [0x03D1]=0x1D717, [0x03D5]=0x1D719, [0x03D6]=0x1D71B, [0x03F0]=0x1D718, [0x03F1]=0x1D71A,
+ [0x03F4]=0x1D6F3, [0x03F5]=0x1D716,
+ },
+ symbols = {
+ [0x2202]=0x1D715, [0x2207]=0x1D6FB,
+ },
+ },
+ bf= {
+ digits = 0x1D7CE,
+ ucletters = 0x1D400,
+ lcletters = 0x1D41A,
+ ucgreek = {
+ [0x0391]=0x1D6A8, [0x0392]=0x1D6A9, [0x0393]=0x1D6AA, [0x0394]=0x1D6AB, [0x0395]=0x1D6AC,
+ [0x0396]=0x1D6AD, [0x0397]=0x1D6AE, [0x0398]=0x1D6AF, [0x0399]=0x1D6B0, [0x039A]=0x1D6B1,
+ [0x039B]=0x1D6B2, [0x039C]=0x1D6B3, [0x039D]=0x1D6B4, [0x039E]=0x1D6B5, [0x039F]=0x1D6B6,
+ [0x03A0]=0x1D6B7, [0x03A1]=0x1D6B8, [0x03A3]=0x1D6BA, [0x03A4]=0x1D6BB, [0x03A5]=0x1D6BC,
+ [0x03A6]=0x1D6BD, [0x03A7]=0x1D6BE, [0x03A8]=0x1D6BF, [0x03A9]=0x1D6C0,
+ },
+ lcgreek = {
+ [0x03B1]=0x1D6C2, [0x03B2]=0x1D6C3, [0x03B3]=0x1D6C4, [0x03B4]=0x1D6C5, [0x03B5]=0x1D6C6,
+ [0x03B6]=0x1D6C7, [0x03B7]=0x1D6C8, [0x03B8]=0x1D6C9, [0x03B9]=0x1D6CA, [0x03BA]=0x1D6CB,
+ [0x03BB]=0x1D6CC, [0x03BC]=0x1D6CD, [0x03BD]=0x1D6CE, [0x03BE]=0x1D6CF, [0x03BF]=0x1D6D0,
+ [0x03C0]=0x1D6D1, [0x03C1]=0x1D6D2, [0x03C2]=0x1D6D3, [0x03C3]=0x1D6D4, [0x03C4]=0x1D6D5,
+ [0x03C5]=0x1D6D6, [0x03C6]=0x1D6D7, [0x03C7]=0x1D6D8, [0x03C8]=0x1D6D9, [0x03C9]=0x1D6DA,
+ [0x03D1]=0x1D6DD, [0x03D5]=0x1D6DF, [0x03D6]=0x1D6E1, [0x03F0]=0x1D6DE, [0x03F1]=0x1D6E0,
+ [0x03F4]=0x1D6B9, [0x03F5]=0x1D6DC,
+ },
+ symbols = {
+ [0x2202]=0x1D6DB, [0x2207]=0x1D6C1,
+ },
+ },
+ bi = {
+ ucletters = 0x1D468,
+ lcletters = 0x1D482,
+ ucgreek = {
+ [0x0391]=0x1D71C, [0x0392]=0x1D71D, [0x0393]=0x1D71E, [0x0394]=0x1D71F, [0x0395]=0x1D720,
+ [0x0396]=0x1D721, [0x0397]=0x1D722, [0x0398]=0x1D723, [0x0399]=0x1D724, [0x039A]=0x1D725,
+ [0x039B]=0x1D726, [0x039C]=0x1D727, [0x039D]=0x1D728, [0x039E]=0x1D729, [0x039F]=0x1D72A,
+ [0x03A0]=0x1D72B, [0x03A1]=0x1D72C, [0x03A3]=0x1D72E, [0x03A4]=0x1D72F, [0x03A5]=0x1D730,
+ [0x03A6]=0x1D731, [0x03A7]=0x1D732, [0x03A8]=0x1D733, [0x03A9]=0x1D734,
+ },
+ lcgreek = {
+ [0x03B1]=0x1D736, [0x03B2]=0x1D737, [0x03B3]=0x1D738, [0x03B4]=0x1D739, [0x03B5]=0x1D73A,
+ [0x03B6]=0x1D73B, [0x03B7]=0x1D73C, [0x03B8]=0x1D73D, [0x03B9]=0x1D73E, [0x03BA]=0x1D73F,
+ [0x03BB]=0x1D740, [0x03BC]=0x1D741, [0x03BD]=0x1D742, [0x03BE]=0x1D743, [0x03BF]=0x1D744,
+ [0x03C0]=0x1D745, [0x03C1]=0x1D746, [0x03C2]=0x1D747, [0x03C3]=0x1D748, [0x03C4]=0x1D749,
+ [0x03C5]=0x1D74A, [0x03C6]=0x1D74B, [0x03C7]=0x1D74C, [0x03C8]=0x1D74D, [0x03C9]=0x1D74E,
+ [0x03D1]=0x1D751, [0x03D5]=0x1D753, [0x03D6]=0x1D755, [0x03F0]=0x1D752, [0x03F1]=0x1D754,
+ [0x03F4]=0x1D72D, [0x03F5]=0x1D750,
+ },
+ symbols = {
+ [0x2202]=0x1D74F, [0x2207]=0x1D735,
+ },
+ },
+ },
+ sansserif = {
+ tf = {
+ digits = 0x1D7E2,
+ ucletters = 0x1D5A0,
+ lcletters = 0x1D5BA,
+ },
+ it = {
+ ucletters = 0x1D608,
+ lcletters = 0x1D622,
+ },
+ bf = {
+ digits = 0x1D7EC,
+ ucletters = 0x1D5D4,
+ lcletters = 0x1D5EE,
+ ucgreek = {
+ [0x0391]=0x1D756, [0x0392]=0x1D757, [0x0393]=0x1D758, [0x0394]=0x1D759, [0x0395]=0x1D75A,
+ [0x0396]=0x1D75B, [0x0397]=0x1D75C, [0x0398]=0x1D75D, [0x0399]=0x1D75E, [0x039A]=0x1D75F,
+ [0x039B]=0x1D760, [0x039C]=0x1D761, [0x039D]=0x1D762, [0x039E]=0x1D763, [0x039F]=0x1D764,
+ [0x03A0]=0x1D765, [0x03A1]=0x1D766, [0x03A3]=0x1D768, [0x03A4]=0x1D769, [0x03A5]=0x1D76A,
+ [0x03A6]=0x1D76B, [0x03A7]=0x1D76C, [0x03A8]=0x1D76D, [0x03A9]=0x1D76E,
+ },
+ lcgreek = {
+ [0x03B1]=0x1D770, [0x03B2]=0x1D771, [0x03B3]=0x1D772, [0x03B4]=0x1D773, [0x03B5]=0x1D774,
+ [0x03B6]=0x1D775, [0x03B7]=0x1D776, [0x03B8]=0x1D777, [0x03B9]=0x1D778, [0x03BA]=0x1D779,
+ [0x03BB]=0x1D77A, [0x03BC]=0x1D77B, [0x03BD]=0x1D77C, [0x03BE]=0x1D77D, [0x03BF]=0x1D77E,
+ [0x03C0]=0x1D77F, [0x03C1]=0x1D780, [0x03C2]=0x1D781, [0x03C3]=0x1D782, [0x03C4]=0x1D783,
+ [0x03C5]=0x1D784, [0x03C6]=0x1D785, [0x03C7]=0x1D786, [0x03C8]=0x1D787, [0x03C9]=0x1D788,
+ [0x03D1]=0x1D78B, [0x03D5]=0x1D78D, [0x03D6]=0x1D78F, [0x03F0]=0x1D78C, [0x03F1]=0x1D78E,
+ [0x03F4]=0x1D767, [0x03F5]=0x1D78A,
+ },
+ symbols = {
+ [0x2202]=0x1D789, [0x2207]=0x1D76F,
+ },
+ },
+ bi = {
+ ucletters = 0x1D63C,
+ lcletters = 0x1D656,
+ ucgreek = {
+ [0x0391]=0x1D790, [0x0392]=0x1D791, [0x0393]=0x1D792, [0x0394]=0x1D793, [0x0395]=0x1D794,
+ [0x0396]=0x1D795, [0x0397]=0x1D796, [0x0398]=0x1D797, [0x0399]=0x1D798, [0x039A]=0x1D799,
+ [0x039B]=0x1D79A, [0x039C]=0x1D79B, [0x039D]=0x1D79C, [0x039E]=0x1D79D, [0x039F]=0x1D79E,
+ [0x03A0]=0x1D79F, [0x03A1]=0x1D7A0, [0x03A3]=0x1D7A2, [0x03A4]=0x1D7A3, [0x03A5]=0x1D7A4,
+ [0x03A6]=0x1D7A5, [0x03A7]=0x1D7A6, [0x03A8]=0x1D7A7, [0x03A9]=0x1D7A8,
+ },
+ lcgreek = {
+ [0x03B1]=0x1D7AA, [0x03B2]=0x1D7AB, [0x03B3]=0x1D7AC, [0x03B4]=0x1D7AD, [0x03B5]=0x1D7AE,
+ [0x03B6]=0x1D7AF, [0x03B7]=0x1D7B0, [0x03B8]=0x1D7B1, [0x03B9]=0x1D7B2, [0x03BA]=0x1D7B3,
+ [0x03BB]=0x1D7B4, [0x03BC]=0x1D7B5, [0x03BD]=0x1D7B6, [0x03BE]=0x1D7B7, [0x03BF]=0x1D7B8,
+ [0x03C0]=0x1D7B9, [0x03C1]=0x1D7BA, [0x03C2]=0x1D7BB, [0x03C3]=0x1D7BC, [0x03C4]=0x1D7BD,
+ [0x03C5]=0x1D7BE, [0x03C6]=0x1D7BF, [0x03C7]=0x1D7C0, [0x03C8]=0x1D7C1, [0x03C9]=0x1D7C2,
+ [0x03D1]=0x1D7C5, [0x03D5]=0x1D7C7, [0x03D6]=0x1D7C9, [0x03F0]=0x1D7C6, [0x03F1]=0x1D7C8,
+ [0x03F4]=0x1D7A1, [0x03F5]=0x1D7C4,
+ },
+ symbols = {
+ [0x2202]=0x1D7C3, [0x2207]=0x1D7A9,
+ },
+ },
+ },
+ monospaced = {
+ tf = {
+ digits = 0x1D7F6,
+ ucletters = 0x1D670,
+ lcletters = 0x1D68A,
+ },
+ },
+ blackboard = { -- ok
+ tf = {
+ digits = 0x1D7D8,
+ ucletters = { -- C H N P Q R Z
+ [0x00041]=0x1D538, [0x00042]=0x1D539, [0x00043]=0x02102, [0x00044]=0x1D53B, [0x00045]=0x1D53C,
+ [0x00046]=0x1D53D, [0x00047]=0x1D53E, [0x00048]=0x0210D, [0x00049]=0x1D540, [0x0004A]=0x1D541,
+ [0x0004B]=0x1D542, [0x0004C]=0x1D543, [0x0004D]=0x1D544, [0x0004E]=0x02115, [0x0004F]=0x1D546,
+ [0x00050]=0x02119, [0x00051]=0x0211A, [0x00052]=0x0211D, [0x00053]=0x1D54A, [0x00054]=0x1D54B,
+ [0x00055]=0x1D54C, [0x00056]=0x1D54D, [0x00057]=0x1D54E, [0x00058]=0x1D54F, [0x00059]=0x1D550,
+ [0x0005A]=0x02124,
+ },
+ lcletters = 0x1D552,
+ lcgreek = { -- gamma pi
+ [0x03B3]=0x0213C, [0x03C0]=0x0213D,
+ },
+ ucgreek = { -- Gamma pi
+ [0x0393]=0x0213E, [0x03A0]=0x0213F,
+ },
+ symbols = { -- sum
+ [0x2211]=0x02140,
+ },
+ },
+ },
+ fraktur = { -- ok
+ tf= {
+ ucletters = { -- C H I R Z
+ [0x00041]=0x1D504, [0x00042]=0x1D505, [0x00043]=0x0212D, [0x00044]=0x1D507, [0x00045]=0x1D508,
+ [0x00046]=0x1D509, [0x00047]=0x1D50A, [0x00048]=0x0210C, [0x00049]=0x02111, [0x0004A]=0x1D50D,
+ [0x0004B]=0x1D50E, [0x0004C]=0x1D50F, [0x0004D]=0x1D510, [0x0004E]=0x1D511, [0x0004F]=0x1D512,
+ [0x00050]=0x1D513, [0x00051]=0x1D514, [0x00052]=0x0211C, [0x00053]=0x1D516, [0x00054]=0x1D517,
+ [0x00055]=0x1D518, [0x00056]=0x1D519, [0x00057]=0x1D51A, [0x00058]=0x1D51B, [0x00059]=0x1D51C,
+ [0x0005A]=0x02128,
+ },
+ lcletters = 0x1D51E,
+ },
+ bf = {
+ ucletters = 0x1D56C,
+ lcletters = 0x1D586,
+ },
+ },
+ script = {
+ tf= {
+ ucletters = { -- B E F H I L M R -- P 2118
+ [0x00041]=0x1D49C, [0x00042]=0x0212C, [0x00043]=0x1D49E, [0x00044]=0x1D49F, [0x00045]=0x02130,
+ [0x00046]=0x02131, [0x00047]=0x1D4A2, [0x00048]=0x0210B, [0x00049]=0x02110, [0x0004A]=0x1D4A5,
+ [0x0004B]=0x1D4A6, [0x0004C]=0x02112, [0x0004D]=0x02133, [0x0004E]=0x1D4A9, [0x0004F]=0x1D4AA,
+ [0x00050]=0x1D4AB, [0x00051]=0x1D4AC, [0x00052]=0x0211B, [0x00053]=0x1D4AE, [0x00054]=0x1D4AF,
+ [0x00055]=0x1D4B0, [0x00056]=0x1D4B1, [0x00057]=0x1D4B2, [0x00058]=0x1D4B3, [0x00059]=0x1D4B4,
+ [0x0005A]=0x1D4B5,
+ },
+ lcletters = { -- E G O -- L 2113
+ [0x00061]=0x1D4B6, [0x00062]=0x1D4B7, [0x00063]=0x1D4B8, [0x00064]=0x1D4B9, [0x00065]=0x0212F,
+ [0x00066]=0x1D4BB, [0x00067]=0x0210A, [0x00068]=0x1D4BD, [0x00069]=0x1D4BE, [0x0006A]=0x1D4BF,
+ [0x0006B]=0x1D4C0, [0x0006C]=0x1D4C1, [0x0006D]=0x1D4C2, [0x0006E]=0x1D4C3, [0x0006F]=0x02134,
+ [0x00070]=0x1D4C5, [0x00071]=0x1D4C6, [0x00072]=0x1D4C7, [0x00073]=0x1D4C8, [0x00074]=0x1D4C9,
+ [0x00075]=0x1D4CA, [0x00076]=0x1D4CB, [0x00077]=0x1D4CC, [0x00078]=0x1D4CD, [0x00079]=0x1D4CE,
+ [0x0007A]=0x1D4CF,
+ }
+ },
+ bf = {
+ ucletters = 0x1D4D0,
+ lcletters = 0x1D4EA,
+ },
+ },
+}
+
+local alphabets = mathematics.alphabets
+local mathremap = { }
+
+for alphabet, styles in next, alphabets do
+ for style, data in next, styles do
+ -- let's keep the long names (for tracing)
+ local n = #mathremap + 1
+ data.attribute = n
+ data.alphabet = alphabet
+ data.style = style
+ mathremap[n] = data
+ end
+end
+
+-- beware, these are shared tables (no problem since they're not
+-- in unicode)
+
+alphabets.regular.it.digits = alphabets.regular.tf.digits
+alphabets.regular.bi.digits = alphabets.regular.bf.digits
+
+alphabets.sansserif.tf.symbols = alphabets.regular.tf.symbols
+alphabets.sansserif.tf.lcgreek = alphabets.regular.tf.lcgreek
+alphabets.sansserif.tf.ucgreek = alphabets.regular.tf.ucgreek
+alphabets.sansserif.tf.digits = alphabets.regular.tf.digits
+alphabets.sansserif.it.symbols = alphabets.regular.tf.symbols
+alphabets.sansserif.it.lcgreek = alphabets.regular.tf.lcgreek
+alphabets.sansserif.it.ucgreek = alphabets.regular.tf.ucgreek
+alphabets.sansserif.bi.digits = alphabets.regular.bf.digits
+
+alphabets.monospaced.tf.symbols = alphabets.sansserif.tf.symbols
+alphabets.monospaced.tf.lcgreek = alphabets.sansserif.tf.lcgreek
+alphabets.monospaced.tf.ucgreek = alphabets.sansserif.tf.ucgreek
+alphabets.monospaced.it = alphabets.sansserif.tf
+alphabets.monospaced.bf = alphabets.sansserif.tf
+alphabets.monospaced.bi = alphabets.sansserif.bf
+
+alphabets.blackboard.tf.symbols = table.merge(alphabets.regular.tf.symbols, alphabets.blackboard.tf.symbols)
+alphabets.blackboard.tf.lcgreek = table.merge(alphabets.regular.tf.lcgreek, alphabets.blackboard.tf.lcgreek)
+alphabets.blackboard.tf.ucgreek = table.merge(alphabets.regular.tf.ucgreek, alphabets.blackboard.tf.ucgreek)
+
+alphabets.blackboard.it = alphabets.blackboard.tf
+alphabets.blackboard.bf = alphabets.blackboard.tf
+alphabets.blackboard.bi = alphabets.blackboard.bf
+
+alphabets.fraktur.tf.digits = alphabets.regular.tf.digits
+alphabets.fraktur.tf.symbols = alphabets.regular.tf.symbols
+alphabets.fraktur.tf.lcgreek = alphabets.regular.tf.lcgreek
+alphabets.fraktur.tf.ucgreek = alphabets.regular.tf.ucgreek
+alphabets.fraktur.bf.digits = alphabets.regular.bf.digits
+alphabets.fraktur.bf.symbols = alphabets.regular.bf.symbols
+alphabets.fraktur.bf.lcgreek = alphabets.regular.bf.lcgreek
+alphabets.fraktur.bf.ucgreek = alphabets.regular.bf.ucgreek
+alphabets.fraktur.it = alphabets.fraktur.tf
+alphabets.fraktur.bi = alphabets.fraktur.bf
+
+alphabets.script.tf.digits = alphabets.regular.tf.digits
+alphabets.script.tf.symbols = alphabets.regular.tf.symbols
+alphabets.script.tf.lcgreek = alphabets.regular.tf.lcgreek
+alphabets.script.tf.ucgreek = alphabets.regular.tf.ucgreek
+alphabets.script.bf.digits = alphabets.regular.bf.digits
+alphabets.script.bf.symbols = alphabets.regular.bf.symbols
+alphabets.script.bf.lcgreek = alphabets.regular.bf.lcgreek
+alphabets.script.bf.ucgreek = alphabets.regular.bf.ucgreek
+alphabets.script.it = alphabets.script.tf
+alphabets.script.bi = alphabets.script.bf
+
+alphabets.tt = alphabets.monospaced
+alphabets.ss = alphabets.sansserif
+alphabets.rm = alphabets.regular
+alphabets.bb = alphabets.blackboard
+alphabets.fr = alphabets.fraktur
+alphabets.sr = alphabets.script
+
+alphabets.serif = alphabets.regular
+alphabets.type = alphabets.monospaced
+alphabets.teletype = alphabets.monospaced
+
+function mathematics.to_a_style(attribute)
+ local r = mathremap[attribute]
+ return r and r.style or "tf"
+end
+
+function mathematics.to_a_name(attribute)
+ local r = mathremap[attribute]
+ return r and r.alphabet or "regular"
+end
+
+-- of course we could do some div/mod trickery instead
+
+local mathalphabet = attributes.private("mathalphabet")
+
+function mathematics.sync_a_both(alphabet,style)
+ local data = alphabets[alphabet or "regular"] or alphabets.regular
+ data = data[style or "tf"] or data.tf
+ texattribute[mathalphabet] = data and data.attribute or texattribute[mathalphabet]
+end
+
+function mathematics.sync_a_style(style)
+--~ local r = mathremap[mathalphabet]
+ local r = mathremap[texattribute[mathalphabet]]
+ local alphabet = r and r.alphabet or "regular"
+ local data = alphabets[alphabet][style]
+ texattribute[mathalphabet] = data and data.attribute or texattribute[mathalphabet]
+end
+
+function mathematics.sync_a_name(alphabet)
+--~ local r = mathremap[mathalphabet]
+ local r = mathremap[texattribute[mathalphabet]]
+ local style = r and r.style or "tf"
+ local data = alphabets[alphabet][style]
+ texattribute[mathalphabet] = data and data.attribute or texattribute[mathalphabet]
+end
+
+local issymbol = mathematics.alphabets.regular.tf.symbols
+local islcgreek = mathematics.alphabets.regular.tf.lcgreek
+local isucgreek = mathematics.alphabets.regular.tf.ucgreek
+
+local remapping = {
+ [1] = { what = "unchanged" }, -- upright
+ [2] = { what = "upright", it = "tf", bi = "bf" }, -- upright
+ [3] = { what = "italic", tf = "it", bf = "bi" }, -- italic
+}
+
+function mathematics.remap_alphabets(char,mathalphabet,mathgreek)
+ if mathgreek > 0 then
+ local lc, uc = floor(mathgreek/10), mathgreek % 10 -- 2 == upright 3 == italic
+ if lc > 1 or uc > 1 then
+ local islc, isuc = islcgreek[char] and lc, isucgreek[char] and uc
+ if islc or isuc then
+ local r = mathremap[mathalphabet] -- what if 0
+ local alphabet = r and r.alphabet or "regular"
+ local style = r and r.style or "tf"
+ if trace_greek then
+ logs.report("math","before: char: %05X, alphabet: %s %s, lcgreek: %s, ucgreek: %s",char,alphabet,style,remapping[lc].what,remapping[uc].what)
+ end
+ local s = remapping[islc or isuc][style]
+ if s then
+ local data = alphabets[alphabet][s]
+ mathalphabet, style = data and data.attribute or mathalphabet, s
+ end
+ if trace_greek then
+ logs.report("math","after : char: %05X, alphabet: %s %s, lcgreek: %s, ucgreek: %s",char,alphabet,style,remapping[lc].what,remapping[uc].what)
+ end
+ end
+ end
+ end
+ if mathalphabet > 0 then
+ local newchar
+ local offset = mathremap[mathalphabet]
+ if not offset then
+ -- nothing to remap
+ elseif char >= 0x030 and char <= 0x039 then
+ local o = offset.digits
+ newchar = (type(o) == "table" and (o[char] or char)) or (char - 0x030 + o)
+ elseif char >= 0x041 and char <= 0x05A then
+ local o = offset.ucletters
+ newchar = (type(o) == "table" and (o[char] or char)) or (char - 0x041 + o)
+ elseif char >= 0x061 and char <= 0x07A then
+ local o = offset.lcletters
+ newchar = (type(o) == "table" and (o[char] or char)) or (char - 0x061 + o)
+ elseif islcgreek[char] then
+ newchar = offset.lcgreek[char]
+ elseif isucgreek[char] then
+ newchar = offset.ucgreek[char]
+ elseif issymbol[char] then
+ newchar = offset.symbols[char]
+ end
+ return newchar ~= char and newchar
+ end
+ return nil
+end
diff --git a/tex/context/base/math-noa.lua b/tex/context/base/math-noa.lua
new file mode 100644
index 000000000..02bbe0a62
--- /dev/null
+++ b/tex/context/base/math-noa.lua
@@ -0,0 +1,369 @@
+if not modules then modules = { } end modules ['math-noa'] = {
+ version = 1.001,
+ comment = "companion to math-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- beware: this is experimental code and there will be a more
+-- generic (attribute value driven) interface too but for the
+-- moment this is ok
+
+local utf = unicode.utf8
+
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local mlist_to_hlist = node.mlist_to_hlist
+local font_of_family = node.family_font
+local fontdata = fonts.identifiers
+
+local format, rep = string.format, string.rep
+local utfchar, utfbyte = utf.char, utf.byte
+
+noads = noads or { }
+
+local trace_remapping = false trackers.register("math.remapping", function(v) trace_remapping = v end)
+local trace_processing = false trackers.register("math.processing", function(v) trace_processing = v end)
+local trace_analyzing = false trackers.register("math.analyzing", function(v) trace_analyzing = v end)
+
+local noad_ord = 0
+local noad_op_displaylimits = 1
+local noad_op_limits = 2
+local noad_op_nolimits = 3
+local noad_bin = 4
+local noad_rel = 5
+local noad_open = 6
+local noad_close = 7
+local noad_punct = 8
+local noad_inner = 9
+local noad_under = 10
+local noad_over = 11
+local noad_vcenter = 12
+
+-- obsolete:
+--
+-- math_ord = node.id("ord") -- attr nucleus sub sup
+-- math_op = node.id("op") -- attr nucleus sub sup subtype
+-- math_bin = node.id("bin") -- attr nucleus sub sup
+-- math_rel = node.id("rel") -- attr nucleus sub sup
+-- math_punct = node.id("punct") -- attr nucleus sub sup
+--
+-- math_open = node.id("open") -- attr nucleus sub sup
+-- math_close = node.id("close") -- attr nucleus sub sup
+--
+-- math_inner = node.id("inner") -- attr nucleus sub sup
+-- math_vcenter = node.id("vcenter") -- attr nucleus sub sup
+-- math_under = node.id("under") -- attr nucleus sub sup
+-- math_over = node.id("over") -- attr nucleus sub sup
+
+local math_noad = node.id("noad") -- attr nucleus sub sup
+
+local math_accent = node.id("accent") -- attr nucleus sub sup accent
+local math_radical = node.id("radical") -- attr nucleus sub sup left degree
+local math_fraction = node.id("fraction") -- attr nucleus sub sup left right
+
+local math_box = node.id("sub_box") -- attr list
+local math_sub = node.id("sub_mlist") -- attr list
+local math_char = node.id("math_char") -- attr fam char
+local math_text_char = node.id("math_text_char") -- attr fam char
+local math_delim = node.id("delim") -- attr small_fam small_char large_fam large_char
+local math_style = node.id("style") -- attr style
+local math_choice = node.id("choice") -- attr display text script scriptscript
+local math_fence = node.id("fence") -- attr subtype
+
+local simple_noads = table.tohash {
+ math_noad,
+}
+
+local all_noads = {
+ math_noad,
+ math_box, math_sub,
+ math_char, math_text_char, math_delim, math_style,
+ math_accent, math_radical, math_fraction, math_choice, math_fence,
+}
+
+noads.processors = noads.processors or { }
+
+local function process(start,what,n)
+ if n then n = n + 1 else n = 0 end
+ while start do
+ if trace_processing then
+ logs.report("math","%s%s",rep(" ",n or 0),tostring(start))
+ end
+ local id = start.id
+ local proc = what[id]
+ if proc then
+ proc(start,what,n)
+ elseif id == math_char or id == math_text_char or id == math_delim then
+ break
+ elseif id == math_style then
+ -- has a next
+ elseif id == math_noad then
+ local noad = start.nucleus if noad then process(noad,what,n) end -- list
+ noad = start.sup if noad then process(noad,what,n) end -- list
+ noad = start.sub if noad then process(noad,what,n) end -- list
+ elseif id == math_box or id == math_sub then
+ local noad = start.list if noad then process(noad,what,n) end -- list
+ elseif id == math_fraction then
+ local noad = start.num if noad then process(noad,what,n) end -- list
+ noad = start.denom if noad then process(noad,what,n) end -- list
+ noad = start.left if noad then process(noad,what,n) end -- delimiter
+ noad = start.right if noad then process(noad,what,n) end -- delimiter
+ elseif id == math_choice then
+ local noad = start.display if noad then process(noad,what,n) end -- list
+ noad = start.text if noad then process(noad,what,n) end -- list
+ noad = start.script if noad then process(noad,what,n) end -- list
+ noad = start.scriptscript if noad then process(noad,what,n) end -- list
+ elseif id == math_fence then
+ local noad = start.delim if noad then process(noad,what,n) end -- delimiter
+ elseif id == math_radical then
+ local noad = start.nucleus if noad then process(noad,what,n) end -- list
+ noad = start.sup if noad then process(noad,what,n) end -- list
+ noad = start.sub if noad then process(noad,what,n) end -- list
+ noad = start.left if noad then process(noad,what,n) end -- delimiter
+ noad = start.degree if noad then process(noad,what,n) end -- list
+ elseif id == math_accent then
+ local noad = start.nucleus if noad then process(noad,what,n) end -- list
+ noad = start.sup if noad then process(noad,what,n) end -- list
+ noad = start.sub if noad then process(noad,what,n) end -- list
+ noad = start.accent if noad then process(noad,what,n) end -- list
+ noad = start.bot_accent if noad then process(noad,what,n) end -- list
+ else
+ -- glue, penalty, etc
+ end
+ start = start.next
+ end
+end
+
+noads.process = process
+
+-- character remapping
+
+local mathalphabet = attributes.private("mathalphabet")
+local mathgreek = attributes.private("mathgreek")
+
+noads.processors.relocate = { }
+
+local function report_remap(tag,id,old,new,extra)
+ logs.report("math","remapping %s in font %s from U+%04X (%s) to U+%04X (%s)%s",tag,id,old,utfchar(old),new,utfchar(new),extra or "")
+end
+
+local remap_alphabets = mathematics.remap_alphabets
+local fcs = fonts.color.set
+
+-- we can have a global famdata == fonts.famdata and chrdata == fonts.chrdata
+
+--~ This does not work out well, as there are no fallbacks. Ok, we could
+--~ define a poor mans simplify mechanism.
+--~
+--~ local function checked(pointer)
+--~ local char = pointer.char
+--~ local fam = pointer.fam
+--~ local id = font_of_family(fam)
+--~ local tfmdata = fontdata[id]
+--~ local tc = tfmdata and tfmdata.characters
+--~ if not tc[char] then
+--~ local specials = characters.data[char].specials
+--~ if specials and (specials[1] == "char" or specials[1] == "font") then
+--~ newchar = specials[#specials]
+--~ if trace_remapping then
+--~ report_remap("fallback",id,char,newchar)
+--~ end
+--~ if trace_analyzing then
+--~ fcs(pointer,"font:isol")
+--~ end
+--~ pointer.char = newchar
+--~ return true
+--~ end
+--~ end
+--~ end
+
+noads.processors.relocate[math_char] = function(pointer)
+ local g = has_attribute(pointer,mathgreek) or 0
+ local a = has_attribute(pointer,mathalphabet) or 0
+ if a > 0 or g > 0 then
+ if a > 0 then
+ set_attribute(pointer,mathgreek,0)
+ end
+ if g > 0 then
+ set_attribute(pointer,mathalphabet,0)
+ end
+ local char = pointer.char
+ local newchar = remap_alphabets(char,a,g)
+ if newchar then
+ local fam = pointer.fam
+ local id = font_of_family(fam)
+ local tfmdata = fontdata[id]
+ if tfmdata and tfmdata.characters[newchar] then -- we could probably speed this up
+ if trace_remapping then
+ report_remap("char",id,char,newchar)
+ end
+ if trace_analyzing then
+ fcs(pointer,"font:isol")
+ end
+ pointer.char = newchar
+ return true
+ elseif trace_remapping then
+ report_remap("char",id,char,newchar," fails")
+ end
+ else
+ -- return checked(pointer)
+ end
+ else
+ -- return checked(pointer)
+ end
+ if trace_analyzing then
+ fcs(pointer,"font:medi")
+ end
+end
+
+noads.processors.relocate[math_text_char] = function(pointer)
+ if trace_analyzing then
+ fcs(pointer,"font:init")
+ end
+end
+
+noads.processors.relocate[math_delim] = function(pointer)
+ if trace_analyzing then
+ fcs(pointer,"font:fina")
+ end
+end
+
+function noads.relocate_characters(head,style,penalties)
+ process(head,noads.processors.relocate)
+ return true
+end
+
+-- some resize options (this works ok because the content is
+-- empty and no larger next will be forced)
+--
+-- beware: we don't use \delcode but \Udelcode and as such have
+-- no large_fam; also, we need to check for subtype and/or
+-- small_fam not being 0 because \. sits in 0,0 by default
+--
+-- todo: just replace the character by an ord noad
+-- and remove the right delimiter as well
+
+local mathsize = attributes.private("mathsize")
+
+noads.processors.resize = { }
+
+noads.processors.resize[math_fence] = function(pointer)
+ if pointer.subtype == 1 then -- left
+ local a = has_attribute(pointer,mathsize)
+ if a and a > 0 then
+ set_attribute(pointer,mathsize,0)
+ local d = pointer.delim
+ local df = d.small_fam
+ local id = font_of_family(df)
+ if id > 0 then
+ local ch = d.small_char
+ d.small_char = mathematics.big(fontdata[id],ch,a)
+ end
+ end
+ end
+end
+
+function noads.resize_characters(head,style,penalties)
+ process(head,noads.processors.resize)
+ return true
+end
+
+-- respacing
+
+local mathpunctuation = attributes.private("mathpunctuation")
+
+noads.processors.respace = { }
+
+local chardata = characters.data
+
+-- only [nd,ll,ul][po][nd,ll,ul]
+
+noads.processors.respace[math_noad] = function(pointer)
+ if pointer.subtype == noad_ord then
+ local a = has_attribute(pointer,mathpunctuation)
+ if a and a > 0 then
+ set_attribute(pointer,mathpunctuation,0)
+ local current_nucleus = pointer.nucleus
+ if current_nucleus.id == math_char then
+ local current_char = current_nucleus.char
+ local fc = chardata[current_char]
+ fc = fc and fc.category
+ if fc == "nd" or fc == "ll" or fc == "lu" then
+ local next_noad = pointer.next
+ if next_noad and next_noad.id == math_noad and next_noad.subtype == noad_punct then
+ local next_nucleus = next_noad.nucleus
+ if next_nucleus.id == math_char then
+ local next_char = next_nucleus.char
+ local nc = chardata[next_char]
+ nc = nc and nc.category
+ if nc == "po" then
+ local last_noad = next_noad.next
+ if last_noad and last_noad.id == math_noad and last_noad.subtype == noad_ord then
+ local last_nucleus = last_noad.nucleus
+ if last_nucleus.id == math_char then
+ local last_char = last_nucleus.char
+ local lc = chardata[last_char]
+ lc = lc and lc.category
+ if lc == "nd" or lc == "ll" or lc == "lu" then
+ local ord = node.new(math_noad) -- todo: pool
+ ord.subtype, ord.nucleus, ord.sub, ord.sup, ord.attr = noad_ord, next_noad.nucleus, next_noad.sub, next_noad.sup, next_noad.attr
+ -- next_noad.nucleus, next_noad.sub, next_noad.sup, next_noad.attr = nil, nil, nil, nil
+ next_noad.nucleus, next_noad.sub, next_noad.sup = nil, nil, nil -- else crash with attributes ref count
+ --~ next_noad.attr = nil
+ ord.next = last_noad
+ pointer.next = ord
+ node.free(next_noad)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+
+function noads.respace_characters(head,style,penalties)
+ noads.process(head,noads.processors.respace)
+ return true
+end
+
+-- the normal builder
+
+function noads.mlist_to_hlist(head,style,penalties)
+ return mlist_to_hlist(head,style,penalties), true
+end
+
+tasks.new (
+ "math",
+ {
+ "before",
+ "normalizers",
+ "builders",
+ "after",
+ }
+)
+
+local actions = tasks.actions("math",2) -- head, style, penalties
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
+function nodes.processors.mlist_to_hlist(head,style,penalties)
+ starttiming(noads)
+ local head, done = actions(head,style,penalties)
+ stoptiming(noads)
+ return head, done
+end
+
+callbacks.register('mlist_to_hlist',nodes.processors.mlist_to_hlist,"preprocessing math list")
+
+-- tracing
+
+statistics.register("math processing time", function()
+ return statistics.elapsedseconds(noads)
+end)
diff --git a/tex/context/base/math-pln.mkii b/tex/context/base/math-pln.mkii
new file mode 100644
index 000000000..f2f3ff183
--- /dev/null
+++ b/tex/context/base/math-pln.mkii
@@ -0,0 +1,360 @@
+%D \module
+%D [ file=math-pln,
+%D version=2001.11.16,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Plain Helpers,
+%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.
+
+% \points should become \bodyfontsize
+
+%D This is a temporary module, some of this code will move to
+%D the other math modules.
+
+\writestatus{loading}{ConTeXt Math Macros / Plain Helpers}
+
+\unprotect
+
+\ifx\displ@y\undefined \let\displ@y\relax\fi
+
+\newbox\rootbox
+
+\def\root#1\of
+ {\setbox\rootbox\hbox{$\mathsurround\zeropoint\scriptscriptstyle{#1}$}%
+ \mathpalette\r@@t}
+
+\def\r@@t#1#2% will be overloaded
+ {\setbox\zerocount\hbox{$\mathsurround\zeropoint#1\sqrt{#2}$}\dimen@\ht\zerocount
+ \advance\dimen@-\dp\zerocount
+ \mkern5mu\raise.6\dimen@\copy\rootbox
+ \mkern-10mu\box\zerocount}
+
+\def\mathhexbox#1#2#3%
+ {\leavevmode
+ \hbox{$\mathsurround\zeropoint\mathchar"#1#2#3$}}
+
+\def\oalign#1%
+ {\leavevmode
+ \vtop
+ {\baselineskip\zeroskip \lineskip.25ex%
+ \ialign{##\crcr#1\crcr}}}
+
+\def\o@lign
+ {\lineskiplimit\zeropoint \oalign}
+
+\def\ooalign % chars over each other
+ {\lineskiplimit-\maxdimen
+ \oalign}
+
+\def\sh@ft#1% kern by #1 times the current slant
+ {\dimen@#1%
+ \kern\expandafter\withoutpt\the\slantperpoint
+ \dimen@}
+
+\def\dots
+ {\relax\ifmmode\ldots\else$\mathsurround\zeropoint\ldots\,$\fi}
+
+\def\hrulefill
+ {\leaders\hrule\hfill}
+
+\def\dotfill
+ {\cleaders\hbox{$\mathsurround\zeropoint \mkern1.5mu.\mkern1.5mu$}\hfill}
+
+\def\rightarrowfill
+ {$\mathsurround\zeropoint\smash-\mkern-7mu%
+ \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
+ \mkern-7mu\mathord\rightarrow$}
+
+\def\leftarrowfill
+ {$\mathsurround\zeropoint\mathord\leftarrow\mkern-7mu%
+ \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
+ \mkern-7mu\smash-$}
+
+% must go to math-tex
+
+\ifx\braceld\undefined
+ % mkii values
+ \mathchardef\braceld="37A
+ \mathchardef\bracerd="37B
+ \mathchardef\bracelu="37C
+ \mathchardef\braceru="37D
+\fi
+
+\def\downbracefill
+ {$\mathsurround\zeropoint\setbox\zerocount\hbox{$\braceld$}%
+ \braceld\leaders\vrule\!!height\ht\zerocount\!!depth\zeropoint\hfill\braceru
+ \bracelu\leaders\vrule\!!height\ht\zerocount\!!depth\zeropoint\hfill\bracerd$}
+
+\def\upbracefill
+ {$\mathsurround\zeropoint\setbox\zerocount\hbox{$\braceld$}%
+ \bracelu\leaders\vrule\!!height\ht\zerocount\!!depth\zeropoint\hfill\bracerd
+ \braceld\leaders\vrule\!!height\ht\zerocount\!!depth\zeropoint\hfill\braceru$}
+
+% hm, shouldn't that be \kern3\bodyfontsize
+
+\def\overbrace#1%
+ {\mathop{\vbox{\mathsurround\zeropoint\ialign{##\crcr\noalign{\kern3\points}
+ \downbracefill\crcr\noalign{\kern3\points\nointerlineskip}
+ $\hfil\displaystyle{#1}\hfil$\crcr}}}\limits}
+
+\def\underbrace#1%
+ {\mathop{\vtop{\mathsurround\zeropoint\ialign{##\crcr
+ $\hfil\displaystyle{#1}\hfil$\crcr\noalign{\kern3\points\nointerlineskip}
+ \upbracefill\crcr\noalign{\kern3\points}}}}\limits}
+
+\let\sp=^ % will become obsolete
+\let\sb=_ % will become obsolete
+
+\ifx\,\undefined \def\,{\mskip \thinmuskip } \fi
+\ifx\>\undefined \def\>{\mskip \medmuskip } \fi
+\ifx\;\undefined \def\;{\mskip \thickmuskip} \fi
+\ifx\!\undefined \def\!{\mskip-\thinmuskip } \fi
+\ifx\*\undefined \def\*{\discretionary{\thinspace\the\textfont2\char2}{}{}} \fi
+
+% {\catcode`\'=\active \gdef'{^\bgroup\prim@s}}
+
+\def\activemathquote{^\bgroup\prim@s}
+
+\def\prim@s
+ {\prime\futurelet\next\pr@m@s}
+
+\def\pr@m@s
+ {\ifx'\next
+ \@EA\pr@@@s
+ \else\ifx^\next
+ \@EAEAEA\pr@@@t
+ \else
+ \@EAEAEA\egroup
+ \fi\fi}
+
+\def\pr@@@s#1%
+ {\prim@s}
+
+\def\pr@@@t#1#2%
+ {#2\egroup}
+
+% {\catcode`\_=\active \global\let_=\_} % _ in math is either subscript or \_
+
+\let\activemathunderscore\_
+
+\def\relbar {\mathrel{\smash-}} % - has the same height as +
+\def\Relbar {\mathrel=}
+
+\def\Longrightarrow {\Relbar\joinrel\Rightarrow}
+\def\longrightarrow {\relbar\joinrel\rightarrow}
+\def\longleftarrow {\leftarrow\joinrel\relbar}
+\def\Longleftarrow {\Leftarrow\joinrel\Relbar}
+\def\longmapsto {\mapstochar\longrightarrow}
+\def\longleftrightarrow{\leftarrow\joinrel\rightarrow}
+\def\Longleftrightarrow{\Leftarrow\joinrel\Rightarrow}
+
+\def\overrightarrow#1%
+ {\vbox{\mathsurround\zeropoint\ialign{##\crcr
+ \rightarrowfill\crcr\noalign{\kern-\onepoint\nointerlineskip}
+ $\hfil\displaystyle{#1}\hfil$\crcr}}}
+
+\def\overleftarrow#1%
+ {\vbox{\mathsurround\zeropoint\ialign{##\crcr
+ \leftarrowfill\crcr\noalign{\kern-\onepoint\nointerlineskip}
+ $\hfil\displaystyle{#1}\hfil$\crcr}}}
+
+\def\skew#1#2#3%
+ {{\muskip\zerocount#1mu\divide\muskip\zerocount\plustwo \mkern\muskip\zerocount
+ #2{\mkern-\muskip\zerocount{#3}\mkern\muskip\zerocount}\mkern-\muskip\zerocount}{}}
+
+\def\choose{\atopwithdelims()}
+\def\brack {\atopwithdelims[]}
+\def\brace {\atopwithdelims\{\}}
+
+\def\mathpalette#1#2%
+ {\mathchoice
+ {#1\displaystyle {#2}}%
+ {#1\textstyle {#2}}%
+ {#1\scriptstyle {#2}}%
+ {#1\scriptscriptstyle{#2}}}
+
+\def\cong
+ {\mathrel{\mathpalette\@vereq\sim}} % congruence sign
+
+\def\@vereq#1#2%
+ {\lower.5\points\vbox{\lineskiplimit\maxdimen\lineskip-.5\points
+ \ialign{$\mathsurround\zeropoint#1\hfil##\hfil$\crcr#2\crcr=\crcr}}}
+
+\def\notin% can be mkiv'd
+ {\mathrel{\mathpalette\c@ncel\in}}
+
+\def\c@ncel#1#2%
+ {\mathsurround\zeropoint\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}}
+
+\def\rightleftharpoons%
+ {\mathrel{\mathpalette\rlh@{}}}
+
+\def\rlh@#1%
+ {\vcenter
+ {\mathsurround\zeropoint
+ \hbox
+ {\ooalign
+ {\raise2pt\hbox{$#1\rightharpoonup$}\crcr
+ $#1\leftharpoondown$}}}}
+
+\def\buildrel#1\over#2%
+ {\mathrel{\mathop{\kern\zeropoint#2}\limits^{#1}}}
+
+\def\doteq
+ {\buildrel\textstyle.\over=}
+
+\ifx\mfunction\undefined \def\mfunction#1{\mathbin{\rm#1}} \fi
+
+\def\bmod
+ {\nonscript
+ \mskip-\medmuskip
+ \mkern5mu
+ \mfunction{mod}%
+ \penalty900
+ \mkern5mu
+ \nonscript
+ \mskip-\medmuskip}
+
+\def\pmod#1%
+ {\allowbreak
+ \mkern18mu
+ (\mfunction{mod}\,\,#1)}
+
+\def\cases#1%
+ {\left\{%
+ \,%
+ \vcenter
+ {\normalbaselines
+ \mathsurround\zeropoint
+ \ialign{$##\hfil$&\quad##\hfil\crcr#1\crcr}}%
+ \right.}
+
+\def\matrix#1%
+ {\null
+ \,%
+ \vcenter
+ {\normalbaselines\mathsurround\zeropoint
+ \ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
+ \mathstrut\crcr\noalign{\kern-\baselineskip}
+ #1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}%
+ \,}
+
+\def\pmatrix#1%
+ {\left(\matrix{#1}\right)}
+
+\newdimen\mathparentwd
+
+% \setbox0=\hbox{\tenex B} \mathparentwd=\wd0 % width of the big left (
+
+\def\bordermatrix#1%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox\zerocount\vbox
+ {\def\cr{\crcr\noalign{\kern2\points\global\let\cr\endline}}%
+ \ialign{$##$\hfil\kern2\points\kern\mathparentwd&\thinspace\hfil$##$\hfil
+ &&\quad\hfil$##$\hfil\crcr
+ \omit\strut\hfil\crcr\noalign{\kern-\baselineskip}%
+ #1\crcr\omit\strut\cr}}%
+ \setbox\plustwo\vbox
+ {\unvcopy\zerocount\global\setbox\plusone\lastbox}%
+ \setbox\plustwo\hbox
+ {\unhbox\plusone\unskip\global\setbox\plusone\lastbox}%
+ \setbox\plustwo\hbox
+ {$\kern\wd\plusone\kern-\mathparentwd\left(\kern-\wd\plusone
+ \global\setbox\plusone\vbox{\box\plusone\kern2\points}%
+ \vcenter{\kern-\ht\plusone\unvbox\zerocount\kern-\baselineskip}\,\right)$}%
+ \null
+ \;%
+ \vbox{\kern\ht\plusone\box\plustwo}%
+ \endgroup}
+
+% \def\openup{\afterassignment\@penup\dimen@=}
+%
+% \def\@penup{\advance\lineskip\dimen@
+% \advance\baselineskip\dimen@
+% \advance\lineskiplimit\dimen@}
+
+\def\openup
+ {\afterassignment\doopenup\scratchdimen=}
+
+\def\doopenup
+ {\advance\lineskip \scratchdimen
+ \advance\baselineskip \scratchdimen
+ \advance\lineskiplimit\scratchdimen}
+
+% \def\jot{.25\bodyfontsize} % plain tex: 3 pt (todo: better name and configurable)
+
+\def\displayopenupvalue{.25\bodyfontsize}
+
+\def\eqalign#1%
+ {\null
+ \,%
+ \vcenter
+ {\openup\displayopenupvalue % was \openup\jot
+ \mathsurround\zeropoint
+ \ialign
+ {\strut\hfil$\displaystyle{##}$&$\displaystyle{{}##}$\hfil\crcr
+ #1\crcr}}%
+ \,}
+
+\def\@lign % restore inside \displ@y
+ {\tabskip\zeroskip
+ \everycr{}}
+
+\def\displaylines#1%
+ {\displ@y
+ \tabskip\zeroskip
+ \halign
+ {\hbox to \displaywidth{$\@lign\hfil\displaystyle##\hfil$}\crcr
+ #1\crcr}}
+
+\def\eqalignno#1%
+ {\displ@y
+ \tabskip\centering
+ \halign to \displaywidth
+ {\hfil$\@lign\displaystyle{##}$\tabskip\zeroskip
+ &$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
+ &\llap{$\@lign##$}\tabskip\zeroskip\crcr
+ #1\crcr}}
+
+\def\leqalignno#1%
+ {\displ@y
+ \tabskip\centering
+ \halign to \displaywidth
+ {\hfil$\@lign\displaystyle{##}$\tabskip\zeroskip
+ &$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
+ &\kern-\displaywidth\rlap{$\@lign##$}\tabskip\displaywidth\crcr
+ #1\crcr}}
+
+% temporary here
+
+% \startcatcodetable \mthcatcodes
+% \setcatcodetable\ctxcatcodes
+% \catcode`\_ = 13
+% \catcode`\' = 13
+% \stopcatcodetable
+%
+% \letcatcodecommand \mthcatcodes `\_ \activemathunderscore
+% \letcatcodecommand \mthcatcodes `\' \activemathquote
+
+% \appendtoks \setcatcodetable\mthcatcodes \to \everymath : spoils xml
+
+% tricky, but some day we will reimplement math
+
+\bgroup
+ \catcode`\_ = 13
+ \catcode`\' = 13
+ \doglobal\appendtoks
+ \let_\activemathunderscore
+ \let'\activemathquote
+ \to \everymathematics
+\egroup
+
+% so far
+
+\protect \endinput
diff --git a/tex/context/base/math-pln.mkiv b/tex/context/base/math-pln.mkiv
new file mode 100644
index 000000000..ab584f10a
--- /dev/null
+++ b/tex/context/base/math-pln.mkiv
@@ -0,0 +1,298 @@
+%D \module
+%D [ file=math-pln,
+%D version=2001.11.16,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Plain Helpers,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is a temporary module, some of this code will move to
+%D the other math modules. Much is copied from Plain \TEX.
+
+% \points should become \bodyfontsize
+
+\writestatus{loading}{ConTeXt Math Macros / Plain Helpers}
+
+\unprotect
+
+\ifx\displ@y\undefined \let\displ@y\relax\fi
+
+\def\oalign#1%
+ {\leavevmode
+ \vtop
+ {\baselineskip\zeroskip \lineskip.25ex%
+ \ialign{##\crcr#1\crcr}}}
+
+\def\o@lign
+ {\lineskiplimit\zeropoint \oalign}
+
+\def\ooalign % chars over each other
+ {\lineskiplimit-\maxdimen
+ \oalign}
+
+\def\sh@ft#1% kern by #1 times the current slant
+ {\dimen@#1%
+ \kern\expandafter\withoutpt\the\slantperpoint
+ \dimen@}
+
+\def\dots
+ {\relax\ifmmode\ldots\else$\mathsurround\zeropoint\ldots\,$\fi}
+
+\def\hrulefill
+ {\leaders\hrule\hfill}
+
+\def\dotfill
+ {\cleaders\hbox{$\mathsurround\zeropoint \mkern1.5mu.\mkern1.5mu$}\hfill}
+
+\def\rightarrowfill
+ {$\mathsurround\zeropoint\smash-\mkern-7mu%
+ \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
+ \mkern-7mu\mathord\rightarrow$}
+
+\def\leftarrowfill
+ {$\mathsurround\zeropoint\mathord\leftarrow\mkern-7mu%
+ \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
+ \mkern-7mu\smash-$}
+
+\let\sp=^ % will become obsolete
+\let\sb=_ % will become obsolete
+
+\ifx\,\undefined \def\,{\mskip \thinmuskip } \fi
+\ifx\>\undefined \def\>{\mskip \medmuskip } \fi
+\ifx\;\undefined \def\;{\mskip \thickmuskip} \fi
+\ifx\!\undefined \def\!{\mskip-\thinmuskip } \fi
+\ifx\*\undefined \def\*{\discretionary{\thinspace\the\textfont2\char2}{}{}} \fi
+
+% {\catcode`\'=\active \gdef'{^\bgroup\prim@s}}
+
+\def\activemathquote{^\bgroup\prim@s}
+
+\def\prim@s
+ {\prime\futurelet\next\pr@m@s}
+
+\def\pr@m@s
+ {\ifx'\next
+ \@EA\pr@@@s
+ \else\ifx^\next
+ \@EAEAEA\pr@@@t
+ \else
+ \@EAEAEA\egroup
+ \fi\fi}
+
+\def\pr@@@s#1%
+ {\prim@s}
+
+\def\pr@@@t#1#2%
+ {#2\egroup}
+
+% {\catcode`\_=\active \global\let_=\_} % _ in math is either subscript or \_
+
+\let\activemathunderscore\_
+
+\def\relbar {\mathrel{\smash-}} % - has the same height as +
+\def\Relbar {\mathrel=}
+
+\def\Longrightarrow {\Relbar\joinrel\Rightarrow} % beware, this overloades cambria native
+\def\longrightarrow {\relbar\joinrel\rightarrow}
+\def\longleftarrow {\leftarrow\joinrel\relbar}
+\def\Longleftarrow {\Leftarrow\joinrel\Relbar}
+\def\longmapsto {\mapstochar\longrightarrow}
+\def\longleftrightarrow{\leftarrow\joinrel\rightarrow}
+\def\Longleftrightarrow{\Leftarrow\joinrel\Rightarrow}
+
+\def\choose{\atopwithdelims()}
+\def\brack {\atopwithdelims[]}
+\def\brace {\atopwithdelims\{\}}
+
+\def\mathpalette#1#2%
+ {\mathchoice
+ {#1\displaystyle {#2}}%
+ {#1\textstyle {#2}}%
+ {#1\scriptstyle {#2}}%
+ {#1\scriptscriptstyle{#2}}}
+
+\def\cong
+ {\mathrel{\mathpalette\@vereq\sim}} % congruence sign
+
+\def\@vereq#1#2%
+ {\lower.5\points\vbox{\lineskiplimit\maxdimen\lineskip-.5\points
+ \ialign{$\mathsurround\zeropoint#1\hfil##\hfil$\crcr#2\crcr=\crcr}}}
+
+\def\notin
+ {\mathrel{\mathpalette\c@ncel\in}}
+
+\def\c@ncel#1#2%
+ {\mathsurround\zeropoint\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}}
+
+\def\rightleftharpoons
+ {\mathrel{\mathpalette\rlh@{}}}
+
+\def\rlh@#1%
+ {\vcenter
+ {\mathsurround\zeropoint
+ \hbox
+ {\ooalign
+ {\raise2pt\hbox{$#1\rightharpoonup$}\crcr
+ $#1\leftharpoondown$}}}}
+
+\def\buildrel#1\over#2%
+ {\mathrel{\mathop{\kern\zeropoint#2}\limits^{#1}}}
+
+\def\doteq
+ {\buildrel\textstyle.\over=}
+
+\ifx\mfunction\undefined \def\mfunction#1{\mathbin{\rm#1}} \fi
+
+\def\bmod
+ {\nonscript
+ \mskip-\medmuskip
+ \mkern5mu
+ \mfunction{mod}%
+ \penalty900
+ \mkern5mu
+ \nonscript
+ \mskip-\medmuskip}
+
+\def\pmod#1%
+ {\allowbreak
+ \mkern18mu
+ (\mfunction{mod}\,\,#1)}
+
+\def\cases#1%
+ {\left\{%
+ \,%
+ \vcenter
+ {\normalbaselines
+ \mathsurround\zeropoint
+ \ialign{$##\hfil$&\quad##\hfil\crcr#1\crcr}}%
+ \right.}
+
+\def\matrix#1%
+ {\null
+ \,%
+ \vcenter
+ {\normalbaselines\mathsurround\zeropoint
+ \ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
+ \mathstrut\crcr\noalign{\kern-\baselineskip}
+ #1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}%
+ \,}
+
+\def\pmatrix#1%
+ {\left(\matrix{#1}\right)}
+
+\newdimen\mathparentwd
+
+% \setbox0=\hbox{\tenex B} \mathparentwd=\wd0 % width of the big left (
+
+\def\bordermatrix#1%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox\zerocount\vbox
+ {\def\cr{\crcr\noalign{\kern2\points\global\let\cr\endline}}%
+ \ialign{$##$\hfil\kern2\points\kern\mathparentwd&\thinspace\hfil$##$\hfil
+ &&\quad\hfil$##$\hfil\crcr
+ \omit\strut\hfil\crcr\noalign{\kern-\baselineskip}%
+ #1\crcr\omit\strut\cr}}%
+ \setbox\plustwo\vbox
+ {\unvcopy\zerocount\global\setbox\plusone\lastbox}%
+ \setbox\plustwo\hbox
+ {\unhbox\plusone\unskip\global\setbox\plusone\lastbox}%
+ \setbox\plustwo\hbox
+ {$\kern\wd\plusone\kern-\mathparentwd\left(\kern-\wd\plusone
+ \global\setbox\plusone\vbox{\box\plusone\kern2\points}%
+ \vcenter{\kern-\ht\plusone\unvbox\zerocount\kern-\baselineskip}\,\right)$}%
+ \null
+ \;%
+ \vbox{\kern\ht\plusone\box\plustwo}%
+ \endgroup}
+
+% \def\openup{\afterassignment\@penup\dimen@=}
+%
+% \def\@penup{\advance\lineskip\dimen@
+% \advance\baselineskip\dimen@
+% \advance\lineskiplimit\dimen@}
+
+\def\openup
+ {\afterassignment\doopenup\scratchdimen=}
+
+\def\doopenup
+ {\advance\lineskip \scratchdimen
+ \advance\baselineskip \scratchdimen
+ \advance\lineskiplimit\scratchdimen}
+
+% \def\jot{.25\bodyfontsize} % plain tex: 3 pt (todo: better name and configurable)
+
+\def\displayopenupvalue{.25\bodyfontsize}
+
+\def\eqalign#1%
+ {\null
+ \,%
+ \vcenter
+ {\openup\displayopenupvalue % was \openup\jot
+ \mathsurround\zeropoint
+ \ialign
+ {\strut\hfil$\displaystyle{##}$&$\displaystyle{{}##}$\hfil\crcr
+ #1\crcr}}%
+ \,}
+
+\def\@lign % restore inside \displ@y
+ {\tabskip\zeroskip
+ \everycr{}}
+
+\def\displaylines#1%
+ {\displ@y
+ \tabskip\zeroskip
+ \halign
+ {\hbox to \displaywidth{$\@lign\hfil\displaystyle##\hfil$}\crcr
+ #1\crcr}}
+
+\def\eqalignno#1%
+ {\displ@y
+ \tabskip\centering
+ \halign to \displaywidth
+ {\hfil$\@lign\displaystyle{##}$\tabskip\zeroskip
+ &$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
+ &\llap{$\@lign##$}\tabskip\zeroskip\crcr
+ #1\crcr}}
+
+\def\leqalignno#1%
+ {\displ@y
+ \tabskip\centering
+ \halign to \displaywidth
+ {\hfil$\@lign\displaystyle{##}$\tabskip\zeroskip
+ &$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
+ &\kern-\displaywidth\rlap{$\@lign##$}\tabskip\displaywidth\crcr
+ #1\crcr}}
+
+% temporary here (weird code)
+
+% \startcatcodetable \mthcatcodes
+% \setcatcodetable\ctxcatcodes
+% \catcode`\_ = 13
+% \catcode`\' = 13
+% \stopcatcodetable
+%
+% \letcatcodecommand \mthcatcodes `\_ \activemathunderscore
+% \letcatcodecommand \mthcatcodes `\' \activemathquote
+
+% \appendtoks \setcatcodetable\mthcatcodes \to \everymath : spoils xml
+
+% tricky, but some day we will reimplement math
+
+\bgroup
+ \catcode`\_ = 13
+ \catcode`\' = 13
+ \doglobal\appendtoks
+ \let_\activemathunderscore
+ \let'\activemathquote
+ \to \everymathematics
+\egroup
+
+% so far
+
+\protect \endinput
diff --git a/tex/context/base/math-run.mkii b/tex/context/base/math-run.mkii
new file mode 100644
index 000000000..6bc4bf4d5
--- /dev/null
+++ b/tex/context/base/math-run.mkii
@@ -0,0 +1,105 @@
+%D \module
+%D [ file=math-run,
+%D version=2001.23.04,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Runtime Macros,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=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 Math Macros / Runtime Macros}
+
+\unprotect
+
+\ifx\showmathmodern\undefined \global\chardef\showmathmodern\zerocount \fi
+
+\gdef\showmathcharacters% nearly \showcharacters
+ {\par
+ \bgroup
+ \ifcase\showmathmodern\or\ifx\modern\undefined\chardef\showmathmodern\zerocount\fi\fi
+ \setuptextrules[\c!bodyfont=,\c!style=]
+ \starttextrule{math characters -- \currentmathcollection}
+ \whitespace
+ \dontcomplain
+ \forgetall
+ \def\startmathcollection[##1]{}
+ \let\stopmathcollection\relax
+ \dimen0\zeropoint
+ \dimen2\zeropoint
+ \def\definemathsymbol {\dosixtupleempty\dodefinemathsymbol}
+ \def\definemathcharacter{\dosixtupleempty\dodefinemathcharacter}
+ \def\definemathcommand {\dotripleempty \dodefinemathcommand}
+ %\newcounter\mathcolor
+ \def\dodefinemathsymbol[##1][##2][##3][##4][##5][##6]%
+ {%\doifcolorelse{math \purefamilyhex{##3}}{}
+ % {\increment\mathcolor
+ % \definecolor[math \purefamilyhex{##3}][\mathcolor]}%
+ \setbox0\hbox spread 1em{\mathematics{\getvalue{##1}{}{}{}}}%
+ \ifdim\wd0>\dimen0 \dimen0=\wd0 \fi
+ \setbox2\hbox spread 1em{\hbox to 1em{\tttf\purefamilyhex{##3}\hss}\box0 ##1}%
+ \ifdim\wd2>\dimen2 \dimen2=\wd2 \fi}
+ \def\dodefinemathcharacter[##1][##2][##3][##4][##5][##6]{}
+ \def\dodefinemathcommand [##1][##2][##3]##4{}
+ \readsysfile{\f!mathprefix tex.mkii}\!!doneatrue\!!doneafalse
+ \readsysfile{\f!mathprefix ams.mkii}\!!donebtrue\!!donebfalse
+ \if!!donea
+ \if!!doneb
+ \edef\encwidth{\the\dimen0}
+ \dimen0=\hsize
+ \advance\dimen0 2em
+ \advance\dimen2 2em
+ \ifcase\showmathmodern\or\advance\dimen2 4em\fi
+ \divide \dimen0 by \dimen2 \advance\dimen0 1sp
+ \edef\enccols{\number\dimen0}
+ \startcolumns[\c!n=\enccols,\c!distance=2em]
+ \def\dodefinemathsymbol[##1][##2][##3][##4][##5][##6]%
+ {%\localcolortrue
+ %\color
+ % [math \purefamilyhex{##3}]
+ {\hbox
+ {\ifcase\showmathmodern\or
+ \hbox to \encwidth{\modern\let\mathcollection\nomathcollection\mathematics{\getvalue{##1}{}{}{}}\hss}%
+ \fi
+ \hbox to \encwidth{\mathematics{\getvalue{##1}{}{}{}}\hss}%
+ \hbox to 1em{\tttf\purefamilyhex{##3}\hss}##1}\par}}
+ \readsysfile{\f!mathprefix tex.mkii}\donothing\donothing
+ \readsysfile{\f!mathprefix ams.mkii}\donothing\donothing
+ \stopcolumns
+ \else
+ \par \tttf no chars in \f!mathprefix ams\par
+ \fi
+ \else
+ \par \tttf no chars in \f!mathprefix tex\par
+ \fi
+ \stoptextrule
+ \egroup}
+
+% \definecolor[math \purefamilyhex{mr}] [darkred]
+% \definecolor[math \purefamilyhex{mi}] [darkgreen]
+% \definecolor[math \purefamilyhex{sy}] [darkblue]
+% \definecolor[math \purefamilyhex{ex}] [darkmagenta]
+% \definecolor[math \purefamilyhex{nn}] [darkyellow]
+% \definecolor[math \purefamilyhex{ma}] [lightred]
+% \definecolor[math \purefamilyhex{mb}] [lightgreen]
+% \definecolor[math \purefamilyhex{mc}] [lightblue]
+% \definecolor[math \purefamilyhex{md}] [lightmagenta]
+
+\gdef\showmathtoken#1%
+ {\starttabulate[|lT|lT|lT|l|]
+ \NC token \NC #1 \NC \NR
+ \NC collection \NC \ifcsname\@mt@\mathcollection#1\endcsname
+ \mathcollection
+ \else\ifcsname\@mt@\nomathcollection#1\endcsname
+ \nomathcollection
+ \else
+ ?%
+ \fi\fi \NC \NR
+ \NC visualization \NC \mathematics{\getvalue{#1}} \NC \NR
+ \NC definition \NC \tttf \@EA\defconvertedcommand\@EA\ascii\csname\@mt@\mathcollection#1\endcsname \ascii \NC \NR
+ \stoptabulate}
+
+\protect \endinput
diff --git a/tex/context/base/math-scr.mkiv b/tex/context/base/math-scr.mkiv
new file mode 100644
index 000000000..eb1db4714
--- /dev/null
+++ b/tex/context/base/math-scr.mkiv
@@ -0,0 +1,135 @@
+%D \module
+%D [ file=math-scr,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Scripts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%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 Math Macros / Scripts}
+
+\unprotect
+
+%D \macros
+%D {super, sub}
+%D
+%D \TEX\ uses \type{^} and \type{_} for entering super- and
+%D subscript mode. We want however a bit more control than
+%D normally provided, and therefore provide \type {\super}
+%D and \type{sub}.
+%D
+%D The grid snapping has been removed.
+
+\global\let\normalsuper=^
+\global\let\normalsuber=_
+
+\ifdefined\supersubmode \else \newcount\supersubmode \fi
+\ifdefined\newevery \else \everysupersub \EverySuperSub \fi
+
+\appendtoks \advance\supersubmode \plusone \to \everysupersub
+
+\setuptextformulas
+ [\c!size=\v!normal]
+
+\def\normalsupsub#1#2%
+ {^{\the\everysupersub#1}_{\the\everysupersub#2}}
+
+\def\super#1{^{\the\everysupersub#1}}
+\def\suber#1{_{\the\everysupersub#1}}
+\def\supsub#1#2{\super{#1}\suber{#2}}
+\def\subsup#1#2{\suber{#1}\super{#2}}
+
+%D \macros
+%D {enablesupersub,enablesimplesupersub}
+%D
+%D We can let \type {^} and \type {_} act like \type {\super}
+%D and \type {\sub} by saying \type {\enablesupersub}.
+
+\bgroup
+\catcode`\^=\@@active
+\catcode`\_=\@@active
+\gdef\enablesupersub
+ {\catcode`\^=\@@active
+ \def^{\ifmmode\expandafter\super\else\expandafter\normalsuper\fi}%
+ \catcode`\_=\@@active
+ \def_{\ifmmode\expandafter\suber\else\expandafter\normalsuber\fi}}
+\egroup
+
+%D \macros
+%D {restoremathstyle}
+%D
+%D We can pick up the current math style by calling \type
+%D {\restoremathstyle}.
+
+\def\restoremathstyle
+ {\ifmmode
+ \ifcase\supersubmode
+ \textstyle
+ \or
+ \scriptstyle
+ \else
+ \scriptscriptstyle
+ \fi
+ \fi}
+
+%D These macros were first needed by Frits Spijker (also
+%D known as Gajes) for typesetting the minus sign that is
+%D keyed into scientific calculators.
+
+% This is the first alternative, which works okay for the
+% minus, but less for the plus.
+%
+% \def\dodoraisedmathord#1#2#3%
+% {\mathord{{#2\raise.#1ex\hbox{#2#3}}}}
+%
+% \def\doraisedmathord#1%
+% {\mathchoice
+% {\dodoraisedmathord5\tf #1}%
+% {\dodoraisedmathord5\tf #1}%
+% {\dodoraisedmathord4\tfx #1}%
+% {\dodoraisedmathord3\tfxx#1}}
+%
+% \def\negative{\doraisedmathord-}
+% \def\positive{\doraisedmathord+}
+%
+% So, now we use the monospaced signs, that we also
+% define as symbol, so that they can be overloaded.
+
+\def\dodoraisedmathord#1#2#3%
+ {\mathord{{#2\raise.#1ex\hbox{#2\symbol[#3]}}}}
+
+\def\doraisedmathord#1%
+ {\mathchoice
+ {\dodoraisedmathord5\tf {#1}}%
+ {\dodoraisedmathord5\tf {#1}}%
+ {\dodoraisedmathord4\tx {#1}}%
+ {\dodoraisedmathord3\txx{#1}}}
+
+\def\dodonumbermathord#1#2%
+ {\setbox\scratchbox\hbox{0}%
+ \mathord{\hbox to \wd\scratchbox{\hss#1\symbol[#2]\hss}}}
+
+\def\donumbermathord#1%
+ {\mathchoice
+ {\dodonumbermathord\tf {#1}}%
+ {\dodonumbermathord\tf {#1}}%
+ {\dodonumbermathord\tx {#1}}%
+ {\dodonumbermathord\txx{#1}}}
+
+\definesymbol[positive] [\getglyph{Mono}{+}]
+\definesymbol[negative] [\getglyph{Mono}{-}]
+\definesymbol[zeroamount][\getglyph{Mono}{-}]
+
+\def\negative {\doraisedmathord{negative}}
+\def\positive {\doraisedmathord{positive}}
+\def\zeroamount{\donumbermathord{zeroamount}}
+
+%D How negative such a symbol looks is demonstrated in:
+%D $\negative 10^{\negative 10^{\negative 10}}$.
+
+\protect \endinput
diff --git a/tex/context/base/math-tex.mkii b/tex/context/base/math-tex.mkii
new file mode 100644
index 000000000..8f34a190e
--- /dev/null
+++ b/tex/context/base/math-tex.mkii
@@ -0,0 +1,720 @@
+%D \module
+%D [ file=math-tex,
+%D version=2001.04.12,
+%D subtitle=Plain Specials,
+%D author={Hans Hagen, Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% beware: in mkiv we will do it differently
+
+\unprotect
+
+\mathcode`\ ="8000 \mathcode`\_="8000 \mathcode`\'="8000
+
+\definefamilysynonym [default] [calligraphic] [sy]
+\definefamilysynonym [default] [oldstyle] [mi]
+\definefamilysynonym [default] [blackboard] [mr]
+\definefamilysynonym [default] [gothic] [mr]
+\definefamilysynonym [default] [fraktur] [mr]
+
+\definefamilysynonym [default] [lcgreek] [mi]
+\definefamilysynonym [default] [ucgreek] [mr]
+\definefamilysynonym [default] [vargreek] [mi]
+
+
+%D \macros
+%D {\setupmathematics}
+%D
+%D Configuration for integrals. (If needed we can speed this up and make it
+%D installable; no processaction is needed then).
+
+\chardef\intlimitcode\zerocount % 0 nolimits 1 displaylimits 2 limits
+
+\def\intlimits
+ {\ifcase\intlimitcode \nolimits \or \displaylimits \or \limits \fi}
+
+\def\setupmathematics
+ {\dosingleargument\dosetupmathematics}
+
+\def\dosetupmathematics[#1]%
+ {\getparameters[\??mo][#1]
+ \processaction[\@@mointegral]
+ [ nolimits=>\chardef\intlimitcode\zerocount,
+ displaylimits=>\chardef\intlimitcode\plusone,
+ limits=>\chardef\intlimitcode\plustwo]}
+
+%D \startbuffer
+%D $\int_a^b f(x) dx$ and also
+%D $\iint_a^b f(x,y) dxdy$, $\iiint_a^b f(x,y) dxdy$,
+%D $\iiiint_a^b f(x) dx$
+%D \startformula
+%D \int_a^b f(x) dx \quad
+%D \iint_a^b f(x) dx \quad
+%D \iiint_a^b f(x) dx \quad
+%D \iiiint_a^b f(x) dx \quad
+%D \stopformula
+%D \stopbuffer
+%D
+%D Default: \getbuffer
+%D
+%D Displaylimits: \setupmathematics[integral=displaylimits] \getbuffer
+%D
+%D Limits: \setupmathematics[integral=limits] \getbuffer
+
+\startmathcollection [default]
+
+\definemathsymbol [alpha] [nothing] [lcgreek] ["0B]
+\definemathsymbol [beta] [nothing] [lcgreek] ["0C]
+\definemathsymbol [gamma] [nothing] [lcgreek] ["0D]
+\definemathsymbol [delta] [nothing] [lcgreek] ["0E]
+\definemathsymbol [epsilon] [nothing] [lcgreek] ["0F]
+\definemathsymbol [zeta] [nothing] [lcgreek] ["10]
+\definemathsymbol [eta] [nothing] [lcgreek] ["11]
+\definemathsymbol [theta] [nothing] [lcgreek] ["12]
+\definemathsymbol [iota] [nothing] [lcgreek] ["13]
+\definemathsymbol [kappa] [nothing] [lcgreek] ["14]
+\definemathsymbol [lambda] [nothing] [lcgreek] ["15]
+\definemathsymbol [mu] [nothing] [lcgreek] ["16]
+\definemathsymbol [nu] [nothing] [lcgreek] ["17]
+\definemathsymbol [xi] [nothing] [lcgreek] ["18]
+\definemathsymbol [omicron] [nothing] [lcgreek] ["6F]
+\definemathsymbol [pi] [nothing] [lcgreek] ["19]
+\definemathsymbol [rho] [nothing] [lcgreek] ["1A]
+\definemathsymbol [sigma] [nothing] [lcgreek] ["1B]
+\definemathsymbol [tau] [nothing] [lcgreek] ["1C]
+\definemathsymbol [upsilon] [nothing] [lcgreek] ["1D]
+\definemathsymbol [phi] [nothing] [lcgreek] ["1E]
+\definemathsymbol [chi] [nothing] [lcgreek] ["1F]
+\definemathsymbol [psi] [nothing] [lcgreek] ["20]
+\definemathsymbol [omega] [nothing] [lcgreek] ["21]
+
+\stopmathcollection
+
+\startmathcollection [default]
+
+\definemathsymbol [varepsilon] [nothing] [vargreek] ["22]
+\definemathsymbol [vartheta] [nothing] [vargreek] ["23]
+\definemathsymbol [varpi] [nothing] [vargreek] ["24]
+\definemathsymbol [varrho] [nothing] [vargreek] ["25]
+\definemathsymbol [varsigma] [nothing] [vargreek] ["26]
+\definemathsymbol [varphi] [nothing] [vargreek] ["27]
+
+\stopmathcollection
+
+\startmathcollection [default]
+
+\definemathsymbol [Alpha] [alpha] [ucgreek] ["41] % A
+\definemathsymbol [Beta] [alpha] [ucgreek] ["42] % B
+\definemathsymbol [Gamma] [alpha] [ucgreek] ["00]
+\definemathsymbol [Delta] [alpha] [ucgreek] ["01]
+\definemathsymbol [Epsilon] [alpha] [ucgreek] ["45] % E
+\definemathsymbol [Zeta] [alpha] [ucgreek] ["5A] % Z
+\definemathsymbol [Eta] [alpha] [ucgreek] ["48] % H
+\definemathsymbol [Theta] [alpha] [ucgreek] ["02]
+\definemathsymbol [Iota] [alpha] [ucgreek] ["49] % I
+\definemathsymbol [Kappa] [alpha] [ucgreek] ["4B] % K
+\definemathsymbol [Lambda] [alpha] [ucgreek] ["03]
+\definemathsymbol [Mu] [alpha] [ucgreek] ["4D] % M
+\definemathsymbol [Nu] [alpha] [ucgreek] ["4E] % N
+\definemathsymbol [Xi] [alpha] [ucgreek] ["04]
+\definemathsymbol [Omicron] [alpha] [ucgreek] ["4F] % O
+\definemathsymbol [Pi] [alpha] [ucgreek] ["05]
+\definemathsymbol [Rho] [alpha] [ucgreek] ["52] % R
+\definemathsymbol [Sigma] [alpha] [ucgreek] ["06]
+\definemathsymbol [Tau] [alpha] [ucgreek] ["54] % T
+\definemathsymbol [Upsilon] [alpha] [ucgreek] ["07]
+\definemathsymbol [Phi] [alpha] [ucgreek] ["08]
+\definemathsymbol [Chi] [alpha] [ucgreek] ["58] % X
+\definemathsymbol [Psi] [alpha] [ucgreek] ["09]
+\definemathsymbol [Omega] [alpha] [ucgreek] ["0A]
+
+\stopmathcollection
+
+% The \mfunction macro is an alternative for \hbox with a
+% controlable font switch.
+
+\startmathcollection[default]
+
+\definemathcommand [arccos] [nolop] {\mfunction{arccos}}
+\definemathcommand [arcsin] [nolop] {\mfunction{arcsin}}
+\definemathcommand [arctan] [nolop] {\mfunction{arctan}}
+\definemathcommand [arg] [nolop] {\mfunction{arg}}
+\definemathcommand [cosh] [nolop] {\mfunction{cosh}}
+\definemathcommand [cos] [nolop] {\mfunction{cos}}
+\definemathcommand [coth] [nolop] {\mfunction{coth}}
+\definemathcommand [cot] [nolop] {\mfunction{cot}}
+\definemathcommand [csc] [nolop] {\mfunction{csc}}
+\definemathcommand [deg] [nolop] {\mfunction{deg}}
+\definemathcommand [det] [limop] {\mfunction{det}}
+\definemathcommand [dim] [nolop] {\mfunction{dim}}
+\definemathcommand [exp] [nolop] {\mfunction{exp}}
+\definemathcommand [gcd] [limop] {\mfunction{gcd}}
+\definemathcommand [hom] [nolop] {\mfunction{hom}}
+\definemathcommand [inf] [limop] {\mfunction{inf}}
+\definemathcommand [injlim] [limop] {\mfunction{inj\,lim}}
+\definemathcommand [ker] [nolop] {\mfunction{ker}}
+\definemathcommand [lg] [nolop] {\mfunction{lg}}
+\definemathcommand [liminf] [limop] {\mfunction{lim\,inf}}
+\definemathcommand [limsup] [limop] {\mfunction{lim\,sup}}
+\definemathcommand [lim] [limop] {\mfunction{lim}}
+\definemathcommand [ln] [nolop] {\mfunction{ln}}
+\definemathcommand [log] [nolop] {\mfunction{log}}
+\definemathcommand [median] [limop] {\mfunction{median}}
+\definemathcommand [max] [limop] {\mfunction{max}}
+\definemathcommand [min] [limop] {\mfunction{min}}
+\definemathcommand [mod] [limop] {\mfunction{mod}}
+\definemathcommand [div] [limop] {\mfunction{div}}
+\definemathcommand [projlim] [limop] {\mfunction{proj\,lim}}
+\definemathcommand [Pr] [limop] {\mfunction{Pr}}
+\definemathcommand [sec] [nolop] {\mfunction{sec}}
+\definemathcommand [sinh] [nolop] {\mfunction{sinh}}
+\definemathcommand [sin] [nolop] {\mfunction{sin}}
+\definemathcommand [sup] [limop] {\mfunction{sup}}
+\definemathcommand [tanh] [nolop] {\mfunction{tanh}}
+\definemathcommand [tan] [nolop] {\mfunction{tan}}
+
+\stopmathcollection
+
+\let\normalmatharg\arg % todo: maybe automatically
+
+\startmathcollection[default]
+
+\definemathcommand [integers] {\mfunction{Z}}
+\definemathcommand [reals] {\mfunction{R}}
+\definemathcommand [rationals] {\mfunction{Q}}
+\definemathcommand [naturalnumbers] {\mfunction{N}}
+\definemathcommand [complexes] {\mfunction{C}}
+\definemathcommand [primes] {\mfunction{P}}
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathcharacter [!] [close] [mr] ["21]
+\definemathcharacter [(] [open] [mr] ["28]
+\definemathcharacter [)] [close] [mr] ["29]
+\definemathcharacter [*] [bin] [sy] ["03]
+\definemathcharacter [+] [bin] [mr] ["2B]
+\definemathcharacter [,] [punct] [mi] ["3B]
+\definemathcharacter [-] [bin] [sy] ["00]
+\definemathcharacter [.] [ord] [mi] ["3A]
+\definemathcharacter [/] [ord] [mi] ["3D]
+\definemathcharacter [:] [rel] [mr] ["3A]
+\definemathcharacter [;] [punct] [mr] ["3B]
+\definemathcharacter [<] [rel] [mi] ["3C]
+\definemathcharacter [=] [rel] [mr] ["3D]
+\definemathcharacter [>] [rel] [mi] ["3E]
+\definemathcharacter [?] [close] [mr] ["3F]
+\definemathcharacter [91] [open] [mr] ["5B] % [
+\definemathcharacter [92] [ord] [sy] ["6E] % \
+\definemathcharacter [93] [close] [mr] ["5D] % ]
+\definemathcharacter [123] [open] [sy] ["66] % {
+\definemathcharacter [124] [ord] [sy] ["6A] % |
+\definemathcharacter [125] [close] [sy] ["67] % }
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathcharacter [(] [nothing] [mr] ["28] [ex] ["00]
+\definemathcharacter [)] [nothing] [mr] ["29] [ex] ["01]
+\definemathcharacter [91] [nothing] [mr] ["5B] [ex] ["02] % [
+\definemathcharacter [93] [nothing] [mr] ["5D] [ex] ["03] % ]
+\definemathcharacter [<] [nothing] [sy] ["68] [ex] ["0A]
+\definemathcharacter [>] [nothing] [sy] ["69] [ex] ["0B]
+\definemathcharacter [/] [nothing] [mr] ["2F] [ex] ["0E]
+\definemathcharacter [124] [nothing] [sy] ["6A] [ex] ["0C] % |
+\definemathcharacter [92] [nothing] [sy] ["6E] [ex] ["0F] % \
+
+\stopmathcollection
+
+\def\PLAINangle
+ {{\vbox{\ialign{$\mathsurround\zeropoint\scriptstyle##$\crcr
+ \not\mathrel{\mkern14mu}\crcr
+ \noalign{\nointerlineskip}
+ \mkern2.5mu\leaders\hrule height.34pt\hfill\mkern2.5mu\crcr}}}}
+
+\startmathcollection[default]
+
+\definemathsymbol [aleph] [nothing] [sy] ["40]
+\definemathsymbol [imath] [nothing] [mi] ["7B]
+\definemathsymbol [jmath] [nothing] [mi] ["7C]
+\definemathsymbol [ell] [nothing] [mi] ["60]
+\definemathsymbol [wp] [nothing] [mi] ["7D]
+\definemathsymbol [Re] [nothing] [sy] ["3C]
+\definemathsymbol [Im] [nothing] [sy] ["3D]
+\definemathsymbol [partial] [nothing] [mi] ["40]
+\definemathsymbol [infty] [nothing] [sy] ["31]
+\definemathsymbol [prime] [nothing] [sy] ["30]
+\definemathsymbol [emptyset] [nothing] [sy] ["3B]
+\definemathsymbol [nabla] [nothing] [sy] ["72]
+\definemathsymbol [top] [nothing] [sy] ["3E]
+\definemathsymbol [bot] [nothing] [sy] ["3F]
+
+\definemathcommand [hbar] {{\mathchar'26\mkern-9muh}}
+\definemathcommand [surd] {{\mathchar"1270}} % ?
+\definemathcommand [angle] {\PLAINangle}
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathsymbol [triangle] [ord] [sy] ["34]
+\definemathsymbol [forall] [ord] [sy] ["38]
+\definemathsymbol [exists] [ord] [sy] ["39]
+\definemathsymbol [neg] [ord] [sy] ["3A]
+\definemathsymbol [flat] [ord] [mi] ["5B]
+\definemathsymbol [natural] [ord] [mi] ["5C]
+\definemathsymbol [sharp] [ord] [mi] ["5D]
+\definemathsymbol [clubsuit] [ord] [sy] ["7C]
+\definemathsymbol [diamondsuit] [ord] [sy] ["7D]
+\definemathsymbol [heartsuit] [ord] [sy] ["7E]
+\definemathsymbol [spadesuit] [ord] [sy] ["7F]
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathcommand [square] {\hbox{\hsmash{$\sqcup$}$\sqcap$}}
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathsymbol [coprod] [op] [ex] ["60]
+\definemathsymbol [bigvee] [op] [ex] ["57]
+\definemathsymbol [bigwedge] [op] [ex] ["56]
+\definemathsymbol [biguplus] [op] [ex] ["55]
+\definemathsymbol [bigcap] [op] [ex] ["54]
+\definemathsymbol [bigcup] [op] [ex] ["53]
+\definemathsymbol [intop] [op] [ex] ["52]
+\definemathsymbol [prod] [op] [ex] ["51]
+\definemathsymbol [sum] [op] [ex] ["50]
+\definemathsymbol [bigotimes] [op] [ex] ["4E]
+\definemathsymbol [bigoplus] [op] [ex] ["4C]
+\definemathsymbol [bigodot] [op] [ex] ["4A]
+\definemathsymbol [ointop] [op] [ex] ["48]
+\definemathsymbol [bigsqcup] [op] [ex] ["46]
+\definemathsymbol [smallint] [op] [sy] ["73]
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathsymbol [triangleleft] [bin] [mi] ["2F]
+\definemathsymbol [triangleright] [bin] [mi] ["2E]
+\definemathsymbol [bigtriangleup] [bin] [sy] ["34]
+\definemathsymbol [bigtriangledown] [bin] [sy] ["35]
+\definemathsymbol [wedge] [bin] [sy] ["5E]
+\definemathsymbol [vee] [bin] [sy] ["5F]
+\definemathsymbol [cap] [bin] [sy] ["5C]
+\definemathsymbol [cup] [bin] [sy] ["5B]
+\definemathsymbol [ddagger] [bin] [sy] ["7A]
+\definemathsymbol [dagger] [bin] [sy] ["79]
+\definemathsymbol [sqcap] [bin] [sy] ["75]
+\definemathsymbol [sqcup] [bin] [sy] ["74]
+\definemathsymbol [uplus] [bin] [sy] ["5D]
+\definemathsymbol [amalg] [bin] [sy] ["71]
+\definemathsymbol [diamond] [bin] [sy] ["05]
+\definemathsymbol [bullet] [bin] [sy] ["0F]
+\definemathsymbol [wr] [bin] [sy] ["6F]
+\definemathsymbol [div] [bin] [sy] ["04]
+\definemathsymbol [odot] [bin] [sy] ["0C]
+\definemathsymbol [oslash] [bin] [sy] ["0B]
+\definemathsymbol [otimes] [bin] [sy] ["0A]
+\definemathsymbol [ominus] [bin] [sy] ["09]
+\definemathsymbol [oplus] [bin] [sy] ["08]
+\definemathsymbol [mp] [bin] [sy] ["07]
+\definemathsymbol [pm] [bin] [sy] ["06]
+\definemathsymbol [circ] [bin] [sy] ["0E]
+\definemathsymbol [bigcirc] [bin] [sy] ["0D]
+\definemathsymbol [setminus] [bin] [sy] ["6E]
+\definemathsymbol [cdot] [bin] [sy] ["01]
+\definemathsymbol [ast] [bin] [sy] ["03]
+\definemathsymbol [times] [bin] [sy] ["02]
+\definemathsymbol [star] [bin] [mi] ["3F]
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathsymbol [propto] [rel] [sy] ["2F]
+\definemathsymbol [sqsubseteq] [rel] [sy] ["76]
+\definemathsymbol [sqsupseteq] [rel] [sy] ["77]
+\definemathsymbol [parallel] [rel] [sy] ["6B]
+\definemathsymbol [mid] [rel] [sy] ["6A]
+\definemathsymbol [dashv] [rel] [sy] ["61]
+\definemathsymbol [vdash] [rel] [sy] ["60]
+\definemathsymbol [nearrow] [rel] [sy] ["25]
+\definemathsymbol [searrow] [rel] [sy] ["26]
+\definemathsymbol [nwarrow] [rel] [sy] ["2D]
+\definemathsymbol [swarrow] [rel] [sy] ["2E]
+\definemathsymbol [Leftrightarrow] [rel] [sy] ["2C]
+\definemathsymbol [Leftarrow] [rel] [sy] ["28]
+\definemathsymbol [Rightarrow] [rel] [sy] ["29]
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathcommand [lnot] {\neg}
+\definemathcommand [int] {\intop \intlimits}
+\definemathcommand [oint] {\ointop\intlimits}
+\definemathcommand [land] {\wedge}
+\definemathcommand [lor] {\vee}
+\definemathcommand [neq] {\not=}
+\definemathcommand [ne] {\neq}
+\definemathcommand [le] {\leq}
+\definemathcommand [ge] {\geq}
+\definemathcommand [eq] {=}
+\definemathcommand [gt] {>}
+\definemathcommand [lt] {<}
+\definemathcommand [gets] {\leftarrow}
+\definemathcommand [owns] {\ni}
+\definemathcommand [to] {\rightarrow}
+\definemathcommand [mapsto] {\mapstochar\rightarrow}
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathsymbol [leq] [rel] [sy] ["14]
+\definemathsymbol [geq] [rel] [sy] ["15]
+\definemathsymbol [succ] [rel] [sy] ["1F]
+\definemathsymbol [prec] [rel] [sy] ["1E]
+\definemathsymbol [approx] [rel] [sy] ["19]
+\definemathsymbol [succeq] [rel] [sy] ["17]
+\definemathsymbol [preceq] [rel] [sy] ["16]
+\definemathsymbol [supset] [rel] [sy] ["1B]
+\definemathsymbol [subset] [rel] [sy] ["1A]
+\definemathsymbol [supseteq] [rel] [sy] ["13]
+\definemathsymbol [subseteq] [rel] [sy] ["12]
+\definemathsymbol [in] [rel] [sy] ["32]
+\definemathsymbol [ni] [rel] [sy] ["33]
+\definemathsymbol [gg] [rel] [sy] ["1D]
+\definemathsymbol [ll] [rel] [sy] ["1C]
+\definemathsymbol [not] [rel] [sy] ["36]
+\definemathsymbol [leftrightarrow] [rel] [sy] ["24]
+\definemathsymbol [leftarrow] [rel] [sy] ["20]
+\definemathsymbol [rightarrow] [rel] [sy] ["21]
+\definemathsymbol [mapstochar] [rel] [sy] ["37]
+\definemathsymbol [sim] [rel] [sy] ["18]
+\definemathsymbol [simeq] [rel] [sy] ["27]
+\definemathsymbol [perp] [rel] [sy] ["3F]
+\definemathsymbol [equiv] [rel] [sy] ["11]
+\definemathsymbol [asymp] [rel] [sy] ["10]
+\definemathsymbol [smile] [rel] [mi] ["5E]
+\definemathsymbol [frown] [rel] [mi] ["5F]
+\definemathsymbol [leftharpoonup] [rel] [mi] ["28]
+\definemathsymbol [leftharpoondown] [rel] [mi] ["29]
+\definemathsymbol [rightharpoonup] [rel] [mi] ["2A]
+\definemathsymbol [rightharpoondown] [rel] [mi] ["2B]
+\definemathsymbol [lhook] [rel] [mi] ["2C]
+\definemathsymbol [rhook] [rel] [mi] ["2D]
+
+\stopmathcollection
+
+\def\PLAINldots
+ {\ldotp\ldotp\ldotp}
+
+\def\PLAINcdots
+ {\cdotp\cdotp\cdotp}
+
+\def\PLAINvdots
+ {\vbox{\baselineskip.4\bodyfontsize\lineskiplimit\zeropoint
+ \kern.6\bodyfontsize\hbox{.}\hbox{.}\hbox{.}}}
+
+\def\PLAINddots
+ {\mkern1mu\raise.7\bodyfontsize\vbox{\kern.7\bodyfontsize\hbox{.}}\mkern2mu
+ \raise.4\bodyfontsize\hbox{.}\mkern2mu\raise.1\bodyfontsize\hbox{.}\mkern1mu}
+
+\startmathcollection[default]
+
+\definemathcommand [hookrightarrow] {\lhook\joinrel\rightarrow}
+\definemathcommand [hookleftarrow] {\leftarrow\joinrel\rhook}
+\definemathcommand [bowtie] {\mathrel\triangleright\joinrel\mathrel\triangleleft}
+\definemathcommand [models] {\mathrel|\joinrel=}
+\definemathcommand [iff] {\;\Longleftrightarrow\;}
+
+\definemathsymbol [ldotp] [punct] [mi] ["3A]
+\definemathsymbol [cdotp] [punct] [sy] ["01]
+\definemathsymbol [colon] [punct] [mr] ["3A]
+
+\definemathcommand [ldots] [inner] {\PLAINldots}
+\definemathcommand [cdots] [inner] {\PLAINcdots}
+\definemathcommand [vdots] [nothing] {\PLAINvdots}
+\definemathcommand [ddots] [inner] {\PLAINddots}
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathsymbol [acute] [accent] [mr] ["13]
+\definemathsymbol [grave] [accent] [mr] ["12]
+\definemathsymbol [ddot] [accent] [mr] ["7F]
+\definemathsymbol [tilde] [accent] [mr] ["7E]
+\definemathsymbol [mathring] [accent] [mr] ["17]
+\definemathsymbol [bar] [accent] [mr] ["16]
+\definemathsymbol [breve] [accent] [mr] ["15]
+\definemathsymbol [check] [accent] [mr] ["14]
+\definemathsymbol [hat] [accent] [mr] ["5E]
+\definemathsymbol [vec] [accent] [mi] ["7E] % [ord]
+\definemathsymbol [dot] [accent] [mr] ["5F]
+\definemathsymbol [widetilde] [accent] [ex] ["65] % [ord]
+\definemathsymbol [widehat] [accent] [ex] ["62] % [ord]
+
+\stopmathcollection
+
+\startmathcollection[default]
+
+\definemathsymbol [lmoustache] [open] [ex] ["7A] [ex] ["40]
+\definemathsymbol [rmoustache] [close] [ex] ["7B] [ex] ["41]
+\definemathsymbol [lgroup] [open] [mr] ["28] [ex] ["3A] % ?
+\definemathsymbol [rgroup] [close] [mr] ["29] [ex] ["3B] % ?
+\definemathsymbol [arrowvert] [nothing] [sy] ["6A] [ex] ["3C]
+\definemathsymbol [Arrowvert] [nothing] [sy] ["6B] [ex] ["3D]
+\definemathsymbol [bracevert] [nothing] [ex] ["3E] % ?
+\definemathsymbol [Vert] [nothing] [sy] ["6B] [ex] ["0D]
+\definemathsymbol [vert] [nothing] [sy] ["6A] [ex] ["0C]
+\definemathsymbol [uparrow] [rel] [sy] ["22] [ex] ["78]
+\definemathsymbol [downarrow] [rel] [sy] ["23] [ex] ["79]
+\definemathsymbol [updownarrow] [rel] [sy] ["6C] [ex] ["3F]
+\definemathsymbol [Uparrow] [rel] [sy] ["2A] [ex] ["7E]
+\definemathsymbol [Downarrow] [rel] [sy] ["2B] [ex] ["7F]
+\definemathsymbol [Updownarrow] [rel] [sy] ["6D] [ex] ["77]
+\definemathsymbol [backslash] [nothing] [sy] ["6E] [ex] ["0F]
+\definemathsymbol [langle] [open] [sy] ["68] [ex] ["0A]
+\definemathsymbol [rangle] [close] [sy] ["69] [ex] ["0B]
+\definemathsymbol [lbrace] [open] [sy] ["66] [ex] ["08]
+\definemathsymbol [rbrace] [close] [sy] ["67] [ex] ["09]
+\definemathsymbol [lceil] [open] [sy] ["64] [ex] ["06]
+\definemathsymbol [rceil] [close] [sy] ["65] [ex] ["07]
+\definemathsymbol [lfloor] [open] [sy] ["62] [ex] ["04]
+\definemathsymbol [rfloor] [close] [sy] ["63] [ex] ["05]
+
+\definemathsymbol [sqrt] [radical] [sy] ["70] [ex] ["70]
+
+\stopmathcollection
+
+%D By request:
+
+\startmathcollection[default]
+
+\definemathsymbol [lvert] [open] [sy] ["6A] [ex] ["0C]
+\definemathsymbol [rvert] [close] [sy] ["6A] [ex] ["0C]
+
+\definemathsymbol [lVert] [open] [sy] ["6B] [ex] ["0D]
+\definemathsymbol [rVert] [close] [sy] ["6B] [ex] ["0D]
+
+\stopmathcollection
+
+%D For brooks:
+%D
+%D \starttyping
+%D $\sqrt[3]{10}$
+%D \stoptyping
+
+\ifx\normalsqrt\undefined \let\normalsqrt\sqrt \fi % just set to: \dohandlemathtoken {sqrt}
+
+\def\notsosqrt[#1]{\root#1\of}
+
+\unexpanded\def\sqrt{\doifnextoptionalelse\notsosqrt\normalsqrt}
+
+\def\PLAINbig {\@@dobig{0.85}}
+\def\PLAINBig {\@@dobig{1.15}}
+\def\PLAINbigg{\@@dobig{1.45}}
+\def\PLAINBigg{\@@dobig{1.75}}
+
+\startrawmathcollection [default]
+
+\definemathcommand [bigl] [open] [one] {\big}
+\definemathcommand [bigm] [rel] [one] {\big}
+\definemathcommand [bigr] [close] [one] {\big}
+\definemathcommand [Bigl] [open] [one] {\Big}
+\definemathcommand [Bigm] [rel] [one] {\Big}
+\definemathcommand [Bigr] [close] [one] {\Big}
+\definemathcommand [biggl] [open] [one] {\bigg}
+\definemathcommand [biggm] [rel] [one] {\bigg}
+\definemathcommand [biggr] [close] [one] {\bigg}
+\definemathcommand [Biggl] [open] [one] {\Bigg}
+\definemathcommand [Biggm] [rel] [one] {\Bigg}
+\definemathcommand [Biggr] [close] [one] {\Bigg}
+
+\definemathcommand [big] {\PLAINbig}
+\definemathcommand [Big] {\PLAINBig}
+\definemathcommand [bigg] {\PLAINbigg}
+\definemathcommand [Bigg] {\PLAINBigg}
+
+\stoprawmathcollection
+
+\startmathcollection[default]
+
+\definemathsymbol [dag] [box] [sy] ["79]
+\definemathsymbol [ddag] [box] [sy] ["7A]
+\definemathsymbol [S] [box] [sy] ["78]
+\definemathsymbol [P] [box] [sy] ["7B]
+\definemathsymbol [Orb] [box] [sy] ["0D]
+
+\stopmathcollection
+
+\def\PLAINroot#1#2%
+ {\setbox\zerocount\hbox{$\mathsurround\zeropoint#1\sqrt{#2}$}\dimen@\ht\zerocount
+ \advance\dimen@-\dp\zerocount
+ \mkern5mu\raise.6\dimen@\copy\rootbox \mkern-10mu\box\zerocount}
+
+\def\PLAINmatrix#1%
+ {\null\,\vcenter{\normalbaselines\mathsurround\zeropoint
+ \ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
+ \mathstrut\crcr\noalign{\kern-\baselineskip}
+ #1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}\,}
+
+\startrawmathcollection[default]
+
+\definemathcommand [mathstrut] {\vphantom{(}}
+\definemathcommand [joinrel] {\mathrel{\mkern-3mu}}
+\definemathcommand [r@@t] {\PLAINroot}
+\definemathcommand [matrix] {\PLAINmatrix}
+
+\definemathcommand [over] {\normalover} % hack, to do
+
+\stoprawmathcollection
+
+\def\{{\lbrace}
+\def\}{\rbrace}
+
+%def\bbd{\fam\purefamily{blackboard}}
+%def\cal{\fam\purefamily{calfamily}}
+
+\def\mit{\fam\purefamily{mitfamily}}
+
+\def\Bbb{\blackboard} % conforming amstex
+
+\startmathcollection[default]
+
+ \definemathsymbol [mathperiod] [ord] [mi] ["3A]
+ \definemathsymbol [textperiod] [punct] [mi] ["3A]
+
+ \definemathsymbol [mathcomma] [ord] [mi] ["3B]
+ \definemathsymbol [textcomma] [punct] [mi] ["3B]
+
+\stopmathcollection
+
+\definemathpunctuation . mathperiod textperiod
+\definemathpunctuation , mathcomma textcomma
+
+%D The following colon related definitions are provided by Aditya
+%D Mahajan who derived them from \type {mathtools.sty} and \type
+%D {colonequals.sty}.
+
+%D \macros
+%D {centercolon, colonminus, minuscolon, colonequals, equalscolon,
+%D colonapprox, approxcolon, colonsim, simcolon, coloncolon,
+%D coloncolonminus, minuscoloncolon, coloncolonequals,
+%D equalscoloncolon, coloncolonapprox, approxcoloncolon,
+%D colonsim, simcoloncolon}
+%D
+%D In $a := b$ the colon is not vertically centered with the equal
+%D to. Also the distance between colon and equal to is a bit large.
+%D So, we define a vertically centered colon \tex {centercolon} and
+%D a few macros for colon and double colon relation symbols.
+%D
+%D \startlines
+%D \formula {A \centercolon B}
+%D \formula {A \colonminus B}
+%D \formula {A \minuscolon B}
+%D \formula {A \colonequals B}
+%D \formula {A \equalscolon B}
+%D \formula {A \colonapprox B}
+%D \formula {A \approxcolon B}
+%D \formula {A \colonsim B}
+%D \formula {A \simcolon B}
+%D \formula {A \coloncolon B}
+%D \formula {A \coloncolonminus B}
+%D \formula {A \minuscoloncolon B}
+%D \formula {A \coloncolonequals B}
+%D \formula {A \equalscoloncolon B}
+%D \formula {A \coloncolonapprox B}
+%D \formula {A \approxcoloncolon B}
+%D \formula {A \colonsim B}
+%D \formula {A \simcoloncolon B}
+%D \stoplines
+
+%D The next macros take care of the space between the colon and the
+%D relation symbol.
+
+\definemathcommand [colonsep] {\mkern-1.2mu}
+\definemathcommand [doublecolonsep] {\mkern-0.9mu}
+
+%D The next macro vertically centeres its contents.
+
+\def\@center@math#1%
+ {\vcenter{\hbox{$\mathsurround\zeropoint#1$}}}
+
+\def\@center@colon
+ {\mathpalette\@center@math{\colon}}
+
+%D Now we define all the colon relations.
+
+\definemathcommand [centercolon] [rel] {\@center@colon}
+\definemathcommand [colonminus] [rel] {\centercolon\colonsep\mathrel{-}}
+\definemathcommand [minuscolon] [rel] {\mathrel{-}\colonsep\centercolon}
+\definemathcommand [colonequals] [rel] {\centercolon\colonsep=}
+\definemathcommand [equalscolon] [rel] {=\centercolon\colonsep}
+\definemathcommand [colonapprox] [rel] {\centercolon\colonsep\approx}
+\definemathcommand [approxcolon] [rel] {\approx\centercolon\colonsep}
+\definemathcommand [colonsim] [rel] {\centercolon\colonsep\sim}
+\definemathcommand [simcolon] [rel] {\sim\centercolon\colonsep}
+
+\definemathcommand [coloncolon] [rel] {\centercolon\doublecolonsep\centercolon}
+\definemathcommand [coloncolonminus] [rel] {\coloncolon\colonsep\mathrel{-}}
+\definemathcommand [minuscoloncolon] [rel] {\mathrel{-}\colonsep\coloncolon}
+\definemathcommand [coloncolonequals] [rel] {\coloncolon\colonsep=}
+\definemathcommand [equalscoloncolon] [rel] {=\coloncolon\colonsep}
+\definemathcommand [coloncolonapprox] [rel] {\coloncolon\colonsep\approx}
+\definemathcommand [approxcoloncolon] [rel] {\approx\coloncolon\colonsep}
+\definemathcommand [colonsim] [rel] {\coloncolon\colonsep\sim}
+\definemathcommand [simcoloncolon] [rel] {\sim\coloncolon\colonsep}
+
+%D More integrals (AM):
+
+\def\dointkern{\mkern-6mu\mathchoice{\mkern-3mu}{}{}{}}
+
+\definemathcommand [iint] {\repeatintegral\plusone }
+\definemathcommand [iiint] {\repeatintegral\plustwo }
+\definemathcommand [iiiint] {\repeatintegral\plusthree}
+
+\def\repeatintegral#1%
+ {\scratchtoks\emptytoks
+ \let\dointlimits\donothing
+ \let\dodointlimits\intlimits
+ \dorecurse{#1}{\appendtoks \intop \dointkern \to \scratchtoks}
+ \appendtoks \intop \dointlimits \dodointlimits \to \scratchtoks
+ \edef\dodorepeatintegral{\the\scratchtoks}%
+ \futurelet\next\dorepeatintegral}
+
+%D If the \type{\limits} option is used after \type{\iint}, use
+%D \type{\mathop} and fudge the left hand space a bit to make the
+%D subscript visually centered.
+
+\def\dorepeatintegral
+ {\ifx\next\limits \dointlimitcorrection \else
+ \ifx\next\displaylimits \dointlimitcorrection \else
+ \ifx\next\nolimits \donothing \else
+ \ifcase\intlimitcode\else \dointlimitcorrection \fi\fi\fi\fi
+ \dodorepeatintegral}
+
+\def\dointlimitcorrection
+ {\mkern-7mu\mathchoice{\mkern-2mu}{}{}{}%
+ \mathop\bgroup
+ \mkern7mu\mathchoice{\mkern2mu}{}{}{}%
+ \let\dointlimits\egroup}
+
+\setupmathematics
+ [integral=nolimits]
+
+\protect \endinput
diff --git a/tex/context/base/math-tim.mkii b/tex/context/base/math-tim.mkii
new file mode 100644
index 000000000..3b9aea103
--- /dev/null
+++ b/tex/context/base/math-tim.mkii
@@ -0,0 +1,371 @@
+%D \module
+%D [ file=math-tim,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Mathtime Specials,
+%D author={Hans Hagen \& Taco Hoekwater},
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\endinput % i will clean this up after taco has gone over it
+
+%D With thanks to Berthold Horn from YandY for providing me
+%D evaluation copies of the MathTimePlus fonts.
+
+% version 0 : Michael Spivak
+% version 1 : Taco Hoekwater
+% version 2 : Hans Hagen
+% version 3 : etc etc etc
+
+\unprotect
+
+%D We use the predefined spare families \type {\mcfam} and
+%D \type {\mdfam}.
+
+\let\cafam\mcfam \let\hexcafam\hexmcfam
+\let\gbfam\mdfam \let\hexgbfam\hexmdfam
+\let\gkfam\mdfam \let\hexgkfam\hexmdfam
+
+% Why is this needed?
+
+% \font\tenmd =mtgu at 10pt
+% \font\sevenmd=mtgu at 7.6pt
+% \font\fivemd =mtgu at 6pt
+% \font\tenmc =mtms at 10pt
+% \font\sevenmc=mtms at 7.6pt
+% \font\fivemc =mtms at 6pt
+%
+% \textfont \mcfam\tenmc \textfont \mdfam\tenmd
+% \scriptfont \mcfam\sevenmc \scriptfont \mdfam\sevenmd
+% \scriptscriptfont\mcfam\fivemc \scriptscriptfont\mdfam\fivemd
+
+% \addtocommalist{gk}\familylist
+% \addtocommalist{gb}\familylist
+%
+% \defineinterfaceconstant {ca} {ca} % boohoo!
+% \defineinterfaceconstant {gk} {gk} % boohoo!
+% \defineinterfaceconstant {gb} {gb} % boohoo!
+
+% \definealternativestyle[script] [\ca][\ca]
+% \definealternativestyle[greek] [\gk][\gk]
+% \definealternativestyle[boldgreek][\gb][\gb]
+
+% \definebodyfont
+% [5pt,6pt,7pt,8pt,9pt,10pt,11pt,12pt,14.4pt] [rm]
+% [ca=mtms sa 1,
+% gk=mtgu sa 1,
+% gb=mtgub sa 1]
+
+%D Since a font size is a rather fuzzy thing, it will be no
+%D surprise that the Math Times fonts have different specs
+%D than the Computer Modern Roman fonts.
+%D
+%D \starttabulate[|Bl|c|c|c|c|c|c|c|c|c|c|]
+%D \NC Computer Modern\NC
+%D 5 \NC6 \NC7 \NC8 \NC9 \NC10 \NC11 \NC12 \NC14 \NC18\NC\NR
+%D \NC Math Times \NC
+%D 6.0\NC6.8\NC7.6\NC8.4\NC9.2\NC10.0\NC10.8\NC11.6\NC13.2\NC--\NC\NR
+%D \stoptabulate
+%D
+%D The following definitions presume the existence of \type
+%D {tio} and \type {tibio} font alternatives. Definitions for
+%D \type {\tf.} etc and \type {\sc} are left as they are.
+
+%D moved code
+
+%D The next lines set up coding dependant versions of math
+%D accents (for \type {texnansi} of course). These are needed
+%D in commands like \type {\bf} and \type {\it} (which use the
+%D text font encoding) a opposed to \type {_no spec_} and
+%D \type {mi} that use the math font encoding. This stuff
+%D should be made more general!
+
+% \daghex, \ddaghex and \dothex were wrong in my version of mtmacs
+
+\def\daghex {86} % to do
+\def\ddaghex {87}
+\def\Shex {A7}
+\def\Phex {B6}
+\def\barhex {16}
+\def\gravehex{12}
+\def\acutehex{13}
+\def\checkhex{14}
+\def\brevehex{15}
+\def\hathex {5E}
+\def\dothex {05}
+\def\tildehex{7E}
+\def\ddothex {7F}
+
+%D The \type {mtex} fonts need a recalculation of \type
+%D {\p@renwd}, which in \CONTEXT\ is done automatically.
+
+%D The following definitions are mostly copied from the file
+%D \type {mtmacs.tex}, which banner said:
+%D
+%D \starttyping
+%D MTMACS.TEX VERSION 1.1.1 (1996 Dec 8)
+%D COPYRIGHT (C) 1992, 1993, 1996 BY THE TEXPLORATORS CORPORATION
+%D ALL RIGHTS RESERVED
+%D \stoptyping
+%D
+%D We reformatted the macros and changed a few bits and
+%D pieces. A further cleanup with regards to the scratch
+%D registers will be done later.
+
+\mathchardef\Gamma = "0130
+\mathchardef\Delta = "0131
+\mathchardef\Theta = "0132
+\mathchardef\Lambda = "0133
+\mathchardef\Xi = "0134
+\mathchardef\Pi = "0135
+\mathchardef\Sigma = "0136
+\mathchardef\Upsilon = "0137
+\mathchardef\Phi = "0138
+\mathchardef\Psi = "0139
+\mathchardef\Omega = "017F
+\mathchardef\varGamma = "0100
+\mathchardef\varDelta = "0101
+\mathchardef\varTheta = "0102
+\mathchardef\varLambda = "0103
+\mathchardef\varXi = "0104
+\mathchardef\varPi = "0105
+\mathchardef\varSigma = "0106
+\mathchardef\varUpsilon = "0107
+\mathchardef\varPhi = "0108
+\mathchardef\varPsi = "0109
+\mathchardef\varOmega = "010A
+\mathchardef\varkappa = "017E
+
+\mathchardef\ldotp = "613A
+
+\mathchardef\triangleleft = "2247
+\mathchardef\triangleright = "2246
+\mathchardef\comp = "2242
+
+\mathchardef\Relbar = "3248
+\mathchardef\dagger = "20\daghex % to do
+\mathchardef\ddagger = "20\ddaghex % to do
+\mathchardef\dotacc = "0250
+
+\mathcode`\( = "412E
+\mathcode`\) = "512F
+\mathcode`\. = "013A
+\mathcode`\, = "613B
+\mathcode`\+ = "2243
+\mathcode`\= = "3244
+\mathcode`\; = "6249
+
+\delcode `\( = "12E300
+\delcode `\) = "12F301
+
+\let\mit=\undefined % to do
+
+\def\vec{\mathaccent"0245 }
+\def\t#1{{\edef\next{\the\font}\the\textfont2\accent"41\next#1}}
+
+% fam equals -1 unless the user has said something
+% like \rm (cf. the texbook page 290)
+
+\def\ifdefaultfamelse#1#2%
+ {\ifnum\fam=\minusone\mathaccent#1\else\mathaccent#2\fi}
+
+\let\noaccents@\relax
+
+\def\grave {\ifdefaultfamelse{"024A}{"70\gravehex}}
+\def\acute {\ifdefaultfamelse{"024B}{"70\acutehex}}
+\def\check {\ifdefaultfamelse{"024C}{"70\checkhex}}
+\def\breve {\ifdefaultfamelse{"024D}{"70\brevehex}}
+\def\bar {\ifdefaultfamelse{"024E}{"70\barhex }}
+\def\hat {\ifdefaultfamelse{"024F}{"70\hathex }}
+\def\dot {\ifdefaultfamelse{"0250}{"70\dothex }}
+\def\tilde {\ifdefaultfamelse{"0251}{"70\tildehex}}
+\def\ddot {\ifdefaultfamelse{"0252}{"70\ddothex }}
+
+\def\widebar{\mathaccent"0253 }
+
+\def\mathhexbox@#1#2#3%
+ {\relax
+ \ifmmode
+ \mathpalette{}{\mathsurround\zeropoint\rm\mathchar"#1#2#3}%
+ \else
+ \leavevmode
+ \hbox{$\mathsurround\zeropoint\rm\mathchar"#1#2#3$}%
+ \fi}
+
+\def\dag {\edef\next@{0\daghex }\expandafter\mathhexbox@\next@}
+\def\ddag{\edef\next@{0\ddaghex}\expandafter\mathhexbox@\next@}
+
+\def\S{\edef\next@{0\Shex}\expandafter\mathhexbox@\next@}
+\def\P{\edef\next@{0\Phex}\expandafter\mathhexbox@\next@}
+
+\def\vdots%
+ {\vbox
+ {\baselineskip4\points
+ \lineskiplimit\zeropoint
+ \kern6\points\hbox{$\mathsurround\zeropoint.$}\hbox{$\mathsurround\zeropoint.$}\hbox{$\mathsurround\zeropoint.$}}}
+
+\def\ddots%
+ {\mathinner
+ {\mkern1mu
+ \raise7\points\vbox{\kern 7\points\hbox{$\mathsurround\zeropoint.$}}\mkern2mu
+ \raise4\points\hbox{$\mathsurround\zeropoint.$}\mkern2mu
+ \raise \points\hbox{$\mathsurround\zeropoint.$}\mkern1mu}}
+
+\def\hbar
+ {{\mathchoice
+ {\hbox{\lower.07em \hbox{$\mathchar"\barhex$}}}
+ {\hbox{\lower.07em \hbox{$\mathchar"\barhex$}}}
+ {\hbox{\lower.049em\hbox{$\scriptstyle\mathchar"\barhex$}}}
+ {\hbox{\lower.035em\hbox{$\scriptscriptstyle\mathchar"\barhex$}}}%
+ \mkern-6.3muh}}
+
+\def\angle%
+ {{\vbox{\ialign{$\mathsurround\zeropoint\scriptstyle##$\crcr
+ \not\mathrel{\mkern14mu}\crcr
+ \noalign{\nointerlineskip}
+ \mkern2.5mu\leaders\hrule height.48\points\hfill\mkern2.5mu\crcr}}}}
+
+\newdimen\amstexex
+
+\amstexex = .2326ex
+
+\def\varinjlim%
+ {\mathop{\vtop{\ialign{##\crcr
+ \hfil\the\textfont\zerocount lim\hfil\crcr
+ \noalign{\nointerlineskip}\rightarrowfill\crcr
+ \noalign{\nointerlineskip\kern-\amstexex}\crcr}}}}
+
+\def\varprojlim%
+ {\mathop{\vtop{\ialign{##\crcr
+ \hfil\the\textfont\zerocount lim\hfil\crcr
+ \noalign{\nointerlineskip}\leftarrowfill\crcr
+ \noalign{\nointerlineskip\kern-\amstexex}\crcr}}}}
+
+\def\varliminf{\mathop{\underbar {lim}}} % context-ified
+\def\varlimsup{\mathop{\overstrike{lim}}} % context-ified
+
+\def\spdot {^{\hbox{\raise\amstexex\hbox{\the\textfont\zerocount .}}}}
+\def\spddot {^{\hbox{\raise\amstexex\hbox{\the\textfont\zerocount ..}}}}
+\def\spdddot {^{\hbox{\raise\amstexex\hbox{\the\textfont\zerocount ...}}}}
+\def\spddddot{^{\hbox{\raise\amstexex\hbox{\the\textfont\zerocount....}}}}
+
+%D Here some code is merged in order to save strings.
+
+\def\domultidot#1#2%
+ {\setbox0\hbox{$#1#2$}%
+ \setbox2\hbox{$#1\infty$}%
+ \dimen0\ht2
+ \ifdim\ht0<\dimen0 \dimen0\ht0 \fi
+ \setbox2\hbox{$#1#2\mathchar"012D$}%
+ \dimen2\wd2
+ \advance\dimen2-\wd0
+ \setbox0\hbox{$#1\rhook$}%
+ \advance\dimen2-\wd0
+ \vbox
+ {\offinterlineskip
+ \ialign{\hfil$#1##$\hfil\cr
+ \kern\dimen2\dotacc\mkern-2.5mu\dotacc\mkern-2.5mu\dotacc\thirddot\cr
+ \noalign{\vskip-\dimen0}%
+ #2\cr}}}
+
+\def\dddot%
+ {\def\thirddot{}%
+ \mathpalette\domultidot}
+
+\def\ddddot%
+ {\def\thirddot{\mkern-2.5mu\dotacc}%
+ \mathpalette\domultidot}
+
+\newcount\uproot@
+\newcount\leftroot@
+
+\def\nonmatherr#1%
+ {\errmessage{\noexpand#1allowed only in math mode}}
+
+\def\uproot#1%
+ {\relax
+ \ifmmode
+ \uproot@#1\relax
+ \else
+ \nonmatherr\uproot
+ \fi}
+
+\def\leftroot#1%
+ {\relax
+ \ifmmode
+ \leftroot@#1\relax
+ \else
+ \nonmatherr\leftroot
+ \fi}
+
+\def\root#1\of#2%
+ {\setbox\rootbox=\hbox{$\mathsurround\zeropoint\scriptscriptstyle{#1}$}%
+ \mathpalette\r@@t{#2}}
+
+\def\r@@t#1#2%
+ {\setbox\zerocount\hbox{$\uproot@\zerocount\leftroot\zerocount\mathsurround\zeropoint#1\sqrt{#2}$}%
+ \dimen@\ht\zerocount\advance\dimen@-\dp\zerocount
+ \dimen@ii\dimen@
+ \ifdim\dimen@>30\points \advance\dimen@ii-16\points \else
+ \ifdim\dimen@>24\points \advance\dimen@ii -8\points \else
+ \ifdim\dimen@>18\points \advance\dimen@ii -6\points \else
+ \ifdim\dimen@>12\points \advance\dimen@ii -4\points \else
+ \ifdim\dimen@>10\points \advance\dimen@ii -2\points \fi\fi\fi\fi\fi
+ \setbox\plustwo=\hbox{$\mathsurround\zeropoint#1\mskip\uproot@ mu$}%
+ \advance\dimen@ii by1.667\wd\plustwo
+ \mkern-\leftroot@ mu\mkern5mu\raise.6\dimen@ii\copy\rootbox
+ \mkern-8mu\mkern\leftroot@ mu\box\zerocount\leftroot\zerocount\uproot\zerocount}
+
+\def\space@.{\futurelet\space@\relax} \space@. % really needed ?
+
+\def\jadjust%
+ {\mkern-\plustwo mu}
+
+%D For the moment the following code is left unchanged. It is
+%D not used anyway.
+
+\newif\ifsubscriptcorrection \subscriptcorrectionfalse
+
+\ifsubscriptcorrection
+
+ \expandafter\let\csname subscript character \string_\endcsname_
+
+ \catcode`\_=\active
+
+ \def_%
+ {\ifmmode
+ \expandafter\sb@
+ \else
+ \expandafter\csname subscript character \string_\endcsname
+ \fi}
+
+ \let\sb_
+
+ \ifnum\catcode`\^^A=8 \catcode`\^^A\active\let^^A_\fi
+
+ \def\sb@#1%
+ {\csname subscript character \string_\endcsname
+ {\futurelet\next\sb@@#1}}
+
+ \def\sb@@%
+ {\ifx\next\space@
+ \def\next@. %
+ {\futurelet\next\sb@@}%
+ \else
+ \def\next@.%
+ {\ifx\next j%
+ \mkern-\plustwo mu\else
+ \ifx\next f%
+ \mkern-\plustwo mu\else
+ \ifx\next p%
+ \mkern-\plusone mu\fi\fi\fi}%
+ \fi
+ \next@.}
+
+\fi
+
+\protect
diff --git a/tex/context/base/math-uni.mkii b/tex/context/base/math-uni.mkii
new file mode 100644
index 000000000..e8fd3f05d
--- /dev/null
+++ b/tex/context/base/math-uni.mkii
@@ -0,0 +1,237 @@
+%D \module
+%D [ file=math-uni,
+%D version=2005.06.11,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=unicode support,
+%D author={Nikolai Weibull \& Taco Hoekwater},
+%D date=\currentdate,
+%D copyright=PRAGMA]
+
+\unprotect
+
+% needed for unic-032 % TH
+
+\startmathcollection[default]
+
+ \definemathcommand [unic@doubleverticalline] {\mathord{\parallel}}
+ \definemathcommand [unic@doublelowline] {\underline{\textunderscore}}
+
+ \definemathcommand [unic@doubleprime] {''}
+ \definemathcommand [unic@tripleprime] {'''}
+
+ \definemathcommand [unic@reverseddoubleprime] {\mathord{\backprime\backprime}}
+ \definemathcommand [unic@reversedtripleprime] {\mathord{\backprime\backprime\backprime}}
+
+ \definemathcommand [unic@fractionslash] {\vulgarfraction{}{}}
+ \definemathcommand [unic@lowasterisk] {\mathord{\lower-.2em\hbox{$\ast$}}}
+
+ \definemathcommand [unic@functionapplication] {\mathop{}}
+ \definemathcommand [unic@invisibletimes] {\mathbin{}}
+ \definemathcommand [unic@invisibleseparator] {\mathpunct{}}
+
+\stopmathcollection
+
+% needed for unic-033 % TH
+
+\def\unic@vulgarfraction#1#2%
+ {\hbox
+ {\high{{\tfx\it #1}\kern -.2em}%
+ \symbol[vulgarfraction]%
+ \kern -.2em\low{{\tfx\it #2}}}}
+
+\startmathcollection[default]
+
+ \definemathcommand [unic@accountof] {\unic@vulgarfraction{a}{c}}
+ \definemathcommand [unic@addressedtothesubject] {\unic@vulgarfraction{a}{s}}
+ \definemathcommand [unic@doublestruckC] {{\Bbb C}}
+ \definemathcommand [unic@degreecelsius] {{\textdegree \tf C}}
+ \definemathcommand [unic@centrelinesymbol] {\unknownchar}
+ \definemathcommand [unic@careof] {\unic@vulgarfraction{c}{o}}
+ \definemathcommand [unic@cadauna] {\unic@vulgarfraction{c}{u}}
+ \definemathcommand [unic@eulerconstant] {{\rm e}}
+ \definemathcommand [unic@scruple] {\unknownchar}
+ \definemathcommand [unic@degreefahrenheit] {{\textdegree \tf F}}
+ \definemathcommand [unic@scriptg] {\unknownchar}
+ \definemathcommand [unic@scriptH] {{\cal H}}
+ \definemathcommand [unic@blackletterH] {{\fraktur H}}
+ \definemathcommand [unic@doublestruckH] {{\Bbb H}}
+ \definemathcommand [unic@planckconstant] {h}
+ \definemathcommand [unic@planckconstantovertwopi] {\hslash}
+ \definemathcommand [unic@scriptI] {{\cal I}}
+ \definemathcommand [unic@blackletterI] {{\fraktur I}}
+ \definemathcommand [unic@scriptL] {{\cal L}}
+ \definemathcommand [unic@scriptl] {\ell}
+ \definemathcommand [unic@lbbarsymbol] {\unknownchar}
+ \definemathcommand [unic@doublestruckN] {{\Bbb N}}
+ \definemathcommand [unic@numerosign] {\hbox{\symbol[numero]}}
+ \definemathcommand [unic@soundrecordingcopyright] {\encircled{{\tfx P}}}
+ \definemathcommand [unic@scriptP] {{\cal P}}
+ \definemathcommand [unic@doublestruckP] {{\Bbb P}}
+ \definemathcommand [unic@doublestruckQ] {{\Bbb Q}}
+ \definemathcommand [unic@scriptR] {{\cal R}}
+ \definemathcommand [unic@blackletterR] {{\fraktur R}}
+ \definemathcommand [unic@doublestruckR] {{\Bbb R}}
+ \definemathcommand [unic@prescriptiontake] {\unknownchar}
+ \definemathcommand [unic@response] {\unknownchar}
+ \definemathcommand [unic@servicemark] {\high{\txx SM}}
+ \definemathcommand [unic@telephonesign] {\high{\txx TEL}}
+ \definemathcommand [unic@trademarksign] {\trademark}
+ \definemathcommand [unic@versickle] {\unknownchar}
+ \definemathcommand [unic@doublestruckZ] {{\Bbb Z}}
+ \definemathcommand [unic@ouncesign] {\unknownchar}
+ \definemathcommand [unic@ohmsign] {\Omega}
+ \definemathcommand [unic@invertedohmsign] {\rotate[\c!rotation=180]{\Omega}}
+ \definemathcommand [unic@blackletterZ] {{\fraktur Z}}
+ \definemathcommand [unic@turnedgreekletteriota] {\rotate[\c!rotation=180]{\iota}}
+ \definemathcommand [unic@kelvinsign] {{\tf K}}
+ \definemathcommand [unic@angstromsign] {\Angstrom}
+ \definemathcommand [unic@scriptB] {{\cal B}}
+ \definemathcommand [unic@blackletterC] {{\fraktur C}}
+ \definemathcommand [unic@estimatedsymbol] {\unknownchar}
+ \definemathcommand [unic@scripte] {\unknownchar}
+ \definemathcommand [unic@scriptE] {{\cal E}}
+ \definemathcommand [unic@scriptF] {{\cal F}}
+ \definemathcommand [unic@turnedF] {\rotate[\c!rotation=180]{{\tf F}}}
+ \definemathcommand [unic@scriptM] {{\cal M}}
+ \definemathcommand [unic@scripto] {\unknownchar}
+
+ \definemathcommand [unic@informationsource] {{\bf i}}
+ \definemathcommand [unic@rotatedQ] {\rotate[\c!rotation=90]{{\tf Q}}}
+ \definemathcommand [unic@facsimilesign] {\unknownchar}
+ \definemathcommand [unic@doublestruckpi] {\pi}%{\unknownchar}
+ \definemathcommand [unic@doublestruckgamma] {\gamma}%{\unknownchar}
+ \definemathcommand [unic@doublestruckGamma] {\Gamma}%{\unknownchar}
+ \definemathcommand [unic@doublestruckPi] {\Pi}%{\unknownchar}
+ \definemathcommand [unic@doublestrucknarysummation] {\unknownchar}
+ \definemathcommand [unic@turnedsansserifG] {\rotate[\c!rotation=180]{{\ss G}}}
+ \definemathcommand [unic@turnedsansserifL] {\rotate[\c!rotation=180]{{\ss L}}}
+ \definemathcommand [unic@reversedsansserifL] {\mirror{{\ss L}}}
+ \definemathcommand [unic@turnedsansserifY] {\rotate[\c!rotation=180]{{\ss Y}}}
+ \definemathcommand [unic@doublestruckitalicD] {D}%{\unknownchar}
+ \definemathcommand [unic@doublestruckitalicd] {d}%{\unknownchar}
+ \definemathcommand [unic@doublestruckitalice] {e}%{\unknownchar}
+ \definemathcommand [unic@doublestruckitalici] {i}%{\unknownchar}
+ \definemathcommand [unic@doublestruckitalicj] {j}%{\unknownchar}
+ \definemathcommand [unic@propertyline] {\unknownchar}
+ \definemathcommand [unic@turnedampersand] {\rotate[\c!rotation=180]{\&}}
+ \definemathcommand [unic@persign] {\unknownchar}
+
+ \definemathcommand [unic@fractiononethird] {\vulgarfraction{1}{3}}
+ \definemathcommand [unic@fractiontwothirds] {\vulgarfraction{2}{3}}
+ \definemathcommand [unic@fractiononefifth] {\vulgarfraction{1}{5}}
+ \definemathcommand [unic@fractiontwofifths] {\vulgarfraction{2}{5}}
+ \definemathcommand [unic@fractionthreefifths] {\vulgarfraction{3}{5}}
+ \definemathcommand [unic@fractionfourfifths] {\vulgarfraction{4}{5}}
+ \definemathcommand [unic@fractiononesixth] {\vulgarfraction{1}{6}}
+ \definemathcommand [unic@fractionfivesixths] {\vulgarfraction{5}{6}}
+ \definemathcommand [unic@fractiononeeighth] {\vulgarfraction{1}{8}}
+ \definemathcommand [unic@fractionthreeeighths] {\vulgarfraction{3}{8}}
+ \definemathcommand [unic@fractionfiveeighths] {\vulgarfraction{5}{8}}
+ \definemathcommand [unic@fractionseveneighths] {\vulgarfraction{7}{8}}
+ \definemathcommand [unic@fractionnumeratorone] {\vulgarfraction{1}{}}
+ \definemathcommand [unic@romannumeralOne] {{\tf I}}
+ \definemathcommand [unic@romannumeralTwo] {{\tf II}}
+ \definemathcommand [unic@romannumeralThree] {{\tf III}}
+ \definemathcommand [unic@romannumeralFour] {{\tf IV}}
+ \definemathcommand [unic@romannumeralFive] {{\tf V}}
+ \definemathcommand [unic@romannumeralSix] {{\tf VI}}
+ \definemathcommand [unic@romannumeralSeven] {{\tf VII}}
+ \definemathcommand [unic@romannumeralEight] {{\tf VIII}}
+ \definemathcommand [unic@romannumeralNine] {{\tf IX}}
+ \definemathcommand [unic@romannumeralTen] {{\tf X}}
+ \definemathcommand [unic@romannumeralEleven] {{\tf XI}}
+ \definemathcommand [unic@romannumeralTwelve] {{\tf XII}}
+ \definemathcommand [unic@romannumeralFifty] {{\tf L}}
+ \definemathcommand [unic@romannumeralOnehundred] {{\tf C}}
+ \definemathcommand [unic@romannumeralFivehundred] {{\tf D}}
+ \definemathcommand [unic@romannumeralOnethousand] {{\tf M}}
+ \definemathcommand [unic@romannumeralone] {{\tf i}}
+ \definemathcommand [unic@romannumeraltwo] {{\tf ii}}
+ \definemathcommand [unic@romannumeralthree] {{\tf iii}}
+ \definemathcommand [unic@romannumeralfour] {{\tf iv}}
+ \definemathcommand [unic@romannumeralfive] {{\tf v}}
+ \definemathcommand [unic@romannumeralsix] {{\tf vi}}
+ \definemathcommand [unic@romannumeralseven] {{\tf vii}}
+ \definemathcommand [unic@romannumeraleight] {{\tf viii}}
+ \definemathcommand [unic@romannumeralnine] {{\tf ix}}
+ \definemathcommand [unic@romannumeralten] {{\tf x}}
+ \definemathcommand [unic@romannumeraleleven] {{\tf xi}}
+ \definemathcommand [unic@romannumeraltwelve] {{\tf xii}}
+ \definemathcommand [unic@romannumeralfifty] {{\tf l}}
+ \definemathcommand [unic@romannumeralonehundred] {{\tf c}}
+ \definemathcommand [unic@romannumeralfivehundred] {{\tf d}}
+ \definemathcommand [unic@romannumeralonethousand] {{\tf m}}
+ \definemathcommand [unic@romannumeralonethousandCD] {\unknownchar}
+ \definemathcommand [unic@romannumeralfivethousand] {\unknownchar}
+ \definemathcommand [unic@romannumeraltenthousand] {\unknownchar}
+ \definemathcommand [unic@romannumeralreversedonehundred] {\mirror{C}}
+
+\stopmathcollection
+
+% needed for unic-033 % NW
+
+\startmathcollection[default]
+
+ \definemathcommand [unic@leftarrowtobar] {\mapstochar\leftarrow}
+
+\stopmathcollection
+
+% needed for unic-034 % NW
+
+\startmathcollection[default]
+
+ \definemathcommand [unic@in] {\in}
+ \definemathcommand [unic@nin] {\not\in}
+ \definemathcommand [unic@nni] {\not\ni}
+ \definemathcommand [unic@minus] {-}
+ \definemathcommand [unic@divisionslash] {/}
+ \definemathcommand [unic@sqrt] {\sqrt{}}
+ \definemathcommand [unic@cubesqrt] {\root 3 \of {}}
+ \definemathcommand [unic@fourthsqrt] {\root 4 \of {}}
+ \definemathcommand [unic@divides] [op] {|} % TODO
+ \definemathcommand [unic@ndivides] [rel] {\mathop{\not|}} % TODO: horrible
+ \definemathcommand [unic@cap] {\cap}
+ \definemathcommand [unic@dblint] {\int\!\!\!\int}
+ \definemathcommand [unic@triint] {\int\!\!\!\int\!\!\!\int}
+ \definemathcommand [unic@ratio] [rel] {:}
+ \definemathcommand [unic@proportion] [rel] {::}
+ \definemathcommand [unic@excess] [op] {-\!\!:}
+ \definemathcommand [unic@geomprop] [op] {:\!\!\!-\!\!\!:}
+ \definemathcommand [unic@homothetic] [op] {\sim\!\!\!:}
+ \definemathcommand [unic@nsimeq] {\not\simeq}
+ \definemathcommand [unic@cong] {\cong}
+ \definemathcommand [unic@napproxeq] {\not\approxeq}
+ \definemathcommand [unic@napprox] {\not\approx}
+ \definemathcommand [unic@doteq] {\doteq}
+ \definemathcommand [unic@correspondsto] {\buildrel \frown \over =}
+ \definemathcommand [unic@estimates] {\buildrel \wedge \over =}
+ \definemathcommand [unic@equiangularto] {\buildrel \vee \over =}
+ \definemathcommand [unic@stareq] {\buildrel \star \over =}
+ \definemathcommand [unic@eqbydef] {\buildrel \rm def \over =}
+ \definemathcommand [unic@measuredby] {\buildrel \rm m \over =}
+ \definemathcommand [unic@questionedeq] {\buildrel \rm ? \over =}
+ \definemathcommand [unic@nequiv] {\not\equiv}
+ \definemathcommand [unic@nasymp] {\not\asymp}
+ \definemathcommand [unic@nlesssim] {\not\lesssim}
+ \definemathcommand [unic@ngtrsim] {\not\gtrsim}
+ \definemathcommand [unic@nlessgtr] {\not\lessgtr}
+ \definemathcommand [unic@ngtrless] {\not\gtrless}
+ \definemathcommand [unic@nsubset] {\not\subset}
+ \definemathcommand [unic@nsupset] {\not\supset}
+ \definemathcommand [unic@nsqsubseteq] {\not\sqsubseteq}
+ \definemathcommand [unic@nsqsupseteq] {\not\sqsupseteq}
+
+\stopmathcollection
+
+% needed for unic-039 % NW
+
+\startmathcollection[default]
+
+ \definemathcommand [unic@Lbracket] [open] {[\![}
+ \definemathcommand [unic@Rbracket] [close] {]\!]}
+ \definemathcommand [unic@Langle] [open] {\langle\!\langle}
+ \definemathcommand [unic@Rangle] [close] {\rangle\!\rangle}
+
+\stopmathcollection
+
+\protect \endinput
diff --git a/tex/context/base/math-vfu.lua b/tex/context/base/math-vfu.lua
new file mode 100644
index 000000000..5023e6b4d
--- /dev/null
+++ b/tex/context/base/math-vfu.lua
@@ -0,0 +1,1379 @@
+if not modules then modules = { } end modules ['math-vfu'] = {
+ version = 1.001,
+ comment = "companion to math-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- All these math vectors .. thanks to Aditya and Mojca they become
+-- better and better. If you have problems with math fonts or miss
+-- characters report it to the ConTeXt mailing list.
+
+local type, next = type, next
+
+local trace_virtual = false trackers.register("math.virtual", function(v) trace_virtual = v end)
+local trace_timings = false trackers.register("math.timings", function(v) trace_timings = v end)
+
+fonts.enc.math = fonts.enc.math or { }
+
+local shared = { }
+
+fonts.vf.math = fonts.vf.math or { }
+fonts.vf.math.optional = false
+
+local push, pop, back = { "push" }, { "pop" }, { "slot", 1, 0x2215 }
+
+local function negate(main,characters,id,size,unicode,basecode)
+ if not characters[unicode] then
+ local basechar = characters[basecode]
+ if basechar then
+ local ht, wd = basechar.height, basechar.width
+ characters[unicode] = {
+ width = wd,
+ height = ht,
+ depth = basechar.depth,
+ italic = basechar.italic,
+ kerns = basechar.kerns,
+ commands = {
+ { "slot", 1, basecode },
+ push,
+ { "down", ht/5},
+ { "right", - wd/2},
+ back,
+ push,
+ }
+ }
+ end
+ end
+end
+
+--~ \Umathchardef\braceld="0 "1 "FF07A
+--~ \Umathchardef\bracerd="0 "1 "FF07B
+--~ \Umathchardef\bracelu="0 "1 "FF07C
+--~ \Umathchardef\braceru="0 "1 "FF07D
+
+local function brace(main,characters,id,size,unicode,first,rule,left,right,rule,last)
+ if not characters[unicode] then
+ characters[unicode] = {
+ horiz_variants = {
+ { extender = 0, glyph = first },
+ { extender = 1, glyph = rule },
+ { extender = 0, glyph = left },
+ { extender = 0, glyph = right },
+ { extender = 1, glyph = rule },
+ { extender = 0, glyph = last },
+ }
+ }
+ end
+end
+
+local function arrow(main,characters,id,size,unicode,arrow,minus,isleft)
+ if characters[unicode] then
+ if isleft then
+ t = {
+ { extender = 0, glyph = arrow },
+ { extender = 1, glyph = minus },
+ }
+ else
+ t = {
+ { extender = 0, glyph = minus },
+ { extender = 1, glyph = arrow },
+ }
+ end
+ --~ main.characters[unicode] = { horiz_variants = t }
+ characters[unicode].horiz_variants = t
+ end
+end
+
+local function parent(main,characters,id,size,unicode,first,rule,last)
+ if not characters[unicode] then
+ characters[unicode] = {
+ horiz_variants = {
+ { extender = 0, glyph = first },
+ { extender = 1, glyph = rule },
+ { extender = 0, glyph = last },
+ }
+ }
+ end
+end
+
+local push, pop, step = { "push" }, { "pop" }, 0.2 -- 0.1 is nicer but gives larger files
+
+local function make(main,characters,id,size,n,m)
+ local old = 0xFF000+n
+ local c = characters[old]
+ if c then
+ local upslot, dnslot, uprule, dnrule = 0xFF100+n, 0xFF200+n, 0xFF300+m, 0xFF400+m
+ local xu = main.parameters.x_height + 0.3*size
+ local xd = 0.3*size
+ local w, h, d = c.width, c.height, c.depth
+ local thickness = h - d
+ local rulewidth = step*size -- we could use an overlap
+ local slot = { "slot", id, old }
+ local rule = { "rule", thickness, rulewidth }
+ local up = { "down", -xu }
+ local dn = { "down", xd }
+ local ht, dp = xu + 3*thickness, 0
+ if not characters[uprule] then
+ characters[uprule] = { width = rulewidth, height = ht, depth = dp, commands = { push, up, rule, pop } }
+ end
+ characters[upslot] = { width = w, height = ht, depth = dp, commands = { push, up, slot, pop } }
+ local ht, dp = 0, xd + 3*thickness
+ if not characters[dnrule] then
+ characters[dnrule] = { width = rulewidth, height = ht, depth = dp, commands = { push, dn, rule, pop } }
+ end
+ characters[dnslot] = { width = w, height = ht, depth = dp, commands = { push, dn, slot, pop } }
+ end
+end
+
+local function minus(main,characters,id,size,unicode)
+ local minus = characters[0x002D]
+ if minus then
+ local mu = size/18
+ local width = minus.width - 5*mu
+ characters[unicode] = {
+ width = width, height = minus.height, depth = minus.depth,
+ commands = { push, { "right", -3*mu }, { "slot", id, 0x002D }, pop }
+ }
+ end
+end
+
+local function dots(main,characters,id,size,unicode)
+ local c = characters[0x002E]
+ if c then
+ local w, h, d = c.width, c.height, c.depth
+ local mu = size/18
+ local right3mu = { "right", 3*mu }
+ local right1mu = { "right", 1*mu }
+ local up1size = { "down", -.1*size }
+ local up4size = { "down", -.4*size }
+ local up7size = { "down", -.7*size }
+ local right2muw = { "right", 2*mu + w }
+ local slot = { "slot", id, 0x002E }
+ if unicode == 0x22EF then
+ local c = characters[0x022C5]
+ if c then
+ local w, h, d = c.width, c.height, c.depth
+ local slot = { "slot", id, 0x022C5 }
+ characters[unicode] = {
+ width = 3*w + 2*3*mu, height = h, depth = d,
+ commands = { push, slot, right3mu, slot, right3mu, slot, pop }
+ }
+ end
+ elseif unicode == 0x22EE then
+ -- weird height !
+ characters[unicode] = {
+ width = w, height = h+(1.4)*size, depth = 0,
+ commands = { push, push, slot, pop, up4size, push, slot, pop, up4size, slot, pop }
+ }
+ elseif unicode == 0x22F1 then
+ characters[unicode] = {
+ width = 3*w + 6*size/18, height = 1.5*size, depth = 0,
+ commands = {
+ push,
+ right1mu,
+ push, up7size, slot, pop,
+ right2muw,
+ push, up4size, slot, pop,
+ right2muw,
+ push, up1size, slot, pop,
+ right1mu,
+ pop
+ }
+ }
+ elseif unicode == 0x22F0 then
+ characters[unicode] = {
+ width = 3*w + 6*size/18, height = 1.5*size, depth = 0,
+ commands = {
+ push,
+ right1mu,
+ push, up1size, slot, pop,
+ right2muw,
+ push, up4size, slot, pop,
+ right2muw,
+ push, up7size, slot, pop,
+ right1mu,
+ pop
+ }
+ }
+ else
+ characters[unicode] = {
+ width = 3*w + 2*3*mu, height = h, depth = d,
+ commands = { push, slot, right3mu, slot, right3mu, slot, pop }
+ }
+ end
+ end
+end
+
+local function vertbar(main,characters,id,size,parent,scale,unicode)
+ local cp = characters[parent]
+ if cp then
+ local sc = scale * size
+ local pc = { "slot", id, parent }
+ characters[unicode] = {
+ width = cp.width,
+ height = cp.height + sc,
+ depth = cp.depth + sc,
+ commands = {
+ push, { "down", -sc }, pc, pop,
+ push, { "down", sc }, pc, pop,
+ pc,
+ },
+ next = cp.next -- can be extensible
+ }
+ cp.next = unicode
+ end
+end
+
+function fonts.vf.math.alas(main,id,size)
+ local characters = main.characters
+ for i=0x7A,0x7D do
+ make(main,characters,id,size,i,1)
+ end
+ brace (main,characters,id,size,0x23DE,0xFF17A,0xFF301,0xFF17D,0xFF17C,0xFF301,0xFF17B)
+ brace (main,characters,id,size,0x23DF,0xFF27C,0xFF401,0xFF27B,0xFF27A,0xFF401,0xFF27D)
+ parent (main,characters,id,size,0x23DC,0xFF17A,0xFF301,0xFF17B)
+ parent (main,characters,id,size,0x23DD,0xFF27C,0xFF401,0xFF27D)
+ negate (main,characters,id,size,0x2260,0x003D)
+ dots (main,characters,id,size,0x2026) -- ldots
+ dots (main,characters,id,size,0x22EE) -- vdots
+ dots (main,characters,id,size,0x22EF) -- cdots
+ dots (main,characters,id,size,0x22F1) -- ddots
+ dots (main,characters,id,size,0x22F0) -- udots
+ minus (main,characters,id,size,0xFF501)
+ arrow (main,characters,id,size,0x2190,0xFE190,0xFF501,true) -- left
+ arrow (main,characters,id,size,0x2192,0xFE192,0xFF501,false) -- right
+ vertbar(main,characters,id,size,0x0007C,0.10,0xFF601) -- big : 0.85 bodyfontsize
+ vertbar(main,characters,id,size,0xFF601,0.30,0xFF602) -- Big : 1.15 bodyfontsize
+ vertbar(main,characters,id,size,0xFF602,0.30,0xFF603) -- bigg : 1.45 bodyfontsize
+ vertbar(main,characters,id,size,0xFF603,0.30,0xFF604) -- Bigg : 1.75 bodyfontsize
+ vertbar(main,characters,id,size,0x02225,0.10,0xFF605)
+ vertbar(main,characters,id,size,0xFF605,0.30,0xFF606)
+ vertbar(main,characters,id,size,0xFF606,0.30,0xFF607)
+ vertbar(main,characters,id,size,0xFF607,0.30,0xFF608)
+end
+
+local unique = 0 -- testcase: \startTEXpage \math{!\text{-}\text{-}\text{-}} \stopTEXpage
+
+function fonts.basecopy(tfmtable,name)
+ local characters, parameters, fullname = tfmtable.characters, tfmtable.parameters, tfmtable.fullname
+ local t, c, p = { }, { }, { }
+ for k, v in next, tfmtable do
+ t[k] = v
+ end
+ if characters then
+ for k, v in next, characters do
+ c[k] = v
+ end
+ t.characters = c
+ else
+ logs.report("math virtual","font %s has no characters",name)
+ end
+ if parameters then
+ for k, v in next, parameters do
+ p[k] = v
+ end
+ t.parameters = p
+ else
+ logs.report("math virtual","font %s has no parameters",name)
+ end
+ -- tricky ... what if fullname does not exist
+ if fullname then
+ unique = unique + 1
+ t.fullname = fullname .. "-" .. unique
+ end
+ return t
+end
+
+local reported = { }
+local reverse -- index -> unicode
+
+function fonts.vf.math.define(specification,set)
+ if not reverse then
+ reverse = { }
+ for k, v in next, fonts.enc.math do
+ local r = { }
+ for u, i in next, v do
+ r[i] = u
+ end
+ reverse[k] = r
+ end
+ end
+ local name = specification.name -- symbolic name
+ local size = specification.size -- given size
+ local fnt, lst, main = { }, { }, nil
+ local start = (trace_virtual or trace_timings) and os.clock()
+ local okset, n = { }, 0
+ for s=1,#set do
+ local ss = set[s]
+ local ssname = ss.name
+ if ss.optional and fonts.vf.math.optional then
+ if trace_virtual then
+ logs.report("math virtual","loading font %s subfont %s with name %s at %s is skipped",name,s,ssname,size)
+ end
+ else
+ if ss.features then ssname = ssname .. "*" .. ss.features end
+ if ss.main then main = s end
+ local f, id = fonts.tfm.read_and_define(ssname,size)
+ if not f then
+ logs.report("math virtual","loading font %s subfont %s with name %s at %s is skipped, not found",name,s,ssname,size)
+ else
+ n = n + 1
+ okset[n] = ss
+ fnt[n] = f
+ lst[n] = { id = id, size = size }
+ if not shared[s] then shared[n] = { } end
+ if trace_virtual then
+ logs.report("math virtual","loading font %s subfont %s with name %s at %s as id %s using encoding %s",name,s,ssname,size,id,ss.vector or "none")
+ end
+ end
+ end
+ end
+ -- beware, fnt[1] is already passed to tex (we need to make a simple copy then .. todo)
+ main = fonts.basecopy(fnt[1],name)
+ main.name, main.fonts, main.virtualized, main.math_parameters = name, lst, true, { }
+ local characters, descriptions = main.characters, main.descriptions
+ local mp = main.parameters
+ if mp then
+ mp.x_height = mp.x_height or 0
+ end
+ local already_reported = false
+ for s=1,n do
+ local ss, fs = okset[s], fnt[s]
+ if not fs then
+ -- skip, error
+ elseif ss.optional and fonts.vf.math.optional then
+ -- skip, redundant
+ else
+ local mm, fp = main.math_parameters, fs.parameters
+ if mm and fp and mp then
+ if ss.extension then
+ mm.math_x_height = fp.x_height or 0 -- math_x_height height of x
+ mm.default_rule_thickness = fp[ 8] or 0 -- default_rule_thickness thickness of \over bars
+ mm.big_op_spacing1 = fp[ 9] or 0 -- big_op_spacing1 minimum clearance above a displayed op
+ mm.big_op_spacing2 = fp[10] or 0 -- big_op_spacing2 minimum clearance below a displayed op
+ mm.big_op_spacing3 = fp[11] or 0 -- big_op_spacing3 minimum baselineskip above displayed op
+ mm.big_op_spacing4 = fp[12] or 0 -- big_op_spacing4 minimum baselineskip below displayed op
+ mm.big_op_spacing5 = fp[13] or 0 -- big_op_spacing5 padding above and below displayed limits
+ -- logs.report("math virtual","loading and virtualizing font %s at size %s, setting ex parameters",name,size)
+ elseif ss.parameters then
+ mp.x_height = fp.x_height or mp.x_height
+ mm.x_height = mm.x_height or fp.x_height or 0 -- x_height height of x
+ mm.num1 = fp[ 8] or 0 -- num1 numerator shift-up in display styles
+ mm.num2 = fp[ 9] or 0 -- num2 numerator shift-up in non-display, non-\atop
+ mm.num3 = fp[10] or 0 -- num3 numerator shift-up in non-display \atop
+ mm.denom1 = fp[11] or 0 -- denom1 denominator shift-down in display styles
+ mm.denom2 = fp[12] or 0 -- denom2 denominator shift-down in non-display styles
+ mm.sup1 = fp[13] or 0 -- sup1 superscript shift-up in uncramped display style
+ mm.sup2 = fp[14] or 0 -- sup2 superscript shift-up in uncramped non-display
+ mm.sup3 = fp[15] or 0 -- sup3 superscript shift-up in cramped styles
+ mm.sub1 = fp[16] or 0 -- sub1 subscript shift-down if superscript is absent
+ mm.sub2 = fp[17] or 0 -- sub2 subscript shift-down if superscript is present
+ mm.sup_drop = fp[18] or 0 -- sup_drop superscript baseline below top of large box
+ mm.sub_drop = fp[19] or 0 -- sub_drop subscript baseline below bottom of large box
+ mm.delim1 = fp[20] or 0 -- delim1 size of \atopwithdelims delimiters in display styles
+ mm.delim2 = fp[21] or 0 -- delim2 size of \atopwithdelims delimiters in non-displays
+ mm.axis_height = fp[22] or 0 -- axis_height height of fraction lines above the baseline
+ -- logs.report("math virtual","loading and virtualizing font %s at size %s, setting sy parameters",name,size)
+ end
+ else
+ logs.report("math virtual","font %s, no parameters set",name)
+ end
+ local vectorname = ss.vector
+ if vectorname then
+ local offset = 0xFF000
+ local vector = fonts.enc.math[vectorname]
+ local rotcev = reverse[vectorname]
+ if vector then
+ local fc, fd, si = fs.characters, fs.descriptions, shared[s]
+ local skewchar = ss.skewchar
+ for unicode, index in next, vector do
+ local fci = fc[index]
+ if not fci then
+ local fontname = fs.name or "unknown"
+ local rf = reported[fontname]
+ if not rf then rf = { } reported[fontname] = rf end
+ local rv = rf[vectorname]
+ if not rv then rv = { } rf[vectorname] = rv end
+ local ru = rv[unicode]
+ if not ru then
+ if trace_virtual then
+ logs.report("math virtual", "unicode point U+%05X has no index %04X in vector %s for font %s",unicode,index,vectorname,fontname)
+ elseif not already_reported then
+ logs.report("math virtual", "the mapping is incomplete for '%s' at %s",name,number.topoints(size))
+ already_reported = true
+ end
+ rv[unicode] = true
+ end
+ else
+ local ref = si[index]
+ if not ref then
+ ref = { { 'slot', s, index } }
+ si[index] = ref
+ end
+ local kerns = fci.kerns
+ if kerns then
+ local width = fci.width
+ local krn = { }
+ for k=1,#kerns do
+ local rk = rotcev[k]
+ if rk then
+ krn[rk] = kerns[k]
+ end
+ end
+ if not next(krn) then
+ krn = nil
+ end
+ local t = {
+ width = width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ kerns = krn,
+ commands = ref,
+ }
+ if skewchar and kerns then
+ local k = kerns[skewchar]
+ if k then
+ t.top_accent = width/2 + k
+ end
+ end
+ characters[unicode] = t
+ else
+ characters[unicode] = {
+ width = fci.width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ commands = ref,
+ }
+ end
+ end
+ end
+ if ss.extension then
+ -- todo: if multiple ex, then 256 offsets per instance
+ local extension = fonts.enc.math["large-to-small"]
+ local variants_done = fs.variants_done
+ for index, fci in next, fc do -- the raw ex file
+ if type(index) == "number" then
+ local ref = si[index]
+ if not ref then
+ ref = { { 'slot', s, index } }
+ si[index] = ref
+ end
+ local t = {
+ width = fci.width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ commands = ref,
+ }
+ local n = fci.next
+ if n then
+ t.next = offset + n
+ elseif variants_done then
+ local vv = fci.vert_variants
+ if vv then
+ t.vert_variants = vv
+ end
+ local hv = fci.horiz_variants
+ if hv then
+ t.horiz_variants = hv
+ end
+ else
+ local vv = fci.vert_variants
+ if vv then
+ for i=1,#vv do
+ local vvi = vv[i]
+ vvi.glyph = vvi.glyph + offset
+ end
+ t.vert_variants = vv
+ end
+ local hv = fci.horiz_variants
+ if hv then
+ for i=1,#hv do
+ local hvi = hv[i]
+ hvi.glyph = hvi.glyph + offset
+ end
+ t.horiz_variants = hv
+ end
+ end
+ characters[offset + index] = t
+ end
+ end
+ fs.variants_done = true
+ for unicode, index in next, extension do
+ local cu = characters[unicode]
+ if cu then
+ cu.next = offset + index
+ --~ local n, c, d = unicode, cu, { }
+ --~ print("START", unicode)
+ --~ while n do
+ --~ n = c.next
+ --~ if n then
+ --~ print("NEXT", n)
+ --~ c = characters[n]
+ --~ if not c then
+ --~ print("EXIT")
+ --~ elseif d[n] then
+ --~ print("LOOP")
+ --~ break
+ --~ end
+ --~ d[n] = true
+ --~ end
+ --~ end
+ else
+ local fci = fc[index]
+ if not fci then
+--~ characters[unicode] = {
+--~ width = 0,
+--~ height = 0,
+--~ depth = 0,
+--~ index = 0,
+--~ }
+ else
+ local ref = si[index]
+ if not ref then
+ ref = { { 'slot', s, index } }
+ si[index] = ref
+ end
+ local kerns = fci.kerns
+ if kerns then
+ local krn = { }
+ for k=1,#kerns do
+ krn[offset + k] = kerns[k]
+ end
+ characters[unicode] = {
+ width = fci.width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ commands = ref,
+ kerns = krn,
+ next = offset + index,
+ }
+ else
+ characters[unicode] = {
+ width = fci.width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ commands = ref,
+ next = offset + index,
+ }
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ mathematics.extras.copy(main) --not needed here (yet)
+ end
+ end
+ lst[#lst+1] = { id = font.nextid(), size = size }
+ if mp then -- weak catch
+ fonts.vf.math.alas(main,#lst,size)
+ end
+ if trace_virtual or trace_timings then
+ logs.report("math virtual","loading and virtualizing font %s at size %s took %0.3f seconds",name,size,os.clock()-start)
+ end
+ main.has_italic = true
+ main.type = "virtual" -- not needed
+ mathematics.scaleparameters(main,main,1)
+ main.nomath = false
+--~ print(table.serialize(characters[0x222B]))
+--~ print(main.fontname,table.serialize(main.MathConstants))
+ return main
+end
+
+function mathematics.make_font(name, set)
+ fonts.define.methods[name] = function(specification)
+ return fonts.vf.math.define(specification,set)
+ end
+end
+
+-- varphi is part of the alphabet, contrary to the other var*s'
+
+fonts.enc.math["large-to-small"] = {
+ [0x00028] = 0x00, -- (
+ [0x00029] = 0x01, -- )
+ [0x0005B] = 0x02, -- [
+ [0x0005D] = 0x03, -- ]
+ [0x0230A] = 0x04, -- lfloor
+ [0x0230B] = 0x05, -- rfloor
+ [0x02308] = 0x06, -- lceil
+ [0x02309] = 0x07, -- rceil
+ [0x0007B] = 0x08, -- {
+ [0x0007D] = 0x09, -- }
+ [0x027E8] = 0x0A, -- <
+ [0x027E9] = 0x0B, -- >
+ [0x0007C] = 0x0C, -- |
+--~ [0x0] = 0x0D, -- lVert rVert Vert
+-- [0x0002F] = 0x0E, -- /
+ [0x0005C] = 0x0F, -- \
+--~ [0x0] = 0x3A, -- lgroup
+--~ [0x0] = 0x3B, -- rgroup
+--~ [0x0] = 0x3C, -- arrowvert
+--~ [0x0] = 0x3D, -- Arrowvert
+ [0x02195] = 0x3F, -- updownarrow
+--~ [0x0] = 0x40, -- lmoustache
+--~ [0x0] = 0x41, -- rmoustache
+ [0x0221A] = 0x70, -- sqrt
+ [0x021D5] = 0x77, -- Updownarrow
+ [0x02191] = 0x78, -- uparrow
+ [0x02193] = 0x79, -- downarrow
+ [0x021D1] = 0x7E, -- Uparrow
+ [0x021D3] = 0x7F, -- Downarrow
+ [0x0220F] = 0x59, -- prod
+ [0x02210] = 0x61, -- coprod
+ [0x02211] = 0x58, -- sum
+ [0x0222B] = 0x5A, -- intop
+ [0x0222E] = 0x49, -- ointop
+ [0xFE302] = 0x62, -- widehat
+ [0xFE303] = 0x65, -- widetilde
+ [0x022C0] = 0x5E, -- bigwedge
+ [0x022C1] = 0x5F, -- bigvee
+ [0x022C2] = 0x5C, -- bigcap
+ [0x022C3] = 0x5B, -- bigcup
+ [0x02044] = 0x0E, -- /
+}
+
+fonts.enc.math["tex-ex"] = {
+ [0x0220F] = 0x51, -- prod
+ [0x0222B] = 0x52, -- intop
+ [0x02210] = 0x60, -- coprod
+ [0x02211] = 0x50, -- sum
+ [0x022C0] = 0x56, -- bigwedge
+ [0x022C1] = 0x57, -- bigvee
+ [0x022C2] = 0x54, -- bigcap
+ [0x022C3] = 0x53, -- bigcup
+ [0x02A04] = 0x55, -- biguplus
+ [0x02A02] = 0x4E, -- bigotimes
+ [0x02A01] = 0x4C, -- bigoplus
+ [0x02A03] = 0x4A, -- bigodot
+ [0x0222E] = 0x48, -- ointop
+ [0x02A06] = 0x46, -- bigsqcup
+}
+
+-- only math stuff is needed, since we always use an lm or gyre
+-- font as main font
+
+fonts.enc.math["tex-mr"] = {
+ [0x00393] = 0x00, -- Gamma
+ [0x00394] = 0x01, -- Delta
+ [0x00398] = 0x02, -- Theta
+ [0x0039B] = 0x03, -- Lambda
+ [0x0039E] = 0x04, -- Xi
+ [0x003A0] = 0x05, -- Pi
+ [0x003A3] = 0x06, -- Sigma
+ [0x003A5] = 0x07, -- Upsilon
+ [0x003A6] = 0x08, -- Phi
+ [0x003A8] = 0x09, -- Psi
+ [0x003A9] = 0x0A, -- Omega
+-- [0x00060] = 0x12, -- [math]grave
+-- [0x000B4] = 0x13, -- [math]acute
+-- [0x002C7] = 0x14, -- [math]check
+-- [0x002D8] = 0x15, -- [math]breve
+-- [0x000AF] = 0x16, -- [math]bar
+-- [0x00021] = 0x21, -- !
+-- [0x00028] = 0x28, -- (
+-- [0x00029] = 0x29, -- )
+-- [0x0002B] = 0x2B, -- +
+-- [0x0002F] = 0x2F, -- /
+-- [0x0003A] = 0x3A, -- :
+-- [0x02236] = 0x3A, -- colon
+-- [0x0003B] = 0x3B, -- ;
+-- [0x0003C] = 0x3C, -- <
+-- [0x0003D] = 0x3D, -- =
+-- [0x0003E] = 0x3E, -- >
+-- [0x0003F] = 0x3F, -- ?
+ [0x00391] = 0x41, -- Alpha
+ [0x00392] = 0x42, -- Beta
+ [0x02145] = 0x44,
+ [0x00395] = 0x45, -- Epsilon
+ [0x00397] = 0x48, -- Eta
+ [0x00399] = 0x49, -- Iota
+ [0x0039A] = 0x4B, -- Kappa
+ [0x0039C] = 0x4D, -- Mu
+ [0x0039D] = 0x4E, -- Nu
+ [0x0039F] = 0x4F, -- Omicron
+ [0x003A1] = 0x52, -- Rho
+ [0x003A4] = 0x54, -- Tau
+ [0x003A7] = 0x58, -- Chi
+ [0x00396] = 0x5A, -- Zeta
+-- [0x0005B] = 0x5B, -- [
+-- [0x0005D] = 0x5D, -- ]
+-- [0x0005E] = 0x5E, -- [math]hat -- the text one
+ [0x00302] = 0x5E, -- [math]hat -- the real math one
+-- [0x002D9] = 0x5F, -- [math]dot
+ [0x02146] = 0x64,
+ [0x02147] = 0x65,
+-- [0x002DC] = 0x7E, -- [math]tilde -- the text one
+ [0x00303] = 0x7E, -- [math]tilde -- the real one
+-- [0x000A8] = 0x7F, -- [math]ddot
+}
+
+fonts.enc.math["tex-mr-missing"] = {
+ [0x02236] = 0x3A, -- colon
+}
+
+fonts.enc.math["tex-mi"] = {
+ [0x1D6E4] = 0x00, -- Gamma
+ [0x1D6E5] = 0x01, -- Delta
+ [0x1D6E9] = 0x02, -- Theta
+ [0x1D6F3] = 0x02, -- varTheta (not present in TeX)
+ [0x1D6EC] = 0x03, -- Lambda
+ [0x1D6EF] = 0x04, -- Xi
+ [0x1D6F1] = 0x05, -- Pi
+ [0x1D6F4] = 0x06, -- Sigma
+ [0x1D6F6] = 0x07, -- Upsilon
+ [0x1D6F7] = 0x08, -- Phi
+ [0x1D6F9] = 0x09, -- Psi
+ [0x1D6FA] = 0x0A, -- Omega
+ [0x1D6FC] = 0x0B, -- alpha
+ [0x1D6FD] = 0x0C, -- beta
+ [0x1D6FE] = 0x0D, -- gamma
+ [0x1D6FF] = 0x0E, -- delta
+ [0x1D716] = 0x0F, -- epsilon TODO: 1D716
+ [0x1D701] = 0x10, -- zeta
+ [0x1D702] = 0x11, -- eta
+ [0x1D703] = 0x12, -- theta TODO: 1D703
+ [0x1D704] = 0x13, -- iota
+ [0x1D705] = 0x14, -- kappa
+ [0x1D718] = 0x14, -- varkappa, not in tex fonts
+ [0x1D706] = 0x15, -- lambda
+ [0x1D707] = 0x16, -- mu
+ [0x1D708] = 0x17, -- nu
+ [0x1D709] = 0x18, -- xi
+ [0x1D70B] = 0x19, -- pi
+ [0x1D70C] = 0x1A, -- rho
+ [0x1D70E] = 0x1B, -- sigma
+ [0x1D70F] = 0x1C, -- tau
+ [0x1D710] = 0x1D, -- upsilon
+ [0x1D719] = 0x1E, -- phi
+ [0x1D712] = 0x1F, -- chi
+ [0x1D713] = 0x20, -- psi
+ [0x1D714] = 0x21, -- omega
+ [0x1D700] = 0x22, -- varepsilon (the other way around)
+ [0x1D717] = 0x23, -- vartheta
+ [0x1D71B] = 0x24, -- varpi
+ [0x1D71A] = 0x25, -- varrho
+ [0x1D70D] = 0x26, -- varsigma
+ [0x1D711] = 0x27, -- varphi (the other way around)
+ [0x021BC] = 0x28, -- leftharpoonup
+ [0x021BD] = 0x29, -- leftharpoondown
+ [0x021C0] = 0x2A, -- rightharpoonup
+ [0x021C1] = 0x2B, -- rightharpoondown
+ [0xFE322] = 0x2C, -- lhook (hook for combining arrows)
+ [0xFE323] = 0x2D, -- rhook (hook for combining arrows)
+ [0x022B3] = 0x2E, -- triangleright (TODO: which one is right?)
+ [0x022B2] = 0x2F, -- triangleleft (TODO: which one is right?)
+-- [0x00041] = 0x30, -- 0
+-- [0x00041] = 0x31, -- 1
+-- [0x00041] = 0x32, -- 2
+-- [0x00041] = 0x33, -- 3
+-- [0x00041] = 0x34, -- 4
+-- [0x00041] = 0x35, -- 5
+-- [0x00041] = 0x36, -- 6
+-- [0x00041] = 0x37, -- 7
+-- [0x00041] = 0x38, -- 8
+-- [0x00041] = 0x39, -- 9
+--~ [0x0002E] = 0x3A, -- .
+ [0x0002C] = 0x3B, -- ,
+ [0x0003C] = 0x3C, -- <
+-- [0x0002F] = 0x3D, -- /, slash, solidus
+ [0x02044] = 0x3D, -- / AM: Not sure
+ [0x0003E] = 0x3E, -- >
+ [0x022C6] = 0x3F, -- star
+ [0x02202] = 0x40, -- partial
+--
+ [0x0266D] = 0x5B, -- flat
+ [0x0266E] = 0x5C, -- natural
+ [0x0266F] = 0x5D, -- sharp
+ [0x02323] = 0x5E, -- smile
+ [0x02322] = 0x5F, -- frown
+ [0x02113] = 0x60, -- ell
+--
+ [0x1D6A4] = 0x7B, -- imath (TODO: also 0131)
+ [0x1D6A5] = 0x7C, -- jmath (TODO: also 0237)
+ [0x02118] = 0x7D, -- wp
+ [0x020D7] = 0x7E, -- vec (TODO: not sure)
+-- 0x7F, -- (no idea what that could be)
+}
+
+
+fonts.enc.math["tex-it"] = {
+-- [0x1D434] = 0x41, -- A
+ [0x1D6E2] = 0x41, -- Alpha
+-- [0x1D435] = 0x42, -- B
+ [0x1D6E3] = 0x42, -- Beta
+-- [0x1D436] = 0x43, -- C
+-- [0x1D437] = 0x44, -- D
+-- [0x1D438] = 0x45, -- E
+ [0x1D6E6] = 0x45, -- Epsilon
+-- [0x1D439] = 0x46, -- F
+-- [0x1D43A] = 0x47, -- G
+-- [0x1D43B] = 0x48, -- H
+ [0x1D6E8] = 0x48, -- Eta
+-- [0x1D43C] = 0x49, -- I
+ [0x1D6EA] = 0x49, -- Iota
+-- [0x1D43D] = 0x4A, -- J
+-- [0x1D43E] = 0x4B, -- K
+ [0x1D6EB] = 0x4B, -- Kappa
+-- [0x1D43F] = 0x4C, -- L
+-- [0x1D440] = 0x4D, -- M
+ [0x1D6ED] = 0x4D, -- Mu
+-- [0x1D441] = 0x4E, -- N
+ [0x1D6EE] = 0x4E, -- Nu
+-- [0x1D442] = 0x4F, -- O
+ [0x1D6F0] = 0x4F, -- Omicron
+-- [0x1D443] = 0x50, -- P
+ [0x1D6F2] = 0x50, -- Rho
+-- [0x1D444] = 0x51, -- Q
+-- [0x1D445] = 0x52, -- R
+-- [0x1D446] = 0x53, -- S
+-- [0x1D447] = 0x54, -- T
+ [0x1D6F5] = 0x54, -- Tau
+-- [0x1D448] = 0x55, -- U
+-- [0x1D449] = 0x56, -- V
+-- [0x1D44A] = 0x57, -- W
+-- [0x1D44B] = 0x58, -- X
+ [0x1D6F8] = 0x58, -- Chi
+-- [0x1D44C] = 0x59, -- Y
+-- [0x1D44D] = 0x5A, -- Z
+--
+-- [0x1D44E] = 0x61, -- a
+-- [0x1D44F] = 0x62, -- b
+-- [0x1D450] = 0x63, -- c
+-- [0x1D451] = 0x64, -- d
+-- [0x1D452] = 0x65, -- e
+-- [0x1D453] = 0x66, -- f
+-- [0x1D454] = 0x67, -- g
+-- [0x1D455] = 0x68, -- h
+ [0x0210E] = 0x68, -- Planck constant (h)
+-- [0x1D456] = 0x69, -- i
+-- [0x1D457] = 0x6A, -- j
+-- [0x1D458] = 0x6B, -- k
+-- [0x1D459] = 0x6C, -- l
+-- [0x1D45A] = 0x6D, -- m
+-- [0x1D45B] = 0x6E, -- n
+-- [0x1D45C] = 0x6F, -- o
+ [0x1D70A] = 0x6F, -- omicron
+-- [0x1D45D] = 0x70, -- p
+-- [0x1D45E] = 0x71, -- q
+-- [0x1D45F] = 0x72, -- r
+-- [0x1D460] = 0x73, -- s
+-- [0x1D461] = 0x74, -- t
+-- [0x1D462] = 0x75, -- u
+-- [0x1D463] = 0x76, -- v
+-- [0x1D464] = 0x77, -- w
+-- [0x1D465] = 0x78, -- x
+-- [0x1D466] = 0x79, -- y
+-- [0x1D467] = 0x7A, -- z
+}
+
+fonts.enc.math["tex-ss"] = { }
+fonts.enc.math["tex-tt"] = { }
+fonts.enc.math["tex-bf"] = { }
+fonts.enc.math["tex-bi"] = { }
+fonts.enc.math["tex-fraktur"] = { }
+fonts.enc.math["tex-fraktur-bold"] = { }
+
+function fonts.vf.math.set_letters(font_encoding, name, uppercase, lowercase)
+ local enc = font_encoding[name]
+ for i = 0,25 do
+ enc[uppercase+i] = i + 0x41
+ enc[lowercase+i] = i + 0x61
+ end
+end
+
+function fonts.vf.math.set_digits(font_encoding, name, digits)
+ local enc = font_encoding[name]
+ for i = 0,9 do
+ enc[digits+i] = i + 0x30
+ end
+end
+
+fonts.enc.math["tex-sy"] = {
+ [0x0002D] = 0x00, -- -
+ [0x02212] = 0x00, -- -
+-- [0x02201] = 0x00, -- complement
+-- [0x02206] = 0x00, -- increment
+-- [0x02204] = 0x00, -- not exists
+--~ [0x000B7] = 0x01, -- cdot
+ [0x022C5] = 0x01, -- cdot
+ [0x000D7] = 0x02, -- times
+ [0x0002A] = 0x03, -- *
+ [0x02217] = 0x03, -- *
+ [0x000F7] = 0x04, -- div
+ [0x022C4] = 0x05, -- diamond
+ [0x000B1] = 0x06, -- pm
+ [0x02213] = 0x07, -- mp
+ [0x02295] = 0x08, -- oplus
+ [0x02296] = 0x09, -- ominus
+ [0x02297] = 0x0A, -- otimes
+ [0x02298] = 0x0B, -- oslash
+ [0x02299] = 0x0C, -- odot
+ [0x025EF] = 0x0D, -- bigcirc, Orb (either 25EF or 25CB) -- todo
+ [0x02218] = 0x0E, -- circ
+ [0x02219] = 0x0F, -- bullet
+ [0x02022] = 0x0F, -- bullet
+ [0x0224D] = 0x10, -- asymp
+ [0x02261] = 0x11, -- equiv
+ [0x02286] = 0x12, -- subseteq
+ [0x02287] = 0x13, -- supseteq
+ [0x02264] = 0x14, -- leq
+ [0x02265] = 0x15, -- geq
+ [0x02AAF] = 0x16, -- preceq
+-- [0x0227C] = 0x16, -- preceq, AM:No see 2AAF
+ [0x02AB0] = 0x17, -- succeq
+-- [0x0227D] = 0x17, -- succeq, AM:No see 2AB0
+ [0x0223C] = 0x18, -- sim
+ [0x02248] = 0x19, -- approx
+ [0x02282] = 0x1A, -- subset
+ [0x02283] = 0x1B, -- supset
+ [0x0226A] = 0x1C, -- ll
+ [0x0226B] = 0x1D, -- gg
+ [0x0227A] = 0x1E, -- prec
+ [0x0227B] = 0x1F, -- succ
+ [0x02190] = 0x20, -- leftarrow
+ [0x02192] = 0x21, -- rightarrow
+--~ [0xFE190] = 0x20, -- leftarrow
+--~ [0xFE192] = 0x21, -- rightarrow
+ [0x02191] = 0x22, -- uparrow
+ [0x02193] = 0x23, -- downarrow
+ [0x02194] = 0x24, -- leftrightarrow
+ [0x02197] = 0x25, -- nearrow
+ [0x02198] = 0x26, -- searrow
+ [0x02243] = 0x27, -- simeq
+ [0x021D0] = 0x28, -- Leftarrow
+ [0x021D2] = 0x29, -- Rightarrow
+ [0x021D1] = 0x2A, -- Uparrow
+ [0x021D3] = 0x2B, -- Downarrow
+ [0x021D4] = 0x2C, -- Leftrightarrow
+ [0x02196] = 0x2D, -- nwarrow
+ [0x02199] = 0x2E, -- swarrow
+ [0x0221D] = 0x2F, -- propto
+ [0x02032] = 0x30, -- prime
+ [0x0221E] = 0x31, -- infty
+ [0x02208] = 0x32, -- in
+ [0x0220B] = 0x33, -- ni
+ [0x025B3] = 0x34, -- triangle, bigtriangleup
+ [0x025BD] = 0x35, -- bigtriangledown
+ [0x00338] = 0x36, -- not
+-- 0x37, -- (beginning of arrow)
+ [0x02200] = 0x38, -- forall
+ [0x02203] = 0x39, -- exists
+ [0x000AC] = 0x3A, -- neg, lnot
+ [0x02205] = 0x3B, -- empty set
+ [0x0211C] = 0x3C, -- Re
+ [0x02111] = 0x3D, -- Im
+ [0x022A4] = 0x3E, -- top
+ [0x022A5] = 0x3F, -- bot, perp
+ [0x02135] = 0x40, -- aleph
+ [0x1D49C] = 0x41, -- script A
+ [0x0212C] = 0x42, -- script B
+ [0x1D49E] = 0x43, -- script C
+ [0x1D49F] = 0x44, -- script D
+ [0x02130] = 0x45, -- script E
+ [0x02131] = 0x46, -- script F
+ [0x1D4A2] = 0x47, -- script G
+ [0x0210B] = 0x48, -- script H
+ [0x02110] = 0x49, -- script I
+ [0x1D4A5] = 0x4A, -- script J
+ [0x1D4A6] = 0x4B, -- script K
+ [0x02112] = 0x4C, -- script L
+ [0x02133] = 0x4D, -- script M
+ [0x1D4A9] = 0x4E, -- script N
+ [0x1D4AA] = 0x4F, -- script O
+ [0x1D4AB] = 0x50, -- script P
+ [0x1D4AC] = 0x51, -- script Q
+ [0x0211B] = 0x52, -- script R
+ [0x1D4AE] = 0x53, -- script S
+ [0x1D4AF] = 0x54, -- script T
+ [0x1D4B0] = 0x55, -- script U
+ [0x1D4B1] = 0x56, -- script V
+ [0x1D4B2] = 0x57, -- script W
+ [0x1D4B3] = 0x58, -- script X
+ [0x1D4B4] = 0x59, -- script Y
+ [0x1D4B5] = 0x5A, -- script Z
+ [0x0222A] = 0x5B, -- cup
+ [0x02229] = 0x5C, -- cap
+ [0x0228E] = 0x5D, -- uplus
+ [0x02227] = 0x5E, -- wedge, land
+ [0x02228] = 0x5F, -- vee, lor
+ [0x022A2] = 0x60, -- vdash
+ [0x022A3] = 0x61, -- dashv
+ [0x0230A] = 0x62, -- lfloor
+ [0x0230B] = 0x63, -- rfloor
+ [0x02308] = 0x64, -- lceil
+ [0x02309] = 0x65, -- rceil
+ [0x0007B] = 0x66, -- {, lbrace
+ [0x0007D] = 0x67, -- }, rbrace
+ [0x027E8] = 0x68, -- <, langle
+ [0x027E9] = 0x69, -- >, rangle
+ [0x0007C] = 0x6A, -- |, mid, lvert, rvert
+ [0x02225] = 0x6B, -- parallel, Vert, lVert, rVert, arrowvert
+ [0x02195] = 0x6C, -- updownarrow
+ [0x021D5] = 0x6D, -- Updownarrow
+ [0x0005C] = 0x6E, -- \, backslash, setminus
+ [0x02216] = 0x6E, -- setminus
+ [0x02240] = 0x6F, -- wr
+ [0x0221A] = 0x70, -- sqrt. AM: Check surd??
+ [0x02A3F] = 0x71, -- amalg
+ [0x1D6FB] = 0x72, -- nabla
+-- [0x0222B] = 0x73, -- smallint (TODO: what about intop?)
+ [0x02294] = 0x74, -- sqcup
+ [0x02293] = 0x75, -- sqcap
+ [0x02291] = 0x76, -- sqsubseteq
+ [0x02292] = 0x77, -- sqsupseteq
+ [0x000A7] = 0x78, -- S
+ [0x02020] = 0x79, -- dagger, dag
+ [0x02021] = 0x7A, -- ddagger, ddag
+ [0x000B6] = 0x7B, -- P
+ [0x02663] = 0x7C, -- clubsuit
+ [0x02662] = 0x7D, -- diamondsuit
+ [0x02661] = 0x7E, -- heartsuit
+ [0x02660] = 0x7F, -- spadesuit
+ [0xFE321] = 0x37, -- mapstochar
+}
+
+-- The names in masm10.enc can be trusted best and are shown in the first
+-- column, while in the second column we show the tex/ams names. As usual
+-- it costs hours to figure out such a table.
+
+fonts.enc.math["tex-ma"] = {
+ [0x022A1] = 0x00, -- squaredot \boxdot
+ [0x0229E] = 0x01, -- squareplus \boxplus
+ [0x022A0] = 0x02, -- squaremultiply \boxtimes
+ [0x025A1] = 0x03, -- square \square \Box
+ [0x025A0] = 0x04, -- squaresolid \blacksquare
+ [0x000B7] = 0x05, -- squaresmallsolid \centerdot
+ [0x022C4] = 0x06, -- diamond \Diamond \lozenge
+ [0x029EB] = 0x07, -- diamondsolid \blacklozenge
+ [0x021BA] = 0x08, -- clockwise \circlearrowright
+ [0x021BB] = 0x09, -- anticlockwise \circlearrowleft
+ [0x021CC] = 0x0A, -- harpoonleftright \rightleftharpoons
+ [0x021CB] = 0x0B, -- harpoonrightleft \leftrightharpoons
+ [0x0229F] = 0x0C, -- squareminus \boxminus
+ [0x022A9] = 0x0D, -- forces \Vdash
+ [0x022AA] = 0x0E, -- forcesbar \Vvdash
+ [0x022A8] = 0x0F, -- satisfies \vDash
+ [0x021A0] = 0x10, -- dblarrowheadright \twoheadrightarrow
+ [0x0219E] = 0x11, -- dblarrowheadleft \twoheadleftarrow
+ [0x021C7] = 0x12, -- dblarrowleft \leftleftarrows
+ [0x021C9] = 0x13, -- dblarrowright \rightrightarrows
+ [0x021C8] = 0x14, -- dblarrowup \upuparrows
+ [0x021CA] = 0x15, -- dblarrowdwn \downdownarrows
+ [0x021BE] = 0x16, -- harpoonupright \upharpoonright \restriction
+ [0x021C2] = 0x17, -- harpoondownright \downharpoonright
+ [0x021BF] = 0x18, -- harpoonupleft \upharpoonleft
+ [0x021C3] = 0x19, -- harpoondownleft \downharpoonleft
+ [0x021A3] = 0x1A, -- arrowtailright \rightarrowtail
+ [0x021A2] = 0x1B, -- arrowtailleft \leftarrowtail
+ [0x021C6] = 0x1C, -- arrowparrleftright \leftrightarrows
+-- [0x021C5] = 0x00, -- \updownarrows (missing in lm)
+ [0x021C4] = 0x1D, -- arrowparrrightleft \rightleftarrows
+ [0x021B0] = 0x1E, -- shiftleft \Lsh
+ [0x021B1] = 0x1F, -- shiftright \Rsh
+ [0x021DD] = 0x20, -- squiggleright \leadsto \rightsquigarrow
+ [0x021AD] = 0x21, -- squiggleleftright \leftrightsquigarrow
+ [0x021AB] = 0x22, -- curlyleft \looparrowleft
+ [0x021AC] = 0x23, -- curlyright \looparrowright
+ [0x02257] = 0x24, -- circleequal \circeq
+ [0x0227F] = 0x25, -- followsorequal \succsim
+ [0x02273] = 0x26, -- greaterorsimilar \gtrsim
+ [0x02A86] = 0x27, -- greaterorapproxeql \gtrapprox
+ [0x022B8] = 0x28, -- multimap \multimap
+ [0x02234] = 0x29, -- therefore \therefore
+ [0x02235] = 0x2A, -- because \because
+ [0x02251] = 0x2B, -- equalsdots \Doteq \doteqdot
+ [0x0225C] = 0x2C, -- defines \triangleq
+ [0x0227E] = 0x2D, -- precedesorequal \precsim
+ [0x02272] = 0x2E, -- lessorsimilar \lesssim
+ [0x02A85] = 0x2F, -- lessorapproxeql \lessapprox
+ [0x02A95] = 0x30, -- equalorless \eqslantless
+ [0x02A96] = 0x31, -- equalorgreater \eqslantgtr
+ [0x022DE] = 0x32, -- equalorprecedes \curlyeqprec
+ [0x022DF] = 0x33, -- equalorfollows \curlyeqsucc
+ [0x0227C] = 0x34, -- precedesorcurly \preccurlyeq
+ [0x02266] = 0x35, -- lessdblequal \leqq
+ [0x02A7D] = 0x36, -- lessorequalslant \leqslant
+ [0x02276] = 0x37, -- lessorgreater \lessgtr
+ [0x02035] = 0x38, -- primereverse \backprime
+ -- [0x0] = 0x39, -- axisshort \dabar
+ [0x02253] = 0x3A, -- equaldotrightleft \risingdotseq
+ [0x02252] = 0x3B, -- equaldotleftright \fallingdotseq
+ [0x0227D] = 0x3C, -- followsorcurly \succcurlyeq
+ [0x02267] = 0x3D, -- greaterdblequal \geqq
+ [0x02A7E] = 0x3E, -- greaterorequalslant \geqslant
+ [0x02277] = 0x3F, -- greaterorless \gtrless
+ [0x0228F] = 0x40, -- squareimage \sqsubset
+ [0x02290] = 0x41, -- squareoriginal \sqsupset
+ -- wrong:
+ [0x022B3] = 0x42, -- triangleright \rhd \vartriangleright
+ [0x022B2] = 0x43, -- triangleleft \lhd \vartriangleleft
+ [0x022B5] = 0x44, -- trianglerightequal \unrhd \trianglerighteq
+ [0x022B4] = 0x45, -- triangleleftequal \unlhd \trianglelefteq
+ --
+ [0x02605] = 0x46, -- star \bigstar
+ [0x0226C] = 0x47, -- between \between
+ [0x025BC] = 0x48, -- triangledownsld \blacktriangledown
+ [0x025B6] = 0x49, -- trianglerightsld \blacktriangleright
+ [0x025C0] = 0x4A, -- triangleleftsld \blacktriangleleft
+ -- [0x0] = 0x4B, -- arrowaxisright
+ -- [0x0] = 0x4C, -- arrowaxisleft
+ [0x025B2] = 0x4D, -- triangle \triangleup \vartriangle
+ [0x025B2] = 0x4E, -- trianglesolid \blacktriangle
+ [0x025BC] = 0x4F, -- triangleinv \triangledown
+ [0x02256] = 0x50, -- ringinequal \eqcirc
+ [0x022DA] = 0x51, -- lessequalgreater \lesseqgtr
+ [0x022DB] = 0x52, -- greaterlessequal \gtreqless
+ [0x02A8B] = 0x53, -- lessdbleqlgreater \lesseqqgtr
+ [0x02A8C] = 0x54, -- greaterdbleqlless \gtreqqless
+ [0x000A5] = 0x55, -- Yen \yen
+ [0x021DB] = 0x56, -- arrowtripleright \Rrightarrow
+ [0x021DA] = 0x57, -- arrowtripleleft \Lleftarrow
+ [0x02713] = 0x58, -- check \checkmark
+ [0x022BB] = 0x59, -- orunderscore \veebar
+ [0x022BC] = 0x5A, -- nand \barwedge
+ [0x02306] = 0x5B, -- perpcorrespond \doublebarwedge
+ [0x02220] = 0x5C, -- angle \angle
+ [0x02221] = 0x5D, -- measuredangle \measuredangle
+ [0x02222] = 0x5E, -- sphericalangle \sphericalangle
+ -- [0x0] = 0x5F, -- proportional \varpropto
+ -- [0x0] = 0x60, -- smile \smallsmile
+ -- [0x0] = 0x61, -- frown \smallfrown
+ [0x022D0] = 0x62, -- subsetdbl \Subset
+ [0x022D1] = 0x63, -- supersetdbl \Supset
+ [0x022D3] = 0x64, -- uniondbl \doublecup \Cup
+ [0x00100] = 0x65, -- intersectiondbl \doublecap \Cap
+ [0x022CF] = 0x66, -- uprise \curlywedge
+ [0x022CE] = 0x67, -- downfall \curlyvee
+ [0x022CB] = 0x68, -- multiopenleft \leftthreetimes
+ [0x022CC] = 0x69, -- multiopenright \rightthreetimes
+ [0x02AC5] = 0x6A, -- subsetdblequal \subseteqq
+ [0x02AC6] = 0x6B, -- supersetdblequal \supseteqq
+ [0x0224F] = 0x6C, -- difference \bumpeq
+ [0x0224E] = 0x6D, -- geomequivalent \Bumpeq
+ [0x022D8] = 0x6E, -- muchless \lll \llless
+ [0x022D9] = 0x6F, -- muchgreater \ggg \gggtr
+ [0x0231C] = 0x70, -- rightanglenw \ulcorner
+ [0x0231D] = 0x71, -- rightanglene \urcorner
+ [0x024C7] = 0x72, -- circleR \circledR
+ [0x024C8] = 0x73, -- circleS \circledS
+ [0x022D4] = 0x74, -- fork \pitchfork
+ [0x02245] = 0x75, -- dotplus \dotplus
+ [0x0223D] = 0x76, -- revsimilar \backsim
+ [0x022CD] = 0x77, -- revasymptequal \backsimeq -- AM: Check this! I mapped it to simeq.
+ [0x0231E] = 0x78, -- rightanglesw \llcorner
+ [0x0231F] = 0x79, -- rightanglese \lrcorner
+ [0x02720] = 0x7A, -- maltesecross \maltese
+ [0x02201] = 0x7B, -- complement \complement
+ [0x022BA] = 0x7C, -- intercal \intercal
+ [0x0229A] = 0x7D, -- circlering \circledcirc
+ [0x0229B] = 0x7E, -- circleasterisk \circledast
+ [0x0229D] = 0x7F, -- circleminus \circleddash
+}
+
+fonts.enc.math["tex-mb"] = {
+ -- [0x0] = 0x00, -- lessornotequal \lvertneqq
+ -- [0x0] = 0x01, -- greaterornotequal \gvertneqq
+ [0x02270] = 0x02, -- notlessequal \nleq
+ [0x02271] = 0x03, -- notgreaterequal \ngeq
+ [0x0226E] = 0x04, -- notless \nless
+ [0x0226F] = 0x05, -- notgreater \ngtr
+ [0x02280] = 0x06, -- notprecedes \nprec
+ [0x02281] = 0x07, -- notfollows \nsucc
+ [0x02268] = 0x08, -- lessornotdbleql \lneqq
+ [0x02269] = 0x09, -- greaterornotdbleql \gneqq
+ -- [0x0] = 0x0A, -- notlessorslnteql \nleqslant
+ -- [0x0] = 0x0B, -- notgreaterorslnteql \ngeqslant
+ [0x02A87] = 0x0C, -- lessnotequal \lneq
+ [0x02A88] = 0x0D, -- greaternotequal \gneq
+ -- [0x0] = 0x0E, -- notprecedesoreql \npreceq
+ -- [0x0] = 0x0F, -- notfollowsoreql \nsucceq
+ [0x022E8] = 0x10, -- precedeornoteqvlnt \precnsim
+ [0x022E9] = 0x11, -- followornoteqvlnt \succnsim
+ [0x022E6] = 0x12, -- lessornotsimilar \lnsim
+ [0x022E7] = 0x13, -- greaterornotsimilar \gnsim
+ -- [0x0] = 0x14, -- notlessdblequal \nleqq
+ -- [0x0] = 0x15, -- notgreaterdblequal \ngeqq
+ [0x02AB5] = 0x16, -- precedenotslnteql \precneqq
+ [0x02AB6] = 0x17, -- follownotslnteql \succneqq
+ [0x02AB9] = 0x18, -- precedenotdbleqv \precnapprox
+ [0x02ABA] = 0x19, -- follownotdbleqv \succnapprox
+ [0x02A89] = 0x1A, -- lessnotdblequal \lnapprox
+ [0x02A8A] = 0x1B, -- greaternotdblequal \gnapprox
+ [0x02241] = 0x1C, -- notsimilar \nsim
+ [0x02247] = 0x1D, -- notapproxequal \ncong
+ -- [0x0] = 0x1E, -- upslope \diagup
+ -- [0x0] = 0x1F, -- downslope \diagdown
+ -- [0x0] = 0x20, -- notsubsetoreql \varsubsetneq
+ -- [0x0] = 0x21, -- notsupersetoreql \varsupsetneq
+ -- [0x0] = 0x22, -- notsubsetordbleql \nsubseteqq
+ -- [0x0] = 0x23, -- notsupersetordbleql \nsupseteqq
+ [0x02ACB] = 0x24, -- subsetornotdbleql \subsetneqq
+ [0x02ACC] = 0x25, -- supersetornotdbleql \supsetneqq
+ -- [0x0] = 0x26, -- subsetornoteql \varsubsetneqq
+ -- [0x0] = 0x27, -- supersetornoteql \varsupsetneqq
+ [0x0228A] = 0x28, -- subsetnoteql \subsetneq
+ [0x0228B] = 0x29, -- supersetnoteql \supsetneq
+ [0x02288] = 0x2A, -- notsubseteql \nsubseteq
+ [0x02289] = 0x2B, -- notsuperseteql \nsupseteq
+ [0x02226] = 0x2C, -- notparallel \nparallel
+ [0x02224] = 0x2D, -- notbar \nmid \ndivides
+ -- [0x0] = 0x2E, -- notshortbar \nshortmid
+ -- [0x0] = 0x2F, -- notshortparallel \nshortparallel
+ [0x022AC] = 0x30, -- notturnstile \nvdash
+ [0x022AE] = 0x31, -- notforces \nVdash
+ [0x022AD] = 0x32, -- notsatisfies \nvDash
+ [0x022AF] = 0x33, -- notforcesextra \nVDash
+ [0x022ED] = 0x34, -- nottriangeqlright \ntrianglerighteq
+ [0x022EC] = 0x35, -- nottriangeqlleft \ntrianglelefteq
+ [0x022EA] = 0x36, -- nottriangleleft \ntriangleleft
+ [0x022EB] = 0x37, -- nottriangleright \ntriangleright
+ [0x0219A] = 0x38, -- notarrowleft \nleftarrow
+ [0x0219B] = 0x39, -- notarrowright \nrightarrow
+ [0x021CD] = 0x3A, -- notdblarrowleft \nLeftarrow
+ [0x021CF] = 0x3B, -- notdblarrowright \nRightarrow
+ [0x021CE] = 0x3C, -- notdblarrowboth \nLeftrightarrow
+ [0x021AE] = 0x3D, -- notarrowboth \nleftrightarrow
+ [0x022C7] = 0x3E, -- dividemultiply \divideontimes
+ [0x02300] = 0x3F, -- diametersign \varnothing
+ [0x02204] = 0x40, -- notexistential \nexists
+ [0x1D538] = 0x41, -- A (blackboard A)
+ [0x1D539] = 0x42, -- B
+ [0x02102] = 0x43, -- C
+ [0x1D53B] = 0x44, -- D
+ [0x1D53C] = 0x45, -- E
+ [0x1D53D] = 0x46, -- F
+ [0x1D53E] = 0x47, -- G
+ [0x0210D] = 0x48, -- H
+ [0x1D540] = 0x49, -- I
+ [0x1D541] = 0x4A, -- J
+ [0x1D542] = 0x4B, -- K
+ [0x1D543] = 0x4C, -- L
+ [0x1D544] = 0x4D, -- M
+ [0x02115] = 0x4E, -- N
+ [0x1D546] = 0x4F, -- O
+ [0x02119] = 0x50, -- P
+ [0x0211A] = 0x51, -- Q
+ [0x0211D] = 0x52, -- R
+ [0x1D54A] = 0x53, -- S
+ [0x1D54B] = 0x54, -- T
+ [0x1D54C] = 0x55, -- U
+ [0x1D54D] = 0x56, -- V
+ [0x1D54E] = 0x57, -- W
+ [0x1D54F] = 0x58, -- X
+ [0x1D550] = 0x59, -- Y
+ [0x02124] = 0x5A, -- Z (blackboard Z)
+ [0x02132] = 0x60, -- hatwide \Finv
+ [0x02141] = 0x61, -- hatwider \Game
+ -- [0x0] = 0x62, tildewide
+ -- [0x0] = 0x63, tildewider
+ -- [0x0] = 0x64, Finv
+ -- [0x0] = 0x65, Gmir
+ [0x02127] = 0x66, -- Omegainv \mho
+ [0x000F0] = 0x67, -- eth \eth
+ [0x02242] = 0x68, -- equalorsimilar \eqsim
+ [0x02136] = 0x69, -- beth \beth
+ [0x02137] = 0x6A, -- gimel \gimel
+ [0x02138] = 0x6B, -- daleth \daleth
+ [0x022D6] = 0x6C, -- lessdot \lessdot
+ [0x022D7] = 0x6D, -- greaterdot \gtrdot
+ [0x022C9] = 0x6E, -- multicloseleft \ltimes
+ [0x022CA] = 0x6F, -- multicloseright \rtimes
+ -- [0x0] = 0x70, -- barshort \shortmid
+ -- [0x0] = 0x71, -- parallelshort \shortparallel
+ -- [0x02216] = 0x72, -- integerdivide \smallsetminus (2216 already part of tex-sy
+ -- [0x0] = 0x73, -- similar \thicksim
+ -- [0x0] = 0x74, -- approxequal \thickapprox
+ [0x0224A] = 0x75, -- approxorequal \approxeq
+ [0x02AB8] = 0x76, -- followsorequal \succapprox
+ [0x02AB7] = 0x77, -- precedesorequal \precapprox
+ [0x021B6] = 0x78, -- archleftdown \curvearrowleft
+ [0x021B7] = 0x79, -- archrightdown \curvearrowright
+ [0x003DC] = 0x7A, -- Digamma \digamma
+ [0x003F0] = 0x7B, -- kappa \varkappa
+ [0x1D55C] = 0x7C, -- k \Bbbk (blackboard k)
+ [0x0210F] = 0x7D, -- planckover2pi \hslash
+ [0x00127] = 0x7E, -- planckover2pi1 \hbar
+ [0x003F6] = 0x7F, -- epsiloninv \backepsilon
+}
+
+fonts.enc.math["tex-fraktur"] = {
+-- [0x1D504] = 0x41, -- A (fraktur A)
+-- [0x1D505] = 0x42, -- B
+ [0x0212D] = 0x43, -- C
+-- [0x1D507] = 0x44, -- D
+-- [0x1D508] = 0x45, -- E
+-- [0x1D509] = 0x46, -- F
+-- [0x1D50A] = 0x47, -- G
+ [0x0210C] = 0x48, -- H
+ [0x02111] = 0x49, -- I
+-- [0x1D50D] = 0x4A, -- J
+-- [0x1D50E] = 0x4B, -- K
+-- [0x1D50F] = 0x4C, -- L
+-- [0x1D510] = 0x4D, -- M
+-- [0x1D511] = 0x4E, -- N
+-- [0x1D512] = 0x4F, -- O
+-- [0x1D513] = 0x50, -- P
+-- [0x1D514] = 0x51, -- Q
+ [0x0211C] = 0x52, -- R
+-- [0x1D516] = 0x53, -- S
+-- [0x1D517] = 0x54, -- T
+-- [0x1D518] = 0x55, -- U
+-- [0x1D519] = 0x56, -- V
+-- [0x1D51A] = 0x57, -- W
+-- [0x1D51B] = 0x58, -- X
+-- [0x1D51C] = 0x59, -- Y
+ [0x02128] = 0x5A, -- Z (fraktur Z)
+-- [0x1D51E] = 0x61, -- a (fraktur a)
+-- [0x1D51F] = 0x62, -- b
+-- [0x1D520] = 0x63, -- c
+-- [0x1D521] = 0x64, -- d
+-- [0x1D522] = 0x65, -- e
+-- [0x1D523] = 0x66, -- f
+-- [0x1D524] = 0x67, -- g
+-- [0x1D525] = 0x68, -- h
+-- [0x1D526] = 0x69, -- i
+-- [0x1D527] = 0x6A, -- j
+-- [0x1D528] = 0x6B, -- k
+-- [0x1D529] = 0x6C, -- l
+-- [0x1D52A] = 0x6D, -- m
+-- [0x1D52B] = 0x6E, -- n
+-- [0x1D52C] = 0x6F, -- o
+-- [0x1D52D] = 0x70, -- p
+-- [0x1D52E] = 0x71, -- q
+-- [0x1D52F] = 0x72, -- r
+-- [0x1D530] = 0x73, -- s
+-- [0x1D531] = 0x74, -- t
+-- [0x1D532] = 0x75, -- u
+-- [0x1D533] = 0x76, -- v
+-- [0x1D534] = 0x77, -- w
+-- [0x1D535] = 0x78, -- x
+-- [0x1D536] = 0x79, -- y
+-- [0x1D537] = 0x7A, -- z
+}
+
+-- now that all other vectors are defined ...
+
+fonts.vf.math.set_letters(fonts.enc.math, "tex-it", 0x1D434, 0x1D44E)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-ss", 0x1D5A0, 0x1D5BA)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-tt", 0x1D670, 0x1D68A)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-bf", 0x1D400, 0x1D41A)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-bi", 0x1D468, 0x1D482)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-fraktur", 0x1D504, 0x1D51E)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-fraktur-bold", 0x1D56C, 0x1D586)
+
+fonts.vf.math.set_digits (fonts.enc.math, "tex-ss", 0x1D7E2)
+fonts.vf.math.set_digits (fonts.enc.math, "tex-tt", 0x1D7F6)
+fonts.vf.math.set_digits (fonts.enc.math, "tex-bf", 0x1D7CE)
+
+-- fonts.vf.math.set_digits (fonts.enc.math, "tex-bi", 0x1D7CE)
+
+-- todo: add ss, tt, bf etc vectors
+-- todo: we can make ss tt etc an option
diff --git a/tex/context/base/meta-clp.tex b/tex/context/base/meta-clp.tex
new file mode 100644
index 000000000..be2506b19
--- /dev/null
+++ b/tex/context/base/meta-clp.tex
@@ -0,0 +1,164 @@
+%D \module
+%D [ file=meta-clp,
+%D version=2000.07.06,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Clipping,
+%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.
+
+%D In this library, we define a bunch of clipping paths that
+%D can be fed to \type {\clip}.
+
+\startMPclip{ellipse}
+ clip currentpicture to unitcircle
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{negellipse}
+ clip currentpicture to (unitcircle peepholed unitsquare)
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{urellipse}
+ clip currentpicture to urcircle scaled 2
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{ulellipse}
+ clip currentpicture to ulcircle scaled 2 shifted (1,0)
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{llellipse}
+ clip currentpicture to llcircle scaled 2 shifted (1,1)
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{lrellipse}
+ clip currentpicture to lrcircle scaled 2 shifted (0,1)
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{tellipse}
+ clip currentpicture to tcircle shifted (.5,0) yscaled 2
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{bellipse}
+ clip currentpicture to bcircle shifted (.5,.5) yscaled 2
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{lellipse}
+ clip currentpicture to lcircle shifted (.5,.5) xscaled 2
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{rellipse}
+ clip currentpicture to rcircle shifted (0,.5) xscaled 2
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{diamond}
+ clip currentpicture to unitdiamond
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{negdiamond}
+ clip currentpicture to (unitdiamond peepholed unitsquare)
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{urtriangle}
+ clip currentpicture to urtriangle scaled 2
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{ultriangle}
+ clip currentpicture to ultriangle scaled 2 shifted (1,0)
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{lltriangle}
+ clip currentpicture to lltriangle scaled 2 shifted (1,1)
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+\startMPclip{lrtriangle}
+ clip currentpicture to lrtriangle scaled 2 shifted (0,1)
+ xscaled \width yscaled \height ;
+\stopMPclip
+
+% More efficient:
+%
+% \def\dosimpleMPclip#1
+% {clip currentpicture to (#1) xscaled \width yscaled \height ;}
+%
+% \def\simpleMPclip#1#2%
+% {\startMPclip{#1}\dosimpleMPclip{#2}\stopMPclip}
+%
+% \simpleMPclip {ellipse} {unitcircle}
+% \simpleMPclip {diamond} {unitdiamond}
+%
+% \simpleMPclip {negellipse} {unitcircle peepholed unitsquare}
+% \simpleMPclip {negdiamond} {unitdiamond peepholed unitsquare}
+%
+% \simpleMPclip {urellipse} {urcircle scaled 2 shifted (0,0)}
+% \simpleMPclip {ulellipse} {ulcircle scaled 2 shifted (1,0)}
+% \simpleMPclip {llellipse} {llcircle scaled 2 shifted (1,1)}
+% \simpleMPclip {lrellipse} {lrcircle scaled 2 shifted (0,1)}
+%
+% \simpleMPclip {tellipse} {tcircle shifted (.5,0) yscaled 2}
+% \simpleMPclip {bellipse} {bcircle shifted (.5,.5) yscaled 2}
+% \simpleMPclip {lellipse} {lcircle shifted (.5,.5) xscaled 2}
+% \simpleMPclip {rellipse} {rcircle shifted (0,.5) xscaled 2}
+%
+% \simpleMPclip {urtriangle} {urtriangle scaled 2 shifted (0,0)}
+% \simpleMPclip {ultriangle} {ultriangle scaled 2 shifted (1,0)}
+% \simpleMPclip {lltriangle} {lltriangle scaled 2 shifted (1,1)}
+% \simpleMPclip {lrtriangle} {lrtriangle scaled 2 shifted (0,1)}
+
+%D \in {Figure} [fig:clipping paths] shows which paths are
+%D predefined. When applied to a whole picture, their usage
+%D is:
+%D
+%D \starttyping
+%D \clip[nx=1,ny=1,mp=ellipse]{some clippable content}
+%D \stoptyping
+%D
+%D \startbuffer
+%D \setupclipping [nx=1,ny=1,x=1,y=1]
+%D \setupblackrules[width=2cm,height=1cm]
+%D \startcombination[6*3] % \startcombination[6*3]
+%D {\clip[mp=urellipse] {\blackrule}} {urellipse}
+%D {\clip[mp=ulellipse] {\blackrule}} {ulellipse}
+%D {\clip[mp=llellipse] {\blackrule}} {llellipse}
+%D {\clip[mp=lrellipse] {\blackrule}} {lrellipse}
+%D {\clip[mp=ellipse] {\blackrule}} {ellipse}
+%D {\clip[mp=negellipse]{\blackrule}} {negellipse}
+%D {\clip[mp=tellipse] {\blackrule}} {tellipse}
+%D {\clip[mp=bellipse] {\blackrule}} {bellipse}
+%D {\clip[mp=lellipse] {\blackrule}} {lellipse}
+%D {\clip[mp=rellipse] {\blackrule}} {rellipse}
+%D {} {}
+%D {} {}
+%D {\clip[mp=urtriangle]{\blackrule}} {urtriangle}
+%D {\clip[mp=ultriangle]{\blackrule}} {ultriangle}
+%D {\clip[mp=lltriangle]{\blackrule}} {lltriangle}
+%D {\clip[mp=lrtriangle]{\blackrule}} {lrtriangle}
+%D {\clip[mp=diamond] {\blackrule}} {diamond}
+%D {\clip[mp=negdiamond]{\blackrule}} {negdiamond}
+%D \stopcombination % \stopcombination
+%D \stopbuffer
+%D
+%D \placefigure % \placefigure
+%D [here][fig:clipping paths]
+%D {The predefined clipping paths.}
+%D {\getbuffer} % {\getbuffer}
+
+\endinput
diff --git a/tex/context/base/meta-dum.tex b/tex/context/base/meta-dum.tex
new file mode 100644
index 000000000..bc19f3c5f
--- /dev/null
+++ b/tex/context/base/meta-dum.tex
@@ -0,0 +1,123 @@
+%D \module
+%D [ file=meta-dum,
+%D version=2003.03.21,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Dummy (External) Graphics,
+%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.
+
+\unprotect
+
+%D This library overloads the normal external figure
+%D placeholder by a nicer one.
+%D
+%D \startbuffer
+%D \useMPlibrary[dum]
+%D
+%D \startlinecorrection
+%D \externalfigure[unknown-a][width=3cm,height=1cm]
+%D \stoplinecorrection
+%D
+%D \startlinecorrection
+%D \externalfigure[unknown-b][width=4cm,height=5cm]
+%D \stoplinecorrection
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+% currently preparempvariables is unable to resolve number
+% fractions like reduction
+
+% June 22, 2003, this definition was patched to adapt itself
+% to transparent colors
+
+\startuseMPgraphic{placeholder}{width,height,reduction,color}
+ numeric w, h, d, r ; color c, b, cc ; path p ; boolean t ;
+ t := is_transparent(\MPvar{color}) ;
+ c := not_transparent(\MPvar{color}) ;
+ b := not_transparent(white) ;
+ w := \MPvar{width} ;
+ h := \MPvar{height} ;
+ r := \MPvar{reduction} ;
+ d := max(w,h) ;
+ p := unitsquare xyscaled (w,h) ;
+ cc := r[.5c,b] ;
+ fill p withcolor if t : transparent(1,.5,cc) else : cc fi ;
+ for i := 1 upto 60 :
+ cc := r[c randomized(.3,.9),b] ;
+ fill fullcircle
+ scaled (d/5 randomized (d/5))
+ shifted (center p randomized (d))
+ withcolor if t : transparent(1,.5,cc) else : cc fi ;
+ endfor ;
+ clip currentpicture to p ;
+\stopuseMPgraphic
+
+\definepalet
+ [placeholder]
+ [1=red,2=green,3=blue,4=cyan,5=magenta,6=yellow]
+
+% \newcounter \figurereplacementcycle
+
+\let\figurereplacementcycle\relax
+
+\setupexternalfigures
+ [\c!reduction=0,
+ \c!text=\v!yes]
+
+\let\normalexternalfigurereplacement\externalfigurereplacement
+
+\def\externalfigurereplacement#1#2#3%
+ {\getpaletsize[placeholder]%
+ \ifx\figurereplacementcycle\relax
+ \getrandomnumber \figurereplacementcycle \!!plusone \paletsize
+ \globallet \figurereplacementcycle \figurereplacementcycle
+ \else
+ \doglobal\increment\figurereplacementcycle
+ \fi
+ \ifnum\figurereplacementcycle>\paletsize
+ \globallet\figurereplacementcycle\!!plusone
+ \fi
+ \weightGRAYfalse % monochrome anyway
+ \MPcmykcolorsfalse
+ \MPspotcolorsfalse
+ \defineoverlay
+ [\s!dummy]
+ [\useMPgraphic
+ {placeholder}%
+ {width=\figurewidth,
+ height=\figureheight,
+ reduction=\@@efreduction,
+ color=placeholder:\figurereplacementcycle}]%
+ \expanded{\localframed
+ [\??ef]
+ [\c!width=\figurewidth,
+ \c!height=\figureheight,
+ \c!frame=\v!off,
+ \c!strut=\v!no,
+ \c!background=\s!dummy,
+ \c!foregroundcolor=\s!white]}%
+ {\doif\@@eftext\v!yes
+ {\infofont \setupinterlinespace \dohyphens % \nohyphens
+ \doifelse{#1}\s!dummy \!!doneafalse\!!doneatrue
+ \doifelse{#2}\s!dummy \!!donebfalse\!!donebtrue
+ \doifelse{#3}\s!unknown\!!donecfalse\!!donectrue
+ \if!!donea
+ name: \expanded{\verbatimstring{#1}}\strut\endgraf
+ \fi
+ \if!!doneb
+ \if!!donea file: \else \if!!donec file: \fi \fi
+ \expanded{\verbatimstring{#2}}\strut\endgraf
+ \fi
+ \if!!donec
+ state: \expanded{\verbatimstring{#3}}\strut\endgraf
+ \fi}}}
+
+\def\dummyfigure{\externalfigure[placeholder]}
+
+\protect \endinput
diff --git a/tex/context/base/meta-fig.mkii b/tex/context/base/meta-fig.mkii
new file mode 100644
index 000000000..3edd73b57
--- /dev/null
+++ b/tex/context/base/meta-fig.mkii
@@ -0,0 +1,89 @@
+%D \module
+%D [ file=meta-fig,
+%D version=2000.09.07,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Stand Alone Graphics,
+%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}{MetaPost Graphics / Stand Alone Graphics}
+
+\unprotect
+
+%D This module implements a method for defining
+%D stand||alone||graphics, that is, each graphic gets is own
+%D page. Because graphics are wrapped in a \type {\framed},
+%D you can add overlays to the graphic directly, and since the
+%D whole \CONTEXT\ machinery is available, you can also add
+%D page backgrounds.
+%D
+%D \starttyping
+%D \setupMPpage
+%D [offset=1pt,
+%D background=color,
+%D backgroundcolor=green]
+%D
+%D \startMPpage
+%D fill fullcircle scaled 10cm withcolor red ;
+%D \stopMPpage
+%D
+%D \startMPpage
+%D fill fullsquare rotated 45 scaled 8cm withcolor blue ;
+%D \stopMPpage
+%D \stoptyping
+%D
+%D Although this is hardly of any use, you can mix these
+%D definitions with the text flow, since all settings are
+%D kept local. The page is clipped to the image size.
+
+\presetlocalframed[\??mg]
+
+\def\setupMPpage
+ {\dodoubleargument\getparameters[\??mg]}
+
+\def\startMPpage
+ {\dodoubleempty\dostartMPpage}
+
+\long\def\dostartMPpage[#1][#2]% second arg gobbles space
+ {\dostartfittingpage[\??mg][#1]%
+ \obeyMPlines
+ \dodostartMPpage}
+
+\long\def\dodostartMPpage#1\stopMPpage
+ {\startuseMPgraphic{@@}#1\stopuseMPgraphic
+ \useMPgraphic{@@}%
+ \dostopfittingpage}
+
+\let\stopMPpage \relax % so that we can use it in \expanded
+
+\setupMPpage
+ [\c!scale=1000,
+ \c!strut=\v!no,
+ \c!align=,
+ \c!offset=\v!overlay,
+ \c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!frame=\v!off]
+
+%D \macros
+%D {MPfigure}
+%D
+%D A bit out of place, here but nevertheless:
+
+\def\MPfigure#1#2% test for dup figure
+ {\bgroup
+ \getfiguredimensionsonly[#1]% [\c!object=\v!no] already set
+ \startMPcode
+ externalfigure "#1"
+ xscaled \figurewidth\space
+ yscaled \figureheight\space
+ #2 ;
+ \stopMPcode
+ \egroup}
+
+\protect \endinput
diff --git a/tex/context/base/meta-fig.mkiv b/tex/context/base/meta-fig.mkiv
new file mode 100644
index 000000000..4738316da
--- /dev/null
+++ b/tex/context/base/meta-fig.mkiv
@@ -0,0 +1,84 @@
+%D \module
+%D [ file=meta-fig,
+%D version=2000.09.07,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Stand Alone Graphics,
+%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}{MetaPost Graphics / Stand Alone Graphics}
+
+\unprotect
+
+%D This module implements a method for defining
+%D stand||alone||graphics, that is, each graphic gets is own
+%D page. Because graphics are wrapped in a \type {\framed},
+%D you can add overlays to the graphic directly, and since the
+%D whole \CONTEXT\ machinery is available, you can also add
+%D page backgrounds.
+%D
+%D \starttyping
+%D \setupMPpage
+%D [offset=1pt,
+%D background=color,
+%D backgroundcolor=green]
+%D
+%D \startMPpage
+%D fill fullcircle scaled 10cm withcolor red ;
+%D \stopMPpage
+%D
+%D \startMPpage
+%D fill fullsquare rotated 45 scaled 8cm withcolor blue ;
+%D \stopMPpage
+%D \stoptyping
+%D
+%D Although this is hardly of any use, you can mix these
+%D definitions with the text flow, since all settings are
+%D kept local. The page is clipped to the image size.
+
+\presetlocalframed[\??mg]
+
+\unexpanded\def\setupMPpage
+ {\dodoubleargument\getparameters[\??mg]}
+
+\def\startMPpage
+ {\dodoubleempty\dostartMPpage}
+
+\long\def\dostartMPpage[#1][#2]#3\stopMPpage % second arg gobbles space
+ {\dostartfittingpage[\??mg][#1]%
+ \processMPgraphic{#3}%
+ \dostopfittingpage}
+
+\let\stopMPpage \relax % so that we can use it in \expanded
+
+\setupMPpage
+ [\c!scale=1000,
+ \c!strut=\v!no,
+ \c!align=,
+ \c!offset=\v!overlay,
+ \c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!frame=\v!off]
+
+%D \macros
+%D {MPfigure}
+%D
+%D A bit out of place, here but nevertheless:
+
+\def\MPfigure#1#2% test for dup figure, can be replaced by a textext
+ {\bgroup
+ \getfiguredimensionsonly[#1]% [\c!object=\v!no] already set
+ \startMPcode
+ externalfigure "#1"
+ xscaled \the\dimexpr\figurewidth \relax\space % must be points
+ yscaled \the\dimexpr\figureheight\relax\space % must be points
+ #2 ;
+ \stopMPcode
+ \egroup}
+
+\protect \endinput
diff --git a/tex/context/base/meta-fun.lua b/tex/context/base/meta-fun.lua
new file mode 100644
index 000000000..fef2aa12b
--- /dev/null
+++ b/tex/context/base/meta-fun.lua
@@ -0,0 +1,55 @@
+if not modules then modules = { } end modules ['meta-fun'] = {
+ version = 1.001,
+ comment = "companion to meta-fun.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- very experimental, actually a joke ... see metafun manual for usage
+
+local format, loadstring, type = string.format, loadstring, type
+local texwrite = tex.write
+
+metafun = metafun or { }
+
+function metafun.topath(t,connector)
+ tex.write("(")
+ if #t > 0 then
+ for i=1,#t do
+ if i > 1 then
+ texwrite(connector or "..")
+ end
+ local ti = t[i]
+ if type(ti) == "string" then
+ texwrite(ti)
+ else
+ texwrite(format("(%s,%s)",ti.x or ti[1] or 0,ti.y or ti[2] or 0))
+ end
+ end
+ else
+ texwrite("origin")
+ end
+ texwrite(")")
+end
+
+function metafun.interpolate(f,b,e,s,c)
+ local done = false
+ tex.write("(")
+ for i=b,e,(e-b)/s do
+ local d = loadstring(format("return function(x) return %s end",f))
+ if d then
+ d = d()
+ if done then
+ texwrite(c or "...")
+ else
+ done = true
+ end
+ texwrite(format("(%s,%s)",i,d(i)))
+ end
+ end
+ if not done then
+ texwrite("origin")
+ end
+ texwrite(")")
+end
diff --git a/tex/context/base/meta-fun.mkiv b/tex/context/base/meta-fun.mkiv
new file mode 100644
index 000000000..a43ffefff
--- /dev/null
+++ b/tex/context/base/meta-fun.mkiv
@@ -0,0 +1,20 @@
+%D \module
+%D [ file=meta-fun,
+%D version=2009.06.02,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Goodies,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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}{MetaPost Graphics / Goodies}
+
+\registerctxluafile{meta-fun}{1.001}
+
+\unprotect
+
+\protect \endinput
diff --git a/tex/context/base/meta-ini.mkii b/tex/context/base/meta-ini.mkii
new file mode 100644
index 000000000..e7c6d218e
--- /dev/null
+++ b/tex/context/base/meta-ini.mkii
@@ -0,0 +1,1054 @@
+%D \module
+%D [ file=meta-ini,
+%D version=1999.07.10,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Initialization,
+%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.
+
+% currently the running color influences the mp graphic in
+% pdftex, but this will change [i.e. become optional]; one
+% problem is that pdf has no grouping with regards to the
+% color
+
+\writestatus{loading}{MetaPost Graphics / Initializations}
+
+\unprotect
+
+%D This module extends the functionality of the support module
+%D \type {supp-mps}, the module that is responsible for
+%D \METAPOST\ inclusion in \CONTEXT. Some basic macros will be
+%D extended. Since some support is depends on \METAPOST\
+%D macros. so let's first preload a few auxiliary \METAPOST\
+%D files.
+
+\maxnofMPgraphics = 4000 % metafun disables the 4K boundary
+
+\appendtoks \flushMPgraphics \to \everygoodbye % \everylastshipout
+
+\def\@@MPG{@MPG@}
+
+\startMPextensions
+ if unknown context_tool: input mp-tool; fi;
+ if unknown context_spec: input mp-spec; fi;
+ if unknown context_grph: input mp-grph; fi;
+\stopMPextensions
+
+%D Since we want lables to follow the document settings, we
+%D also set the font related variables.
+
+\ifnum\texengine=\xetexengine
+ \startMPinitializations % scale is not yet ok
+ defaultfont:="rm-lmtt10";
+ defaultscale:=\the\bodyfontsize/10pt;
+ \stopMPinitializations
+\else
+ \startMPinitializations % scale is not yet ok
+ defaultfont:="\truefontname{Regular}";
+ defaultscale:=\the\bodyfontsize/10pt;
+ \stopMPinitializations
+\fi
+
+%D In order to support fancy text features (like outline
+%D fonts), we set:
+
+\startMPextensions
+ graphictextformat:="context";
+ graphictextdirective "\the\everyMPTEXgraphic";
+\stopMPextensions
+
+% \startMPextensions
+% textextdirective "\the\everyMPTEXgraphic";
+% \stopMPextensions
+
+%D A signal that we're in combines \CONTEXT||\METAFUN mode:
+
+\startMPextensions
+ string contextversion;
+ contextversion:="\contextversion";
+\stopMPextensions
+
+%D Some safeguards:
+%D
+%D \starttyping
+%D \appendtoks \cleanupfeatures \to \everyMPgraphic
+%D \stoptyping
+%D
+%D No, we don't want that (else we loose UTF etc).
+
+%D Another one:
+
+\prependtoks \MPstaticgraphictrue \to \everyoverlay
+\prependtoks \MPstaticgraphictrue \to \everypagebody
+
+%D We save the number of graphics for the sake of \TEXEXEC.
+
+\newcounter\totalnofMPgraphics
+
+\def\thenofMPgraphics{\the\nofMPgraphics} % from supp-mps
+
+\appendtoks
+ \savecurrentvalue\totalnofMPgraphics\thenofMPgraphics
+\to \everybye
+
+%D \macros
+%D {setupMPvariables}
+%D
+%D When we build collections of \METAPOST\ graphics, like
+%D background and buttons, the need for passing settings
+%D arises. By (mis|)|using the local prefix that belongs to
+%D \type {\framed}, we get a rather natural interface to
+%D backgrounds. To prevent conflicts, we will use the \type
+%D {-} in \METAPOST\ specific variables, like:
+%D
+%D \starttyping
+%D \setupMPvariables[meta:button][size=20pt]
+%D \stoptyping
+
+\def\@@meta{meta:}
+
+\def\setupMPvariables
+ {\dodoubleempty\dosetupMPvariables}
+
+\def\dosetupMPvariables[#1][#2]%
+ {\ifsecondargument
+ \getrawparameters[#1:][#2]% brr, todo: [\@@meta#1:]
+ \else
+ \getrawparameters[\@@meta][#1]%
+ \fi}
+
+\let\@@framed\s!unknown
+
+\def\MPvariable#1%
+ {\csname
+ \ifcsname\@@framed\@@meta#1\endcsname\@@framed\fi\@@meta#1%
+ \endcsname}
+
+\let\MPvar\MPvariable
+
+\let\setMPvariables\setupMPvariables
+
+\def\MPrawvar#1#2{\csname#1:#2\endcsname}
+
+\def\presetMPvariable
+ {\dodoubleargument\dopresetMPvariable}
+
+\def\dopresetMPvariable[#1][#2=#3]%
+ {\doifundefined{#1:#2}{\setvalue{#1:#2}{#3}}}
+
+\def\useMPvariables
+ {\dodoubleargument\douseMPvariables}
+
+\def\douseMPvariables[#1][#2]%
+ {\def\@@meta{#1:}%
+ \prepareMPvariables{#2}}
+
+%D \macros
+%D {startuniqueMPgraphic, uniqueMPgraphic}
+%D
+%D This macros is probably of most use to myself, since I like
+%D to use graphics that adapt themselves. The next \METAPOST\
+%D kind of graphic is both unique and reused when possible.
+%D
+%D \starttyping
+%D \defineoverlay[example][\uniqueMPgraphic{test}]
+%D
+%D \startuniqueMPgraphic {test}
+%D draw unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D \stopuniqueMPgraphic
+%D \stoptyping
+
+%D For educational purposes, we show the original version
+%D first. This one used a rather simple method for determining
+%D the uniqueness.
+%D
+%D \starttyping
+%D \long\def\startuniqueMPgraphic#1#2\stopuniqueMPgraphic%
+%D {\setvalue{\@@MPG#1}%
+%D {\startreusableMPgraphic{\overlaystamp:#1}#2\stopreusableMPgraphic
+%D \reuseMPgraphic{\overlaystamp:#1}}}
+%D
+%D \def\uniqueMPgraphic#1%
+%D {\getvalue{\@@MPG#1}}
+%D \stoptyping
+
+%\def\overlaystamp % watch the \MPcolor, since colors can be redefined
+% {\overlaywidth:\overlayheight:\overlaydepth
+% :\MPcolor{\overlaycolor}:\MPcolor{\overlaylinecolor}}
+
+\def\overlaystamp % watch the \MPcolor, since colors can be redefined
+ {\overlaywidth:\overlayheight:\overlaydepth
+ :\MPcolor\overlaycolor:\MPcolor\overlaylinecolor}
+
+%D A better approach is to let additional variables play a role
+%D in determining the uniqueness. In the next macro, the
+%D second, optional, argument is used to guarantee the
+%D uniqueness, as well as prepare variables for passing them to
+%D \METAPOST.
+%D
+%D \starttyping
+%D \startuniqueMPgraphic{meta:hash}{gap,angle,...}
+%D \stoptyping
+%D
+%D The calling macro also accepts a second argument. For
+%D convenient use in overlay definitions, we use \type {{}}
+%D instead of \type {[]}.
+%D
+%D \starttyping
+%D \uniqueMPgraphic{meta:hash}{gap=10pt,angle=30}
+%D \stoptyping
+
+\long\def\handleuniqueMPgraphic#1#2#3%
+ {\blabelgroup
+ \def\@@meta{#1:}%
+ \extendMPoverlaystamp{#2}% incl prepare
+ \ifundefined{\@@MPG\overlaystamp:#1}%
+ \enableincludeMPgraphics
+ \startMPgraphic#3\stopMPgraphic
+ \doifobjectssupportedelse\donothing\useMPboxfalse
+ \ifuseMPbox
+ \@EA\douseMPbox
+ \else
+ \@EA\nouseMPbox
+ \fi {\@@MPG\overlaystamp:#1}%
+ \fi
+ \getvalue{\@@MPG\overlaystamp:#1}%
+ \elabelgroup}
+
+\long\def\startuniqueMPgraphic
+ {\blabelgroup
+ \dodoublegroupempty\dostartuniqueMPgraphic}
+
+\long\def\dostartuniqueMPgraphic
+ {\obeyMPlines
+ \dodostartuniqueMPgraphic}
+
+\long\def\dodostartuniqueMPgraphic#1#2#3\stopuniqueMPgraphic%
+ {\long\setgvalue{\@@MPG#1}{\handleuniqueMPgraphic{#1}{#2}{#3}}%
+ \elabelgroup}
+
+\unexpanded\def\uniqueMPgraphic
+ {\dodoublegroupempty\douniqueMPgraphic}
+
+\def\douniqueMPgraphic#1#2%
+ {\blabelgroup
+ \setupMPvariables[#1][#2]%
+ \getvalue{\@@MPG#1}{}%
+ \elabelgroup}
+
+\let\stopuniqueMPcode \relax % so that we can use it in \expanded
+
+\def\includeMPgraphic#1%
+ {\executeifdefined{\@@MPG#1};} % ; if not found
+
+\long\def\handleuseMPgraphic#1#2#3%
+ {\blabelgroup
+ \def\@@meta{#1:}%
+ \prepareMPvariables{#2}%
+ \enableincludeMPgraphics
+ \startMPgraphic#3\stopMPgraphic
+ \ifMPrun \else % see mfun-004 : processing buffer
+ \loadMPgraphic{\MPgraphicfile.\the\currentMPgraphic}{}%
+ \placeMPgraphic
+ \fi
+ \deallocateMPslot\currentMPgraphic
+ \elabelgroup}
+
+\long\def\startuseMPgraphic
+ {\blabelgroup
+ \dodoublegroupempty\dostartuseMPgraphic}
+
+\long\def\dostartuseMPgraphic
+ {\obeyMPlines
+ \dodostartuseMPgraphic}
+
+\long\def\dodostartuseMPgraphic#1#2#3\stopuseMPgraphic
+ {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}%
+ \elabelgroup}
+
+\long\def\startusableMPgraphic % redundant but handy
+ {\blabelgroup
+ \dodoublegroupempty\dostartusableMPgraphic}
+
+\long\def\dostartusableMPgraphic % redundant but handy
+ {\obeyMPlines
+ \dodostartusableMPgraphic}
+
+\long\def\dodostartusableMPgraphic#1#2#3\stopusableMPgraphic
+ {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}%
+ \elabelgroup}
+
+\long\def\handlereusableMPgraphic#1#2#3%
+ {\blabelgroup
+ \def\@@meta{#1:}%
+ \prepareMPvariables{#2}%
+ \enableincludeMPgraphics
+ \startMPgraphic#3\stopMPgraphic
+ \doifobjectssupportedelse\donothing\useMPboxfalse
+ \ifuseMPbox
+ \@EA\douseMPbox
+ \else
+ \@EA\nouseMPbox
+ \fi {\@@MPG#1}%
+ \getvalue{\@@MPG#1}%
+ \elabelgroup}
+
+\long\def\startreusableMPgraphic
+ {\blabelgroup
+ \dodoublegroupempty\dostartreusableMPgraphic}
+
+\def\dostartreusableMPgraphic
+ {\obeyMPlines
+ \dodostartreusableMPgraphic}
+
+\long\def\dodostartreusableMPgraphic#1#2#3\stopreusableMPgraphic
+ {\long\setgvalue{\@@MPG#1}{\handlereusableMPgraphic{#1}{#2}{#3}}%
+ \elabelgroup}
+
+\unexpanded\def\useMPgraphic
+ {\dodoublegroupempty\douseMPgraphic}
+
+\def\douseMPgraphic#1#2%
+ {\blabelgroup
+ \setupMPvariables[#1][#2]%
+ \getvalue{\@@MPG#1}{}%
+ \elabelgroup}
+
+\let\reuseMPgraphic\useMPgraphic
+
+\let\stopuseMPcode \relax % so that we can use it in \expanded
+\let\stopusableMPcode \relax % so that we can use it in \expanded
+\let\stopreusableMPcode \relax % so that we can use it in \expanded
+\let\stopuniqueMPcode \relax % so that we can use it in \expanded
+
+\def\enableincludeMPgraphics
+ {\let\handleuseMPgraphic \thirdofthreearguments
+ \let\handlereusableMPgraphic\thirdofthreearguments}
+
+% todo: each code/page/buffer a var class
+
+%D \macros
+%D {startuniqueMPpagegraphic,uniqueMPpagegraphic}
+%D
+%D Experimental.
+
+\def\MPpageprefix{\doifoddpageelse oe:}
+
+\def\overlaypagestamp
+ {\MPpageprefix\overlaywidth:\overlayheight:\overlaydepth
+ :\MPcolor\overlaycolor:\MPcolor\overlaylinecolor}
+
+\long\def\startuniqueMPpagegraphic
+ {\blabelgroup
+ \dodoublegroupempty\dostartuniqueMPpagegraphic}
+
+\long\def\dostartuniqueMPpagegraphic
+ {\obeyMPlines
+ \dodostartuniqueMPpagegraphic}
+
+\long\def\dodostartuniqueMPpagegraphic#1#2#3\stopuniqueMPpagegraphic
+ {\long\setgvalue{\@@MPG o:#1}{\handleuniqueMPgraphic{o:#1}{#2}{#3}}%
+ \long\setgvalue{\@@MPG e:#1}{\handleuniqueMPgraphic{e:#1}{#2}{#3}}%
+ \elabelgroup}
+
+\unexpanded\def\uniqueMPpagegraphic
+ {\dodoublegroupempty\douniqueMPpagegraphic}
+
+% \def\douniqueMPpagegraphic#1#2%
+% {\blabelgroup
+% \let\overlaystamp\overlaypagestamp
+% \setupMPvariables[#1][#2]%
+% \getvalue{\@@MPG\MPpageprefix#1}{}%
+% \elabelgroup}
+
+\def\douniqueMPpagegraphic#1#2%
+ {\blabelgroup
+ \let\overlaystamp\overlaypagestamp
+ \setupMPvariables[\MPpageprefix#1][#2]% prefix is new here
+ \getvalue{\@@MPG\MPpageprefix#1}{}%
+ \elabelgroup}
+
+%D One way of defining a stamp is:
+%D
+%D \starttyping
+%D \def\extendMPoverlaystamp#1%
+%D {\def\docommand##1%
+%D {\edef\overlaystamp{\overlaystamp:\MPvariable{##1}}}%
+%D \processcommalist[#1]\docommand}
+%D \stoptyping
+
+%D Since we need to feed \METAPOST\ with expanded dimensions,
+%D we introduce a dedicated expansion engine.
+
+\def\prepareMPvariable#1%
+ {\ifundefined{\@@framed\@@meta#1}%
+ \doprepareMPvariable{\@@meta#1}%
+ \else
+ \doprepareMPvariable{\@@framed\@@meta#1}%
+ \fi}
+
+% \startlines
+% \def\xxx{\lineheight} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{2pt} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{2} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{\scratchcounter} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{red} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{0.4} \doprepareMPvariable{xxx} \xxx
+% \stoplines
+
+\def\doprepareMPvariable#1%
+ {\edef\theMPvariable{\getvalue{#1}}%
+ \doifelsenothing\theMPvariable
+ {\setevalue{#1}{\MPcolor{black}}}
+ {\defconvertedcommand\ascii\theMPvariable % otherwise problems
+ \doifcolorelse \ascii % with 2\bodyfontsize
+ {\setevalue{#1}{\MPcolor\theMPvariable}}
+ {% can be aux macro
+ \setbox\scratchbox\hbox{\scratchdimen\theMPvariable sp}%
+ \ifdim\wd\scratchbox=\zeropoint
+ % \scratchcounter\theMPvariable
+ % \setevalue{#1}{\the\scratchcounter}%
+ % also accepts 0.number :
+ \setevalue{#1}{\number\theMPvariable}%
+ \else
+ \scratchdimen\theMPvariable
+ \setevalue{#1}{\the\scratchdimen}%
+ \fi}}}
+
+%D We redefine \type {\extendMPoverlaystamp} to preprocess
+%D variables using \type {\prepareMPvariable}.
+
+\def\doextendMPoverlaystamp#1%
+ {\prepareMPvariable{#1}%
+ \edef\overlaystamp{\overlaystamp:\MPvariable{#1}}}
+
+\def\extendMPoverlaystamp#1%
+ {\processcommalist[#1]\doextendMPoverlaystamp}
+
+\def\prepareMPvariables#1%
+ {\processcommalist[#1]\prepareMPvariable}
+
+%D \macros
+%D {MPdatafile}
+%D
+%D We redefine a macro from \type {supp-mps.tex}:
+
+\def\MPdatafile
+ {\bufferprefix mpd-\the\currentMPgraphic.mpd}
+
+%D \macros
+%D {MPrunfile}
+%D
+%D This one is more abstract and does not assume knowledge
+%D of buffer prefixes.
+
+\def\MPrunfile#1%
+ {\bufferprefix mprun.#1}
+
+%D \macros
+%D {getMPdata}
+%D
+%D When we collect graphics in one file, we run into
+%D troubles, since \METAPOST\ has a built in limit (of 4)
+%D on the number of files it can handle. It's therefore
+%D better to collect all data in one file and filter it.
+
+\def\MPdataMPDfile{\jobname-mpgraph.mpd}
+\def\MPdataMPOfile{\jobname-mpgraph.mpo}
+\def\MPdataMPYfile{\jobname-mpgraph.mpy}
+
+\startMPextensions
+ boolean collapse_data; collapse_data:=true;
+ def data_mpd_file = "\MPdataMPDfile" enddef ;
+ def data_mpo_file = "\MPdataMPOfile" enddef ;
+ def data_mpy_file = "\MPdataMPYfile" enddef ;
+\stopMPextensions
+
+\def\getMPdata
+ {\long\def\MPdata##1##2{\ifnum##1=\currentMPgraphic\relax##2\fi}%
+ \startreadingfile
+ % \startnointerference % no, else we need to do all data global
+ \readlocfile\MPdataMPDfile\donothing\donothing
+ % \stopnointerference
+ \stopreadingfile}
+
+%D We have to enable this mechanism with:
+
+\startMPextensions
+\stopMPextensions
+
+%D For the moment, the next one is a private macro:
+
+\def\processMPbuffer
+ {\dosingleempty\doprocessMPbuffer}
+
+\def\doprocessMPbuffer[#1]%
+ {\doifelsenothing{#1}
+ {\doprocessMPbuffer[\jobname]}
+ {\bgroup
+ \setnormalcatcodes
+ \obeyMPlines
+ %\let\par\empty % oeps, this makes dvi mode graphics hang when not found
+ \!!toksa\emptytoks
+ \def\copyMPbufferline{\expandafter\appendtoks\fileline\to\!!toksa}%
+ \def\dodoprocessMPbuffer##1%
+ {\doprocessfile\scratchread{\TEXbufferfile{##1}}\copyMPbufferline}%
+ \processcommalist[#1]\dodoprocessMPbuffer
+ \@EA\startMPcode\the\!!toksa\stopMPcode % more efficient
+ \egroup}}
+
+\def\runMPbuffer
+ {\dosingleempty\dorunMPbuffer}
+
+\def\dorunMPbuffer[#1]% processing only
+ {{\MPruntrue\doprocessMPbuffer[#1]}}
+
+%D \macros
+%D {startMPenvironment, resetMPenvironment}
+%D
+%D In order to synchronize the main \TEX\ run and the runs
+%D local to \METAPOST, environments can be passed.
+
+\ifx\everyMPTEXgraphic\undefined
+ \newtoks\everyMPTEXgraphic
+\fi
+
+%D A more general way of passing environments is:
+
+\def\startMPenvironment % second arg gobbles spaces, so that reset gives \emptytoks
+ {\bgroup
+ \catcode`\^^M=\@@space
+ \dodoubleempty\dostartMPenvironment}
+
+\long\def\dostartMPenvironment[#1][#2]#3\stopMPenvironment
+ {\egroup
+ \doif{#1}\s!reset\resetMPenvironment % reset mp toks
+ \doif{#1}\v!global{#3}% % use in main doc too
+ \doif{#1}+{#3}% % use in main doc too
+ \defconvertedargument\ascii{#3}%
+ \expandafter\appendtoks\ascii\to\everyMPTEXgraphic}
+
+\def\resetMPenvironment
+ {\everyMPTEXgraphic\emptytoks % = is really needed !
+ \startMPenvironment
+ \global\loadfontfileoncetrue
+ \stopMPenvironment}
+
+\resetMPenvironment
+
+\def\useMPenvironmentbuffer[#1]%
+ {\expanded{\startMPenvironment\noexpand\readfile{\TEXbufferfile{\jobname}}{}{}}\stopMPenvironment}
+
+% \useMPenvironmentbuffer[mp] % what was this?
+
+%D This command takes \type {[reset]} as optional
+%D argument.
+%D
+%D \starttyping
+%D \startMPenvironment
+%D \setupbodyfont[pos,14.4pt]
+%D \stopMPenvironment
+%D
+%D \startMPcode
+%D draw btex \sl Hans Hagen etex scaled 5 ;
+%D \stopMPcode
+%D \stoptyping
+%D
+%D The \type {\resetMPenvironment} is a quick way to erase
+%D the token list.
+%D
+%D You should be aware of independencies. For instance, if you use a font
+%D in a graphic that is not used in the main document, you need to load the
+%D typescript at the outer level (either directly or by using the global
+%D option).
+%D
+%D \starttyping
+%D \usetypescript[palatino][texnansi]
+%D
+%D \startMPenvironment
+%D \usetypescript[palatino][texnansi]
+%D \enableregime[utf]
+%D \setupbodyfont[palatino]
+%D \stopMPenvironment
+%D
+%D \startMPpage
+%D draw btex aap‒noot coördinatie – één etex ;
+%D \stopMPpage
+%D \stoptyping
+
+%D We don't want spurious files, do we?
+
+%\def\initializeMPgraphics
+% {%\ifx\bufferprefix\empty \else
+% \immediate\openout\MPwrite\MPgraphicfile.mp
+% \immediate\write\MPwrite{end.}%
+% \immediate\closeout\MPwrite
+% }%\fi}
+
+% strange :
+
+% \def\initializeMPgraphicfile
+% {\bgroup
+% \doinitializeMPgraphicfile
+% \MPruntrue
+% \doinitializeMPgraphicfile
+% \egroup}
+
+% \def\doinitializeMPgraphicfile
+% {\immediate\openout\scratchwrite\MPgraphicfile.mp
+% \immediate\write\scratchwrite{end.}%
+% \immediate\closeout\scratchwrite}
+
+\def\initializeMPgraphicfile
+ {\immediate\openout\scratchwrite\MPgraphicfile.mp
+ \immediate\write\scratchwrite{end.}%
+ \immediate\closeout\scratchwrite}
+
+\def\initializeMPgraphics
+ {\bgroup
+ \initializeMPgraphicfile
+ \ifx\bufferprefix\empty\else
+ \let\bufferprefix\empty
+ \initializeMPgraphicfile
+ \fi
+ \egroup}
+
+%D Loading specific \METAPOST\ related definitions is
+%D accomplished by:
+
+\def\douseMPlibrary#1%
+ {\ifundefined{\c!file\f!metapostprefix#1}%
+ \letvalueempty{\c!file\f!metapostprefix#1}%
+ \makeshortfilename[\truefilename{\f!metapostprefix#1}]%
+ \startreadingfile
+ \readsysfile\shortfilename{\showmessage\m!metapost1{#1}}\donothing
+ \stopreadingfile
+ \fi}
+
+\def\useMPlibrary[#1]%
+ {\processcommalist[#1]\douseMPlibrary}
+
+%D \macros
+%D {setMPtext, MPtext, MPstring, MPbetex}
+%D
+%D To be documented:
+%D
+%D \starttyping
+%D \setMPtext{identifier}{text}
+%D
+%D \MPtext {identifier}
+%D \MPstring{identifier}
+%D \MPbetex {identifier}
+%D \stoptyping
+
+\def\@@MPT{@MPT@}
+
+\def\forceMPTEXgraphic
+ {\long\def\checkMPTEXgraphic##1{\global\MPTEXgraphictrue}}
+
+\def\setMPtext#1#2% todo : #1 must be made : safe
+ {%\forceMPTEXgraphic
+ \defconvertedargument\ascii{#2}%
+ \dodoglobal\letvalue{\@@MPT#1}\ascii}
+
+% \def\MPtext #1{\getvalue{\@@MPT#1}}
+% \def\MPstring #1{"\getvalue{\@@MPT#1}"}
+% \def\MPbetex #1{btex \getvalue{\@@MPT#1} etex}
+
+\def\MPtext #1{\executeifdefined{\@@MPT#1}\empty}
+\def\MPstring #1{"\executeifdefined{\@@MPT#1}\empty"}
+\def\MPbetex #1{btex \executeifdefined{\@@MPT#1}\empty\space etex}
+
+%D Unfortunately \METAPOST\ does not have \CMYK\ support
+%D built in, but by means of specials we can supply the
+%D information needed to handle them naturaly.
+
+\newif\ifMPcmykcolors \MPcmykcolorstrue
+\newif\ifMPspotcolors \MPspotcolorstrue
+
+\startMPinitializations
+ cmykcolors:=\ifMPcmykcolors true\else false\fi;
+ spotcolors:=\ifMPspotcolors true\else false\fi;
+\stopMPinitializations
+
+%D In order to communicate conveniently with the \TEX\
+%D engine, we introduce some typesetting variables.
+
+% todo : backgroundoffsets
+
+\startMPextensions
+ color OverlayColor,OverlayLineColor;
+\stopMPextensions
+
+\startMPinitializations
+ OverlayWidth:=\overlaywidth;
+ OverlayHeight:=\overlayheight;
+ OverlayDepth:=\overlayheight;
+ OverlayColor:=\MPcolor{\overlaycolor};
+ OverlayLineWidth:=\overlaylinewidth;
+ OverlayLineColor:=\MPcolor{\overlaylinecolor};
+ %
+ BaseLineSkip:=\the\baselineskip;
+ LineHeight:=\the\baselineskip;
+ BodyFontSize:=\the\bodyfontsize;
+ %
+ TopSkip:=\the\topskip;
+ StrutHeight:=\strutheight;
+ StrutDepth:=\strutdepth;
+ %
+ CurrentWidth:=\the\hsize;
+ CurrentHeight:=\the\vsize;
+ %
+ EmWidth:=\the\emwidth;
+ ExHeight:=\the\exheight;
+ %
+ PageNumber:=\the\pageno;
+ RealPageNumber:=\the\realpageno;
+ LastPageNumber:= \lastpage;
+\stopMPinitializations
+
+\appendtoks
+ \disablediscretionaries
+ \disablecompoundcharacters
+\to\everyMPgraphic
+
+% New, experimental (if complaints than only in enco-ffr.mkii), well
+% Mojca complained that it does not work with utf-8 and textext, see
+% ** in meta-tex.
+
+\appendtoks
+ \chardef\activecharactermode\zerocount
+\to\everyMPgraphic
+
+\appendtoks
+ \expanded{\definecolor[currentcolor][\currentcolorname]}%
+\to \everyMPgraphic
+
+\appendtoks
+ \baselineskip1\baselineskip
+ \lineheight 1\lineheight
+ \topskip 1\topskip
+\to \everyMPgraphic
+
+%D Alas, the prologue settings differ per driver.
+
+\ifx\undefined\MPprologues \def\MPprologues{0} \fi
+
+\startMPinitializations
+ prologues:=\MPprologues;
+ mpprocset:=1;
+\stopMPinitializations
+
+\appendtoks
+ \def\MPprologues{0}%
+ \def\MPOSTdriver{dvips}%
+\to \everyresetspecials
+
+%D \macros
+%D {PDFMPformoffset}
+%D
+%D In \PDF, forms are clipped and therefore we have to take
+%D precautions to get this right. Since this is related to
+%D objects, we use the same offset as used there.
+
+\def\PDFMPformoffset{\objectoffset}
+
+%D \macros
+%D {insertMPfile}
+%D
+%D Bypassing the special driver and figure mechanism is not
+%D that nice but saves upto 5\% time in embedding \METAPOST\
+%D graphics by using the low level \PDF\ converter directly,
+%D given of course that we use \PDFTEX. As a result we need to
+%D fool around with the object trigger.
+
+\newtoks\everyinsertMPfile
+
+%D First we present the reasonable fast alternative that we
+%D happily used for some time.
+%D
+%D \starttyping
+%D \def\insertMPfile#1#2%
+%D {\ifx\undefined\externalfigure
+%D \message{[insert file #1 here]}%
+%D \else
+%D \bgroup
+%D \the\everyinsertMPfile
+%D \externalfigure
+%D [#1]
+%D [\c!type=\c!mps,\c!object=\v!no,%
+%D \c!symbol=\v!yes,\c!reset=\v!yes,%
+%D \c!maxwidth=,\c!maxheight=,%
+%D \c!frame=\v!off,\c!background=,%
+%D #2]%
+%D \egroup
+%D \fi}
+%D \stoptyping
+%D
+%D However, on a 1 Gig Pentium, the next alternative saves
+%D us 20 seconds run time for the 300 page \METAFUN\ manual:
+
+\let\insertMPfileARG\insertMPfile
+
+\def\insertMPfile#1#2% in context #2 is empty
+ {\doifelsenothing{#2}{\doinsertMPfile{#1}}{\insertMPfileARG{#1}{#2}}}
+
+\def\includeMPasEPS#1% untested !!
+ {\bgroup
+ \message{[MP as EPS #1]}%
+ \the\everyinsertMPfile
+ \dogetEPSboundingbox{#1}\!!widtha\!!heighta\!!widthb\!!heightb
+ \setbox\scratchbox\vbox to \!!heightb
+ {\vfill
+ \let \@@DriverImageType \c!mps
+ \def \@@DriverImageFile {#1}%
+ \edef\@@DriverImageWidth {\the\!!widthb }%
+ \edef\@@DriverImageHeight{\the\!!heightb}%
+ \doinsertfile}%
+ \wd\scratchbox\!!widthb
+ \dp\scratchbox\zeropoint
+ \box\scratchbox
+ \egroup}
+
+\def\includeMPasPDF#1%
+ {\bgroup
+ \the\everyinsertMPfile
+ \ifinobject \else \chardef\makeMPintoPDFobject\plustwo \fi % when needed
+ \convertMPtoPDF{#1}{1}{1}% no \plusone !
+ \egroup}
+
+%D So, using a low level approach (thereby avoiding the slower
+%D figure analysis macros) pays off. This kind of
+%D optimizations are a bit tricky since we must make sure that
+%D special resources end up in the (PDF) files. Because the
+%D \METAPOST\ to \PDF\ can handle objects itself, it is not
+%D that complicated.
+
+%D We hook a couple of initializations into the graphic
+%D macros.
+
+\appendtoks
+ \let\figuretypes\c!mps
+ \runutilityfilefalse
+ \consultutilityfilefalse
+\to \everyinsertMPfile
+
+%D One more: (still needed?)
+
+\startMPextensions
+ def initialize_form_numbers =
+ do_initialize_numbers;
+ enddef;
+\stopMPextensions
+
+\startMPinitializations
+ HSize:=\the\hsize ;
+ VSize:=\the\vsize ;
+\stopMPinitializations
+
+\startMPextensions
+ vardef ForegroundBox =
+ unitsquare xysized(HSize,VSize)
+ enddef ;
+ vardef PageFraction =
+ if \lastpage>1: (\realfolio-1)/(\lastpage-1) else: 1 fi
+ enddef ;
+\stopMPextensions
+
+%D And some more. These are not really needed since we
+%D don't use the normal figure inclusion macros any longer.
+
+\appendtoks
+ \externalfigurepostprocessors\emptytoks % safeguard
+\to \everyinsertMPfile
+
+%D We also take care of disabling fancy figure features, that
+%D can terribly interfere when dealing with symbols,
+%D background graphics and running (postponed) graphics.
+%D You won't believe me if I tell you what funny side effects
+%D can occur. One took me over a day to uncover when
+%D processing the screen version of the \METAFUN\ manual.
+
+%D For my eyes only:
+
+\def\doifelseMPgraphic#1{\doifdefinedelse{\@@MPG#1}}
+
+%D \macros
+%D {startMPcolor}
+%D
+%D The following time consuming method uses \METAPOST\ to
+%D calculate a color. This enables a match between colors
+%D resulting from a complex calculation (e.g. for a title
+%D page) and those in the text.
+
+% \startuseMPgraphic{somecolors}
+% color c[] ; c[1] := .7[red,green] ; c[2] := .7[blue,yellow] ;
+% \stopuseMPgraphic
+
+% \startMPcolor[shade-1][t=.2,a=1]
+% \includeMPgraphic{somecolors} ; fill fullcircle withcolor c[1] ;
+% \stopMPcolor
+
+% \startMPcolor[shade-2][t=.2,a=1]
+% \includeMPgraphic{somecolors} ; fill fullcircle withcolor c[2] ;
+% \stopMPcolor
+
+% \blackrule[width=\hsize,height=4cm,color=shade-1]
+% \blackrule[width=\hsize,height=4cm,color=shade-2]
+
+\def\startMPcolor
+ {\dodoubleempty\dostartMPcolor}
+
+\long\def\dostartMPcolor[#1][#2]#3\stopMPcolor % slow but sometimes handy
+ {\startnointerference
+ \def\handleMPgraycolor{\expanded{\defineglobalcolor[#1][s=\!MPgMPa1,#2]}}%
+ \def\handleMPrgbcolor {\expanded{\defineglobalcolor[#1][r=\!MPgMPa1,g=\!MPgMPa2,b=\!MPgMPa3,#2]}}%
+ \def\handleMPcmykcolor{\expanded{\defineglobalcolor[#1][c=\!MPgMPa1,m=\!MPgMPa2,y=\!MPgMPa3,k=\!MPgMPa4,#2]}}%
+ \startMPcode#3\stopMPcode
+ \stopnointerference}
+
+%D New:
+
+\definelayerpreset % no dx,dy - else nasty non-mp placement
+ [mp]
+ [\c!y=-\MPury bp,
+ \c!x=\MPllx bp,
+ \c!method=\v!fit]
+
+\definelayer
+ [mp]
+ [\c!preset=mp]
+
+%D Usage:
+%D
+%D \starttyping
+%D \defineproperty[one][layer][state=start]
+%D \defineproperty[two][layer][state=stop]
+%D
+%D \startuseMPgraphic{step-1}
+%D fill fullcircle scaled 10cm withcolor red ;
+%D \stopuseMPgraphic
+%D
+%D \startuseMPgraphic{step-2}
+%D fill fullcircle scaled 5cm withcolor green ;
+%D \stopuseMPgraphic
+%D
+%D \setlayer[mp]{\property[one]{\useMPgraphic{step-1}}}
+%D \setlayer[mp]{\property[two]{\useMPgraphic{step-2}}}
+%D
+%D \ruledhbox{\flushlayer[mp]}
+%D \stoptyping
+%D
+%D Reusing graphics is also possible (now):
+%D
+%D \starttyping
+%D \startreusableMPgraphic{axis}
+%D tickstep := 1cm ; ticklength := 2mm ;
+%D drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ;
+%D tickstep := tickstep/2 ; ticklength := ticklength/2 ;
+%D drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ;
+%D \stopreusableMPgraphic
+%D
+%D \startuseMPgraphic{demo}
+%D drawpoint "1cm,1.5cm" ;
+%D \stopuseMPgraphic
+%D
+%D \definelayer[mp][preset=mp]
+%D \setlayer[mp]{\reuseMPgraphic{axis}}
+%D \setlayer[mp]{\useMPgraphic{demo}}
+%D \ruledhbox{\flushlayer[mp]}
+%D \stoptyping
+
+%D \macros
+%D {startstaticMPfigure,useMPstaticfigure}
+%D
+%D Static figures are processed only when there has been
+%D something changed. Here is Aditya Mahajan's testcase:
+%D
+%D \startbuffer
+%D \startstaticMPfigure{circle}
+%D fill fullcircle scaled 1cm withcolor blue;
+%D \stopstaticMPfigure
+%D
+%D \startstaticMPfigure{axis}
+%D drawarrow (0,0)--(2cm,0) ;
+%D drawarrow (0,0)--(0,2cm) ;
+%D label.llft(textext("(0,0)") ,origin) ;
+%D \stopstaticMPfigure
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\usestaticMPfigure[#1]%
+ {\dodoubleempty\externalfigure[\jobname-#1.pdf]}
+
+\def\startstaticMPfigure
+ {\begingroup
+ \obeyMPlines
+ \dostartstaticMPfigure}
+
+\def\dostartstaticMPfigure#1#2\stopstaticMPfigure
+ {\startstaticMPgraphic{\jobname-#1}#2\stopstaticMPgraphic
+ \endgroup}
+
+% faster, but more tricky
+%
+% \def\startstaticMPfigure
+% {\doifmodeelse{*\v!first}
+% {\begingroup
+% \obeyMPlines
+% \dostartstaticMPfigure}
+% {\gobbleuntil\stopstaticMPfigure}}
+%
+% \def\dostartstaticMPfigure#1#2\stopstaticMPfigure
+% {\startMPstaticgraphic{\jobname-#1}#2\stopMPstaticgraphic
+% % dirty trick, don't register, so no second main run of texexec:
+% \global\advance\nofMPgraphics \minusone
+% \endgroup}}
+
+%D New:
+
+% \appendtoks \closeMPgraphicfiles \to \everystoptext
+
+%D New:
+
+\newconditional\manyMPspecials % when set to true, > 1000 specials can be used
+
+\settrue \manyMPspecials % per 1/4/2006
+
+\prependtoks
+ _special_div_ := 1000\ifconditional\manyMPspecials0\fi ;
+\to \MPextensions
+
+%D Needed (will become default):
+
+\prependtoks
+ \resetlanguagespecifics
+\to \everyMPgraphic
+
+%D Goody for preventing overflows:
+
+\def\MPdivten[#1]{\withoutpt\the\dimexpr#1pt/10\relax}
+
+%D Done.
+
+\protect \endinput
+
+%D Experimental:
+
+\appendtoks
+ \ifrunMPgraphics \ifcase\systemcommandmode \or
+ \runMPgraphicsfalse
+ \fi \fi
+\to \everyjob
+
+% also:
+%
+% linecap := rounded ;
+% linejoin := rounded ;
+% drawoptions () ;
diff --git a/tex/context/base/meta-ini.mkiv b/tex/context/base/meta-ini.mkiv
new file mode 100644
index 000000000..61acbca32
--- /dev/null
+++ b/tex/context/base/meta-ini.mkiv
@@ -0,0 +1,1275 @@
+%D \module
+%D [ file=meta-ini,
+%D version=2008.03.25,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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}{MetaPost Graphics / Initializations}
+
+\unprotect
+
+%D Instead of sharing code with \MKII, I decided to copy
+%D the code. Otherwise maintainance becomes a pain and after all,
+%D the \MKII\ code will not change.
+
+\let \useMETAFUNformattrue\relax \let \useMETAFUNformatfalse\relax
+\let \longMPlinestrue\relax \let \longMPlinesfalse\relax
+\let \runMPgraphicstrue\relax \let \runMPgraphicsfalse\relax
+\let \runMPTEXgraphicstrue\relax \let \runMPTEXgraphicsfalse\relax
+\let \MPstaticgraphictrue\relax \let \MPstaticgraphicfalse\relax
+\let\forceMPTEXgraphictrue\relax \let\forceMPTEXgraphicfalse\relax
+
+\let \obeyMPlines\relax
+\let \forceMPTEXcheck\gobbleoneargument
+\let\maxnofMPgraphics\scratchcounter
+
+\newtoks \MPextensions % mp, once
+\newtoks \MPinitializations % tex, each
+\newtoks \MPuserinclusions % mp, user
+\newtoks \MPfinalizations % mp, user
+\newtoks \everyMPgraphic % mp
+\newtoks \everyMPTEXgraphic % tex
+
+\newif\ifMPrun
+\def\MPruntimefile{mprun}
+
+% The next command is, of course, dedicated to Mojca, who
+% needs it for gnuplot. Anyway, the whole multiple engine
+% mechanism is to keep her gnuplot from interfering.
+
+\def\startMPdefinitions
+ {\dosinglegroupempty\dostartMPdefinitions}
+
+\long\def\dostartMPdefinitions#1#2\stopMPdefinitions
+ {\edef\currentMPgraphicinstance{#1}%
+ \ifx\currentMPgraphicinstance\empty
+ \let\currentMPgraphicinstance\defaultMPgraphicinstance
+ \fi
+ \global\MPinstancetoks\expandafter{\the\MPinstancetoks#2}}
+
+\long\def\startMPextensions#1\stopMPextensions
+ {\global\MPextensions\expandafter{\the\MPextensions#1}}
+
+\long\def\startMPinitializations#1\stopMPinitializations
+ {\global\MPinitializations\expandafter{\the\MPinitializations#1}}
+
+\long\def\startMPinclusions
+ {\dosingleempty\dostartMPinclusions}
+
+\long\def\dostartMPinclusions[#1]#2\stopMPinclusions
+ {\doifnot{#1}{+}{\global\MPuserinclusions\emptytoks}%
+ \global\MPuserinclusions\expandafter{\the\MPuserinclusions#2}}
+
+\def\MPinclusions
+ {\dosingleempty\doMPinclusions}
+
+\long\def\doMPinclusions[#1]#2%
+ {\doifnot{#1}{+}{\global\MPuserinclusions\emptytoks}%
+ \global\MPuserinclusions\expandafter{\the\MPuserinclusions#2}}
+
+\def\presetMPdefinitions
+ {\edef\overlaywidth {\overlaywidth \space}%
+ \edef\overlayheight {\overlayheight \space}%
+ \edef\overlaylinewidth{\overlaylinewidth\space}%
+ \edef\currentwidth {\the\hsize \space}%
+ \edef\currentheight {\the\vsize \space}}
+
+\def\currentMPformat{metafun}
+
+\def\@@MPF{@MPF@}
+
+\def\MPinstancetoks{\csname\@@MPF::\currentMPgraphicinstance\endcsname}
+
+\unexpanded\def\defineMPinstance
+ {\dodoubleargument\dodefineMPinstance}
+
+\def\dodefineMPinstance[#1][#2]%
+ {\ifcsname\@@MPF::#1\endcsname\else\expandafter\newtoks\csname\@@MPF::#1\endcsname\fi
+ \MPinstancetoks\emptytoks % in case we redefine
+ \getparameters[\@@MPF#1][\s!format=mpost,\s!extensions=\v!no,\s!initializations=\v!no,#2]}
+
+\def\resetMPinstance[#1]%
+ {\writestatus\m!metapost{reset will be implemented when needed}}
+
+\def\defaultMPgraphicinstance{metafun}
+
+\def\splitMPgraphicname[#1]%
+ {\dosplitMPgraphicname[#1::::]}
+
+\def\dosplitMPgraphicname[#1::#2::#3]% instance ::
+ {\edef\currentMPgraphicname{#2}%
+ \ifx\currentMPgraphicname\empty
+ \edef\currentMPgraphicname{#1}%
+ \let\currentMPgraphicinstance\defaultMPgraphicinstance
+ \else
+ \edef\currentMPgraphicinstance{#1}%
+ \fi
+ \edef\currentMPgraphicformat
+ {\ifcsname\@@MPF\currentMPgraphicinstance\s!format\endcsname
+ \csname\@@MPF\currentMPgraphicinstance\s!format\endcsname
+ \else
+ \defaultMPgraphicinstance
+ \fi}}
+
+\def\currentMPgraphicinstance{\defaultMPgraphicinstance}
+\def\currentMPgraphicformat {\currentMPgraphicinstance}
+
+\defineMPinstance[metafun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[extrafun][\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[mprun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[metapost][\s!format=mpost]
+\defineMPinstance[nofun] [\s!format=mpost]
+
+\def\beginMPgraphicgroup#1%
+ {\begingroup
+ \splitMPgraphicname[#1]}
+
+\def\endMPgraphicgroup
+ {\endgroup}
+
+\newconditional \METAFUNinitialized
+
+\def\MPaskedfigure{false}
+
+\def\currentMPinitializations
+ {\ifconditional\includeMPinitializations\the\MPinitializations;\fi\theMPrandomseed;}
+
+\def\currentMPpreamble
+ {\ifconditional\includeMPextensions\the\MPextensions;\the\MPuserinclusions;\fi\the\MPinstancetoks;}
+
+\def\dostartcurrentMPgraphic
+ {\begingroup
+ \enableincludeMPgraphics
+ \the\everyMPgraphic
+ \presetMPdefinitions
+ \setMPrandomseed % this has to change
+ % we need to preexpand the token lists
+ \doifelsevalue{\@@MPF\currentMPgraphicinstance\s!extensions}\v!yes
+ {\settrue \includeMPextensions\letgvalue{\@@MPF\currentMPgraphicinstance\s!extensions}\v!no}
+ {\setfalse\includeMPextensions}%
+ \doifelsevalue{\@@MPF\currentMPgraphicinstance\s!initializations}\v!yes
+ {\settrue \includeMPinitializations}%
+ {\setfalse\includeMPinitializations}}
+
+\def\dostopcurrentMPgraphic
+ {\global\MPinstancetoks\emptytoks
+ \global\settrue\METAFUNinitialized % becomes obsolete
+ \endgroup}
+
+\unexpanded\long\def\processMPgraphic#1% todo: extensions and inclusions outside beginfig
+ {\dostartcurrentMPgraphic
+ \forgetall
+ \setbox\MPgraphicbox\hbox\bgroup
+ \normalexpanded{\noexpand\ctxlua{metapost.graphic(
+ "\currentMPgraphicinstance",
+ "\currentMPgraphicformat",
+ \!!bs#1\!!es,
+ \!!bs\currentMPinitializations\!!es,
+ \!!bs\currentMPpreamble\!!es,
+ \MPaskedfigure
+ )}}%
+ \egroup
+ \placeMPgraphic
+ \dostopcurrentMPgraphic}
+
+\newif\ifsetMPrandomseed \setMPrandomseedtrue % false by default
+
+\def\setMPrandomseed
+ {\let\theMPrandomseed\empty
+ \ifsetMPrandomseed \ifx\getrandomnumber\undefined \else
+ \getrandomnumber\localMPseed\zerocount{4095}%
+ \def\theMPrandomseed{randomseed:=\localMPseed}%
+ \fi\fi}
+
+%D To be integrated
+
+\def\@@MPG{@MPG@}
+
+\def\doifMPgraphicelse#1%
+ {\ifcsname\@@MPG#1\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
+
+\def\includeMPgraphic#1%
+ {\executeifdefined{\@@MPG#1};} % ; if not found
+
+\def\enableincludeMPgraphics
+ {\let\handleuseMPgraphic \thirdofthreearguments
+ \let\handlereusableMPgraphic\thirdofthreearguments}
+
+\let\MPdrawingdata\empty
+
+\newif\ifMPdrawingdone \MPdrawingdonefalse
+
+\def\resetMPdrawing
+ {\globallet\MPdrawingdata\empty
+ \global\MPdrawingdonefalse}
+
+\def\pushMPdrawing
+ {\globalpushmacro\MPdrawingdata
+ \globallet\MPdrawingdata\empty}
+
+\def\popMPdrawing
+ {\globalpopmacro\MPdrawingdata}
+
+\def\getMPdrawing{\dosinglegroupempty\dogetMPdrawing}
+
+\def\startMPdrawing
+ {\dosingleempty\dostartMPdrawing}
+
+\long\def\dostartMPdrawing[#1]#2\stopMPdrawing
+ {\relax
+ \bgroup
+ \enableincludeMPgraphics
+ \presetMPdefinitions % in case #2 has measures
+ \doifelse{#1}{-}{\convertargument#2\to\asciia}{\long\def\asciia{#2}}%
+ \long\xdef\MPdrawingdata{\MPdrawingdata\asciia}%
+ \egroup}
+
+\let\stopMPdrawing\relax
+
+\let\MPdrawingdata\empty
+
+\newif\ifMPshiftdrawing \MPshiftdrawingfalse
+
+\def\resetMPdrawing
+ {\globallet\MPdrawingdata\empty
+ \global\MPdrawingdonefalse}
+
+\def\pushMPdrawing
+ {\globalpushmacro\MPdrawingdata
+ \globallet\MPdrawingdata\empty}
+
+\def\popMPdrawing
+ {\globalpopmacro\MPdrawingdata}
+
+\def\getMPdrawing
+ {\ifMPdrawingdone
+ \expandafter\processMPgraphic\expandafter{\MPdrawingdata}% is this expansion still needed?
+ \fi}
+
+\def\startMPdrawing
+ {\dosingleempty\dostartMPdrawing}
+
+\long\def\dostartMPdrawing[#1]#2\stopMPdrawing
+ {\relax
+ \bgroup
+ \enableincludeMPgraphics
+ \presetMPdefinitions % in case #2 has measures
+ \doifelse{#1}{-}{\convertargument#2\to\asciia}{\long\def\asciia{#2}}%
+ \long\xdef\MPdrawingdata{\MPdrawingdata\asciia}%
+ \egroup}
+
+\let\stopMPdrawing\relax
+
+\let\stopMPclip\relax
+
+\long\def\startMPclip#1#2\stopMPclip % todo: store at the lua end or just store less
+ {\long\setgvalue{MPC:#1}{#2}}
+
+\def\grabMPclippath#1#2#3#4#5% #5 is alternative
+ {\begingroup
+ \edef\width {#3\space}\let\overlaywidth \width
+ \edef\height{#4\space}\let\overlayheight\height
+ \ifcsname MPC:#1\endcsname
+ \dostartcurrentMPgraphic
+ \xdef\MPclippath{\normalexpanded{\noexpand\ctxlua{metapost.theclippath(
+ "\currentMPgraphicinstance",
+ "\currentMPgraphicformat",
+ \!!bs\getvalue{MPC:#1}\!!es,
+ \!!bs\currentMPinitializations\!!es,
+ \!!bs\currentMPpreamble\!!es
+ )}}}%
+ \dostopcurrentMPgraphic
+ \ifx\MPclippath\empty\xdef\MPclippath{#5}\fi
+ \else
+ \xdef\MPclippath{#5}%
+ \fi
+ % #2 : method is obsolete, only pdf now, we can always
+ % gsub the result to ps
+ \endgroup}
+
+%D Next we will use these support macros.
+
+\startMPextensions
+ if unknown context_tool: input mp-tool; fi;
+ if unknown context_spec: input mp-spec; fi;
+ if unknown context_grph: input mp-grph; fi;
+\stopMPextensions
+
+%D Since we want lables to follow the document settings, we
+%D also set the font related variables.
+
+\startMPinitializations % scale is not yet ok
+ defaultfont:="\truefontname{Regular}";
+ defaultscale:=\the\bodyfontsize/10pt;
+\stopMPinitializations
+
+% watch out, this is a type1 font because mp can only handle 8 bit fonts
+
+\startMPinitializations % scale is not yet ok
+ defaultfont:="rm-lmtt10";
+\stopMPinitializations
+
+%D A signal that we're in combines \CONTEXT||\METAFUN mode:
+
+\startMPextensions
+ string contextversion;
+ contextversion:="\contextversion";
+\stopMPextensions
+
+%D Some safeguards:
+%D
+%D \starttyping
+%D \appendtoks \cleanupfeatures \to \everyMPgraphic
+%D \stoptyping
+%D
+%D No, we don't want that (else we loose UTF etc).
+
+%D Another one:
+
+\prependtoks \MPstaticgraphictrue \to \everyoverlay
+\prependtoks \MPstaticgraphictrue \to \everypagebody
+
+%D \macros
+%D {setupMPvariables}
+%D
+%D When we build collections of \METAPOST\ graphics, like
+%D background and buttons, the need for passing settings
+%D arises. By (mis|)|using the local prefix that belongs to
+%D \type {\framed}, we get a rather natural interface to
+%D backgrounds. To prevent conflicts, we will use the \type
+%D {-} in \METAPOST\ specific variables, like:
+%D
+%D \starttyping
+%D \setupMPvariables[meta:button][size=20pt]
+%D \stoptyping
+
+\def\@@meta{meta:}
+
+\unexpanded\def\setupMPvariables
+ {\dodoubleempty\dosetupMPvariables}
+
+\def\dosetupMPvariables[#1][#2]%
+ {\ifsecondargument
+ \getrawparameters[#1:][#2]% brr, todo: [\@@meta#1:]
+ \else
+ \getrawparameters[\@@meta][#1]%
+ \fi}
+
+\let\@@framed\s!unknown
+
+\def\MPvariable#1%
+ {\csname
+ \ifcsname\@@framed\@@meta#1\endcsname\@@framed\fi\@@meta#1%
+ \endcsname}
+
+\let\MPvar\MPvariable
+
+\let\setMPvariables\setupMPvariables
+
+\def\MPrawvar#1#2{\csname#1:#2\endcsname}
+
+\def\presetMPvariable
+ {\dodoubleargument\dopresetMPvariable}
+
+\def\dopresetMPvariable[#1][#2=#3]%
+ {\ifcsname#1:#2\endcsname\else\setvalue{#1:#2}{#3}\fi}
+
+\def\useMPvariables
+ {\dodoubleargument\douseMPvariables}
+
+\def\douseMPvariables[#1][#2]%
+ {\def\@@meta{#1:}%
+ \prepareMPvariables{#2}}
+
+%D \macros
+%D {startuniqueMPgraphic, uniqueMPgraphic}
+%D
+%D This macros is probably of most use to myself, since I like
+%D to use graphics that adapt themselves. The next \METAPOST\
+%D kind of graphic is both unique and reused when possible.
+%D
+%D \starttyping
+%D \defineoverlay[example][\uniqueMPgraphic{test}]
+%D
+%D \startuniqueMPgraphic {test}
+%D draw unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D \stopuniqueMPgraphic
+%D \stoptyping
+
+\def\overlaystamp % watch the \MPcolor, since colors can be redefined
+ {\overlaywidth:\overlayheight:\overlaydepth:\MPcolor\overlaycolor:\MPcolor\overlaylinecolor}
+
+%D A better approach is to let additional variables play a role
+%D in determining the uniqueness. In the next macro, the
+%D second, optional, argument is used to guarantee the
+%D uniqueness, as well as prepare variables for passing them to
+%D \METAPOST.
+%D
+%D \starttyping
+%D \startuniqueMPgraphic{meta:hash}{gap,angle,...}
+%D \stoptyping
+%D
+%D The calling macro also accepts a second argument. For
+%D convenient use in overlay definitions, we use \type {{}}
+%D instead of \type {[]}.
+%D
+%D \starttyping
+%D \uniqueMPgraphic{meta:hash}{gap=10pt,angle=30}
+%D \stoptyping
+
+\newcount\MPobjectcounter
+\newbox \MPgraphicbox
+
+\chardef\MPboxmode\zerocount
+
+\def\doobeyMPboxdepth % mode = 1
+ {\setbox\MPgraphicbox\hbox{\hskip\MPllx\onebasepoint\raise\MPlly\onebasepoint\box\MPgraphicbox}}
+
+\def\doignoreMPboxdepth % mode = 2
+ {\normalexpanded
+ {\noexpand\doobeyMPboxdepth
+ \wd\MPgraphicbox\the\wd\MPgraphicbox
+ \ht\MPgraphicbox\the\ht\MPgraphicbox
+ \dp\MPgraphicbox\the\dp\MPgraphicbox}}
+
+\def\obeyMPboxdepth {\chardef\MPboxmode\plusone}
+\def\ignoreMPboxdepth{\chardef\MPboxmode\plustwo}
+\def\normalMPboxdepth{\chardef\MPboxmode\zerocount}
+
+% compatibility hack:
+
+\let\MPshiftdrawingtrue \ignoreMPboxdepth
+\let\MPshiftdrawingfalse\normalMPboxdepth
+
+\unexpanded\def\placeMPgraphic
+ {\ifcase\MPboxmode
+ \or % 1
+ \doobeyMPboxdepth
+ \or % 2
+ \doignoreMPboxdepth
+ \fi
+ \box\MPgraphicbox}
+
+\def\reuseMPbox#1#2#3#4#5% space delimiting would save some tokens
+ {\xdef\MPllx{#2}% but it's not worth the effort and looks
+ \xdef\MPlly{#3}% ugly as well
+ \xdef\MPurx{#4}%
+ \xdef\MPury{#5}%
+ \hbox{\forcecolorhack\getobject{MP}{#1}}} % else no proper color intent
+
+\long\def\handleuniqueMPgraphic#1#2#3%
+ {\begingroup
+ \def\@@meta{#1:}%
+ \extendMPoverlaystamp{#2}% incl prepare
+ \ifcsname\@@MPG\overlaystamp:#1\endcsname\else
+ \enableincludeMPgraphics % redundant
+ \global\advance\MPobjectcounter\plusone
+ \setobject{MP}{\number\MPobjectcounter}\hbox{\processMPgraphic{#3}}% was vbox, graphic must end up as hbox
+ \setxvalue{\@@MPG\overlaystamp:#1}{\noexpand\reuseMPbox{\number\MPobjectcounter}{\MPllx}{\MPlly}{\MPurx}{\MPury}}%
+ \fi
+ \getvalue{\@@MPG\overlaystamp:#1}%
+ \endgroup}
+
+\long\unexpanded\def\startuniqueMPgraphic
+ {\dodoublegroupempty\dostartuniqueMPgraphic}
+
+\long\def\dostartuniqueMPgraphic#1#2#3\stopuniqueMPgraphic%
+ {\long\setgvalue{\@@MPG#1}{\handleuniqueMPgraphic{#1}{#2}{#3}}}
+
+\unexpanded\def\uniqueMPgraphic
+ {\dodoublegroupempty\douniqueMPgraphic}
+
+\def\douniqueMPgraphic#1#2%
+ {\beginMPgraphicgroup{#1}%
+ \setupMPvariables[\currentMPgraphicname][#2]%
+ \getvalue{\@@MPG\currentMPgraphicname}\empty
+ \endMPgraphicgroup}
+
+\let\stopuniqueMPcode \relax % so that we can use it in \expanded
+
+\long\def\handleuseMPgraphic#1#2#3%
+ {\begingroup
+ \def\@@meta{#1:}%
+ \prepareMPvariables{#2}%
+ \enableincludeMPgraphics % redundant
+ \processMPgraphic{#3}%
+ \endgroup}
+
+\long\unexpanded\def\startuseMPgraphic
+ {\dodoublegroupempty\dostartuseMPgraphic}
+
+\long\def\dostartuseMPgraphic#1#2#3\stopuseMPgraphic
+ {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}}
+
+\long\unexpanded\def\startusableMPgraphic % redundant but handy
+ {\dodoublegroupempty\dostartusableMPgraphic}
+
+\long\def\dostartusableMPgraphic#1#2#3\stopusableMPgraphic
+ {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}}
+
+\let\stopuseMPgraphic \relax % so that we can use it in \expanded
+\let\stopusableMPgraphic \relax % so that we can use it in \expanded
+
+\long\def\handlereusableMPgraphic#1#2#3%
+ {\begingroup
+ \def\@@meta{#1:}%
+ \prepareMPvariables{#2}%
+ \enableincludeMPgraphics % redundant
+ \global\advance\MPobjectcounter\plusone
+ \setobject{MP}{\number\MPobjectcounter}\hbox{\processMPgraphic{#3}}% was vbox, graphic must end up as hbox
+ \setxvalue{\@@MPG#1}{\noexpand\reuseMPbox{\number\MPobjectcounter}{\MPllx}{\MPlly}{\MPurx}{\MPury}}%
+ \getvalue{\@@MPG#1}%
+ \endgroup}
+
+\long\unexpanded\def\startreusableMPgraphic
+ {\dodoublegroupempty\dostartreusableMPgraphic}
+
+\long\def\dostartreusableMPgraphic#1#2#3\stopreusableMPgraphic
+ {\long\setgvalue{\@@MPG#1}{\handlereusableMPgraphic{#1}{#2}{#3}}}
+
+\let\stopreusableMPgraphic \relax % so that we can use it in \expanded
+
+\unexpanded\def\useMPgraphic
+ {\dodoublegroupempty\douseMPgraphic}
+
+\def\douseMPgraphic#1#2%
+ {\beginMPgraphicgroup{#1}%
+ \doifsomething{#2}{\setupMPvariables[\currentMPgraphicname][#2]}%
+ \getvalue{\@@MPG\currentMPgraphicname}\empty
+ \endMPgraphicgroup}
+
+\let\reuseMPgraphic \useMPgraphic % we can save a setup here if needed
+\let\reusableMPgraphic\reuseMPgraphic % we can save a setup here if needed
+
+\let\stopuseMPcode \relax % so that we can use it in \expanded
+\let\stopusableMPcode \relax % so that we can use it in \expanded
+\let\stopreusableMPcode \relax % so that we can use it in \expanded
+\let\stopuniqueMPcode \relax % so that we can use it in \expanded
+
+\def\enableincludeMPgraphics
+ {\let\handleuseMPgraphic \thirdofthreearguments
+ \let\handlereusableMPgraphic\thirdofthreearguments}
+
+%D \macros
+%D {startuniqueMPpagegraphic,uniqueMPpagegraphic}
+%D
+%D Experimental.
+
+\def\MPpageprefix{\doifoddpageelse oe:}
+
+\def\overlaypagestamp
+ {\MPpageprefix\overlaywidth:\overlayheight:\overlaydepth:\MPcolor\overlaycolor:\MPcolor\overlaylinecolor}
+
+\long\unexpanded\def\startuniqueMPpagegraphic
+ {\dodoublegroupempty\dostartuniqueMPpagegraphic}
+
+\long\def\dostartuniqueMPpagegraphic#1#2#3\stopuniqueMPpagegraphic
+ {\long\setgvalue{\@@MPG o:#1}{\handleuniqueMPgraphic{o:#1}{#2}{#3}}%
+ \long\setgvalue{\@@MPG e:#1}{\handleuniqueMPgraphic{e:#1}{#2}{#3}}}
+
+\unexpanded\def\uniqueMPpagegraphic
+ {\dodoublegroupempty\douniqueMPpagegraphic}
+
+\def\douniqueMPpagegraphic#1#2%
+ {\beginMPgraphicgroup{#1}%
+ \let\overlaystamp\overlaypagestamp
+ \setupMPvariables[\MPpageprefix\currentMPgraphicname][#2]% prefix is new here
+ \getvalue{\@@MPG\MPpageprefix\currentMPgraphicname}{}%
+ \endMPgraphicgroup}
+
+%D One way of defining a stamp is:
+%D
+%D \starttyping
+%D \def\extendMPoverlaystamp#1%
+%D {\def\docommand##1%
+%D {\edef\overlaystamp{\overlaystamp:\MPvariable{##1}}}%
+%D \processcommalist[#1]\docommand}
+%D \stoptyping
+
+%D Since we need to feed \METAPOST\ with expanded dimensions,
+%D we introduce a dedicated expansion engine.
+
+\def\prepareMPvariable#1%
+ {\ifcsname\@@framed\@@meta#1\endcsname
+ \doprepareMPvariable{\@@framed\@@meta#1}%
+ \else
+ \doprepareMPvariable{\@@meta#1}%
+ \fi}
+
+% \startlines
+% \def\xxx{\lineheight} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{2pt} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{2} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{\scratchcounter} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{red} \doprepareMPvariable{xxx} \xxx
+% \def\xxx{0.4} \doprepareMPvariable{xxx} \xxx
+% \stoplines
+
+\def\doprepareMPvariable#1%
+ {\edef\theMPvariable{\getvalue{#1}}%
+ \doifelsenothing\theMPvariable
+ {\setevalue{#1}{\MPcolor{black}}}
+ {\defconvertedcommand\ascii\theMPvariable % otherwise problems
+ \doifcolorelse \ascii % with 2\bodyfontsize
+ {\setevalue{#1}{\MPcolor\theMPvariable}}
+ {% can be aux macro
+ \setbox\scratchbox\hbox{\scratchdimen\theMPvariable sp}%
+ \ifdim\wd\scratchbox=\zeropoint
+ % \scratchcounter\theMPvariable
+ % \setevalue{#1}{\the\scratchcounter}%
+ % also accepts 0.number :
+ \setevalue{#1}{\number\theMPvariable}%
+ \else
+ \scratchdimen\theMPvariable
+ \setevalue{#1}{\the\scratchdimen}%
+ \fi}}}
+
+%D We redefine \type {\extendMPoverlaystamp} to preprocess
+%D variables using \type {\prepareMPvariable}.
+
+\def\doextendMPoverlaystamp#1%
+ {\prepareMPvariable{#1}%
+ \edef\overlaystamp{\overlaystamp:\MPvariable{#1}}}
+
+\def\extendMPoverlaystamp#1%
+ {\processcommalist[#1]\doextendMPoverlaystamp}
+
+\def\prepareMPvariables#1%
+ {\processcommalist[#1]\prepareMPvariable}
+
+%D \macros
+%D {MPdatafile}
+%D
+%D We redefine a macro from \type {supp-mps.tex}:
+
+\def\MPdataMPDfile{\jobname-mpgraph.mpd}
+\def\MPdataMPOfile{\jobname-mpgraph.mpo}
+\def\MPdataMPYfile{\jobname-mpgraph.mpy}
+
+\startMPextensions
+ boolean collapse_data; collapse_data:=true;
+ def data_mpd_file = "\MPdataMPDfile" enddef ;
+ def data_mpo_file = "\MPdataMPOfile" enddef ;
+ def data_mpy_file = "\MPdataMPYfile" enddef ;
+\stopMPextensions
+
+\chardef\currentMPgraphic\plusone
+
+\def\getMPdata
+ {\let\MPdata\secondoftwoarguments
+ \startreadingfile
+ % \startnointerference % no, else we need to do all data global
+ \readlocfile\MPdataMPDfile\donothing\donothing
+ % \stopnointerference
+ \stopreadingfile}
+
+%D \macros
+%D {MPrunfile}
+%D
+%D This one is more abstract and does not assume knowledge
+%D of buffer prefixes.
+
+\def\MPrunfile#1%
+ {\bufferprefix mprun.#1}
+
+%D For the moment, the next one is a private macro:
+
+\def\processMPbuffer
+ {\dosingleempty\doprocessMPbuffer}
+
+\def\doprocessMPbuffer[#1]%
+ {\doifelsenothing{#1}
+ {\dodoprocessMPbuffer{\jobname}}
+ {\dodoprocessMPbuffer{#1}}}
+
+% we need to go via a toks because we have no multiline print in
+% luatex (i.e. tex.sprint does not interpret lines) and therefore
+% omits all after a comment token
+
+\newtoks\mpbuffertoks
+
+\def\doprocessMPbuffer[#1]%
+ {\doifelsenothing{#1}
+ {\doprocessMPbuffer[\jobname]}
+ {\beginMPgraphicgroup{#1}%
+ % we need this trick because tex.sprint does not interprets newlines and the scanner
+ % stops at a newline; also, we do need to flush the buffer under a normal catcode
+ % regime in order to expand embedded tex macros; #1 can be a list
+ \processMPgraphic{\ctxlua{buffers.feedback("\currentMPgraphicname")}}%
+ \endMPgraphicgroup}}
+
+\def\runMPbuffer
+ {\dosingleempty\dorunMPbuffer}
+
+\def\dorunMPbuffer[#1]% processing only
+ {\startnointerference\doprocessMPbuffer[#1]\stopnointerference}
+
+%D \macros
+%D {startMPenvironment, resetMPenvironment}
+%D
+%D In order to synchronize the main \TEX\ run and the runs
+%D local to \METAPOST, environments can be passed.
+
+\ifx\everyMPTEXgraphic\undefined
+ \newtoks\everyMPTEXgraphic
+\fi
+
+%D A more general way of passing environments is:
+
+\def\startMPenvironment % second arg gobbles spaces, so that reset gives \emptytoks
+ {\dodoubleempty\dostartMPenvironment}
+
+\long\def\dostartMPenvironment[#1][#2]#3\stopMPenvironment
+ {\doif{#1}\s!reset\resetMPenvironment % reset mp toks
+ \doif{#1}\v!global{#3}% % use in main doc too
+ \doif{#1}+{#3}% % use in main doc too
+ \ctxlua{metapost.tex.set(\!!bs\detokenize{#3}\!!es)}}
+
+\def\resetMPenvironment
+ {\ctxlua{metapost.tex.reset()}}
+
+\resetMPenvironment
+
+\def\useMPenvironmentbuffer[#1]%
+ {\ctxlua{metapost.tex.set(buffers.content("#1"))}}
+
+%D This command takes \type {[reset]} as optional
+%D argument.
+%D
+%D \starttyping
+%D \startMPenvironment
+%D \setupbodyfont[pos,14.4pt]
+%D \stopMPenvironment
+%D
+%D \startMPcode
+%D draw btex \sl Hans Hagen etex scaled 5 ;
+%D \stopMPcode
+%D \stoptyping
+%D
+%D The most simple case:
+
+\def\startMPcode{\dosinglegroupempty\dostartMPcode}
+
+\def\dostartMPcode
+ {\iffirstargument
+ \expandafter\dodostartMPcode
+ \else
+ \expandafter\nodostartMPcode
+ \fi}
+
+\def\dodostartMPcode#1#2\stopMPcode
+ {\beginMPgraphicgroup{#1::\s!dummy}% name does not matter
+ \processMPgraphic{#2}%
+ \endMPgraphicgroup}
+
+\def\nodostartMPcode#1#2\stopMPcode
+ {\processMPgraphic{#2}}
+
+\let\stopMPcode\relax
+
+% a bit nasty (also needed for compatibility:
+
+% \startMPrun input mp-www.mp ; \stopMPrun
+% \externalfigure[mprun.3][width=10cm,height=8cm]
+
+% \startMPrun{mprun} input mp-www.mp ; \stopMPrun % instance
+% \externalfigure[mprun.4][width=10cm,height=8cm]
+
+\let\MPruninstance\defaultMPgraphicinstance
+
+\def\useMPrun#1#2% name n
+ {\begingroup
+ \def\MPaskedfigure{#2}%
+ \doifelsenothing{#1}
+ {\useMPgraphic{mprun}}%
+ {\useMPgraphic{#1}}%
+ \endgroup}
+
+\def\startMPrun
+ {\dosinglegroupempty\dostartMPrun}
+
+\long\def\dostartMPrun#1#2\stopMPrun
+ {\iffirstargument
+ \startuseMPgraphic{#1}#2\stopuseMPgraphic
+ \else
+ \startuseMPgraphic{mprun}#2\stopuseMPgraphic
+ \fi}
+
+% for old time sake
+
+\def\dostartMPgraphic
+ {\iffirstargument
+ \expandafter\dodostartMPgraphic
+ \else
+ \expandafter\nodostartMPgraphic
+ \fi}
+
+\def\dodostartMPgraphic#1#2\stopMPgraphic
+ {\beginMPgraphicgroup{#1::\s!dummy}% name does not matter
+ \processMPgraphic{#2}%
+ \endMPgraphicgroup}
+
+\def\nodostartMPgraphic#1#2\stopMPcode
+ {\processMPgraphic{#2}}
+
+\let\stopMPcode\relax
+
+%D The \type {\resetMPenvironment} is a quick way to erase
+%D the token list.
+%D
+%D You should be aware of independencies. For instance, if you use a font
+%D in a graphic that is not used in the main document, you need to load the
+%D typescript at the outer level (either directly or by using the global
+%D option).
+%D
+%D \starttyping
+%D \usetypescript[palatino][texnansi]
+%D
+%D \startMPenvironment
+%D \usetypescript[palatino][texnansi]
+%D \enableregime[utf]
+%D \setupbodyfont[palatino]
+%D \stopMPenvironment
+%D
+%D \startMPpage
+%D draw btex aap‒noot coördinatie – één etex ;
+%D \stopMPpage
+%D \stoptyping
+
+%D Loading specific \METAPOST\ related definitions is
+%D accomplished by:
+
+\def\douseMPlibrary#1%
+ {\ifcsname\c!file\f!metapostprefix#1\endcsname\else
+ \letvalueempty{\c!file\f!metapostprefix#1}%
+ \makeshortfilename[\truefilename{\f!metapostprefix#1}]%
+ \startreadingfile
+ \readsysfile\shortfilename{\showmessage\m!metapost1{#1}}\donothing
+ \stopreadingfile
+ \fi}
+
+\def\useMPlibrary[#1]%
+ {\processcommalist[#1]\douseMPlibrary}
+
+%D \macros
+%D {setMPtext, MPtext, MPstring, MPbetex}
+%D
+%D To be documented:
+%D
+%D \starttyping
+%D \setMPtext{identifier}{text}
+%D
+%D \MPtext {identifier}
+%D \MPstring{identifier}
+%D \MPbetex {identifier}
+%D \stoptyping
+
+\def\@@MPT{@MPT@}
+
+\def\forceMPTEXgraphic
+ {\long\def\checkMPTEXgraphic##1{\global\MPTEXgraphictrue}}
+
+\def\setMPtext#1#2% todo : #1 must be made : safe
+ {%\forceMPTEXgraphic
+ \defconvertedargument\ascii{#2}%
+ \dodoglobal\letvalue{\@@MPT#1}\ascii}
+
+\def\MPtext #1{\executeifdefined{\@@MPT#1}\empty}
+\def\MPstring #1{"\executeifdefined{\@@MPT#1}\empty"}
+\def\MPbetex #1{btex \executeifdefined{\@@MPT#1}\empty\space etex}
+
+%D Unfortunately \METAPOST\ does not have \CMYK\ support
+%D built in, but by means of specials we can supply the
+%D information needed to handle them naturaly.
+
+% \newif\ifMPcmykcolors \MPcmykcolorstrue
+% \newif\ifMPspotcolors \MPspotcolorstrue
+
+\startMPinitializations
+ cmykcolors:=\ifMPcmykcolors true\else false\fi;
+ spotcolors:=\ifMPspotcolors true\else false\fi;
+\stopMPinitializations
+
+%D In order to communicate conveniently with the \TEX\
+%D engine, we introduce some typesetting variables.
+
+\startMPextensions
+ color OverlayColor,OverlayLineColor;
+\stopMPextensions
+
+\startMPinitializations
+ OverlayWidth:=\overlaywidth;
+ OverlayHeight:=\overlayheight;
+ OverlayDepth:=\overlayheight;
+ OverlayColor:=\MPcolor{\overlaycolor};
+ OverlayLineWidth:=\overlaylinewidth;
+ OverlayLineColor:=\MPcolor{\overlaylinecolor};
+ %
+ BaseLineSkip:=\the\baselineskip;
+ LineHeight:=\the\baselineskip;
+ BodyFontSize:=\the\bodyfontsize;
+ %
+ TopSkip:=\the\topskip;
+ StrutHeight:=\strutheight;
+ StrutDepth:=\strutdepth;
+ %
+ CurrentWidth:=\the\hsize;
+ CurrentHeight:=\the\vsize;
+ %
+ EmWidth:=\the\emwidth;
+ ExHeight:=\the\exheight;
+ %
+ PageNumber:=\the\pageno;
+ RealPageNumber:=\the\realpageno;
+ LastPageNumber:= \lastpage;
+\stopMPinitializations
+
+\appendtoks
+ \disablediscretionaries
+ \disablecompoundcharacters
+\to \everyMPgraphic
+
+\appendtoks % before color
+ %\normalexpanded{\noexpand\definecolor[currentcolor][\currentcolorname]}%
+ \doregistercolor{currentcolor}\currentcolorname
+\to \everyMPgraphic
+
+% \color[green]{abc \startMPcode
+% fill fullcircle scaled 3cm withoutcolor;
+% fill fullcircle scaled 2cm withcolor \MPcolor{currentcolor} ;
+% fill fullcircle scaled 1cm withcolor \MPcolor{red} ;
+% \stopMPcode def}
+
+% \appendtoks
+% \doactivatecolor\s!black\forcecolorhack % we can also move this to the backend
+% \to \everyMPgraphic
+
+\appendtoks
+ \baselineskip1\baselineskip
+ \lineheight 1\lineheight
+ \topskip 1\topskip
+\to \everyMPgraphic
+
+\appendtoks
+ \let \# \letterhash
+ \let \_ \letterunderscore
+ \let \& \letterampersand
+ \let \{ \letteropenbrace
+ \let \} \letterclosebrace
+\to \everyMPgraphic
+
+\startMPinitializations
+ prologues:=0;
+ mpprocset:=1;
+\stopMPinitializations
+
+%D \macros
+%D {PDFMPformoffset}
+%D
+%D In \PDF, forms are clipped and therefore we have to take
+%D precautions to get this right. Since this is related to
+%D objects, we use the same offset as used there.
+
+\def\PDFMPformoffset{\objectoffset}
+
+% %D \macros
+% %D {insertMPfile}
+% %D
+% %D Bypassing the special driver and figure mechanism is not
+% %D that nice but saves upto 5\% time in embedding \METAPOST\
+% %D graphics by using the low level \PDF\ converter directly,
+% %D given of course that we use \PDFTEX. As a result we need to
+% %D fool around with the object trigger.
+
+\newtoks\everyinsertMPfile
+
+% removed in backend:
+%
+% \def\doinsertMPfile#1%
+% {\doiffileelse{./#1}{\includeMPasPDF{./#1}}{\message{[MP #1]}}}
+%
+% \let\insertMPfileARG\insertMPfile
+%
+% \def\insertMPfile#1#2% in context #2 is empty
+% {\doifelsenothing{#2}{\doinsertMPfile{#1}}{\insertMPfileARG{#1}{#2}}}
+%
+% \def\includeMPasEPS#1% untested !!
+% {\bgroup
+% \message{[MP as EPS #1]}%
+% \the\everyinsertMPfile
+% \dogetEPSboundingbox{#1}\!!widtha\!!heighta\!!widthb\!!heightb
+% \setbox\scratchbox\vbox to \!!heightb
+% {\vfill
+% \let \@@DriverImageType \c!mps
+% \def \@@DriverImageFile {#1}%
+% \edef\@@DriverImageWidth {\the\!!widthb }%
+% \edef\@@DriverImageHeight{\the\!!heightb}%
+% \doinsertfile}%
+% \wd\scratchbox\!!widthb
+% \dp\scratchbox\zeropoint
+% \box\scratchbox
+% \egroup}
+%
+% \def\includeMPasPDF#1%
+% {\bgroup
+% \the\everyinsertMPfile
+% \ifinobject \else \chardef\makeMPintoPDFobject\plustwo \fi % when needed
+% \convertMPtoPDF{#1}{1}{1}% no \plusone !
+% \egroup}
+%
+% %D So, using a low level approach (thereby avoiding the slower
+% %D figure analysis macros) pays off. This kind of
+% %D optimizations are a bit tricky since we must make sure that
+% %D special resources end up in the (PDF) files. Because the
+% %D \METAPOST\ to \PDF\ can handle objects itself, it is not
+% %D that complicated.
+%
+% %D We hook a couple of initializations into the graphic
+% %D macros.
+%
+% \appendtoks
+% \let\figuretypes\c!mps
+% \runutilityfilefalse
+% \consultutilityfilefalse
+% \to \everyinsertMPfile
+%
+% %D One more: (still needed?)
+
+\startMPextensions
+ def initialize_form_numbers =
+ do_initialize_numbers;
+ enddef;
+\stopMPextensions
+
+\startMPinitializations
+ HSize:=\the\hsize ;
+ VSize:=\the\vsize ;
+\stopMPinitializations
+
+\startMPextensions
+ vardef ForegroundBox =
+ unitsquare xysized(HSize,VSize)
+ enddef ;
+ vardef PageFraction =
+ if \lastpage>1: (\realfolio-1)/(\lastpage-1) else: 1 fi
+ enddef ;
+\stopMPextensions
+
+%D And some more. These are not really needed since we
+%D don't use the normal figure inclusion macros any longer.
+
+\appendtoks
+ \externalfigurepostprocessors\emptytoks % safeguard
+\to \everyinsertMPfile
+
+%D We also take care of disabling fancy figure features, that
+%D can terribly interfere when dealing with symbols,
+%D background graphics and running (postponed) graphics.
+%D You won't believe me if I tell you what funny side effects
+%D can occur. One took me over a day to uncover when
+%D processing the screen version of the \METAFUN\ manual.
+
+%D For my eyes only:
+
+\def\doifelseMPgraphic#1{\doifdefinedelse{\@@MPG#1}}
+
+%D \macros
+%D {startMPcolor}
+
+\long\unexpanded\def\startMPcolor#1\stopMPcolor
+ {\writestatus \m!metapost % eventually this placeholder will go away
+ {\string\startMPcolor...\stopMPcolor\space is obsolete,\space
+ use \string\defineintermediatecolor\space instead}}
+
+\let\stopMPcolor\relax
+
+%D New:
+
+\definelayerpreset % no dx,dy - else nasty non-mp placement
+ [mp]
+ [\c!y=-\MPury bp,
+ \c!x=\MPllx bp,
+ \c!method=\v!fit]
+
+\definelayer
+ [mp]
+ [\c!preset=mp]
+
+%D Usage:
+%D
+%D \starttyping
+%D \defineproperty[one][layer][state=start]
+%D \defineproperty[two][layer][state=stop]
+%D
+%D \startuseMPgraphic{step-1}
+%D fill fullcircle scaled 10cm withcolor red ;
+%D \stopuseMPgraphic
+%D
+%D \startuseMPgraphic{step-2}
+%D fill fullcircle scaled 5cm withcolor green ;
+%D \stopuseMPgraphic
+%D
+%D \setlayer[mp]{\property[one]{\useMPgraphic{step-1}}}
+%D \setlayer[mp]{\property[two]{\useMPgraphic{step-2}}}
+%D
+%D \ruledhbox{\flushlayer[mp]}
+%D \stoptyping
+%D
+%D Reusing graphics is also possible (now):
+%D
+%D \starttyping
+%D \startreusableMPgraphic{axis}
+%D tickstep := 1cm ; ticklength := 2mm ;
+%D drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ;
+%D tickstep := tickstep/2 ; ticklength := ticklength/2 ;
+%D drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ;
+%D \stopreusableMPgraphic
+%D
+%D \startuseMPgraphic{demo}
+%D drawpoint "1cm,1.5cm" ;
+%D \stopuseMPgraphic
+%D
+%D \definelayer[mp][preset=mp]
+%D \setlayer[mp]{\reuseMPgraphic{axis}}
+%D \setlayer[mp]{\useMPgraphic{demo}}
+%D \ruledhbox{\flushlayer[mp]}
+%D \stoptyping
+
+%D \macros
+%D {startstaticMPfigure,useMPstaticfigure}
+%D
+%D Static figures are processed only when there has been
+%D something changed. Here is Aditya Mahajan's testcase:
+%D
+%D \startbuffer
+%D \startstaticMPfigure{circle}
+%D fill fullcircle scaled 1cm withcolor blue;
+%D \stopstaticMPfigure
+%D
+%D \startstaticMPfigure{axis}
+%D drawarrow (0,0)--(2cm,0) ;
+%D drawarrow (0,0)--(0,2cm) ;
+%D label.llft(textext("(0,0)") ,origin) ;
+%D \stopstaticMPfigure
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\usestaticMPfigure
+ {\dodoubleempty\dousestaticMPfigure}
+
+\def\dousestaticMPfigure[#1][#2]%
+ {\ifsecondargument
+ \scale[#2]{\reuseMPgraphic{\@@MPG#1@S@}}%
+ \else
+ \reuseMPgraphic{\@@MPG#1@S@}%
+ \fi}
+
+\unexpanded\def\startstaticMPfigure#1#2\stopstaticMPfigure
+ {\startreusableMPgraphic{\@@MPG#1@S@}#2\stopreusableMPgraphic}
+
+\long\unexpanded\def\startstaticMPgraphic
+ {\dodoublegroupempty\dostartstaticMPgraphic}
+
+\long\def\dostartstaticMPgraphic#1#2#3\stopstaticMPgraphic
+ {\long\setgvalue{\@@MPG#1@S@}{\handlereusableMPgraphic{#1}{#2}{#3}}}
+
+%D New:
+
+\newconditional\manyMPspecials % when set to true, > 1000 specials can be used
+
+\settrue \manyMPspecials % per 1/4/2006
+
+\prependtoks
+ _special_div_ := 1000\ifconditional\manyMPspecials0\fi ;
+\to \MPextensions
+
+%D Needed too.
+
+\let\initializeMPgraphics\relax
+
+%D Goody for preventing overflows:
+
+\def\MPdivten[#1]{\withoutpt\the\dimexpr#1pt/10\relax}
+
+%D There is no way to distinguish the black color that you get when
+%D you issue a \type {draw} without color specification from a color
+%D that has an explicit black specification unless you set the
+%D variable \type {defaultcolormodel} to 1. Hoewever, in that case
+%D you cannot distinguish that draw from one with a \type
+%D {withoutcolor} specification. This means that we have to provide
+%D multiple variants of inheritance.
+%D
+%D In any case we need to tell the converter what the inherited color
+%D is to start with. Case~3 is kind of unpredictable as it closely
+%D relates to the order in which paths are flushed. If you want to
+%Dinherit automatically from the surrounding, you can best stick to
+%D variant 1. Variant 0 (an isolated graphic) is the default.
+%D
+%D \startbuffer
+%D \startuseMPgraphic{test}
+%D drawoptions(withpen pencircle scaled 1pt) ;
+%D def shift_cp = currentpicture := currentpicture shifted (-15pt,0) ; enddef ;
+%D draw fullcircle scaled 10pt withoutcolor ; shift_cp ;
+%D fill fullcircle scaled 10pt ; shift_cp ;
+%D draw fullcircle scaled 10pt withoutcolor ; shift_cp ;
+%D fill fullcircle scaled 10pt withcolor red ; shift_cp ;
+%D draw fullcircle scaled 10pt withoutcolor ; shift_cp ;
+%D fill fullcircle scaled 10pt ; shift_cp ;
+%D \stopuseMPgraphic
+%D
+%D \starttabulate
+%D \NC 0\quad \NC \chardef\MPcolormethod0 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR
+%D \NC 1\quad \NC \chardef\MPcolormethod1 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR
+%D \NC 2\quad \NC \chardef\MPcolormethod2 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR
+%D \NC 3\quad \NC \chardef\MPcolormethod3 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR
+%D \stoptabulate
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\chardef\MPcolormethod\zerocount
+
+% can be faster, just
+
+\appendtoks
+ \ctxlua{metapost.set_outer_color(\number\MPcolormethod,\number\currentcolormodel,\number\dogetattribute{color},\number\dogetattribute{transparency})}%
+\to \everyMPgraphic
+
+\startMPinitializations
+ defaultcolormodel := \ifcase\MPcolormethod1\or1\or3\else3\fi;
+\stopMPinitializations
+
+%D \macros
+%D {setupMPgraphics}
+%D
+%D Here is a generic setup command:
+
+\newtoks \everysetupMPgraphics
+
+\unexpanded\def\setupMPgraphics[#1]%
+ {\getparameters[\??mp][#1]%
+ \the\everysetupMPgraphics}
+
+%D Here we hook in the outer color. When \type {color} is set to \type
+%D {global} we get the outer color automatically. If you change this
+%D setting, you should do it grouped in order not to make other graphics
+%D behave in unexpected ways.
+
+\appendtoks
+ \doifelse\@@mpcolor\v!global{\chardef\MPcolormethod\plusone}{\chardef\MPcolormethod\zerocount}%
+\to \everysetupMPgraphics
+
+\setupMPgraphics
+ [\c!color=\v!local]
+
+%D Done.
+
+\protect \endinput
diff --git a/tex/context/base/meta-mis.tex b/tex/context/base/meta-mis.tex
new file mode 100644
index 000000000..29ab43007
--- /dev/null
+++ b/tex/context/base/meta-mis.tex
@@ -0,0 +1,54 @@
+%D \module
+%D [ file=meta-mis,
+%D version=2006.06.06,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Misc Test Graphics,
+%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.
+
+\unprotect
+
+% p/s 1/false 1/true 2/false 2/true
+%
+% MKII 8.5 8.0 8.8 8.5
+% MKIV 16.1 7.2 16.3 7.4
+
+\startuseMPgraphic{mptopdf-test}
+ prologues := 2;
+ mpprocset := 1 ;
+ fill fullcircle scaled 3cm withcolor red ;
+ fill fullcircle scaled 2cm withcolor green ;
+ fill fullcircle scaled 1cm withcolor blue ;
+ currentpicture := currentpicture shifted (-4cm,0) ;
+ fill fullcircle scaled 3cm withcolor cmyk(0,0,1,0) ;
+ fill fullcircle scaled 2cm withcolor cmyk(0,1,0,0) ;
+ fill fullcircle scaled 1cm withcolor cmyk(1,0,0,0) ;
+ currentpicture := currentpicture shifted (-4cm,0) ;
+ draw fullcircle scaled 3cm dashed evenly ;
+ draw fullcircle scaled 2cm dashed withdots ;
+ draw origin withpen pencircle scaled 3mm;
+ currentpicture := currentpicture shifted (-4cm,0) ;
+ fill fullcircle scaled 2cm shifted (-.5cm,+.5cm) withcolor transparent(1,.5,red);
+ fill fullcircle scaled 2cm shifted (-.5cm,-.5cm) withcolor transparent(1,.5,red);
+ fill fullcircle scaled 2cm shifted (+.5cm,+.5cm) withcolor transparent(1,.5,green);
+ fill fullcircle scaled 2cm shifted (+.5cm,-.5cm) withcolor transparent(1,.5,cmyk(1,0,1,.5));
+ currentpicture := currentpicture shifted (12cm,-4cm) ;
+ draw "o e p s" infont defaultfont scaled 2 shifted (-1cm,0) ;
+ currentpicture := currentpicture shifted (-4cm,0) ;
+ % bug: shift
+ draw fullcircle scaled 3cm withpen pencircle yscaled 3mm xscaled 2mm rotated 30 ;
+ draw fullcircle scaled 2cm withpen pencircle yscaled 3mm xscaled 2mm rotated 20 withcolor red ;
+ filldraw fullcircle scaled 1cm withpen pencircle yscaled 3mm xscaled 2mm rotated 10 withcolor green ;
+ currentpicture := currentpicture shifted (-4cm,0) ;
+ % shade cannot handle shift
+ circular_shade(fullcircle scaled 3cm,0,.2red,.9green) ;
+ circular_shade(fullcircle scaled 3cm shifted(+4cm,0),0,cmyk(1,0,0,0),cmyk(0,1,0,0)) ;
+ filldraw boundingbox currentpicture enlarged (-bbheight(currentpicture)/2+2.5mm) withpen pencircle scaled 1pt withcolor .5white ;
+\stopuseMPgraphic
+
+\protect \endinput
diff --git a/tex/context/base/meta-nav.tex b/tex/context/base/meta-nav.tex
new file mode 100644
index 000000000..9c1cbb4db
--- /dev/null
+++ b/tex/context/base/meta-nav.tex
@@ -0,0 +1,65 @@
+%D \module
+%D [ file=meta-nav,
+%D version=2003.03.28,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Navigational Graphics,
+%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.
+
+\startuniqueMPgraphic{navplus}{size,color,type,mode}
+ color c ; numeric s, t ; path p ;
+ t := \MPvar{type} ; c := \MPvar{color} ; s := \MPvar{size} ;
+ if \MPvar{mode} = 1 : c := .5[c,white] fi ;
+ if t = 1 :
+ p := ((0,0)--(1/2,0)--(1,1/3)--(1,1)--(0,1)--(0,0)--cycle)
+ xyscaled (3,4) ;
+ elseif t = 2 :
+ p := ((0,0)--(1,0)--(1,1)--(0,1)--(1/2,2/5)--(1,1)--(0,1)--cycle)
+ xyscaled (4,3) ;
+ else :
+ p := fullsquare xyscaled (3,3) ;
+ fi ;
+ draw p withpen pencircle scaled (1/2) withcolor .75white ;
+ fill p withcolor c ;
+ draw p withpen pencircle scaled (1/3) withcolor .5c ;
+ currentpicture := currentpicture scaled s ;
+ currentpicture := currentpicture shifted -center currentpicture ;
+\stopuniqueMPgraphic
+
+\setupMPvariables
+ [navplus]
+ [size=1ex,
+ color=black,
+ type=1,
+ mode=0]
+
+\definepalet
+ [navplus]
+ [attach=darkred,
+ comment=darkblue]
+
+\definesymbol
+ [comment-normal]
+ [\uniqueMPgraphic{navplus}{type=1,color=navplus:comment}]
+\definesymbol
+ [comment-down]
+ [\uniqueMPgraphic{navplus}{type=1,color=navplus:comment,mode=1}]
+
+\definesymbol
+ [attach-normal]
+ [\uniqueMPgraphic{navplus}{type=2,color=navplus:attach}]
+\definesymbol
+ [attach-down]
+ [\uniqueMPgraphic{navplus}{type=2,color=navplus:attach,mode=1}]
+
+\unprotect
+
+\setupcomment [\c!symbol={comment-normal,comment-down}]
+\setupattachments[\c!symbol={attach-normal,attach-down}]
+
+\protect \endinput
diff --git a/tex/context/base/meta-pag.mkii b/tex/context/base/meta-pag.mkii
new file mode 100644
index 000000000..000e56a2e
--- /dev/null
+++ b/tex/context/base/meta-pag.mkii
@@ -0,0 +1,226 @@
+%D \module
+%D [ file=meta-pag,
+%D version=1999.07.10,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Initialization,
+%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.
+
+%D These definitions used to be part of the old \type
+%D {core-mps} file, later changed into \type {meta-ini}, but
+%D keeping them separate is cleaner.
+
+\writestatus{loading}{MetaPost Graphics / Page Data Management}
+
+\unprotect
+
+\startMPextensions
+ if unknown context_page: input mp-page; fi;
+\stopMPextensions
+
+%D The next few macros tell \METAPOST\ how the \CONTEXT\
+%D pagebody looks.
+
+\startMPextensions
+ boolean PageStateAvailable,OnRightPage,InPageBody;
+ PageStateAvailable:=true;
+\stopMPextensions
+
+\startMPinitializations
+ OnRightPage:=true;
+ InPageBody:=\ifinpagebody true \else false \fi;
+\stopMPinitializations
+
+\startMPinitializations
+ def LoadPageState =
+ OnRightPage:=\MPonrightpage;
+ OnOddPage:=\MPonoddpage;
+ RealPageNumber:=\the\realpageno;
+ PageNumber:=\the\pageno;
+ NOfPages:=\lastpage;
+ PaperHeight:=\the\paperheight;
+ PaperWidth:=\the\paperwidth;
+ PrintPaperHeight:=\the\printpaperheight;
+ PrintPaperWidth:=\the\printpaperwidth;
+ TopSpace:=\the\topspace;
+ BottomSpace:=\the\bottomspace;
+ BackSpace:=\the\backspace;
+ CutSpace:=\the\cutspace;
+ MakeupHeight:=\the\makeupheight;
+ MakeupWidth:=\the\makeupwidth;
+ TopHeight:=\the\topheight;
+ TopDistance:=\the\topdistance;
+ HeaderHeight:=\the\headerheight;
+ HeaderDistance:=\the\headerdistance;
+ TextHeight:=\the\textheight;
+ FooterDistance:=\the\footerdistance;
+ FooterHeight:=\the\footerheight;
+ BottomDistance:=\the\bottomdistance;
+ BottomHeight:=\the\bottomheight;
+ LeftEdgeWidth:=\the\leftedgewidth;
+ LeftEdgeDistance:=\the\leftedgedistance;
+ LeftMarginWidth:=\the\leftmarginwidth;
+ LeftMarginDistance:=\the\leftmargindistance;
+ TextWidth:=\the\textwidth ;
+ RightMarginDistance:=\the\rightmargindistance;
+ RightMarginWidth:=\the\rightmarginwidth;
+ RightEdgeDistance:=\the\rightedgedistance;
+ RightEdgeWidth:=\the\rightedgewidth;
+ InnerMarginDistance:=\the\innermargindistance;
+ InnerMarginWidth:=\the\innermarginwidth;
+ OuterMarginDistance:=\the\outermargindistance;
+ OuterMarginWidth:=\the\outermarginwidth;
+ InnerEdgeDistance:=\the\inneredgedistance;
+ InnerEdgeWidth:=\the\inneredgewidth;
+ OuterEdgeDistance:=\the\outeredgedistance;
+ OuterEdgeWidth:=\the\outeredgewidth;
+ PageOffset:=\the\pageoffset;
+ PageDepth:=\the\pagedepth;
+ LayoutColumns:=\the\layoutcolumns;
+ LayoutColumnDistance:=\the\layoutcolumndistance;
+ LayoutColumnWidth:=\the\layoutcolumnwidth;
+ enddef;
+\stopMPinitializations
+
+\def\MPonrightpage{true}
+\def\MPonoddpage {true}
+
+\def\freezeMPpagelayout
+ {\doifbothsides
+ {\def\MPonrightpage{true}}
+ {\def\MPonrightpage{true}}
+ {\def\MPonrightpage{false}}%
+ \edef\MPonoddpage{\doifoddpageelse{true}{false}}}
+
+\let\freezeMPlayout\relax % obsolete
+
+%D We need to freeze the pagelayout before the backgrounds
+%D are build, because the overlay will temporarily become
+%D zero (overlay).
+
+\appendtoks
+ \freezeMPpagelayout
+\to \everybeforepagebody
+
+%D By freezing these value every graphic, we can use layout
+%D variables that change halfways a page, whatever use that
+%D has.
+
+\prependtoks
+ \calculatereducedvsizes % this is really needed
+ \freezeMPpagelayout
+ \freezeMPlayout % to be used grouped
+\to \everyMPgraphic
+
+%D The next feature provides information about for instance
+%D column positions. This is an experimental feature,
+%D introduced when we needed backgrounds in columns (fill||in
+%D questions as implemented in a private module).
+%D
+%D See \type {mp-page.mp} for the definition of the macros:
+%D
+%D \starttabulate[|tl|l|p|]
+%D \NC ResetTextAreas \NC no arguments \NC
+%D reset areas on page \NC \NR
+%D \NC RegisterTextArea \NC x, y, w, h \NC
+%D adds area to the list \NC \NR
+%D \NC TextAreaX,Y,W,H,XY,WH \NC x and/or y \NC
+%D reports offsets and dimensions \NC \NR
+%D \stoptabulate
+%D
+%D The \type {TextArea*} macros can be used to determine
+%D overlap.
+
+\newcount\currentMPtextareadata
+
+\newtoks\MPsavedtextareadata
+\newtoks\MPtextareadata
+\newtoks\MPlocaltextareadata
+
+% optimaliseren voor herhaling
+
+\def\registerMPtextarea#1%
+ {\ifpositioning
+ \bgroup
+ \global\advance\currentMPtextareadata\plusone
+ %\hpos{gbd:\the\currentMPtextareadata}{#1}%
+ \hpos{gbd:\the\currentMPtextareadata}%
+ {\iftracetextareas\boxrulewidth1.5pt\ruledhbox\fi{#1}}%
+ \edef\!!stringa{gbd:\the\currentMPtextareadata}%
+ \edef\!!stringa{RegisterTextArea(%
+ \MPx\!!stringa,\MPy\!!stringa,%
+ \MPw\!!stringa,\MPh\!!stringa,\MPd\!!stringa);}%
+ \@EA \doglobal \@EA \appendtoks \!!stringa \to \MPtextareadata
+ \egroup
+ \else
+ \hbox{#1}%
+ \fi}
+
+\def\registerMPlocaltextarea#1%
+ {\ifpositioning
+ \bgroup
+ \global\advance\currentMPtextareadata\plusone
+ %\hpos{gbd:\the\currentMPtextareadata}{#1}%
+ \hpos{gbd:\the\currentMPtextareadata}%
+ {\iftracetextareas\boxrulewidth3pt\ruledhbox\fi{#1}}%
+ \edef\!!stringa{gbd:\the\currentMPtextareadata}%
+ \edef\!!stringa{RegisterLocalTextArea(%
+ \MPx\!!stringa,\MPy\!!stringa,%
+ \MPw\!!stringa,\MPh\!!stringa,\MPd\!!stringa);}%
+ \global\MPlocaltextareadata\@EA{\!!stringa}%
+ \egroup
+ \else
+ \hbox{#1}%
+ \fi}
+
+% better, so that we can force a key and share with e.g. renumbering
+%
+% \let\namedtextarea\empty
+%
+% \def\registerMPlocaltextarea#1%
+% {\ifpositioning
+% \bgroup
+% \ifx\namedtextarea\empty
+% \global\advance\currentMPtextareadata\plusone
+% \edef\namedtextarea{gbd:\the\currentMPtextareadata}%
+% \fi
+% \hpos\namedtextarea{\iftracetextareas\boxrulewidth3pt\ruledhbox\fi{#1}}%
+% \edef\ascii{RegisterLocalTextArea(%
+% \MPx\namedtextarea,\MPy\namedtextarea,%
+% \MPw\namedtextarea,\MPh\namedtextarea,\MPd\namedtextarea);}%
+% \global\MPlocaltextareadata\@EA{\ascii}%
+% \egroup
+% \else
+% \hbox{#1}%
+% \fi}
+
+\def\resetMPlocaltextarea
+ {\global\MPlocaltextareadata\emptytoks}
+
+\startMPextensions
+ path PlainTextArea;
+\stopMPextensions
+
+\startMPinitializations
+ ResetTextAreas;
+ \the\MPsavedtextareadata;
+ SaveTextAreas;
+ ResetTextAreas;
+ \the\MPtextareadata;
+ \the\MPlocaltextareadata;
+ PlainTextArea:=boundingbox(\MPxy{text:\realfolio}--\MPxy{text:\realfolio}
+ shifted (\MPw{text:\realfolio},\MPh{text:\realfolio}));
+\stopMPinitializations
+
+\appendtoks
+ \global\MPsavedtextareadata\MPtextareadata
+ \global\MPtextareadata \emptytoks
+ \global\MPlocaltextareadata\emptytoks
+\to \everyshipout
+
+\protect \endinput
diff --git a/tex/context/base/meta-pag.mkiv b/tex/context/base/meta-pag.mkiv
new file mode 100644
index 000000000..ef3817721
--- /dev/null
+++ b/tex/context/base/meta-pag.mkiv
@@ -0,0 +1,223 @@
+%D \module
+%D [ file=meta-pag,
+%D version=1999.07.10,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Initialization,
+%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.
+
+%D These definitions used to be part of the old \type
+%D {core-mps} file, later changed into \type {meta-ini}, but
+%D keeping them separate is cleaner.
+
+\writestatus{loading}{MetaPost Graphics / Page Data Management}
+
+\unprotect
+
+\startMPextensions
+ if unknown context_page: input mp-page; fi;
+\stopMPextensions
+
+%D The next few macros tell \METAPOST\ how the \CONTEXT\
+%D pagebody looks.
+
+\startMPextensions
+ boolean PageStateAvailable,OnRightPage,InPageBody;
+ PageStateAvailable:=true;
+\stopMPextensions
+
+\startMPinitializations
+ OnRightPage:=true;
+ InPageBody:=\ifinpagebody true \else false \fi;
+\stopMPinitializations
+
+\startMPinitializations
+ def LoadPageState =
+ OnRightPage:=\MPonrightpage;
+ OnOddPage:=\MPonoddpage;
+ RealPageNumber:=\the\realpageno;
+ PageNumber:=\the\pageno;
+ NOfPages:=\lastpage;
+ PaperHeight:=\the\paperheight;
+ PaperWidth:=\the\paperwidth;
+ PrintPaperHeight:=\the\printpaperheight;
+ PrintPaperWidth:=\the\printpaperwidth;
+ TopSpace:=\the\topspace;
+ BottomSpace:=\the\bottomspace;
+ BackSpace:=\the\backspace;
+ CutSpace:=\the\cutspace;
+ MakeupHeight:=\the\makeupheight;
+ MakeupWidth:=\the\makeupwidth;
+ TopHeight:=\the\topheight;
+ TopDistance:=\the\topdistance;
+ HeaderHeight:=\the\headerheight;
+ HeaderDistance:=\the\headerdistance;
+ TextHeight:=\the\textheight;
+ FooterDistance:=\the\footerdistance;
+ FooterHeight:=\the\footerheight;
+ BottomDistance:=\the\bottomdistance;
+ BottomHeight:=\the\bottomheight;
+ LeftEdgeWidth:=\the\leftedgewidth;
+ LeftEdgeDistance:=\the\leftedgedistance;
+ LeftMarginWidth:=\the\leftmarginwidth;
+ LeftMarginDistance:=\the\leftmargindistance;
+ TextWidth:=\the\textwidth ;
+ RightMarginDistance:=\the\rightmargindistance;
+ RightMarginWidth:=\the\rightmarginwidth;
+ RightEdgeDistance:=\the\rightedgedistance;
+ RightEdgeWidth:=\the\rightedgewidth;
+ InnerMarginDistance:=\the\innermargindistance;
+ InnerMarginWidth:=\the\innermarginwidth;
+ OuterMarginDistance:=\the\outermargindistance;
+ OuterMarginWidth:=\the\outermarginwidth;
+ InnerEdgeDistance:=\the\inneredgedistance;
+ InnerEdgeWidth:=\the\inneredgewidth;
+ OuterEdgeDistance:=\the\outeredgedistance;
+ OuterEdgeWidth:=\the\outeredgewidth;
+ PageOffset:=\the\pageoffset;
+ PageDepth:=\the\pagedepth;
+ LayoutColumns:=\the\layoutcolumns;
+ LayoutColumnDistance:=\the\layoutcolumndistance;
+ LayoutColumnWidth:=\the\layoutcolumnwidth;
+ enddef;
+\stopMPinitializations
+
+\def\MPonrightpage{true}
+\def\MPonoddpage {true}
+
+\def\freezeMPpagelayout
+ {\edef\MPonrightpage{\doifbothsides {tru}{tru}{fals}e}%
+ \edef\MPonoddpage {\doifoddpageelse {tru}{fals}e}}
+
+\let\freezeMPlayout\relax % obsolete
+
+%D We need to freeze the pagelayout before the backgrounds
+%D are build, because the overlay will temporarily become
+%D zero (overlay).
+
+\appendtoks
+ \freezeMPpagelayout
+\to \everybeforepagebody
+
+%D By freezing these value every graphic, we can use layout
+%D variables that change halfways a page, whatever use that
+%D has.
+
+\prependtoks
+ \calculatereducedvsizes % this is really needed
+ \freezeMPpagelayout
+ \freezeMPlayout % to be used grouped
+\to \everyMPgraphic
+
+%D The next feature provides information about for instance
+%D column positions. This is an experimental feature,
+%D introduced when we needed backgrounds in columns (fill||in
+%D questions as implemented in a private module).
+%D
+%D See \type {mp-page.mp} for the definition of the macros:
+%D
+%D \starttabulate[|tl|l|p|]
+%D \NC ResetTextAreas \NC no arguments \NC
+%D reset areas on page \NC \NR
+%D \NC RegisterTextArea \NC x, y, w, h \NC
+%D adds area to the list \NC \NR
+%D \NC TextAreaX,Y,W,H,XY,WH \NC x and/or y \NC
+%D reports offsets and dimensions \NC \NR
+%D \stoptabulate
+%D
+%D The \type {TextArea*} macros can be used to determine
+%D overlap.
+
+\newcount\currentMPtextareadata
+
+\newtoks\MPsavedtextareadata
+\newtoks\MPtextareadata
+\newtoks\MPlocaltextareadata
+
+% optimaliseren voor herhaling
+
+\def\registerMPtextarea#1%
+ {\ifpositioning
+ \bgroup
+ \global\advance\currentMPtextareadata\plusone
+ %\hpos{gbd:\the\currentMPtextareadata}{#1}%
+ \hpos{gbd:\the\currentMPtextareadata}%
+ {\iftracetextareas\boxrulewidth1.5pt\ruledhbox\fi{#1}}%
+ \edef\!!stringa{gbd:\the\currentMPtextareadata}%
+ \edef\!!stringa{RegisterTextArea(%
+ \MPx\!!stringa,\MPy\!!stringa,%
+ \MPw\!!stringa,\MPh\!!stringa,\MPd\!!stringa);}%
+ \@EA \doglobal \@EA \appendtoks \!!stringa \to \MPtextareadata
+ \egroup
+ \else
+ \hbox{#1}%
+ \fi}
+
+\def\registerMPlocaltextarea#1%
+ {\ifpositioning
+ \bgroup
+ \global\advance\currentMPtextareadata\plusone
+ %\hpos{gbd:\the\currentMPtextareadata}{#1}%
+ \hpos{gbd:\the\currentMPtextareadata}%
+ {\iftracetextareas\boxrulewidth3pt\ruledhbox\fi{#1}}%
+ \edef\!!stringa{gbd:\the\currentMPtextareadata}%
+ \edef\!!stringa{RegisterLocalTextArea(%
+ \MPx\!!stringa,\MPy\!!stringa,%
+ \MPw\!!stringa,\MPh\!!stringa,\MPd\!!stringa);}%
+ \global\MPlocaltextareadata\@EA{\!!stringa}%
+ \egroup
+ \else
+ \hbox{#1}%
+ \fi}
+
+% better, so that we can force a key and share with e.g. renumbering
+%
+% \let\namedtextarea\empty
+%
+% \def\registerMPlocaltextarea#1%
+% {\ifpositioning
+% \bgroup
+% \ifx\namedtextarea\empty
+% \global\advance\currentMPtextareadata\plusone
+% \edef\namedtextarea{gbd:\the\currentMPtextareadata}%
+% \fi
+% \hpos\namedtextarea{\iftracetextareas\boxrulewidth3pt\ruledhbox\fi{#1}}%
+% \edef\ascii{RegisterLocalTextArea(%
+% \MPx\namedtextarea,\MPy\namedtextarea,%
+% \MPw\namedtextarea,\MPh\namedtextarea,\MPd\namedtextarea);}%
+% \global\MPlocaltextareadata\@EA{\ascii}%
+% \egroup
+% \else
+% \hbox{#1}%
+% \fi}
+
+\def\resetMPlocaltextarea
+ {\global\MPlocaltextareadata\emptytoks}
+
+\startMPextensions
+ path PlainTextArea;
+\stopMPextensions
+
+\startMPinitializations
+ ResetTextAreas;
+ \the\MPsavedtextareadata;
+ SaveTextAreas;
+ ResetTextAreas;
+ \the\MPtextareadata;
+ \the\MPlocaltextareadata;
+ PlainTextArea:=boundingbox(\MPxy{text:\realfolio}--\MPxy{text:\realfolio}
+ shifted (\MPw{text:\realfolio},\MPh{text:\realfolio}));
+\stopMPinitializations
+
+\appendtoks
+ \global\MPsavedtextareadata\MPtextareadata
+ \global\MPtextareadata \emptytoks
+ \global\MPlocaltextareadata\emptytoks
+\to \everyshipout
+
+\protect \endinput
diff --git a/tex/context/base/meta-pdf.lua b/tex/context/base/meta-pdf.lua
new file mode 100644
index 000000000..23f8d4de0
--- /dev/null
+++ b/tex/context/base/meta-pdf.lua
@@ -0,0 +1,553 @@
+if not modules then modules = { } end modules ['meta-pdf'] = {
+ version = 1.001,
+ comment = "companion to meta-pdf.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Finally we used an optimized version. The test code can be found in
+-- meta-pdh.lua but since we no longer want to overload functione we use
+-- more locals now. This module keeps changing as it is also a testbed.
+
+local concat, format, gsub, find, byte, gmatch, match = table.concat, string.format, string.gsub, string.find, string.byte, string.gmatch, string.match
+local lpegmatch = lpeg.match
+local round = math.round
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+
+local pdfrgbcode = lpdf.rgbcode
+local pdfcmykcode = lpdf.cmykcode
+local pdfgraycode = lpdf.graycode
+local pdfspotcode = lpdf.spotcode
+local pdftransparencycode = lpdf.transparencycode
+local pdffinishtransparencycode = lpdf.finishtransparencycode
+
+mptopdf = { }
+mptopdf.n = 0
+
+local m_path, m_stack, m_texts, m_version, m_date, m_shortcuts = { }, { }, { }, 0, 0, false
+
+local m_stack_close, m_stack_path, m_stack_concat = false, { }, nil
+local extra_path_code, ignore_path = nil, false
+local specials = { }
+
+local function resetpath()
+ m_stack_close, m_stack_path, m_stack_concat = false, { }, nil
+end
+
+local function resetall()
+ m_path, m_stack, m_texts, m_version, m_shortcuts = { }, { }, { }, 0, false
+ extra_path_code, ignore_path = nil, false
+ specials = { }
+ resetpath()
+end
+
+resetall()
+
+-- todo: collect and flush packed using pdfliteral node injection but we're
+-- in no hurry as this kind of conversion does not happen that often in mkiv
+
+local function pdfcode(str) -- could be a node.write instead
+ texsprint(ctxcatcodes,"\\pdfliteral{",str,"}")
+end
+
+local function texcode(str)
+ texsprint(ctxcatcodes,str)
+end
+
+function mpscode(str)
+ if ignore_path then
+ pdfcode("h W n")
+ if extra_path_code then
+ pdfcode(extra_path_code)
+ extra_path_code = nil
+ end
+ ignore_path = false
+ else
+ pdfcode(str)
+ end
+end
+
+-- auxiliary functions
+
+local function flushconcat()
+ if m_stack_concat then
+ mpscode(concat(m_stack_concat," ") .. " cm")
+ m_stack_concat = nil
+ end
+end
+
+local function flushpath(cmd)
+ if #m_stack_path > 0 then
+ local path = { }
+ if m_stack_concat then
+ local sx, sy = m_stack_concat[1], m_stack_concat[4]
+ local rx, ry = m_stack_concat[2], m_stack_concat[3]
+ local tx, ty = m_stack_concat[5], m_stack_concat[6]
+ local d = (sx*sy) - (rx*ry)
+ for k=1,#m_stack_path do
+ local v = m_stack_path[k]
+ local px, py = v[1], v[2] ; v[1], v[2] = (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d -- mpconcat(v[1],v[2])
+ if #v == 7 then
+ local px, py = v[3], v[4] ; v[3], v[4] = (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d -- mpconcat(v[3],v[4])
+ local px, py = v[5], v[6] ; v[5], v[6] = (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d -- mpconcat(v[5],v[6])
+ end
+ path[#path+1] = concat(v," ")
+ end
+ else
+ for k=1,#m_stack_path do
+ path[#path+1] = concat(m_stack_path[k]," ")
+ end
+ end
+ flushconcat()
+ pdfcode(concat(path," "))
+ if m_stack_close then
+ mpscode("h " .. cmd)
+ else
+ mpscode(cmd)
+ end
+ end
+ resetpath()
+end
+
+-- mp interface
+
+mps = mps or { }
+
+function mps.creator(a, b, c)
+ m_version = tonumber(b)
+end
+
+function mps.creationdate(a)
+ m_date = a
+end
+
+function mps.newpath()
+ m_stack_path = { }
+end
+
+function mps.boundingbox(llx, lly, urx, ury)
+ texcode("\\MPSboundingbox{" .. llx .. "}{" .. lly .. "}{" .. urx .. "}{" .. ury .. "}")
+end
+
+function mps.moveto(x,y)
+ m_stack_path[#m_stack_path+1] = {x,y,"m"}
+end
+
+function mps.curveto(ax, ay, bx, by, cx, cy)
+ m_stack_path[#m_stack_path+1] = {ax,ay,bx,by,cx,cy,"c"}
+end
+
+function mps.lineto(x,y)
+ m_stack_path[#m_stack_path+1] = {x,y,"l"}
+end
+
+function mps.rlineto(x,y)
+ local dx, dy = 0, 0
+ if #m_stack_path > 0 then
+ dx, dy = m_stack_path[#m_stack_path][1], m_stack_path[#m_stack_path][2]
+ end
+ m_stack_path[#m_stack_path+1] = {dx,dy,"l"}
+end
+
+function mps.translate(tx,ty)
+ mpscode("1 0 0 0 1 " .. tx .. " " .. ty .. " cm")
+end
+
+function mps.scale(sx,sy)
+ m_stack_concat = {sx,0,0,sy,0,0}
+end
+
+function mps.concat(sx, rx, ry, sy, tx, ty)
+ m_stack_concat = {sx,rx,ry,sy,tx,ty}
+end
+
+function mps.setlinejoin(d)
+ mpscode(d .. " j")
+end
+
+function mps.setlinecap(d)
+ mpscode(d .. " J")
+end
+
+function mps.setmiterlimit(d)
+ mpscode(d .. " M")
+end
+
+function mps.gsave()
+ mpscode("q")
+end
+
+function mps.grestore()
+ mpscode("Q")
+end
+
+function mps.setdash(...) -- can be made faster, operate on t = { ... }
+ local n = select("#",...)
+ mpscode("[" .. concat({...}," ",1,n-1) .. "] " .. select(n,...) .. " d")
+end
+
+function mps.resetdash()
+ mpscode("[ ] 0 d")
+end
+
+function mps.setlinewidth(d)
+ mpscode(d .. " w")
+end
+
+function mps.closepath()
+ m_stack_close = true
+end
+
+function mps.fill()
+ flushpath('f')
+end
+
+function mps.stroke()
+ flushpath('S')
+end
+
+function mps.both()
+ flushpath('B')
+end
+
+function mps.clip()
+ flushpath('W n')
+end
+
+function mps.textext(font, scale, str) -- old parser
+ local dx, dy = 0, 0
+ if #m_stack_path > 0 then
+ dx, dy = m_stack_path[1][1], m_stack_path[1][2]
+ end
+ flushconcat()
+ texcode("\\MPStextext{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}")
+ resetpath()
+end
+
+local handlers = { }
+
+handlers[1] = function(s)
+ pdfcode(pdffinishtransparencycode())
+ pdfcode(pdfcmykcode(mps.colormodel,s[3],s[4],s[5],s[6]))
+end
+handlers[2] = function(s)
+ pdfcode(pdffinishtransparencycode())
+ pdfcode(pdfspotcode(mps.colormodel,s[3],s[4],s[5],s[6]))
+end
+handlers[3] = function(s)
+ pdfcode(pdfrgbcode(mps.colormodel,s[4],s[5],s[6]))
+ pdfcode(pdftransparencycode(s[2],s[3]))
+end
+handlers[4] = function(s)
+ pdfcode(pdfcmykcode(mps.colormodel,s[4],s[5],s[6],s[7]))
+ pdfcode(pdftransparencycode(s[2],s[3]))
+end
+handlers[5] = function(s)
+ pdfcode(pdfspotcode(mps.colormodel,s[4],s[5],s[6],s[7]))
+ pdfcode(pdftransparencycode(s[2],s[3]))
+end
+
+-- todo: color conversion
+
+local nofshades, tn = 0, tonumber
+
+local function linearshade(colorspace,domain,ca,cb,coordinates)
+ pdfcode(pdffinishtransparencycode())
+ nofshades = nofshades + 1
+ local name = format("MpsSh%s",nofshades)
+ lpdf.linearshade(name,domain,ca,cb,1,colorspace,coordinates)
+ extra_path_code, ignore_path = format("/%s sh Q",name), true
+ pdfcode("q /Pattern cs")
+end
+
+local function circularshade(colorspace,domain,ca,cb,coordinates)
+ pdfcode(pdffinishtransparencycode())
+ nofshades = nofshades + 1
+ local name = format("MpsSh%s",nofshades)
+ lpdf.circularshade(name,domain,ca,cb,1,colorspace,coordinates)
+ extra_path_code, ignore_path = format("/%s sh Q",name), true
+ pdfcode("q /Pattern cs")
+end
+
+handlers[30] = function(s)
+ linearshade("DeviceRGB", { tn(s[ 2]), tn(s[ 3]) },
+ { tn(s[ 5]), tn(s[ 6]), tn(s[ 7]) }, { tn(s[10]), tn(s[11]), tn(s[12]) },
+ { tn(s[ 8]), tn(s[ 9]), tn(s[13]), tn(s[14]) } )
+end
+
+handlers[31] = function(s)
+ circularshade("DeviceRGB", { tn(s[ 2]), tn(s[ 3]) },
+ { tn(s[ 5]), tn(s[ 6]), tn(s[ 7]) }, { tn(s[11]), tn(s[12]), tn(s[13]) },
+ { tn(s[ 8]), tn(s[ 9]), tn(s[10]), tn(s[14]), tn(s[15]), tn(s[16]) } )
+end
+
+handlers[32] = function(s)
+ linearshade("DeviceCMYK", { tn(s[ 2]), tn(s[ 3]) },
+ { tn(s[ 5]), tn(s[ 6]), tn(s[ 7]), tn(s[ 8]) }, { tn(s[11]), tn(s[12]), tn(s[13]), tn(s[14]) },
+ { tn(s[ 9]), tn(s[10]), tn(s[15]), tn(s[16]) } )
+end
+
+handlers[33] = function(s)
+ circularshade("DeviceCMYK", { tn(s[ 2]), tn(s[ 3]) },
+ { tn(s[ 5]), tn(s[ 6]), tn(s[ 7]), tn(s[ 8]) }, { tn(s[12]), tn(s[13]), tn(s[14]), tn(s[15]) },
+ { tn(s[ 9]), tn(s[10]), tn(s[11]), tn(s[16]), tn(s[17]), tn(s[18]) } )
+end
+
+handlers[34] = function(s) -- todo (after further cleanup)
+ linearshade("DeviceGray", { tn(s[ 2]), tn(s[ 3]) }, { 0 }, { 1 }, { tn(s[9]), tn(s[10]), tn(s[15]), tn(s[16]) } )
+end
+
+handlers[35] = function(s) -- todo (after further cleanup)
+ circularshade("DeviceGray", { tn(s[ 2]), tn(s[ 3]) }, { 0 }, { 1 }, { tn(s[9]), tn(s[10]), tn(s[15]), tn(s[16]) } )
+end
+
+-- not supported in mkiv , use mplib instead
+
+handlers[10] = function() logs.report("mptopdf","skipping special %s",10) end
+handlers[20] = function() logs.report("mptopdf","skipping special %s",20) end
+handlers[50] = function() logs.report("mptopdf","skipping special %s",50) end
+
+--end of not supported
+
+function mps.setrgbcolor(r,g,b) -- extra check
+ r, g = tonumber(r), tonumber(g) -- needed when we use lpeg
+ if r == 0.0123 and g < 0.1 then
+ g, b = round(g*10000), round(b*10000)
+ local s = specials[b]
+ local h = round(s[#s])
+ local handler = handlers[h]
+ if handler then
+ handler(s)
+ else
+ logs.report("mptopdf","unknown special handler %s (1)",h)
+ end
+ elseif r == 0.123 and g < 0.1 then
+ g, b = round(g*1000), round(b*1000)
+ local s = specials[b]
+ local h = round(s[#s])
+ local handler = handlers[h]
+ if handler then
+ handler(s)
+ else
+ logs.report("mptopdf","unknown special handler %s (2)",h)
+ end
+ else
+ pdfcode(pdffinishtransparencycode())
+ pdfcode(pdfrgbcode(mps.colormodel,r,g,b))
+ end
+end
+
+function mps.setcmykcolor(c,m,y,k)
+ pdfcode(pdffinishtransparencycode())
+ pdfcode(pdfcmykcode(mps.colormodel,c,m,y,k))
+end
+
+function mps.setgray(s)
+ pdfcode(pdffinishtransparencycode())
+ pdfcode(pdfgrayliteral(mps.colormodel,s))
+end
+
+function mps.specials(version,signal,factor) -- 2.0 123 1000
+end
+
+function mps.special(...) -- 7 1 0.5 1 0 0 1 3
+ local t = { ... }
+ local n = tonumber(t[#t-1])
+ specials[n] = t
+end
+
+function mps.begindata()
+end
+
+function mps.enddata()
+end
+
+function mps.showpage()
+end
+
+-- lpeg parser
+
+-- The lpeg based parser is rather optimized for the kind of output
+-- that MetaPost produces. It's my first real lpeg code, which may
+-- show. Because the parser binds to functions, we define it last.
+
+local lpegP, lpegR, lpegS, lpegC, lpegCc, lpegCs = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Cs
+
+local digit = lpegR("09")
+local eol = lpegS('\r\n')^1
+local sp = lpegP(' ')^1
+local space = lpegS(' \r\n')^1
+local number = lpegS('0123456789.-+')^1
+local nonspace = lpegP(1-lpegS(' \r\n'))^1
+
+local spec = digit^2 * lpegP("::::") * digit^2
+local text = lpegCc("{") * (
+ lpegP("\\") * ( (digit * digit * digit) / function(n) return "c" .. tonumber(n,8) end) +
+ lpegP(" ") / function(n) return "\\c32" end + -- never in new mp
+ lpegP(1) / function(n) return "\\c" .. byte(n) end
+ ) * lpegCc("}")
+local package = lpegCs(spec + text^0)
+
+function mps.fshow(str,font,scale) -- lpeg parser
+ mps.textext(font,scale,lpegmatch(package,str))
+end
+
+local cnumber = lpegC(number)
+local cstring = lpegC(nonspace)
+
+local specials = (lpegP("%%MetaPostSpecials:") * sp * (cstring * sp^0)^0 * eol) / mps.specials
+local special = (lpegP("%%MetaPostSpecial:") * sp * (cstring * sp^0)^0 * eol) / mps.special
+local boundingbox = (lpegP("%%BoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
+local highresboundingbox = (lpegP("%%HiResBoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
+
+local setup = lpegP("%%BeginSetup") * (1 - lpegP("%%EndSetup") )^1
+local prolog = lpegP("%%BeginProlog") * (1 - lpegP("%%EndProlog"))^1
+local comment = lpegP('%')^1 * (1 - eol)^1
+
+local curveto = ((cnumber * sp)^6 * lpegP("curveto") ) / mps.curveto
+local lineto = ((cnumber * sp)^2 * lpegP("lineto") ) / mps.lineto
+local rlineto = ((cnumber * sp)^2 * lpegP("rlineto") ) / mps.rlineto
+local moveto = ((cnumber * sp)^2 * lpegP("moveto") ) / mps.moveto
+local setrgbcolor = ((cnumber * sp)^3 * lpegP("setrgbcolor") ) / mps.setrgbcolor
+local setcmykcolor = ((cnumber * sp)^4 * lpegP("setcmykcolor") ) / mps.setcmykcolor
+local setgray = ((cnumber * sp)^1 * lpegP("setgray") ) / mps.setgray
+local newpath = ( lpegP("newpath") ) / mps.newpath
+local closepath = ( lpegP("closepath") ) / mps.closepath
+local fill = ( lpegP("fill") ) / mps.fill
+local stroke = ( lpegP("stroke") ) / mps.stroke
+local clip = ( lpegP("clip") ) / mps.clip
+local both = ( lpegP("gsave fill grestore")) / mps.both
+local showpage = ( lpegP("showpage") )
+local setlinejoin = ((cnumber * sp)^1 * lpegP("setlinejoin") ) / mps.setlinejoin
+local setlinecap = ((cnumber * sp)^1 * lpegP("setlinecap") ) / mps.setlinecap
+local setmiterlimit = ((cnumber * sp)^1 * lpegP("setmiterlimit") ) / mps.setmiterlimit
+local gsave = ( lpegP("gsave") ) / mps.gsave
+local grestore = ( lpegP("grestore") ) / mps.grestore
+
+local setdash = (lpegP("[") * (cnumber * sp^0)^0 * lpegP("]") * sp * cnumber * sp * lpegP("setdash")) / mps.setdash
+local concat = (lpegP("[") * (cnumber * sp^0)^6 * lpegP("]") * sp * lpegP("concat") ) / mps.concat
+local scale = ( (cnumber * sp^0)^6 * sp * lpegP("concat") ) / mps.concat
+
+local fshow = (lpegP("(") * lpegC((1-lpegP(")"))^1) * lpegP(")") * space * cstring * space * cnumber * space * lpegP("fshow")) / mps.fshow
+local fshow = (lpegP("(") * lpegCs( ( lpegP("\\(")/"\\050" + lpegP("\\)")/"\\051" + (1-lpegP(")")) )^1 )
+ * lpegP(")") * space * cstring * space * cnumber * space * lpegP("fshow")) / mps.fshow
+
+local setlinewidth_x = (lpegP("0") * sp * cnumber * sp * lpegP("dtransform truncate idtransform setlinewidth pop")) / mps.setlinewidth
+local setlinewidth_y = (cnumber * sp * lpegP("0 dtransform exch truncate exch idtransform pop setlinewidth") ) / mps.setlinewidth
+
+local c = ((cnumber * sp)^6 * lpegP("c") ) / mps.curveto -- ^6 very inefficient, ^1 ok too
+local l = ((cnumber * sp)^2 * lpegP("l") ) / mps.lineto
+local r = ((cnumber * sp)^2 * lpegP("r") ) / mps.rlineto
+local m = ((cnumber * sp)^2 * lpegP("m") ) / mps.moveto
+local vlw = ((cnumber * sp)^1 * lpegP("vlw")) / mps.setlinewidth
+local hlw = ((cnumber * sp)^1 * lpegP("hlw")) / mps.setlinewidth
+
+local R = ((cnumber * sp)^3 * lpegP("R") ) / mps.setrgbcolor
+local C = ((cnumber * sp)^4 * lpegP("C") ) / mps.setcmykcolor
+local G = ((cnumber * sp)^1 * lpegP("G") ) / mps.setgray
+
+local lj = ((cnumber * sp)^1 * lpegP("lj") ) / mps.setlinejoin
+local ml = ((cnumber * sp)^1 * lpegP("ml") ) / mps.setmiterlimit
+local lc = ((cnumber * sp)^1 * lpegP("lc") ) / mps.setlinecap
+
+local n = lpegP("n") / mps.newpath
+local p = lpegP("p") / mps.closepath
+local S = lpegP("S") / mps.stroke
+local F = lpegP("F") / mps.fill
+local B = lpegP("B") / mps.both
+local W = lpegP("W") / mps.clip
+local P = lpegP("P") / mps.showpage
+
+local q = lpegP("q") / mps.gsave
+local Q = lpegP("Q") / mps.grestore
+
+local sd = (lpegP("[") * (cnumber * sp^0)^0 * lpegP("]") * sp * cnumber * sp * lpegP("sd")) / mps.setdash
+local rd = ( lpegP("rd")) / mps.resetdash
+
+local s = ( (cnumber * sp^0)^2 * lpegP("s") ) / mps.scale
+local t = (lpegP("[") * (cnumber * sp^0)^6 * lpegP("]") * sp * lpegP("t") ) / mps.concat
+
+-- experimental
+
+local preamble = (
+ prolog + setup +
+ boundingbox + highresboundingbox + specials + special +
+ comment
+)
+
+local procset = (
+ lj + ml + lc +
+ c + l + m + n + p + r +
+ R + C + G +
+ S + F + B + W +
+ vlw + hlw +
+ Q + q +
+ sd + rd +
+ t + s +
+ fshow +
+ P
+)
+
+local verbose = (
+ curveto + lineto + moveto + newpath + closepath + rlineto +
+ setrgbcolor + setcmykcolor + setgray +
+ setlinejoin + setmiterlimit + setlinecap +
+ stroke + fill + clip + both +
+ setlinewidth_x + setlinewidth_y +
+ gsave + grestore +
+ concat + scale +
+ fshow +
+ setdash + -- no resetdash
+ showpage
+)
+
+-- order matters in terms of speed / we could check for procset first
+
+local captures_old = ( space + verbose + preamble )^0
+--~ local captures_new = ( space + procset + preamble + verbose )^0
+local captures_new = ( space + verbose + procset + preamble )^0
+
+local function parse(m_data)
+ if find(m_data,"%%%%BeginResource: procset mpost") then
+ lpegmatch(captures_new,m_data)
+ else
+ lpegmatch(captures_old,m_data)
+ end
+end
+
+-- main converter
+
+local a_colorspace = attributes.private('colormodel')
+
+function mptopdf.convertmpstopdf(name)
+ resetall()
+ local ok, m_data, n = resolvers.loadbinfile(name, 'tex') -- we need a binary load !
+ if ok then
+ mps.colormodel = tex.attribute[a_colorspace]
+ statistics.starttiming(mptopdf)
+ mptopdf.n = mptopdf.n + 1
+ pdfcode(format("\\letterpercent\\space mptopdf begin: n=%s, file=%s",mptopdf.n,file.basename(name)))
+ pdfcode("q 1 0 0 1 0 0 cm")
+ parse(m_data)
+ pdfcode(pdffinishtransparencycode())
+ pdfcode("Q")
+ pdfcode("\\letterpercent\\space mptopdf end")
+ resetall()
+ statistics.stoptiming(mptopdf)
+ else
+ commands.writestatus("mptopdf","file '%s' not found",name)
+ end
+end
+
+
+-- status info
+
+statistics.register("mps conversion time",function()
+ local n = mptopdf.n
+ if n > 0 then
+ return format("%s seconds, %s conversions", statistics.elapsedtime(mptopdf),n)
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/meta-pdf.mkii b/tex/context/base/meta-pdf.mkii
new file mode 100644
index 000000000..2099b0d37
--- /dev/null
+++ b/tex/context/base/meta-pdf.mkii
@@ -0,0 +1,2761 @@
+%D \module
+%D [ file=meta-pdf,
+%D version=2006.06.07,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Conversion to \PDF,
+%D author=Hans Hagen \& others (see text),
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Formerly known as supp-pdf.tex and supp-mpe.tex.
+
+%D We will clean up the color mess later.
+
+%D These macros are written as generic as possible. Some
+%D general support macro's are loaded from a small module
+%D especially made for non \CONTEXT\ use. In this module I
+%D use a matrix transformation macro written by Tanmoy
+%D Bhattacharya. Thanks to extensive testing by Sebastian
+%D Ratz I was able to complete this module within reasonable
+%D time. This module has support for \METAPOST\ extensions
+%D built in.
+%D
+%D Daniel H. Luecking came up with a better (more precise)
+%D transformation method. You can recognize his comment by
+%D his initials. (We keep the old code around because it's a
+%D nice illustration on how a module like this evolves.)
+
+% Beware, we cannot use 0pt here by defaukt since it may be
+% defined in the range \dimen 0 - 20 which we happen to use
+% as scratch registers; for this reason we start allocating
+% scratch registers > 20
+
+%D This module handles some \PDF\ conversion and insertions
+%D topics. By default, the macros use the \PDFTEX\ primitive
+%D \type{\pdfliteral} when available. Since \PDFTEX\ is now the
+%D default engine for \TEX\ distributions, we need a more complex
+%D test.
+
+\writestatus{loading}{MetaPost Graphics / MPS to PDF}
+
+\unprotect
+
+\ifx\PDFcode \undefined \let\PDFcode \gobbleoneargument \fi
+\ifx\PDFcomment\undefined \def\PDFcomment#1{\PDFcode{\letterpercent\space#1}} \fi
+
+%D First we define a handy constant:
+
+\bgroup \catcode`\%=\@@other \xdef\letterpercent{\string%} \egroup
+
+%D \macros
+%D {pdfimage,pdfimages,pdfclippedimage}
+%D
+%D Starting with pdftex version 14, images are included more
+%D natural to the form embedding. This enables alternative
+%D images to be embedded.
+%D
+%D \starttyping
+%D \pdfimage {file}
+%D \pdfimages {high res file} {low res file}
+%D \stoptyping
+%D
+%D The first one replaces the pre||version||14 original,
+%D while the latter provides alternative images.
+%D
+%D The next macro is dedicated to Maarten Gelderman, who
+%D needed to paste prepared \PDF\ pages into conference
+%D proceedings.
+%D
+%D \starttyping
+%D \pdfclippedimage {file} {l} {r} {t} {b}
+%D \stoptyping
+
+\ifx\pdftexversion\undefined \else \ifnum\pdftexversion>13 % still relevant?
+
+ \def\pdfimage#1#%
+ {\dopdfimage{#1}}
+
+ \def\dopdfimage#1#2%
+ {\immediate\pdfximage#1{#2}%
+ \pdfrefximage\pdflastximage}
+
+ \def\pdfimages#1#%
+ {\dopdfimages{#1}}
+
+ \def\dopdfimages#1#2#3%
+ {\immediate\pdfximage#1{#2}%
+ \immediate\pdfobj{[ << /Image \the\pdflastximage\space0 R /DefaultForPrinting true >> ]}%
+ \immediate\pdfximage#1 attr {/Alternates \the\pdflastobj\space0 R}{#3}%
+ \pdfrefximage\pdflastximage}
+
+ \def\pdfclippedimage#1#% specs {file}{left}{right}{top}{bottom}
+ {\dopdfclippedimage{#1}}
+
+ \def\dopdfclippedimage#1#2#3#4#5#6%
+ {\bgroup
+ \pdfximage#1{#2}%
+ \setbox\scratchbox\hbox{\pdfrefximage\pdflastximage}%
+ \hsize\dimexpr\wd\scratchbox-#3-#4\relax
+ \vsize\dimexpr\ht\scratchbox-#5-#6\relax
+ \setbox\scratchbox\vbox to \vsize
+ {\vskip-#5\hbox to \hsize{\hskip-#3\box\scratchbox\hss}}%
+ \pdfxform\scratchbox
+ \pdfrefxform\pdflastxform
+ \egroup}
+
+\fi \fi
+
+%D \macros
+%D {convertMPtoPDF}
+%D
+%D The next set of macros implements \METAPOST\ to \PDF\
+%D conversion. The traditional method is in the MkII file.
+
+%D The main conversion command is:
+%D
+%D \starttyping
+%D \convertMPtoPDF {filename} {x scale} {y scale}
+%D \stoptyping
+%D
+%D The dimensions are derived from the bounding box. So we
+%D only have to say:
+%D
+%D \starttyping
+%D \convertMPtoPDF{mp-pra-1.eps}{1}{1}
+%D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5}
+%D \stoptyping
+
+%D \macros
+%D {makeMPintoPDFobject,lastPDFMPobject}
+%D
+%D For experts there are a few more options. When attributes
+%D are to be added, the code must be embedded in an object
+%D accompanied with the appropriate directives. One can
+%D influence this process with \type {\makeMPintoPDFobject}.
+%D
+%D This option defaults to~0, because \CONTEXT\ takes care
+%D of objects at another level, which saves some bytes.
+%D
+%D \starttabulate[|l|l|p|]
+%D \NC 0 \NC never \NC don't use an object \NC\NR
+%D \NC 1 \NC always \NC always use an object \NC\NR
+%D \NC 2 \NC optional \NC use object when needed \NC\NR
+%D \stoptabulate
+%D
+%D The last object number used is avaliable in the macro
+%D \type {\lastPDFMPobject}.
+
+\ifx\makeMPintoPDFobject \undefined \chardef\makeMPintoPDFobject \zerocount \fi
+\ifx\blackoutMPgraphic \undefined \chardef\blackoutMPgraphic \plusone \fi
+\ifx\everyMPtoPDFconversion\undefined \newtoks\everyMPtoPDFconversion \fi
+
+\let\lastPDFMPobject \!!zerocount
+\let\currentPDFresources\empty
+\let\setMPextensions \relax
+
+\def\PDFMPformoffset
+ {\ifx\objectoffset\undefined\zeropoint\else\objectoffset\fi}
+
+\def\resetMPvariables#1#2#3%
+ {\global\let\MPwidth \!!zeropoint
+ \global\let\MPheight\!!zeropoint
+ \global\let\MPllx \!!zerocount
+ \global\let\MPlly \!!zerocount
+ \global\let\MPurx \!!zerocount
+ \global\let\MPury \!!zerocount
+ \xdef\MPxscale {#2}\ifx\MPxscale\empty\let\MPxscale\!!plusone\fi
+ \xdef\MPyscale {#3}\ifx\MPyscale\empty\let\MPyscale\!!plusone\fi
+ \xdef\MPfilename {#1}}
+
+%D The main macro:
+
+\def\convertMPtoPDF#1#2#3%
+ {\resetMPvariables{#1}{#2}{#3}%
+ \vbox\bgroup
+ \forgetall
+ \offinterlineskip
+ \ifx\pdfdecimaldigits\undefined\else \pdfdecimaldigits=5 \fi % new
+ \global\let\MPheight\!!zeropoint
+ \global\let\MPwidth \!!zeropoint
+ \setbox\scratchbox\vbox\bgroup
+ \message{[MP to PDF]}%
+ \startMPresources
+ \PDFcomment{mps begin}%
+ \PDFcode{q}%
+ \PDFcode{1 0 0 1 0 0 cm}%
+ \ifcase\blackoutMPgraphic\or\PDFcode{0 g 0 G}\fi
+ \doprocessMPtoPDFfile}
+
+\def\processMPtoPDFfile#1#2#3% obsolete
+ {\resetMPvariables{#1}{#2}{#3}%
+ \bgroup
+ \let\finishMPgraphic\egroup
+ \doprocessMPtoPDFfile}
+
+\def\doprocessMPtoPDFfile
+ {\setMPspecials
+ \setMPextensions
+ \the\everyMPtoPDFconversion
+ \catcode`\^^M=\@@endofline
+ \startMPscanning
+ \let\do\empty
+ \donefalse
+ \let\handleMPsequence\dohandleMPsequence
+ \input\MPfilename\relax}
+
+\def\finishMPgraphic
+ {\PDFcode{Q}%
+ \PDFcomment{mps end}%
+ \stopMPresources
+ \egroup
+ \setbox\scratchbox\hbox\bgroup
+ \hskip-\MPllx\onebasepoint
+ \raise-\MPlly\onebasepoint
+ \box\scratchbox
+ \egroup
+ \setbox\scratchbox\vbox to \MPheight\bgroup
+ \vfill
+ \hsize\MPwidth
+ \smashbox\scratchbox
+ \box\scratchbox
+ \egroup
+ \wd\scratchbox\MPwidth
+ \ht\scratchbox\MPheight
+ \dopackageMPgraphic\scratchbox
+ \egroup
+ \endinput}
+
+%D A common hook.
+
+\let\MPfshowcommand\empty
+
+%D Objects.
+
+\def\dopackageMPgraphic#1% #1 = boxregister
+ {\ifcase\makeMPintoPDFobject\or\or\ifx\currentPDFresources\empty\else
+ % an existing value of 2 signals object support (set elsewhere)
+ \chardef\makeMPintoPDFobject\plusone
+ \fi\fi
+ \ifcase\makeMPintoPDFobject
+ \box#1%
+ \or
+ \scratchdimen\PDFMPformoffset\relax
+ \ifdim\scratchdimen>\zeropoint % compensate for error
+ \setbox#1\vbox spread 2\scratchdimen
+ {\forgetall\vss\hbox spread 2\scratchdimen{\hss\box#1\hss}\vss}%
+ \fi
+ \setMPPDFobject{\currentPDFresources}{#1}%
+ \ifdim\scratchdimen>\zeropoint % compensate for error
+ \vbox to \MPheight
+ {\forgetall\vss\hbox to \MPwidth{\hss\getMPPDFobject\hss}\vss}%
+ \else
+ \getMPPDFobject
+ \fi
+ \global\let\currentPDFresources\empty
+ \else
+ \box#1%
+ \fi}
+
+\def\setMPPDFobject#1#2% resources boxnumber
+ {\ifx\pdfxform\undefined
+ \def\getMPPDFobject{\box#2}%
+ \else\ifx\pdftexversion\undefined
+ \def\getMPPDFobject{\box#2}%
+ \else\ifnum\pdftexversion<14
+ \def\getMPPDFobject{\box#2}%
+ \else
+ \ifx\everyPDFxform\undefined\else\the\everyPDFxform\fi
+ \immediate\pdfxform resources{#1}#2%
+ \edef\getMPPDFobject{\noexpand\pdfrefxform\the\pdflastxform}%
+ \fi\fi\fi}
+
+\let\getMPPDFobject\relax
+
+%D \macros
+%D {deleteMPgraphic,
+%D startMPresources,
+%D stopMPresources}
+
+\ifx\deleteMPgraphic\undefined
+ \def\deleteMPgraphic#1{}
+\fi
+
+\ifx\startMPresources\undefined
+ \let\startMPresources\relax
+ \let\stopMPresources\relax
+\fi
+
+%D We implement extensions by using the \METAPOST\ special
+%D mechanism. Opposite to \TEX's specials, the \METAPOST\ ones
+%D are flushed before or after the graphic data, but thereby
+%D are no longer connected to a position.
+%D
+%D We implement specials by overloading the \type {fill}
+%D operator. By counting the fills, we can let the converter
+%D treat the appropriate fill in a special way. The
+%D specification of the speciality can have two forms,
+%D determined by the setting of a boolean variable:
+%D
+%D \starttyping
+%D _inline_specials_ := false ; % comment like code (default)
+%D _inline_specials_ := true ; % command like code
+%D \stoptyping
+%D
+%D When the specification is embedded as comment, it looks
+%D like:
+%D
+%D \starttyping
+%D %%MetaPostSpecial
+%D \stoptyping
+%D
+%D The in||line alternative is more tuned for \POSTSCRIPT,
+%D since it permits us to define a macro \type {special}.
+%D
+%D \starttyping
+%D inline : special
+%D \stoptyping
+%D
+%D The \type {identifier} determines what to do, and the data
+%D can be used to accomplish this. A type~2 shading function
+%D has identifier~2. Alltogether, the number of parameters is
+%D specified in \type {size}. The \type {number} is the number
+%D of the fill that needs the special treatment. For a type~2
+%D and~3 shaded fill, the datablock contains the following
+
+%D data:
+%D
+%D \starttyping
+%D from to n inner_r g b x y outer_r g b x y
+%D from to n inner_r g b x y radius outer_r g b x y radius
+%D \stoptyping
+
+\newconditional\manyMPspecials \settrue\manyMPspecials
+
+%D In case of \PDF, we need to prepare resourcs.
+
+\newtoks\MPstartresources
+\newtoks\MPstopresources
+
+\def\startMPresources
+ {\the\MPstartresources}
+
+\def\stopMPresources
+ {\the\MPstopresources}
+
+%D Some day we may consider collecting local resources.
+
+\appendtoks
+ \global\let\currentPDFresources\empty % kind of redundant
+\to \MPstartresources
+
+% \appendtoks
+% \collectPDFresources
+% \global\let\currentPDFresources\collectedPDFresources
+% \to \MPstopresources
+
+\appendtoksonce
+ \the\everyPDFxform
+\to \MPstopresources
+
+%D Since colors are not subjected to transformations, we can
+%D only use colors as signal. In our case, we use a dummy colored
+%D path with a red color component of \type {0.n}, so \type
+%D {0.001} is the first path and \type {0.010} the tenth. Since
+%D \METAPOST strips trailing zeros, we have to padd the string.
+
+\newif\ifMPcmykcolors
+\newif\ifMPspotcolors
+
+\def\dohandleMPrgb #1#2#3{\revokeMPtransparencyspecial\execcolorR #1:#2:#3:0:0\od}
+\def\dohandleMPcmyk#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
+\def\dohandleMPgray #1{\revokeMPtransparencyspecial\execcolorS #1:0:0\od}
+\def\dohandleMPspot#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}
+
+%D Specials:
+
+\settrue \manyMPspecials \newcount\nofMParguments \let\extraMPpathcode\empty
+
+\def\@@MP {@@MP}
+\def\@@MPSK{@MPSK@}
+
+\def\MPspecial{\@@MPSK\@@MPSK\gMPs\nofMParguments}
+
+\def\defineMPspecial#1#2%
+ {\setvalue{\@@MPSK\@@MPSK#1}{#2}}
+
+%D Special number~1 is dedicated to \CMYK\ support. If you
+%D want to know why: look at this:
+%D
+%D \startbuffer[mp]
+%D fill fullcircle xyscaled (3cm,1cm) withcolor \MPcolor{test} ;
+%D \stopbuffer
+%D
+%D \startbuffer[cmyk]
+%D \startcombination[4*1]
+%D {\definecolor[test][c=1,y=.3,k=.3] \processMPbuffer[mp]} {c=1 y=.3 k=.3}
+%D {\definecolor[test][c=.9,y=.15] \processMPbuffer[mp]} {c=.9 y=.15}
+%D {\definecolor[test][c=.25,y=.8] \processMPbuffer[mp]} {c=.25 y=.8}
+%D {\definecolor[test][c=.45,y=.1] \processMPbuffer[mp]} {c=.45 y=.1}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \placefigure
+%D {\CMYK\ support disabled,
+%D conversion to \RGB.}
+%D {\setupcolors[cmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no support in \METAPOST.}
+%D {\setupcolors[cmyk=ja,mpcmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no conversion to \RGB,
+%D support in \METAPOST}
+%D {\setupcolors[cmyk=ja,state=start]\getbuffer[cmyk]}
+
+\defineMPspecial{1}
+ {\ifMPcmykcolors
+ \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPcmykcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
+ \fi}
+
+\defineMPspecial{2}
+ {\ifMPspotcolors
+ \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPspotcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
+% \checkMPspot{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}%
+ \fi}
+
+% \def\checkMPspot#1#2#3#4%
+% {\expanded{\resolveMPspotcolor#1 #2 #3 #4}\end
+% \ifx\MPspotspace\MPresolvedspace
+% \edef\MPspotspacespec{/\MPspotspace\space}%
+% \doifinstringelse\MPspotspacespec\currentMPcolorspaces
+% \donothing\registerMPcolorspace
+% \fi}
+
+\let\revokeMPtransparencyspecial\relax
+
+\def\dohandleMPrgbcolor #1#2#3{\revokeMPtransparencyspecial\execcolorR #1:#2:#3:0:0\od}
+\def\dohandleMPcmykcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
+\def\dohandleMPgraycolor #1{\revokeMPtransparencyspecial\execcolorS #1:0:0\od}
+\def\dohandleMPspotcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}
+
+%D Transparency support used specials 60 (rgb) and 61
+%D (cmyk).
+%D
+%D \startbufferFshade
+
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor transparent(1,.5,yellow) ;
+%D fill p rotated 210 withcolor transparent(1,.5,green) ;
+%D fill p rotated 330 withcolor transparent(1,.5,blue) ;
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+%D
+%D One can also communicate colors between \CONTEXT\ and
+%D \METAPOST:
+%D
+%D \startbuffer
+%D \definecolor[tcyan] [c=1,k=.2,t=.5]
+%D \definecolor[tmagenta][m=1,k=.2,t=.5]
+%D \definecolor[tyellow] [y=1,k=.2,t=.5]
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor \MPcolor{tcyan} ;
+%D fill p rotated 210 withcolor \MPcolor{tmagenta} ;
+%D fill p rotated 330 withcolor \MPcolor{tyellow} ;
+%D \stopbuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+%D
+%D We save all the three components needed in one macro,
+%D just to save hash space.
+
+\def\dohandleMPrgbtransparency #1#2#3#4#5{\execcolorR #1:#2:#3:#4:#5\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+\def\dohandleMPcmyktransparency#1#2#3#4#5#6{\execcolorC#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+\def\dohandleMPgraytransparency #1#2#3{\execcolorS #1:#2:#3\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+\def\dohandleMPspottransparency#1#2#3#4#5#6{\execcolorP#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+
+\def\dorevokeMPtransparencyspecial
+ {\PDFcode{\PDFtransparencyresetidentifier\space gs}%
+ \let\revokeMPtransparencyspecial\relax}
+
+\defineMPspecial{3} % rgb
+ {\setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPrgbtransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs1}{\gMPs2}}}
+
+\defineMPspecial{4} % cmyk
+ {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPcmyktransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}}
+
+\defineMPspecial{5} % spot
+ {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPspottransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}%
+ }%\checkMPspot{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}
+
+%D Shading is an example of a more advanced graphic feature,
+%D but users will seldom encounter those complications. Here
+%D we only show a few simple examples, but many other
+%D alternatives are possible by setting up the functions built
+%D in \PDF\ in the appropriate way.
+%D
+%D Shading has to do with interpolation between two or more
+%D points or user supplied ranges. In \PDF, the specifications
+%D of a shade has to be encapsulated in objects and passed on
+%D as resources. This is a \PDF\ level 1.3. feature. One can
+%D simulate three dimensional shades as well and define simple
+%D functions using a limited set of \POSTSCRIPT\ primitives.
+%D Given the power of \METAPOST\ and these \PDF\ features, we
+%D can achieve superb graphic effects.
+%D
+%D Since everything is hidden in \TEX\ and \METAPOST\ graphics,
+%D we can stick to high level \CONTEXT\ command, as shown in
+%D the following exmples.
+%D
+%D \startbuffer
+%D \startuniqueMPgraphic{CircularShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D circular_shade(p,0,.2red,.9red) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{LinearShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,0,.2blue,.9blue) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{DuotoneShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,2,.5green,.5red) ;
+%D \stopuniqueMPgraphic
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D These graphics can be hooked into the overlay mechanism,
+%D which is available in many commands.
+%D
+%D \startbuffer
+%D \defineoverlay[demo 1][\uniqueMPgraphic{CircularShade}]
+%D \defineoverlay[demo 2][\uniqueMPgraphic {LinearShade}]
+%D \defineoverlay[demo 3][\uniqueMPgraphic {DuotoneShade}]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D These backgrounds can for instance be applied to \type
+%D {\framed}:
+%D
+%D \startbuffer
+%D \setupframed[width=3cm,height=2cm,frame=off]
+%D \startcombination[3*1]
+%D {\framed[backgroundachtergrond=demo 1]{\bfd \white Demo 1}} {}
+%D {\framed[backgroundachtergrond=demo 2]{\bfd \white Demo 2}} {}
+%D {\framed[backgroundachtergrond=demo 3]{\bfd \white Demo 3}} {}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D There are a few more alternatives, determined by the second
+%D parameter passed to \type {circular_shade} and alike.
+%D
+%D \def\SomeShade#1#2#3#4#5%
+%D {\startuniqueMPgraphic{Shade-#1}
+%D width := \overlaywidth ;
+%D height := \overlayheight ;
+%D path p ; p := unitsquare xscaled width yscaled height ;
+%D #2_shade(p,#3,#4,#5) ;
+%D \stopuniqueMPgraphic
+%D \defineoverlay[Shade-#1][\uniqueMPgraphic{Shade-#1}]%
+%D \framed[backgroundachtergrond=Shade-#1,width=2cm,height=2cm,frame=off]{}}
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{10}{circular}{0}{.3blue}{.9blue}} {circular 0}
+%D {\SomeShade{11}{circular}{1}{.3blue}{.9blue}} {circular 1}
+%D {\SomeShade{12}{circular}{2}{.3blue}{.9blue}} {circular 2}
+%D {\SomeShade{13}{circular}{3}{.3blue}{.9blue}} {circular 3}
+%D {\SomeShade{14}{circular}{4}{.3blue}{.9blue}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \blank
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{20}{circular}{0}{.9green}{.3green}} {circular 0}
+%D {\SomeShade{21}{circular}{1}{.9green}{.3green}} {circular 1}
+%D {\SomeShade{22}{circular}{2}{.9green}{.3green}} {circular 2}
+%D {\SomeShade{23}{circular}{3}{.9green}{.3green}} {circular 3}
+%D {\SomeShade{24}{circular}{4}{.9green}{.3green}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \blank
+%D
+%D \startlinecorrection
+%D \startcombination[4*1]
+%D {\SomeShade{30}{linear}{0}{.3red}{.9red}} {linear 0}
+%D {\SomeShade{31}{linear}{1}{.3red}{.9red}} {linear 1}
+%D {\SomeShade{32}{linear}{2}{.3red}{.9red}} {linear 2}
+%D {\SomeShade{33}{linear}{3}{.3red}{.9red}} {linear 3}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D These macros closely cooperate with the \METAPOST\ module
+%D \type {mp-spec.mp}, which is part of the \CONTEXT\
+%D distribution.
+%D
+%D The low level (\PDF) implementation is based on the \TEX\
+%D based \METAPOST\ to \PDF\ converter. Shading is supported
+%D by overloading the \type {fill} operator as implemented
+%D earlier. In \PDF\ type~2 and~3 shading functions are
+%D specified in terms of:
+%D
+%D \starttabulate[|Tl|l|]
+%D \NC /Domain \NC sort of meeting range \NC \NR
+%D \NC /C0 \NC inner shade \NC \NR
+%D \NC /C1 \NC outer shade \NC \NR
+%D \NC /N \NC smaller values, bigger inner circles \NC \NR
+%D \stoptabulate
+
+\newcount\currentPDFshade % 0 % global (document wide) counter
+
+% \def\dosetMPsomePDFshade#1#2% generic but needs refs
+% {\global\advance\currentPDFshade \plusone
+% \doPDFdictionaryobject{FDF}{ftn:Sh:\the\currentPDFshade}
+% {/FunctionType 2
+% /Domain [\gMPs1 \gMPs2]
+% /C0 [\MPshadeA]
+% /C1 [\MPshadeB]
+% /N \gMPs3}%
+% \doPDFgetobjectreference{FDF}{ftn:Sh:\the\currentPDFshade}\PDFobjectreference
+% \doPDFdictionaryobject{FDF}{obj:Sh:\the\currentPDFshade}
+% {/ShadingType #1
+% /ColorSpace /\MPresolvedspace
+% /Function \PDFobjectreference\space
+% /Coords [\MPshadeC]
+% /Extend [true true]}%
+% \doPDFgetobjectreference{FDF}{obj:Sh:\the\currentPDFshade}\PDFobjectreference
+% \appendtoPDFdocumentshades{/Sh\the\currentPDFshade\space\PDFobjectreference}%
+% \setxvalue{\@@MPSK#2}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}
+
+\def\dosetMPsomePDFshade#1#2%
+ {\immediate\pdfobj
+ {<>}%
+ \immediate\pdfobj
+ {<>}%
+ \global\advance\currentPDFshade \plusone
+ \appendtoPDFdocumentshades{/Sh\the\currentPDFshade\space\the\pdflastobj\space0 R }%
+ \setxvalue{\@@MPSK#2}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}
+
+\def\dosetMPlinearshade {\dosetMPsomePDFshade2}% #1
+\def\dosetMPcircularshade{\dosetMPsomePDFshade3}% #1
+
+\defineMPspecial{30}
+ {\expanded{\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
+ \expanded{\resolveMPrgbcolor{\gMPs{9}}{\gMPs{10}}{\gMPs{11}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs{12} \gMPs{13}}%
+ \dosetMPlinearshade{\gMPs{14}}}
+
+\defineMPspecial{31}
+ {\expanded{\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
+ \expanded{\resolveMPrgbcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs9 \gMPs{13} \gMPs{14} \gMPs{15}}%
+ \dosetMPcircularshade{\gMPs{16}}}
+
+\defineMPspecial{32}
+ {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \expanded{\resolveMPcmykcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
+ \dosetMPlinearshade{\gMPs{16}}}
+
+\defineMPspecial{33}
+ {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \expanded{\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
+ \dosetMPcircularshade{\gMPs{18}}}
+
+\defineMPspecial{34}
+ {\expanded{\resolveMPspotcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \expanded{\resolveMPspotcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
+ \dosetMPlinearshade{\gMPs{16}}}
+
+\defineMPspecial{35}
+ {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \expanded{\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
+ \dosetMPcircularshade{\gMPs{18}}}
+
+
+\newconditional\ignoreMPpath
+
+\def\dohandleMPshade#1%
+ {\revokeMPtransparencyspecial
+ \settrue\ignoreMPpath
+ \def\extraMPpathcode{/Sh#1 sh Q}%
+ \chardef\finiMPpath\zerocount
+ \PDFcode{q /Pattern cs}}
+
+%D Figure inclusion is kind of strange to \METAPOST, but when
+%D Santiago Muelas started discussing this with me, I was able
+%D to cook up a solution using specials.
+
+\defineMPspecial{10}
+ {\setxvalue{\@@MPSK\gMPs8}%
+ {\noexpand\handleMPfigurespecial{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}{\gMPs8}}}
+
+\def\handleMPfigurespecial#1#2#3#4#5#6#7#8% todo : combine with ext fig
+ {\global\letvalue{\@@MPSK#8}\empty
+ \vbox to \zeropoint
+ {\vss
+ \hbox to \zeropoint
+ {\ifcase\pdfoutput\or % will be hooked into the special driver
+ \doiffileelse{#7}
+ {\doifundefinedelse{mps:x:#7}
+ {\immediate\pdfximage\!!width\onebasepoint\!!height\onebasepoint{#7}%
+ \setxvalue{mps:x:#7}{\pdfrefximage\the\pdflastximage}}%
+ {\message{[reusing figure #7]}}%
+ \PDFcode{q #1 #2 #3 #4 #5 #6 cm}%
+ \rlap{\getvalue{mps:x:#7}}%
+ \PDFcode{Q}}
+ {\message{[unknown figure #7]}}%
+ \fi
+ \hss}}}
+
+%D An example of using both special features is the
+%D following.
+%D
+%D \starttyping
+%D \startMPpage
+%D externalfigure "hakker1b.png" scaled 22cm rotated 10 shifted (-2cm,0cm);
+%D externalfigure "hakker1b.png" scaled 10cm rotated -10 ;
+%D externalfigure "hakker1b.png" scaled 7cm rotated 45 shifted (8cm,12cm) ;
+%D path p ; p := unitcircle xscaled 15cm yscaled 20cm;
+%D path q ; q := p rotatedaround(center p,90) ;
+%D path r ; r := buildcycle(p,q) ; clip currentpicture to r ;
+%D path s ; s := boundingbox currentpicture enlarged 5mm ;
+%D picture c ; c := currentpicture ; currentpicture := nullpicture ;
+%D circular_shade(s,0,.2red,.9red) ;
+%D addto currentpicture also c ;
+%D \stopMPpage
+%D \stoptyping
+
+%D This is some experimental hyperlink driver that I wrote
+%D for Mark Wicks.
+
+\defineMPspecial{20}
+ {\setxvalue{\@@MPSK\gMPs6}%
+ {\noexpand\handleMPhyperlink{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}}
+
+\def\handleMPhyperlink#1#2#3#4#5#6%
+ {\global\letvalue{\@@MPSK#6}\empty
+ \setbox\scratchbox\hbox
+ {\setbox\scratchbox\null
+ \wd\scratchbox\dimexpr-#1\onebasepoint+#3\onebasepoint\relax
+ \ht\scratchbox\dimexpr-#2\onebasepoint+#4\onebasepoint\relax
+ \incolorfalse
+ \gotobox{\box\scratchbox}[#5]}%
+ \setbox\scratchbox\hbox
+ {\hskip\dimexpr\MPxoffset\onebasepoint+#1\onebasepoint\relax
+ \raise\dimexpr\MPyoffset\onebasepoint+#2\onebasepoint\relax
+ \box\scratchbox}%
+ \smashbox\scratchbox
+ \box\scratchbox}
+
+%D This special (number 50) passes positions to a tex file.
+%D This method uses a two||pass approach an (mis|)|used the
+%D context positioning macros. In \type {core-pos} we will
+%D implement the low level submacro needed.
+%D
+%D \startbuffer
+%D \definelayer[test]
+%D
+%D \setlayer
+%D [test]
+%D [x=\MPx{somepos-1},y=\MPy{somepos-1}]
+%D {Whatever we want here!}
+%D
+%D \setlayer
+%D [test]
+%D [x=\MPx{somepos-2},y=\MPy{somepos-2}]
+%D {Whatever we need there!}
+%D
+%D \startuseMPgraphic{oeps}
+%D draw fullcircle scaled 6cm withcolor red ;
+%D register ("somepos-1",1cm,2cm,center currentpicture) ;
+%D register ("somepos-2",4cm,3cm,(-1cm,-2cm)) ;
+%D \stopuseMPgraphic
+%D
+%D \framed[background=test,offset=overlay]{\useMPgraphic{oeps}}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Here the width and height are not realy used, but one can
+%D imagine situations where tex has to work with values
+%D calculated by \METAPOST.
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D Later we will implement a more convenient macro:
+%D
+%D \starttyping
+%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
+%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
+%D \stoptyping
+
+\defineMPspecial{50} % x y width height label
+ {\dosavepositionwhd
+ {\gMPs5}%
+ {0}%
+ {\the\dimexpr-\MPllx\onebasepoint+\gMPs1\onebasepoint\relax}
+ {\the\dimexpr\gMPs2\onebasepoint-\scratchdimen+\MPury\onebasepoint\relax}%
+ {\the\dimexpr\gMPs3\onebasepoint\relax}%
+ {\the\dimexpr\gMPs4\onebasepoint\relax}%
+ {0pt}}
+
+%D A few auxiliary macros. This will move to colo-ini.
+
+\def\MPgrayspace{DeviceGray}
+\def\MPrgbspace {DeviceRGB}
+\def\MPcmykspace{DeviceCMYK}
+\let\MPspotspace\MPgrayspace
+
+\def\MPcmykBlack{0 0 0 0}
+\def\MPcmykWhite{0 0 0 1}
+
+\def\startMPcolorresolve
+ {\bgroup
+ \def\dostartgraycolormode##1%
+ {\global\let\MPresolvedspace\MPgrayspace
+ \xdef\MPresolvedcolor{##1}}%
+ \def\dostartrgbcolormode ##1##2##3%
+ {\global\let\MPresolvedspace\MPrgbspace
+ \xdef\MPresolvedcolor{##1 ##2 ##3}}%
+ \def\dostartcmykcolormode##1##2##3##4%
+ {\global\let\MPresolvedspace\MPcmykspace
+ \xdef\MPresolvedcolor{##1 ##2 ##3 ##4}}%
+ \def\dostartspotcolormode##1##2%
+ {\global\let\MPspotspace\empty % left over ?
+ \xdef\MPresolvedspace{##1}%
+ \xdef\MPresolvedcolor{##2}%
+ \global\let\MPspotspace\MPresolvedspace}% signal
+ \dostartgraycolormode\!!zerocount} % kind of hackery initialization
+
+\let\stopMPcolorresolve\egroup
+
+\def\resolveMPrgbcolor#1#2#3\to#4%
+ {\startMPcolorresolve
+ \execcolorR#1:#2:#3:0:0\od
+ \stopMPcolorresolve
+ \let#4\MPresolvedcolor}
+
+\def\resolveMPcmykcolor#1#2#3#4\to#5%
+ {\startMPcolorresolve
+ \execcolorC#1:#2:#3:#4:0:0\od
+ \stopMPcolorresolve
+ \let#5\MPresolvedcolor}
+
+\def\resolveMPgraycolor#1\end\to#2%
+ {\startMPcolorresolve
+ \execcolorS#1:0:0\od
+ \stopMPcolorresolve
+ \let#2\MPresolvedcolor}
+
+\def\resolveMPspotcolor#1#2#3#4\end\to#5%
+ {\startMPcolorresolve
+ \ifnum#2>\plusone
+ \checkmultitonecolor{#1}%
+ \fi
+ \execcolorP#1:#2:#3:#4:0:0\od
+ \stopMPcolorresolve
+ \let#5\MPresolvedcolor}
+
+%D \macros
+%D {dogetPDFmediabox}
+%D
+%D The next macro can be used to find the mediabox of a \PDF\
+%D illustration.
+%D
+%D \starttyping
+%D \dogetPDFmediabox
+%D {filename}
+%D {new dimen}{new dimen}{new dimen}{new dimen}
+%D \stoptyping
+%D
+%D Beware of dimen clashes: this macro uses the 5~default
+%D scratch registers! When no file or mediabox is found, the
+%D dimensions are zeroed.
+
+\def\dogetPDFmediabox#1#2#3#4#5%
+ {\bgroup
+ \def\PDFxscale{1}%
+ \def\PDFyscale{1}%
+ \uncatcodespecials
+ \endlinechar\minusone
+ \def\checkPDFtypepage##1/Type /Page##2##3\done%
+ {\ifx##2\relax
+ \else\if##2s% accept /Page and /Pages
+ \let\doprocessPDFline\findPDFmediabox
+ \else
+ \let\doprocessPDFline\findPDFmediabox
+ \fi\fi}%
+ \def\findPDFtypepage
+ {\expandafter\checkPDFtypepage\fileline/Type /Page\relax\done}%
+ \def\checkPDFmediabox##1/MediaBox##2##3\done%
+ {\ifx##2\relax \else
+ \setPDFmediabox##2##3\done
+ \fileprocessedtrue
+ \fi}%
+ \def\findPDFmediabox
+ {\expandafter\checkPDFmediabox\fileline/MediaBox\relax\done}%
+ \let\doprocessPDFline\findPDFtypepage
+ \doprocessfile\scratchread{#1}\doprocessPDFline
+ \egroup
+ \ifx\PDFxoffset\undefined
+ #2=\zeropoint
+ #3=\zeropoint
+ #4=\zeropoint
+ #5=\zeropoint
+ \else
+ #2=\PDFxoffset\onebasepoint
+ #3=\PDFyoffset\onebasepoint
+ #4=\PDFwidth
+ #5=\PDFheight
+ \fi}
+
+\def\setPDFboundingbox#1#2#3#4#5#6%
+ {\dimen0=#1\dimen0=#5\dimen0
+ \ScaledPointsToBigPoints{\number\dimen0}\PDFxoffset
+ \dimen0=#3\dimen0=#5\dimen0
+ \xdef\PDFwidth{\the\dimen0}%
+ \dimen0=#2\dimen0=#6\dimen0
+ \ScaledPointsToBigPoints{\number\dimen0}\PDFyoffset
+ \dimen0=#4\dimen0=#6\dimen0
+ \xdef\PDFheight{\the\dimen0}%
+ \global\let\PDFxoffset\PDFxoffset
+ \global\let\PDFyoffset\PDFyoffset}
+
+\def\setPDFmediabox#1[#2 #3 #4 #5]#6\done
+ {\dimen2=#2\onebasepoint\dimen2=-\dimen2 % \dimen2=-#2\onebasepoint also works since tex handles --
+ \dimen4=#3\onebasepoint\dimen4=-\dimen4 % \dimen4=-#3\onebasepoint also works since tex handles --
+ \dimen6=#4\onebasepoint\advance\dimen6 \dimen2
+ \dimen8=#5\onebasepoint\advance\dimen8 \dimen4
+ \setPDFboundingbox{\dimen2}{\dimen4}{\dimen6}{\dimen8}\PDFxscale\PDFyscale}
+
+%D End of soon obsolete code.
+
+\startMPinitializations
+ mp_shade_version := 2 ;
+\stopMPinitializations
+
+%D Here comes the traditional \MKII\ converter.
+%D
+%D Because we want to test as fast as possible, we first
+%D define the \POSTSCRIPT\ operators that \METAPOST\ uses.
+%D We don't define irrelevant ones, because these are
+%D skipped anyway.
+%D
+%D The converter can be made a bit faster by replacing the
+%D two test macros (the ones with the many \type {\if's}) by
+%D a call to named branch macros (something \typ {\getvalue
+%D {xPSmoveto}}. For everyday documents with relatively
+%D small graphics the gain in speed can be neglected.
+
+\def \PScurveto {curveto}
+\def \PSlineto {lineto}
+\def \PSmoveto {moveto}
+\def \PSshowpage {showpage}
+\def \PSnewpath {newpath}
+\def \PSfshow {fshow}
+\def \PSclosepath {closepath}
+\def \PSfill {fill}
+\def \PSstroke {stroke}
+\def \PSclip {clip}
+\def \PSrlineto {rlineto}
+\def \PSsetlinejoin {setlinejoin}
+\def \PSsetlinecap {setlinecap}
+\def \PSsetmiterlimit {setmiterlimit}
+\def \PSsetgray {setgray}
+\def \PSsetrgbcolor {setrgbcolor}
+\def \PSsetcmykcolor {setcmykcolor}
+\def \PSsetdash {setdash}
+\def \PSgsave {gsave}
+\def \PSgrestore {grestore}
+\def \PStranslate {translate}
+\def \PSscale {scale}
+\def \PSconcat {concat}
+\def \PSdtransform {dtransform}
+\def \PSsetlinewidth {setlinewidth}
+\def \PSpop {pop}
+
+\def \PSnfont {nfont} % was needed for TUG98 proceedings
+\def \PSspecial {special} % extensions to MetaPost
+
+%D A previous version set \type {%} to ignore, which
+%D simplified the following definitions. At the start of
+%D conversion the percent character was made active again.
+%D Because the whole graphic is one paragraph (there are no
+%D empty lines) this does not give the desired effect. This
+%D went unnoticed untill Scott Pakin sent me a test file
+%D percent characters in a string. So, from now on we have
+%D to prefix the following strings with percentages.
+
+%D Some day I'll figure out a better solution (line by line reading
+%D using \ETEX).
+
+\edef \PSBoundingBox {\letterpercent\letterpercent BoundingBox:}
+\edef \PSHiResBoundingBox {\letterpercent\letterpercent HiResBoundingBox:}
+\edef \PSExactBoundingBox {\letterpercent\letterpercent ExactBoundingBox:}
+\edef \PSMetaPostSpecial {\letterpercent\letterpercent MetaPostSpecial:}
+\edef \PSMetaPostSpecials {\letterpercent\letterpercent MetaPostSpecials:}
+\edef \PSPage {\letterpercent\letterpercent Page:}
+\edef \PSBeginProlog {\letterpercent\letterpercent BeginProlog}
+\edef \PSEndProlog {\letterpercent\letterpercent EndProlog}
+\edef \PSEof {\letterpercent\letterpercent EOF}
+
+%D By the way, the \type {setcmykcolor} operator is not
+%D output by \METAPOST\ but can result from converting the
+%D \cap{RGB} color specifications, as implemented in
+%D \type{supp-mps}.
+
+%D In \POSTSCRIPT\ arguments precede the operators. Due to the
+%D fact that in some translations we need access to those
+%D arguments, and also because sometimes we have to skip them,
+%D we stack them up. The stack is one||dimensional for non path
+%D operators and two||dimensional for operators inside a path.
+%D This is because we have to save the whole path for
+%D (optional) postprocessing. Values are pushed onto the stack
+%D by:
+%D
+%D \starttyping
+%D \setMPargument {value}
+%D \stoptyping
+%D
+%D They can be retrieved by the short named macros:
+%D
+%D \starttyping
+%D \gMPa {number}
+%D \gMPs {number}
+%D \stoptyping
+%D
+%D When scanning a path specification, we also save the
+%D operator, using
+%D
+%D \starttyping
+%D \setMPkeyword {n}
+%D \stoptyping
+%D
+%D The path drawing operators are coded for speed: \type{clip},
+%D \type{stroke}, \type{fill} and \type{fillstroke} become
+%D 1, 2, 3 and~4.
+%D
+%D When processing the path this code can be retrieved
+%D using
+%D
+%D \starttyping
+%D \getMPkeyword % {n}
+%D \stoptyping
+%D
+%D When setting an argument, the exact position on the stack
+%D depends on the current value of the \COUNTERS\
+%D \type{\nofMPsegments} and \type{\nofMParguments}.
+
+\newcount\nofMPsegments
+\newcount\nofMParguments
+
+%D These variables hold the coordinates. The argument part of
+%D the stack is reset by:
+%D
+%D \starttyping
+%D \resetMPstack
+%D \stoptyping
+%D
+%D We use the prefix \type{@@MP} to keep the stack from
+%D conflicting with existing macros. To speed up things a bit
+%D more, we use the constant \type{\@@MP}.
+
+\def\@@MP{@@MP}
+
+\def\setMPargument% #1%
+ {\advance\nofMParguments \plusone
+ \expandafter\def\csname\@@MP\the\nofMPsegments\the\nofMParguments\endcsname} % {#1}
+
+\def\letMPargument
+ {\advance\nofMParguments \plusone
+ \expandafter\let\csname\@@MP\the\nofMPsegments\the\nofMParguments\endcsname}
+
+\def\setMPsequence#1 %
+ {\advance\nofMParguments \plusone
+ \expandafter\def\csname\@@MP\the\nofMPsegments\the\nofMParguments\endcsname{#1}%
+ \handleMPsequence}
+
+\def\gMPa#1%
+ {\csname\@@MP0\number#1\endcsname}
+
+\def\gMPs#1%
+ {\csname\@@MP\the\nofMPsegments\number#1\endcsname}
+
+\def\dogMPa#1%
+ {\@EAEAEA\do\csname\@@MP0\number#1\endcsname}
+
+\def\setMPkeyword#1 %
+ {\expandafter\def\csname\@@MP\the\nofMPsegments0\endcsname{#1}%
+ \advance\nofMPsegments \plusone
+ \nofMParguments\zerocount}
+
+\def\getMPkeyword% #1%
+ {\csname\@@MP\the\nofMPsegments0\endcsname} % {\csname\@@MP#10\endcsname}
+
+\def\docleanupMPargument#1% we need this because args can have [ or ] pre/appended
+ {\expandafter\edef\csname\@@MP\the\nofMPsegments\number#1\endcsname
+ {\csname\@@MP\the\nofMPsegments\number#1\endcsname}}
+
+%D When we reset the stack, we can assume that all further
+%D comment is to be ignored and handled in strings.
+%D By redefining the reset macro after the first call, we
+%D save some run time. Only use this macro after all
+%D comments are processed and use the simple alternative
+%D when dealing with comments.
+
+\def\doresetMPstack
+ {\nofMParguments\zerocount}
+
+\def\resetMPstack
+ {\let\handleMPgraphic\handleMPendgraphic
+ \let\resetMPstack\doresetMPstack
+ \resetMPstack}
+
+%D The arguments are saved with the preceding command
+%D \type{\do}. By default this command expands to nothing, but
+%D when we deal with strings it's used to strip off the
+%D \type{(} and \type{)}.
+%D
+%D Strings are kind of tricky, because characters can be
+%D passed verbatim \type{(hello)}, by octal number
+%D \type{(\005)} or as command \type{(\()}. We therefore
+%D cannot simply ignore \type{(} and \type{)}, the way we do
+%D with \type{[} and \type{]}. Another complication is that
+%D strings may contain characters that normally have a
+%D special meaning in \TEX, like \type{$} and \type{{}}.
+%D
+%D A previous solution made \type{\} an active character and
+%D let it look ahead for a number or characters. We had to
+%D abandon this scheme because of the need for verbatim
+%D support. The next solution involved some \CATCODE\
+%D trickery but works well.
+
+\def\octalMPcharacter#1#2#3%
+ {\char'#1#2#3\relax}
+
+%D curly braces and squarly brackets are stored in the argument stack
+%D as part of strings, for instance in:
+%D
+%D \starttyping
+%D /fshow {exch findfont exch scalefont setfont show}bind def
+%D [3 3 ] 0 setdash
+%D \stoptyping
+%D
+%D but we need to keep them in situation like
+%D
+%D \starttyping
+%D ([bla bla] bla bla) ec-lmr10 9.96265 fshow
+%D ({bla bla} bla bla) ec-lmr10 9.96265 fshow
+%D \stoptyping
+%D
+%D So, when we store the snippets, we keep the special tokens, and
+%D when needed we either ignore or obey them
+
+%D We could use a catcodetable here.
+
+\bgroup
+\catcode`\|=\@@comment
+\catcode`\%=\@@active
+\catcode`\[=\@@active
+\catcode`\]=\@@active
+\catcode`\{=\@@active
+\catcode`\}=\@@active
+\catcode`B=\@@begingroup
+\catcode`E=\@@endgroup
+\gdef\keepMPspecials|
+ B\let%\letterpercent|
+ \def[B\noexpand[E|
+ \def]B\noexpand]E|
+ \def{B\noexpand{E|
+ \def}B\noexpand}EE
+\gdef\ignoreMPspecials|
+ B\let%\letterpercent|
+ \def[BE|
+ \def]BE|
+ \def{BE|
+ \def}BEE
+\gdef\obeyMPspecials|
+ B\def%B\char 37\relax E|
+ \def[B\char 91\relax E|
+ \def]B\char 93\relax E|
+ \def{B\char123\relax E|
+ \def}B\char125\relax EE
+\gdef\setMPspecials|
+ B\setnaturalcatcodes
+ \catcode`\\=\@@escape
+ \catcode`\%=\@@active
+ \catcode`\[=\@@active
+ \catcode`\]=\@@active
+ \catcode`\{=\@@active
+ \catcode`\}=\@@active
+ \lccode`\-=0 | latex sets this to `\-
+ \lccode`\%=`\%| otherwise it's seen as a number
+ \def\(B\char40\relax E|
+ \def\)B\char41\relax E|
+ \def\\B\char92\relax E|
+ \def\0B\octalMPcharacter0E|
+ \def\1B\octalMPcharacter1E|
+ \def\2B\octalMPcharacter2E|
+ \def\3B\octalMPcharacter3E|
+ \def\4B\octalMPcharacter4E|
+ \def\5B\octalMPcharacter5E|
+ \def\6B\octalMPcharacter6E|
+ \def\7B\octalMPcharacter7E|
+ \def\8B\octalMPcharacter8E|
+ \def\9B\octalMPcharacter9EE
+\egroup
+
+%D We use the comment symbol as a sort of trigger. Beware!
+%D The whole graphic is seen as on eparagraph, which means
+%D that we cannot change the catcodes in between.
+
+\bgroup
+\catcode`\%=\@@active
+\gdef\startMPscanning{\let%=\startMPconversion}
+\egroup
+
+%D In earlier versions we used the sequence
+%D
+%D \starttyping
+%D \expandafter\handleMPsequence\input filename\relax
+%D \stoptyping
+%D
+%D Persistent problems in \LATEX\ however forced us to use a
+%D different scheme. Every \POSTSCRIPT\ file starts with a
+%D \type{%}, so we temporary make this an active character
+%D that starts the scanning and redefines itself. (The problem
+%D originates in the redefinition by \LATEX\ of the
+%D \type{\input} primitive.)
+
+\def\startMPconversion
+ {\keepMPspecials
+ \handleMPsequence}
+
+%D Here comes the main loop. Most arguments are numbers. This
+%D means that they can be recognized by their \type{\lccode}.
+%D This method saves a lot of processing time. We could
+%D speed up the conversion by handling the \type{path}
+%D seperately.
+
+\def\dohandleMPsequence#1%
+ {\ifdone
+ \ifcase\lccode`#1\relax
+ \@EAEAEA\dohandleMPsequenceA
+ \else
+ \@EAEAEA\dohandleMPsequenceB
+ \fi
+ \else
+ \@EA\dohandleMPsequenceC
+ \fi#1}
+
+\let\dohandleMPsequenceA\setMPsequence
+
+\def\installMPSkeywordN#1#2%
+ {\expandafter\def\csname\@@MP:N:#1\endcsname{#2}}
+
+\def\installMPSshortcutN#1#2% todo: \let
+ {\expandafter\let\csname\@@MP:N:#1\expandafter\endcsname\csname\@@MP:N:#2\endcsname}
+
+\def\dohandleMPsequenceB#1 %
+ {\edef\somestring{#1}%
+ \executeifdefined{\@@MP:N:\somestring}\handleMPgraphic
+ \handleMPsequence}
+
+\installMPSkeywordN \PSmoveto
+ {\edef\lastMPmoveX{\gMPa1}%
+ \edef\lastMPmoveY{\gMPa2}%
+ \resetMPstack}
+\installMPSkeywordN \PSnewpath
+ {\let\handleMPsequence\handleMPpath}
+\installMPSkeywordN \PSgsave
+ {\PDFcode{q}%
+ \resetMPstack}
+\installMPSkeywordN \PSgrestore
+ {\PDFcode{Q}%
+ \resetMPstack}
+\installMPSkeywordN \PSdtransform % == setlinewidth
+ {\let\handleMPsequence\handleMPdtransform}
+ % after that we will encounter more tokens until setlinewidth+pop
+ % or pop+setlinewidth which we catch next; we explicitly need to
+ % reset the stack since [] n setdash may follow; a more clever
+ % approach would be to read on till the condition is met, but it's
+ % the only pop / setlinewidth we will encounter so ...
+\installMPSkeywordN \PSsetlinewidth
+ {% already handled in dtransform
+ \resetMPstack}
+\installMPSkeywordN \PSpop
+ {% already handled in dtransform
+ \resetMPstack}
+\installMPSkeywordN \PSconcat
+ {\cleanupMPconcat
+ \PDFcode{\gMPa1 \gMPa2 \gMPa3 \gMPa4 \gMPa5 \gMPa6 cm}%
+ \resetMPstack}
+\installMPSkeywordN \PSsetrgbcolor
+ {\handleMPrgbcolor
+ \resetMPstack}
+\installMPSkeywordN \PSsetcmykcolor
+ {\handleMPcmykcolor
+ \resetMPstack}
+\installMPSkeywordN \PSsetgray
+ {\handleMPgraycolor
+ \resetMPstack}
+\installMPSkeywordN \PStranslate
+ {\PDFcode{1 0 0 1 \gMPa1 \gMPa2 cm}%
+ \resetMPstack}
+\installMPSkeywordN \PSsetdash
+ {\handleMPsetdash
+ \resetMPstack}
+\installMPSkeywordN \PSsetlinejoin
+ {\PDFcode{\gMPa1 j}%
+ \resetMPstack}
+\installMPSkeywordN \PSsetmiterlimit
+ {\PDFcode{\gMPa1 M}%
+ \resetMPstack}
+\installMPSkeywordN \PSfshow
+ {%\PDFcode{n}% removed !
+ \handleMPfshow
+ \resetMPstack}
+\installMPSkeywordN \PSsetlinecap
+ {\PDFcode{\gMPa1 J}%
+ \resetMPstack}
+\installMPSkeywordN \PSrlineto
+ {\flushMPmoveto
+ \PDFcode{\!MP\lastMPmoveX\space\!MP\lastMPmoveY\space l S}%
+ \resetMPmoveto
+ \resetMPstack}
+\installMPSkeywordN \PSscale
+ {\PDFcode{\gMPa1 0 0 \gMPa2 0 0 cm}%
+ \resetMPstack}
+\installMPSkeywordN \PSspecial
+ {\handleMPspecialcommand
+ \resetMPstack}
+
+\installMPSshortcutN {n} \PSnewpath
+\installMPSshortcutN {p} \PSclosepath
+\installMPSshortcutN {l} \PSlineto
+\installMPSshortcutN {r} \PSrlineto
+\installMPSshortcutN {m} \PSmoveto
+\installMPSshortcutN {c} \PScurveto
+\installMPSshortcutN {C} \PSsetcmykcolor
+\installMPSshortcutN {G} \PSsetgray
+\installMPSshortcutN {R} \PSsetrgbcolor
+\installMPSshortcutN {lj} \PSsetlinejoin
+\installMPSshortcutN {ml} \PSsetmiterlimit
+\installMPSshortcutN {lc} \PSsetlinecap
+\installMPSshortcutN {sd} \PSsetdash
+\installMPSshortcutN {S} \PSstroke
+\installMPSshortcutN {F} \PSfill
+\installMPSshortcutN {W} \PSclip
+
+\installMPSshortcutN {q} \PSgsave
+\installMPSshortcutN {Q} \PSgrestore
+
+\installMPSshortcutN {s} \PSscale
+\installMPSshortcutN {t} \PSconcat
+\installMPSshortcutN {P} \PSshowpage
+
+\installMPSkeywordN {hlw} {\PDFcode{\gMPa1 w}\resetMPstack}
+\installMPSkeywordN {vlw} {\PDFcode{\gMPa1 w}\resetMPstack}
+\installMPSkeywordN {rd} {\PDFcode{[] 0 d}\resetMPstack}
+
+\def\dohandleMPsequenceC#1 %
+ {\edef\somestring{#1}%
+ \handleMPgraphic
+ \handleMPsequence}
+
+%D Since colors are not sensitive to transformations, they
+%D are sometimes used for signaling. Therefore, we handle them
+%D separately. The next macro can be redefined if needed.
+
+\def\handleMPrgbcolor
+ {\PDFcode{\!MPgMPa1 \!MPgMPa2 \!MPgMPa3 rg
+ \!MPgMPa1 \!MPgMPa2 \!MPgMPa3 RG}}
+
+\def\handleMPcmykcolor
+ {\PDFcode{\!MPgMPa1 \!MPgMPa2 \!MPgMPa3 \!MPgMPa4 k
+ \!MPgMPa1 \!MPgMPa2 \!MPgMPa3 \!MPgMPa4 K}}
+
+\def\handleMPgraycolor
+ {\PDFcode{\!MPgMPa1 g
+ \!MPgMPa1 G}}
+
+\def\handleMPspotcolor
+ {\PDFcode{0 g
+ 0 G}}
+
+%D Beginning and ending the graphics is taken care of by the
+%D macro \type{\handleMPgraphic}, which is redefined when
+%D the first graphics operator is met.
+
+\def\handleMPendgraphic % #1%
+ {\ifx\somestring\PSshowpage
+ \let\handleMPsequence\finishMPgraphic
+ \else\ifx\somestring\PSEof
+ \let\handleMPsequence\finishMPgraphic
+ \else
+ \letMPargument\somestring % {#1}%
+ \fi\fi}
+
+\def\handleMPbegingraphic % #1%
+ {\ifx\somestring\PSBoundingBox
+ \def\handleMPsequence{\handleMPboundingbox1}%
+ \else\ifx\somestring\PSHiResBoundingBox
+ \def\handleMPsequence{\handleMPboundingbox2}%
+ \else\ifx\somestring\PSExactBoundingBox
+ \def\handleMPsequence{\handleMPboundingbox3}%
+ \else\ifx\somestring\PSshowpage
+ \let\handleMPsequence\finishMPgraphic
+ \else\ifx\somestring\PSEof
+ \let\handleMPsequence\finishMPgraphic
+ \else\ifx\somestring\PSPage
+ \let\handleMPsequence\handleMPpage
+ \else\ifx\somestring\PSMetaPostSpecials
+ \let\handleMPsequence\handleMPspecialscomment
+ \else\ifx\somestring\PSMetaPostSpecial
+ \let\handleMPsequence\handleMPspecialcomment
+ \else\ifx\somestring\PSBeginProlog
+ \let\handleMPsequence\handleMPprolog
+ \else
+ \letMPargument\somestring % {#1}%
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+\let\handleMPgraphic=\handleMPbegingraphic
+
+%D New: we can best filter the prolog because nowdays it can contain
+%D quite some code.
+
+% hm, catcode mess, so we need to tweak %'s catcode here
+% \long\expandafter\def\expandafter\handleMPprolog\expandafter#\expandafter1\PSEndProlog%
+% but today i'm not in the mood for ugly stuff
+
+\long\def\handleMPprolog#1EndProlog %
+ {\doresetMPstack
+ \let\handleMPsequence\dohandleMPsequence
+ \handleMPsequence}
+
+%D We check for three kind of bounding boxes: the normal one
+%D and two high precision ones:
+%D
+%D \starttyping
+%D BoundingBox: llx lly ucx ucy
+%D HiResBoundingBox: llx lly ucx ucy
+%D ExactBoundingBox: llx lly ucx ucy
+%D \stoptyping
+%D
+%D The original as well as the recalculated dimensions are
+%D saved for later use.
+
+\newif\ifskipemptyMPgraphic \skipemptyMPgraphicfalse
+
+\chardef\currentMPboundingbox=0
+
+\def\handleMPboundingbox#1#2 #3 #4 #5
+ {\ifnum#1>\currentMPboundingbox
+ \chardef\currentMPboundingbox#1\relax
+ \xdef\MPllx {#2}%
+ \xdef\MPlly {#3}%
+ \xdef\MPurx {#4}%
+ \xdef\MPury {#5}%
+ \xdef\MPwidth {\the\dimexpr\MPurx\onebasepoint-\MPllx\onebasepoint\relax}%
+ \xdef\MPheight{\the\dimexpr\MPury\onebasepoint-\MPlly\onebasepoint\relax}%
+ \fi
+ \doresetMPstack
+ \let\handleMPsequence\dohandleMPsequence
+ \let\next\handleMPsequence
+ \ifskipemptyMPgraphic
+ \ifdim\MPheight=\zeropoint\ifdim\MPwidth=\zeropoint
+ \def\next{\endinput\finishMPgraphic}%
+ \fi\fi
+ \fi
+ \next}
+
+%D Unless defined otherwise, we simply ignore specialcomments.
+
+\def\handleMPspecialcomment
+ {\doresetMPstack
+ \let\handleMPsequence\dohandleMPsequence
+ \handleMPsequence}
+
+\let\handleMPspecialscomment\handleMPspecialcomment
+
+%D We use the \type{page} comment as a signal that
+%D stackbuilding can be started.
+
+\def\handleMPpage #1 #2
+ {\doresetMPstack
+ \donetrue
+ \let\handleMPsequence\dohandleMPsequence
+ \handleMPsequence}
+
+%D The same applies to the special extensions.
+
+\def\handleMPspecialcommand
+ {\doresetMPstack
+ \let\handleMPsequence\dohandleMPsequence
+ \handleMPsequence}
+
+%D \METAPOST\ draws its dots by moving to a location and
+%D invoking \type{0 0 rlineto}. This operator is not
+%D available in \PDF. Our solution is straightforward: we draw
+%D a line from $(current\_x, current\_y)$ to itself. This
+%D means that the arguments of the preceding \type{moveto} have
+%D to be saved.
+
+%D These saved coordinates are also used when we handle the
+%D texts. Text handling proved to be a bit of a nuisance, but
+%D finally I saw the light. It proved that we also had to
+%D take care of \type{(split arguments)}.
+
+% \startMPcode
+% draw btex Ga toch effe f\kern0ptietsen?{}` etex ;
+% \stopMPcode
+
+\newtoks \everyMPshowfont
+
+\def\setMPfshowfont#1#2%
+ {\font\temp=#1\space at #2\relax\temp
+ \the\everyMPshowfont}
+
+\let\MPfshowcommand\empty
+
+\def\dohandleMPfshow
+ {\setbox\scratchbox\hbox
+ {\obeyMPspecials
+ \edef\MPtextsize{\gMPa\nofMParguments}%
+ \def\do(##1){##1}% only works in latest mp
+ \edef\MPtextdata{\dogMPa1}% beware, stack can have more
+ \handleMPtext}%
+ \setbox\scratchbox\hbox
+ {\hskip\lastMPmoveX\onebasepoint
+ \raise\lastMPmoveY\onebasepoint
+ \box\scratchbox}%
+ \smashbox\scratchbox
+ \box\scratchbox}
+
+\def\handleMPtext {\handleMPtextnormal} % so we can overload this one later
+\def\handleMPfshow{\dohandleMPfshow } % so we can overload this one later
+
+\def\handleMPtext
+ {\ifnum\nofMParguments>\plusthree
+ \handleMPtextnormal
+ \else
+ \defconvertedcommand\MPtextdata\MPtextdata
+ \expanded{\splitstring\MPtextdata}\at::::\to\MPtexttag\and\MPtextnumber
+ \executeifdefined{handleMPtext\MPtexttag}\handleMPtextnormal
+ \fi}
+
+% elsewhere we will implement \handleMPtextmptxt
+
+\def\doflushMPtext#1%
+ {\edef\!!stringa{#1}%
+ \@EA\dodoflushMPtext\!!stringa\relax}
+
+\def\dodoflushMPtext
+ {\afterassignment\dododoflushMPtext\let\nexttoken=}
+
+\def\dododoflushMPtext
+ {\ifx\nexttoken\relax
+ % done
+ \else\ifx\nexttoken\char
+ \@EA\@EA\@EA\dodododoflushMPtext
+ \else
+ {\nexttoken}%
+ \@EA\@EA\@EA\dodoflushMPtext
+ \fi\fi}
+
+\def\dodododoflushMPtext
+ {\afterassignment\dododododoflushMPtext\scratchcounter}
+
+\def\dododododoflushMPtext
+ {{\char\scratchcounter}\let\next\dodoflushMPtext}
+
+\def\handleMPtextnormal
+ {\let\ \relax % mp breaks long lines and appends a \
+ \ifx\MPtextsize\PSnfont % round font size (to pt)
+ \advance\nofMParguments \minusone
+ \expandafter\scratchdimen\gMPa\nofMParguments\onepoint\relax
+ \ifdim\scratchdimen<\onepoint
+ \def\MPtextsize{1pt}%
+ \else
+ \advance\scratchdimen .5\onepoint
+ \def\MPtextsize##1.##2\relax{\def\MPtextsize{##1pt}}%
+ \expandafter\MPtextsize\the\scratchdimen\relax
+ \fi
+ \else
+ \edef\MPtextsize{\MPtextsize bp}%
+ \fi
+ \advance\nofMParguments \minusone
+ \setMPfshowfont{\gMPa\nofMParguments}\MPtextsize
+ \advance\nofMParguments \minusone
+ \temp
+ \MPfshowcommand
+ {\ifnum\nofMParguments=\plusone
+ \def\do(##1){##1}%
+ \doflushMPtext{\dogMPa1}%
+ \else % can't happen anymore in mp version 1+
+ % we need to catch ( a ) (a a a) (\123 \123 \123) etc
+ \scratchcounter\plusone
+ \def\dodo##1% Andreas Fieger's bug: (\304...)
+ {\edef\!!stringa{##1\empty\empty}% and another one: ( 11) -> \ifx 11
+ \ifx\!!stringa\MPspacechar\MPspacechar\else\expandafter##1\fi}%
+ \def\do(##1{\dodo{##1}}%
+ \dogMPa\scratchcounter\MPspacechar
+ \let\do\relax
+ \loop
+ \advance\scratchcounter \plusone
+ \ifnum\scratchcounter<\nofMParguments\relax
+ \gMPa\scratchcounter\MPspacechar
+ \repeat
+ \def\do##1){\dodo{##1}}%
+ \dogMPa\scratchcounter
+ \fi
+ \unskip}}
+
+%D You could consider the following definition to be the most
+%D natural one.
+
+% \def\MPspacechar{\space} % normal case
+
+\def\MPspacechar{\char32\relax} % old solution does not work with math
+
+%D However, the following implementation is more robust, since
+%D some fonts have funny visible spaces in the space slot. This
+%D gives a mismatch between the space that \METAPOST\ took into
+%D account and the \quote {natural} space. This only happens in
+%D labels, since \type {btex}||\type {etex} thingies don't have
+%D spaces. This phenomena showed up when preparing the
+%D \METAFUN\ manual, where Palatino fonts are used. We can
+%D safely assume that \METAPOST\ considers \type {\char32} to
+%D be the space.
+
+\def\MPspacechar{\setbox\scratchbox\hbox{\char32}\kern\wd\scratchbox}
+
+%D Well, this does not work with math fonts, so:
+
+\def\MPspacechar{\char32\relax}
+
+%D Most operators are just converted and keep their
+%D arguments. Dashes however need a bit different treatment,
+%D otherwise \PDF\ viewers complain loudly. Another
+%D complication is that one argument comes after the \type{]}.
+%D When reading the data, we simply ignore the array boundary
+%D characters. We save ourselves some redundant newlines and
+%D at the same time keep the output readable by packing the
+%D literals.
+
+\def\handleMPsetdash
+ {\bgroup
+ \ignoreMPspecials
+ \let\somestring\empty
+ \scratchcounter\plusone
+ \loop
+ \ifnum\scratchcounter<\nofMParguments
+ \edef\somestring{\somestring\space\gMPa\scratchcounter}%
+ \advance\scratchcounter \plusone
+ \repeat
+ \edef\somestring{[\somestring]\space\gMPa\scratchcounter\space d}%
+ \PDFcode{\somestring}%
+ \egroup}
+
+%D The \type{setlinewidth} commands looks a bit complicated. There are
+%D two alternatives, that result in a similar look in both
+%D $x$- and $y$-dorection. As John Hobby says:
+%D
+%D \startnarrower \switchtobodyfont[ss]
+%D \starttyping
+%D x 0 dtransform exch truncate exch idtransform pop setlinewidth
+%D 0 y dtransform truncate idtransform setlinewidth pop
+%D \stoptyping
+%D
+%D These are just fancy versions of \type{x setlinewidth} and
+%D \type{y setlinewidth}. The \type{x 0 ...} form is used if
+%D the path is {\em primarily vertical}. It rounds the width
+%D so that vertical lines come out an integer number of pixels
+%D wide in device space. The \type{0 y ...} form does the same
+%D for paths that are {\em primarily horizontal}. The reason
+%D why I did this is Knuth insists on getting exactly the
+%D widths \TEX\ intends for the horizontal and vertical rules
+%D in \type{btex...etex} output. (Note that PostScript scan
+%D conversion rules cause a horizontal or vertical line of
+%D integer width $n$ in device space to come out $n+1$ pixels
+%D wide, regardless of the phase relative to the pixel grid.)
+%D \stopnarrower
+%D
+%D The common operator in these sequences is \type{dtransform},
+%D so we can use this one to trigger setting the linewidth.
+
+\def\handleMPdtransform
+ {\ifdim\gMPa1\onepoint>\zeropoint
+ \PDFcode{\gMPa1 w}%
+ \def\next##1 ##2 ##3 ##4 ##5 ##6 {\handleMPsequence}%
+ \else
+ \PDFcode{\gMPa2 w}%
+ \def\next##1 ##2 ##3 ##4 {\handleMPsequence}%
+ \fi
+ \let\handleMPsequence\dohandleMPsequence
+ \resetMPstack
+ \next}
+
+%D The most complicated command is \type{concat}. \METAPOST\
+%D applies this operator to \type{stroke}. At that moment the
+%D points set by \type{curveto} and \type{moveto}, are already
+%D fixed. In \PDF\ however the \type{cm} operator affects the
+%D points as well as the pen (stroke). Like more \PDF\
+%D operators, \type{cm} is defined in a bit ambiguous way.
+%D The only save route for non||circular penshapes, is saving
+%D the path, recalculating the points and applying the
+%D transformation matrix in such a way that we can be sure
+%D that its behavior is well defined. This comes down to
+%D inverting the path and applying \type{cm} to that path as
+%D well as the pen. This all means that we have to save the
+%D path.
+
+%D In \METAPOST\ there are three ways to handle a path $p$:
+%D
+%D \starttyping
+%D draw p; fill p; filldraw p;
+%D \stoptyping
+%D
+%D The last case outputs a \type{gsave fill grestore} before
+%D \type{stroke}. Handling the path outside the main loops
+%D saves about 40\% run time.\footnote{We can save some more by
+%D following the \METAPOST\ output routine, but for the moment
+%D we keep things simple.} Switching between the main loop and
+%D the path loop is done by means of the recursely called
+%D macro \type{\handleMPsequence}.
+
+\def\handleMPpath
+ {\chardef\finiMPpath\zerocount
+ \let\closeMPpath\relax
+ \let\flushMPpath\flushnormalMPpath
+ \resetMPstack
+ \nofMPsegments\plusone
+ \let\handleMPsequence\dohandleMPpath
+ \dohandleMPpath}
+
+%D Most paths are drawn with simple round pens. Therefore we've
+%D split up the routine in two.
+
+\def\resetMPmoveto
+ {\let\lastMPmoveX\empty
+ \let\lastMPmoveY\empty}
+
+\resetMPmoveto
+
+\def\flushMPmoveto
+ {\ifx\lastMPmoveX\empty \else
+ \PDFcode{\!MP\lastMPmoveX\space \!MP\lastMPmoveY\space m}%
+ \fi}
+
+\def\flushnormalMPsegment
+ {\ifcase\getMPkeyword\relax
+ \flushMPmoveto
+ \resetMPmoveto
+ \PDFcode{\!MPgMPs1 \!MPgMPs2 l}%
+ \or
+ \flushMPmoveto
+ \resetMPmoveto
+ \PDFcode{\!MPgMPs1 \!MPgMPs2 \!MPgMPs3 \!MPgMPs4 \!MPgMPs5 \!MPgMPs6 c}%
+ \or
+ \ifx\lastMPmoveX\empty \else % we assume 0,0 rlineto
+ \flushMPmoveto
+ \PDFcode{\!MP\lastMPmoveX\space \!MP\lastMPmoveY\space l}%
+ \resetMPmoveto
+ \fi
+ \or
+ % \flushMPmoveto
+ % \resetMPmoveto
+ \fi}
+
+\def\flushMPconcatmoveto
+ {\ifx\lastMPmoveX\empty\else
+ \doMPconcat\lastMPmoveX\lastMPmoveX\lastMPmoveY\lastMPmoveY
+ \flushMPmoveto
+ \fi}
+
+\def\flushconcatMPsegment
+ {\ifcase\getMPkeyword\relax
+ \flushMPconcatmoveto
+ \resetMPmoveto
+ \doMPconcat{\gMPs1}\a{\gMPs2}\b%
+ \PDFcode{\!MP\a\space\!MP\b\space l}%
+ \or
+ \flushMPconcatmoveto
+ \resetMPmoveto
+ \doMPconcat{\gMPs1}\a{\gMPs2}\b%
+ \doMPconcat{\gMPs3}\c{\gMPs4}\d%
+ \doMPconcat{\gMPs5}\e{\gMPs6}\f%
+ \PDFcode{\!MP\a\space\!MP\b\space
+ \!MP\c\space\!MP\d\space
+ \!MP\e\space\!MP\f\space c}%
+ \or % rather mp specific ... rline always has 0,0
+ \bgroup
+ \noMPtranslate
+ \flushMPconcatmoveto
+ % next should be \lastMPmoveX+\a,\lastMPmoveY+\b but we know it's 0,0
+ \PDFcode{\!MP\lastMPmoveX\space\!MP\lastMPmoveY\space l S}%
+ \resetMPmoveto
+ \egroup
+ \or
+% \flushMPconcatmoveto
+% \resetMPmoveto
+ \fi}
+
+\def\doflushsomeMPpath
+ {\dodoflushsomeMPpath
+ \advance\nofMPsegments \plusone
+ \ifnum\nofMPsegments<\scratchcounter
+ \expandafter\doflushsomeMPpath
+ \fi}
+
+\def\flushsomeMPpath
+ {\scratchcounter\nofMPsegments
+ \nofMPsegments\plusone
+ \doflushsomeMPpath}
+
+\def\flushnormalMPpath{\let\dodoflushsomeMPpath\flushnormalMPsegment\flushsomeMPpath}
+
+%OLD \def\flushconcatMPpath{\let\dodoflushsomeMPpath\flushconcatMPsegment\flushsomeMPpath}
+
+%NEW pre-calculate 1/D so it needn't be repeated for each control point.
+
+\def\flushconcatMPpath
+ {\MPreciprocaldeterminant
+ \let\dodoflushsomeMPpath\flushconcatMPsegment\flushsomeMPpath}
+
+%D The transformation of the coordinates is handled by one of
+%D the macros Tanmoy posted to the \PDFTEX\ mailing list.
+%D I rewrote and optimized the original macro to suit the other
+%D macros in this module.
+%D
+%D \starttyping
+%D \doMPconcat {x position} \xresult {y position} \yresult
+%D \stoptyping
+%D
+%D By setting the auxiliary \DIMENSIONS\ \type{\dimen0} upto
+%D \type{\dimen10} only once per path, we save over 20\% run
+%D time. Some more speed was gained by removing some parameter
+%D passing. These macros can be optimized a bit more by using
+%D more constants. There is however not much need for further
+%D optimization because penshapes usually are round and
+%D therefore need no transformation. Nevertheless we move the
+%D factor to the outer level and use a bit different \type{pt}
+%D removal macro. Although the values represent base points,
+%D we converted them to pure points, simply because those can
+%D be converted back.
+
+%OLD \mathchardef\MPconcatfactor=256 % beware don't remove spaces before it
+
+%OLD \def\doMPreducedimen#1
+%OLD {\count0\MPconcatfactor
+%OLD \advance\dimen#1 \ifdim\dimen#1>\zeropoint .5\else -.5\fi\count0
+%OLD \divide\dimen#1 \count0\relax}
+
+%OLD % too inaccurate (see old pragma logo)
+%OLD
+%OLD \def\doMPreducedimen#1
+%OLD {\count0=\MPconcatfactor
+%OLD \divide\dimen#1 \count0\relax}
+
+%OLD \def\doMPreducedimen#1
+%OLD {\advance\dimen#1 \ifdim\dimen#1>\zeropoint .5\else -.5\fi\MPconcatfactor
+%OLD \divide\dimen#1 \MPconcatfactor}
+
+%D The transformation code is rewritten by Daniel H. Luecking who
+%D describes his patch as follows:
+%D
+%D We would like to divide 1 by $X$, but all divisions are integer so
+%D for accuracy we want to convert to large integers and make sure the
+%D integer quotient has as many significant digits as possible. Thus we
+%D need to replace $1/X$ with $M/N$ where $N$ is as large as possible
+%D and $M/N$ is as large as possible. Also for simplicity $M$ should be
+%D a power of 2. So we make $M = 2^{30}$ \footnote{$2^{31} - 1$ is the
+%D largest legal integer. Using it (and simply ignoring the inaccuracy
+%D caused by $-1$) turns out to be at least as accurate in all cases,
+%D and more accurate in some.} (largest legal power of 2) and adjust
+%D $X$ downward (if necessary) to the the range $1-2^{16}$. This gives
+%D at least 15 significant binary digits, (almost as accurate as
+%D \METAPOST\ for numbers near 1) or almost 5 significant figures
+%D (decimal).
+
+\newcount\MPscratchCnt
+\newdimen\MPscratchDim % will be assigned global
+
+\def\MPadjustdimen % sets \MPscratchDim and \MPscratchCnt
+ {\MPscratchCnt\zerocount
+ \doMPadjustdimen}
+
+\def\doMPadjustdimen
+ {\ifdim\MPscratchDim>\onepoint
+ \divide \MPscratchDim\plustwo
+ \advance\MPscratchCnt\plusone
+ \expandafter\doMPadjustdimen
+ \fi}
+
+%OLD \def\doMPexpanddimen#1
+%OLD {\multiply\dimen#1 \MPconcatfactor\relax}
+
+%D DHL: When viewed as an integer, $1 \hbox{pt}=2^{16}$ so $2^{32}/X$
+%D is the right way to do $(1 \hbox{pt})/(X \hbox{pt})$ and get the
+%D answer in points. But we are limited to $2^{30}/X$. However, we
+%D actually do $[ 2^{30} / (X/2^K) ]*2^{2-K}$ where $K$ is the number
+%D of halvings it takes to bring $X$ below $1 \hbox{pt}$. If $K$ is 0
+%D or 1 we readjust by multiplying by 4 or 2, otherwise by halving
+%D $(K-2)$ times \type {\MPscratchCnt} holds the value of $K$ from
+%D \type {\MPadjustdimen}.
+
+\def\MPreadjustdimen % acts on \MPscratchDim and MPscratchCnt
+ {\ifcase\MPscratchCnt
+ \multiply\scratchdimen \plusfour
+ \or
+ \multiply\scratchdimen \plustwo
+ \else
+ \expandafter\doMPreadjustdimen
+ \fi}
+
+\def\doMPreadjustdimen
+ {\ifnum\MPscratchCnt>\plustwo
+ \divide \scratchdimen\plustwo
+ \advance\MPscratchCnt\minusone
+ \expandafter\doMPreadjustdimen
+ \fi}
+
+\def\MPreciprocaldeterminant
+ {\scratchdimen\withoutpt\the\dimen0 \dimen6 % s_x*s_y
+ \advance\scratchdimen -\withoutpt\the\dimen2 \dimen4 % s_x*s_y - r_x*r_y
+ \ifdim\scratchdimen<\zeropoint % we need a positive dimension
+ \scratchdimen-\scratchdimen % for \MPadjustdimen (?)
+ \doMPreciprocal
+ \scratchdimen-\scratchdimen
+ \else
+ \doMPreciprocal
+ \fi
+ \edef\MPreciprocal{\withoutpt\the\scratchdimen}}
+
+\newcount\MPnumerator \MPnumerator = 1073741824 % 2^{30}
+
+% todo: dimexpr
+
+\def\doMPreciprocal % replace \scratchdimen with its reciprocal
+ {\ifdim\scratchdimen=\onepoint \else
+ \MPadjustdimen
+ \scratchcounter\MPnumerator
+ \divide\scratchcounter\scratchdimen
+ \scratchdimen1\scratchcounter % 1 needed
+ \MPreadjustdimen
+ \fi}
+
+%OLD \def\presetMPconcat
+%OLD {\dimen 0=\gMPs1\onepoint \doMPreducedimen 0 % r_x
+%OLD \dimen 2=\gMPs2\onepoint \doMPreducedimen 2 % s_x
+%OLD \dimen 4=\gMPs3\onepoint \doMPreducedimen 4 % s_y
+%OLD \dimen 6=\gMPs4\onepoint \doMPreducedimen 6 % r_y
+%OLD \dimen 8=\gMPs5\onepoint \doMPreducedimen 8 % t_x
+%OLD \dimen10=\gMPs6\onepoint \doMPreducedimen10 } % t_y
+%OLD
+%OLD \def\presetMPscale
+%OLD {\dimen 0=\gMPs1\onepoint \doMPreducedimen 0
+%OLD \dimen 2 \zeropoint
+%OLD \dimen 4 \zeropoint
+%OLD \dimen 6=\gMPs2\onepoint \doMPreducedimen 6
+%OLD \dimen 8 \zeropoint
+%OLD \dimen10 \zeropoint}
+
+\def\cleanupMPconcat
+ {\ignoreMPspecials
+ \docleanupMPargument1%
+ \docleanupMPargument6%
+ \keepMPspecials}
+
+\def\presetMPconcat
+ {\dimen 0=\gMPs1\onepoint % s_x
+ \dimen 2=\gMPs2\onepoint % r_x
+ \dimen 4=\gMPs3\onepoint % r_y
+ \dimen 6=\gMPs4\onepoint % s_y
+ \dimen 8=\gMPs5\onepoint % t_x
+ \dimen10=\gMPs6\onepoint} % t_y
+
+\def\presetMPscale
+ {\dimen 0=\gMPs1\onepoint
+ \dimen 2 \zeropoint
+ \dimen 4 \zeropoint
+ \dimen 6=\gMPs2\onepoint
+ \dimen 8 \zeropoint
+ \dimen10 \zeropoint}
+
+\def\noMPtranslate % use this one grouped
+ {\dimen 8 \zeropoint % t_x
+ \dimen10 \zeropoint} % t_y
+
+%D \starttyping
+%D \def\doMPconcat#1#2#3#4%
+%D {\dimen12=#1 pt \doMPreducedimen12 % p_x
+%D \dimen14=#3 pt \doMPreducedimen14 % p_y
+%D %
+%D \dimen16 \dimen 0
+%D \multiply \dimen16 \dimen 6
+%D \dimen20 \dimen 2
+%D \multiply \dimen20 \dimen 4
+%D \advance \dimen16 -\dimen20
+%D %
+%D \dimen18 \dimen12
+%D \multiply \dimen18 \dimen 6
+%D \dimen20 \dimen14
+%D \multiply \dimen20 \dimen 4
+%D \advance \dimen18 -\dimen20
+%D \dimen20 \dimen 4
+%D \multiply \dimen20 \dimen10
+%D \advance \dimen18 \dimen20
+%D \dimen20 \dimen 6
+%D \multiply \dimen20 \dimen 8
+%D \advance \dimen18 -\dimen20
+%D %
+%D \multiply \dimen12 -\dimen 2
+%D \multiply \dimen14 \dimen 0
+%D \advance \dimen12 \dimen14
+%D \dimen20 \dimen 2
+%D \multiply \dimen20 \dimen 8
+%D \advance \dimen12 \dimen20
+%D \dimen20 \dimen 0
+%D \multiply \dimen20 \dimen10
+%D \advance \dimen12 -\dimen20
+%D %
+%D \doMPreducedimen16
+%D \divide \dimen18 \dimen16 \doMPexpanddimen18
+%D \divide \dimen12 \dimen16 \doMPexpanddimen12
+%D %
+%D \edef#2{\withoutpt\the\dimen18}% % p_x^\prime
+%D \edef#4{\withoutpt\the\dimen12}} % p_y^\prime
+%D \stoptyping
+
+%D The following optimization resulted from some tests by
+%D and email exchanges with Sanjoy Mahajan.
+%D
+%D \starttyping
+%D \def\doMPconcat#1#2#3#4%
+%D {\dimen12=#1 pt \doMPreducedimen12 % p_x
+%D \dimen14=#3 pt \doMPreducedimen14 % p_y
+%D %
+%D \dimen16 \dimen 0
+%D \multiply \dimen16 \dimen 6
+%D \dimen20 \dimen 2
+%D \multiply \dimen20 \dimen 4
+%D \advance \dimen16 -\dimen20
+%D %
+%D \dimen18 \dimen12
+%D \multiply \dimen18 \dimen 6
+%D \dimen20 \dimen14
+%D \multiply \dimen20 \dimen 4
+%D \advance \dimen18 -\dimen20
+%D \dimen20 \dimen 4
+%D \multiply \dimen20 \dimen10
+%D \advance \dimen18 \dimen20
+%D \dimen20 \dimen 6
+%D \multiply \dimen20 \dimen 8
+%D \advance \dimen18 -\dimen20
+%D %
+%D \multiply \dimen12 -\dimen 2
+%D \multiply \dimen14 \dimen 0
+%D \advance \dimen12 \dimen14
+%D \dimen20 \dimen 2
+%D \multiply \dimen20 \dimen 8
+%D \advance \dimen12 \dimen20
+%D \dimen20 \dimen 0
+%D \multiply \dimen20 \dimen10
+%D \advance \dimen12 -\dimen20
+%D %
+%D %\ifdim\dimen16>\onepoint % oeps, can be < 1pt too
+%D \ifdim\dimen16=\onepoint \else
+%D \ifdim\dimen16>\MPconcatfactor pt
+%D \doMPreducedimen16
+%D \divide \dimen18 \dimen16 \doMPexpanddimen18
+%D \divide \dimen12 \dimen16 \doMPexpanddimen12
+%D \else
+%D \divide \dimen18 \dimen16 \doMPexpanddimen18 \doMPexpanddimen18
+%D \divide \dimen12 \dimen16 \doMPexpanddimen12 \doMPexpanddimen12
+%D \fi
+%D \fi
+%D %
+%D \edef#2{\withoutpt\the\dimen18}% % p_x^\prime
+%D \edef#4{\withoutpt\the\dimen12}} % p_y^\prime
+%D \stoptyping
+%D
+%D But, this one is still too inaccurate, so we now have:
+
+%D DHL: Ideally, $r_x$, $r_y$, $s_x$, $s_y$ should be in macros, not
+%D dimensions (they are scalar quantities after all, not lengths). I
+%D suppose the authors decided to do calculations with integer
+%D arithmetic instead of using real factors because it's faster.
+%D However, the actual macros test slower, possibly because I've
+%D omitted three nested loops. In my test files, my approach is more
+%D accurate. It is also far simpler and overflow does not seem to be a
+%D significant concern. The scale factors written by Metapost are (?)
+%D always $<=1$ (it scales coordinates internally) and coordinates are
+%D always likely to be less than \type {\maxdimen}.
+%D
+%D If this should ever cause problems, the scale factors can be reduced.
+
+% the original:
+%
+% \def\doMPconcat#1#2#3#4%
+% {\dimen12=#1\onepoint% p_x % #1\onepoint
+% \dimen14=#3\onepoint% p_y % #3\onepoint
+% \advance\dimen12 -\dimen8 % p_x - t_x
+% \advance\dimen14 -\dimen10 % p_y - t_y
+% \dimen18=\withoutpt\the\dimen6 \dimen12 % s_y(p_x - t_x)
+% \advance\dimen18 -\withoutpt\the\dimen4 \dimen14 % - r_y(p_y-t_y)
+% \dimen14=\withoutpt\the\dimen0 \dimen14 % s_x(p_y-t_y)
+% \advance\dimen14 -\withoutpt\the\dimen2 \dimen12 % - r_x(p_x-t_x)
+% % \MPreciprocal contains precomputed 1/D:
+% \dimen18=\MPreciprocal\dimen18
+% \dimen14=\MPreciprocal\dimen14
+% \edef#2{\withoutpt\the\dimen18}% % p_x^\prime
+% \edef#4{\withoutpt\the\dimen14}} % p_y^\prime
+%
+% faster but not that often used
+
+\def\doMPconcat#1#2#3#4%
+ {\dimen12\dimexpr#1\points-\dimen 8\relax % p_x-t_x
+ \dimen14\dimexpr#3\points-\dimen10\relax % p_y-t_y
+ \dimen18\dimexpr\withoutpt\the\dimen6\dimen12-\withoutpt\the\dimen4\dimen14\relax % s_y(p_x-t_x)-r_y(p_y-t_y)
+ \dimen14\dimexpr\withoutpt\the\dimen0\dimen14-\withoutpt\the\dimen2\dimen12\relax % s_x(p_y-t_y)-r_x(p_x-t_x)
+ \edef#2{\withoutpt\the\dimexpr\MPreciprocal\dimen18\relax}% % p_x^\prime
+ \edef#4{\withoutpt\the\dimexpr\MPreciprocal\dimen14\relax}} % p_y^\prime
+
+%D One reason for Daniel to write this patch was that at small sizes
+%D the accuracy was less than optimal. Here is a test that demonstrates
+%D that his alternative is pretty good:
+%D
+%D \startlinecorrection
+%D \startMPcode
+%D for i = 5cm,1cm,5mm,1mm,.5mm,.1mm,.01mm :
+%D draw fullcircle scaled i withpen pencircle xscaled (i/10) yscaled (i/20) rotated 45 ;
+%D endfor ;
+%D \stopMPcode
+%D \stoplinecorrection
+
+%D The following explanation of the conversion process was
+%D posted to the \PDFTEX\ mailing list by Tanmoy. The original
+%D macro was part of a set of macro's that included sinus and
+%D cosinus calculations as well as scaling and translating. The
+%D \METAPOST\ to \PDF\ conversion however only needs
+%D transformation.
+
+%M \start \switchtobodyfont [ss]
+
+%D Given a point $(U_x, U_y)$ in user coordinates, the business
+%D of \POSTSCRIPT\ is to convert it to device space. Let us say
+%D that the device space coordinates are $(D_x, D_y)$. Then, in
+%D \POSTSCRIPT\ $(D_x, D_y)$ can be written in terms of
+%D $(U_x, U_y)$ in matrix notation, either as
+%D
+%D \placeformula
+%D \startformula
+%D \pmatrix{D_x&D_y&1\cr} = \pmatrix{U_x&U_y&1\cr}
+%D \pmatrix{s_x&r_x&0\cr
+%D r_y&s_y&0\cr
+%D t_x&t_y&1\cr}
+%D \stopformula
+%D
+%D or
+%D
+%D \placeformula
+%D \startformula
+%D \pmatrix{D_x\cr D_y\cr 1} = \pmatrix{s_x&r_y&t_x\cr
+%D r_x&s_y&t_y\cr
+%D 0 &0 &1 \cr}
+%D \pmatrix{U_x\cr
+%D U_y\cr
+%D 1 \cr}
+%D \stopformula
+%D
+%D both of which is a shorthand for the same set of equations:
+%D
+%D \placeformula
+%D \startformula
+%D D_x = s_x U_x + r_y U_y + t_x
+%D \stopformula
+%D
+%D \placeformula
+%D \startformula
+%D D_y = r_x U_x + s_y U_y + t_y
+%D \stopformula
+%D
+%D which define what is called an `affine transformation'.
+%D
+%D \POSTSCRIPT\ represents the `transformation matrix' as a
+%D six element matrix instead of a $3\times 3$ array because
+%D three of the elements are always~0, 0 and~1. Thus the above
+%D transformation is written in postscript as $[s_x\, r_x\,
+%D r_y\, s_y\, t_x\, t_y]$. However, when doing any
+%D calculations, it is useful to go back to the original
+%D matrix notation (whichever: I will use the second) and
+%D continue from there.
+%D
+%D As an example, if the current transformation matrix is
+%D $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$ and you say \typ{[a b
+%D c d e f] concat}, this means:
+%D
+%D \startnarrower
+%D Take the user space coordinates and transform them to an
+%D intermediate set of coordinates using array $[a\, b\, c\, d\,
+%D e\, f]$ as the transformation matrix.
+%D
+%D Take the intermediate set of coordinates and change them to
+%D device coordinates using array $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$
+%D as the transformation matrix.
+%D \stopnarrower
+%D
+%D Well, what is the net effect? In matrix notation, it is
+%D
+%D \placeformula
+%D \startformula
+%D \pmatrix{I_x\cr I_y\cr 1\cr} = \pmatrix{a&c&e\cr
+%D b&d&f\cr
+%D 0&0&1\cr}
+%D \pmatrix{U_x\cr
+%D U_y\cr
+%D 1 \cr}
+%D \stopformula
+%D
+%D \placeformula
+%D \startformula
+%D \pmatrix{D_y\cr D_y\cr 1\cr} = \pmatrix{s_x&r_y&t_x\cr
+%D r_x&s_y&t_y\cr
+%D 0 &0 &1 \cr}
+%D \pmatrix{I_x\cr
+%D I_y\cr
+%D 1 \cr}
+%D \stopformula
+%D
+%D where $(I_x, I_y)$ is the intermediate coordinate.
+%D
+%D Now, the beauty of the matrix notation is that when there is
+%D a chain of such matrix equations, one can always compose
+%D them into one matrix equation using the standard matrix
+%D composition law. The composite matrix from two matrices can
+%D be derived very easily: the element in the $i$\high{th}
+%D horizontal row and $j$\high{th} vertical column is
+%D calculated by`multiplying' the $i$\high{th} row of the first
+%D matrix and the $j$\high{th} column of the second matrix (and
+%D summing over the elements). Thus, in the above:
+%D
+%D \placeformula
+%D \startformula
+%D \pmatrix{D_x\cr D_y\cr 1} = \pmatrix{s_x^\prime&r_y^\prime&t_x^\prime\cr
+%D r_x^\prime&s_y^\prime&t_y^\prime\cr
+%D 0 &0 &0 \cr}
+%D \pmatrix{U_x\cr
+%D U_y\cr
+%D 1 \cr}
+%D \stopformula
+%D
+%D with
+%D
+%D \placeformula
+%D \startformula
+%D \eqalign
+%D {s_x^\prime & = s_x a + r_y b \cr
+%D r_x^\prime & = r_x a + s_y b \cr
+%D r_y^\prime & = s_x c + r_y d \cr
+%D s_y^\prime & = r_x c + s_y d \cr
+%D t_x^\prime & = s_x e + r_y f + t_x \cr
+%D t_y^\prime & = r_x e + s_y f + t_y \cr}
+%D \stopformula
+
+%D In fact, the same rule is true not only when one is going
+%D from user coordinates to device coordinates, but whenever
+%D one is composing two `transformations' together
+%D (transformations are `associative'). Note that the formula
+%D is not symmetric: you have to keep track of which
+%D transformation existed before (i.e.\ the equivalent of
+%D $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$) and which was
+%D specified later (i.e.\ the equivalent of $[a\, b\, c\, d\,
+%D e\, f]$). Note also that the language can be rather
+%D confusing: the one specified later `acts earlier',
+%D converting the user space coordinates to intermediate
+%D coordinates, which are then acted upon by the pre||existing
+%D transformation. The important point is that order of
+%D transformation matrices cannot be flipped (transformations
+%D are not `commutative').
+%D
+%D Now what does it mean to move a transformation matrix
+%D before a drawing? What it means is that given a point
+%D $(P_x, P_y)$ we need a different set of coordinates
+%D $(P_x^\prime, P_y^\prime)$ such that if the transformation
+%D acts on $(P_x^\prime, P_y^\prime)$, they produce $(P_x,
+%D P_y)$. That is we need to solve the set of equations:
+%D
+%D \placeformula
+%D \startformula
+%D \pmatrix{P_x\cr P_y\cr 1\cr} = \pmatrix{s_x&r_y&t_x\cr
+%D r_x&s_y&t_y\cr
+%D 0 &0 &1 \cr}
+%D \pmatrix{P_x^\prime\cr
+%D P_y^\prime\cr
+%D 1 \cr}
+%D \stopformula
+%D
+%D Again matrix notation comes in handy (i.e. someone has
+%D already solved the problem for us): we need the inverse
+%D transformation matrix. The inverse transformation matrix can
+%D be calculated very easily:
+%D
+%D \placeformula
+%D \startformula
+%D \pmatrix{P_x^\prime\cr P_y^\prime\cr 1\cr} =
+%D \pmatrix{s_x^\prime&r_y^\prime&t_x^\prime\cr
+%D r_x^\prime&s_y^\prime&t_y^\prime\cr
+%D 0 &0 &1 \cr}
+%D \pmatrix{P_x\cr
+%D P_y\cr
+%D 1 \cr}
+%D \stopformula
+%D
+%D where, the inverse transformation matrix is given by
+%D
+%D \placeformula
+%D \startformula
+%D \eqalign
+%D {D & = s_x s_y - r_x r_y \cr
+%D s_x^\prime & = s_y / D \cr
+%D s_y^\prime & = s_x / D \cr
+%D r_x^\prime & = - r_x / D \cr
+%D r_y^\prime & = - r_y / D \cr
+%D t_x^\prime & = ( - s_y t_x + r_y t_y ) / D \cr
+%D t_y^\prime & = ( r_x t_x - s_x t_y ) / D \cr}
+%D \stopformula
+%D
+%D And you can see that when expanded out, this does
+%D give the formulas:
+%D
+%D \placeformula
+%D \startformula
+%D P_x^\prime = { { s_y(p_x-t_x) + r_y(t_y-p_y) } \over
+%D { s_x s_y-r_x r_y } }
+%D \stopformula
+%D
+%D \placeformula
+%D \startformula
+%D P_y^\prime = { { s_x(p_y-t_y) + r_x(t_x-p_x) } \over
+%D { s_x*s_y-r_x*r_y } }
+%D \stopformula
+%D
+%D The code works by representing a real number by converting
+%D it to a dimension to be put into a \DIMENSION\ register: 2.3 would
+%D be represented as 2.3pt for example. In this scheme,
+%D multiplying two numbers involves multiplying the \DIMENSION\
+%D registers and dividing by 65536. Accuracy demands that the
+%D division be done as late as possible, but overflow
+%D considerations need early division.
+%D
+%D Division involves dividing the two \DIMENSION\ registers and
+%D multiplying the result by 65536. Again, accuracy would
+%D demand that the numerator be multiplied (and|/|or the
+%D denominator divided) early: but that can lead to overflow
+%D which needs to be avoided.
+%D
+%D If nothing is known about the numbers to start with (in
+%D concat), I have chosen to divide the 65536 as a 256 in each
+%D operand. However, in the series calculating the sine and
+%D cosine, I know that the terms are small (because I never
+%D have an angle greater than 45 degrees), so I chose to
+%D apportion the factor in a different way.
+
+%M \stop
+
+%D The path is output using the values saved on the stack. If
+%D needed, all coordinates are recalculated.
+
+\def\finishMPpath
+ {\PDFcode{\ifcase\finiMPpath W n\or S\or f\or B\fi}}
+
+\def\processMPpath
+ {\checkMPpath
+ \ifcase\nofMPsegments\else
+ \flushMPpath
+ \closeMPpath
+ \finishMPpath
+ \fi
+ \let\handleMPsequence\dohandleMPsequence
+ \resetMPstack
+ \nofMPsegments\zerocount
+ \handleMPsequence}
+
+%D The following \METAPOST\ code is quite valid but, when
+%D processed and converted to \PDF, will make a file
+%D unprintable on a Hewlett Packard printer (from Acrobat
+%D $v<=5$). Who is to blame, the driver of the OS layer in
+%D between, is hard to determine, so we add an additional
+%D check.
+%D
+%D \starttyping
+%D clip currentpicture to origin -- cycle ;
+%D setbounds currentpicture to fullsquare scaled 5cm ;
+%D \stoptyping
+
+\def\checkMPpath
+ {\ifcase\finiMPpath
+ \ifnum\nofMPsegments<\plusthree % n is one ahead
+ \message{omitting zero clip path}%
+ \nofMPsegments\zerocount
+ \fi
+ \fi}
+
+%D In \PDF\ the \type{cm} operator must precede the path
+%D specification. We therefore can output the \type{cm} at
+%D the moment we encounter it.
+
+\def\handleMPpathconcat
+ {\presetMPconcat
+ \PDFcode{\gMPs1 \gMPs2 \gMPs3 \gMPs4 \gMPs5 \gMPs6 cm}%
+ \resetMPstack}
+
+\def\handleMPpathscale
+ {\presetMPscale
+ \PDFcode{\gMPs1 0 0 \gMPs2 0 0 cm}%
+ \resetMPstack}
+
+%D This macro interprets the path and saves it as compact as
+%D possible.
+
+\def\dohandleMPpath#1%
+ {\ifcase\lccode`#1\relax
+ \@EA\dohandleMPpathA
+ \else
+ \@EA\dohandleMPpathB
+ \fi#1}
+
+\let\dohandleMPpathA\setMPsequence
+
+\def\installMPSkeywordP#1#2%
+ {\expandafter\def\csname\@@MP:P:#1\endcsname{#2}}
+
+\def\installMPSshortcutP#1#2% todo: \let
+ {\expandafter\let\csname\@@MP:P:#1\expandafter\endcsname\csname\@@MP:P:#2\endcsname}
+
+\def\dohandleMPpathB#1 %
+ {\def\somestring{#1}%
+ \executeifdefined{\@@MP:P:\somestring}\relax
+ \handleMPsequence}
+
+\installMPSkeywordP \PSlineto
+ {\setMPkeyword0 }
+\installMPSkeywordP \PScurveto
+ {\setMPkeyword1 }
+\installMPSkeywordP \PSrlineto
+ {\setMPkeyword2 }
+\installMPSkeywordP \PSmoveto
+ {\edef\lastMPmoveX{\gMPs1}%
+ \edef\lastMPmoveY{\gMPs2}%
+ \resetMPstack
+ \setMPkeyword3 }
+\installMPSkeywordP \PSclip
+ {% \chardef\finiMPpath\zerocount % already
+ \let\handleMPsequence\processMPpath}
+\installMPSkeywordP \PSgsave
+ {\chardef\finiMPpath\plusthree}
+\installMPSkeywordP \PSgrestore
+ {}
+\installMPSkeywordP \PSfill
+ {\ifcase\finiMPpath
+ \chardef\finiMPpath\plustwo
+ \let\handleMPsequence\processMPpath
+ \fi}
+\installMPSkeywordP \PSstroke
+ {\ifcase\finiMPpath
+ \chardef\finiMPpath\plusone
+ \fi
+ \let\handleMPsequence\processMPpath}
+\installMPSkeywordP \PSclosepath
+ {\def\closeMPpath{\PDFcode{h}}}
+\installMPSkeywordP \PSconcat
+ {\cleanupMPconcat
+ \let\flushMPpath\flushconcatMPpath
+ \handleMPpathconcat}
+\installMPSkeywordP \PSscale
+ {\let\flushMPpath\flushconcatMPpath
+ \handleMPpathscale}
+
+\installMPSshortcutP {l} \PSlineto
+\installMPSshortcutP {r} \PSrlineto
+\installMPSshortcutP {m} \PSmoveto
+\installMPSshortcutP {c} \PScurveto
+
+\installMPSshortcutP {q} \PSgsave
+\installMPSshortcutP {Q} \PSgrestore
+\installMPSshortcutP {S} \PSstroke
+\installMPSshortcutP {F} \PSfill
+\installMPSshortcutP {B} \PSgsave
+\installMPSshortcutP {W} \PSclip
+\installMPSshortcutP {p} \PSclosepath
+
+\installMPSshortcutP {s} \PSscale
+\installMPSshortcutP {t} \PSconcat
+
+%D \macros
+%D {twodigitMPoutput}
+%D
+%D We can limit the precision to two digits after the comma
+%D by saying:
+%D
+%D \starttyping
+%D \twodigitMPoutput
+%D \stoptyping
+%D
+%D This option only works in \CONTEXT\ combined with \ETEX.
+
+\def\twodigitMPoutput
+ {\let\!MP \twodigitrounding
+ \def\!MPgMPs##1{\twodigitrounding{\gMPs##1}}%
+ \def\!MPgMPa##1{\twodigitrounding{\gMPa##1}}}
+
+\let\!MP \empty
+\let\!MPgMPa\gMPa
+\let\!MPgMPs\gMPs
+
+%D Here comes the special-specific code:
+
+\def\setMPextensions
+ {\ifconditional\manyMPspecials
+ \def\MPrgbnumber##1{\expandafter\doMPrgbnumber##10000.00000\relax}%
+ \def\doMPrgbnumber##1.##2##3##4##5##6\relax{##2##3##4##5}%
+ \else
+ \def\MPrgbnumber##1{\expandafter\doMPrgbnumber##1000.0000\relax}%
+ \def\doMPrgbnumber##1.##2##3##4##5\relax{##2##3##4}%
+ \fi}
+
+% \settrue\manyMPspecials \setMPextensions
+
+%D This macro handles the special definitions that are
+%D passed as comment.
+
+%D The implementation below saves the data on the stack in
+%D a way similar to the macros in \type {supp-pdf.tex}, and
+%D just overload a few already defined handlers. That way,
+%D the existing macros are still generic. \footnote {Actually,
+%D the macros here are just as generic.}
+%D
+%D Currently the only extension concerns shading, which is
+%D accomplished by handling yet another value of \type
+%D {\finiMPpath}. The recource disctionary is stored and
+%D later picked up by the general \CONTEXT\ figure inclusion
+%D macros.
+
+%D The \type {%%MetaPostSpecials: version.revision signal} line
+%D triggers this module into handling color specifications kind
+%D of special. We need this safeguard for non||special
+%D usage.
+
+%D When defined inline, we use another macro to handle the
+%D definitions. Actually, this macro is called by the
+%D previous ones.
+
+\chardef\MPspecialversion = 0 % specials when >1
+\chardef\MPspecialrevision = 0 % specials when >1
+\chardef\MPspecialsignal = 0 % passed on by graphic
+
+\chardef\inlineMPspecials = 1 % only needed for stack resetting
+
+\def\dohandleMPspecialcomment#1
+ {\setMPargument{#1}%
+ \advance\scratchcounter \minusone
+ \ifcase\scratchcounter
+ \handleMPspecialcommand
+ \donetrue
+ \doresetMPstack
+ \let\handleMPsequence\dohandleMPsequence
+ \expandafter\handleMPsequence
+ \else
+ \expandafter\dohandleMPspecialcomment
+ \fi}
+
+\def\handleMPspecialcomment #1 % number of arguments
+ {\doresetMPstack
+ \scratchcounter#1\relax
+ \ifcase\scratchcounter % when zero, inline shading is used
+ \chardef\inlineMPspecials\plusone
+ \let\handleMPsequence\dohandleMPsequence
+ \expandafter\handleMPsequence
+ \else
+ \chardef\inlineMPspecials\zerocount
+ \expandafter\dohandleMPspecialcomment
+ \fi}
+
+%D When defined inline, we use another macro to handle the
+%D definitions. Actually, this macro is called by the
+%D previous ones.
+
+\def\handleMPspecialcommand
+ {\ifcase\inlineMPspecials\or
+ \advance\nofMParguments \minusone % pop the size
+ \fi
+ \ifundefined\MPspecial % beware, no real \if
+ \message{[unknown \MPspecial]}%
+ \else
+ \csname\MPspecial\endcsname
+ \fi
+ \ifcase\inlineMPspecials
+ \doresetMPstack % 0
+ \else
+ \resetMPstack % 1
+ \fi}
+
+\def\handleMPspecialscomment #1.#2 #3 % version.revision signal #4=div=1000|10000
+ {\doresetMPstack
+ \chardef\MPspecialversion #1%
+ \chardef\MPspecialrevision#2%
+ \chardef\MPspecialsignal #3%
+ \let\handleMPsequence\dohandleMPsequence
+ \ifnum#1=\plusone
+ \expandafter\handleMPsequence
+ \else
+ \expandafter\handleMPspecialscommentx
+ \fi}
+
+\def\handleMPspecialscommentx #1 % version 2
+ {\ifnum10000=0#1\relax
+ \settrue \manyMPspecials
+ \else
+ \setfalse\manyMPspecials
+ \fi
+ \setMPextensions
+ \handleMPsequence}
+
+\def\handleMPrgbcolor
+ {\edef\lastMPrvalue{\csname\@@MP01\endcsname}%{\gMPs1}%
+ \edef\lastMPgvalue{\csname\@@MP02\endcsname}%{\gMPs2}%
+ \edef\lastMPbvalue{\csname\@@MP03\endcsname}%{\gMPs3}%
+ \ifnum\MPrgbnumber\lastMPrvalue=123\relax
+ \csname\@@MPSK\number\MPrgbnumber\lastMPbvalue\endcsname
+ \else
+ \dohandleMPrgb\lastMPrvalue\lastMPgvalue\lastMPbvalue
+ \fi}
+
+\def\handleMPgraycolor{\dohandleMPgray{\gMPs1}}
+\def\handleMPcmykcolor{\dohandleMPcmyk{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}}
+\def\handleMPspotcolor{\dohandleMPspot{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}}
+
+% \newcontitional\ignoreMPpath
+
+\def\finishMPpath
+ {\ifconditional\ignoreMPpath
+ \PDFcode{W n\space}%
+ \else
+ \PDFcode{\ifcase\finiMPpath W n\or S\or f\or B\else W n\fi}%
+ \fi
+ \ifx\extraMPpathcode\empty\else
+ \PDFcode{\extraMPpathcode}%
+ \let\extraMPpathcode\empty
+ \fi
+ \setfalse\ignoreMPpath}
+
+\def\processMPpath
+ {\checkMPpath % !
+ \flushMPpath
+ \closeMPpath
+ \finishMPpath
+ \let\handleMPsequence\dohandleMPsequence
+ \resetMPstack
+ \nofMPsegments\zerocount
+ \handleMPsequence}
+
+\protect \endinput
+
+% When i'm bored ...
+
+% \newcatcodetable\mpscatcodes
+
+% \startcatcodetable \mpscatcodes
+% \catcode`\| \@@comment
+% \catcode`\% \@@active
+% \catcode`\[ \@@active
+% \catcode`\] \@@active
+% \catcode`\{ \@@active
+% \catcode`\} \@@active
+% \stopcatcodetable
+
+% \def\keepMPspecials
+% {\setcatcodecommand \mpscatcodes `\% \letterpercent
+% \setcatcodecommand \mpscatcodes `\[ \letterleftbracket
+% \setcatcodecommand \mpscatcodes `\] \letterrightbracket
+% \setcatcodecommand \mpscatcodes `\{ \letterleftbrace
+% \setcatcodecommand \mpscatcodes `\} \letterrightbrace}
+
+% \def\ignoreMPspecials
+% {\setcatcodecommand \mpscatcodes `\% \letterpercent
+% \setcatcodecommand \mpscatcodes `\[ \empty
+% \setcatcodecommand \mpscatcodes `\] \empty
+% \setcatcodecommand \mpscatcodes `\{ \empty
+% \setcatcodecommand \mpscatcodes `\} \empty}
+
+% \def\obeyMPspecials
+% {\setcatcodecommand \mpscatcodes `\% \letterpercent
+% \setcatcodecommand \mpscatcodes `\[ \letterleftbracket
+% \setcatcodecommand \mpscatcodes `\] \letterrightbracket
+% \setcatcodecommand \mpscatcodes `\{ \letterleftbrace
+% \setcatcodecommand \mpscatcodes `\} \letterrightbrace}
+
+% \gdef\setMPspecials|
+% {\setcatcodetable\mpscatcodes
+% \lccode`\-=\zerocount % to be sure, it could be a letter
+% \lccode`\%=`\%% % otherwise it's seen as a number
+% \def\({\char40\relax }%
+% \def\){\char41\relax }%
+% \def\\{\char92\relax }%
+% \def\0{\octalMPcharacter0}%
+% \def\1{\octalMPcharacter1}%
+% \def\2{\octalMPcharacter2}%
+% \def\3{\octalMPcharacter3}%
+% \def\4{\octalMPcharacter4}%
+% \def\5{\octalMPcharacter5}%
+% \def\6{\octalMPcharacter6}%
+% \def\7{\octalMPcharacter7}%
+% \def\8{\octalMPcharacter8}%
+% \def\9{\octalMPcharacter9}}
diff --git a/tex/context/base/meta-pdf.mkiv b/tex/context/base/meta-pdf.mkiv
new file mode 100644
index 000000000..fa9627fbe
--- /dev/null
+++ b/tex/context/base/meta-pdf.mkiv
@@ -0,0 +1,474 @@
+%D \module
+%D [ file=meta-pdf,
+%D version=2006.06.07,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Conversion to \PDF,
+%D author=Hans Hagen \& others (see text),
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\registerctxluafile{meta-pdf}{1.003}
+
+%D We will clean up the color mess later.
+
+\writestatus{loading}{MetaPost Graphics / MPS to PDF}
+
+\unprotect
+
+%D \macros
+%D {convertMPtoPDF}
+%D
+%D The next set of macros implements \METAPOST\ to \PDF\
+%D conversion. The traditional method is in the MkII file.
+%D
+%D The main conversion command is:
+%D
+%D \starttyping
+%D \convertMPtoPDF {filename} {x scale} {y scale}
+%D \stoptyping
+%D
+%D The dimensions are derived from the bounding box. So we
+%D only have to say:
+%D
+%D \starttyping
+%D \convertMPtoPDF{mp-pra-1.eps}{1}{1}
+%D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5}
+%D \stoptyping
+
+\def\PDFMPformoffset
+ {\ifdefined\objectoffset\objectoffset\else\zeropoint\fi}
+
+%D The main macro:
+
+\def\convertMPtoPDF#1#2#3% scaling no longer supported at this level (so #2 & #3 ignored)
+ {\vbox\bgroup
+ \message{[MP to PDF]}%
+ \xdef\MPfilename{#1}%
+ \glet\MPwidth \!!zeropoint
+ \glet\MPheight\!!zeropoint
+ \glet\MPllx \!!zerocount
+ \glet\MPlly \!!zerocount
+ \glet\MPurx \!!zerocount
+ \glet\MPury \!!zerocount
+ \forgetall
+ \offinterlineskip
+ \setbox\scratchbox\vbox\bgroup
+ \ctxlua{mptopdf.convertmpstopdf("\MPfilename")}\removeunwantedspaces
+ \egroup
+ \setbox\scratchbox\hbox\bgroup
+ \hskip-\MPllx\onebasepoint
+ \raise-\MPlly\onebasepoint
+ \box\scratchbox
+ \egroup
+ \setbox\scratchbox\vbox to \MPheight\bgroup
+ \vfill
+ \hsize\MPwidth
+ \smashbox\scratchbox
+ \box\scratchbox
+ \egroup
+ \wd\scratchbox\MPwidth
+ \ht\scratchbox\MPheight
+ \dopackageMPgraphic\scratchbox
+ \egroup}
+
+%D Objects (move all to backend)
+
+% \def\dopackageMPgraphic#1% #1 = boxregister
+% {\scratchdimen\PDFMPformoffset\relax
+% \ifdim\scratchdimen>\zeropoint % compensate for error
+% \setbox#1\vbox spread 2\scratchdimen
+% {\forgetall\vss\hbox spread 2\scratchdimen{\hss\box#1\hss}\vss}%
+% \fi
+% \setMPPDFobject{#1}%
+% \ifdim\scratchdimen>\zeropoint % compensate for error
+% \vbox to \MPheight
+% {\forgetall\vss\hbox to \MPwidth{\hss\getMPPDFobject\hss}\vss}%
+% \else
+% \getMPPDFobject
+% \fi}
+%
+% \def\setMPPDFobject#1% boxnumber
+% {\the\pdfbackendeveryxform
+% \finalizeobjectbox{#1}%
+% \immediate\pdfxform resources{\pdfcurrentresources}#1%
+% \edef\getMPPDFobject{\noexpand\pdfrefxform\the\pdflastxform}}
+%
+% \let\getMPPDFobject\relax
+
+% we don't need to package as each page has all resources anyway
+
+\let\dopackageMPgraphic\box
+
+%D \macros
+%D {deleteMPgraphic,
+%D startMPresources,
+%D stopMPresources}
+
+\ifx\deleteMPgraphic\undefined
+ \def\deleteMPgraphic#1{}
+\fi
+
+\ifx\startMPresources\undefined
+ \let\startMPresources\relax
+ \let\stopMPresources\relax
+\fi
+
+%D We implement extensions by using the \METAPOST\ special
+%D mechanism. Opposite to \TEX's specials, the \METAPOST\ ones
+%D are flushed before or after the graphic data, but thereby
+%D are no longer connected to a position.
+%D
+%D We implement specials by overloading the \type {fill}
+%D operator. By counting the fills, we can let the converter
+%D treat the appropriate fill in a special way. The
+%D specification of the speciality can have two forms,
+%D determined by the setting of a boolean variable:
+%D
+%D \starttyping
+%D _inline_specials_ := false ; % comment like code (default)
+%D _inline_specials_ := true ; % command like code
+%D \stoptyping
+%D
+%D When the specification is embedded as comment, it looks
+%D like:
+%D
+%D \starttyping
+%D %%MetaPostSpecial
+%D \stoptyping
+%D
+%D The in||line alternative is more tuned for \POSTSCRIPT,
+%D since it permits us to define a macro \type {special}.
+%D
+%D \starttyping
+%D inline : special
+%D \stoptyping
+%D
+%D The \type {identifier} determines what to do, and the data
+%D can be used to accomplish this. A type~2 shading function
+%D has identifier~2. Alltogether, the number of parameters is
+%D specified in \type {size}. The \type {number} is the number
+%D of the fill that needs the special treatment. For a type~2
+%D and~3 shaded fill, the datablock contains the following
+
+%D data:
+%D
+%D \starttyping
+%D from to n inner_r g b x y outer_r g b x y
+%D from to n inner_r g b x y radius outer_r g b x y radius
+%D \stoptyping
+
+\newconditional\manyMPspecials \settrue\manyMPspecials
+
+%D Since colors are not subjected to transformations, we can
+%D only use colors as signal. In our case, we use a dummy colored
+%D path with a red color component of \type {0.n}, so \type
+%D {0.001} is the first path and \type {0.010} the tenth. Since
+%D \METAPOST strips trailing zeros, we have to padd the string.
+
+\newif\ifMPcmykcolors
+\newif\ifMPspotcolors
+
+%D We support specials but assume that the files are somewhat simple
+%D ones wo we have dropped a few. The reason is that runtime \METAPOST\
+%D processing now uses \MPLIB\ so we only need to deal with the
+%D conversion here. See meta-pdh.mkiv (and older files) for more
+%D details. Here we just give a few examples.
+%D
+%D \startbuffer[mp]
+%D fill fullcircle xyscaled (3cm,1cm) withcolor \MPcolor{test} ;
+%D \stopbuffer
+%D
+%D \startbuffer[cmyk]
+%D \startcombination[4*1]
+%D {\definecolor[test][c=1,y=.3,k=.3] \processMPbuffer[mp]} {c=1 y=.3 k=.3}
+%D {\definecolor[test][c=.9,y=.15] \processMPbuffer[mp]} {c=.9 y=.15}
+%D {\definecolor[test][c=.25,y=.8] \processMPbuffer[mp]} {c=.25 y=.8}
+%D {\definecolor[test][c=.45,y=.1] \processMPbuffer[mp]} {c=.45 y=.1}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \placefigure
+%D {\CMYK\ support disabled,
+%D conversion to \RGB.}
+%D {\setupcolors[cmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no support in \METAPOST.}
+%D {\setupcolors[cmyk=ja,mpcmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no conversion to \RGB,
+%D support in \METAPOST}
+%D {\setupcolors[cmyk=ja,state=start]\getbuffer[cmyk]}
+%D
+%D Transparency support used specials 60 (rgb) and 61
+%D (cmyk).
+%D
+%D \startbuffer
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor transparent(1,.5,yellow) ;
+%D fill p rotated 210 withcolor transparent(1,.5,green) ;
+%D fill p rotated 330 withcolor transparent(1,.5,blue) ;
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+%D
+%D One can also communicate colors between \CONTEXT\ and
+%D \METAPOST:
+%D
+%D \startbuffer
+%D \definecolor[tcyan] [c=1,k=.2,t=.5]
+%D \definecolor[tmagenta][m=1,k=.2,t=.5]
+%D \definecolor[tyellow] [y=1,k=.2,t=.5]
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor \MPcolor{tcyan} ;
+%D fill p rotated 210 withcolor \MPcolor{tmagenta} ;
+%D fill p rotated 330 withcolor \MPcolor{tyellow} ;
+%D \stopbuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+%D
+%D Shading is an example of a more advanced graphic feature,
+%D but users will seldom encounter those complications. Here
+%D we only show a few simple examples, but many other
+%D alternatives are possible by setting up the functions built
+%D in \PDF\ in the appropriate way.
+%D
+%D Shading has to do with interpolation between two or more
+%D points or user supplied ranges. In \PDF, the specifications
+%D of a shade has to be encapsulated in objects and passed on
+%D as resources. This is a \PDF\ level 1.3. feature. One can
+%D simulate three dimensional shades as well and define simple
+%D functions using a limited set of \POSTSCRIPT\ primitives.
+%D Given the power of \METAPOST\ and these \PDF\ features, we
+%D can achieve superb graphic effects.
+%D
+%D Since everything is hidden in \TEX\ and \METAPOST\ graphics,
+%D we can stick to high level \CONTEXT\ command, as shown in
+%D the following exmples.
+%D
+%D \startbuffer
+%D \startuniqueMPgraphic{CircularShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D circular_shade(p,0,.2red,.9red) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{LinearShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,0,.2blue,.9blue) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{DuotoneShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,2,.5green,.5red) ;
+%D \stopuniqueMPgraphic
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D These graphics can be hooked into the overlay mechanism,
+%D which is available in many commands.
+%D
+%D \startbuffer
+%D \defineoverlay[demo 1][\uniqueMPgraphic{CircularShade}]
+%D \defineoverlay[demo 2][\uniqueMPgraphic {LinearShade}]
+%D \defineoverlay[demo 3][\uniqueMPgraphic {DuotoneShade}]
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D These backgrounds can for instance be applied to \type
+%D {\framed}:
+%D
+%D \startbuffer
+%D \setupframed[width=3cm,height=2cm,frame=off]
+%D \startcombination[3*1]
+%D {\framed[backgroundachtergrond=demo 1]{\bfd \white Demo 1}} {}
+%D {\framed[backgroundachtergrond=demo 2]{\bfd \white Demo 2}} {}
+%D {\framed[backgroundachtergrond=demo 3]{\bfd \white Demo 3}} {}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D There are a few more alternatives, determined by the second
+%D parameter passed to \type {circular_shade} and alike.
+%D
+%D \def\SomeShade#1#2#3#4#5%
+%D {\startuniqueMPgraphic{Shade-#1}
+%D width := \overlaywidth ;
+%D height := \overlayheight ;
+%D path p ; p := unitsquare xscaled width yscaled height ;
+%D #2_shade(p,#3,#4,#5) ;
+%D \stopuniqueMPgraphic
+%D \defineoverlay[Shade-#1][\uniqueMPgraphic{Shade-#1}]%
+%D \framed[backgroundachtergrond=Shade-#1,width=2cm,height=2cm,frame=off]{}}
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{10}{circular}{0}{.3blue}{.9blue}} {circular 0}
+%D {\SomeShade{11}{circular}{1}{.3blue}{.9blue}} {circular 1}
+%D {\SomeShade{12}{circular}{2}{.3blue}{.9blue}} {circular 2}
+%D {\SomeShade{13}{circular}{3}{.3blue}{.9blue}} {circular 3}
+%D {\SomeShade{14}{circular}{4}{.3blue}{.9blue}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{20}{circular}{0}{.9green}{.3green}} {circular 0}
+%D {\SomeShade{21}{circular}{1}{.9green}{.3green}} {circular 1}
+%D {\SomeShade{22}{circular}{2}{.9green}{.3green}} {circular 2}
+%D {\SomeShade{23}{circular}{3}{.9green}{.3green}} {circular 3}
+%D {\SomeShade{24}{circular}{4}{.9green}{.3green}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \startlinecorrection
+%D \startcombination[4*1]
+%D {\SomeShade{30}{linear}{0}{.3red}{.9red}} {linear 0}
+%D {\SomeShade{31}{linear}{1}{.3red}{.9red}} {linear 1}
+%D {\SomeShade{32}{linear}{2}{.3red}{.9red}} {linear 2}
+%D {\SomeShade{33}{linear}{3}{.3red}{.9red}} {linear 3}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D These macros closely cooperate with the \METAPOST\ module
+%D \type {mp-spec.mp}, which is part of the \CONTEXT\
+%D distribution.
+%D
+%D The low level (\PDF) implementation is based on the \TEX\
+%D based \METAPOST\ to \PDF\ converter. Shading is supported
+%D by overloading the \type {fill} operator as implemented
+%D earlier. In \PDF\ type~2 and~3 shading functions are
+%D specified in terms of:
+%D
+%D \starttabulate[|Tl|l|]
+%D \NC /Domain \NC sort of meeting range \NC \NR
+%D \NC /C0 \NC inner shade \NC \NR
+%D \NC /C1 \NC outer shade \NC \NR
+%D \NC /N \NC smaller values, bigger inner circles \NC \NR
+%D \stoptabulate
+%D
+%D An example of using both special features is the
+%D following.
+%D
+%D \starttyping
+%D \startMPpage
+%D externalfigure "hakker1b.png" scaled 22cm rotated 10 shifted (-2cm,0cm);
+%D externalfigure "hakker1b.png" scaled 10cm rotated -10 ;
+%D externalfigure "hakker1b.png" scaled 7cm rotated 45 shifted (8cm,12cm) ;
+%D path p ; p := unitcircle xscaled 15cm yscaled 20cm;
+%D path q ; q := p rotatedaround(center p,90) ;
+%D path r ; r := buildcycle(p,q) ; clip currentpicture to r ;
+%D path s ; s := boundingbox currentpicture enlarged 5mm ;
+%D picture c ; c := currentpicture ; currentpicture := nullpicture ;
+%D circular_shade(s,0,.2red,.9red) ;
+%D addto currentpicture also c ;
+%D \stopMPpage
+%D \stoptyping
+
+\startMPinitializations
+ mp_shade_version := 2 ;
+\stopMPinitializations
+
+%D This is done much cleaner in \MPLIB.
+
+% %D A common hook.
+%
+% \let\MPfshowcommand\empty
+%
+% \def\MPStextext#1#2#3#4#5% if we clean up this plugin model, we can
+% {\def\MPtextdata{#3}% % delegate the splitter to lua + redesign
+% \def\MPtextsize{#2}%
+% \def\lastMPmoveX{#4}%
+% \def\lastMPmoveY{#5}%
+% \defconvertedcommand\MPtextdata\MPtextdata % no edef
+% \splitstring\MPtextdata\at::::\to\MPtexttag\and\MPtextnumber
+% \executeifdefined{handleMPtext\MPtexttag}
+% {\setbox\scratchbox\hbox
+% {\font\temp=#1\space at #2\onebasepoint
+% \let\c\char
+% \temp
+% \MPfshowcommand{#3}}%
+% \setbox\scratchbox\hbox
+% {\hskip#4\onebasepoint
+% \raise#5\onebasepoint
+% \box\scratchbox}%
+% \smashbox\scratchbox
+% \box\scratchbox}}
+
+\unexpanded\def\MPStextext#1#2#3#4#5% if we clean up this plugin model, we can
+ {\setbox\scratchbox\hbox
+ {\font\temp=#1\space at #2\onebasepoint \let\c\char \temp #3}%
+ \setbox\scratchbox\hbox
+ {\hskip#4\onebasepoint \raise#5\onebasepoint \box\scratchbox}%
+ \smashbox\scratchbox
+ \box\scratchbox}
+
+%D The boundingbox.
+
+\def\MPSboundingbox#1#2#3#4%
+ {\xdef\MPllx{#1}\xdef\MPlly{#2}\xdef\MPurx{#3}\xdef\MPury{#4}%
+ \xdef\MPwidth {\the\dimexpr#3\onebasepoint-#1\onebasepoint\relax}%
+ \xdef\MPheight{\the\dimexpr#4\onebasepoint-#2\onebasepoint\relax}}
+
+\MPSboundingbox0000
+
+%D Test code:
+%D
+%D \startbuffer
+%D \startMPcode
+%D fill fullcircle scaled 3cm withcolor red ;
+%D fill fullcircle scaled 2cm withcolor green ;
+%D fill fullcircle scaled 1cm withcolor blue ;
+%D currentpicture := currentpicture shifted (-4cm,0) ;
+%D fill fullcircle scaled 3cm withcolor cmyk(0,0,1,0) ;
+%D fill fullcircle scaled 2cm withcolor cmyk(0,1,0,0) ;
+%D fill fullcircle scaled 1cm withcolor cmyk(0,0,1,0) ;
+%D currentpicture := currentpicture shifted (-4cm,0) ;
+%D draw fullcircle scaled 3cm dashed evenly ;
+%D draw fullcircle scaled 2cm dashed withdots ;
+%D draw origin withpen pencircle scaled 3mm;
+%D currentpicture := currentpicture shifted (-4cm,0) ;
+%D fill fullcircle scaled 2cm shifted (-.5cm,+.5cm) withcolor transparent(1,.5,red);
+%D fill fullcircle scaled 2cm shifted (-.5cm,-.5cm) withcolor transparent(1,.5,red);
+%D fill fullcircle scaled 2cm shifted (+.5cm,+.5cm) withcolor transparent(1,.5,green);
+%D fill fullcircle scaled 2cm shifted (+.5cm,-.5cm) withcolor transparent(1,.5,cmyk(1,0,1,.5));
+%D currentpicture := currentpicture shifted (12cm,-4cm) ;
+%D draw "o e p s" infont defaultfont scaled 2 shifted (-1cm,0) ;
+%D currentpicture := currentpicture shifted (-4cm,0) ;
+%D % bug: shift
+%D draw fullcircle scaled 3cm withpen pencircle yscaled 3mm xscaled 2mm rotated 30 ;
+%D draw fullcircle scaled 2cm withpen pencircle yscaled 3mm xscaled 2mm rotated 20 withcolor red ;
+%D filldraw fullcircle scaled 1cm withpen pencircle yscaled 3mm xscaled 2mm rotated 10 withcolor green ;
+%D currentpicture := currentpicture shifted (-4cm,0) ;
+%D % shade cannot handle shift
+%D circular_shade(fullcircle scaled 3cm,0,.2red,.9green) ;
+%D circular_shade(fullcircle scaled 3cm shifted(+4cm,0),0,cmyk(1,0,0,0),cmyk(0,1,0,0)) ;
+%D filldraw boundingbox currentpicture enlarged -3cm withpen pencircle scaled 1pt withcolor .5white ;
+%D \stopMPcode
+%D \stopbuffer
+%D
+%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection
+
+\protect \endinput
diff --git a/tex/context/base/meta-pdh.lua b/tex/context/base/meta-pdh.lua
new file mode 100644
index 000000000..05cdfc176
--- /dev/null
+++ b/tex/context/base/meta-pdh.lua
@@ -0,0 +1,602 @@
+if not modules then modules = { } end modules ['meta-pdf'] = {
+ version = 1.001,
+ comment = "companion to meta-pdf.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This file contains the history of the converter. We keep it around as it
+-- relates to the development of luatex.
+
+-- This is the third version. Version 1 converted to Lua code,
+-- version 2 gsubbed the file into TeX code, and version 3 uses
+-- the new lpeg functionality and streams the result into TeX.
+
+-- We will move old stuff to edu.
+
+--~ old lpeg 0.4 lpeg 0.5
+--~ 100 times test graphic 2.45 (T:1.07) 0.72 (T:0.24) 0.580 (0.560 no table) -- 0.54 optimized for one space (T:0.19)
+--~ 100 times big graphic 10.44 4.30/3.35 nogb 2.914 (2.050 no table) -- 1.99 optimized for one space (T:0.85)
+--~ 500 times test graphic T:1.29 T:1.16 (T:1.10 no table) -- T:1.10
+
+-- only needed for mp output on disk
+
+local concat, format, find, gsub, gmatch = table.concat, string.format, string.find, string.gsub, string.gmatch
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+local tostring, tonumber, select = tostring, tonumber, select
+local lpegmatch = lpeg.match
+
+mptopdf = { }
+mptopdf.parsers = { }
+mptopdf.parser = 'none'
+mptopdf.n = 0
+
+function mptopdf.reset()
+ mptopdf.data = ""
+ mptopdf.path = { }
+ mptopdf.stack = { }
+ mptopdf.texts = { }
+ mptopdf.version = 0
+ mptopdf.shortcuts = false
+ mptopdf.resetpath()
+end
+
+function mptopdf.resetpath()
+ mptopdf.stack.close = false
+ mptopdf.stack.path = { }
+ mptopdf.stack.concat = nil
+ mptopdf.stack.special = false
+end
+
+mptopdf.reset()
+
+function mptopdf.parsers.none()
+ -- no parser set
+end
+
+function mptopdf.parse()
+ mptopdf.parsers[mptopdf.parser]()
+end
+
+-- old code
+
+mptopdf.steps = { }
+
+mptopdf.descapes = {
+ ['('] = "\\\\char40 ",
+ [')'] = "\\\\char41 ",
+ ['"'] = "\\\\char92 "
+}
+
+function mptopdf.descape(str)
+ str = gsub(str,"\\(%d%d%d)",function(n)
+ return "\\char" .. tonumber(n,8) .. " "
+ end)
+ return gsub(str,"\\([%(%)\\])",mptopdf.descapes)
+end
+
+function mptopdf.steps.descape(str)
+ str = gsub(str,"\\(%d%d%d)",function(n)
+ return "\\\\char" .. tonumber(n,8) .. " "
+ end)
+ return gsub(str,"\\([%(%)\\])",mptopdf.descapes)
+end
+
+function mptopdf.steps.strip() -- .3 per expr
+ mptopdf.data = gsub(mptopdf.data,"^(.-)%%+Page:.-%c+(.*)%s+%a+%s+%%+EOF.*$", function(preamble, graphic)
+ local bbox = "0 0 0 0"
+ for b in gmatch(preamble,"%%%%%a+oundingBox: +(.-)%c+") do
+ bbox = b
+ end
+ local name, version = gmatch(preamble,"%%%%Creator: +(.-) +(.-) ")
+ mptopdf.version = tostring(version or "0")
+ if find(preamble,"/hlw{0 dtransform") then
+ mptopdf.shortcuts = true
+ end
+ -- the boundingbox specification needs to come before data, well, not really
+ return bbox .. " boundingbox\n" .. "\nbegindata\n" .. graphic .. "\nenddata\n"
+ end, 1)
+ mptopdf.data = gsub(mptopdf.data,"%%%%MetaPostSpecials: +(.-)%c+", "%1 specials\n", 1)
+ mptopdf.data = gsub(mptopdf.data,"%%%%MetaPostSpecial: +(.-)%c+", "%1 special\n")
+ mptopdf.data = gsub(mptopdf.data,"%%.-%c+", "")
+end
+
+function mptopdf.steps.cleanup()
+ if not mptopdf.shortcuts then
+ mptopdf.data = gsub(mptopdf.data,"gsave%s+fill%s+grestore%s+stroke", "both")
+ mptopdf.data = gsub(mptopdf.data,"([%d%.]+)%s+([%d%.]+)%s+dtransform%s+exch%s+truncate%s+exch%s+idtransform%s+pop%s+setlinewidth", function(wx,wy)
+ if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end
+ end)
+ mptopdf.data = gsub(mptopdf.data,"([%d%.]+)%s+([%d%.]+)%s+dtransform%s+truncate%s+idtransform%s+setlinewidth%s+pop", function(wx,wy)
+ if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end
+ end)
+ end
+end
+
+function mptopdf.steps.convert()
+ mptopdf.data = gsub(mptopdf.data,"%c%((.-)%) (.-) (.-) fshow", function(str,font,scale)
+ mptopdf.texts[mptopdf.texts+1] = {mptopdf.steps.descape(str), font, scale}
+ return "\n" .. #mptopdf.texts .. " textext"
+ end)
+ mptopdf.data = gsub(mptopdf.data,"%[%s*(.-)%s*%]", function(str)
+ return gsub(str,"%s+"," ")
+ end)
+ local t
+ mptopdf.data = gsub(mptopdf.data,"%s*([^%a]-)%s*(%a+)", function(args,cmd)
+ if cmd == "textext" then
+ t = mptopdf.texts[tonumber(args)]
+ return "mps.textext(" .. "\"" .. t[2] .. "\"," .. t[3] .. ",\"" .. t[1] .. "\")\n"
+ else
+ return "mps." .. cmd .. "(" .. gsub(args," +",",") .. ")\n"
+ end
+ end)
+end
+
+function mptopdf.steps.process()
+ assert(loadstring(mptopdf.data))() -- () runs the loaded chunk
+end
+
+function mptopdf.parsers.gsub()
+ mptopdf.steps.strip()
+ mptopdf.steps.cleanup()
+ mptopdf.steps.convert()
+ mptopdf.steps.process()
+end
+
+-- end of old code
+
+-- from lua to tex
+
+function mptopdf.pdfcode(str)
+ texsprint(ctxcatcodes,"\\pdfliteral{" .. str .. "}") -- \\MPScode
+end
+
+function mptopdf.texcode(str)
+ texsprint(ctxcatcodes,str)
+end
+
+-- auxiliary functions
+
+function mptopdf.flushconcat()
+ if mptopdf.stack.concat then
+ mptopdf.pdfcode(concat(mptopdf.stack.concat," ") .. " cm")
+ mptopdf.stack.concat = nil
+ end
+end
+
+function mptopdf.flushpath(cmd)
+ -- faster: no local function and loop
+ if #mptopdf.stack.path > 0 then
+ local path = { }
+ if mptopdf.stack.concat then
+ local sx, sy = mptopdf.stack.concat[1], mptopdf.stack.concat[4]
+ local rx, ry = mptopdf.stack.concat[2], mptopdf.stack.concat[3]
+ local tx, ty = mptopdf.stack.concat[5], mptopdf.stack.concat[6]
+ local d = (sx*sy) - (rx*ry)
+ local function mpconcat(px, py)
+ return (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d
+ end
+ local stackpath = mptopdf.stack.path
+ for k=1,#stackpath do
+ local v = stackpath[k]
+ v[1],v[2] = mpconcat(v[1],v[2])
+ if #v == 7 then
+ v[3],v[4] = mpconcat(v[3],v[4])
+ v[5],v[6] = mpconcat(v[5],v[6])
+ end
+ path[#path+1] = concat(v," ")
+ end
+ else
+ local stackpath = mptopdf.stack.path
+ for k=1,#stackpath do
+ path[#path+1] = concat(stackpath[k]," ")
+ end
+ end
+ mptopdf.flushconcat()
+ mptopdf.texcode("\\MPSpath{" .. concat(path," ") .. "}")
+ if mptopdf.stack.close then
+ mptopdf.texcode("\\MPScode{h " .. cmd .. "}")
+ else
+ mptopdf.texcode("\\MPScode{" .. cmd .."}")
+ end
+ end
+ mptopdf.resetpath()
+end
+
+function mptopdf.loaded(name)
+ local ok, n
+ mptopdf.reset()
+ ok, mptopdf.data, n = resolvers.loadbinfile(name, 'tex') -- we need a binary load !
+ return ok
+end
+
+if not mptopdf.parse then
+ function mptopdf.parse() end -- forward declaration
+end
+
+function mptopdf.convertmpstopdf(name)
+ if mptopdf.loaded(name) then
+ mptopdf.n = mptopdf.n + 1
+ statistics.starttiming(mptopdf)
+ mptopdf.parse()
+ mptopdf.reset()
+ statistics.stoptiming(mptopdf)
+ else
+ tex.print("file " .. name .. " not found")
+ end
+end
+
+-- mp interface
+
+mps = mps or { }
+
+function mps.creator(a, b, c)
+ mptopdf.version = tonumber(b)
+end
+
+function mps.creationdate(a)
+ mptopdf.date= a
+end
+
+function mps.newpath()
+ mptopdf.stack.path = { }
+end
+
+function mps.boundingbox(llx, lly, urx, ury)
+ mptopdf.texcode("\\MPSboundingbox{" .. llx .. "}{" .. lly .. "}{" .. urx .. "}{" .. ury .. "}")
+end
+
+function mps.moveto(x,y)
+ mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"m"}
+end
+
+function mps.curveto(ax, ay, bx, by, cx, cy)
+ mptopdf.stack.path[#mptopdf.stack.path+1] = {ax,ay,bx,by,cx,cy,"c"}
+end
+
+function mps.lineto(x,y)
+ mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"l"}
+end
+
+function mps.rlineto(x,y)
+ local dx, dy = 0, 0
+ if #mptopdf.stack.path > 0 then
+ dx, dy = mptopdf.stack.path[#mptopdf.stack.path][1], mptopdf.stack.path[#mptopdf.stack.path][2]
+ end
+ mptopdf.stack.path[#mptopdf.stack.path+1] = {dx,dy,"l"}
+end
+
+function mps.translate(tx,ty)
+ mptopdf.pdfcode("1 0 0 0 1 " .. tx .. " " .. ty .. " cm")
+end
+
+function mps.scale(sx,sy)
+ mptopdf.stack.concat = {sx,0,0,sy,0,0}
+end
+
+function mps.concat(sx, rx, ry, sy, tx, ty)
+ mptopdf.stack.concat = {sx,rx,ry,sy,tx,ty}
+end
+
+function mps.setlinejoin(d)
+ mptopdf.pdfcode(d .. " j")
+end
+
+function mps.setlinecap(d)
+ mptopdf.pdfcode(d .. " J")
+end
+
+function mps.setmiterlimit(d)
+ mptopdf.pdfcode(d .. " M")
+end
+
+function mps.gsave()
+ mptopdf.pdfcode("q")
+end
+
+function mps.grestore()
+ mptopdf.pdfcode("Q")
+end
+
+function mps.setdash(...)
+ local n = select("#",...)
+ mptopdf.pdfcode("[" .. concat({...}," ",1,n-1) .. "] " .. select(n,...) .. " d")
+end
+
+function mps.resetdash()
+ mptopdf.pdfcode("[ ] 0 d")
+end
+
+function mps.setlinewidth(d)
+ mptopdf.pdfcode(d .. " w")
+end
+
+function mps.closepath()
+ mptopdf.stack.close = true
+end
+
+function mps.fill()
+ mptopdf.flushpath('f')
+end
+
+function mps.stroke()
+ mptopdf.flushpath('S')
+end
+
+function mps.both()
+ mptopdf.flushpath('B')
+end
+
+function mps.clip()
+ mptopdf.flushpath('W n')
+end
+
+function mps.textext(font, scale, str) -- old parser
+ local dx, dy = 0, 0
+ if #mptopdf.stack.path > 0 then
+ dx, dy = mptopdf.stack.path[1][1], mptopdf.stack.path[1][2]
+ end
+ mptopdf.flushconcat()
+ mptopdf.texcode("\\MPStextext{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}")
+ mptopdf.resetpath()
+end
+
+--~ function mps.handletext(font,scale.str,dx,dy)
+--~ local one, two = string.match(str, "^(%d+)::::(%d+)")
+--~ if one and two then
+--~ mptopdf.texcode("\\MPTOPDFtextext{"..font.."}{"..scale.."}{"..one.."}{"..two.."}{"..dx.."}{"..dy.."}")
+--~ else
+--~ mptopdf.texcode("\\MPTOPDFtexcode{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}")
+--~ end
+--~ end
+
+function mps.setrgbcolor(r,g,b) -- extra check
+ r, g = tonumber(r), tonumber(g) -- needed when we use lpeg
+ if r == 0.0123 and g < 0.1 then
+ mptopdf.texcode("\\MPSspecial{" .. g*10000 .. "}{" .. b*10000 .. "}")
+ elseif r == 0.123 and g < 0.1 then
+ mptopdf.texcode("\\MPSspecial{" .. g* 1000 .. "}{" .. b* 1000 .. "}")
+ else
+ mptopdf.texcode("\\MPSrgb{" .. r .. "}{" .. g .. "}{" .. b .. "}")
+ end
+end
+
+function mps.setcmykcolor(c,m,y,k)
+ mptopdf.texcode("\\MPScmyk{" .. c .. "}{" .. m .. "}{" .. y .. "}{" .. k .. "}")
+end
+
+function mps.setgray(s)
+ mptopdf.texcode("\\MPSgray{" .. s .. "}")
+end
+
+function mps.specials(version,signal,factor) -- 2.0 123 1000
+end
+
+function mps.special(...) -- 7 1 0.5 1 0 0 1 3
+ local n = select("#",...)
+ mptopdf.texcode("\\MPSbegin\\MPSset{" .. concat({...},"}\\MPSset{",2,n) .. "}\\MPSend")
+end
+
+function mps.begindata()
+end
+
+function mps.enddata()
+end
+
+function mps.showpage()
+end
+
+mps.n = mps.newpath -- n
+mps.p = mps.closepath -- h
+mps.l = mps.lineto -- l
+mps.r = mps.rlineto -- r
+mps.m = mps.moveto -- m
+mps.c = mps.curveto -- c
+mps.hlw = mps.setlinewidth
+mps.vlw = mps.setlinewidth
+
+mps.C = mps.setcmykcolor -- k
+mps.G = mps.setgray -- g
+mps.R = mps.setrgbcolor -- rg
+
+mps.lj = mps.setlinejoin -- j
+mps.ml = mps.setmiterlimit -- M
+mps.lc = mps.setlinecap -- J
+mps.sd = mps.setdash -- d
+mps.rd = mps.resetdash
+
+mps.S = mps.stroke -- S
+mps.F = mps.fill -- f
+mps.B = mps.both -- B
+mps.W = mps.clip -- W
+
+mps.q = mps.gsave -- q
+mps.Q = mps.grestore -- Q
+
+mps.s = mps.scale -- (not in pdf)
+mps.t = mps.concat -- (not the same as pdf anyway)
+
+mps.P = mps.showpage
+
+-- experimental
+
+function mps.attribute(id,value)
+ mptopdf.texcode("\\attribute " .. id .. "=" .. value .. " ")
+-- mptopdf.texcode("\\dompattribute{" .. id .. "}{" .. value .. "}")
+end
+
+-- lpeg parser
+
+-- The lpeg based parser is rather optimized for the kind of output
+-- that MetaPost produces. It's my first real lpeg code, which may
+-- show. Because the parser binds to functions, we define it last.
+
+do -- assumes \let\c\char
+
+ local byte = string.byte
+ local digit = lpeg.R("09")
+ local spec = digit^2 * lpeg.P("::::") * digit^2
+ local text = lpeg.Cc("{") * (
+ lpeg.P("\\") * ( (digit * digit * digit) / function(n) return "c" .. tonumber(n,8) end) +
+ lpeg.P(" ") / function(n) return "\\c32" end + -- never in new mp
+ lpeg.P(1) / function(n) return "\\c" .. byte(n) end
+ ) * lpeg.Cc("}")
+ local package = lpeg.Cs(spec + text^0)
+
+ function mps.fshow(str,font,scale) -- lpeg parser
+ mps.textext(font,scale,lpegmatch(package,str))
+ end
+
+end
+
+do
+
+ local eol = lpeg.S('\r\n')^1
+ local sp = lpeg.P(' ')^1
+ local space = lpeg.S(' \r\n')^1
+ local number = lpeg.S('0123456789.-+')^1
+ local nonspace = lpeg.P(1-lpeg.S(' \r\n'))^1
+
+ local cnumber = lpeg.C(number)
+ local cstring = lpeg.C(nonspace)
+
+ local specials = (lpeg.P("%%MetaPostSpecials:") * sp * (cstring * sp^0)^0 * eol) / mps.specials
+ local special = (lpeg.P("%%MetaPostSpecial:") * sp * (cstring * sp^0)^0 * eol) / mps.special
+ local boundingbox = (lpeg.P("%%BoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
+ local highresboundingbox = (lpeg.P("%%HiResBoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
+
+ local setup = lpeg.P("%%BeginSetup") * (1 - lpeg.P("%%EndSetup") )^1
+ local prolog = lpeg.P("%%BeginProlog") * (1 - lpeg.P("%%EndProlog"))^1
+ local comment = lpeg.P('%')^1 * (1 - eol)^1
+
+ local curveto = ((cnumber * sp)^6 * lpeg.P("curveto") ) / mps.curveto
+ local lineto = ((cnumber * sp)^2 * lpeg.P("lineto") ) / mps.lineto
+ local rlineto = ((cnumber * sp)^2 * lpeg.P("rlineto") ) / mps.rlineto
+ local moveto = ((cnumber * sp)^2 * lpeg.P("moveto") ) / mps.moveto
+ local setrgbcolor = ((cnumber * sp)^3 * lpeg.P("setrgbcolor") ) / mps.setrgbcolor
+ local setcmykcolor = ((cnumber * sp)^4 * lpeg.P("setcmykcolor") ) / mps.setcmykcolor
+ local setgray = ((cnumber * sp)^1 * lpeg.P("setgray") ) / mps.setgray
+ local newpath = ( lpeg.P("newpath") ) / mps.newpath
+ local closepath = ( lpeg.P("closepath") ) / mps.closepath
+ local fill = ( lpeg.P("fill") ) / mps.fill
+ local stroke = ( lpeg.P("stroke") ) / mps.stroke
+ local clip = ( lpeg.P("clip") ) / mps.clip
+ local both = ( lpeg.P("gsave fill grestore")) / mps.both
+ local showpage = ( lpeg.P("showpage") )
+ local setlinejoin = ((cnumber * sp)^1 * lpeg.P("setlinejoin") ) / mps.setlinejoin
+ local setlinecap = ((cnumber * sp)^1 * lpeg.P("setlinecap") ) / mps.setlinecap
+ local setmiterlimit = ((cnumber * sp)^1 * lpeg.P("setmiterlimit") ) / mps.setmiterlimit
+ local gsave = ( lpeg.P("gsave") ) / mps.gsave
+ local grestore = ( lpeg.P("grestore") ) / mps.grestore
+
+ local setdash = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("setdash")) / mps.setdash
+ local concat = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("concat") ) / mps.concat
+ local scale = ( (cnumber * sp^0)^6 * sp * lpeg.P("concat") ) / mps.concat
+
+ local fshow = (lpeg.P("(") * lpeg.C((1-lpeg.P(")"))^1) * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow
+ local fshow = (lpeg.P("(") *
+ lpeg.Cs( ( lpeg.P("\\(")/"\\050" + lpeg.P("\\)")/"\\051" + (1-lpeg.P(")")) )^1 )
+ * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow
+
+ local setlinewidth_x = (lpeg.P("0") * sp * cnumber * sp * lpeg.P("dtransform truncate idtransform setlinewidth pop")) / mps.setlinewidth
+ local setlinewidth_y = (cnumber * sp * lpeg.P("0 dtransform exch truncate exch idtransform pop setlinewidth") ) / mps.setlinewidth
+
+ local c = ((cnumber * sp)^6 * lpeg.P("c") ) / mps.curveto -- ^6 very inefficient, ^1 ok too
+ local l = ((cnumber * sp)^2 * lpeg.P("l") ) / mps.lineto
+ local r = ((cnumber * sp)^2 * lpeg.P("r") ) / mps.rlineto
+ local m = ((cnumber * sp)^2 * lpeg.P("m") ) / mps.moveto
+ local vlw = ((cnumber * sp)^1 * lpeg.P("vlw")) / mps.setlinewidth
+ local hlw = ((cnumber * sp)^1 * lpeg.P("hlw")) / mps.setlinewidth
+
+ local R = ((cnumber * sp)^3 * lpeg.P("R") ) / mps.setrgbcolor
+ local C = ((cnumber * sp)^4 * lpeg.P("C") ) / mps.setcmykcolor
+ local G = ((cnumber * sp)^1 * lpeg.P("G") ) / mps.setgray
+
+ local lj = ((cnumber * sp)^1 * lpeg.P("lj") ) / mps.setlinejoin
+ local ml = ((cnumber * sp)^1 * lpeg.P("ml") ) / mps.setmiterlimit
+ local lc = ((cnumber * sp)^1 * lpeg.P("lc") ) / mps.setlinecap
+
+ local n = lpeg.P("n") / mps.newpath
+ local p = lpeg.P("p") / mps.closepath
+ local S = lpeg.P("S") / mps.stroke
+ local F = lpeg.P("F") / mps.fill
+ local B = lpeg.P("B") / mps.both
+ local W = lpeg.P("W") / mps.clip
+ local P = lpeg.P("P") / mps.showpage
+
+ local q = lpeg.P("q") / mps.gsave
+ local Q = lpeg.P("Q") / mps.grestore
+
+ local sd = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("sd")) / mps.setdash
+ local rd = ( lpeg.P("rd")) / mps.resetdash
+
+ local s = ( (cnumber * sp^0)^2 * lpeg.P("s") ) / mps.scale
+ local t = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("t") ) / mps.concat
+
+ -- experimental
+
+ local attribute = ((cnumber * sp)^2 * lpeg.P("attribute")) / mps.attribute
+ local A = ((cnumber * sp)^2 * lpeg.P("A")) / mps.attribute
+
+ local preamble = (
+ prolog + setup +
+ boundingbox + highresboundingbox + specials + special +
+ comment
+ )
+
+ local procset = (
+ lj + ml + lc +
+ c + l + m + n + p + r +
+ A +
+ R + C + G +
+ S + F + B + W +
+ vlw + hlw +
+ Q + q +
+ sd + rd +
+ t + s +
+ fshow +
+ P
+ )
+
+ local verbose = (
+ curveto + lineto + moveto + newpath + closepath + rlineto +
+ setrgbcolor + setcmykcolor + setgray +
+ attribute +
+ setlinejoin + setmiterlimit + setlinecap +
+ stroke + fill + clip + both +
+ setlinewidth_x + setlinewidth_y +
+ gsave + grestore +
+ concat + scale +
+ fshow +
+ setdash + -- no resetdash
+ showpage
+ )
+
+ -- order matters in terms of speed / we could check for procset first
+
+ local captures_old = ( space + verbose + preamble )^0
+ local captures_new = ( space + procset + preamble + verbose )^0
+
+ function mptopdf.parsers.lpeg()
+ if find(mptopdf.data,"%%%%BeginResource: procset mpost") then
+ lpegmatch(captures_new,mptopdf.data)
+ else
+ lpegmatch(captures_old,mptopdf.data)
+ end
+ end
+
+end
+
+mptopdf.parser = 'lpeg'
+
+-- status info
+
+statistics.register("mps conversion time",function()
+ local n = mptopdf.n
+ if n > 0 then
+ return format("%s seconds, %s conversions", statistics.elapsedtime(mptopdf),n)
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/meta-pdh.mkiv b/tex/context/base/meta-pdh.mkiv
new file mode 100644
index 000000000..7cdd1471f
--- /dev/null
+++ b/tex/context/base/meta-pdh.mkiv
@@ -0,0 +1,780 @@
+%D \module
+%D [ file=meta-pdf,
+%D version=2006.06.07,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Conversion to \PDF,
+%D author=Hans Hagen \& others (see text),
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Formerly known as supp-pdf.tex and supp-mpe.tex and meta-pdf.mkiv.
+%D
+%D Beware: this file is not used but kept for historic purposed!
+
+% \useMPgraphic{1}
+% \testfeatureonce{250}{\setbox0\hbox{\convertMPtoPDF{test-mps-mpgraph.1}{1}{1}}}
+%
+% 8.4 : mkii, direct parsing by tex
+% 11.8 : mkiv, dirty conversion (10.8 with dirty tricks)
+% 14.5 : mkiv, clean conversion
+% 7.4 : mkiv, simulated clean direct lua from mp
+% 0.3 : time taken by tex to handle converted code
+%
+% timings may differ now that we revamped the backend
+
+\registerctxluafile{meta-pdf}{1.003}
+
+%D We will clean up the color mess later.
+
+\writestatus{loading}{MetaPost Graphics / MPS to PDF}
+
+\unprotect
+
+%D First we define a handy constant:
+
+\bgroup \catcode`\%=\@@other \xdef\letterpercent{\string%} \egroup
+
+%D \macros
+%D {convertMPtoPDF}
+%D
+%D The next set of macros implements \METAPOST\ to \PDF\
+%D conversion. The traditional method is in the MkII file.
+%D
+%D The main conversion command is:
+%D
+%D \starttyping
+%D \convertMPtoPDF {filename} {x scale} {y scale}
+%D \stoptyping
+%D
+%D The dimensions are derived from the bounding box. So we
+%D only have to say:
+%D
+%D \starttyping
+%D \convertMPtoPDF{mp-pra-1.eps}{1}{1}
+%D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5}
+%D \stoptyping
+
+%D \macros
+%D {makeMPintoPDFobject,lastPDFMPobject}
+%D
+%D For experts there are a few more options. When attributes
+%D are to be added, the code must be embedded in an object
+%D accompanied with the appropriate directives. One can
+%D influence this process with \type {\makeMPintoPDFobject}.
+%D
+%D This option defaults to~0, because \CONTEXT\ takes care
+%D of objects at another level, which saves some bytes.
+%D
+%D \starttabulate[|l|l|p|]
+%D \NC 0 \NC never \NC don't use an object \NC\NR
+%D \NC 1 \NC always \NC always use an object \NC\NR
+%D \NC 2 \NC optional \NC use object when needed \NC\NR
+%D \stoptabulate
+%D
+%D The last object number used is avaliable in the macro
+%D \type {\lastPDFMPobject}.
+
+\ifx\makeMPintoPDFobject \undefined \chardef\makeMPintoPDFobject \zerocount \fi
+\ifx\everyMPtoPDFconversion\undefined \newtoks\everyMPtoPDFconversion \fi
+
+\let\lastPDFMPobject \!!zerocount
+\let\currentPDFresources\empty
+\let\setMPextensions \relax
+
+\def\PDFMPformoffset
+ {\ifx\objectoffset\undefined\zeropoint\else\objectoffset\fi}
+
+\def\resetMPvariables#1#2#3%
+ {\global\let\MPwidth \!!zeropoint
+ \global\let\MPheight\!!zeropoint
+ \global\let\MPllx \!!zerocount
+ \global\let\MPlly \!!zerocount
+ \global\let\MPurx \!!zerocount
+ \global\let\MPury \!!zerocount
+ \xdef\MPxscale {#2}\ifx\MPxscale\empty\let\MPxscale\!!plusone\fi
+ \xdef\MPyscale {#3}\ifx\MPyscale\empty\let\MPyscale\!!plusone\fi
+ \xdef\MPfilename {#1}}
+
+%D The main macro:
+
+\def\convertMPtoPDF#1#2#3% watch the transparency reset
+ {\resetMPvariables{#1}{#2}{#3}%
+ \vbox\bgroup
+ \forgetall
+ \offinterlineskip
+ \setbox\scratchbox\vbox\bgroup
+ \setnormalcatcodes % we can be in verbatim or so
+ \message{[MP to PDF]}%
+ \startMPresources
+ \pdfliteral{\letterpercent\space mps begin}%
+ \pdfliteral{q 1 0 0 1 0 0 cm}%
+ \ctxlua{mptopdf.convertmpstopdf("\MPfilename")}\removeunwantedspaces
+ \pdfliteral{Q}%
+ \pdfliteral{\letterpercent\space mps end}%
+ \stopMPresources
+ \egroup
+ \setbox\scratchbox\hbox\bgroup
+ \hskip-\MPllx\onebasepoint
+ \raise-\MPlly\onebasepoint
+ \box\scratchbox
+ \egroup
+ \setbox\scratchbox\vbox to \MPheight\bgroup
+ \vfill
+ \hsize\MPwidth
+ \smashbox\scratchbox
+ \box\scratchbox
+ \egroup
+ \wd\scratchbox\MPwidth
+ \ht\scratchbox\MPheight
+ \dopackageMPgraphic\scratchbox
+ \egroup}
+
+\let\processMPtoPDFfile\convertMPtoPDF
+
+%D A common hook.
+
+\let\MPfshowcommand\empty
+
+%D Objects.
+
+\def\dopackageMPgraphic#1% #1 = boxregister
+ {\ifcase\makeMPintoPDFobject\or\or\ifx\currentPDFresources\empty\else
+ % an existing value of 2 signals object support (set elsewhere)
+ \chardef\makeMPintoPDFobject\plusone
+ \fi\fi
+ \ifcase\makeMPintoPDFobject
+ \box#1%
+ \or
+ \scratchdimen\PDFMPformoffset\relax
+ \ifdim\scratchdimen>\zeropoint % compensate for error
+ \setbox#1\vbox spread 2\scratchdimen
+ {\forgetall\vss\hbox spread 2\scratchdimen{\hss\box#1\hss}\vss}%
+ \fi
+ \setMPPDFobject{\currentPDFresources}{#1}%
+ \ifdim\scratchdimen>\zeropoint % compensate for error
+ \vbox to \MPheight
+ {\forgetall\vss\hbox to \MPwidth{\hss\getMPPDFobject\hss}\vss}%
+ \else
+ \getMPPDFobject
+ \fi
+ \global\let\currentPDFresources\empty
+ \else
+ \box#1%
+ \fi}
+
+\def\setMPPDFobject#1#2% resources boxnumber
+ {\ifx\everyPDFxform\undefined\else\the\everyPDFxform\fi
+ \immediate\pdfxform resources{#1}#2%
+ \edef\getMPPDFobject{\noexpand\pdfrefxform\the\pdflastxform}}
+
+\let\getMPPDFobject\relax
+
+%D \macros
+%D {deleteMPgraphic,
+%D startMPresources,
+%D stopMPresources}
+
+\ifx\deleteMPgraphic\undefined
+ \def\deleteMPgraphic#1{}
+\fi
+
+\ifx\startMPresources\undefined
+ \let\startMPresources\relax
+ \let\stopMPresources\relax
+\fi
+
+%D We implement extensions by using the \METAPOST\ special
+%D mechanism. Opposite to \TEX's specials, the \METAPOST\ ones
+%D are flushed before or after the graphic data, but thereby
+%D are no longer connected to a position.
+%D
+%D We implement specials by overloading the \type {fill}
+%D operator. By counting the fills, we can let the converter
+%D treat the appropriate fill in a special way. The
+%D specification of the speciality can have two forms,
+%D determined by the setting of a boolean variable:
+%D
+%D \starttyping
+%D _inline_specials_ := false ; % comment like code (default)
+%D _inline_specials_ := true ; % command like code
+%D \stoptyping
+%D
+%D When the specification is embedded as comment, it looks
+%D like:
+%D
+%D \starttyping
+%D %%MetaPostSpecial
+%D \stoptyping
+%D
+%D The in||line alternative is more tuned for \POSTSCRIPT,
+%D since it permits us to define a macro \type {special}.
+%D
+%D \starttyping
+%D inline : special
+%D \stoptyping
+%D
+%D The \type {identifier} determines what to do, and the data
+%D can be used to accomplish this. A type~2 shading function
+%D has identifier~2. Alltogether, the number of parameters is
+%D specified in \type {size}. The \type {number} is the number
+%D of the fill that needs the special treatment. For a type~2
+%D and~3 shaded fill, the datablock contains the following
+
+%D data:
+%D
+%D \starttyping
+%D from to n inner_r g b x y outer_r g b x y
+%D from to n inner_r g b x y radius outer_r g b x y radius
+%D \stoptyping
+
+\newconditional\manyMPspecials \settrue\manyMPspecials
+
+%D In case of \PDF, we need to prepare resourcs.
+
+\newtoks\MPstartresources
+\newtoks\MPstopresources
+
+\def\startMPresources
+ {\the\MPstartresources}
+
+\def\stopMPresources
+ {\the\MPstopresources}
+
+%D Some day we may consider collecting local resources.
+
+\appendtoks
+ \global\let\currentPDFresources\empty % kind of redundant
+\to \MPstartresources
+
+% \appendtoks
+% \collectPDFresources
+% \global\let\currentPDFresources\collectedPDFresources
+% \to \MPstopresources
+
+\appendtoksonce
+ \the\everyPDFxform
+\to \MPstopresources
+
+%D Since colors are not subjected to transformations, we can
+%D only use colors as signal. In our case, we use a dummy colored
+%D path with a red color component of \type {0.n}, so \type
+%D {0.001} is the first path and \type {0.010} the tenth. Since
+%D \METAPOST strips trailing zeros, we have to padd the string.
+
+\newif\ifMPcmykcolors
+\newif\ifMPspotcolors
+
+%D Specials:
+
+% \settrue \manyMPspecials \newcount\nofMParguments \let\extraMPpathcode\empty
+%
+% \def\@@MP {@@MP}
+% \def\@@MPSK{@MPSK@}
+%
+% \def\MPspecial{\@@MPSK\@@MPSK\gMPs\nofMParguments}
+%
+% \unexpanded\def\defineMPspecial#1#2%
+% {\setvalue{\@@MPSK\@@MPSK#1}{#2}}
+
+%D Special number~1 is dedicated to \CMYK\ support. If you
+%D want to know why: look at this:
+%D
+%D \startbuffer[mp]
+%D fill fullcircle xyscaled (3cm,1cm) withcolor \MPcolor{test} ;
+%D \stopbuffer
+%D
+%D \startbuffer[cmyk]
+%D \startcombination[4*1]
+%D {\definecolor[test][c=1,y=.3,k=.3] \processMPbuffer[mp]} {c=1 y=.3 k=.3}
+%D {\definecolor[test][c=.9,y=.15] \processMPbuffer[mp]} {c=.9 y=.15}
+%D {\definecolor[test][c=.25,y=.8] \processMPbuffer[mp]} {c=.25 y=.8}
+%D {\definecolor[test][c=.45,y=.1] \processMPbuffer[mp]} {c=.45 y=.1}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \placefigure
+%D {\CMYK\ support disabled,
+%D conversion to \RGB.}
+%D {\setupcolors[cmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no support in \METAPOST.}
+%D {\setupcolors[cmyk=ja,mpcmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no conversion to \RGB,
+%D support in \METAPOST}
+%D {\setupcolors[cmyk=ja,state=start]\getbuffer[cmyk]}
+
+% \let\revokeMPtransparencyspecial\relax
+
+%D Transparency support used specials 60 (rgb) and 61
+%D (cmyk).
+%D
+%D \startbuffer
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor transparent(1,.5,yellow) ;
+%D fill p rotated 210 withcolor transparent(1,.5,green) ;
+%D fill p rotated 330 withcolor transparent(1,.5,blue) ;
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+%D
+%D One can also communicate colors between \CONTEXT\ and
+%D \METAPOST:
+%D
+%D \startbuffer
+%D \definecolor[tcyan] [c=1,k=.2,t=.5]
+%D \definecolor[tmagenta][m=1,k=.2,t=.5]
+%D \definecolor[tyellow] [y=1,k=.2,t=.5]
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor \MPcolor{tcyan} ;
+%D fill p rotated 210 withcolor \MPcolor{tmagenta} ;
+%D fill p rotated 330 withcolor \MPcolor{tyellow} ;
+%D \stopbuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+
+%D Shading is an example of a more advanced graphic feature,
+%D but users will seldom encounter those complications. Here
+%D we only show a few simple examples, but many other
+%D alternatives are possible by setting up the functions built
+%D in \PDF\ in the appropriate way.
+%D
+%D Shading has to do with interpolation between two or more
+%D points or user supplied ranges. In \PDF, the specifications
+%D of a shade has to be encapsulated in objects and passed on
+%D as resources. This is a \PDF\ level 1.3. feature. One can
+%D simulate three dimensional shades as well and define simple
+%D functions using a limited set of \POSTSCRIPT\ primitives.
+%D Given the power of \METAPOST\ and these \PDF\ features, we
+%D can achieve superb graphic effects.
+%D
+%D Since everything is hidden in \TEX\ and \METAPOST\ graphics,
+%D we can stick to high level \CONTEXT\ command, as shown in
+%D the following exmples.
+%D
+%D \startbuffer
+%D \startuniqueMPgraphic{CircularShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D circular_shade(p,0,.2red,.9red) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{LinearShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,0,.2blue,.9blue) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{DuotoneShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,2,.5green,.5red) ;
+%D \stopuniqueMPgraphic
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D These graphics can be hooked into the overlay mechanism,
+%D which is available in many commands.
+%D
+%D \startbuffer
+%D \defineoverlay[demo 1][\uniqueMPgraphic{CircularShade}]
+%D \defineoverlay[demo 2][\uniqueMPgraphic {LinearShade}]
+%D \defineoverlay[demo 3][\uniqueMPgraphic {DuotoneShade}]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D These backgrounds can for instance be applied to \type
+%D {\framed}:
+%D
+%D \startbuffer
+%D \setupframed[width=3cm,height=2cm,frame=off]
+%D \startcombination[3*1]
+%D {\framed[backgroundachtergrond=demo 1]{\bfd \white Demo 1}} {}
+%D {\framed[backgroundachtergrond=demo 2]{\bfd \white Demo 2}} {}
+%D {\framed[backgroundachtergrond=demo 3]{\bfd \white Demo 3}} {}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D There are a few more alternatives, determined by the second
+%D parameter passed to \type {circular_shade} and alike.
+%D
+%D \def\SomeShade#1#2#3#4#5%
+%D {\startuniqueMPgraphic{Shade-#1}
+%D width := \overlaywidth ;
+%D height := \overlayheight ;
+%D path p ; p := unitsquare xscaled width yscaled height ;
+%D #2_shade(p,#3,#4,#5) ;
+%D \stopuniqueMPgraphic
+%D \defineoverlay[Shade-#1][\uniqueMPgraphic{Shade-#1}]%
+%D \framed[backgroundachtergrond=Shade-#1,width=2cm,height=2cm,frame=off]{}}
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{10}{circular}{0}{.3blue}{.9blue}} {circular 0}
+%D {\SomeShade{11}{circular}{1}{.3blue}{.9blue}} {circular 1}
+%D {\SomeShade{12}{circular}{2}{.3blue}{.9blue}} {circular 2}
+%D {\SomeShade{13}{circular}{3}{.3blue}{.9blue}} {circular 3}
+%D {\SomeShade{14}{circular}{4}{.3blue}{.9blue}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \blank
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{20}{circular}{0}{.9green}{.3green}} {circular 0}
+%D {\SomeShade{21}{circular}{1}{.9green}{.3green}} {circular 1}
+%D {\SomeShade{22}{circular}{2}{.9green}{.3green}} {circular 2}
+%D {\SomeShade{23}{circular}{3}{.9green}{.3green}} {circular 3}
+%D {\SomeShade{24}{circular}{4}{.9green}{.3green}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \blank
+%D
+%D \startlinecorrection
+%D \startcombination[4*1]
+%D {\SomeShade{30}{linear}{0}{.3red}{.9red}} {linear 0}
+%D {\SomeShade{31}{linear}{1}{.3red}{.9red}} {linear 1}
+%D {\SomeShade{32}{linear}{2}{.3red}{.9red}} {linear 2}
+%D {\SomeShade{33}{linear}{3}{.3red}{.9red}} {linear 3}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D These macros closely cooperate with the \METAPOST\ module
+%D \type {mp-spec.mp}, which is part of the \CONTEXT\
+%D distribution.
+%D
+%D The low level (\PDF) implementation is based on the \TEX\
+%D based \METAPOST\ to \PDF\ converter. Shading is supported
+%D by overloading the \type {fill} operator as implemented
+%D earlier. In \PDF\ type~2 and~3 shading functions are
+%D specified in terms of:
+%D
+%D \starttabulate[|Tl|l|]
+%D \NC /Domain \NC sort of meeting range \NC \NR
+%D \NC /C0 \NC inner shade \NC \NR
+%D \NC /C1 \NC outer shade \NC \NR
+%D \NC /N \NC smaller values, bigger inner circles \NC \NR
+%D \stoptabulate
+
+% \newcount\currentPDFshade % 0 % global (document wide) counter
+%
+% \def\dosetMPsomePDFshade#1#2%
+% {\immediate\pdfobj
+% {<>}%
+% \immediate\pdfobj
+% {<>}%
+% \global\advance\currentPDFshade \plusone
+% \ctxlua{lpdf.adddocumentshade("Sh\the\currentPDFshade",lpdf.reference(\the\pdflastobj))}%
+% \setxvalue{\@@MPSK#2}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}
+%
+% \def\dosetMPlinearshade {\dosetMPsomePDFshade2}% #1
+% \def\dosetMPcircularshade{\dosetMPsomePDFshade3}% #1
+%
+% \defineMPspecial{30}
+% {\normalexpanded{\noexpand\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
+% \normalexpanded{\noexpand\resolveMPrgbcolor{\gMPs{9}}{\gMPs{10}}{\gMPs{11}}}\to\MPshadeB
+% \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs{12} \gMPs{13}}%
+% \dosetMPlinearshade{\gMPs{14}}}
+%
+% \defineMPspecial{31}
+% {\normalexpanded{\noexpand\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
+% \normalexpanded{\noexpand\resolveMPrgbcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}}\to\MPshadeB
+% \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs9 \gMPs{13} \gMPs{14} \gMPs{15}}%
+% \dosetMPcircularshade{\gMPs{16}}}
+%
+% \defineMPspecial{32}
+% {\normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+% \normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
+% \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
+% \dosetMPlinearshade{\gMPs{16}}}
+%
+% \defineMPspecial{33}
+% {\normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+% \normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
+% \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
+% \dosetMPcircularshade{\gMPs{18}}}
+%
+% \defineMPspecial{34}
+% {\normalexpanded{\noexpand\resolveMPspotcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+% \normalexpanded{\noexpand\resolveMPspotcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
+% \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
+% \dosetMPlinearshade{\gMPs{16}}}
+%
+% \defineMPspecial{35}
+% {\normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+% \normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
+% \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
+% \dosetMPcircularshade{\gMPs{18}}}
+%
+% \newconditional\ignoreMPpath
+%
+% \def\dohandleMPshade#1%
+% {\revokeMPtransparencyspecial
+% \settrue\ignoreMPpath
+% \def\extraMPpathcode{/Sh#1 sh Q}%
+% \pdfliteral{q /Pattern cs}}
+%
+% \defineMPspecial{10}
+% {\setxvalue{\@@MPSK\gMPs8}%
+% {\noexpand\handleMPfigurespecial{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}{\gMPs8}}}
+%
+% \def\handleMPfigurespecial#1#2#3#4#5#6#7#8% todo : combine with ext fig
+% {\global\letvalue{\@@MPSK#8}\empty
+% \vbox to \zeropoint
+% {\vss
+% \hbox to \zeropoint
+% {\ifcase\pdfoutput\or % will be hooked into the special driver
+% \doiffileelse{#7}
+% {\doifundefinedelse{mps:x:#7}
+% {\immediate\pdfximage\!!width\onebasepoint\!!height\onebasepoint{#7}%
+% \setxvalue{mps:x:#7}{\pdfrefximage\the\pdflastximage}}%
+% {\message{[reusing figure #7]}}%
+% \pdfliteral{q #1 #2 #3 #4 #5 #6 cm}%
+% \rlap{\getvalue{mps:x:#7}}%
+% \pdfliteral{Q}}
+% {\message{[unknown figure #7]}}%
+% \fi
+% \hss}}}
+
+%D An example of using both special features is the
+%D following.
+%D
+%D \starttyping
+%D \startMPpage
+%D externalfigure "hakker1b.png" scaled 22cm rotated 10 shifted (-2cm,0cm);
+%D externalfigure "hakker1b.png" scaled 10cm rotated -10 ;
+%D externalfigure "hakker1b.png" scaled 7cm rotated 45 shifted (8cm,12cm) ;
+%D path p ; p := unitcircle xscaled 15cm yscaled 20cm;
+%D path q ; q := p rotatedaround(center p,90) ;
+%D path r ; r := buildcycle(p,q) ; clip currentpicture to r ;
+%D path s ; s := boundingbox currentpicture enlarged 5mm ;
+%D picture c ; c := currentpicture ; currentpicture := nullpicture ;
+%D circular_shade(s,0,.2red,.9red) ;
+%D addto currentpicture also c ;
+%D \stopMPpage
+%D \stoptyping
+
+% \defineMPspecial{20}
+% {\setxvalue{\@@MPSK\gMPs6}%
+% {\noexpand\handleMPhyperlink{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}}
+%
+% \def\handleMPhyperlink#1#2#3#4#5#6%
+% {\global\letvalue{\@@MPSK#6}\empty
+% \setbox\scratchbox\hbox
+% {\setbox\scratchbox\null
+% \wd\scratchbox\dimexpr-#1\onebasepoint+#3\onebasepoint\relax
+% \ht\scratchbox\dimexpr-#2\onebasepoint+#4\onebasepoint\relax
+% \gotobox{\box\scratchbox}[#5]}%
+% \setbox\scratchbox\hbox
+% {\hskip\dimexpr\MPxoffset\onebasepoint+#1\onebasepoint\relax
+% \raise\dimexpr\MPyoffset\onebasepoint+#2\onebasepoint\relax
+% \box\scratchbox}%
+% \smashbox\scratchbox
+% \box\scratchbox}
+
+%D This special (number 50) passes positions to a tex file.
+%D This method uses a two||pass approach an (mis|)|used the
+%D context positioning macros. In \type {core-pos} we will
+%D implement the low level submacro needed.
+%D
+%D \startbuffer
+%D \definelayer[test]
+%D
+%D \setlayer
+%D [test]
+%D [x=\MPx{somepos-1},y=\MPy{somepos-1}]
+%D {Whatever we want here!}
+%D
+%D \setlayer
+%D [test]
+%D [x=\MPx{somepos-2},y=\MPy{somepos-2}]
+%D {Whatever we need there!}
+%D
+%D \startuseMPgraphic{oeps}
+%D draw fullcircle scaled 6cm withcolor red ;
+%D register ("somepos-1",1cm,2cm,center currentpicture) ;
+%D register ("somepos-2",4cm,3cm,(-1cm,-2cm)) ;
+%D \stopuseMPgraphic
+%D
+%D \framed[background=test,offset=overlay]{\useMPgraphic{oeps}}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Here the width and height are not realy used, but one can
+%D imagine situations where tex has to work with values
+%D calculated by \METAPOST.
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D Later we will implement a more convenient macro:
+%D
+%D \starttyping
+%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
+%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
+%D \stoptyping
+
+% \defineMPspecial{50} % x y width height label
+% {\dosavepositionwhd
+% {\gMPs5}%
+% {0}%
+% {\the\dimexpr-\MPllx\onebasepoint+\gMPs1\onebasepoint\relax}
+% {\the\dimexpr\gMPs2\onebasepoint-\scratchdimen+\MPury\onebasepoint\relax}% scratchdimen ?
+% {\the\dimexpr\gMPs3\onebasepoint\relax}%
+% {\the\dimexpr\gMPs4\onebasepoint\relax}%
+% {0pt}}
+
+\startMPinitializations
+ mp_shade_version := 2 ;
+\stopMPinitializations
+
+%D This is done much cleaner in \MPLIB.
+
+\def\MPStextext#1#2#3#4#5% if we clean up this plugin model, we can
+ {\def\MPtextdata{#3}% % delegate the splitter to lua + redesign
+ \def\MPtextsize{#2}%
+ \def\lastMPmoveX{#4}%
+ \def\lastMPmoveY{#5}%
+ \defconvertedcommand\MPtextdata\MPtextdata % no edef
+ \splitstring\MPtextdata\at::::\to\MPtexttag\and\MPtextnumber
+ \executeifdefined{handleMPtext\MPtexttag}
+ {\setbox\scratchbox\hbox
+ {\font\temp=#1\space at #2\onebasepoint
+ \let\c\char
+ \temp
+ \MPfshowcommand{#3}}%
+ \setbox\scratchbox\hbox
+ {\hskip#4\onebasepoint
+ \raise#5\onebasepoint
+ \box\scratchbox}%
+ \smashbox\scratchbox
+ \box\scratchbox}}
+
+%D We save the special variables on a stack. It's not that
+%D fast, but it make implementing the special more convenient.
+
+% \def\MPSbegin
+% {\nofMParguments\zerocount}
+%
+% \def\MPSend
+% {\csname\MPspecial\endcsname}
+%
+% \def\MPSset
+% {\advance\nofMParguments\plusone
+% \expandafter\def\csname\@@MP\number\nofMParguments\endcsname}
+%
+% \def\gMPs#1{\csname\@@MP\number#1\endcsname}
+
+%D The boundingbox.
+
+\def\MPSboundingbox#1#2#3#4%
+ {\xdef\MPllx{#1}\xdef\MPlly{#2}\xdef\MPurx{#3}\xdef\MPury{#4}%
+ \xdef\MPwidth {\the\dimexpr#3\onebasepoint-#1\onebasepoint\relax}%
+ \xdef\MPheight{\the\dimexpr#4\onebasepoint-#2\onebasepoint\relax}}
+
+\MPSboundingbox0000
+
+% \def\MPSspecial#1#2%
+% {\csname\@@MPSK#2\endcsname}
+
+%D A path is (in most cases) just a sequence of \PDF\ commands.
+
+% \newconditional\ignoreMPpath
+
+% \def\MPSpath
+% {\pdfliteral}
+
+% \def\MPScode % hack, will be improved
+% {\ifconditional\ignoreMPpath
+% \pdfliteral{h W n}%
+% \ifx\extraMPpathcode\empty\else
+% \pdfliteral{\extraMPpathcode}%
+% \let\extraMPpathcode\empty
+% \fi
+% \setfalse\ignoreMPpath
+% \expandafter\gobbleoneargument
+% \else
+% \expandafter\pdfliteral
+% \fi}
+
+%D Test code:
+
+% \startMPcode
+% fill fullcircle scaled 3cm withcolor red ;
+% fill fullcircle scaled 2cm withcolor green ;
+% fill fullcircle scaled 1cm withcolor blue ;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% fill fullcircle scaled 3cm withcolor cmyk(0,0,1,0) ;
+% fill fullcircle scaled 2cm withcolor cmyk(0,1,0,0) ;
+% fill fullcircle scaled 1cm withcolor cmyk(0,0,1,0) ;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% draw fullcircle scaled 3cm dashed evenly ;
+% draw fullcircle scaled 2cm dashed withdots ;
+% draw origin withpen pencircle scaled 3mm;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% fill fullcircle scaled 2cm shifted (-.5cm,+.5cm) withcolor transparent(1,.5,red);
+% fill fullcircle scaled 2cm shifted (-.5cm,-.5cm) withcolor transparent(1,.5,red);
+% fill fullcircle scaled 2cm shifted (+.5cm,+.5cm) withcolor transparent(1,.5,green);
+% fill fullcircle scaled 2cm shifted (+.5cm,-.5cm) withcolor transparent(1,.5,cmyk(1,0,1,.5));
+% currentpicture := currentpicture shifted (12cm,-4cm) ;
+% draw "o e p s" infont defaultfont scaled 2 shifted (-1cm,0) ;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% % bug: shift
+% draw fullcircle scaled 3cm withpen pencircle yscaled 3mm xscaled 2mm rotated 30 ;
+% draw fullcircle scaled 2cm withpen pencircle yscaled 3mm xscaled 2mm rotated 20 withcolor red ;
+% filldraw fullcircle scaled 1cm withpen pencircle yscaled 3mm xscaled 2mm rotated 10 withcolor green ;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% % shade cannot handle shift
+% circular_shade(fullcircle scaled 3cm,0,.2red,.9green) ;
+% circular_shade(fullcircle scaled 3cm shifted(+4cm,0),0,cmyk(1,0,0,0),cmyk(0,1,0,0)) ;
+% filldraw boundingbox currentpicture enlarged -3cm withpen pencircle scaled 1pt withcolor .5white ;
+% \stopMPcode
+
+% We cannot use attributes for switching colors in mp literals because
+% grouping (qQ) interferes.
+
+% \def\dohandleMPshade#1%
+% {\revokeMPtransparencyspecial
+% \settrue\ignoreMPpath
+% \def\extraMPpathcode{/#1 sh Q}%
+% \pdfliteral{q /Pattern cs}}
+
+\protect \endinput
diff --git a/tex/context/base/meta-pre.tex b/tex/context/base/meta-pre.tex
new file mode 100644
index 000000000..cb861ff20
--- /dev/null
+++ b/tex/context/base/meta-pre.tex
@@ -0,0 +1,68 @@
+%D \module
+%D [ file=meta-pre,
+%D version=2001.03.21,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Predefined Goodies,
+%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.
+
+%D In this library, we define a couple of handy graphics.
+
+% todo: use the predefine grid macros, mp code will move to
+% mp-* file
+
+\startuseMPgraphic{pagegrid}
+ StartPage ;
+ drawoptions(withcolor .8white) ;
+ fill Field[Text][Text] ;
+ drawoptions(withcolor .65white) ;
+ fill Field[Footer][Text] ;
+ fill Field[Header][Text] ;
+ fill Field[LeftMargin][Text] ;
+ fill Field[RightMargin][Text] ;
+ drawoptions(withcolor .65yellow) ;
+ fill Field[LeftEdge][Text] ;
+ fill Field[RightEdge][Text] ;
+ fill Field[Bottom][Text] ;
+ fill Field[Top][Text] ;
+ drawoptions(withpen pencircle scaled .3pt withcolor .65white) ;
+ for i=-3cm step 1cm until PaperWidth+3cm :
+ draw (i,-3cm)--(i,PaperHeight+3cm) ;
+ endfor ;
+ for i=PaperHeight+3cm step -1cm until -3cm :
+ draw (-3cm,i)--(PaperWidth+3cm,i) ;
+ endfor ;
+ drawoptions(withpen pencircle scaled .15pt) ;
+ for i=.5cm-3cm step 1cm until PaperWidth+3cm :
+ draw (i,-3cm)--(i,PaperHeight+3cm) ;
+ endfor ;
+ for i=PaperHeight-.5cm+3cm step -1cm until -3cm :
+ draw (-3cm,i)--(PaperWidth+3cm,i) ;
+ endfor ;
+ drawoptions(withpen pencircle scaled .3pt withcolor .65red) ;
+ for i=0 step 1cm until PaperWidth :
+ draw (i,0)--(i,PaperHeight) ;
+ endfor ;
+ for i=PaperHeight step -1cm until 0 :
+ draw (0,i)--(PaperWidth,i) ;
+ endfor ;
+ drawoptions(withpen pencircle scaled .15pt withcolor .65red) ;
+ for i=.5cm step 1cm until PaperWidth :
+ draw (i,0)--(i,PaperHeight) ;
+ endfor ;
+ for i=PaperHeight-.5cm step -1cm until 0 :
+ draw (0,i)--(PaperWidth,i) ;
+ endfor ;
+ drawoptions(withpen pencircle scaled 5pt withcolor .65red) ;
+ draw ulcorner Page ;
+ StopPage ;
+\stopuseMPgraphic
+
+\defineoverlay[pagegrid][\useMPgraphic{pagegrid}]
+
+\endinput
diff --git a/tex/context/base/meta-tex.mkii b/tex/context/base/meta-tex.mkii
new file mode 100644
index 000000000..190a694d9
--- /dev/null
+++ b/tex/context/base/meta-tex.mkii
@@ -0,0 +1,350 @@
+%D \module
+%D [ file=meta-tex,
+%D version=2006.06.07,
+%D title=\CONTEXT\ Support Macros,
+%D subtitle=\METAPOST\ fast text insertion,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Many thanks to Fabrice Popineau and Taco Hoekwater in helping me
+%D figure out some aspects of the text inclusion method implemented
+%D here. The following code is derived from a more advanced (and to
+%D be used) mechanism where \TEX, \METAPOST\ and \LUA\ play together.
+
+%D Much of this mechanism was written with running live DVD's of
+%D the Dave Matthews band in the background (or the corner of my
+%D screen).
+
+% todo: testmacro for empty pic
+
+\unprotect
+
+\newwrite\TeXtextwrite
+
+\def\openTeXtexts {\immediate\openout \TeXtextwrite\currentTeXtext.mpb\relax}
+\def\closeTeXtexts{\immediate\closeout\TeXtextwrite}
+
+\def\currentTeXtext {\jobname-mpgraph}
+\def\currentTeXstack{mpgtxt}
+
+\initializeboxstack\currentTeXstack
+
+\newtoks\collectedmptexts
+\newtoks\everyTeXtexts
+
+\chardef\TeXtextsmode\zerocount % no inheritance
+
+\long\def\startTeXtexts#1\stopTeXtexts
+ {\global\collectedmptexts\expandafter{\the\collectedmptexts#1}}
+
+\def\dostartTeXtexts
+ {\global\setfalse\TeXtextdone
+ \startnointerference
+ \openTeXtexts
+ \ifcase\TeXtextsmode
+ % normally there is no need for this (faster anyway)
+ \or
+ \scantokens\expandafter{\the\everyMPTEXgraphic}% brr
+ \or
+ \the\everyTeXtexts
+ \fi
+ \ifrunMPgraphics
+ \initializeboxstack\currentTeXstack
+ \else
+ \global\let\openTeXtexts\relax
+ \global\let\finishTeXtexts\closeTeXtexts
+ \fi}
+
+\def\dostopTeXtexts
+ {\ifrunMPgraphics
+ \closeTeXtexts
+ \fi
+ \stopnointerference}
+
+\let\finishTeXtexts\relax
+
+\appendtoks
+ \finishTeXtexts
+\to \everystoptext
+
+\newconditional\TeXtextdone
+
+% \long\def\TeXtext#1%
+% {\dowithnextboxcontent
+% {\setnormalcatcodes}
+% {\global\settrue\TeXtextdone
+% \immediate\write\TeXtextwrite{savetxt(#1,\the\wd\nextbox,\the\ht\nextbox,\the\dp\nextbox);}%
+% \savebox\currentTeXstack{#1}{\box\nextbox}}
+% \hbox}
+
+\long\def\TeXtext
+ {\dosingleempty\doTeXtext}
+
+% currently, colors in the converter don't use the color stack
+%
+% 0 = nothing, withcolor works ok, but nested colors fail
+% 1 = local color stack ok
+% 2 = obey color stack (not yet supported)
+
+\chardef\TeXtextcolormode\plusone
+
+\def\definetextext[#1]#2{\setvalue{textext@@#1}{#2}}
+
+% \definetextext[framed]{\framed}
+%
+% \startMPcode
+% draw \sometxt[framed]{black} rotated 45 ;
+% \stopMPcode
+
+\long\def\doTeXtext[#1]#2#3%
+ {\begingroup
+ \setnormalcatcodes
+ \chardef\activecharactermode\plusone % compensates ** in meta-ini.mkii
+ \endlinechar\minusone
+ \everyeof\emptytoks
+ %\def\ascii{#3}\scantokens\expandafter{\ascii}}%
+ \setbox\nextbox\hbox
+ {\ifcase\TeXtextcolormode
+ \scantokens{\executeifdefined{textext@@#1}\firstofoneargument{#3}}%
+ \else
+ \localcolortrue
+ \startcurrentcolor
+ \scantokens{\executeifdefined{textext@@#1}\firstofoneargument{#3}}%
+ \stopcurrentcolor
+ \fi}%
+ \global\settrue\TeXtextdone
+ \edef\currenttextxt{\number#2}%
+ \executeifdefined{textext::#1}{\getvalue{textext::depth}}%
+ \savebox\currentTeXstack\currenttextxt{\box\nextbox}%
+ \endgroup}
+
+\setvalue{textext::depth}{\immediate\write\TeXtextwrite{savetxt(\currenttextxt,\the\nextboxwd,\the\nextboxht,\the\nextboxdp) shifted (0,-\the\nextboxdp);}}
+\setvalue{textext::nodepth}{\immediate\write\TeXtextwrite{savetxt(\currenttextxt,\the\nextboxwd,\the\nextboxht,\the\nextboxdp);}}
+
+\setvalue{textext::d}{\getvalue{textext::depth}}
+\setvalue{textext::n}{\getvalue{textext::nodepth}}
+
+\newbox\mptextbox
+
+% \loadmapfile[lm-texnansi.map] % the font is not really used, i.e. nothing ends up in the file
+\definefontsynonym[MPtxtfont][texnansi-lmtt10]
+\definefont[localMPtxtfont][MPtxtfont at 10bp]
+
+\ifx\getTeXtext\undefined
+
+ % this took a while to figure out
+
+ \let\MPtextdata\empty
+
+ \def\getTeXtext
+ {\ifx\MPtextdata\empty\else
+ \localMPtxtfont
+ \setbox\mptextbox\hbox{\foundbox\currentTeXstack{\number\nofTeXtexts}}%
+ \setbox\scratchbox\hbox{\MPtextdata}% set in meta-pdf.mkii/mkiv
+ \edef\mpwd{\the\dimexpr\MPtextsize\dimexpr\wd\scratchbox/10\relax\relax}%
+ \edef\mpht{\the\dimexpr\MPtextsize\dimexpr\ht\scratchbox/10\relax\relax}%
+ \setbox\mptextbox\hbox{\raise\dp\mptextbox\box\mptextbox}%
+ \dp\mptextbox\zeropoint
+ \scale[\c!width=\mpwd,\c!height=\mpht]{\box\mptextbox}%
+ \fi}
+
+\fi
+
+\let\nofTeXtexts\!!zerocount
+
+\setvalue{handleMPtext00001}% only height in tag (00001)
+ {\setbox\scratchbox\hbox
+ {\obeyMPspecials
+ \edef\nofTeXtexts{\number\MPtextnumber}%
+ \getTeXtext}%
+ \setbox\scratchbox\hbox
+ {\hskip\lastMPmoveX\onebasepoint\raise\lastMPmoveY\onebasepoint
+ \box\scratchbox}%
+ \ht\scratchbox\zeropoint
+ \dp\scratchbox\zeropoint
+ \wd\scratchbox\zeropoint
+ \box\scratchbox}
+
+\startMPextensions
+ string txtfile ; txtfile := "\currentTeXtext.mpb" ;
+ string txtfont ; txtfont := "\truefontname{MPtxtfont}" ;
+ string txtpref ; txtpref := "00001::::" ;
+\stopMPextensions
+
+\newcount\metatxtcounter
+
+\long\def\dodofiltersometxt#1#2#3%
+ {\ifx#2\empty
+ \else
+ \advance\metatxtcounter\plusone
+ \TeXtext{\the\metatxtcounter}{#1}%
+ \expandafter\filtersometxt
+ \fi#2#3}
+
+\long\def\redofiltersometxt[#1]#2%
+ {\advance\metatxtcounter\plusone
+ \TeXtext[#1]{\the\metatxtcounter}{#2}%
+ \filtersometxt}
+
+\long\def\filtersometxt#1\sometxt
+ {\doifnextoptionalelse\redofiltersometxt\dodofiltersometxt}
+
+% cleaner in mkiv
+%
+% \filtersometxt abc\sometxt{def};hij\sometxt{klm};\sometxt{}\empty\relax
+
+\long\def\flushTeXtexts#1%
+ {\metatxtcounter\zerocount
+ \dostartTeXtexts
+ \the\collectedmptexts
+ \filtersometxt#1\sometxt{}\empty\relax
+ \dostopTeXtexts
+ \ifconditional\TeXtextdone
+ \immediate\write\MPwrite{loadtxts ; txtnext := 0 ;}%
+ \global\collectedmptexts\emptytoks
+ \fi
+ \metatxtcounter\zerocount}
+
+% \long\def\sometxt#1{sometxt(nexttxt)} % to be used in mp definitions, no ; here
+
+\long\def\sometxt #1#{\dosometxt} % grab optional [args]
+\long\def\dosometxt#1{sometxt(nexttxt)} % to be used in mp definitions, no ; here
+
+% we redefine the writer:
+
+\long\def\writecheckedMPgraphic#1%
+ {\ifforceMPTEXgraphic
+ \global\MPTEXgraphictrue
+ \else
+ \global\MPTEXgraphicfalse
+ \edef\ascii{#1}\defconvertedcommand\MPascii\ascii
+ \the\MPTEXgraphicchecks\relax % \relax is end condition!
+ \fi
+ \flushMPTEXgraphic% % verbatimtex etc
+ \flushTeXtexts{#1}% added
+ \writeMPgraphic{#1}} % potential optimization: pass \ascii
+
+\protect \endinput
+
+% torture test (will move)
+
+\startMPpage
+ numeric a_b_c ;
+ picture p ; pickup pencircle scaled .1pt ;
+ p := \sometxt{Just a \color[blue]{simple} example text.} ;
+ p := image(draw p; draw boundingbox p withcolor red; ) ;
+ p := p rotatedaround(center p, 360*(5/100)) ;
+ draw p ; draw boundingbox p withcolor blue ;
+ currentpicture := currentpicture scaled 20 ;
+ draw boundingbox currentpicture withcolor .5white ;
+ setbounds currentpicture to boundingbox currentpicture enlarged 10pt ;
+\stopMPpage
+
+\startMPpage
+ picture p ;
+ p := \sometxt{\framed[width=fit,align=middle]{\input tufte\relax}} ;
+ draw p rotatedaround(center p, 30) ;
+\stopMPpage
+
+\startMPpage
+ picture p ;
+ p := \sometxt{\framed[width=fit,align=middle]{\input tufte\relax}} ;
+ draw p slanted .5 ;
+\stopMPpage
+
+\dorecurse{10} {
+ \startTeXtexts
+ \TeXtext{\recurselevel}{\ruledhbox{I must be {\green crazy} to implement this}}
+ \stopTeXtexts
+ \startMPpage
+ picture p ; pickup pencircle scaled .1pt ;
+ numeric i ; i := \recurselevel ;
+ p := sometxt(i) ;
+ p := p rotatedaround(center p, 360*(i*5/100)) ;
+ draw p ; draw boundingbox p withcolor blue ;
+ currentpicture := currentpicture scaled 20 ;
+ draw boundingbox currentpicture withcolor .5white ;
+ \stopMPpage
+}
+
+\startTeXtexts
+ \dorecurse{100}{\TeXtext{\recurselevel}{\ruledhbox{\strut interesting \recurselevel}}}
+\stopTeXtexts
+
+\startMPpage
+ picture p ; pickup pencircle scaled .1pt ;
+ for i = 1 upto 100:
+ p := sometxt(i) ;
+ p := p rotatedaround(center p, 360*(i*5/100)) ;
+ draw p ; draw boundingbox p withcolor blue ;
+ endfor ;
+ currentpicture := currentpicture scaled 20 ;
+ draw boundingbox currentpicture withcolor .5white ;
+\stopMPpage
+
+\startTeXtexts
+ \dorecurse{100}{\TeXtext{\recurselevel}{\ruledhbox{\strut interesting \recurselevel}}}
+\stopTeXtexts
+
+\startMPpage
+ picture p ; pickup pencircle scaled .1pt ;
+ for i = 1 step 5 until 100 :
+ p := sometxt(i) ;
+ p := p rotatedaround(center p, 360*(i/100)) ;
+ draw p ; draw boundingbox p withcolor blue ;
+ endfor ;
+ currentpicture := currentpicture scaled 20 ;
+ draw boundingbox currentpicture withcolor .5white ;
+\stopMPpage
+
+\startTeXtexts
+ \dorecurse{20}{\TeXtext{\recurselevel}{\externalfigure[t:/sources/cow.pdf][width=1cm]}}
+\stopTeXtexts
+
+\startMPpage
+ picture p ; pickup pencircle scaled .1pt ;
+ for i = 1 upto 20 :
+ p := sometxt(i) ;
+ p := p shifted (2.5cm,0) rotated (360*(i/20)) ;
+ draw p ; draw boundingbox p withcolor blue ;
+ endfor ;
+ currentpicture := currentpicture scaled 10 ;
+ draw boundingbox currentpicture withcolor .5white ;
+\stopMPpage
+
+\startTeXtexts
+ \dorecurse{200}{\TeXtext{\recurselevel}{\ruledhbox{\strut I must be {\green crazy} \recurselevel}}}
+\stopTeXtexts
+
+\startMPpage
+ picture p ; pickup pencircle scaled .1pt ;
+ numeric i ; i := 100 ;
+ p := sometxt(i) ;
+ p := p rotatedaround(center p, 360*(i*36/100)) ;
+ draw p ; draw boundingbox p withcolor blue ;
+ currentpicture := currentpicture scaled 20 ;
+ draw boundingbox currentpicture withcolor .5white ;
+\stopMPpage
+
+\dorecurse{10}{
+ \startTeXtexts
+ \dorecurse{200}{\TeXtext{\recurselevel}{\ruledhbox{\strut I must be {\green crazy} \recurselevel}}}
+ \stopTeXtexts
+ \startMPpage
+ picture p ; pickup pencircle scaled .1pt ;
+ j := 10*\recurselevel-9;
+ k := 10*\recurselevel;
+ for i = j upto k:
+ p := sometxt(i) ;
+ p := p rotatedaround(center p, 360*(i/100)) ;
+ draw p ; draw boundingbox p withcolor blue ;
+ endfor ;
+ currentpicture := currentpicture scaled 20 ;
+ draw boundingbox currentpicture withcolor red ;
+ \stopMPpage
+}
diff --git a/tex/context/base/meta-tex.mkiv b/tex/context/base/meta-tex.mkiv
new file mode 100644
index 000000000..e35f95385
--- /dev/null
+++ b/tex/context/base/meta-tex.mkiv
@@ -0,0 +1,72 @@
+%D \module
+%D [ file=meta-tex,
+%D version=2006.06.07,
+%D title=\CONTEXT\ Support Macros,
+%D subtitle=\METAPOST\ fast text insertion,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=\PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+% Ok, we support this in MkIV because Mojca kept the pressure on. It
+% looks a bit like a hack.
+
+\long\def\startTeXtexts#1\stopTeXtexts
+ {#1}
+
+\long\def\TeXtext
+ {\dosingleempty\doTeXtext}
+
+\long\def\doTeXtext[#1]#2#3% contrary to mkii we don't process yet but we do expand
+ {\long\setxvalue{@@st@@::#2}{\noexpand\dodoTeXtext{#1}{#3}}}
+
+\long\def\dodoTeXtext#1#2%
+ {\begingroup
+ \setbox\nextbox\hbox{\executeifdefined{textext@@#1}\firstofoneargument{#2}}%
+ \executeifdefined{textext::#1}{\getvalue{textext::depth}}%
+ \box\nextbox
+ \endgroup}
+
+\def\getTeXtext#1%
+ {\getvalue{@@st@@::#1}}
+
+\setvalue{textext::d}{\setbox\nextbox\hbox{\lower\dp\nextbox\box\nextbox}} % unchecked
+\setvalue{textext::n}{} % unchecked
+
+\setvalue {textext::depth}{\getvalue{textext::d}}
+\setvalue{textext::nodepth}{\getvalue{textext::n}}
+
+% \definetextext[framed]{\framed}
+%
+% \startMPcode
+% draw \sometxt[framed]{black} rotated 45 ;
+% \stopMPcode
+
+\unexpanded\def\definetextext[#1]#2{\setvalue{@@st@@[#1]}{#2}\setvalue{@@st@@[#1] }{#2}} % we don't grab spaces after [#1]
+
+\long\def\sometxt#1#{\dosometxt{#1}} % grab optional [args]
+
+\long\def\dosometxt#1#2%
+ {textext.drt("\ifcsname @@st@@#1\endcsname\csname @@st@@#1\endcsname{#2}\else#2\fi")}
+
+% Best use the mp macro instead since it provides positioning.
+%
+% \startuseMPgraphic{testgraphic}
+% draw \sometxt{\ruledhbox{\strut hans hagen}} scaled 3;
+% % draw textext.drt("\ruledhbox{\strut hans hagen}") scaled 3;
+% % draw textext.dlft("\ruledhbox{\strut hans hagen}") scaled 3;
+% % draw textext.lft("\ruledhbox{\strut hans hagen}") scaled 3;
+% draw llcorner currentpicture -- urcorner currentpicture withcolor yellow;
+% draw lrcorner currentpicture -- ulcorner currentpicture withcolor yellow;
+% draw boundingbox currentpicture withcolor blue ;
+% draw origin withcolor red withpen pencircle scaled 1pt;
+% \stopuseMPgraphic
+%
+% {\showstruts\useMPgraphic{testgraphic}}
+
+\protect \endinput
diff --git a/tex/context/base/meta-txt.tex b/tex/context/base/meta-txt.tex
new file mode 100644
index 000000000..474253a40
--- /dev/null
+++ b/tex/context/base/meta-txt.tex
@@ -0,0 +1,304 @@
+%D \module
+%D [ file=meta-txt,
+%D version=2000.07.06,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Text Tricks,
+%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.
+
+%D In this library some handy text manipulations are
+%D defined. Some can and will be improved as soon as the
+%D \TEX||\METAPOST\ interface is stable. Some of the
+%D solutions may look weird, which is entirely my fault,
+%D since I implemented them in the process of getting grip
+%D on this kind of manipulations. Undoubtly better
+%D \METAPOST\ code is possible, but my way of learning
+%D this kind of trickery happens to be by \quote {trial
+%D and error} and \quote {look and feel} (as well as
+%D identifying tricks in Hobby's code).
+
+% textext ipv btex ... etex
+
+% we need a proper prefix here
+
+\unprotect
+
+\startMPextensions
+ if unknown context_text: input mp-text; fi;
+\stopMPextensions
+
+%%%%%%%
+
+% \def\newchar#1{\chardef#1=0 }
+
+\ifdefined\MPtoks \else \newtoks\MPtoks \fi
+\ifdefined\MPbox \else \newbox \MPbox \fi
+
+\ifdefined\parwidth \else \newdimen\parwidth \fi
+\ifdefined\parheight \else \newdimen\parheight \fi
+\ifdefined\parvoffset \else \newdimen\parvoffset \fi
+\ifdefined\parhoffset \else \newdimen\parhoffset \fi
+\ifdefined\parlines \else \newcount\parlines \fi
+\ifdefined\partoks \else \newtoks \partoks \fi
+\ifdefined\shapetextbox \else \newbox \shapetextbox \fi
+ \newif \ifparseries
+\ifdefined\parfirst \else \chardef \parfirst=0 \fi
+
+\def\startshapetext[#1]%
+ {\global\newcounter\currentshapetext
+ \global\setbox\shapetextbox\vbox\bgroup
+ \expanded{\switchtobodyfont[\@@shbodyfont]}%
+ \dontcomplain
+ \hsize\parwidth
+ \setuptolerance[\v!verytolerant,\v!stretch]%
+ \!!counta\zerocount
+ \!!toksa\emptytoks
+ \def\docommand##1%
+ {\setbox\scratchbox\hbox{\useMPgraphic{##1}}%
+ \global\chardef\parfirst\zerocount
+ \getMPdata % \readlocfile{\MPdatafile}{}{}%
+ \setshapecharacteristics
+ \advance\!!counta by \parlines
+ \expandafter\appendtoks\the\partoks\to\!!toksa}%
+ \processcommalist[#1]\docommand
+ \global\parseriestrue
+ \xdef\totalparlines{\the\!!counta}%
+ \global\partoks\!!toksa
+ %\ifx\partoks\emptytoks\else % safeguard
+ \expanded{\parshape \the\!!counta \the\!!toksa}%
+ %\fi
+ \setshapecharacteristics % extra dummy
+ \ifparseries\def\par{\endgraf\adaptparshape}\fi
+ \EveryPar{\begstrut}}
+
+\def\stopshapetext
+ {\endstrut
+ %\removebottomthings
+ \egroup
+ \global\newcounter\currentshapetext
+ \getshapecharacteristics}
+
+\def\adaptparshape%
+ {\def\docommand##1%
+ {\ifcase\!!counta
+ \expandafter\appendtoks\space##1 \to\!!toksa
+ \else
+ \advance\!!counta \minusone
+ \fi}%
+ \!!counta\prevgraf
+ \doglobal\decrement(\totalparlines,\!!counta)%
+ \multiply\!!counta \plustwo
+ \!!toksa\emptytoks
+ \expanded{\processseparatedlist[\the\partoks][\space]}\docommand
+ \global\partoks\!!toksa
+ %\ifx\partoks\emptytoks\else % safeguard
+ \expanded{\parshape\totalparlines\the\partoks}%
+ }%\fi}
+
+\def\getshapecharacteristics%
+ {\doglobal\increment\currentshapetext
+ \doifdefinedelse{parlines:\currentshapetext}
+ {\global\parlines \getvalue{parlines:\currentshapetext}%
+ \global\chardef\parfirst \getvalue{parfirst:\currentshapetext}%
+ \global\parvoffset \getvalue{parvoffset:\currentshapetext}%
+ \global\parhoffset \getvalue{parhoffset:\currentshapetext}%
+ \global\parwidth \getvalue{parwidth:\currentshapetext}%
+ \global\parheight \getvalue{parheight:\currentshapetext}}
+ {\global\parlines \plusone
+ \global\chardef\parfirst \zerocount
+ \global\parvoffset \zeropoint
+ \global\parhoffset \zeropoint
+ \global\parwidth \hsize
+ \global\parheight \vsize}}
+
+\def\setshapecharacteristics%
+ {\doglobal\increment\currentshapetext
+ \setxvalue{parlines:\currentshapetext }{\the\parlines}%
+ \setxvalue{parfirst:\currentshapetext }{\the\parfirst}%
+ \setxvalue{parvoffset:\currentshapetext}{\the\parvoffset}%
+ \setxvalue{parhoffset:\currentshapetext}{\the\parhoffset}%
+ \setxvalue{parwidth:\currentshapetext }{\the\parwidth}%
+ \setxvalue{parheight:\currentshapetext }{\the\parheight}}
+
+\def\getshapetext% option: unvbox
+ {\vbox\bgroup
+ \forgetall
+ \setbox\scratchbox\vbox to \parheight
+ {\expanded{\switchtobodyfont[\@@shbodyfont]}% evt strutheight en
+ \splittopskip\strutheight % lineheight opslaan
+ \vskip\parvoffset % scheelt switch en
+ \ifcase\parfirst\or\vskip\lineheight\fi % is ook veiliger
+ \hskip\parhoffset
+ \hbox{\vsplit\shapetextbox to \parlines\lineheight}}%
+ \wd\scratchbox\parwidth
+ \ht\scratchbox\parheight
+ \dp\scratchbox\zeropoint
+ \box\scratchbox
+ \getshapecharacteristics
+ \egroup}
+
+\def\setupshapetexts%
+ {\dodoubleempty\getparameters[\??sh]}
+
+\setupshapetexts%
+ [\c!bodyfont=]
+
+%%%%%%% rotfont nog definieren
+
+\doifundefined{RotFont}{\definefont[RotFont][RegularBold]}
+
+\def\processfollowingtoken#1% strut toegevoegd
+ {\appendtoks#1\to\MPtoks
+ \setbox\MPbox=\hbox{\RotFont\setstrut\strut\the\MPtoks}%
+ \startMPdrawing
+ n := n + 1 ; len[n] := \the\wd\MPbox ;
+ \stopMPdrawing
+ \startMPdrawing[-]
+ % pic[n] := textext{\RotFont\setstrut\strut#1} ; % btex \RotFont\setstrut\strut#1 etex ;
+ pic[n] := btex \RotFont\setstrut\strut#1 etex ;
+ pic[n] := pic[n] shifted - llcorner pic[n] ;
+ \stopMPdrawing}
+
+\startuseMPgraphic{followtokens}
+ % we default to nothing
+\stopuseMPgraphic
+
+\def\followtokens#1%
+ {\vbox\bgroup
+ \forgetall
+ \dontcomplain
+ \startMPenvironment
+ \doifundefined{RotFont}{\definefont[RotFont][RegularBold]}
+ \stopMPenvironment
+ \MPtoks\emptytoks
+ \resetMPdrawing
+ \startMPdrawing
+ \includeMPgraphic{followtokens} ;
+ picture pic[] ; numeric len[], n ; n := 0 ;
+ \stopMPdrawing
+ \handletokens#1\with\processfollowingtoken
+ \startMPdrawing
+ if unknown RotPath : path RotPath ; RotPath := origin ; fi ;
+ if unknown RotColor : color RotColor ; RotColor := black ; fi ;
+ if unknown TraceRot : boolean TraceRot ; TraceRot := false ; fi ;
+ if unknown ExtraRot : numeric ExtraRot ; ExtraRot := 0 ; fi ;
+ numeric al, at, pl, wid, pos ; pair ap, ad ;
+ al := arclength RotPath ;
+ if al=0 :
+ al := len[n] + ExtraRot ;
+ RotPath := origin -- (al,0) ;
+ fi ;
+ if al1 : (n-1) else : 1 fi) ;
+ if TraceRot :
+ draw RotPath withpen pencircle scaled 1pt withcolor blue ;
+ fi ;
+ for i=1 upto n :
+ wid := abs(xpart urcorner pic[i] - xpart llcorner pic[i]) ;
+ pos := len[i]-wid/2 + (i-1)*pl ;
+ at := arctime pos of RotPath ;
+ ap := point at of RotPath ;
+ ad := direction at of RotPath ;
+ draw pic[i] shifted (-wid/2,0) rotated(angle(ad)) shifted ap
+ withcolor RotColor ;
+ if TraceRot :
+ draw boundingbox
+ pic[i] shifted (-wid/2,0) rotated(angle(ad)) shifted ap
+ withpen pencircle scaled .25pt withcolor red ;
+ draw ap
+ withpen pencircle scaled .50pt withcolor green ;
+ fi ;
+ endfor ;
+ \stopMPdrawing
+ \MPdrawingdonetrue
+ \getMPdrawing
+ \resetMPdrawing
+ \egroup}
+
+% \followtokens
+% {This is just a dummy text, kerned by T{\kern
+% -.1667em\lower .5ex\hbox {E}}{\kern -.125emX} and typeset
+% in a circle using {\setMFPfont M}{\setMFPfont
+% E}{\setMFPfont T}{\setMFPfont A}{\setMFPfont
+% P}{\setMFPfont O}{\setMFPfont S}{\setMFPfont T}.\quad}
+
+\startuseMPgraphic{fuzzycount}
+ begingroup
+ save height, span, drift, d, cp ;
+ height := 3/ 5 * \baselinedistance ;
+ span := 1/ 3 * height ;
+ drift := 1/10 * height ;
+ pickup pencircle scaled (1/12 * height) ;
+ def d = (uniformdeviate drift) enddef ;
+ for i := 1 upto \MPvar{n} :
+ draw
+ if (i mod 5)=0 : ((-d-4.5span,d)--(+d-0.5span,height-d))
+ else : ((-d,+d)--(+d,height-d)) fi
+ shifted (span*i,d-drift) ;
+ endfor;
+ picture cp ; cp := currentpicture ; % for readability
+ setbounds currentpicture to
+ (llcorner cp shifted (0,-ypart llcorner cp) --
+ lrcorner cp shifted (0,-ypart lrcorner cp) --
+ urcorner cp -- ulcorner cp -- cycle) ;
+ endgroup ;
+\stopuseMPgraphic
+
+\setupMPvariables
+ [fuzzycount]
+ [n=10]
+
+\def\fuzzycount#1%
+ {{\tx\useMPgraphic{fuzzycount}{n=#1}}}
+
+\defineconversion[fuzzy][\fuzzycount]
+
+%%%%%%%
+
+\setupMPvariables
+ [EnglishRule]
+ [height=1ex,
+ width=\the\localhsize, % without \the, problems in non e-tex
+ color=darkgray]
+
+\defineblank
+ [EnglishRule]
+ [medium]
+
+\startuniqueMPgraphic{EnglishRule}{height,width,color}
+ height = \MPvar{height} ;
+ x1 = 0 ; x3 = \MPvar{width} ; x2 = x4 = .5x3 ;
+ y1 = y3 = 0 ; y2 = -y4 = height/2 ;
+ fill z1..z2..z3 & z3..z4..z1 & cycle withcolor \MPvar{color} ;
+\stopuniqueMPgraphic
+
+\def\EnglishRule%
+ {\startlinecorrection[EnglishRule]
+ \setlocalhsize \noindent \reuseMPgraphic{EnglishRule}
+ \stoplinecorrection}
+
+%D The following macro returns a tight bound character
+%D sequence.
+%D
+%D \useMPlibrary[txt]
+%D
+%D \startlinecorrection
+%D \TightText{\ss\bf 123}{0cm}{3cm}{red}
+%D \stoplinecorrection
+
+\def\TightText#1#2#3#4%
+ {\hbox % \ruledhbox
+ {\startMPcode
+ picture p ; p := image (graphictext "#1" withfillcolor red) ;
+ draw p xsized #2 ysized #3 withcolor \MPcolor{#4} ;
+ \stopMPcode}}
+
+\protect \endinput
diff --git a/tex/context/base/meta-xml.tex b/tex/context/base/meta-xml.tex
new file mode 100644
index 000000000..f6f81f767
--- /dev/null
+++ b/tex/context/base/meta-xml.tex
@@ -0,0 +1,29 @@
+%D \module
+%D [ file=meta-xml,
+%D version=2002.11.27,
+%D title=\METAPOST\ Graphics,
+%D subtitle=XML Hacks,
+%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}{MetaPost Graphics / XML Hacks}
+
+%D When we are dealing with XML, we need to make sure that
+%D \METAPOST\ knows about it. The next macro expands its
+%D argument (think of widget XFDF) into \type {\getXMLentity}
+%D calls.
+
+\unprotect
+
+\def\setMPtextXML#1#2%
+ {\bgroup
+ \enableXML
+ \expanded{\defconvertedcommand\noexpand\ascii{#2}}%
+ \expanded{\egroup\noexpand\dodoglobal\noexpand\setvalue{\@@MPT#1}{\ascii}}}
+
+\protect \endinput
diff --git a/tex/context/base/metatex.tex b/tex/context/base/metatex.tex
new file mode 100644
index 000000000..e90af709c
--- /dev/null
+++ b/tex/context/base/metatex.tex
@@ -0,0 +1,154 @@
+%D \module
+%D [ file=metatex,
+%D version=2008.10.10,
+%D title=\METATEX,
+%D subtitle=\METATEX\ Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen / \CONTEXT\ Development Team]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D We can experiment here with runtime loading, id est no longer
+%D use a format. However, we still need a stub then but it could
+%D as well be luatools (mtxrun) itself then.
+
+%D This format is just a minimal layer on top of the \LUATEX\
+%D engine and will not provide high level functionality. It can
+%D be used as basis for dedicated (specialized) macro packages.
+%D
+%D A format is generated with the command;
+%D
+%D \starttyping
+%D luatools --make --compile metatex
+%D \stoptyping
+%D
+%D Remark: this is far from complete. We will gradually add
+%D more. Also, it's not yet clean what exactly will be part
+%D of it. This is a prelude to a configureable macro package.
+
+\catcode`\{=1 \catcode`\}=2 \catcode`\#=6
+
+\edef\metatexformat {\jobname}
+\edef\metatexversion{2007.04.03 13:01}
+
+\let\fmtname \metatexformat
+\let\fmtversion\metatexversion
+
+\ifx\normalinput\undefined \let\normalinput\input \fi
+
+\def\loadcorefile#1{\normalinput#1.tex \relax}
+\def\loadmarkfile#1{\normalinput#1.mkiv\relax}
+
+\loadcorefile{syst-ini}
+
+\ifnum\luatexversion<60 % also change message
+ \writestatus{!!!!}{Your luatex binary is too old, you need at least version 0.60!}
+ \expandafter\end
+\fi
+
+\newtoks\metatexversiontoks \metatexversiontoks\expandafter{\metatexversion} % at the lua end
+
+\loadcorefile{syst-pln} % plain tex initializations of internal registers (no further code)
+
+\loadmarkfile{luat-cod} %
+\loadmarkfile{luat-bas} %
+\loadmarkfile{luat-lib} %
+
+% needs stripping:
+
+\loadmarkfile{catc-ini} % catcode table management
+\loadcorefile{catc-act} % active character definition mechanisms
+\loadcorefile{catc-def} % some generic catcode tables
+\loadcorefile{catc-ctx} % a couple of context specific tables but expected by later modules
+\loadcorefile{catc-sym} % some definitions related to \letter
+
+% helpers, maybe less
+
+\loadmarkfile{syst-aux} % a whole lot of auxiliary macros
+%loadmarkfile{syst-lua} % some helpers using lua instead
+%loadmarkfile{syst-con} % some rather basic conversions
+%loadmarkfile{syst-fnt}
+%loadmarkfile{syst-str}
+%loadmarkfile{syst-rtp}
+
+% not needed
+
+% \loadmarkfile{supp-fil}
+% \loadmarkfile{supp-dir}
+
+% characters
+
+\loadmarkfile{char-utf}
+\loadmarkfile{char-ini}
+\loadmarkfile{char-enc} % \registerctxluafile{char-enc}{1.001}
+
+% nodes
+
+\loadmarkfile{node-ini}
+%loadmarkfile{node-fin}
+%loadmarkfile{node-par}
+
+% attributes, not needed:
+
+%loadmarkfile{attr-ini}
+
+% regimes
+
+% \loadmarkfile{regi-ini}
+% \loadcorefile{regi-syn}
+
+% languages
+
+% fonts
+
+% \loadcorefile{enco-ini.mkiv}
+% \loadcorefile{hand-ini.mkiv}
+
+\registerctxluafile{font-ini}{1.001}
+
+\registerctxluafile{node-fnt}{1.001}
+
+\registerctxluafile{font-enc}{1.001}
+\registerctxluafile{font-map}{1.001}
+\registerctxluafile{font-syn}{1.001}
+\registerctxluafile{font-tfm}{1.001}
+\registerctxluafile{font-afm}{1.001}
+\registerctxluafile{font-cid}{1.001}
+\registerctxluafile{font-ott}{1.001}
+\registerctxluafile{font-otf}{1.001}
+\registerctxluafile{font-otb}{1.001}
+\registerctxluafile{font-otn}{1.001}
+\registerctxluafile{font-ota}{1.001}
+\registerctxluafile{font-otp}{1.001}
+\registerctxluafile{font-otc}{1.001}
+%registerctxluafile{font-vf} {1.001}
+\registerctxluafile{font-def}{1.001}
+%registerctxluafile{font-ctx}{1.001}
+\registerctxluafile{font-xtx}{1.001}
+%registerctxluafile{font-fbk}{1.001}
+%registerctxluafile{font-ext}{1.001}
+\registerctxluafile{font-pat}{1.001}
+%registerctxluafile{font-chk}{1.001}
+
+%registerctxluafile{math-ini}{1.001}
+%registerctxluafile{math-dim}{1.001}
+%registerctxluafile{math-ent}{1.001}
+%registerctxluafile{math-ext}{1.001}
+%registerctxluafile{math-vfu}{1.001}
+%registerctxluafile{math-map}{1.001}
+%registerctxluafile{math-noa}{1.001}
+
+\registerctxluafile{task-ini}{1.001}
+
+%registerctxluafile{l-xml}{1.001} % needed for font database
+
+% why not ...
+
+\pdfoutput\plusone
+
+% done
+
+\errorstopmode \dump \endinput
diff --git a/tex/context/base/mlib-ctx.lua b/tex/context/base/mlib-ctx.lua
new file mode 100644
index 000000000..cc5682e6f
--- /dev/null
+++ b/tex/context/base/mlib-ctx.lua
@@ -0,0 +1,84 @@
+if not modules then modules = { } end modules ['mlib-ctx'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- todo
+
+local format, join = string.format, table.concat
+local sprint = tex.sprint
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
+metapost = metapost or {}
+metapost.defaultformat = "metafun"
+
+function metapost.graphic(instance,mpsformat,str,initializations,preamble,askedfig)
+ local mpx = metapost.format(instance,mpsformat or metapost.defaultformat)
+ metapost.graphic_base_pass(mpx,str,initializations,preamble,askedfig)
+end
+
+function metapost.getclippath(instance,mpsformat,data,initializations,preamble)
+ local mpx = metapost.format(instance,mpsformat or metapost.defaultformat)
+ if mpx and data then
+ starttiming(metapost)
+ starttiming(metapost.exectime)
+ local result = mpx:execute(format("%s;beginfig(1);%s;%s;endfig;",preamble or "",initializations or "",data))
+ stoptiming(metapost.exectime)
+ if result.status > 0 then
+ logs.report("metafun", "%s: %s", result.status, result.error or result.term or result.log)
+ result = nil
+ else
+ result = metapost.filterclippath(result)
+ end
+ stoptiming(metapost)
+ return result
+ end
+end
+
+function metapost.filterclippath(result)
+ if result then
+ local figures = result.fig
+ if figures and #figures > 0 then
+ local figure = figures[1]
+ local objects = figure:objects()
+ if objects then
+ local lastclippath
+ for o=1,#objects do
+ local object = objects[o]
+ if object.type == "start_clip" then
+ lastclippath = object.path
+ end
+ end
+ return lastclippath
+ end
+ end
+ end
+end
+
+function metapost.theclippath(...)
+ local result = metapost.getclippath(...)
+ if result then -- we could just print the table
+ result = join(metapost.flushnormalpath(result),"\n")
+ sprint(result)
+ end
+end
+
+statistics.register("metapost processing time", function()
+ local n = metapost.n
+ if n > 0 then
+ local e, t = metapost.externals.n, statistics.elapsedtime
+ local str = format("%s seconds, loading: %s seconds, execution: %s seconds, n: %s",
+ t(metapost), t(mplib), t(metapost.exectime), n)
+ if e > 0 then
+ return format("%s, external: %s seconds (%s calls)", str, t(metapost.externals), e)
+ else
+ return str
+ end
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/mlib-ctx.mkiv b/tex/context/base/mlib-ctx.mkiv
new file mode 100644
index 000000000..6f56b7e68
--- /dev/null
+++ b/tex/context/base/mlib-ctx.mkiv
@@ -0,0 +1,81 @@
+%D \module
+%D [ file=mlib-ctx,
+%D version=2008.03.25,
+%D title=\METAPOST\ Integrated Graphics,
+%D subtitle=Basics,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This file contains the \MPLIB\ variants of the by now ancient
+%D \MPTOPDF\ code.
+
+\writestatus{loading}{MetaPost Library Graphics / Initializations}
+
+\registerctxluafile{mlib-run}{1.001}
+\registerctxluafile{mlib-ctx}{1.001}
+
+\unprotect
+
+\protect \endinput
+
+% local mpgraphic = [[
+% for i=1 upto 1000 :
+% beginfig(0);
+% draw halfcircle scaled 1cm withcolor green ;
+% picture p ; p := "oeps" infont defaultfont scaled .75 rotated 45 ;
+% p := p shifted - (xpart center p,0) ;
+% draw p ; draw boundingbox p ;
+% endfig ;
+% beginfig(0);
+% draw halfcircle scaled 1cm dashed evenly withcolor green ;
+% endfig ;
+% beginfig(0);
+% pickup pencircle xscaled .5mm yscaled .25mm rotated 45 ;
+% draw halfcircle scaled 1cm withcolor red ;
+% endfig ;
+% beginfig(0);
+% draw halfcircle scaled 1cm ;
+% endfig ;
+% beginfig(0);
+% pickup pencircle xscaled .5mm yscaled .25mm rotated 45 ;
+% for k:=1 upto 10 :
+% draw halfcircle scaled uniformdeviate(1cm) withcolor (red/(k/4)) ;
+% endfor ;
+% endfig ;
+% endfor ;
+% ]]
+% -- local mpx = metapost.format("metafun")
+% metapost.process(metapost.format("metafun"),mpgraphic)
+
+% \starttext
+% \setupcolors[state=start]
+% \definecolor[red] [r=1]
+% \definecolor[cyan][c=1]
+% \setbox\scratchbox\hbox{\startMPcode\stopMPcode} % first specials are forgotten
+% \definecolor[sss][t=.5,a=1,r=1]
+% \definespotcolor[oeps1][green][p=.5]
+% \definespotcolor[oeps2][green][p=.25]
+% \definespotcolor[oeps3][green][p=.25,t=.5,a=1]
+% \startMPpage
+% fill fullcircle scaled 10cm withcolor \MPcolor{red} ;
+% fill fullcircle scaled 8cm withcolor cmyk(1,0,0,0) ;
+% fill fullcircle scaled 6cm withcolor cmyk(0,1,0,0) ;
+% fill fullcircle scaled 4cm withcolor cmyk(0,0,1,0) ;
+% fill fullcircle scaled 2cm withcolor cmyk(0,0,0,1) ;
+% currentpicture := currentpicture shifted (-7.5cm,0) ;
+% fill fullcircle scaled 10cm withcolor transparent(1,0.75,cmyk(0,0,1,0)) ;
+% fill fullcircle scaled 8cm withcolor \MPcolor{sss} ;
+% fill fullcircle scaled 6cm withcolor \MPcolor{oeps1} ;
+% fill fullcircle scaled 4cm withcolor \MPcolor{oeps2} ;
+% currentpicture := currentpicture shifted (-7.5cm,0) ;
+% fill fullcircle scaled 10cm withcolor \MPcolor{oeps3} ;
+% circular_shade(fullcircle scaled 8cm, 1, red, blue) ;
+% circular_shade(fullcircle scaled 6cm, 1, (1,0,0,0), (0,1,0,0)) ;
+% circular_shade(fullcircle scaled 4cm, 1, cmyk(.5,.5,1,0), (0,1,0,0)) ;
+% \stopMPpage
+% \stoptext
diff --git a/tex/context/base/mlib-pdf.lua b/tex/context/base/mlib-pdf.lua
new file mode 100644
index 000000000..352070408
--- /dev/null
+++ b/tex/context/base/mlib-pdf.lua
@@ -0,0 +1,530 @@
+if not modules then modules = { } end modules ['mlib-pdf'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local format, concat, gsub = string.format, table.concat, string.gsub
+local texsprint = tex.sprint
+local abs, sqrt, round = math.abs, math.sqrt, math.round
+
+local copy_node, write_node = node.copy, node.write
+
+local ctxcatcodes = tex.ctxcatcodes
+
+metapost = metapost or { }
+metapost.multipass = false
+metapost.n = 0
+metapost.optimize = true -- false
+
+--~ Because in MKiV we always have two passes, we save the objects. When an extra
+--~ mp run is done (due to for instance texts identifier in the parse pass), we
+--~ get a new result table and the stored objects are forgotten. Otherwise they
+--~ are reused.
+
+local function getobjects(result,figure,f)
+ if metapost.optimize then
+ local objects = result.objects
+ if not objects then
+ result.objects = { }
+ end
+ objects = result.objects[f]
+ if not objects then
+ objects = figure:objects()
+ result.objects[f] = objects
+ end
+ return objects
+ else
+ return figure:objects()
+ end
+end
+
+function metapost.convert(result, trialrun, flusher, multipass, askedfig)
+ if trialrun then
+ metapost.multipass = false
+ metapost.parse(result, askedfig)
+ if multipass and not metapost.multipass and metapost.optimize then
+ metapost.flush(result, flusher, askedfig) -- saves a run
+ else
+ return false
+ end
+ else
+ metapost.flush(result, flusher, askedfig)
+ end
+ return true -- done
+end
+
+metapost.flushers = { }
+metapost.flushers.pdf = { }
+
+local savedliterals = nil
+
+local mpsliteral = nodes.register(node.new("whatsit",8))
+
+function metapost.flush_literal(d) -- \def\MPLIBtoPDF#1{\ctxlua{metapost.flush_literal(#1)}}
+ if savedliterals then
+ local literal = copy_node(mpsliteral)
+ literal.data = savedliterals[d]
+ write_node(literal)
+ else
+ logs.report("metapost","problem flushing literal %s",d)
+ end
+end
+
+function metapost.flush_reset()
+ savedliterals = nil
+end
+
+function metapost.flushers.pdf.comment(message)
+ if message then
+ message = format("%% mps graphic %s: %s", metapost.n, message)
+ if savedliterals then
+ local last = #savedliterals + 1
+ savedliterals[last] = message
+ texsprint(ctxcatcodes,"\\MPLIBtoPDF{",last,"}")
+ else
+ savedliterals = { message }
+ texsprint(ctxcatcodes,"\\MPLIBtoPDF{1}")
+ end
+ end
+end
+
+function metapost.flushers.pdf.startfigure(n,llx,lly,urx,ury,message)
+ savedliterals = nil
+ metapost.n = metapost.n + 1
+ texsprint(ctxcatcodes,format("\\startMPLIBtoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury))
+ if message then metapost.flushers.pdf.comment(message) end
+end
+
+function metapost.flushers.pdf.stopfigure(message)
+ if message then metapost.flushers.pdf.comment(message) end
+ texsprint(ctxcatcodes,"\\stopMPLIBtoPDF")
+ texsprint(ctxcatcodes,"\\ctxlua{metapost.flush_reset()}") -- maybe just at the beginning
+end
+
+function metapost.flushers.pdf.flushfigure(pdfliterals) -- table
+ if #pdfliterals > 0 then
+ pdfliterals = concat(pdfliterals,"\n")
+ if savedliterals then
+ local last = #savedliterals + 1
+ savedliterals[last] = pdfliterals
+ texsprint(ctxcatcodes,"\\MPLIBtoPDF{",last,"}")
+ else
+ savedliterals = { pdfliterals }
+ texsprint(ctxcatcodes,"\\MPLIBtoPDF{1}")
+ end
+ end
+end
+
+function metapost.flushers.pdf.textfigure(font,size,text,width,height,depth) -- we could save the factor
+ text = gsub(text,".","\\hbox{%1}") -- kerning happens in metapost (i have to check if this is true for mplib)
+ texsprint(ctxcatcodes,format("\\MPLIBtextext{%s}{%s}{%s}{%s}{%s}",font,size,text,0,-number.dimenfactors.bp*depth))
+end
+
+local bend_tolerance = 131/65536
+
+local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
+
+local function pen_characteristics(object)
+ if mplib.pen_info then
+ local t = mplib.pen_info(object)
+ rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
+ divider = sx*sy - rx*ry
+ return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
+ else
+ rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
+ return false, 1
+ end
+end
+
+local function mpconcat(px, py) -- no tx, ty here / we can move this one inline if needed
+ return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider
+end
+
+local function curved(ith,pth)
+ local d = pth.left_x - ith.right_x
+ if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then
+ d = pth.left_y - ith.right_y
+ if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then
+ return false
+ end
+ end
+ return true
+end
+
+local function flushnormalpath(path, t, open)
+ t = t or { }
+ local pth, ith
+ for i=1,#path do
+ pth = path[i]
+ if not ith then
+ t[#t+1] = format("%f %f m",pth.x_coord,pth.y_coord)
+ elseif curved(ith,pth) then
+ t[#t+1] = format("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord)
+ else
+ t[#t+1] = format("%f %f l",pth.x_coord,pth.y_coord)
+ end
+ ith = pth
+ end
+ if not open then
+ local one = path[1]
+ if curved(pth,one) then
+ t[#t+1] = format("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord )
+ else
+ t[#t+1] = format("%f %f l",one.x_coord,one.y_coord)
+ end
+ elseif #path == 1 then
+ -- special case .. draw point
+ local one = path[1]
+ t[#t+1] = format("%f %f l",one.x_coord,one.y_coord)
+ end
+ return t
+end
+
+local function flushconcatpath(path, t, open)
+ t = t or { }
+ t[#t+1] = format("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty)
+ local pth, ith
+ for i=1,#path do
+ pth = path[i]
+ if not ith then
+ t[#t+1] = format("%f %f m",mpconcat(pth.x_coord,pth.y_coord))
+ elseif curved(ith,pth) then
+ local a, b = mpconcat(ith.right_x,ith.right_y)
+ local c, d = mpconcat(pth.left_x,pth.left_y)
+ t[#t+1] = format("%f %f %f %f %f %f c",a,b,c,d,mpconcat(pth.x_coord,pth.y_coord))
+ else
+ t[#t+1] = format("%f %f l",mpconcat(pth.x_coord, pth.y_coord))
+ end
+ ith = pth
+ end
+ if not open then
+ local one = path[1]
+ if curved(pth,one) then
+ local a, b = mpconcat(pth.right_x,pth.right_y)
+ local c, d = mpconcat(one.left_x,one.left_y)
+ t[#t+1] = format("%f %f %f %f %f %f c",a,b,c,d,mpconcat(one.x_coord, one.y_coord))
+ else
+ t[#t+1] = format("%f %f l",mpconcat(one.x_coord,one.y_coord))
+ end
+ elseif #path == 1 then
+ -- special case .. draw point
+ local one = path[1]
+ t[#t+1] = format("%f %f l",mpconcat(one.x_coord,one.y_coord))
+ end
+ return t
+end
+
+metapost.flushnormalpath = flushnormalpath
+
+metapost.specials = metapost.specials or { }
+
+-- we have two extension handlers, one for pre and postscripts, and one for colors
+
+-- the flusher is pdf based, if another backend is used, we need to overload the
+-- flusher; this is beta code, the organization will change
+
+function metapost.flush(result,flusher,askedfig) -- pdf flusher, table en dan concat is sneller, 1 literal
+ if result then
+ local figures = result.fig
+ if figures then
+ flusher = flusher or metapost.flushers.pdf
+ local colorconverter = metapost.colorconverter() -- function !
+ local colorhandler = metapost.colorhandler
+ for f=1, #figures do
+ local figure = figures[f]
+ local objects = getobjects(result,figure,f)
+ local fignum = figure:charcode() or 0
+ if not askedfig or (askedfig == fignum) then
+ local t = { }
+ local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
+ local bbox = figure:boundingbox()
+ local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack
+ metapost.llx = llx
+ metapost.lly = lly
+ metapost.urx = urx
+ metapost.ury = ury
+ if urx < llx then
+ -- invalid
+ flusher.startfigure(fignum,0,0,0,0,"invalid",figure)
+ flusher.stopfigure()
+ else
+ flusher.startfigure(fignum,llx,lly,urx,ury,"begin",figure)
+ t[#t+1] = "q"
+ if objects then
+ t[#t+1] = metapost.colorinitializer()
+ -- once we have multiple prescripts we can do more tricky things like
+ -- text and special colors at the same time
+ for o=1,#objects do
+ local object = objects[o]
+ local objecttype = object.type
+ if objecttype == "start_bounds" or objecttype == "stop_bounds" then
+ -- skip
+ elseif objecttype == "start_clip" then
+ t[#t+1] = "q"
+ flushnormalpath(object.path,t,false)
+ t[#t+1] = "W n"
+ elseif objecttype == "stop_clip" then
+ t[#t+1] = "Q"
+ miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
+ elseif objecttype == "special" then
+ metapost.specials.register(object.prescript)
+ elseif objecttype == "text" then
+ t[#t+1] = "q"
+ local ot = object.transform -- 3,4,5,6,1,2
+ t[#t+1] = format("%f %f %f %f %f %f cm",ot[3],ot[4],ot[5],ot[6],ot[1],ot[2]) -- TH: format("%f %f m %f %f %f %f 0 0 cm",unpack(ot))
+ flusher.flushfigure(t) -- flush accumulated literals
+ t = { }
+ flusher.textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
+ t[#t+1] = "Q"
+ else
+ -- alternatively we can pass on the stack, could be a helper
+ -- can be optimized with locals
+ local currentobject = { -- not needed when no extensions
+ type = object.type,
+ miterlimit = object.miterlimit,
+ linejoin = object.linejoin,
+ linecap = object.linecap,
+ color = object.color,
+ dash = object.dash,
+ path = object.path,
+ htap = object.htap,
+ pen = object.pen,
+ prescript = object.prescript,
+ postscript = object.postscript,
+ }
+ --
+ local before, inbetween, after = nil, nil, nil
+ --
+ local cs, cr = currentobject.color, nil
+ -- todo document why ...
+ if cs and colorhandler and #cs > 0 and round(cs[1]*10000) == 123 then -- test in function
+ currentobject, cr = colorhandler(cs,currentobject,t,colorconverter)
+ objecttype = currentobject.type
+ end
+ --
+ local prescript = currentobject.prescript
+ if prescript and prescript ~= "" then
+ -- move test to function
+ local special = metapost.specials[prescript]
+ if special then
+ currentobject, before, inbetween, after = special(currentobject.postscript,currentobject,t,flusher)
+ objecttype = currentobject.type
+ end
+ end
+ --
+ cs = currentobject.color
+ if cs and #cs > 0 then
+ t[#t+1], cr = colorconverter(cs)
+ end
+ --
+ if before then currentobject, t = before() end
+ local ml = currentobject.miterlimit
+ if ml and ml ~= miterlimit then
+ miterlimit = ml
+ t[#t+1] = format("%f M",ml)
+ end
+ local lj = currentobject.linejoin
+ if lj and lj ~= linejoin then
+ linejoin = lj
+ t[#t+1] = format("%i j",lj)
+ end
+ local lc = currentobject.linecap
+ if lc and lc ~= linecap then
+ linecap = lc
+ t[#t+1] = format("%i J",lc)
+ end
+ local dl = currentobject.dash
+ if dl then
+ local d = format("[%s] %i d",concat(dl.dashes or {}," "),dl.offset)
+ if d ~= dashed then
+ dashed = d
+ t[#t+1] = dashed
+ end
+ elseif dashed then
+ t[#t+1] = "[] 0 d"
+ dashed = false
+ end
+ if inbetween then currentobject, t = inbetween() end
+ local path = currentobject.path
+ local transformed, penwidth = false, 1
+ local open = path and path[1].left_type and path[#path].right_type -- at this moment only "end_point"
+ local pen = currentobject.pen
+ if pen then
+ if pen.type == 'elliptical' then
+ transformed, penwidth = pen_characteristics(object) -- boolean, value
+ t[#t+1] = format("%f w",penwidth) -- todo: only if changed
+ if objecttype == 'fill' then
+ objecttype = 'both'
+ end
+ else -- calculated by mplib itself
+ objecttype = 'fill'
+ end
+ end
+ if transformed then
+ t[#t+1] = "q"
+ end
+ if path then
+ if transformed then
+ flushconcatpath(path,t,open)
+ else
+ flushnormalpath(path,t,open)
+ end
+ if objecttype == "fill" then
+ t[#t+1] = "h f"
+ elseif objecttype == "outline" then
+ t[#t+1] = (open and "S") or "h S"
+ elseif objecttype == "both" then
+ t[#t+1] = "h B"
+ end
+ end
+ if transformed then
+ t[#t+1] = "Q"
+ end
+ local path = currentobject.htap
+ if path then
+ if transformed then
+ t[#t+1] = "q"
+ end
+ if transformed then
+ flushconcatpath(path,t,open)
+ else
+ flushnormalpath(path,t,open)
+ end
+ if objecttype == "fill" then
+ t[#t+1] = "h f"
+ elseif objecttype == "outline" then
+ t[#t+1] = (open and "S") or "h S"
+ elseif objecttype == "both" then
+ t[#t+1] = "h B"
+ end
+ if transformed then
+ t[#t+1] = "Q"
+ end
+ end
+ if cr then
+ t[#t+1] = cr
+ end
+ if after then currentobject, t = after() end
+ end
+ end
+ end
+ t[#t+1] = "Q"
+ flusher.flushfigure(t)
+ flusher.stopfigure("end")
+ end
+ if askedfig then
+ break
+ end
+ end
+ end
+ end
+ end
+end
+
+function metapost.parse(result,askedfig)
+ if result then
+ local figures = result.fig
+ if figures then
+ for f=1, #figures do
+ local figure = figures[f]
+ local fignum = figure:charcode() or 0
+ if not askedfig or (askedfig == fignum) then
+ local bbox = figure:boundingbox()
+ local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack
+ metapost.llx = llx
+ metapost.lly = lly
+ metapost.urx = urx
+ metapost.ury = ury
+ local objects = getobjects(result,figure,f)
+ if objects then
+ for o=1,#objects do
+ local object = objects[o]
+ if object.type == "outline" then
+ local prescript = object.prescript
+ if prescript then
+ local special = metapost.specials[prescript]
+ if special then
+ special(object.postscript,object)
+ end
+ end
+ end
+ end
+ end
+ break
+ end
+ end
+ end
+ end
+end
+
+-- tracing:
+
+local t = { }
+
+local flusher = {
+ startfigure = function()
+ t = { }
+ texsprint(ctxcatcodes,"\\startnointerference")
+ end,
+ flushfigure = function(literals)
+ for i=1, #literals do
+ t[#t+1] = literals[i]
+ end
+ end,
+ stopfigure = function()
+ texsprint(ctxcatcodes,"\\stopnointerference")
+ end
+}
+
+function metapost.pdfliterals(result)
+ metapost.flush(result,flusher)
+ return t
+end
+
+-- so far
+
+function metapost.totable(result)
+ local figure = result and result.fig and result.fig[1]
+ if figure then
+ local t = { }
+ local objects = figure:objects()
+ for o=1,#objects do
+ local object = objects[o]
+ local tt = { }
+ local fields = mplib.fields(object)
+ for f=1,#fields do
+ local field = fields[f]
+ tt[field] = object[field]
+ end
+ t[#t+1] = tt
+ end
+ local b = figure:boundingbox()
+ return {
+ boundingbox = { llx = b[1], lly = b[2], urx = b[3], ury = b[4] },
+ objects = t
+ }
+ else
+ return nil
+ end
+end
+
+-- will be overloaded later
+
+function metapost.colorconverter()
+ return function(cr)
+ local n = #cr
+ if n == 4 then
+ local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
+ return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G"
+ elseif n == 3 then
+ local r, g, b = cr[1], cr[2], cr[3]
+ return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G"
+ else
+ local s = cr[1]
+ return format("%.3f g %.3f G",s,s), "0 g 0 G"
+ end
+ end
+end
diff --git a/tex/context/base/mlib-pdf.mkiv b/tex/context/base/mlib-pdf.mkiv
new file mode 100644
index 000000000..2681b0810
--- /dev/null
+++ b/tex/context/base/mlib-pdf.mkiv
@@ -0,0 +1,91 @@
+%D \module
+%D [ file=mlib-pdf,
+%D version=2008.03.25,
+%D title=\METAPOST\ Integrated Graphics,
+%D subtitle=Conversion to PDF,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\registerctxluafile{mlib-pdf}{1.001}
+
+\def\MPLIBtoPDF#1{\ctxlua{metapost.flush_literal(#1)}}
+
+\def\MPLIBboundingbox#1#2#3#4%
+ {\xdef\MPllx{#1}%
+ \xdef\MPlly{#2}%
+ \xdef\MPurx{#3}%
+ \xdef\MPury{#4}%
+ \xdef\MPwidth {\the\dimexpr#3\onebasepoint-#1\onebasepoint\relax}%
+ \xdef\MPheight{\the\dimexpr#4\onebasepoint-#2\onebasepoint\relax}}
+
+\def\startMPLIBtoPDF#1#2#3#4% watch the transparency reset
+ {\naturalhbox\bgroup
+ \doactivatecolor\s!black\forcecolorhack
+ \MPLIBboundingbox{#1}{#2}{#3}{#4}%
+ %\forgetall % done already elsewhere
+ \setbox\scratchbox\vbox\bgroup
+ \noindent % this is really needed in order to force tex into proper cm's
+ \startMPresources}
+
+\def\stopMPLIBtoPDF % watch the transparency reset
+ {%\dohandleMPresettransparency % not needed
+ \stopMPresources
+ \egroup
+ \setbox\scratchbox\hbox\bgroup
+ \hskip-\MPllx\onebasepoint
+ \raise-\MPlly\onebasepoint
+ \box\scratchbox
+ \egroup
+ \setbox\scratchbox\vbox to \MPheight\bgroup
+ \vfill
+ \hsize\MPwidth
+ \smashbox\scratchbox
+ \box\scratchbox
+ \egroup
+ \wd\scratchbox\MPwidth
+ \ht\scratchbox\MPheight
+ \dopackageMPgraphic\scratchbox
+ \egroup}
+
+% \def\MPLIBtextext#1#2#3#4#5%
+% {\begingroup
+% \def\MPtextdata{#3}% delegate the splitter to lua
+% \defconvertedcommand\MPtextdata\MPtextdata % no edef
+% \splitstring\MPtextdata\at::::\to\MPtexttag\and\MPtextnumber
+% \executeifdefined{handleMPtext\MPtexttag}
+% {\setbox\scratchbox\hbox
+% {\font\temp=#1\space at #2\onebasepoint
+% \let\c\char
+% \temp
+% \MPfshowcommand{#3}}%
+% \setbox\scratchbox\hbox
+% {\hskip#4\onebasepoint
+% \raise#5\onebasepoint
+% \box\scratchbox}%
+% \smashbox\scratchbox
+% \box\scratchbox}%
+% \endgroup}
+
+\def\MPLIBtextext#1#2#3#4#5%
+ {\begingroup
+ \setbox\scratchbox\hbox
+ {\font\temp=#1\space at #2\onebasepoint
+ \let\c\char
+ \temp
+ #3}%
+ \setbox\scratchbox\hbox
+ {\hskip#4\onebasepoint
+ \raise#5\onebasepoint
+ \box\scratchbox}%
+ \smashbox\scratchbox
+ \box\scratchbox
+ \endgroup}
+
+\protect \endinput
diff --git a/tex/context/base/mlib-pps.lua b/tex/context/base/mlib-pps.lua
new file mode 100644
index 000000000..8b36660d3
--- /dev/null
+++ b/tex/context/base/mlib-pps.lua
@@ -0,0 +1,897 @@
+if not modules then modules = { } end modules ['mlib-pps'] = { -- prescript, postscripts and specials
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- current limitation: if we have textext as well as a special color then due to
+-- prescript/postscript overload we can have problems
+--
+-- todo: report max textexts
+
+local format, gmatch, concat, round, match = string.format, string.gmatch, table.concat, math.round, string.match
+local sprint = tex.sprint
+local tonumber, type = tonumber, type
+local lpegmatch = lpeg.match
+local texbox = tex.box
+local copy_list = node.copy_list
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
+local ctxcatcodes = tex.ctxcatcodes
+
+local trace_textexts = false trackers.register("metapost.textexts", function(v) trace_textexts = v end)
+
+colors = colors or { }
+
+local rgbtocmyk = colors.rgbtocmyk or function() return 0,0,0,1 end
+local cmyktorgb = colors.cmyktorgb or function() return 0,0,0 end
+local rgbtogray = colors.rgbtogray or function() return 0 end
+local cmyktogray = colors.cmyktogray or function() return 0 end
+
+metapost = metapost or { }
+metapost.specials = metapost.specials or { }
+metapost.specials.data = metapost.specials.data or { }
+metapost.externals = metapost.externals or { n = 0 }
+
+local data = metapost.specials.data
+
+local colordata = { {}, {}, {}, {}, {} }
+
+--~ (r,g,b) => cmyk : r=123 g= 1 b=hash
+--~ => spot : r=123 g= 2 b=hash
+--~ => transparent rgb : r=123 g= 3 b=hash
+--~ => transparent cmyk : r=123 g= 4 b=hash
+--~ => transparent spot : r=123 g= 5 b=hash
+--~ => rest : r=123 g=n>10 b=whatever
+
+local nooutercolor = "0 g 0 G"
+local nooutertransparency = "/Tr0 gs" -- only when set
+local outercolormode = 0
+local outercolor = nooutercolor
+local outertransparency = nooutertransparency
+local innercolor = nooutercolor
+local innertransparency = nooutertransparency
+
+local pdfcolor, pdftransparency = lpdf.color, lpdf.transparency
+local registercolor, registerspotcolor = colors.register, colors.registerspotcolor
+local registertransparency = transparencies.register
+
+function metapost.set_outer_color(mode,colormodel,colorattribute,transparencyattribute)
+ -- has always to be called before conversion
+ -- todo: transparency (not in the mood now)
+ outercolormode = mode
+ if mode == 1 or mode == 3 then
+ -- inherit from outer (registered color)
+ outercolor = pdfcolor(colormodel,colorattribute) or nooutercolor
+ outertransparency = pdftransparency(transparencyattribute) or nooutertransparency
+ elseif mode == 2 then
+ -- stand alone (see m-punk.tex)
+ outercolor = ""
+ outertransparency = ""
+ else -- 0
+ outercolor = nooutercolor
+ outertransparency = nooutertransparency
+ end
+ innercolor = outercolor
+ innertransparency = outertransparency -- not yet used
+end
+
+local function checked_color_pair(color)
+ if not color then
+ return innercolor, outercolor
+ elseif outercolormode == 3 then
+ innercolor = color
+ return innercolor, innercolor
+ else
+ return color, outercolor
+ end
+end
+
+metapost.checked_color_pair = checked_color_pair
+
+function metapost.colorinitializer()
+ innercolor = outercolor
+ innertransparency = outertransparency
+ return outercolor, outertransparency
+end
+
+function metapost.specials.register(str) -- only colors
+ local size, content, n, class = match(str,"^%%%%MetaPostSpecial: (%d+) (.*) (%d+) (%d+)$")
+ if class then
+ -- use lpeg splitter
+ local data = { }
+ for s in gmatch(content,"[^ ]+") do
+ data[#data+1] = s
+ end
+ class, n = tonumber(class), tonumber(n)
+ if class == 3 or class == 4 or class == 5 then
+ -- hm, weird
+ else
+ n = tonumber(data[1])
+ end
+ if n then
+ local cc = colordata[class]
+ if cc then
+ cc[n] = data
+ else
+ logs.report("mplib","problematic special: %s (no colordata class %s)", str or "?",class)
+ end
+ else
+ -- there is some bug to be solved, so we issue a message
+ logs.report("mplib","problematic special: %s", str or "?")
+ end
+ end
+--~ if match(str,"^%%%%MetaPostOption: multipass") then
+--~ metapost.multipass = true
+--~ end
+end
+
+local function spotcolorconverter(parent, n, d, p)
+ registerspotcolor(parent)
+ return pdfcolor(colors.model,registercolor(nil,'spot',parent,n,d,p))
+end
+
+function metapost.colorhandler(cs, object, result, colorconverter) -- handles specials
+ local cr = outercolor
+ local what = round(cs[2]*10000)
+ local data = colordata[what]
+ if data then
+ data = data[round(cs[3]*10000)]
+ end
+ if not data then
+ --
+ elseif what == 1 then
+ result[#result+1], cr = colorconverter({ data[2], data[3], data[4], data[5] })
+ elseif what == 2 then
+ result[#result+1] = spotcolorconverter(data[2],data[3],data[4],data[5])
+ else
+ if what == 3 then
+ result[#result+1], cr = colorconverter({ data[3], data[4], data[5]})
+ elseif what == 4 then
+ result[#result+1], cr = colorconverter({ data[3], data[4], data[5], data[6]})
+ elseif what == 5 then
+ result[#result+1] = spotcolorconverter(data[3],data[4],data[5],data[6])
+ end
+ object.prescript = "tr"
+ object.postscript = data[1] .. "," .. data[2]
+ end
+ object.color = nil
+ return object, cr
+end
+
+function metapost.colorspec(cs) -- used for shades ... returns table (for checking) or string (spot)
+ local what = round(cs[2]*10000)
+ local data = colordata[what][round(cs[3]*10000)]
+ if not data then
+ return { 0 }
+ elseif what == 1 then
+ return { tonumber(data[2]), tonumber(data[3]), tonumber(data[4]), tonumber(data[5]) }
+ elseif what == 2 then
+ return spotcolorconverter(data[2],data[3],data[4],data[5])
+ elseif what == 3 then
+ return { tonumber(data[3]), tonumber(data[4]), tonumber(data[5]) }
+ elseif what == 4 then
+ return { tonumber(data[3]), tonumber(data[4]), tonumber(data[5]), tonumber(data[6]) }
+ elseif what == 5 then
+ return spotcolorconverter(data[3],data[4],data[5],data[6])
+ end
+end
+
+function metapost.specials.tr(specification,object,result)
+ local a, t = match(specification,"^(.+),(.+)$")
+ local before = a and t and function()
+ result[#result+1] = format("/Tr%s gs",registertransparency(nil,a,t,true)) -- maybe nil instead of 'mp'
+ return object, result
+ end
+ local after = before and function()
+ result[#result+1] = outertransparency -- here we could revert to the outer color
+ return object, result
+ end
+ return object, before, nil, after
+end
+
+local specificationsplitter = lpeg.Ct(lpeg.splitat(" "))
+local colorsplitter = lpeg.Ct(lpeg.splitat(":"))
+local colorsplitter = lpeg.Ct(lpeg.splitter(":",tonumber))
+
+-- Unfortunately we cannot use cmyk colors natively because there is no
+-- generic color allocation primitive ... it's just an rgbcolor color.. This
+-- means that we cannot pass colors in either cmyk or rgb form.
+--
+-- def cmyk(expr c,m,y,k) =
+-- 1 withprescript "cc" withpostscript ddddecimal (c,m,y,k)
+-- enddef ;
+--
+-- This is also an example of a simple plugin.
+
+--~ function metapost.specials.cc(specification,object,result)
+--~ object.color = lpegmatch(specificationsplitter,specification)
+--~ return object, nil, nil, nil
+--~ end
+--~ function metapost.specials.cc(specification,object,result)
+--~ local c = lpegmatch(specificationsplitter,specification)
+--~ local o = object.color[1]
+--~ c[1],c[2],c[3],c[4] = o*c[1],o*c[2],o*c[3],o*c[4]
+--~ return object, nil, nil, nil
+--~ end
+
+-- thanks to taco's reading of the postscript manual:
+--
+-- x' = sx * x + ry * y + tx
+-- y' = rx * x + sy * y + ty
+
+function metapost.specials.fg(specification,object,result,flusher) -- graphics
+ local op = object.path
+ local first, second, fourth = op[1], op[2], op[4]
+ local tx, ty = first.x_coord , first.y_coord
+ local sx, sy = second.x_coord - tx, fourth.y_coord - ty
+ local rx, ry = second.y_coord - ty, fourth.x_coord - tx
+ if sx == 0 then sx = 0.00001 end
+ if sy == 0 then sy = 0.00001 end
+ local before = specification and function()
+ flusher.flushfigure(result)
+ sprint(ctxcatcodes,format("\\MPLIBfigure{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,specification))
+ object.path = nil
+ return object, { }
+ end
+ return { } , before, nil, nil -- replace { } by object for tracing
+end
+
+function metapost.specials.ps(specification,object,result) -- positions
+ local op = object.path
+ local first, third = op[1], op[3]
+ local x, y = first.x_coord, first.y_coord
+ local w, h = third.x_coord - x, third.y_coord - y
+ local label = specification
+ x = x - metapost.llx
+ y = metapost.ury - y
+ -- logs.report("mplib", "todo: position '%s' at (%s,%s) with (%s,%s)",label,x,y,w,h)
+ sprint(ctxcatcodes,format("\\dosavepositionwhd{%s}{0}{%sbp}{%sbp}{%sbp}{%sbp}{0pt}",label,x,y,w,h))
+ return { }, nil, nil, nil
+end
+
+local nofshades = 0 -- todo: hash resources, start at 1000 in order not to clash with older
+
+local function normalize(ca,cb)
+ if #cb == 1 then
+ if #ca == 4 then
+ cb[1], cb[2], cb[3], cb[4] = 0, 0, 0, 1-cb[1]
+ else
+ cb[1], cb[2], cb[3] = cb[1], cb[1], cb[1]
+ end
+ elseif #cb == 3 then
+ if #ca == 4 then
+ cb[1], cb[2], cb[3], cb[4] = rgbtocmyk(cb[1],cb[2],cb[3])
+ else
+ cb[1], cb[2], cb[3] = cmyktorgb(cb[1],cb[2],cb[3],cb[4])
+ end
+ end
+end
+
+-- todo: check for the same colorspace (actually a backend issue), now we can
+-- have several similar resources
+--
+-- normalize(ca,cb) fails for spotcolors
+
+function metapost.specials.cs(specification,object,result,flusher) -- spot colors?
+ -- a mess, not dynamic anyway
+ nofshades = nofshades + 1
+ flusher.flushfigure(result)
+ result = { }
+ local t = lpegmatch(specificationsplitter,specification)
+ -- we need a way to move/scale
+ local ca = lpegmatch(colorsplitter,t[4])
+ local cb = lpegmatch(colorsplitter,t[8])
+ if round(ca[1]*10000) == 123 then ca = metapost.colorspec(ca) end
+ if round(cb[1]*10000) == 123 then cb = metapost.colorspec(cb) end
+ local name = format("MplSh%s",nofshades)
+ local domain = { tonumber(t[1]), tonumber(t[2]) }
+ local coordinates = { tonumber(t[5]), tonumber(t[6]), tonumber(t[7]), tonumber(t[9]), tonumber(t[10]), tonumber(t[11]) }
+ if type(ca) == "string" then
+ -- backend specific (will be renamed)
+ lpdf.circularshade(name,domain,{ 0 },{ 1 },1,"DeviceGray",coordinates)
+ else
+ if #ca > #cb then
+ normalize(ca,cb)
+ elseif #ca < #cb then
+ normalize(cb,ca)
+ end
+ local model = colors.model
+ if model == "all" then
+ model= (#ca == 4 and "cmyk") or (#ca == 3 and "rgb") or "gray"
+ end
+ if model == "rgb" then
+ if #ca == 4 then
+ ca[1], ca[2], ca[3] = cmyktorgb(ca[1],ca[2],ca[3],ca[4])
+ cb[1], cb[2], cb[3] = cmyktorgb(cb[1],cb[2],cb[3],cb[4])
+ ca[4], cb[4] = nil, nil
+ elseif #ca == 1 then
+ local a, b = 1-ca[1], 1-cb[1]
+ ca[1], ca[2], ca[3] = a, a, a
+ cb[1], cb[2], cb[3] = b, b, b
+ end
+ -- backend specific (will be renamed)
+ lpdf.circularshade(name,domain,ca,cb,1,"DeviceRGB",coordinates)
+ elseif model == "cmyk" then
+ if #ca == 3 then
+ ca[1], ca[2], ca[3], ca[4] = rgbtocmyk(ca[1],ca[2],ca[3])
+ cb[1], cb[2], cb[3], ca[4] = rgbtocmyk(cb[1],cb[2],cb[3])
+ elseif #ca == 1 then
+ ca[1], ca[2], ca[3], ca[4] = 0, 0, 0, ca[1]
+ cb[1], cb[2], cb[3], ca[4] = 0, 0, 0, ca[1]
+ end
+ -- backend specific (will be renamed)
+ lpdf.circularshade(name,domain,ca,cb,1,"DeviceCMYK",coordinates)
+ else
+ if #ca == 4 then
+ ca[1] = cmyktogray(ca[1],ca[2],ca[3],ca[4])
+ cb[1] = cmyktogray(cb[1],cb[2],cb[3],cb[4])
+ elseif #ca == 3 then
+ ca[1] = rgbtogray(ca[1],ca[2],ca[3])
+ cb[1] = rgbtogray(cb[1],cb[2],cb[3])
+ end
+ -- backend specific (will be renamed)
+ lpdf.circularshade(name,domain,ca,cb,1,"DeviceGRAY",coordinates)
+ end
+ end
+ local before = function()
+ result[#result+1] = "q /Pattern cs"
+ return object, result
+ end
+ local after = function()
+ result[#result+1] = format("W n /%s sh Q", name)
+ return object, result
+ end
+ object.color, object.type = nil, nil
+ return object, before, nil, after
+end
+
+function metapost.specials.ls(specification,object,result,flusher)
+ nofshades = nofshades + 1
+ flusher.flushfigure(result)
+ result = { }
+ local t = lpegmatch(specificationsplitter,specification)
+ -- we need a way to move/scale
+ local ca = lpegmatch(colorsplitter,t[4])
+ local cb = lpegmatch(colorsplitter,t[7])
+ if round(ca[1]*10000) == 123 then ca = metapost.colorspec(ca) end
+ if round(cb[1]*10000) == 123 then cb = metapost.colorspec(cb) end
+ local name = format("MpSh%s",nofshades)
+ local domain = { tonumber(t[1]), tonumber(t[2]) }
+ local coordinates = { tonumber(t[5]), tonumber(t[6]), tonumber(t[8]), tonumber(t[9]) }
+ if type(ca) == "string" then
+ -- backend specific (will be renamed)
+ lpdf.linearshade(name,domain,{ 0 },{ 1 },1,"DeviceGray",coordinates)
+ else
+ if #ca > #cb then
+ normalize(ca,cb)
+ elseif #ca < #cb then
+ normalize(cb,ca)
+ end
+ local model = colors.model
+ if model == "all" then
+ model= (#ca == 4 and "cmyk") or (#ca == 3 and "rgb") or "gray"
+ end
+ if model == "rgb" then
+ if #ca == 4 then
+ ca[1], ca[2], ca[3] = cmyktorgb(ca[1],ca[2],ca[3],ca[4])
+ cb[1], cb[2], cb[3] = cmyktorgb(cb[1],cb[2],cb[3],cb[4])
+ elseif #ca == 1 then
+ local a, b = 1-ca[1], 1-cb[1]
+ ca[1], ca[2], ca[3] = a, a, a
+ cb[1], cb[2], cb[3] = b, b, b
+ end
+ -- backend specific (will be renamed)
+ lpdf.linearshade(name,domain,ca,cb,1,"DeviceRGB",coordinates)
+ elseif model == "cmyk" then
+ if #ca == 3 then
+ ca[1], ca[2], ca[3], ca[4] = rgbtocmyk(ca[1],ca[2],ca[3])
+ cb[1], cb[2], cb[3], ca[4] = rgbtocmyk(cb[1],cb[2],cb[3])
+ elseif #ca == 1 then
+ ca[1], ca[2], ca[3], ca[4] = 0, 0, 0, ca[1]
+ cb[1], cb[2], cb[3], ca[4] = 0, 0, 0, ca[1]
+ end
+ -- backend specific (will be renamed)
+ lpdf.linearshade(name,domain,ca,cb,1,"DeviceCMYK",coordinates)
+ else
+ if #ca == 4 then
+ ca[1] = cmyktogray(ca[1],ca[2],ca[3],ca[4])
+ cb[1] = cmyktogray(cb[1],cb[2],cb[3],cb[4])
+ elseif #ca == 3 then
+ ca[1] = rgbtogray(ca[1],ca[2],ca[3])
+ cb[1] = rgbtogray(cb[1],cb[2],cb[3])
+ end
+ -- backend specific (will be renamed)
+ lpdf.linearshade(name,domain,ca,cb,1,"DeviceGRAY",coordinates)
+ end
+ end
+ local before = function()
+ result[#result+1] = "q /Pattern cs"
+ return object, result
+ end
+ local after = function()
+ result[#result+1] = format("W n /%s sh Q", name)
+ return object, result
+ end
+ object.color, object.type = nil, nil
+ return object, before, nil, after
+end
+
+-- no need for a before here
+
+local current_format, current_graphic, current_initializations
+
+-- metapost.first_box = metapost.first_box or 1000
+-- metapost.last_box = metapost.last_box or 1100
+--~ metapost.textext_current = metapost.first_box
+metapost.multipass = false
+
+local textexts = { }
+
+function metapost.free_boxes() -- todo: mp direct list ipv box
+ -- for i = metapost.first_box,metapost.last_box do
+ -- local b = texbox[i]
+ -- if b then
+ -- texbox[i] = nil -- no node.flush_list(b) needed, else double free error
+ -- else
+ -- break
+ -- end
+ -- end
+ for n, box in next, textexts do
+ local tn = textexts[n]
+ if tn then
+ -- somehow not flushed (used)
+ textexts[n] = nil
+ end
+ end
+ textexts = { }
+end
+
+function metapost.settext(box,slot)
+ textexts[slot] = copy_list(texbox[box])
+ texbox[box] = nil
+ -- this will become
+ -- textexts[slot] = texbox[box]
+ -- unsetbox(box)
+end
+
+function metapost.gettext(box,slot)
+ texbox[box] = copy_list(textexts[slot])
+-- textexts[slot] = nil -- no, pictures can be placed several times
+end
+
+function metapost.specials.tf(specification,object)
+--~ print("setting", metapost.textext_current)
+ local n, str = match(specification,"^(%d+):(.+)$")
+ if n and str then
+ n = tonumber(n)
+ -- if metapost.textext_current < metapost.last_box then
+ -- metapost.textext_current = metapost.first_box + n - 1
+ -- end
+ if trace_textexts then
+ -- logs.report("metapost","first pass: order %s, box %s",n,metapost.textext_current)
+ logs.report("metapost","first pass: order %s",n)
+ end
+ -- sprint(ctxcatcodes,format("\\MPLIBsettext{%s}{%s}",metapost.textext_current,str))
+ sprint(ctxcatcodes,format("\\MPLIBsettext{%s}{%s}",n,str))
+ metapost.multipass = true
+ end
+ return { }, nil, nil, nil
+end
+
+function metapost.specials.ts(specification,object,result,flusher)
+ -- print("getting", metapost.textext_current)
+ local n, str = match(specification,"^(%d+):(.+)$")
+ if n and str then
+ n = tonumber(n)
+ if trace_textexts then
+ -- logs.report("metapost","second pass: order %s, box %s",n,metapost.textext_current)
+ logs.report("metapost","second pass: order %s",n)
+ end
+ local op = object.path
+ local first, second, fourth = op[1], op[2], op[4]
+ local tx, ty = first.x_coord , first.y_coord
+ local sx, sy = second.x_coord - tx, fourth.y_coord - ty
+ local rx, ry = second.y_coord - ty, fourth.x_coord - tx
+ if sx == 0 then sx = 0.00001 end
+ if sy == 0 then sy = 0.00001 end
+ if not trace_textexts then
+ object.path = nil
+ end
+ local before = function() -- no need for before function (just do it directly)
+ --~ flusher.flushfigure(result)
+ --~ sprint(ctxcatcodes,format("\\MPLIBgettext{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,metapost.textext_current))
+ --~ result = { }
+ result[#result+1] = format("q %f %f %f %f %f %f cm", sx,rx,ry,sy,tx,ty)
+ flusher.flushfigure(result)
+ -- if metapost.textext_current < metapost.last_box then
+ -- metapost.textext_current = metapost.first_box + n - 1
+ -- end
+ -- local b = metapost.textext_current
+ -- local box = texbox[b]
+ local box = textexts[n]
+ if box then
+ -- sprint(ctxcatcodes,format("\\MPLIBgettextscaled{%s}{%s}{%s}",b,metapost.sxsy(box.width,box.height,box.depth)))
+ sprint(ctxcatcodes,format("\\MPLIBgettextscaled{%s}{%s}{%s}",n,metapost.sxsy(box.width,box.height,box.depth)))
+ else
+ -- error
+ end
+ result = { "Q" }
+ return object, result
+ end
+ return { }, before, nil, nil -- replace { } by object for tracing
+ else
+ return { }, nil, nil, nil -- replace { } by object for tracing
+ end
+end
+
+-- rather generic pdf, so use this elsewhere too it no longer pays
+-- off to distinguish between outline and fill (we now have both
+-- too, e.g. in arrows)
+
+metapost.reducetogray = true
+
+local models = { }
+
+function models.all(cr)
+ local n = #cr
+ if n == 0 then
+ return checked_color_pair()
+ elseif metapost.reducetogray then
+ if n == 1 then
+ local s = cr[1]
+ return checked_color_pair(format("%.3f g %.3f G",s,s))
+ elseif n == 3 then
+ local r, g, b = cr[1], cr[2], cr[3]
+ if r == g and g == b then
+ return checked_color_pair(format("%.3f g %.3f G",r,r))
+ else
+ return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+ end
+ else
+ local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
+ if c == m and m == y and y == 0 then
+ k = 1 - k
+ return checked_color_pair(format("%.3f g %.3f G",k,k))
+ else
+ return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+ end
+ end
+ elseif n == 1 then
+ local s = cr[1]
+ return checked_color_pair(format("%.3f g %.3f G",s,s))
+ elseif n == 3 then
+ local r, g, b = cr[1], cr[2], cr[3]
+ return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+ else
+ local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
+ return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+ end
+end
+
+function models.rgb(cr)
+ local n = #cr
+ if n == 0 then
+ return checked_color_pair()
+ elseif metapost.reducetogray then
+ if n == 1 then
+ local s = cr[1]
+ checked_color_pair(format("%.3f g %.3f G",s,s))
+ elseif n == 3 then
+ local r, g, b = cr[1], cr[2], cr[3]
+ if r == g and g == b then
+ return checked_color_pair(format("%.3f g %.3f G",r,r))
+ else
+ return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+ end
+ else
+ local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
+ if c == m and m == y and y == 0 then
+ k = 1 - k
+ return checked_color_pair(format("%.3f g %.3f G",k,k))
+ else
+ local r, g, b = cmyktorgb(c,m,y,k)
+ return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+ end
+ end
+ elseif n == 1 then
+ local s = cr[1]
+ return checked_color_pair(format("%.3f g %.3f G",s,s))
+ else
+ local r, g, b
+ if n == 3 then
+ r, g, b = cmyktorgb(cr[1],cr[2],cr[3],cr[4])
+ else
+ r, g, b = cr[1], cr[2], cr[3]
+ end
+ return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+ end
+end
+
+function models.cmyk(cr)
+ local n = #cr
+ if n == 0 then
+ return checked_color_pair()
+ elseif metapost.reducetogray then
+ if n == 1 then
+ local s = cr[1]
+ return checked_color_pair(format("%.3f g %.3f G",s,s))
+ elseif n == 3 then
+ local r, g, b = cr[1], cr[2], cr[3]
+ if r == g and g == b then
+ return checked_color_pair(format("%.3f g %.3f G",r,r))
+ else
+ local c, m, y, k = rgbtocmyk(r,g,b)
+ return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+ end
+ else
+ local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
+ if c == m and m == y and y == 0 then
+ k = 1 - k
+ return checked_color_pair(format("%.3f g %.3f G",k,k))
+ else
+ return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+ end
+ end
+ elseif n == 1 then
+ local s = cr[1]
+ return checked_color_pair(format("%.3f g %.3f G",s,s))
+ else
+ local c, m, y, k
+ if n == 3 then
+ c, m, y, k = rgbtocmyk(cr[1],cr[2],cr[3])
+ else
+ c, m, y, k = cr[1], cr[2], cr[3], cr[4]
+ end
+ return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+ end
+end
+
+function models.gray(cr)
+ local n, s = #cr, 0
+ if n == 0 then
+ return checked_color_pair()
+ elseif n == 4 then
+ s = cmyktogray(cr[1],cr[2],cr[3],cr[4])
+ elseif n == 3 then
+ s = rgbtogray(cr[1],cr[2],cr[3])
+ else
+ s = cr[1]
+ end
+ return checked_color_pair(format("%.3f g %.3f G",s,s))
+end
+
+function metapost.colorconverter()
+ return models[colors.model] or gray
+end
+
+do
+
+ local P, S, V, Cs = lpeg.P, lpeg.S, lpeg.V, lpeg.Cs
+
+ local btex = P("btex")
+ local etex = P(" etex")
+ local vtex = P("verbatimtex")
+ local ttex = P("textext")
+ local gtex = P("graphictext")
+ local multipass = P("forcemultipass")
+ local spacing = S(" \n\r\t\v")^0
+ local dquote = P('"')
+
+ local found, forced = false, false
+
+ local function convert(str)
+ found = true
+ return "rawtextext(\"" .. str .. "\")" -- centered
+ end
+ local function ditto(str)
+ return "\" & ditto & \""
+ end
+ local function register()
+ found = true
+ end
+ local function force()
+ forced = true
+ end
+
+ local texmess = (dquote/ditto + (1 - etex))^0
+
+ local function ignore(s)
+ logs.report("mplib","ignoring verbatim tex: %s",s)
+ return ""
+ end
+
+ local parser = P {
+ [1] = Cs((V(2)/register + V(4)/ignore + V(3)/convert + V(5)/force + 1)^0),
+ [2] = ttex + gtex,
+ [3] = btex * spacing * Cs(texmess) * etex,
+ [4] = vtex * spacing * Cs(texmess) * etex,
+ [5] = multipass, -- experimental, only for testing
+ }
+
+ -- currently a a one-liner produces less code
+
+ local parser = Cs((
+ (ttex + gtex)/register
+ + (btex * spacing * Cs(texmess) * etex)/convert
+ + (vtex * spacing * Cs(texmess) * etex)/ignore
+ + 1
+ )^0)
+
+ function metapost.check_texts(str)
+ found, forced = false, false
+ return lpegmatch(parser,str), found, forced
+ end
+
+end
+
+local factor = 65536*(7227/7200)
+
+function metapost.edefsxsy(wd,ht,dp) -- helper for figure
+ local hd = ht + dp
+ commands.edef("sx",(wd ~= 0 and factor/wd) or 0)
+ commands.edef("sy",(hd ~= 0 and factor/hd) or 0)
+end
+
+function metapost.sxsy(wd,ht,dp) -- helper for text
+ local hd = ht + dp
+ return (wd ~= 0 and factor/wd) or 0, (hd ~= 0 and factor/hd) or 0
+end
+
+local no_trial_run = "_trial_run_ := false ;"
+local do_trial_run = "if unknown _trial_run_ : boolean _trial_run_ fi ; _trial_run_ := true ;"
+local text_data_template = "_tt_w_[%i]:=%f;_tt_h_[%i]:=%f;_tt_d_[%i]:=%f;"
+local do_begin_fig = "; beginfig(1); "
+local do_end_fig = "; endfig ;"
+local do_safeguard = ";"
+
+function metapost.text_texts_data()
+ local t, n = { }, 0
+--~ for i = metapost.first_box, metapost.last_box do
+--~ n = n + 1
+--~ local box = texbox[i]
+ for n, box in next, textexts do
+ if trace_textexts then
+ logs.report("metapost","passed data: order %s, box %s",n,i)
+ end
+ if box then
+ t[#t+1] = format(text_data_template,n,box.width/factor,n,box.height/factor,n,box.depth/factor)
+ else
+ break
+ end
+ end
+--~ print(table.serialize(t))
+ return t
+end
+
+metapost.intermediate = metapost.intermediate or {}
+metapost.intermediate.actions = metapost.intermediate.actions or {}
+metapost.intermediate.needed = false
+
+metapost.method = 1 -- 1:dumb 2:clever
+
+function metapost.graphic_base_pass(mpsformat,str,initializations,preamble,askedfig)
+ local nofig = (askedfig and "") or false
+ local done_1, done_2, forced_1, forced_2
+ str, done_1, forced_1 = metapost.check_texts(str)
+ if not preamble or preamble == "" then
+ preamble, done_2, forced_2 = "", false, false
+ else
+ preamble, done_2, forced_2 = metapost.check_texts(preamble)
+ end
+ -- metapost.textext_current = metapost.first_box
+ metapost.intermediate.needed = false
+ metapost.multipass = false -- no needed here
+ current_format, current_graphic, current_initializations = mpsformat, str, initializations or ""
+ if metapost.method == 1 or (metapost.method == 2 and (done_1 or done_2)) then
+ -- first true means: trialrun, second true means: avoid extra run if no multipass
+ local flushed = metapost.process(mpsformat, {
+ preamble,
+ nofig or do_begin_fig,
+ do_trial_run,
+ current_initializations,
+ do_safeguard,
+ current_graphic,
+ nofig or do_end_fig
+ -- }, true, nil, true )
+ }, true, nil, not (forced_1 or forced_2), false, askedfig)
+ if metapost.intermediate.needed then
+ for _, action in next, metapost.intermediate.actions do
+ action()
+ end
+ end
+ if not flushed or not metapost.optimize then
+ -- tricky, we can only ask once for objects and therefore
+ -- we really need a second run when not optimized
+ sprint(ctxcatcodes,format("\\ctxlua{metapost.graphic_extra_pass(%s)}",askedfig or "false"))
+ end
+ else
+ metapost.process(mpsformat, {
+ preamble,
+ nofig or do_begin_fig,
+ no_trial_run,
+ current_initializations,
+ do_safeguard,
+ current_graphic,
+ nofig or do_end_fig
+ }, false, nil, false, false, askedfig )
+ end
+ -- here we could free the textext boxes
+ metapost.free_boxes()
+end
+
+function metapost.graphic_extra_pass(askedfig)
+ local nofig = (askedfig and "") or false
+ -- metapost.textext_current = metapost.first_box
+ metapost.process(current_format, {
+ nofig or do_begin_fig,
+ no_trial_run,
+ concat(metapost.text_texts_data()," ;\n"),
+ current_initializations,
+ do_safeguard,
+ current_graphic,
+ nofig or do_end_fig
+ }, false, nil, false, true, askedfig )
+end
+
+metapost.tex = metapost.tex or { }
+
+do -- only used in graphictexts
+
+ local environments = { }
+
+ function metapost.tex.set(str)
+ environments[#environments+1] = str
+ end
+ function metapost.tex.reset()
+ environments = { }
+ end
+ function metapost.tex.get()
+ return concat(environments,"\n")
+ end
+
+end
+
+local graphics = { }
+local start = [[\starttext]]
+local preamble = [[\long\def\MPLIBgraphictext#1{\startTEXpage[scale=10000]#1\stopTEXpage}]]
+local stop = [[\stoptext]]
+
+function metapost.specials.gt(specification,object) -- number, so that we can reorder
+ graphics[#graphics+1] = format("\\MPLIBgraphictext{%s}",specification)
+ metapost.intermediate.needed = true
+ metapost.multipass = true
+ return { }, nil, nil, nil
+end
+
+function metapost.intermediate.actions.makempy()
+ if #graphics > 0 then
+ local externals = metapost.externals
+ externals.n = externals.n + 1
+ starttiming(externals)
+ local mpofile = tex.jobname .. "-mpgraph"
+ local mpyfile = file.replacesuffix(mpofile,"mpy")
+ local pdffile = file.replacesuffix(mpofile,"pdf")
+ local texfile = file.replacesuffix(mpofile,"tex")
+ io.savedata(texfile, { start, preamble, metapost.tex.get(), concat(graphics,"\n"), stop }, "\n")
+ local command = format("context --once %s %s", (tex.interactionmode == 0 and "--batchmode") or "", texfile)
+ os.execute(command)
+ if io.exists(pdffile) then
+ command = format("pstoedit -ssp -dt -f mpost %s %s", pdffile, mpyfile)
+ os.execute(command)
+ local result = { }
+ if io.exists(mpyfile) then
+ local data = io.loaddata(mpyfile)
+ for figure in gmatch(data,"beginfig(.-)endfig") do
+ result[#result+1] = format("begingraphictextfig%sendgraphictextfig ;\n", figure)
+ end
+ io.savedata(mpyfile,concat(result,""))
+ end
+ end
+ stoptiming(externals)
+ graphics = { } -- ?
+ end
+end
diff --git a/tex/context/base/mlib-pps.mkiv b/tex/context/base/mlib-pps.mkiv
new file mode 100644
index 000000000..0a78a8704
--- /dev/null
+++ b/tex/context/base/mlib-pps.mkiv
@@ -0,0 +1,70 @@
+%D \module
+%D [ file=mlib-pps,
+%D version=2008.03.25,
+%D title=\METAPOST\ Integrated Graphics,
+%D subtitle=Basics,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\registerctxluafile{mlib-pps}{1.001}
+
+%D Todo: catch nested graphics like external figures with dummies.
+
+% \newtoks\everyMPLIBtext % not yet used
+
+% \appendtoks
+% \let\handleuseMPgraphic \thirdofthreearguments
+% \let\handlereusableMPgraphic\thirdofthreearguments
+% \to \everyMPLIBtext
+
+% this will move !
+
+% Instead of preallocated boxes we now use a table of lists so that we
+% have no limitation. Typically an example of a next version solution
+% due to \LUATEX\ evolving.
+
+\newbox \MPtextbox
+\newtoks\everyMPLIBsettext
+
+\def\MPLIBfigure#1#2#3#4#5#6#7% todo: move Q q to lua
+ {\setbox\scratchbox\hbox{\externalfigure[#7]}%
+ \ctxlua{metapost.edefsxsy(\number\wd\scratchbox,\number\ht\scratchbox,0)}%
+ \pdfliteral direct{q #1 #2 #3 #4 #5 #6 cm}% no direct
+ \vbox to \zeropoint{\vss\hbox to \zeropoint{\scale[sx=\sx,sy=\sy]{\box\scratchbox}\hss}}%
+ \pdfliteral direct{Q}}
+
+\def\MPLIBsettext#1% #2%
+ {\dowithnextbox{\ctxlua{metapost.settext(\number\nextbox,#1)}}\hbox}
+
+\def\MPLIBgettextscaled#1#2#3% why a copy
+ {\ctxlua{metapost.gettext(\number\MPtextbox,#1)}%
+ \vbox to \zeropoint{\vss\hbox to \zeropoint{\black\scale[sx=#2,sy=#3]{\raise\dp\MPtextbox\box\MPtextbox}\hss}}}
+
+\def\MPLIBgraphictext#1%
+ {\startTEXpage[\c!scale=10000]#1\stopTEXpage}
+
+\protect \endinput
+
+% \def\MPLIBsettext#1% #2% we could as well store in hlists at the lua end i.e. just one box
+% {\global\setbox#1\hbox}
+%
+% \def\MPLIBfreetext#1%
+% {\global\setbox#1\emptybox}
+%
+% \def\MPLIBgettextscaled#1#2#3% why a copy
+% {\vbox to \zeropoint{\vss\hbox to \zeropoint{\black\scale[sx=#2,sy=#3]{\raise\dp#1\copy#1}\hss}}}
+%
+% \def\MPLIBallocate#1%
+% {\newbox\MPLIBfirst
+% \dorecurse{\numexpr#1-1\relax}{\let\MPLIBlast\relax\newbox\MPLIBlast}%
+% \MPLIBregister}
+%
+% \def\MPLIBregister % after allocate!
+% {\ctxlua{metapost.first_box, metapost.last_box = \number\MPLIBfirst, \number\MPLIBlast}}
diff --git a/tex/context/base/mlib-run.lua b/tex/context/base/mlib-run.lua
new file mode 100644
index 000000000..f352e1db1
--- /dev/null
+++ b/tex/context/base/mlib-run.lua
@@ -0,0 +1,379 @@
+if not modules then modules = { } end modules ['mlib-run'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+--~ cmyk -> done, native
+--~ spot -> done, but needs reworking (simpler)
+--~ multitone ->
+--~ shade -> partly done, todo: cm
+--~ figure -> done
+--~ hyperlink -> low priority, easy
+
+-- new * run
+-- or
+-- new * execute^1 * finish
+
+-- a*[b,c] == b + a * (c-b)
+
+--[[ldx--
+
The directional helpers and pen analysis are more or less translated from the
+ code. It really helps that Taco know that source so well. Taco and I spent
+quite some time on speeding up the and code. There is not
+much to gain, especially if one keeps in mind that when integrated in
+only a part of the time is spent in . Of course an integrated
+approach is way faster than an external and processing time
+nears zero.