summaryrefslogtreecommitdiff
path: root/tex/context/base/xtag-ini.tex~
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/xtag-ini.tex~')
-rw-r--r--tex/context/base/xtag-ini.tex~1161
1 files changed, 1161 insertions, 0 deletions
diff --git a/tex/context/base/xtag-ini.tex~ b/tex/context/base/xtag-ini.tex~
new file mode 100644
index 000000000..fed3e7c2b
--- /dev/null
+++ b/tex/context/base/xtag-ini.tex~
@@ -0,0 +1,1161 @@
+%D \module
+%D [ file=xtag-ini,
+%D version=2000.12.20,
+%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.
+
+% etex optimized
+
+\unprotect
+
+\def\unspaced#1%
+ {\dounspaced#1\end}
+
+\def\dounspaced#1%
+ {\ifx#1\end
+ \else\ifx#1\blankspace
+ \@EA\@EA\@EA\dounspaced
+ \else
+ #1\@EA\@EA\@EA\dounspaced
+ \fi\fi}
+
+\def\unspaceargument#1\to#2%
+ {\convertargument#1\to#2%
+ \@EA\edef\@EA#2\@EA{\@EA\unspaced\@EA{#2}}}
+
+\def\unspaceafter#1#2%
+ {\edef\ascii{\dounspaced#2\end}\@EA#1\@EA{\ascii}}
+
+\protect
+
+\beginTEX
+ \writestatus{xml}{sorry, xml is only supported in (pdf)etex}
+ \endinput
+\endTEX
+
+\writestatus{loading}{Context XML Macros (ini)}
+
+%D Remark: some hard coded character things will be replaced
+%D by named glyphs as soon as the upgraded encoding modules
+%D are released. At that moment, unicode support will be
+%D provided in accordance with the normal support in \CONTEXT.
+
+%D Like it or not, this module deals with angle bracketed
+%D input. Processing \XML\ alike input in \CONTEXT\ has been
+%D possible since 1994, but several methods ran in parallel
+%D and were implemented in modules like \type {m-sgml}.
+%D
+%D There is no one optimal solution for processing \XML\ data.
+%D The oldest method was based on a very simple preprocessor
+%D written in \PERL: \type {<command>} was converted into
+%D \type {\begSGML[command]} and optional parameters were
+%D passed.
+%D
+%D A second method is to use a \PERL\ or \XSL\ transformation
+%D script that produces \CONTEXT\ commands. This method is
+%D much slower, mainly because the whole document is read into
+%D memory and a document tree is to be build. The advantage is
+%D that processing of the resulting document is fast.
+%D
+%D The third method uses a basic parser written in the \TEX\
+%D language, and apart from a few pitfalls, this method is
+%D clean and efficient, but not always robust. Because errors
+%D in the input are not catched on forhand, processing in
+%D \TEX\ may fail due to errors. But, given that a document
+%D can be validated on forehand, this is no big problem.
+%D
+%D Each method has it's advantage, but especially the third
+%D method puts some demands on \CONTEXT, since no interference
+%D between the parser and the core commands may occur. What
+%D method is used, depends on the situation.
+%D
+%D All three methods introduce some problems in interfacing to
+%D core \CONTEXT\ functionality. This is due to the fact that
+%D sometimes we want to typeset content directly, while on
+%D other cases we just want to pick up data for later usage,
+%D either or not using delimited arguments. And, when moving
+%D data around, there is always the expansion problem to deal
+%D with.
+%D
+%D In order to be able to incorporate \XML\ style definitions
+%D into basic \TEX\ styles, we will provide some basic
+%D functionality in the core itself.
+
+%D We will be dealing with elements, which means that we have
+%D to take care of \type {<this>} and \type {</that>}, but
+%D also with \type {<such/>} and \type {<so />}. In due time
+%D this module will deal with all these animals in a
+%D convenient way. In some cases the upper and lowercase
+%D alternatives need to be dealt with, although this is not
+%D realy needed since XML is case sensitive.
+%D
+%D We also have to handle entities, like \type {&you;} and
+%D \type {&me;}. These are quite easy to deal with and need to
+%D be hooked into the encoding and abbreviation mechanisms.
+%D
+%D And then there are the parameters to be taken care of. Here
+%D we meet \type {key="value"} but also \type {key='eulav'}
+%D and even the spacy \typ {key = "value"}.
+%D
+%D Since we have to handlers for each element and entity, we
+%D will create a few namespaces. Special care has to be
+%D given to preformated code.
+
+\unprotect
+
+\def\@@XML {XML:}
+\def\@@XMLentity {\@@XML ent}
+\def\@@XMLelement {\@@XML ele}
+\def\@@XMLvariable {\@@XML var}
+\def\@@XMLvalue {\@@XML val}
+\def\@@XMLpars {\@@XML par}
+\def\@@XMLdata {\@@XML dat}
+\def\@@XMLcode {\@@XML cod}
+\def\@@XMLinstruction {\@@XML ins}
+\def\@@XMLmap {\@@XML map}
+\def\@@XMLlist {\@@XML lst}
+
+\newtoks\XMLtoks
+\newtoks\XMLresetlist
+
+\chardef\XMLargumentmode=0
+
+\newif\ifignoreXMLcase
+\newif\ifignoreXMLspaces
+\newif\iffixedXMLfont
+
+%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 \starttypen
+%D so test\compound{}test can be used instead of test||test
+%D \stoptypen
+
+\let\docompound=| \def\compound#1{\docompound#1|}
+
+%D We will implement the parser by making a few characters
+%D active. For that reason we also have to save their
+%D original meaning. The core handlers are \type
+%D {\doXMLentity} and \type {\doXMLelement}.
+
+%D \macros
+%D {enableXML}
+%D
+%D The macro \type {\enableXML} will be used to turn on the
+%D parser. This means that after that, \TEX\ commands starting
+%D with a backslash will not longer be read as such. There is
+%D a way around this, but for convenience \TEXEXEC\ will take
+%D care of processing raw \XML\ files in a transparant way.
+
+\bgroup
+\catcode`\*=\@@comment
+\catcode`\.=\@@escape
+.catcode`.B=.@@begingroup
+.catcode`.E=.@@endgroup
+
+.catcode`.&=.@@active .gdef.letterampersand B.string&E
+.catcode`.<=.@@active .gdef.letterless B.string<E
+
+.catcode`.#=.@@active .gdef.letterhash B.string#E
+.catcode`.$=.@@active .gdef.letterdollar B.string$E
+.catcode`.%=.@@active
+.catcode`.\=.@@active .gdef.letterbackslash B.string\E
+.catcode`.^=.@@active .gdef.letterhat B.string^E
+.catcode`._=.@@active .gdef.letterunderscore B.string_E
+.catcode`.{=.@@active .gdef.letterbgroup B.string{E
+.catcode`.}=.@@active .gdef.letteregroup B.string}E
+.catcode`.|=.@@active .gdef.letterbar B.string|E
+.catcode`.~=.@@active .gdef.lettertilde B.string~E
+
+.gdef.enableXMLexpansion
+ B.def<B.doXMLelementE.let&=.doXMLentityE
+
+.gdef.disableXMLexpansion
+ B.unexpanded.def<B.doXMLelementE.let&=.doXMLentityE
+
+.gdef.enableXML*
+ B.catcode`.!=.@@other*
+ .catcode`.?=.@@other*
+ .catcode`.&=.@@active .let&=.doXMLentity*
+ .catcode`.<=.@@active .unexpanded.def<B.doXMLelementE*
+ .catcode`.>=.@@other*
+ .catcode`.#=.@@active .def#B&tex-hash;E*
+ .catcode`.$=.@@active .def$B&tex-dollar;E*
+ .catcode`.%=.@@active .def%B&tex-percent;E*
+ .catcode`.\=.@@active .def\B&tex-backslash;E*
+ .catcode`.^=.@@active .def^B&tex-hat;E*
+ .catcode`._=.@@active .def_B&tex-underscore;E*
+ .catcode`.{=.@@active .def{B&tex-leftbrace;E*
+ .catcode`.}=.@@active .def}B&tex-rightbrace;E*
+ .catcode`.|=.@@active .def|B&tex-bar;E*
+ .catcode`.~=.@@other* active .def~B&tex-tilde;E*
+ .relax* needed for successive .if's
+ E
+
+.gdef.enableXMLelements*
+ B.catcode`.<=.@@active .unexpanded.def<B.doXMLelementE*
+ .catcode`.>=.@@other*
+ .relax* needed for successive .if's
+ E
+
+.egroup
+
+%D An element can be singular or paired. A singular element is
+%D called an empty element. The following definitions are
+%D equivalent:
+%D
+%D \starttypen
+%D <eerste></eerste> <eerste/> <eerste />
+%D \stoptypen
+%D
+%D Empty elements can have arguments too. Conforming the
+%D standard, each key must have a value. These are separated
+%D by an \type {=} sign and the value is delimited by either
+%D \type {"} or \type {'}. There may be spaces around the
+%D equal sign.
+%D
+%D \starttypen
+%D <eerste a= "b" c ="d" /> <eerste a = "b" c="d"/>
+%D \stoptypen
+%D
+%D Officially the following definition is not valid:
+%D
+%D \starttypen
+%D <eerste>some text</eerste> <eerste/> <eerste />
+%D \stoptypen
+%D
+%D Although we can handle both cases independently, this is
+%D seldom needed.
+%D
+%D Processing instructions are identified by a~\type {?} and are
+%D like empty elements.
+%D
+%D \starttypen
+%D <?doel a="b" c="d"?> <?doel a="b" c="d" ?>
+%D \stoptypen
+%D
+%D Comment is formatted as follows.
+%D
+%D \starttypen
+%D <!-- comment -->
+%D \stoptypen
+%D
+%D Verbatim code inits purest form is called \type {CDATA} and
+%D is embedded in the following ugly and therefore recognizable
+%D way:
+%D
+%D \starttypen
+%D <![CDATA[
+%D Dit is nogal verbatim !
+%D Dit is nogal verbatim !
+%D Dit is nogal verbatim !
+%D ]]>
+%D \stoptypen
+
+%D The parser is implemented as a multi||step macro. Because
+%D \type {!} and \type {?} should be picked up correctly, we
+%D need to define a few macros in unprotected mode!
+%D
+%D Because \XML\ is defined with some restrictions in mind,
+%D parsing the elements is not that complicated. First we have
+%D to determine if we're dealing with a comment or processing
+%D instruction. We need a bit of grouping because we have to
+%D mess up with catcodes. We probably have to treat a few
+%D more catcode and first character cases. We need to use
+%D \type {\begingroup} here, otherwise we get funny spaces in
+%D math.
+
+\protect
+
+\long\def\doXMLelement#1%
+ {\begingroup % maybe tab and space needs some treatment too: \catcode`\ =10 % \@@space
+ \catcode`\^^M=10
+ \if#1!\let\next \xdoXMLelement \else
+ \if#1?\let\next \ydoXMLelement \else
+ \let\next \zdoXMLelement \fi\fi
+ \next#1}
+
+%D By using a few {\expandafter}'s we can us a \type {\next}
+%D construction. We could speed the first char test up a bit
+%D by using an installer and something \typ {\getvalue
+%D {#1doXMLelement}} (todo).
+
+\long\def\doXMLelement#1%
+ {\begingroup % maybe tab and space needs some treatment too: \catcode`\ =10 % \@@space
+ \catcode`\^^M=10\relax
+ \if#1!\expandafter \xdoXMLelement \else
+ \if#1?\expandafter\expandafter\expandafter \ydoXMLelement \else
+ \expandafter\expandafter\expandafter \zdoXMLelement \fi\fi
+ #1}
+
+%D The (yet experimental) \type {CDATA} parser is implemented
+%D on top of the verbatim environment.
+
+\long\def\xdoXMLelement !#1 % !-- --> or !xyz >
+ {\endgroup
+ \doifelse{#1}{--}
+ {\long\def\nextelement{\gobbleuntil{-->}}}
+ {\doifelse{#1}{[CDATA[}
+ {\long\def\nextelement{\skipfirstverbatimlinefalse
+ \processtaggeddisplayverbatim{]]>}}}
+ {\long\def\nextelement{\gobbleuntil{>}}}}%
+ \nextelement}
+
+%D In our case, processing instructions are only needed if
+%D we want specific \CONTEXT\ support. This may be useful in
+%D applications where the data is generated by an
+%D application. We will implement a \CONTEXT\ code handler
+%D later.
+
+\long\def\ydoXMLelement#1 #2?>% ?target ?>
+ {\endgroup\dodoXMLprocessor{#1}{#2}}
+
+%D The normal elements are handled by \type {\dodoXMLelement}.
+
+\long\def\zdoXMLelement#1>%
+ {\endgroup\dodoXMLelement#1 >}
+
+%D Now we switch to unprotected mode again.
+
+\unprotect
+
+%D The processing instructions handler is implemented as
+%D follows.
+
+\long\def\dodoXMLprocessor#1%
+ {\ifundefined{\@@XMLinstruction:#1}%
+ \let\next\gobbleoneargument
+ \else
+ \def\next{\getvalue{\@@XMLinstruction:#1}}%
+ \fi
+ \next}
+
+\long\def\defineXMLprocessor[#1]#2% watch the ?
+ {\long\setvalue{\@@XMLinstruction:?#1}{#2}}
+
+%D As an example, we implement a \CONTEXT\ code handler:
+
+\defineXMLprocessor[context] {\contextXMLcommand}
+\defineXMLprocessor[context-command]{\contextXMLcommand}
+
+\def\contextXMLcommand#1%
+ {\def\disableXML{\global\let\afterXMLprocessor\empty}%
+ \global\let\afterXMLprocessor\enableXML
+ \setnormalcatcodes\scantokens{#1}\afterXMLprocessor}
+
+\defineXMLprocessor[context-directive]{\contextXMLdirective}
+
+\def\contextXMLdirective#1%
+ {\docontextXMLdirective#1 dummy dummy dummy\end}
+
+\def\docontextXMLdirective#1 #2 #3 #4\end% class var value
+ {\setvalue{\@@XMLvariable:#1:#2}{#3}}
+
+\defineXMLprocessor[context-message]{\contextXMLmessage}
+
+\def\contextXMLmessage#1%
+ {\writestatus{xml}{#1}}
+
+\def\setnormalcatcodes%
+ {\catcode`\!=\@@other \catcode`\?=\@@other
+ \catcode`\&=\@@alignment \catcode`\<=\@@other
+ \catcode`\#=\@@parameter \catcode`\$=\@@mathshift
+ \catcode`\%=\@@comment \catcode`\\=\@@escape
+ \catcode`\^=\@@superscript \catcode`\_=\@@subscript
+ %\catcode`\|=\@@active \catcode`\~=\@@active
+ \catcode`\{=\@@begingroup \catcode`\}=\@@endgroup}
+
+%D Given the previous definition, and given that \ETEX\ is
+%D used, we can now say:
+%D
+%D \starttypen
+%D <?context {\bf Start Of Some \TeX\ Text} ?>
+%D \stoptypen
+%D
+%D A non||\ETEX\ solution is also possible, using buffers,
+%D but for the moment we assume that \ETEX\ is used.
+
+%D Next we will implement the normal element handler.
+
+\let\currentXMLarguments\empty
+\let\currentXMLelement \empty
+
+\newtoks\everyXMLelement
+
+\long\def\dodoXMLelement#1 #2>%
+ {\def\!!stringa{#2}%
+ \def\!!stringb{/ }%
+ \ifx\!!stringa\empty
+ \let\currentXMLarguments\empty
+ \def\currentXMLelement{#1}%
+ \the\everyXMLelement
+ \else\ifx\!!stringa\!!stringb
+ \let\currentXMLarguments\empty
+ \def\currentXMLelement{#1/}%
+ \the\everyXMLelement
+ \else
+ \def\currentXMLelement{#1}%
+ \def\currentXMLarguments{#2}%
+ \the\everyXMLelement
+ %\getXMLarguments\currentXMLelement{#2}%
+ \dogetXMLarguments\currentXMLelement#2>%
+ \fi \fi
+ \executeXMLelement\currentXMLelement}
+
+\def\executeXMLelement#1%
+ {\getvalue{\@@XMLelement:#1}}
+
+\newif\ifXMLrawentities
+
+% \bgroup
+%
+% \catcode`<=\@@active
+%
+% \gdef\defineXMLentity[#1]#2%
+% {\unspaceargument#1\to\ascii
+% \long\setvalue{\@@XMLelement:ent:\@EA\firstofoneargument\ascii/}{#2}}
+%
+% \gdef\doXMLentity#1;%
+% {\ifXMLrawentities#1\else\executeXMLentity{#1}\fi}
+%
+% \gdef\executeXMLentity#1%
+% {<ent:#1/>}
+%
+% \gdef\getXMLentity#1%
+% {\getvalue{\@@XMLelement:ent:#1/}}
+%
+% \gdef\doifXMLentityelse#1#2#3%
+% {\ifundefined{\@@XMLelement:ent:#1/}#3\else#2\fi}
+%
+% \egroup
+
+\gdef\defineXMLentity[#1]#2%
+ {\unspaceargument#1\to\ascii
+ \long\setvalue{\@@XMLentity:\@EA\firstofoneargument\ascii}{#2}}
+
+% we need to be able to do:
+%
+% \defineXMLentity[amp] {\FunnyAmp} \def\FunnyAmp#1;{\getXMLentity{#1}}
+%
+% \defineXMLentity [pound] {(why not use euro's?)}
+%
+% \startXMLdata
+% test &amp;pound; test
+% \stopXMLdata
+%
+% so we need an ifless implementation of:
+
+\gdef\doXMLentity#1;%
+ {\ifXMLrawentities
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\executeXMLentity
+ \fi{#1}}
+
+\def\executeXMLentity#1% internal ! ! !
+ {\getXMLentity{#1}}
+
+\def\expandedXMLentity#1%
+ {\getvalue{\@@XMLentity:#1}}
+
+\unexpanded\def\getXMLentity#1%
+ {\getvalue{\@@XMLentity:#1}}
+
+\gdef\doifXMLentityelse#1#2#3%
+ {\ifundefined{\@@XMLentity:#1}#3\else#2\fi}
+
+% \long\def\getXMLarguments#1#2%
+% {\dogetXMLarguments{#1}#2>}
+%
+% \long\def\dogetXMLarguments#1%
+% {\XMLtoks\emptytoks
+% \def\@@XMLclass{#1}%
+% \let\dodoparseXMLarguments\doparseXMLarguments
+% \doparseXMLarguments}
+%
+% \def\dosetXMLargument#1%
+% {\setvalue{\@@XMLvariable:\@@XMLclass:\@@XMLname}{#1}%
+% %\message{[\@@XMLname=#1]}%
+% \let\dodoparseXMLarguments\doparseXMLarguments
+% \dodoparseXMLarguments}
+
+% see \defineXML... commands:
+%
+% [key=val] => \presetXMLarguments{element} => default key/vals
+% [blabla] => \theXMLarguments{blabla} => user key/vals
+% [blabla] [key=val] => \presetXMLarguments{element} => default key/vals
+% \theXMLarguments{blabla} => user key/vals
+%
+% <element key="val"> stored in case of [blabla] else set as \XMLpar
+%
+% see m-steps for an example of usage
+
+\long\def\getXMLarguments#1#2%
+ {\dogetXMLarguments{#1}#2>}
+
+\long\def\dogetXMLarguments#1%
+ {\XMLtoks\emptytoks
+ \ifcsname\@@XMLmap:#1\endcsname
+ \let\dosetXMLargument\dosetXMLargumentB
+ \else
+ \def\@@XMLclass{#1}%
+ \let\dosetXMLargument\dosetXMLargumentA
+ \fi
+ \let\dodoparseXMLarguments\doparseXMLarguments
+ \doparseXMLarguments}
+
+\def\dosetXMLargumentA#1%
+ {\setvalue{\@@XMLvariable:\@@XMLclass:\@@XMLname}{#1}%
+ \let\dodoparseXMLarguments\doparseXMLarguments
+ %\message{[\@@XMLclass][\@@XMLname=#1]}\wait
+ \dodoparseXMLarguments}
+
+\def\dosetXMLargumentB#1%
+ {\setevalue{\@@XMLmap:\@@XMLmapmap}%
+ {\@EA\ifx\csname\@@XMLmap:\@@XMLmapmap\endcsname\empty\else
+ \csname\@@XMLmap:\@@XMLmapmap\endcsname,%
+ \fi
+ \@@XMLname=#1}%
+ \let\dodoparseXMLarguments\doparseXMLarguments
+ %\message{[\@@XMLprefix][\@@XMLname=#1]}\wait
+ \dodoparseXMLarguments}
+
+\appendtoks
+ \resetXMLarguments\currentXMLelement
+\to \everyXMLelement
+
+\def\resetXMLarguments#1%
+ {\ifcsname\@@XMLmap:#1\endcsname
+ \@EA\let\@EA\@@XMLmapmap\csname\@@XMLmap:#1\endcsname
+ \@EA\let\csname\@@XMLmap:\@@XMLmapmap\endcsname\empty
+ \fi}
+
+\def\theXMLarguments#1%
+ {\ifcsname\@@XMLmap:#1\endcsname\csname\@@XMLmap:#1\endcsname\fi}
+
+\long\def\doparseXMLarguments#1% space goes ok
+ {\if#1>%
+ \let\dodoparseXMLarguments\empty
+ \else\if#1=%
+ \edef\@@XMLname{\the\XMLtoks}%
+ \XMLtoks\emptytoks
+ \else\if#1"%
+ \let\dodoparseXMLarguments\dodoparseXMLargumentsD
+ \else\if#1'%
+ \let\dodoparseXMLarguments\dodoparseXMLargumentsS
+ \else\if#1/%
+ \edef\currentXMLelement{\currentXMLelement/}%
+ \else
+ \@EA\XMLtoks\@EA{\the\XMLtoks#1}%
+ \fi\fi\fi\fi\fi
+ \dodoparseXMLarguments}
+
+\def\dodoparseXMLargumentsD#1"{\dosetXMLargument{#1}}
+\def\dodoparseXMLargumentsS#1'{\dosetXMLargument{#1}}
+
+%D The previous macros were the basic parser and their working
+%D is left to the imagination of the reader. These macros
+%D will be improved.
+
+\bgroup
+
+\catcode`<=\@@active
+
+\long\gdef\dododefineXMLsingular#1#2%
+ {\long\setvalue{\@@XMLelement:#1/}{#2}}
+
+\long\gdef\dododefineXMLcommand#1#2%
+ {\long\setvalue{\@@XMLelement:#1/}{#2}%
+ \long\setvalue{\@@XMLelement:#1}{#2}}
+
+\long\gdef\dododefineXMLgrouped#1#2%
+ {\long\setvalue{\@@XMLelement:#1}{\groupedcommand{#2}{}\bgroup}%
+ \long\setvalue{\@@XMLelement:/#1}{\egroup}}
+
+\long\gdef\dododefineXMLargument#1#2% watch the {} around ##1
+ {\long\setvalue{\@@XMLelement:#1/}{#2{}}%
+ \long\setvalue{\@@XMLelement:#1}##1</#1>{#2{##1}}}
+
+\long\gdef\dododefineXMLignore#1%
+ {\long\setvalue{\@@XMLelement:#1/}{}%
+ \long\setvalue{\@@XMLelement:#1}##1</#1>{}}
+
+\long\gdef\dododefineXMLpickup#1#2#3%
+ {\long\setvalue{\@@XMLelement:#1/}{#2#3}%
+ \long\setvalue{\@@XMLelement:#1}##1</#1>{#2##1#3}}
+
+\long\gdef\dododefineXMLenvironment#1#2#3%
+ {\long\setvalue{\@@XMLelement:#1/}{#2#3}% % genereert evt relax
+ \long\setvalue{\@@XMLelement:#1}{#2}%
+ \long\setvalue{\@@XMLelement:/#1}{#3}}
+
+\long\gdef\dododefineXMLpush#1%
+ {\long\setvalue{\@@XMLelement:#1/}{\long\setvalue{\@@XMLdata:#1}{}}%
+ \long\setvalue{\@@XMLelement:#1}##1</#1>{\long\setvalue{\@@XMLdata:#1}{##1}}}
+
+\long\gdef\dododefineXMLenvironmentpush#1#2#3%
+ {\long\setvalue{\@@XMLelement:#1/}{#2\long\setvalue{\@@XMLdata:#1}{}#3}%
+ \long\setvalue{\@@XMLelement:#1}##1</#1>{#2\long\setvalue{\@@XMLdata:#1}{##1}#3}}
+
+\long\gdef\dododefineXMLprocess#1%
+ {\long\setvalue{\@@XMLelement:#1/}{}%
+ \long\setvalue{\@@XMLelement:#1}{}%
+ \long\setvalue{\@@XMLelement:/#1}{}}
+
+\long\gdef\dododefineXMLnestedenvironment#1#2#3%
+ {\long\setvalue{\@@XMLelement:#1}{\getXMLgroupedenvironment{#1}{#2}{#3}}}
+
+\long\gdef\dododefineXMLnestedargument#1#2%
+ {\long\setvalue{\@@XMLelement:#1}{\getXMLgroupedargument{#1}{#2}}}
+
+\egroup
+
+%D The high level definition macros.
+
+\def\defineXMLsingular {\dotripleempty\dodefineXMLsingular}
+\def\defineXMLcommand {\dotripleempty\dodefineXMLcommand}
+\def\defineXMLgrouped {\dotripleempty\dodefineXMLgrouped}
+\def\defineXMLargument {\dotripleempty\dodefineXMLargument}
+\def\defineXMLignore {\dotripleempty\dodefineXMLignore}
+\def\defineXMLpickup {\dotripleempty\dodefineXMLpickup}
+\def\defineXMLenvironment {\dotripleempty\dodefineXMLenvironment}
+\def\defineXMLpush {\dotripleempty\dodefineXMLpush}
+\def\defineXMLenvironmentpush{\dotripleempty\dodefineXMLenvironmentpush}
+\def\defineXMLprocess {\dotripleempty\dodefineXMLprocess}
+
+% goes for all types
+
+\def\defineXMLnested {\dotripleempty\dodefineXMLnestedenvironment}
+\def\defineXMLnestedenvironment{\dotripleempty\dodefineXMLnestedenvironment}
+\def\defineXMLnestedargument {\dotripleempty\dodefineXMLnestedargument}
+
+\long\def\dodefineXMLsingular[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLsingular{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLcommand[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLcommand{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLgrouped[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLgrouped{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLargument[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLargument{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLignore[#1][#2][#3]%
+ {\defineXMLmethod\dododefineXMLignore{#1}{#2}{#3}{}{}}
+
+\long\def\dodefineXMLpickup[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLpickup{#1}{#2}{#3}{#4}{#5}}
+
+\long\def\dodefineXMLenvironment[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLenvironment{#1}{#2}{#3}{#4}{#5}}
+
+\long\def\dodefineXMLpush[#1][#2][#3]%
+ {\defineXMLmethod\dododefineXMLpush{#1}{#2}{#3}{}{}}
+
+\long\def\dodefineXMLenvironmentpush[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLenvironmentpush{#1}{#2}{#3}{#4}{#5}}
+
+\long\def\dodefineXMLprocess[#1][#2][#3]%
+ {\defineXMLmethod\dododefineXMLprocess{#1}{#2}{#3}{}{}}
+
+\long\def\dodefineXMLnestedenvironment[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLnestedenvironment{#1}{#2}{#3}{#4}{#5}}
+
+\long\def\dodefineXMLnestedargument[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLnestedargument{#1}{#2}{#3}{#4}{}}
+
+% [key=val] => \presetXMLarguments{element} => default key/vals
+% [blabla] => \theXMLarguments{blabla} => user key/vals
+% [blabla] [key=val] => \presetXMLarguments{element} => default key/vals
+% \theXMLarguments{blabla} => user key/vals
+
+\long\def\defineXMLmethod#1#2#3#4#5#6% command element [map] [parlst] begin end
+ {\ifsecondargument
+ \setXMLarguments{#2}{#3}{#4}%
+ \fi
+ \ifignoreXMLcase
+ \lowercasestring#2\to\ascii \@EA#1\@EA{\ascii}{#5}{#6}%
+ \uppercasestring#2\to\ascii \@EA#1\@EA{\ascii}{#5}{#6}%
+ \else
+ #1{#2}{#5}{#6}%
+ \fi}
+
+\def\setXMLarguments#1#2#3% element [tag] settings
+ {\doifassignmentelse{#2}
+ {\setvalue{\@@XMLpars:#1}{\getrawparameters[\@@XMLvariable:#1:][#2]}}
+ {\setvalue{\@@XMLmap :#1}{#2}% later we can init vars by this name
+ \doifsomething{#3}{\setvalue{\@@XMLpars:#1}{\getrawparameters[#2][#3]}}}}
+
+\def\presetXMLarguments#1%
+ {\getvalue{\@@XMLpars:#1}}
+
+\prependtoks
+ \presetXMLarguments\currentXMLelement
+\to \everyXMLelement
+
+\def\doifXMLdataelse#1#2#3% % \relax too, so no etex
+% wrong
+% {\expandafter\ifx\csname\@@XMLdata:#1\endcsname\relax
+% slow
+% {\ifundefined{\@@XMLdata:#1}%
+% etex
+ {\unless\ifcsname\@@XMLdata:#1\endcsname
+ #3%
+ \else\expandafter\ifx\csname\@@XMLdata:#1\endcsname\empty
+ #3%
+ \else\expandafter\ifx\csname\@@XMLdata:#1\endcsname\relax
+ #3%
+ \else
+ #2%
+ \fi\fi\fi}
+
+\def\XMLpop#1% one level
+% wrong
+% {\expandafter\ifx\csname\@@XMLdata:#1\endcsname\relax\else
+% \csname\@@XMLdata:#1\endcsname
+% \fi}
+% slow, hm was not commented
+% {\ifundefined{\@@XMLdata:#1}\else\getvalue{\@@XMLdata:#1}\fi}
+% etex
+ {\ifcsname\@@XMLdata:#1\endcsname\csname\@@XMLdata:#1\endcsname\fi}
+
+\def\XMLpopdata#1% see m-steps for usage
+ {\unless\ifcsname\@@XMLdata:#1\endcsname
+ \else\expandafter\ifx\csname\@@XMLdata:#1\endcsname\empty
+ \else\expandafter\ifx\csname\@@XMLdata:#1\endcsname\relax
+ \else
+ \@EA\@EA\@EA\XMLdata\@EA\@EA\@EA{\csname\@@XMLdata:#1\endcsname}%
+ \fi\fi\fi}
+
+\def\XMLappend#1#2%
+ {\edef\!!stringa{\@@XMLdata:#1}%
+ \doifXMLdataelse{#1}%
+ {\@EA\@EA\@EA\setvalue\@EA\@EA\@EA\!!stringa\@EA\@EA\@EA
+ {\csname\!!stringa\endcsname#2}}
+ {\setvalue\!!stringa{#2}}}
+
+\def\XMLprepend#1#2%
+ {\edef\!!stringa{\@@XMLdata:#1}%
+ \doifXMLdataelse{#1}%
+ {\@EA\@EA\@EA\setvalue\@EA\@EA\@EA\!!stringa\@EA\@EA\@EA
+ {#2\csname\!!stringa\endcsname}}
+ {\setvalue\!!stringa{#2}}}
+
+\def\XMLerase#1%
+ {\letvalue{\@@XMLdata:#1}\empty}
+
+\def\XMLassign#1%
+ {\setvalue{\@@XMLdata:#1}}
+
+\def\defXMLstring#1#2%
+% {\@EA\convertcommand\csname\@@XMLdata:#2\endcsname\to#1}
+ {\bgroup
+ \let\getXMLentity\firstofoneargument
+ \xdef\@@XML@@string{\csname\@@XMLdata:#2\endcsname}%
+ \egroup
+ \@EA\convertcommand\@@XML@@string\to#1}
+
+\def\XMLshow#1%
+ {\showvalue{\@@XMLdata:#1\endcsname}}
+
+\def\XMLunspace#1%
+ {\ifcsname\@@XMLdata:#1\endcsname
+ \setevalue{\@@XMLdata:#1}%
+ {\@EA\@EA\@EA\dounspaced\csname\@@XMLdata:#1\endcsname\end}%
+ \fi}
+
+\def\defXMLlowerclean#1% lowercase ! evt tzt upper too
+ {\bgroup
+ \lccode`\#=32\lccode`\$=32\lccode`\%=32\lccode`\\=32\lccode`\^=32
+ \lccode`\_=32\lccode`\{=32\lccode`\}=32\lccode`\|=32\lccode`\~=32
+ \@EA\lowercase\@EA{\@EA\xdef\@EA#1\@EA{#1}}%
+ \egroup}
+
+\def\processXMLparelse#1#2#3#4%
+ {\processaction
+ [\XMLpar{#1}{#2}{}]
+ [#3,\s!unknown=>{#4},\s!default={#4}]}
+
+%D We can pick up key|/|value pairs, but we still need a way
+%D to process these.
+
+\def\mapXMLvalue#1#2#3% td align center -> middle
+ {\setvalue{\@@XMLvalue:#1:#2:#3}}
+
+% \def\XMLvar#1#2#3% td align center
+% {\ifundefined{\@@XMLvariable:#1:#2}%
+% \XMLval{#1}{#2}{#3}%
+% \else
+% \XMLval{#1}{#2}{\getvalue{\@@XMLvariable:#1:#2}}%
+% \fi}
+%
+% \def\XMLval#1#2#3%
+% {\ifundefined{\@@XMLvalue:#1:#2}%
+% #3%
+% \else
+% \getvalue{\@@XMLvalue:#1:#2}%
+% \fi}
+%
+% \def\XMLpar#1#2#3%
+% {\ifundefined{\@@XMLvariable:#1:#2}%
+% #3%
+% \else
+% \getvalue{\@@XMLvariable:#1:#2}%
+% \fi}
+%
+% speedup
+
+\def\XMLvar#1#2#3% td align center
+ {\ifcsname\@@XMLvariable:#1:#2\endcsname
+ \XMLval{#1}{#2}{\csname\@@XMLvariable:#1:#2\endcsname}%
+ \else
+ \XMLval{#1}{#2}{#3}% evt inline code
+ \fi}
+
+\def\XMLval#1#2#3%
+ {\ifcsname\@@XMLvalue:#1:#2\endcsname
+ \csname\@@XMLvalue:#1:#2\endcsname
+ \else
+ #3%
+ \fi}
+
+\def\XMLpar#1#2#3%
+ {\ifcsname\@@XMLvariable:#1:#2\endcsname
+ \csname\@@XMLvariable:#1:#2\endcsname
+ \else
+ #3%
+ \fi}
+
+% so far for speedup
+
+\defineXMLsingular [begingroup] {\begingroup}
+\defineXMLsingular [endgroup] {\endgroup}
+
+\def\XMLstr#1%
+ {{\enableXML\scantokens{#1}\unskip}}
+
+\def\XMLstr#1% test
+ {\scantokens{\begingroup\enableXML#1<endgroup/>}}
+
+%\def\XMLstrpar#1#2#3%
+% {{\enableXML
+% \ifundefined{\@@XMLvariable:#1:#2}%
+% \scantokens{#3}%
+% \else
+% \scantokens\@EA\@EA\@EA
+% {\csname\@@XMLvariable:#1:#2\endcsname}\unskip
+% \fi}}
+
+\def\XMLstrpar#1#2#3% test
+ {\ifundefined{\@@XMLvariable:#1:#2}%
+ \scantokens{\begingroup\enableXML#3<endgroup/>}%
+ \else
+ \scantokens\@EA\@EA\@EA{\@EA\begingroup\@EA\enableXML
+ \csname\@@XMLvariable:#1:#2\endcsname<endgroup/>}%
+ \fi}
+
+\def\doifXMLvarelse#1#2#3#4% geen etex, \relax too
+ {\expandafter\ifx\csname\@@XMLvariable:#1:#2\endcsname\relax#4\else
+ \expandafter\ifx\csname\@@XMLvariable:#1:#2\endcsname\empty#4\else#3\fi\fi}
+
+\def\doifXMLvalelse#1#2#3#4% geen etex, \relax too
+ {\expandafter\ifx\csname\@@XMLvalue:#1:#2\endcsname\relax#4\else
+ \expandafter\ifx\csname\@@XMLvalue:#1:#2\endcsname\empty#4\else#3\fi\fi}
+
+\let\doifXMLparelse\doifXMLvarelse
+
+\def\dogotoXML%
+ {\ifx\nexttoken<%
+ \expandafter\nexttoken
+ \else
+ \expandafter\gotoXML
+ \fi}
+
+\def\gotoXML%
+ {\afterassignment\dogotoXML\let\nexttoken=}
+
+%D Saves tokens and typing.
+
+\def\XMLownvar {\XMLvar \currentXMLelement}
+\def\XMLownval {\XMLval \currentXMLelement}
+\def\XMLownpar {\XMLpar \currentXMLelement}
+\def\XMLownstrpar {\XMLstrpar \currentXMLelement}
+\def\doifXMLownvarelse{\doifXMLvarelse\currentXMLelement}
+\def\doifXMLownvalelse{\doifXMLvalelse\currentXMLelement}
+\def\doifXMLownparelse{\doifXMLparelse\currentXMLelement}
+
+%D
+
+\long\def\startXMLcode[#1] #2 \stopXMLcode
+ {\setgvalue{\@@XMLcode:#1}{\startXMLdata#2\stopXMLdata}}
+
+\def\getXMLcode[#1]% \expandXMLcode
+ {\getvalue{\@@XMLcode:#1}}
+
+% \long\def\startXMLdata#1\stopXMLdata%
+% {\begingroup\enableXML\scantokens{#1}\endgroup}
+%
+% \defineXMLentity[tex-backslash] {\catchXMLpar}
+%
+% \def\catchXMLpar#1#2#3
+% {\if#1p\if#2a\if#3r\ifmmode\else\endgraf\fi
+% \else\texescape\fi\else\texescape\fi\else\texescape\fi}
+
+\long\def\startXMLdata
+ {\begingroup
+ \catcode`\^^I=\@@space
+ \catcode`\^^M=\@@space
+ \catcode`\^^L=\@@space
+ \dostartXMLdata}
+
+% \long\def\dostartXMLdata#1\stopXMLdata
+% {\enableXML\scantokens{#1}\endgroup}
+
+\long\def\dostartXMLdata#1\stopXMLdata
+ {\enableXML\scantokens{#1}\ifhmode\unskip\unskip\fi\endgroup}
+
+\unexpanded\def\XMLdata#1% % \unexpanded added 22/5/2001
+ {\begingroup
+ \enableXML\scantokens{#1}\ifhmode\unskip\unskip\fi
+ \endgroup}
+
+\unexpanded\def\XMLdata#1% % grouping changed 20/5/2001
+ {\scantokens{\begingroup\enableXML#1<endgroup/>}}
+
+%D
+
+\def\bXMLs{\ifignoreXMLspaces\ignorespaces\fi}
+\def\eXMLs{\ifignoreXMLspaces\ifhmode\unskip\fi\fi}
+
+\protect
+
+% \defineXMLcommand{placeindex/}
+% {\placeindex[criterium=all]}
+%
+% \defineXMLargument{index}
+% {\index[\XMLvar{index}{key}{}]}
+
+%D Here we implement the handling of preformatted code.
+
+\unprotect
+
+\def\startXMLpreformatted#1%
+ {\startpacked
+ #1%
+ \fixedXMLfonttrue
+ \obeylines
+ \obeyspaces
+ \setbox\scratchbox=\hbox{x}%
+ \edef\obeyedspace{\noindent\noexpand\kern\the\wd\scratchbox}}
+
+\def\stopXMLpreformatted#1%
+ {\stoppacked}
+
+%D
+
+\def\XMLinput{\enableXML\input} \global\let\inputXML\XMLinput
+
+% options
+
+\def\processXMLfile #1{\enableXML\processfile{#1}}
+\def\processXMLfilegrouped#1{{\enableXML\processfile{#1}\relax\ifmmode\else\par\fi}}
+
+% partially defined here
+
+\fetchruntimecommand\showXMLfile {\f!xtagprefix\s!run}
+\fetchruntimecommand\showXMLbuffer{\f!xtagprefix\s!run}
+
+\fetchruntimecommand\showXMLtxt {\f!xtagprefix\s!run}
+\fetchruntimecommand\showXMLpar {\f!xtagprefix\s!run}
+\fetchruntimecommand\showXMLlin {\f!xtagprefix\s!run}
+\fetchruntimecommand\showXMLwrd {\f!xtagprefix\s!run}
+\fetchruntimecommand\showXMLemp {\f!xtagprefix\s!run}
+
+%D \type
+%D {processXMLbuffer}
+%D
+%D For illustrative purposes, we need to be able to reuse
+%D definitions, which is why we implement a buffer processor
+%D here. The macro \type {\processXMLbuffer} behaves like
+%D any buffer processor.
+
+\def\processXMLbuffer%
+ {\dosingleempty\doprocessXMLbuffer}
+
+\def\doprocessXMLbuffer[#1]%
+ {\doifelsenothing{#1}
+ {\doprocessXMLbuffer[\jobname]}
+ {\begingroup
+ \def\dodoprocessXMLbuffer##1%
+ {\enableXML\processXMLfile{\TEXbufferfile{##1}}}%
+ \processcommalist[#1]\dodoprocessXMLbuffer
+ \endgroup}}
+
+%D Loading specific modules takes place with \type
+%D {\useXMLfilters}.
+
+\def\useXMLfilter[#1]%
+ {\processcommalist[#1]\douseXMLfilter}
+
+\def\douseXMLfilter#1%
+ {\doifundefined{\c!file\f!xtagprefix#1}
+ {\setvalue{\c!file\f!xtagprefix#1}{}%
+ \makeshortfilename[\f!xtagprefix#1]%
+ \writestatus{xml}{loading module #1}% will be \showmessage
+ \startreadingfile
+ \readsysfile{\shortfilename}{}{}%
+ \stopreadingfile}}
+
+%D Temporarily here.
+
+\newtoks\groupedtoks
+
+\bgroup
+
+\catcode`\<=\@@active
+
+\long\unexpanded\gdef\getXMLgrouped#1#2#3%
+ {\groupedtoks\emptytoks
+ \convertargument<#1>\to\xxascii
+ \convertargument<#1 \to\yyascii
+ \newcounter\groupedlevel
+ \long\def\dogetgrouped##1</#1>%
+ {\appendtoks##1\to\groupedtoks
+ \convertargument##1\to\ascii
+ \doloop
+ {\@EA\@EA\@EA\aftersplitstring\@EA\ascii\@EA\at\xxascii\to\ascii
+ \ifx\ascii\empty
+ \exitloop
+ \else
+ \increment\groupedlevel
+ \fi}%
+ \convertargument##1\to\ascii
+ \doloop
+ {\@EA\@EA\@EA\aftersplitstring\@EA\ascii\@EA\at\yyascii\to\ascii
+ \ifx\ascii\empty
+ \exitloop
+ \else
+ \increment\groupedlevel
+ \fi}%
+ \ifnum\groupedlevel>0
+ \decrement\groupedlevel
+ \appendtoks</#1>\to\groupedtoks
+ \else
+ \edef\dogetgrouped{\noexpand#2\the\groupedtoks\noexpand#3}%
+ \fi
+ \dogetgrouped}%
+ \dogetgrouped}
+
+%D Cleaner but hardly faster unless big strings are passed.
+
+\long\gdef\docountXMLgrouped#1\end#2\end
+ {\long\def\dosplitstring##1#2##2@@##3\end%
+ {\def\ascii{##2}%
+ \ifx\ascii\empty \else
+ \advance\scratchcounter 1
+ \dosplitstring##2@@#2@@\end
+ \fi}%
+ \dosplitstring#1@@#2@@\end}
+
+\long\unexpanded\gdef\getXMLgrouped#1#2#3%
+ {\groupedtoks\emptytoks
+ \scratchcounter=0
+ \long\def\dogetgrouped##1</#1>%
+ {\appendtoks##1\to\groupedtoks
+ \docountXMLgrouped##1\end<#1>\end
+ \docountXMLgrouped##1\end<#1 \end
+ \ifcase\scratchcounter
+ \def\dogetgrouped{\@EA#2\the\groupedtoks#3}%
+ \else
+ \advance\scratchcounter -1
+ \appendtoks</#1>\to\groupedtoks
+ \fi
+ \dogetgrouped}%
+ \dogetgrouped}
+
+%D More versatile.
+
+\long\unexpanded\gdef\getXMLgroupedenvironment#1#2#3%
+ {\def\dodogetgrouped{\@EA#2\the\groupedtoks#3}%
+ \getXMLgrouped{#1}}
+
+\long\unexpanded\gdef\getXMLgroupedargument#1#2%
+ {\def\dodogetgrouped{\@EA#2\@EA{\the\groupedtoks}}%
+ \getXMLgrouped{#1}}
+
+\long\unexpanded\gdef\getXMLgrouped#1%
+ {\groupedtoks\emptytoks
+ \scratchcounter=0
+ \long\def\dogetgrouped##1</#1>%
+ {\appendtoks##1\to\groupedtoks
+ \docountXMLgrouped##1\end<#1>\end
+ \docountXMLgrouped##1\end<#1 \end
+ \ifcase\scratchcounter
+ \let\dogetgrouped\dodogetgrouped
+ \else
+ \advance\scratchcounter -1
+ \appendtoks</#1>\to\groupedtoks
+ \fi
+ \dogetgrouped}%
+ \dogetgrouped}
+
+\egroup
+
+% {pre}{pos}{before}{after}
+%
+%\unexpanded\def\getgrouped#1#2#3#4%
+% {\groupedtoks\emptytoks
+% \convertargument#1\to\xxascii
+% \newcounter\groupedlevel
+% \def\dogetgrouped##1#2%
+% {\appendtoks##1\to\groupedtoks
+% \convertargument##1\to\ascii
+% \doloop
+% {\@EA\@EA\@EA\aftersplitstring\@EA\ascii\@EA\at\xxascii\to\ascii
+% \ifx\ascii\empty
+% \exitloop
+% \else
+% \increment\groupedlevel
+% \fi}%
+% \ifnum\groupedlevel>0
+% \decrement\groupedlevel
+% \appendtoks#2\to\groupedtoks
+% \else
+% \edef\dogetgrouped{\noexpand#3\the\groupedtoks\noexpand#4}%
+% \fi
+% \dogetgrouped}%
+% \dogetgrouped}
+
+% interesting and fully expandable
+
+\def\XMLifequalelse#1#2#3#4#5%
+ {\ifundefined{\@@XMLvariable:#1:#2}%
+ #5%
+ \else
+ \@EA\@EA\@EA\@@ifequal\csname\@@XMLvariable:#1:#2\endcsname
+ \relax\@@and#3\relax\@@then#4\@@else#5\@@fi
+ \fi}
+
+\def\expifequalelse#1#2#3#4%
+ {\@@ifequal#1\relax\relax\@@and#2\relax\relax\@@then#3\@@else#4\@@fi}
+
+\def\@@ifequal#1#2\@@and#3#4\@@then#5\@@else#6\@@fi%
+ {\ifx#1\relax
+ \ifx#3\relax#5\else#6\fi
+ \else
+ \ifx#3\relax#6\else\@@ifequal#2\@@and#4\@@then#5\@@else#6\@@fi\fi
+ \fi}
+
+\protect \endinput