diff options
author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2016-01-12 17:15:07 +0100 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2016-01-12 17:15:07 +0100 |
commit | 8d8d528d2ad52599f11250cfc567fea4f37f2a8b (patch) | |
tree | 94286bc131ef7d994f9432febaf03fe23d10eef8 /tex/context/base/syst-ext.mkii | |
parent | f5aed2e51223c36c84c5f25a6cad238b2af59087 (diff) | |
download | context-8d8d528d2ad52599f11250cfc567fea4f37f2a8b.tar.gz |
2016-01-12 16:26:00
Diffstat (limited to 'tex/context/base/syst-ext.mkii')
-rw-r--r-- | tex/context/base/syst-ext.mkii | 5025 |
1 files changed, 0 insertions, 5025 deletions
diff --git a/tex/context/base/syst-ext.mkii b/tex/context/base/syst-ext.mkii deleted file mode 100644 index 39f4145f2..000000000 --- a/tex/context/base/syst-ext.mkii +++ /dev/null @@ -1,5025 +0,0 @@ -%D \module -%D [ file=syst-ext, -%D version=1995.10.10, -%D title=\CONTEXT\ System Macros, -%D subtitle=Extras, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright={PRAGMA ADE \& \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. - -\writestatus{loading}{ConTeXt System Macros / Extras} - -%D In this second system module, we continue the definition of -%D some handy commands. - -\unprotect - -%D \macros -%D {rawgetparameters} -%D -%D A raw and dirty alternative for \type {\getparameters}; no -%D checking is done! - -% \def\rawgetparameters[#1][#2]% scheelt 5\% -% {\def\rawparameterprefix{#1}% -% \expandafter\rawsetparameter#2,]=,} - -\def\rawsetparameter#1=#2,% - {\if]#1\else - \expandafter\def\csname\rawparameterprefix#1\endcsname{#2}% - \expandafter\rawsetparameter - \fi} - -% the next one handles empty #1 okay: - -\def\rawgetparameters[#1][#2% some 5-10% faster - {\ifx#2]% test is needed, else bomb on [#1][] - \expandafter\gobbleoneargument - \else - \def\rawparameterprefix{#1}% - \expandafter\dorawgetparameters - \fi#2} - -\def\dorawgetparameters#1]% - {\expandafter\rawsetparameter#1,]=,} - -%D \macros -%D {doglobal, -%D redoglobal,dodoglobal,resetglobal} -%D -%D The two macros \type {\redoglobal} and \type{\dodoglobal} are -%D used in this and some other modules to enforce a user -%D specified \type {\doglobal} action. The last and often only -%D global assignment in a macro is done with -%D \type {\dodoglobal}, but all preceding ones with -%D \type {\redoglobal}. When using only alternatives, one can -%D reset this mechanism with \type {\resetglobal}. - -\def\doglobal - {\let\redoglobal\global - \def\dodoglobal{\resetglobal\global}} - -\def\resetglobal - {\let\redoglobal\relax - \let\dodoglobal\relax} - -\resetglobal - -%D New: - -\def\doglobal - {\ifx\redoglobal\relax - \let\redoglobal\global - \let\dodoglobal\@@dodoglobal - %\else - % \writestatus{system}{global not reset, warn me!}% - \fi} - -\def\@@dodoglobal - {\resetglobal\global} - -\def\saveglobal - {\let\@@dodoglobal\dodoglobal - \let\@@redoglobal\redoglobal} - -\def\restoreglobal - {\let\redoglobal\@@redoglobal - \let\dodoglobal\@@dodoglobal} - -%D A very useful application of this macro is \type {\newif}, -%D \TEX's fake boolean type. Not being a primitive, -%D \type {\global} hopelessly fails here. But a slight -%D adaption of Knuth's original macro permits: -%D -%D \starttyping -%D \doglobal\newif\iftest -%D \stoptyping -%D -%D Of course one can still say: -%D -%D \starttyping -%D \global\testtrue -%D \global\testfalse -%D \stoptyping -%D -%D Apart from the prefixes, a few more \type{\expandafters} -%D are needed: - -\def\newif#1% - {\scratchcounter\escapechar - \escapechar\minusone - \expandafter\expandafter\expandafter - \redoglobal\expandafter\expandafter\expandafter - \edef\@if#1{true}{\let\noexpand#1\noexpand\iftrue}% - \expandafter\expandafter\expandafter - \redoglobal\expandafter\expandafter\expandafter - \edef\@if#1{false}{\let\noexpand#1\noexpand\iffalse}% - \dodoglobal\@if#1{false}% - \escapechar\scratchcounter} - -%D Also: - -\def\define#1% - {\ifx#1\undefined - \expandafter\long\expandafter\def - \else - \message{[\noexpand#1is already defined]}% - \expandafter\long\expandafter\def\expandafter\gobbleddefinition - \fi#1} - -\def\redefine#1% - {\ifx#1\undefined\else - \message{[\noexpand#1is redefined]}% - \fi - \long\def#1} - -% \define\hans{hans} -% \redefine\hans{hans} -% \define\hans#1[]#2#3{hans} - -%D The next variant fits nicely in the setups syntax: -%D -%D \starttyping -%D \starttexdefinition bagger [#1] #2 -%D oeps -%D #1 -%D oeps -%D \stoptexdefinition -%D -%D \bagger [a] {b} -%D \stoptyping - -\bgroup \obeylines - -\gdef\starttexdefinition% - {\bgroup% - \obeylines% - \dostarttexdefinition} - -\gdef\dostarttexdefinition #1 - {\catcode13=\@@ignore% - \doifinstringelse\letterhash{\detokenize{#1}}\dodostarttexdefinition\nonostarttexdefinition#1 - } - -\long\gdef\dodostarttexdefinition#1 #2 - {\dododostarttexdefinition{#1}{#2}} - -\long\gdef\dododostarttexdefinition#1#2#3\stoptexdefinition% - {\egroup% - \long\setvalue{#1}#2{#3}} - -\long\gdef\nonostarttexdefinition#1 - {\nononostarttexdefinition{#1}{}} - -\long\gdef\nononostarttexdefinition#1#2#3\stoptexdefinition% - {\egroup% - \long\setvalue{#1}{#3}} - -\egroup - -%D \macros -%D {newcounter, -%D increment,decrement} -%D -%D Unfortunately the number of \COUNTERS\ in \TEX\ is limited, -%D but fortunately we can store numbers in a macro. We can -%D increment such pseudo \COUNTERS\ with \type{\increment}. -%D -%D \starttyping -%D \increment(\counter,20) -%D \increment(\counter,-4) -%D \increment(\counter) -%D \increment\counter -%D \stoptyping -%D -%D After this sequence of commands, the value of -%D \type{\counter} is 20, 16, 17 and~18. Of course there is -%D also the complementary command \type{\decrement}. -%D -%D Global assignments are possible too, using \type{\doglobal}: -%D -%D \starttyping -%D \doglobal\increment\counter -%D \stoptyping -%D -%D When \type{\counter} is undefined, it's value is initialized -%D at~0. It is nevertheless better to define a \COUNTER\ -%D explicitly. One reason could be that the \COUNTER\ can be -%D part of a test with \type{\ifnum} and this conditional does -%D not accept undefined macro's. The \COUNTER\ in our example -%D can for instance be defined with: -%D -%D \starttyping -%D \newcounter\counter -%D \stoptyping -%D -%D The command \type{\newcounter} must not be confused with -%D \type{\newcount}! Of course this mechanism is much slower -%D than using \TEX's \COUNTERS\ directly. In practice -%D \COUNTERS\ (and therefore our pseudo counters too) are -%D seldom the bottleneck in the processing of a text. Apart -%D from some other incompatilities we want to mention a pitfal -%D when using \type{\ifnum}. -%D -%D \starttyping -%D \ifnum\normalcounter=\pseudocounter \doif \else \doelse \fi -%D \ifnum\pseudocounter=\normalcounter \doif \else \doelse \fi -%D \stoptyping -%D -%D In the first test, \TEX\ continues it's search for the -%D second number after reading \type{\pseudocounter}, while -%D in the second test, it stops reading after having -%D encountered a real one. Tests like the first one therefore -%D can give unexpected results, for instance execution -%D of \type{\doif} even if both numbers are unequal. - -\def\zerocountervalue{0} - -\def\newcounter#1% - {\dodoglobal\let#1\zerocountervalue} - -% This is the original implementation: -% -% \def\dodododoincrement(#1,#2)% -% {\ifx#1\undefined -% \redoglobal\let#1\zerocountervalue -% \else\ifx#1\relax % \csname...\endcsname -% \redoglobal\let#1\zerocountervalue -% \fi\fi -% \scratchcounter=#2\relax -% \scratchcounter=\incrementsign\scratchcounter -% \advance\scratchcounter #1\relax -% \dodoglobal\edef#1{\the\scratchcounter}} -% -% \def\dododoincrement#1% -% {\dodododoincrement(#1,1)} -% -% \def\dodoincrement(#1% -% {\doifnextcharelse,% -% {\dodododoincrement(#1}{\dodododoincrement(#1,1}} -% -% \def\doincrement#1% -% {\def\incrementsign{#1}% -% \doifnextcharelse(\dodoincrement\dododoincrement} -% -% \def\increment{\doincrement+} -% \def\decrement{\doincrement-} -% -% And this is the one optimized for speed: - -% maxcounter = 2\maxdimen=1 - -\def\!!zerocount {0} % alongside \zerocount -\def\!!minusone {-1} % alongside \minusone -\def\!!plusone {1} % alongside \plusone - -\beginTEX - -\def\dodoindecrement#1(#2,#3)% - {\ifx#2\undefined - \redoglobal\let#2\zerocountervalue - \else\ifx#2\relax % \csname...\endcsname - \redoglobal\let#2\zerocountervalue - \fi\fi - \scratchcounter#3\relax - \scratchcounter#1\scratchcounter - \advance\scratchcounter#2\relax - \dodoglobal\edef#2{\the\scratchcounter}} - -\def\dodoincrement(#1% - {\doifnextcharelse,{\dodoindecrement+(#1}{\dodoindecrement+(#1,1}} - -\def\dododecrement(#1% - {\doifnextcharelse,{\dodoindecrement-(#1}{\dodoindecrement-(#1,1}} - -\def\doincrement#1% 10% faster alternative - {\ifx#1\undefined - \dodoglobal\let#1\!!plusone - \else\ifx#1\relax % \csname...\endcsname - \dodoglobal\let#1\!!plusone - \else - \fastincrement#1% - \fi\fi} - -\def\dodecrement#1% 10% faster alternative - {\ifx#1\undefined - \dodoglobal\let#1\!!minusone - \else\ifx#1\relax % \csname...\endcsname - \dodoglobal\let#1\!!minusone - \else - \fastdecrement#1% - \fi\fi} - -\def\fastdecrement#1% 50% faster alternative - {\scratchcounter#1\advance\scratchcounter\minusone - \dodoglobal\edef#1{\the\scratchcounter}} - -\def\fastincrement#1% 50% faster alternative - {\scratchcounter#1\advance\scratchcounter\plusone - \dodoglobal\edef#1{\the\scratchcounter}} - -\endTEX - -\beginETEX \numexpr - -% \def\doindecrement#1#2% -% {\dodoglobal\edef#2% -% {\the\numexpr(\ifx#2\undefined\else\ifx#2\relax\else#2\fi\fi#11)}} -% -% \def\doincrement{\doindecrement+} -% \def\dodecrement{\doindecrement-} -% -% some 3\% faster: - -\def\doindecrement#1#2% - {\dodoglobal\edef#2% - {\the\numexpr\ifx#2\undefined\else\ifx#2\relax\else#2\fi\fi+#1\relax}} - -\def\doincrement{\doindecrement\plusone } -\def\dodecrement{\doindecrement\minusone} - -\def\dodoindecrement#1#2,#3)% - {\dodoglobal\edef#2% - {\the\numexpr\ifx#2\undefined\else\ifx#2\relax\else#2\fi\fi#1#3\relax}} - -\def\dodoincrement(#1% - {\doifnextcharelse,{\dodoindecrement+#1}{\dodoindecrement+#1,\plusone}} - -\def\dododecrement(#1% - {\doifnextcharelse,{\dodoindecrement-#1}{\dodoindecrement-#1,\plusone}} - -\def\fastincrement#1{\dodoglobal\edef#1{\the\numexpr#1+\plusone \relax}} -\def\fastdecrement#1{\dodoglobal\edef#1{\the\numexpr#1+\minusone\relax}} - -\endETEX - -\def\increment{\doifnextcharelse(\dodoincrement\doincrement} -\def\decrement{\doifnextcharelse(\dododecrement\dodecrement} - -\def\incrementvalue#1{\expandafter\increment\csname#1\endcsname} -\def\decrementvalue#1{\expandafter\decrement\csname#1\endcsname} - -%D \macros -%D {newsignal} -%D -%D When writing advanced macros, we cannot do without -%D signaling. A signal is a small (invisible) kern or penalty -%D that signals the next macro that something just happened. -%D This macro can take any action depending on the previous -%D signal. Signals must be unique and the next macro takes care -%D of that. -%D -%D \starttyping -%D \newsignal\somesignal -%D \stoptyping -%D -%D Signals old dimensions and can be used in skips, kerns and -%D tests like \type{\ifdim}. - -\newdimen\maximumsignal % step is about 0.00025pt - -\def\newsignal#1% - {\ifx#1\undefined - \advance\maximumsignal 2sp % to be save in rounding - \edef#1{\the\maximumsignal}% - \fi} - -%D \macros -%D {newskimen} -%D -%D \TEX\ offers 256 \DIMENSIONS\ and \SKIPS. Unfortunately this -%D amount is too small to suit certain packages. Therefore when -%D possible one should use: -%D -%D \starttyping -%D \newskimen\tempskimen -%D \stoptyping -%D -%D This commands allocates a \DIMENSION\ or a \SKIP, depending -%D on the availability. One should be aware of the difference -%D between both. When searching for some glue \TEX\ goes on -%D searching till it's sure that no other glue component if -%D found. This search can be canceled by using \type{\relax} -%D when possible and needed. -%D -%D \starttyping -%D \def\newskimen#1% -%D {\ifx#1\undefined -%D \ifnum\count11>\count12 -%D \newskip#1\relax -%D \else -%D \newdimen#1\relax -%D \fi -%D \fi} -%D \stoptyping -%D -%D In order to make this macro work in plain \TEX\ too, we -%D use the following alternative, which fools \TEX\ about -%D the new commands being \type {\outer} ones. - -% \def\newskimen#1% -% {\ifx#1\undefined -% \csname new\ifnum\count11>\count12 skip\else dimen\fi\endcsname#1% -% \fi} - -\let\newskimen\newdimen % it's all etex or later now - -%D \macros -%D {strippedcsname} -%D -%D The next macro can be very useful when using \type{\csname} -%D like in: -%D -%D \starttyping -%D \csname if\strippedcsname\something\endcsname -%D \stoptyping -%D -%D This expands to \type{\ifsomething}. -%D -%D \starttyping -%D \def\strippedcsname -%D {\expandafter\gobbleoneargument\string} -%D \stoptyping -%D -%D Slower but better: - -\ifx\letterbackslash\undefined - {\catcode`.=0 .catcode`.\ 12 .xdef.letterbackslash{.string\}} % hack -\fi - -\def\strippedcsname#1% this permits \strippedcsname{\xxx} and \strippedcsname{xxx} - {\expandafter\dostrippedcsname\string#1} - -\def\dostrippedcsname#1% - {\if\noexpand#1\letterbackslash\else#1\fi} - -%D \macros -%D {savenormalmeaning} -%D -%D We will use this one in: - -\def\savenormalmeaning#1% - {\ifundefined{normal\strippedcsname#1}% - \letvalue{normal\strippedcsname#1}#1% - \fi} - -%D \macros -%D {newconditional, -%D settrue, setfalse, -%D ifconditional,then} -%D -%D \TEX's lacks boolean variables, although the \PLAIN\ format -%D implements \type{\newif}. The main disadvantage of this -%D scheme is that it takes three hash table entries. A more -%D memory saving alternative is presented here. A conditional -%D is defined by: -%D -%D \starttyping -%D \newconditional\doublesided -%D \setfalse -%D \stoptyping -%D Setting a conditional is done by \type{\settrue} and -%D \type{\setfalse}: -%D -%D \starttyping -%D \settrue\doublesided -%D \setfalse -%D \stoptyping -%D while testing is accomplished by: -%D -%D \starttyping -%D \ifconditional\doublesided ... \else ... \fi -%D \setfalse -%D \stoptyping -%D We cannot use the simple scheme: -%D -%D \starttyping -%D \def\settrue #1{\let#1=\iftrue} -%D \def\setfalse#1{\let#1=\iffalse} -%D \stoptyping -%D -%D Such an implementation gives problems with nested -%D conditionals. The next implementation is abaou as fast -%D and just as straightforward: - -\def\settrue #1{\chardef#1\zerocount} -\def\setfalse#1{\chardef#1\plusone} - -\let\newconditional = \setfalse -\let\ifconditional = \ifcase - -\let\then\relax % so that we can say \ifnum1>2\then -) - -%D \macros -%D {ifzeropt} -%D -%D The next macro is both cosmetic and byte saving. It is -%D pretty \type{\if}||safe too. It can be used in cases -%D like: -%D -%D \starttyping -%D \ifzeropt \somedimen ... \else ... \fi -%D \stoptyping - -\let\ifzeropt\ifcase - -%D \macros -%D {dorecurse,recurselevel,recursedepth, -%D dostepwiserecurse, -%D for} -%D -%D \TEX\ does not offer us powerfull for||loop mechanisms. On -%D the other hand its recursion engine is quite unique. We -%D therefore identify the for||looping macros by this method. -%D The most simple alternative is the one that only needs a -%D number. -%D -%D \starttyping -%D \dorecurse {n} {whatever we want} -%D \stoptyping -%D -%D This macro can be nested without problems and therefore be -%D used in situations where \PLAIN\ \TEX's \type{\loop} macro -%D ungracefully fails. The current value of the counter is -%D available in \type{\recurselevel}, before as well as after -%D the \typ{whatever we wat} stuff. -%D -%D \starttyping -%D \dorecurse % inner loop -%D {10} -%D {\recurselevel: % outer value -%D \dorecurse % inner loop -%D {\recurselevel} % outer value -%D {\recurselevel} % inner value -%D \dorecurse % inner loop -%D {\recurselevel} % outer value -%D {\recurselevel} % inner value -%D \endgraf} -%D \stoptyping -%D -%D In this example the first, second and fourth -%D \type{\recurselevel} concern the outer loop, while the third -%D and fifth one concern the inner loop. The depth of the -%D nesting is available for inspection in \type{\recursedepth}. -%D -%D Both \type{\recurselevel} and \type{\recursedepth} are -%D macros. The real \COUNTERS\ are hidden from the user because -%D we don't want any interference. - -\newcount\outerrecurse -\newcount\innerrecurse - -\def\recursedepth{\the\outerrecurse} -\def\recurselevel{0} - -\let\nextrecurse\relax - -%D Acceptable: -%D -%D \starttyping -%D \long\def\dostepwiserecurse#1#2#3% -%D {\let\nextrecurse\gobblefourarguments -%D \ifnum#3>0\relax\ifnum#2<#1\relax\else -%D \def\nextrecurse{\dosetstepwiserecurse>}% -%D \fi\fi -%D \ifnum#3<0\relax\ifnum#1<#2\relax\else -%D \def\nextrecurse{\dosetstepwiserecurse<}% -%D \fi\fi -%D \nextrecurse{#1}{#2}{#3}} -%D \stoptyping -%D -%D Better: -%D -%D \starttyping -%D \long\def\dostepwiserecurse#1#2#3% -%D {\let\nextrecurse\gobblefourarguments -%D \ifnum#3>0\relax \ifnum#2<#1\relax \else -%D \def\nextrecurse{\dosetstepwiserecurse>}% -%D \fi \else \ifnum#3<0\relax \ifnum#1<#2\relax \else -%D \def\nextrecurse{\dosetstepwiserecurse<}% -%D \fi \fi \fi -%D \nextrecurse{#1}{#2}{#3}} -%D -%D \def\@@irecurse{@@irecurse} % stepper -%D \def\@@nrecurse{@@nrecurse} % number of steps -%D \def\@@srecurse{@@srecurse} % step -%D \def\@@drecurse{@@drecurse} % direction, < or > -%D \def\@@arecurse{@@arecurse} % action -%D -%D \long\def\dosetstepwiserecurse#1#2#3#4#5% -%D {\global\advance\outerrecurse 1 -%D \setevalue{\@@drecurse\recursedepth}{#1}% -%D \setevalue{\@@irecurse\recursedepth}{\number#2}% -%D \setevalue{\@@nrecurse\recursedepth}{\number#3}% -%D \setevalue{\@@srecurse\recursedepth}{\number#4}% -%D \long\setvalue{\@@arecurse\recursedepth}{#5}% -%D \dodorecurse} -%D -%D \def\donorecurse -%D {} -%D -%D \def\dododorecurse -%D {\edef\recurselevel{\csname\@@irecurse\recursedepth\endcsname}% -%D \getvalue{\@@arecurse\recursedepth}% -%D \edef\recurselevel{\csname\@@irecurse\recursedepth\endcsname}% -%D \innerrecurse\recurselevel -%D \advance\innerrecurse \csname\@@srecurse\recursedepth\endcsname -%D \setevalue{\@@irecurse\recursedepth}{\the\innerrecurse}% -%D \dodorecurse} -%D -%D \def\dodorecurse -%D {\ifnum\csname\@@irecurse\recursedepth\endcsname -%D \csname\@@drecurse\recursedepth\endcsname -%D \csname\@@nrecurse\recursedepth\endcsname\relax -%D \expandafter\nododorecurse -%D \else -%D \expandafter\dododorecurse -%D \fi} -%D -%D \def\nododorecurse -%D {\global\advance\outerrecurse -1 -%D \edef\recurselevel{\csname\@@irecurse\recursedepth\endcsname}} -%D \stoptyping -%D -%D Cleaner and much faster: - -\def\@@irecurse{@@ir@@} % ecurse} % stepper -\def\@@arecurse{@@ar@@} % ecurse} % action - -% \mathchardef - -\long\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4 - {\global\advance\outerrecurse \plusone - \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname{#4}% - \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel - \ifnum#3>0\relax - \ifnum#2<#1\relax - \let\nextrecurse\exitstepwiserecurse - \else - \let\nextrecurse\dodostepwiserecurse - \fi - \else - \ifnum#3<0\relax - \ifnum#1<#2\relax - \let\nextrecurse\exitstepwiserecurse - \else - \let\nextrecurse\dodostepwisereverse - \fi - \else - \let\nextrecurse\exitstepwiserecurse - \fi - \fi\expanded{\nextrecurse{\number#1}{\number#2}{\number#3}}} - -\beginETEX \numexpr - -\long\def\dodostepwiserecurse#1#2#3% from to step - {\ifnum#1>#2\relax - \@EA\nodostepwiserecurse - \else - \def\recurselevel{#1}% - \@EAEAEA\redostepwiserecurse\@EA - \fi\@EA{\the\numexpr\recurselevel+#3\relax}{#2}{#3}} - -\endETEX - -\beginTEX - -\long\def\dodostepwiserecurse#1#2#3% from to step - {\ifnum#1>#2\relax - \@EA\nodostepwiserecurse - \else - \def\recurselevel{#1}% - \innerrecurse#1\advance\innerrecurse#3\relax - \@EAEAEA\redostepwiserecurse\@EA - \fi\@EA{\the\innerrecurse}{#2}{#3}} - -\endTEX - -\def\expandrecursecontent - {\csname\@@arecurse\recursedepth\endcsname} - -\def\redostepwiserecurse - {\expandrecursecontent\dodostepwiserecurse} - -\beginETEX \numexpr - -\long\def\dodostepwisereverse#1#2#3% from to step - {\ifnum#1<#2\relax - \@EA\nodostepwiserecurse - \else - \def\recurselevel{#1}% - \@EAEAEA\redostepwisereverse\@EA - \fi\@EA{\the\numexpr\recurselevel#3\relax}{#2}{#3}} - -\endETEX - -\beginTEX - -\long\def\dodostepwisereverse#1#2#3% from to step - {\ifnum#1<#2\relax - \@EA\nodostepwiserecurse - \else - \def\recurselevel{#1}% - \innerrecurse#1\relax - \advance\innerrecurse#3\relax - \@EAEAEA\redostepwisereverse\@EA - \fi\@EA{\the\innerrecurse}{#2}{#3}} - -\endTEX - -\def\redostepwisereverse - {\expandrecursecontent\dodostepwisereverse} - -\def\exitstepwiserecurse - {\nodostepwiserecurse\relax} - -\def\nodostepwiserecurse#1#2#3#4% - {\@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname - \global\advance\outerrecurse \minusone} - -\def\nonostepwiserecurse#1#2#3% - {\@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname - \global\advance\outerrecurse \minusone} - -\def\dorecurse#1% - {\dostepwiserecurse1{#1}1} - -%D As we can see here, the simple command \type{\dorecurse} is -%D a special case of the more general: -%D -%D \starttyping -%D \dostepwiserecurse {from} {to} {step} {action} -%D \stoptyping -%D -%D This commands accepts positive and negative steps. Illegal -%D values are handles as good as possible and the macro accepts -%D numbers and \COUNTERS. -%D -%D \starttyping -%D \dostepwiserecurse {1} {10} {2} {...} -%D \dostepwiserecurse {10} {1} {-2} {...} -%D \stoptyping -%D -%D Because the simple case is used often, we implement it -%D more efficiently: - -\long\def\dorecurse#1% - {\ifcase#1\relax - \expandafter\gobbletwoarguments - \or - \expandafter\ydorecurse - \else - \expandafter\xdorecurse - \fi{#1}} - -\long\def\xdorecurse#1#2% - {\global\advance\outerrecurse \plusone - \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname{#2}% - \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel - \@EA\dodorecurse\@EA1\@EA{\number#1}} - -\long\def\ydorecurse#1#2% - {\global\advance\outerrecurse \plusone - \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel - \let\recurselevel\!!plusone - #2% - \@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname - \global\advance\outerrecurse \minusone} - -\beginETEX \numexpr - -\long\def\dodorecurse#1#2% from to - {\ifnum#1>#2\relax - \@EA\nodorecurse - \else - \def\recurselevel{#1}% - \@EAEAEA\redorecurse - \fi\@EA{\the\numexpr\recurselevel+\plusone\relax}{#2}} - -\endETEX - -\beginTEX - -\long\def\dodorecurse#1#2% from to - {\ifnum#1>#2\relax - \@EA\nodorecurse - \else - \def\recurselevel{#1}% - \innerrecurse#1\advance\innerrecurse\plusone - \@EAEAEA\redorecurse - \fi\@EA{\the\innerrecurse}{#2}} - -\endTEX - -\def\redorecurse - {\expandrecursecontent\dodorecurse} - -\def\nodorecurse#1#2#3% - {\@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname - \global\advance\outerrecurse \minusone } - -%D \macros -%D {doloop,exitloop} -%D -%D Sometimes loops are not determined by counters, but by -%D (a combinations of) conditions. We therefore implement a -%D straightforward loop, which can only be left when we -%D explictly exit it. Nesting is supported. First we present -%D a more extensive alternative. -%D -%D \starttyping -%D \doloop -%D {Some kind of typesetting punishment \par -%D \ifnum\pageno>100 \exitloop \fi} -%D \stoptyping -%D -%D When needed, one can call for \type{\looplevel} and -%D \type{\loopdepth}. -%D -%D If we write this macros from scratch, we end up with -%D something like the ones described above: -%D -%D \starttyping -%D \def\@@eloop{@@eloop} % exit -%D \def\@@iloop{@@iloop} % stepper -%D \def\@@aloop{@@aloop} % action -%D -%D \newcount\outerloop -%D -%D \def\loopdepth% -%D {\the\outerloop} -%D -%D \def\exitloop% -%D {\setevalue{\@@eloop\loopdepth}{0}} -%D -%D \long\def\doloop#1% -%D {\global\advance\outerloop by 1 -%D \setevalue{\@@iloop\loopdepth}{1}% -%D \setevalue{\@@eloop\loopdepth}{1}% -%D \long\setvalue{\@@aloop\loopdepth}{#1}% -%D \dodoloop} -%D -%D \def\dodonoloop% -%D {\global\advance\outerloop by -1\relax} -%D -%D \def\dododoloop% -%D {\edef\looplevel{\getvalue{\@@iloop\loopdepth}}% -%D \innerrecurse=\looplevel -%D \advance\innerrecurse by 1 -%D \setevalue{\@@iloop\loopdepth}{\the\innerrecurse}% -%D \getvalue{\@@aloop\loopdepth}% -%D \edef\looplevel{\getvalue{\@@iloop\loopdepth}}% -%D \dodoloop} -%D -%D \def\dodoloop% -%D {\ifnum\getvalue{\@@eloop\loopdepth}=0 -%D \expandafter\dodonoloop -%D \else -%D \expandafter\dododoloop -%D \fi} -%D -%D \def\doloop% -%D {\dostepwiserecurse{1}{\maxdimen}{1}} -%D -%D \def\exitloop -%D {\setvalue{\@@irecurse\recursedepth}{\maxdimen}} -%D -%D \def\looplevel{\recurselevel} -%D \def\loopdepth{\recursedepth} -%D \stoptyping -%D -%D We don't have to declare new counters for \type{\looplevel} -%D and \type{\loopdepth} because we can use \type{\recurselevel} -%D and \type{\recursedepth}. -%D -%D We prefer however a more byte saving implementation, that -%D executes of course a bit slower. -%D -%D \starttyping -%D \def\doloop% -%D {\dostepwiserecurse1\maxdimen1} -%D -%D \def\exitloop% -%D {\letvalue{\@@irecurse\recursedepth}\maxdimen} -%D \stoptyping -%D -%D Although, the next version is faster because it used the -%D simple loop. - -\let\endofloop\donothing - -\long\def\doloop#1% - {\global\advance\outerrecurse \plusone - \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname{#1}% - \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel - \let\endofloop\dodoloop - \dodoloop1} % no \plusone else \recurselevel wrong - -\beginETEX \numexpr - -\long\def\dodoloop#1% - {\def\recurselevel{#1}% - \@EA\redoloop\@EA{\the\numexpr\recurselevel+\plusone\relax}} - -\endETEX - -\beginTEX - -\long\def\dodoloop#1% - {\def\recurselevel{#1}% - \innerrecurse#1\advance\innerrecurse\plusone - \@EA\redoloop\@EA{\the\innerrecurse}} - -\endTEX - -\def\redoloop - {\expandrecursecontent\endofloop} - -\def\nodoloop#1% - {\let\endofloop\dodoloop % new, permits nested \doloop's - \@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname - \global\advance\outerrecurse\minusone} - -\def\exitloop % \exitloop quits at end - {\let\endofloop\nodoloop} - -\long\def\exitloopnow#1\endofloop % \exitloopnow quits directly - {\nodoloop} - -%D The loop is executed at least once, so beware of situations -%D like: -%D -%D \starttyping -%D \doloop {\exitloop some commands} -%D \stoptyping -%D -%D It's just a matter of putting the text into the \type{\if} -%D statement that should be there anyway, like in: -%D -%D \starttyping -%D \doloop {\ifwhatever \exitloop \else some commands\fi} -%D \stoptyping -%D -%D You can also quit a loop immediately, by using \type -%D {\exitloopnow} instead. Beware, this is more sensitive -%D for conditional errors. - -%D Krzysztof Leszczynski suggested to provide access to the level by -%D means of a \type {#1}. I decided to pass the more frequently used -%D level as \type {#1} and the less favoured depth as \type {#2}. The -%D intended usage is: -%D -%D \starttyping -%D \dorecurse{3}{\definesymbol[test-#1][xx-#1]} -%D -%D \def\test{\dorecurse{3}{\definesymbol[test-##1][xx-##1]}} \test -%D -%D \symbol[test-1]\quad\symbol[test-2]\quad\symbol[test-3] -%D \stoptyping -%D -%D Since the hashed arguments are expanded, we don't need tricky -%D expansion here. -%D -%D \starttyping -%D \dorecurse{3}{\expanded{\definesymbol[test-\recurselevel][xx-\recurselevel]}} -%D \stoptyping - -\def\expandrecursecontent - {\csname\@@arecurse\recursedepth\@EA\@EA\@EA\endcsname\@EA\@EA\@EA{\@EA\recurselevel\@EA}\@EA{\recursedepth}} - -\long\def\xdorecurse#1#2% - {\global\advance\outerrecurse \plusone - \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#2}% - \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel - \@EA\dodorecurse\@EA1\@EA{\number#1}} - -\long\def\ydorecurse#1#2% - {\global\advance\outerrecurse \plusone - \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel - \let\recurselevel\!!plusone - \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#2}% - \expandrecursecontent - \@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname - \global\advance\outerrecurse \minusone} - -\long\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4 - {\global\advance\outerrecurse \plusone - \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#4}% - \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel - \ifnum#3>0\relax - \ifnum#2<#1\relax - \let\nextrecurse\exitstepwiserecurse - \else - \let\nextrecurse\dodostepwiserecurse - \fi - \else - \ifnum#3<0\relax - \ifnum#1<#2\relax - \let\nextrecurse\exitstepwiserecurse - \else - \let\nextrecurse\dodostepwisereverse - \fi - \else - \let\nextrecurse\exitstepwiserecurse - \fi - \fi\expanded{\nextrecurse{\number#1}{\number#2}{\number#3}}} - -\long\def\doloop#1% - {\global\advance\outerrecurse \plusone - \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#1}% - \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel - \let\endofloop\dodoloop - \dodoloop1} % no \plusone else \recurselevel wrong - -%D For special purposes: - -\newcount\fastrecursecounter -\newcount\lastrecursecounter -\newcount\steprecursecounter - -\def\dofastrecurse#1#2#3#4% - {\def\fastrecursebody{#4}% - \fastrecursecounter#1\relax - \lastrecursecounter#2\relax - \steprecursecounter#3\relax - \def\recurselevel{\number\fastrecursecounter}% - \dodofastrecurse} - -\def\resetrecurselevel{\let\recurselevel\!!zerocount} - -\def\dodofastrecurse - {\ifnum\fastrecursecounter>\lastrecursecounter - % \resetrecurselevel % slows down - \else - \fastrecursebody - \advance\fastrecursecounter\steprecursecounter - \expandafter\dodofastrecurse - \fi} - -% \appendtoks \resetrecurselevel \to \everydump - -\everydump\expandafter{\the\everydump\resetrecurselevel} - -%D This alternative looks a bit different and uses a -%D pseudo counter. When this macro is nested, we have to use -%D different counters. This time we use keywords. -%D -%D \starttyping -%D \def\alfa{2} \def\beta{100} \def\gamma{3} -%D -%D \for \n=55 \to 100 \step 1 \do {... \n ...} -%D \for \n=\alfa \to \beta \step \gamma \do {... \n ...} -%D \for \n=\n \to 120 \step 1 \do {... \n ...} -%D \for \n=120 \to 100 \step -3 \do {... \n ...} -%D \for \n=55 \to 100 \step 2 \do {... \n ...} -%D \stoptyping -%D -%D Only in the third example we need to predefine \type{\n}. -%D The use of \type{\od} as a dilimiter would have made nested -%D use more problematic. - -%D Don't use this one, it's kind of obsolete. - -\def\for#1=#2\to#3\step#4\do#5% - {\dostepwiserecurse{#2}{#3}{#4} - {\let#1\recurselevel#5\let#1\recurselevel}} - -%D \macros -%D {newevery,everyline,EveryLine,EveryPar} -%D -%D Lets skip to something quite different. It's common use -%D to use \type{\everypar} for special purposes. In \CONTEXT\ -%D we use this primitive for locating sidefloats. This means -%D that when user assignments to \type{\everypar} can interfere -%D with those of the package. We therefore introduce -%D \type{\EveryPar}. -%D -%D The same goes for \type{\EveryLine}. Because \TEX\ offers -%D no \type{\everyline} primitive, we have to call for -%D \type{\everyline} when we are working on a line by line -%D basis. Just by calling \type{\EveryPar{}} and -%D \type{\EveryLine{}} we restore the old situation. -%D -%D The definition command \type{\DoWithEvery} will be quite -%D unreadable, so let's first show an implementation that -%D shows how things are done: -%D -%D \starttyping -%D \newtoks \everyline -%D \newtoks \oldeveryline -%D \newif \ifeveryline -%D -%D \def\DoWithEvery#1#2#3#4% -%D {#3\else\edef\next{\noexpand#2={\the#1}}\next\fi -%D \edef\next{\noexpand#1={\the#2\the\scratchtoks}}\next -%D #4} -%D -%D \def\doEveryLine% -%D {\DoWithEvery\everyline\oldeveryline\ifeveryline\everylinetrue} -%D -%D \def\EveryLine% -%D {\afterassignment\doEveryLine\scratchtoks} -%D \stoptyping -%D -%D The real implementation is a bit more complicated but we -%D prefer something more versatile. - -% the old one -% -% \def\DoWithEvery#1% -% {\csname if\strippedcsname#1\endcsname \else -% \edef\next% -% {\@EA\noexpand\csname old\strippedcsname#1\endcsname= -% {\the#1}}% -% \next -% \fi -% \edef\next% -% {\noexpand#1= -% {\@EA\the\csname old\strippedcsname#1\endcsname\the\scratchtoks}}% -% \next -% \csname\strippedcsname#1true\endcsname} -% -% \def\dowithevery#1% -% {\@EA\afterassignment\csname do\strippedcsname#1\endcsname\scratchtoks} -% -% \def\newevery#1#2% -% {\ifx#1\undefined\newtoks#1\fi -% \ifx#2\relax\else\ifx#2\undefined -% \@EA\newtoks\csname old\strippedcsname#1\endcsname -% \@EA\newif \csname if\strippedcsname#1\endcsname -% \@EA\def \csname do\strippedcsname#2\endcsname{\DoWithEvery#1}% -% \def#2{\dowithevery#2}% -% \fi\fi} -% -% cleaner and more efficient - -%\def\dowithevery#1% -% {\def\dodowithevery% -% {\ifcase\csname c\strippedcsname#1\endcsname \expandafter\chardef -% \csname c\strippedcsname#1\endcsname=1 -% \csname t\strippedcsname#1\endcsname=#1% -% \fi -% \edef\next% -% {#1={\the\csname t\strippedcsname#1\endcsname\the\scratchtoks}}% -% \next}% -% \afterassignment\dodowithevery\scratchtoks} -% -% more efficient: - -\def\dodowithevery#1% - {\ifcase\csname c\strippedcsname#1\endcsname \expandafter\chardef - \csname c\strippedcsname#1\endcsname1 - \csname t\strippedcsname#1\endcsname#1% - \fi - \edef\next% - {#1{\the\csname t\strippedcsname#1\endcsname\the\scratchtoks}}% - \next} - -\def\dowithevery#1% - {\def\next{\dodowithevery#1}% - \afterassignment\next\scratchtoks} - -\bgroup \let\newtoks\relax % plain safe (\outer) - -\gdef\newevery#1#2% - {\ifx#1\undefined\csname newtoks\endcsname#1\fi % plain safe (\outer) - \ifx#2\relax\else\ifx#2\undefined - \expandafter\newtoks\csname t\strippedcsname#1\endcsname - \expandafter\chardef\csname c\strippedcsname#1\endcsname\zerocount - \def#2{\dowithevery#1}% - \fi\fi} - -\egroup - -%D The first \type {\outer} hack is needed to trick \TEX\ -%D into thinking that \type {\newtoks} is no outer macro, -%D the second hack is needed due to some funny interaction -%D between outer macros and \type {\if} at expansion time. - -%D This one permits definitions like: - -\newevery \everypar \EveryPar -\newevery \everyline \EveryLine - -%D and how about: - -\newevery \neverypar \NeveryPar - -%D Which we're going to use indeed! When the second argument -%D equals \type {\relax}, the first token list is created -%D unless it is already defined. - -%D Technically spoken we could have used the method we are -%D going to present in the visual debugger. First we save -%D the primitive \type{\everypar}: -%D -%D \starttyping -%D \let\normaleverypar=\everypar -%D \stoptyping -%D -%D Next we allocate a \TOKENLIST\ named \type{\everypar}, -%D which means that \type{\everypar} is no longer a primitive -%D but something like \type{\toks44}. -%D -%D \starttyping -%D \newtoks\everypar -%D \stoptyping -%D -%D Because \TEX\ now executes \type{\normaleverypar} instead -%D of \type{\everypar}, we are ready to assign some tokens to -%D this internally known and used \TOKENLIST. -%D -%D \starttyping -%D \normaleverypar={all the things the system wants to do \the\everypar} -%D \stoptyping -%D -%D Where the user can provide his own tokens to be expanded -%D every time he expects them to expand. -%D -%D \starttyping -%D \everypar={something the user wants to do} -%D \stoptyping -%D -%D We don't use this method because it undoubtly leads to -%D confusing situations, especially when other packages are -%D used, but it's this kind of tricks that make \TEX\ so -%D powerful. - -%D \macros -%D {convertargument,convertcommand,convertvalue} -%D -%D Some persistent experimenting led us to the next macro. This -%D macro converts a parameter or an expanded macro to it's -%D textual meaning. -%D -%D \starttyping -%D \convertargument ... \to \command -%D \stoptyping -%D -%D For example, -%D -%D \starttyping -%D \convertargument{one \two \three{four}}\to\ascii -%D \stoptyping -%D -%D The resulting macro \type{\ascii} can be written to a file -%D or the terminal without problems. In \CONTEXT\ we use this -%D macro for generating registers and tables of contents. -%D -%D The second conversion alternative accepts a command: -%D -%D \starttyping -%D \convertcommand\command\to\ascii -%D \stoptyping -%D -%D Both commands accept the prefix \type{\doglobal} for global -%D assignments. - -\beginTEX - -\def\doconvertargument#1>{} - -\def\convertedcommand - {\expandafter\doconvertargument\meaning} - -\long\def\convertargument#1\to#2% - {\long\def#2{#1}% saves a restore - \dodoglobal\edef#2{\convertedcommand#2}} - -\long\def\convertcommand#1\to#2% - {\dodoglobal\edef#2{\convertedcommand#1}} - -% no dodoglobal ! - -\long\def\defconvertedargument#1#2% less sensitive for \to - {\long\def#1{#2}% saves a restore - \edef#1{\convertedcommand#1}} - -\long\def\defconvertedcommand#1#2% less sensitive for \to - {\edef#1{\convertedcommand#2}} - -\long\def\gdefconvertedargument#1#2% less sensitive for \to - {\long\gdef#1{#2}% saves a restore - \xdef#1{\convertedcommand#1}} - -\long\def\gdefconvertedcommand#1#2% less sensitive for \to - {\xdef#1{\convertedcommand#2}} - -\endTEX - -\def\convertvalue#1\to - {\expandafter\convertcommand\csname#1\endcsname\to} - -\def\defconvertedvalue#1#2% less sensitive for \to - {\@EA\defconvertedcommand\@EA#1\csname#2\endcsname} - -%D \macros -%D {doifassignmentelse} -%D -%D A lot of \CONTEXT\ commands take optional arguments, for -%D instance: -%D -%D \starttyping -%D \dothisorthat[alfa,beta] -%D \dothisorthat[first=foo,second=bar] -%D \dothisorthat[alfa,beta][first=foo,second=bar] -%D \stoptyping -%D -%D Although a combined solution is possible, we prefer a -%D seperation. The next command takes care of propper -%D handling of such multi||faced commands. -%D -%D \starttyping -%D \doifassignmentelse {...} {then ...} {else ...} -%D \stoptyping - -% not robust -% -% \def\doifassignmentelse% -% {\doifinstringelse{=}} -% -% readable -% -% \def\doifassignmentelse#1% -% {\convertargument#1\to\ascii -% \doifinstringelse{=}{\ascii}} - -\def\doifassignmentelse#1% - {\convertargument#1\to\ascii - \doifinstringelse=\ascii} - -%D \macros -%D {convertasciiafter} -%D -%D Sometimes we need to convert an argument to a string (letters -%D only), for instance when we compare it with another string: -%D -%D \starttyping -%D \convertasciiafter\doifinstringelse{em}{\ascii}{...} -%D \stoptyping - -\def\convertasciiafter#1#2% - {\convertargument#2\to\asciiafter - \@EA#1\@EA{\asciiafter}} - -%D In \ETEX\ we can use \type {\detokenize} and gain some -%D speed, but in general far less that 1\% for \type -%D {\convertargument} and nil for \type {\convertcommand}. -%D This macro is more robust than the pure \TEX\ one, -%D something I found out when primitives like \type -%D {\jobname} were fed (or something undefined). - -% command variant: one level expansion ! - -\beginETEX \detokenize - -\long\def\convertargument#1\to#2{\dodoglobal\edef#2{\detokenize{#1}}} -\long\def\convertcommand #1\to#2{\dodoglobal\edef#2{\@EA\detokenize\@EA{#1}}} % hm, only second is also ok - -\long\def\defconvertedargument #1#2{\edef#1{\detokenize {#2}}} -\long\def\defconvertedcommand #1#2{\edef#1{\detokenize\@EA{#2}}} -\long\def\edefconvertedargument#1#2{\edef#1{#2}% - \edef#1{\detokenize\@EA{#1}}} -\long\def\gdefconvertedargument#1#2{\xdef#1{\detokenize {#2}}} -\long\def\gdefconvertedcommand #1#2{\xdef#1{\detokenize\@EA{#2}}} -\long\def\xdefconvertedargument#1#2{\xdef#1{#2}% - \xdef#1{\detokenize\@EA{#1}}} - -\endETEX - -%D When you try to convert a primitive command, you'll find -%D out that the \ETEX\ method fails on for instance \type -%D {\jobname} in the sense that it returns the filename -%D instead of just \type {\jobname}. So far this does not -%D give real problems. - -%D This is typically a macro that one comes to after reading -%D the \TEX book carefully. Even then, the definite solution -%D was found after rereading the \TEX book. The first -%D implementation was: -%D -%D \starttyping -%D \def\doconvertargument#1->#2\\\\{#2} -%D \stoptyping -%D -%D The \type{-}, the delimiter \type{\\\\} and the the second -%D argument are completely redundant. - -%D \macros -%D {showvalue,showargument} -%D -%D Two handy macros for testing purposes only: - -\def\showvalue#1% - {\expandafter\show\csname#1\endcsname} - -\beginETEX - -\def\showvalue#1% - {\ifcsname#1\endcsname - \expandafter\show\csname#1\endcsname - \else - \show\undefined - \fi} - -\endETEX - -\long\def\showargument#1% - {\defconvertedargument\ascii{#1}\ascii} - -%D \macros -%D {doifmeaningelse} -%D -%D We can use both commands in testing, but alas, not all -%D meanings expand to something \type {->}. This is no problem -%D in the \ETEX\ implementation, but since we want -%D compatibility, we need: -%D -%D \starttyping -%D \doifmeaningelse {\next} {\something} {true} {false} -%D \stoptyping -%D -%D Watch the one level expansion of the second argument. - -\def\doifmeaningelse#1#2% - {\edef\!!stringa{\meaning#1}% - \def\!!stringb{#2}\edef\!!stringb{\meaning\!!stringb}% - \ifx\!!stringa\!!stringb - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -%D \macros -%D {doifsamestringselse,doifsamestring,doifnotsamestring} -%D -%D The next comparison macro converts the arguments into -%D expanded strings. This command can be used to compare for -%D instance \type {\jobname} with a name stored in a macro. - -\def\@@doifsamestringelse#1#2% - {\edef\!!stringa{#1}% - \edef\!!stringb{#2}% - \convertcommand\!!stringa\to\!!stringa - \convertcommand\!!stringb\to\!!stringb - \ifx\!!stringa\!!stringb} - -\def\doifsamestringelse#1#2% - {\@@doifsamestringelse{#1}{#2}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\def\doifsamestring#1#2% - {\@@doifsamestringelse{#1}{#2}% - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\def\doifnotsamestring#1#2% - {\@@doifsamestringelse{#1}{#2}% - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -%D \macros -%D {ExpandFirstAfter,ExpandSecondAfter,ExpandBothAfter} -%D -%D These three commands support expansion of arguments before -%D executing the commands that uses them. We can best -%D illustrate this with an example. -%D -%D \starttyping -%D \def\first {alfa,beta,gamma} -%D \def\second {alfa,epsilon,zeta} -%D -%D \ExpandFirstAfter \doifcommon {\first} {alfa} {\message{OK}} -%D \ExpandSecondAfter \doifcommon {alfa} {\second} {\message{OK}} -%D \ExpandBothAfter \doifcommon {\first} {\second} {\message{OK}} -%D -%D \ExpandFirstAfter\processcommalist[\first]\message -%D -%D \ExpandAfter \doifcommon {\first} {alfa} {\message{OK}} -%D \stoptyping -%D -%D The first three calls result in the threefold message -%D \type{OK}, the fourth one shows the three elements of -%D \type{\first}. The command \type{\ExpandFirstAfter} takes -%D care of (first) arguments that are delimited by \type{[ ]}, -%D but the faster \type{\ExpandAfter} does not. - -\def\simpleExpandFirstAfter#1% - {\long\xdef\@@expanded{\noexpand\ExpandCommand{#1}}\@@expanded} - -\def\complexExpandFirstAfter[#1]% - {\long\xdef\@@expanded{\noexpand\ExpandCommand[#1]}\@@expanded} - -\def\ExpandFirstAfter#1% - {\let\ExpandCommand#1% - \doifnextoptionalelse\complexExpandFirstAfter\simpleExpandFirstAfter} - -\def\ExpandSecondAfter#1#2#3% - {\scratchtoks{#2}% - \long\xdef\@@expanded{\noexpand#1{\the\scratchtoks}{#3}}\@@expanded} - -\def\ExpandBothAfter#1#2#3% - {\long\xdef\@@expanded{\noexpand#1{#2}{#3}}\@@expanded} - -\def\ExpandAfter#1#2% - {\long\xdef\@@expanded{\noexpand#1{#2}}\@@expanded} - -%D Now we can for instance define \type{\ifinstringelse} as: - -\def\ifinstringelse - {\ExpandBothAfter\p!doifinstringelse} - -%D \macros -%D {ConvertToConstant,ConvertConstantAfter} -%D -%D When comparing arguments with a constant, we can get into -%D trouble when this argument consists of tricky expandable -%D commands. One solution for this is converting the -%D argument to a string of unexpandable characters. To make -%D comparison possible, we have to convert the constant too -%D -%D \starttyping -%D \ConvertToConstant\doifelse {...} {...} {then ...} {else ...} -%D \stoptyping -%D -%D This construction is only needed when the first argument -%D can give troubles. Misuse can slow down processing. -%D -%D \starttyping -%D \ConvertToConstant\doifelse{\c!alfa} {\c!alfa}{...}{...} -%D \ConvertToConstant\doifelse{alfa} {\c!alfa}{...}{...} -%D \ConvertToConstant\doifelse{alfa} {alfa} {...}{...} -%D \ConvertToConstant\doifelse{alfa \alfa test}{\c!alfa}{...}{...} -%D \stoptyping -%D -%D In examples~2 and~3 both arguments equal, in~1 and~4 -%D they differ. - -\beginTEX - -\long\def\ConvertToConstant#1#2#3% - {\expandafter\defconvertedargument\expandafter\!!stringa\expandafter{#2}% - \expandafter\defconvertedargument\expandafter\!!stringb\expandafter{#3}% - #1{\!!stringa}{\!!stringb}} - -\endTEX - -\beginETEX \detokenize - -\long\def\ConvertToConstant#1#2#3% - {\edef\!!stringa{\expandafter\detokenize\expandafter{#2}}% - \edef\!!stringb{\expandafter\detokenize\expandafter{#3}}% - #1{\!!stringa}{\!!stringb}} - -\endETEX - -%D When the argument \type{#1} consists of commands, we had -%D better use -%D -%D \starttyping -%D \ConvertConstantAfter\processaction[#1][...] -%D \ConvertConstantAfter\doifelse{#1}{\v!something}{}{} -%D \stoptyping -%D -%D This commands accepts things like: -%D -%D \starttyping -%D \v!constant -%D constant -%D \hbox to \hsize{\rubish} -%D \stoptyping -%D -%D As we will see in the core modules, this macro permits -%D constructions like: -%D -%D \starttyping -%D \setupfootertexts[...][...] -%D \setupfootertexts[margin][...][...] -%D \setupfootertexts[\v!margin][...][...] -%D \stoptyping -%D -%D where \type{...} can be anything legally \TEX. - -\def\CheckConstantAfter#1#2% - {\@EA\convertargument\v!prefix!\to\ascii - \convertargument#1\to#2\relax - \doifinstringelse\ascii{#2} - {\expandafter\convertargument#1\to#2} - {}} - -\def\ConvertConstantAfter#1#2#3% - {\CheckConstantAfter{#2}\asciia - \CheckConstantAfter{#3}\asciib - #1{\asciia}{\asciib}} - -%D \macros -%D {assignifempty} -%D -%D We can assign a default value to an empty macro using: -%D -%D \starttyping -%D \assignifempty \macros {default value} -%D \stoptyping -%D -%D We don't explicitly test if the macro is defined. - -\def\assignifempty#1#2% can be sped up - {\doifsomething{#1}{\def#1{#2}}} % {\doifnot{#1}{}{\def#1{#2}}} - -%D \macros -%D {gobbleuntil,grabuntil,gobbleuntilrelax, -%D processbetween,processuntil} -%D -%D In \TEX\ gobbling usually stand for skipping arguments, so -%D here are our gobbling macros. -%D -%D In \CONTEXT\ we use a lot of \type{\start}||\type{\stop} -%D like constructions. Sometimes, the \type{\stop} is used as a -%D hard coded delimiter like in: -%D -%D \starttyping -%D \def\startcommand#1\stopcommand% -%D {... #1 ...} -%D \stoptyping -%D -%D In many cases the \type{\start}||\type{\stop} pair is -%D defined at format generation time or during a job. This -%D means that we cannot hardcode the \type{\stop} criterium. -%D Only after completely understanding \type{\csname} and -%D \type{\expandafter} I was able to to implement a solution, -%D starting with: -%D -%D \starttyping -%D \grabuntil{stop}\command -%D \stoptyping -%D -%D This commands executes, after having encountered -%D \type {\stop} the command \type {\command}. This command -%D receives as argument the text preceding the \type {\stop}. -%D This means that: -%D -%D \starttyping -%D \def\starthello% -%D {\grabuntil{stophello}\message} -%D -%D \starthello Hello world!\stophello -%D \stoptyping -%D -%D results in: \type{\message{Hello world!}}. - -\def\dograbuntil#1#2% - {\long\def\next##1#1{#2{##1}}\next} - -\def\grabuntil#1% - {\expandafter\dograbuntil\expandafter{\csname#1\endcsname}} - -%D The next command build on this mechanism: -%D -%D \starttyping -%D \processbetween{string}\command -%D \stoptyping -%D -%D Here: -%D -%D \starttyping -%D \processbetween{hello}\message -%D \starthello Hello again!\stophello -%D \stoptyping -%D -%D leads to: \type{\message{Hello again!}}. The command -%D -%D \starttyping -%D \gobbleuntil{sequence} -%D \stoptyping -%D -%D is related to these commands. This one simply throws away -%D everything preceding \type{\command}. - -\long\def\processbetween#1#2% - {\setvalue{\s!start#1}{\grabuntil{\s!stop#1}{#2}}} - -\def\gobbleuntil#1% - {\long\def\next##1#1{}\next} - -\def\gobbleuntilrelax#1\relax - {} - -%D The next one simply expands the pickup up tokens. -%D -%D \starttyping -%D \processuntil{sequence} -%D \stoptyping - -\def\processuntil#1% - {\long\def\next##1#1{##1}\next} - -%D \macros -%D {groupedcommand} -%D -%D Commands often manipulate argument as in: -%D -%D \starttyping -%D \def\doezomaarwat#1{....#1....} -%D \stoptyping -%D -%D A disadvantage of this approach is that the tokens that -%D form \type{#1} are fixed the the moment the argument is read -%D in. Normally this is no problem, but for instance verbatim -%D environments adapt the \CATCODES\ of characters and therefore -%D are not always happy with already fixed tokens. -%D -%D Another problem arises when the argument is grouped not by -%D \type{{}} but by \type{\bgroup} and \type{\egroup}. Such an -%D argument fails, because the \type{\bgroup} is een as the -%D argument (which is quite normal). -%D -%D The next macro offers a solution for both unwanted -%D situations: -%D -%D \starttyping -%D \groupedcommand {before} {after} -%D \stoptyping -%D -%D Which can be used like: -%D -%D \starttyping -%D \def\cite% -%D {\groupedcommand{\rightquote\rightquote}{\leftquote\leftquote}} -%D \stoptyping -%D -%D This command is equivalent to, but more 'robust' than: -%D -%D \starttyping -%D \def\cite#1% -%D {\rightquote\rightquote#1\leftquote\leftquote} -%D \stoptyping -%D -%D One should say that the next implementation would suffice: -%D -%D \starttyping -%D \def\groupedcommand#1#2% -%D {\def\BeforeGroup{#1\ignorespaces}% -%D \def\AfterGroup{\unskip#2\egroup}% -%D \bgroup\bgroup -%D \aftergroup\AfterGroup -%D \afterassignment\BeforeGroup -%D \let\next=} -%D \stoptyping -%D -%D It did indeed, but one day we decided to support the -%D processing of boxes too: -%D -%D \starttyping -%D \def\rightword% -%D {\groupedcommand{\hfill\hbox}{\parfillskip\!!zeropoint}} -%D -%D .......... \rightword{the right way} -%D \stoptyping -%D -%D Here \TEX\ typesets \type{\bf the right way} unbreakable -%D at the end of the line. The solution mentioned before does -%D not work here. -%D -%D \starttyping -%D \long\unexpanded\def\groupedcommand#1#2% -%D {\bgroup -%D \long\def\BeforeGroup% -%D {\bgroup#1\bgroup\aftergroup\AfterGroup}% -%D \long\def\AfterGroup% -%D {#2\egroup\egroup}% -%D \afterassignment\BeforeGroup -%D \let\next=} -%D \stoptyping -%D -%D We used this method some time until the next alternative -%D was needed. From now on we support both -%D -%D \starttyping -%D to be \bold{bold} or not, that's the question -%D \stoptyping -%D -%D and -%D -%D \starttyping -%D to be {\bold bold} or not, that's the question -%D \stoptyping -%D -%D This alternative checks for a \type{\bgroup} token first. -%D The internal alternative does not accept the box handling -%D mentioned before, but further nesting works all right. The -%D extra \type{\bgroup}||\type{\egroup} is needed to keep -%D \type{\AfterGroup} both into sight and local. - -\long\def\HandleGroup#1#2% - {\bgroup - \long\def\BeforeGroup{\bgroup#1\bgroup\aftergroup\AfterGroup}% - \long\def\AfterGroup {#2\egroup\egroup}% - \afterassignment\BeforeGroup - \let\next=} - -\long\def\HandleSimpleGroup#1#2% no inner group (so no kerning interference) - {\bgroup - %long\def\BeforeGroup{\bgroup#1\aftergroup\AfterGroup}% interferes - \long\def\BeforeGroup{\bgroup\aftergroup\AfterGroup#1}% - \long\def\AfterGroup {#2\egroup}% - \afterassignment\BeforeGroup - \let\next=} - -\long\def\HandleNoGroup#1#2% - {\long\def\AfterGroup{#2\egroup}% - \bgroup\aftergroup\AfterGroup#1} - -%D These macros come together in: -%D -%D \starttyping -%D \long\unexpanded\def\groupedcommand#1#2% -%D {\def\dogroupedcommand% -%D {\ifx\next\bgroup -%D \let\next=\HandleGroup -%D \else -%D \let\next=\HandleNoGroup -%D \fi -%D \next{#1}{#2}}% -%D \futurelet\next\dogroupedcommand} -%D \stoptyping -%D -%D From the missing paragraph number one can deduce that the -%D last macro is not the real one yet. I considered it a -%D nuisance that -%D -%D \starttyping -%D \color[green] -%D {as grass} -%D \stoptyping -%D -%D was not interpreted as one would expect. This is due to the -%D fact that \type{\futurelet} obeys blank spaces, and a -%D line||ending token is treated as a blank space. So the final -%D implementation became: - -%\long\unexpanded\def\groupedcommand#1#2% -% {\bgroup -% \def\dogroupedcommand% -% {\ifx\next\bgroup -% \def\\{\egroup\HandleGroup{#1}{#2}}% -% \else\ifx\next\blankspace -% \def\\ {\egroup\groupedcommand{#1}{#2}}% -% \else -% \def\\{\egroup\HandleNoGroup{#1}{#2}}% -% \fi\fi -% \\}% -% \futurelet\next\dogroupedcommand} -% -% compatible ? - -\long\unexpanded\def\groupedcommand#1#2% - {\doifnextbgroupelse{\HandleGroup{#1}{#2}}{\HandleNoGroup{#1}{#2}}} - -\long\unexpanded\def\simplegroupedcommand#1#2% - {\doifnextbgroupelse{\HandleSimpleGroup{#1}{#2}}{\HandleNoGroup{#1}{#2}}} - -%D Users should be aware of the fact that grouping can -%D interfere with ones paragraph settings that are executed -%D after the paragraph is closed. One should therefore -%D explictly close the paragraph with \type{\par}, else the -%D settings will be forgotten and not applied. So it's: -%D -%D \starttyping -%D \def\BoldRaggedCenter% -%D {\groupedcommand{\raggedcenter\bf}{\par}} -%D \stoptyping - -%D \macros -%D {checkdefined} -%D -%D The bigger the system, the greater the change that -%D user defined commands collide with those that are part of -%D the system. The next macro gives a warning when a command is -%D already defined. We considered blocking the definition, but -%D this is not always what we want. -%D -%D \starttyping -%D \checkdefined {category} {class} {command} -%D \stoptyping -%D -%D The user is warned with the suggestion to use -%D \type{CAPITALS}. This suggestion is feasible, because -%D \CONTEXT only defines lowcased macros. - -\def\showdefinederror#1#2% - {\writestatus\m!systems{#1 #2 replaces a macro, use CAPITALS!}} - -\def\checkdefined#1#2#3% - {\doifdefined{#3}{\showdefinederror{#2}{#3}}} - -%D \macros -%D {GotoPar,GetPar} -%D -%D Typesetting a paragraph in a special way can be done by -%D first grabbing the contents of the paragraph and processing -%D this contents grouped. The next macro for instance typesets -%D a paragraph in boldface. -%D -%D \starttyping -%D \def\remark#1\par% -%D {\bgroup\bf#1\egroup} -%D \stoptyping -%D -%D This macro has to be called like -%D -%D \starttyping -%D \remark some text ... ending with \par -%D \stoptyping -%D -%D Instead of \type{\par} we can of course use an empty line. -%D When we started typesetting with \TEX, we already had -%D produced lots of text in plain \ASCII. In producing such -%D simple formatted texts, we adopted an open layout, and when -%D switching to \TEX, we continued this open habit. Although -%D \TEX\ permits a cramped and badly formatted source, it adds -%D to confusion and sometimes introduces errors. So we prefer: -%D -%D \starttyping -%D \remark -%D -%D some text ... ending with an empty line -%D \stoptyping -%D -%D We are going to implement a mechanism that allows such open -%D specifications. The definition of the macro handling -%D \type{\remark} becomes: -%D -%D \starttyping -%D \def\remark% -%D {\BeforePar{\bgroup\bf}% -%D \AfterPar{\egroup}% -%D \GetPar} -%D \stoptyping -%D -%D A macro like \type{\GetPar} can be defined in several -%D ways. The recent version, the fourth one in a row, -%D originally was far more complicated, but some functionality -%D has been moved to other macros. -%D -%D We start with the more simple but in some cases more -%D appropriate alternative is \type{\GotoPar}. This one leaves -%D \type{\par} unchanged and is therefore more robust. On the -%D other hand, \type{\AfterPar} is not supported. - -\newtoks\BeforePar -\newtoks\AfterPar - -\let\endoflinetoken=^^M - -%D The original definition was: -%D -%D \starttyping -%D \def\doGotoPar -%D {\ifx\nextchar\blankspace -%D \@EA\GotoPar -%D \else\ifx\nextchar\endoflinetoken -%D \@EAEAEA\GotoPar -%D \else -%D \@EAEAEA\dodoGotoPar -%D \fi\fi} -%D -%D \def\dodoGotoPar -%D {\the\BeforePar -%D \BeforePar\emptytoks -%D \nextchar} -%D -%D \def\GotoPar -%D {\afterassignment\doGotoPar\let\nextchar=} -%D \stoptyping - -%D Its big brother \type{\GetPar} redefines the \type{\par} -%D primitive, which can lead to unexpected results, depending -%D in the context. -%D -%D \starttyping -%D \def\GetPar -%D {\expanded -%D {\BeforePar -%D {\the\BeforePar -%D \BeforePar\emptytoks -%D \bgroup -%D \def\par -%D {\egroup -%D \par -%D \the\AfterPar -%D \BeforePar\emptytoks -%D \AfterPar\emptytoks}}}% -%D \GotoPar} -%D \stoptyping - -%D However, we can implement a better alternative by using: -%D -%D \starttyping -%D \def\dowithpar#1#2% -%D {\def\handlepar##1\par{#1##1#2}% -%D \def\gobblepar\par{\dowithpar{#1}{#2}}% -%D \doifnextcharelse\par\gobblepar\handlepar} -%D \stoptyping -%D -%D Or, nicer - -\def\redowithpar\par - {\doifnextcharelse\par\redowithpar\dodowithpar}% - -\def\dowithpar#1#2% - {\def\dodowithpar##1\par{#1##1#2}% - \redowithpar\par} - -\def\redogotopar\par - {\doifnextcharelse\par\redogotopar\dodogotopar}% - -\def\dogotopar#1% - {\def\dodogotopar{#1}% - \redogotopar\par} - -%D The previosuly defined macros now become: - -\def\GetPar - {\expanded - {\dowithpar - {\the\BeforePar - \BeforePar\emptytoks} - {\the\AfterPar - \BeforePar\emptytoks - \AfterPar\emptytoks}}} - -\def\GotoPar - {\expanded - {\dogotopar - {\the\BeforePar - \BeforePar\emptytoks}}} - -%D \macros -%D {dowithpargument,dowithwargument} -%D -%D The next macros are a variation on \type{\GetPar}. When -%D macros expect an argument, it interprets a grouped sequence -%D of characters a one token. While this adds to robustness and -%D less ambiguous situations, we sometimes want to be a bit -%D more flexible, or at least want to be a bit more tolerant -%D to user input. -%D -%D We start with a commands that acts on paragraphs. This -%D command is called as: -%D -%D \starttyping -%D \dowithpargument\command -%D \dowithpargument{\command ... } -%D \stoptyping -%D -%D In \CONTEXT\ we use this one to read in the titles of -%D chapters, sections etc. The commands responsible for these -%D activities accept several alternative ways of argument -%D passing. In these examples, the \type{\par} can be omitted -%D when an empty line is present. -%D -%D \starttyping -%D \command{...} -%D \command ... \par -%D \command -%D {...} -%D \command -%D ... \par -%D \stoptyping -%D -%D We show two implementations, of which for the moment the -%D we prefier to use the second one: -%D -%D \starttyping -%D \def\dowithpargument#1% -%D {\def\dodowithpargument% -%D {\ifx\next\bgroup -%D \def\next{#1}% -%D \else -%D \def\next####1 \par{#1{####1}}% -%D \fi -%D \next}% -%D \futurelet\next\dodowithpargument} -%D \stoptyping -%D -%D A second and better implementation was: -%D -%D \starttyping -%D \def\dowithpargument#1% -%D {\def\nextpar##1 \par{#1{##1}}% -%D \def\nextarg##1{#1{##1}}% -%D \doifnextcharelse\bgroup -%D {\nextarg} -%D {\nextpar}} -%D \stoptyping -%D -%D We ended up with an alternative that also accepts en empty -%D argument. This command permits for instance chapters to -%D have no title. - -%\def\dowithpargument#1% -% {\def\nextpar##1 \par{#1{##1}}% -% \def\nextarg##1{#1{##1}}% -% \doifnextcharelse\bgroup -% {\nextarg} -% {\doifnextcharelse{\par} -% {#1{}} -% {\nextpar}}} - -\def\dowithpargument#1% - {\def\nextpar##1 \par{#1{##1}}% - \def\nextarg##1{#1{##1}}% - \doifnextbgroupelse\nextarg{\doifnextcharelse\par{#1{}}\nextpar}} - -%D The \type{p} in the previous command stands for paragraph. -%D When we want to act upon words we can use the \type{w} -%D alternative. -%D -%D \starttyping -%D \dowithwargument\command -%D \dowithwargument{... \command ...} -%D \stoptyping -%D -%D The main difference bwteen two alternatives is in the -%D handling of \type{\par}'s. This time the space token acts -%D as a delimiter. -%D -%D \starttyping -%D \command{...} -%D \command ... -%D \command -%D {...} -%D \command -%D ... -%D \stoptyping -%D -%D Again there are two implementations possible: -%D -%D \starttyping -%D \def\dowithwargument#1% -%D {\def\dodowithwargument% -%D {\ifx\next\bgroup -%D \def\next{#1}% -%D \else -%D \def\next####1 {#1{####1}}% -%D \fi -%D \next}% -%D \futurelet\next\dodowithwargument} -%D \stoptyping -%D -%D We've chosen: - -%\def\dowithwargument#1% -% {\def\nextwar##1 {#1{##1}}% -% \def\nextarg##1{#1{##1}}% -% \doifnextcharelse\bgroup -% {\nextarg} -% {\nextwar}} - -\def\dowithwargument#1% - {\def\nextwar##1 {#1{##1}}% - \def\nextarg##1{#1{##1}}% - \doifnextbgroupelse\nextarg\nextwar} - -%D \macros -%D {dorepeat,dorepeatwithcommand} -%D -%D When doing repetitive tasks, we stromgly advice to use -%D \type{\dorecurse}. The next alternative however, suits -%D better some of the \CONTEXT\ interface commands. -%D -%D \starttyping -%D \dorepeat[n*\command] -%D \stoptyping -%D -%D The value of the used \COUNTER\ can be called within -%D \type{\command} by \type{\repeater}. -%D -%D A slightly different alternative is: -%D -%D \starttyping -%D \dorepeatwithcommand[n*{...}]\command -%D \stoptyping -%D -%D When we call for something like: -%D -%D \starttyping -%D \dorepeatwithcommand[3*{Hello}]\message -%D \stoptyping -%D -%D we get ourselves three \type{\message{Hello}} messages in -%D a row. In both commands, the \type{n*} is optional. When this -%D specification is missing, the command executes once. - -% this one is obsolete: - -\def\dorepeat[#1]% - {\dodorepeat#1*\empty*\relax} - -\long\def\dodorepeat#1*#2#3*#4\relax - {\ifx#2\empty#1\else\dorecurse{#1}{#2#3}\fi} - -\def\repeater - {\recurselevel} - -% this one will be kept - -\def\dorepeatwithcommand[#1]% - {\dodorepeatwithcommand#1*\empty*\relax} - -% \long\def\dodorepeatwithcommand#1*#2#3*#4\relax#5% -% {\ifx#2\empty -% #5{#1}% -% \else -% \dorecurse{#1}{#5{#2#3}}% -% \fi} -% -% more complex but better: - -% \long\def\dodorepeatwithcommand#1*#2#3*#4\relax#5% -% {\ifx#2\empty -% #5{#1}% -% \else\ifnum#1<\zerocount -% % a la etex -% % \dorecurse{-\numexpr(#1)}{#5{-#2#3}}% -% % indirect -% %\innerrecurse#1% -% %\expanded{\dorecurse{\number-\innerrecurse}}{#5{-#2#3}}% -% % safer: -% \bgroup\scratchcounter#1% -% \expanded{\egroup\noexpand\dorecurse{\number-\scratchcounter}}{#5{-#2#3}}% -% \else\ifx#2+% -% \dorecurse{#1}{#5{#3}}% -% \else -% \dorecurse{#1}{#5{#2#3}}% -% \fi\fi\fi} - -\def\dorepeatwithcommand[#1]% - {\dodorepeatwithcommand#1*\empty*\relax} - -\long\def\dodorepeatwithcommand#1*#2#3*#4\relax#5% - {\ifx#2\empty\redorepeatwithcommand[#1]#5\else\dododorepeatwithcommand{#1}{#2}{#3}#5\fi} - -\long\def\dododorepeatwithcommand#1#2#3#4% - {\ifx#2\empty % redundant but gives cleaner extensions - #4{#1}% - \else\ifnum#1<\zerocount - \bgroup\scratchcounter#1% - \expanded{\egroup\noexpand\dorecurse{\number-\scratchcounter}}{#4{-#2#3}}% - \else\ifx#2+% - \dorecurse{#1}{#4{#3}}% - \else - \dorecurse{#1}{#4{#2#3}}% - \fi\fi\fi} - -\def\redorepeatwithcommand[#1]#2% - {#2{#1}} - -%D The extension hook permits something like: -%D -%D \starttyping -%D \bgroup -%D -%D \catcode`\*=\@@superscript -%D -%D \gdef\redorepeatwithcommand[#1]% -%D {\redodorepeatwithcommand#1*\empty*\relax} -%D -%D \long\gdef\redodorepeatwithcommand#1*#2#3*#4\relax#5% -%D {\dododorepeatwithcommand{#1}{#2}{#3}#5} -%D -%D \egroup -%D \stoptyping -%D -%D although one may wonder if changing the catcode of \type {*} is wise. - -%D \macros -%D {normalbgroup,normalgroup} -%D -%D No comment. - -\let\normalbgroup\bgroup -\let\normalegroup\egroup - -%D \macros -%D {doifstringinstringelse} -%D -%D The next macro is meant for situations where both strings -%D are macros. This save some unneeded expansion. -%D -%D \starttyping -%D \long\def\doifstringinstringelse#1#2% -%D {\p!doifinstringelse#1#2% -%D \@EA\firstoftwoarguments -%D \else -%D \@EA\secondoftwoarguments -%D \fi} -%D \stoptyping -%D -%D A bit faster is: - -\def\pp!doifstringinstringelse#1% - {\if#1@% - \@EA\secondoftwoarguments - \else - \@EA\firstoftwoarguments - \fi} - -\long\def\doifstringinstringelse#1#2% - {\long\@EA\def\@EA\p!doifstringinstringelse\@EA##\@EA1#1##2##3\war - {\pp!doifstringinstringelse##2}% - \@EA\@EA\@EA\p!doifstringinstringelse\@EA#2#1@@\war} - -%D \macros -%D {appendtoks,prependtoks,appendtoksonce,prependtoksonce, -%D doifintokselse,flushtoks,dotoks} -%D -%D We use \TOKENLISTS\ sparsely within \CONTEXT, because the -%D comma separated lists are more suitable for the user -%D interface. Nevertheless we have: -%D -%D \starttyping -%D (\doglobal) \appendtoks ... \to\tokenlist -%D (\doglobal) \prependtoks ... \to\tokenlist -%D (\doglobal) \flushtoks\tokenlist -%D \dotoks\tokenlist -%D \stoptyping -%D -%D Er worden eerst enkele klad||registers gedefinieerd. These -%D macros are clones of the ones implemented in page~378 of -%D Knuth's \TeX book. -%D -%D A simple implementation, one that does not handle braces -%D at the outer level, is: -%D -%D \starttyping -%D \def\appendtoks#1\to#2% -%D {\scratchtoks={#1}% -%D \expanded{\dodoglobal\noexpand#2{\the#2\the\scratchtoks}}} -%D -%D \def\prependtoks#1\to#2% -%D {\scratchtoks={#1}% -%D \expanded{\dodoglobal\noexpand#2{\the\scratchtoks\the#2}}} -%D \stoptyping -%D -%D But here we prefer: - -\newtoks\@@scratchtoks - -% before we had the once only alternatives, we had: -% -% \def\appendtoks {\doappendtoks \relax} -% \def\prependtoks{\doprependtoks\relax} -% -% \long\def\doappendtoks#1\to#2% -% {\@@scratchtoks\@EA{\gobbleoneargument#1}% -% \expanded{\dodoglobal\noexpand#2{\the#2\the\@@scratchtoks}}} -% -% \long\def\doprependtoks#1\to#2% -% {\@@scratchtoks\@EA{\gobbleoneargument#1}% -% \expanded{\dodoglobal\noexpand#2{\the\@@scratchtoks\the#2}}} - -\def\appendtoks {\doappendtoks \relax} -\def\prependtoks {\doprependtoks \relax} -\def\appendtoksonce {\doappendtoksonce \relax} -\def\prependtoksonce{\doprependtoksonce\relax} - -% \def\dodoappendtoks#1% -% {\expanded{\dodoglobal\noexpand#1{\the#1\the\@@scratchtoks}}} -% -% \def\dodoprependtoks#1% -% {\expanded{\dodoglobal\noexpand#1{\the\@@scratchtoks\the#1}}} -% -% \long\def\doappendtoks#1\to% -% {\@@scratchtoks\@EA{\gobbleoneargument#1}\dodoappendtoks} -% -% \long\def\doprependtoks#1\to% -% {\@@scratchtoks\@EA{\gobbleoneargument#1}\dodoprependtoks} -% -% \long\def\doappendtoksonce#1\to#2% -% {\@@scratchtoks\@EA{\gobbleoneargument#1}% -% \doifintokselse\@@scratchtoks{#2}{}{\dodoappendtoks{#2}}} -% -% \long\def\doprependtoksonce#1\to#2% -% {\@@scratchtoks\@EA{\gobbleoneargument#1}% -% \doifintokselse\@@scratchtoks{#2}{}{\dodoprependtoks{#2}}} -% -% A slightly (but in the case of large arguments -% significantly) faster alternative is given below: - -\newtoks\@@toks - -\def\dodoappendtoks - {\dodoglobal\@@toks\@EAEAEA{\@EA\the\@EA\@@toks\the\@@scratchtoks}} - -\def\dodoprependtoks - {\dodoglobal\@@toks\@EAEAEA{\@EA\the\@EA\@@scratchtoks\the\@@toks}} - -\long\def\doappendtoks#1\to#2% - {\def\@@toks{#2}% - \@@scratchtoks\@EA{\gobbleoneargument#1}\dodoappendtoks} - -\long\def\doprependtoks#1\to#2% - {\def\@@toks{#2}% - \@@scratchtoks\@EA{\gobbleoneargument#1}\dodoprependtoks} - -\long\def\doappendtoksonce#1\to#2% - {\def\@@toks{#2}% - \@@scratchtoks\@EA{\gobbleoneargument#1}% - \doifintokselse\@@scratchtoks\@@toks\donothing\dodoappendtoks} - -\long\def\doprependtoksonce#1\to#2% - {\def\@@toks{#2}% - \@@scratchtoks\@EA{\gobbleoneargument#1}% - \doifintokselse\@@scratchtoks\@@toks\donothing\dodoprependtoks} - -%D The test macro: -%D -%D \starttyping -%D \def\doifintokselse#1#2% #1 en #2 zijn toks -%D {\edef\!!stringa{\the#1}\convertcommand\!!stringa\to\asciia -%D \edef\!!stringb{\the#2}\convertcommand\!!stringb\to\asciib -%D \doifinstringelse\asciia\asciib} -%D \stoptyping -%D -%D Better: -%D -%D \starttyping -%D \def\doifintokselse#1#2% #1 en #2 zijn toks -%D {\edef\!!stringa{\the#1}\convertcommand\!!stringa\to\asciia -%D \edef\!!stringb{\the#2}\convertcommand\!!stringb\to\asciib -%D \doifstringinstringelse\asciia\asciib} -%D \stoptyping -%D -%D Even better: - -\beginETEX - - \def\doifintokselse#1#2% #1 en #2 zijn toks - {\@EA\convertargument\the#1\to\asciia - \@EA\convertargument\the#2\to\asciib - \doifstringinstringelse\asciia\asciib} - -\endETEX - -\beginTEX - - \def\doifintokselse#1#2% #1 en #2 zijn toks - {\edef\asciia{\the#1}\convertcommand\asciia\to\asciia - \edef\asciib{\the#2}\convertcommand\asciib\to\asciib - \doifstringinstringelse\asciia\asciib} - -\endTEX - -%D Also: - -\def\appendetoks #1\to{\expanded{\appendtoks #1}\to} -\def\prependetoks#1\to{\expanded{\prependtoks#1}\to} - -%D Hm. - -\def\flushtoks#1% nb: can reassing to #1 again, hence the indirectness - {\@@scratchtoks#1\relax - \dodoglobal#1\emptytoks - \the\@@scratchtoks\relax} - -\let\dotoks\the - -%D \macros -%D {makecounter,pluscounter,minuscounter, -%D resetcounter,setcounter,countervalue} -%D -%D Declaring, setting and resetting \COUNTERS\ can be doen -%D with the next set of commands. -%D -%D \starttyping -%D \makecounter {name} -%D \pluscounter {name} -%D \minuscounter {name} -%D \resetcounter {name} -%D \setcounter {name} {value} -%D \countervalue {name} -%D \stoptyping -%D -%D We prefer the use of global counters. This means that we -%D have to load \PLAIN\ \TEX\ in a bit different way: -%D -%D \starttyping -%D \let\oldouter=\outer -%D \let\outer=\relax -%D \input plain.tex -%D \let\outer=\oldouter -%D -%D \def\newcount% -%D {\alloc@0\count\countdef\insc@unt} -%D \stoptyping -%D -%D First we show a solution in which we use real \COUNTERS. -%D Apart from some expansion, nothing special is done. -%D -%D \starttyping -%D \def\makecounter#1% -%D {\expandafter\newcount\csname#1\endcsname} -%D -%D \def\pluscounter#1% -%D {\global\advance\csname#1\endcsname by 1 } -%D -%D \def\minuscounter#1% -%D {\global\advance\csname#1\endcsname by -1 } -%D -%D \def\resetcounter#1% -%D {\expandafter\global\csname#1\endcsname=0 } -%D -%D \def\setcounter#1#2% -%D {\expandafter\global\csname#1\endcsname=#2 } -%D -%D \def\countervalue#1% -%D {\the\getvalue{#1}} -%D \stoptyping -%D -%D Because these macros are already an indirect way of working -%D with counters, there is no harm in using pseudo \COUNTERS\ -%D here: - -\def\makecounter#1% - {\letgvalue{#1}\zerocountervalue} % see earlier - -% \def\countervalue#1% -% {\getvalue{#1}} - -\let\countervalue\getvalue - -\def\pluscounter#1% - {\scratchcounter\getvalue{#1}% - \advance\scratchcounter \plusone - \setxvalue{#1}{\the\scratchcounter}} - -\def\minuscounter#1% - {\scratchcounter\getvalue{#1}% - \advance\scratchcounter \minusone - \setxvalue{#1}{\the\scratchcounter}} - -\def\resetcounter#1% - {\letgvalue{#1}\zerocountervalue} - -\def\setcounter#1#2% or: \setxvalue{#1}{\number#2} - {\scratchcounter#2% - \setxvalue{#1}{\the\scratchcounter}} - -\def\incrementcounter#1#2% #1 name #2 value - {\setxvalue{#1}{\the\numexpr\csname#1\endcsname+#2\relax}} - -\def\decrementcounter#1#2% #1 name #2 value - {\setxvalue{#1}{\the\numexpr\csname#1\endcsname-#2\relax}} - -%D \macros -%D {savecounter,restorecounter} -%D -%D These two commands can be used to save and restore counter -%D values. Only one level is saved. - -\def\savecounter#1% - {{\scratchcounter\getvalue {#1}\setxvalue{!#1}{\the\scratchcounter}}} - -\def\restorecounter#1% - {{\scratchcounter\getvalue{!#1}\setxvalue {#1}{\the\scratchcounter}}} - -% == {\setxvalue{#1}{\getvalue{!#1}}} - -%D The next \ETEX\ based solution is some 15\% faster, which -%D goes unnoticed in any normal run, simply because these -%D macros are not used milions of times. - -\beginETEX \numexpr - -\def\makecounter#1% - {\global\@EA\let\csname#1\endcsname\zerocountervalue} % see earlier - -\def\countervalue#1% - {\ifcsname#1\endcsname\csname#1\endcsname\fi} - -\def\pluscounter#1% - {\@EA\xdef\csname#1\endcsname{\the\numexpr\csname#1\endcsname+\plusone\relax}} - -\def\minuscounter#1% - {\@EA\xdef\csname#1\endcsname{\the\numexpr\csname#1\endcsname-\plusone\relax}} - -\def\resetcounter#1% - {\global\@EA\let\csname#1\endcsname\zerocountervalue} - -\def\setcounter#1#2% - {\@EA\xdef\csname#1\endcsname{\the\numexpr#2\relax}} - -\def\savecounter#1% - {\@EA\xdef\csname !#1\endcsname{\the\numexpr\csname#1\endcsname\relax}} - -\def\restorecounter#1% - {\@EA\xdef\csname#1\endcsname{\the\numexpr\csname !#1\endcsname\relax}} - -\endETEX - -%D \macros -%D {beforesplitstring,aftersplitstring} -%D -%D These both commands split a string at a given point in two -%D parts, so \type{x.y} becomes \type{x} or \type{y}. -%D -%D \starttyping -%D \beforesplitstring test.tex\at.\to\filename -%D \aftersplitstring test.tex\at.\to\extension -%D \stoptyping -%D -%D The first routine looks (and is indeed) a bit simpler than -%D the second one. The alternative looking more or less like -%D the first one did not always give the results we needed. -%D Both implementations show some insight in the manipulation -%D of arguments. - -\def\beforesplitstring#1\at#2\to#3% - {\def\dosplitstring##1#2##2#2##3\\% - {\def#3{##1}}% - \@EA\dosplitstring#1#2#2\\} - -\def\aftersplitstring#1\at#2\to#3% - {\def\dosplitstring##1#2##2@@@##3\\% - {\def#3{##2}}% - \@EA\dosplitstring#1@@@#2@@@\\} - -%D \macros -%D {splitstring,greedysplitstring} -%D -%D A bonus macro. - -\def\splitstring#1\at#2\to#3\and#4% - {\def\dosplitstring##1#2##2\empty\empty\empty##3\\% - {\def#3{##1}% - \def\dosplitstring{##3}% - \ifx\dosplitstring\empty - \let#4\empty - \else - \def#4{##2}% - \fi}% - \@EA\dosplitstring#1\empty\empty\empty#2\empty\empty\empty\\} - -% Ok, but not for all cases: -% -% \def\greedysplitstring#1\at#2\to#3\and#4% -% {\edef\asciib{#1}% -% \let\asciic\asciib -% \let#3\empty -% \let#4\empty -% \doloop -% {\expandafter\splitstring\asciib\at#2\to\asciia\and\asciib -% \ifx\asciib\empty -% \exitloop -% \else -% \edef#3{\ifx#3\empty\else#3#2\fi\asciia}% -% \let#4\asciib -% \fi}% -% \ifx#3\empty\let#3\asciic\fi} -% -% The next one is some 25\% faster, but it hardly matters because -% we seldom use this macro. -% -% \def\greedysplitstring#1\at#2\to#3\and#4% -% {\edef\asciib{#1}% -% \let\asciic\asciib -% \let#3\empty -% \let#4\empty -% \def\dogreedysplitstring -% {\expandafter\splitstring\asciib\at#2\to\asciia\and\asciib -% \ifx\asciib\empty -% \expandafter\dogreedysplitstring -% \else -% \edef#3{\ifx#3\empty\else#3#2\fi\asciia}% -% \let#4\asciib -% \fi}% -% \dogreedysplitstring -% \ifx#3\empty\let#3\asciic\fi} -% -% The better alternative: - -\def\greedysplitstring#1\at#2\to#3\and#4% - {\edef\asciib{#1}% - \let\asciic\asciib - \let#3\empty - \let#4\empty - \doloop - {\expandafter\splitstring\asciib\at#2\to\asciia\and\asciib - \ifx\asciib\empty - \exitloop - \else - % not \edef#3{\ifx#3\empty\else#3#2\fi\asciia} else - % /root/path fails because then #3==empty - \edef#3{\ifcase\recurselevel\or\else#3#2\fi\asciia}% - \let#4\asciib - \fi}% - \ifx#3\empty\let#3\asciic\fi} - -%D \macros -%D {beforetestandsplitstring, -%D aftertestandsplitstring, -%D testandsplitstring} -%D -%D The next alternatives are for Simon Pepping. This time -%D the result is empty when no split is done. - -% \def\beforetestandsplitstring#1\at#2\to#3% -% {\def\dosplitstring##1#2##2#2##3\\{\doifelsenothing -% {##3}{\let#3\empty}{\def#3{##1}}}% -% \@EA\dosplitstring#1#2#2\\} -% -% \def\aftertestandsplitstring#1\at#2\to#3% -% {\def\dosplitstring ##1#2##2@@@##3\\{\doifelsenothing -% {##3}{\let#3\empty}{\def#3{##2}}}% -% \@EA\dosplitstring #1@@@#2@@@\\} -% -% \def\testandsplitstring#1\at#2\to#3\and#4% -% {\def\dosplitstring##1#2##2#2##3\\{\doifelsenothing -% {##3}{\let#3\empty\let#4\empty}{\def#3{##1}\def#4{##2}}}% -% \@EA\dosplitstring#1#2#2\\} -% -% faster: - -\def\beforetestandsplitstring#1\at#2\to#3% - {\def\dosplitstring##1#2##2#2##3##4\\% - {\ifx##3\empty\let#3\empty\else\def#3{##1}\fi}% - \@EA\dosplitstring#1#2#2\empty\\} - -\def\aftertestandsplitstring#1\at#2\to#3% - {\def\dosplitstring ##1#2##2@@@##3##4\\% - {\ifx##3\empty\let#3\empty\else\def#3{##2}\fi}% - \@EA\dosplitstring #1@@@#2@@@\empty\\} - -\def\testandsplitstring#1\at#2\to#3\and#4% - {\def\dosplitstring##1#2##2#2##3##4\\% - {\ifx##3\empty\let#3\empty\let#4\empty\else\def#3{##1}\def#4{##2}\fi}% - \@EA\dosplitstring#1#2#2\empty\\} - -%D \macros -%D {removesubstring} -%D -%D A first application of the two routines defined above is: -%D -%D \starttyping -%D \removesubstring-\from first-last\to\nothyphenated -%D \stoptyping -%D -%D Which in terms of \TEX\ looks like: - -%\def\removesubstring#1\from#2\to#3% -% {\doifinstringelse{#1}{#2} -% {\beforesplitstring#2\at#1\to\!!stringa -% \aftersplitstring #2\at#1\to\!!stringb -% \edef#3{\!!stringa\!!stringb}% -% \removesubstring#1\from#3\to#3} -% {}} - -\def\removesubstring#1\from#2\to#3% - {\splitstring#2\to\!!stringa\and\!!stringb - \dodoglobal#3{\!!stringa\!!stringb}} - -%D \macros -%D {appendtocommalist,prependtocommalist, -%D addtocommalist,removefromcommalist} -%D -%D When working with comma separated lists, one sooner or -%D later want the tools to append or remove items from such a -%D list. When we add an item, we first check if it's already -%D there. This means that every item in the list is unique. -%D -%D \starttyping -%D \addtocommalist {alfa} \name -%D \addtocommalist {beta} \name -%D \addtocommalist {gamma} \name -%D \removefromcommalist {beta} \name -%D \stoptyping -%D -%D These commands can be prefixed with \type{\doglobal}. The -%D implementation of the second command is more complecated, -%D because we have to take leading spaces into account. Keep in -%D mind that users may provide lists with spaces after the -%D commas. When one item is left, we also have to get rid of -%D trailing spaces. -%D -%D \starttyping -%D \def\words{alfa, beta, gamma, delta} -%D \def\words{alfa,beta,gamma,delta} -%D \stoptyping -%D -%D Removing an item takes more time than adding one. -%D -%D A fast appending alternative, without any testing, is -%D also provided: -%D -%D \starttyping -%D \appendtocommalist {something} \name -%D \prependtocommalist {something} \name -%D \stoptyping -%D -%D This can be implemented as follows: -%D -%D \starttyping -%D \def\appendtocommalist#1#2% -%D {\ifx#2\empty -%D \dodoglobal\edef#2{#1}% -%D \else % no test on empty -%D \dodoglobal\edef#2{#2,#1}% -%D \fi} -%D -%D \def\prependtocommalist#1#2% -%D {\ifx#2\empty -%D \dodoglobal\edef#2{#1}% -%D \else % no test on empty -%D \dodoglobal\edef#2{#1,#2}% -%D \fi} -%D \stoptyping -%D -%D The faster alternatives are: - -\def\appendtocommalist#1#2% - {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}} - -\def\prependtocommalist#1#2% - {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}} - -%D The old ones are: -%D -%D \starttyping -%D \def\addtocommalist#1#2% -%D {\ifx#2\empty -%D \dodoglobal\edef#2{#1}% -%D \else -%D \edef\!!stringa{#2,,}% -%D \beforesplitstring#2\at,,\to#2\relax -%D \ExpandBothAfter\doifinsetelse{#1}{#2} -%D {\resetglobal} -%D {\dodoglobal\edef#2{#2,#1}}% -%D \fi} -%D -%D \def\pretocommalist#1#2% -%D {\ifx#2\empty -%D \dodoglobal\edef#2{#1}% -%D \else -%D \edef\!!stringa{#2,,}% -%D \beforesplitstring#2\at,,\to#2\relax -%D \ExpandBothAfter\doifinsetelse{#1}{#2} -%D {\resetglobal} -%D {\dodoglobal\edef#2{#1,#2}}% -%D \fi} -%D -%D \def\doremovefromcommalist#1#2#3% nog \doglobal -%D {\edef\!!stringa{,,#3,,}% -%D \beforesplitstring\!!stringa\at,#1#2,\to\!!stringb -%D \aftersplitstring\!!stringa\at,#1#2,\to\!!stringc -%D \edef#3{\!!stringb,\!!stringc}% -%D \aftersplitstring#3\at,,\to#3\relax -%D \beforesplitstring#3\at,,\to#3} -%D -%D \def\removefromcommalist#1#2% -%D {\doremovefromcommalist{ }{#1}{#2}% -%D \doremovefromcommalist{}{#1}{#2}% -%D \dofrontstrip#2% -%D \dodoglobal\edef#2{#2}} -%D \stoptyping -%D -%D Significantly faster (especially for longer lists): - -\def\addtocommalist#1#2% {item} \cs - {\rawdoifinsetelse{#1}#2\resetglobal - {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}} - -\def\pretocommalist#1#2% {item} \cs - {\rawdoifinsetelse{#1}#2\resetglobal - {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}} - -\def\robustdoifinsetelse#1#2% - {\expanded{\convertargument#1}\to\!!stringa - \expanded{\convertargument#2}\to\!!stringb - \rawdoifinsetelse\!!stringa\!!stringb} - -\def\robustaddtocommalist#1#2% {item} \cs - {\robustdoifinsetelse{#1}#2\resetglobal - {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}} - -\def\robustpretocommalist#1#2% {item} \cs - {\robustdoifinsetelse{#1}#2\resetglobal - {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}} - -\def\xsplitstring#1#2% \cs {str} - {\def\dosplitstring##1,#2,##2,#2,##3\\% - {\edef\!!stringa{\bcleanedupcommalist##1\empty\empty\relax}% - \edef\!!stringb{\acleanedupcommalist##2,,\relax}}% - \@EA\dosplitstring\@EA,#1,,#2,,#2,\\} - -\def\bcleanedupcommalist#1#2#3\relax{\if#1,\else#1\fi\if#2,\else#2\fi#3} -\def\bcleanedupcommalist#1#2\relax{\if#1,\else#1\fi#2} -\def\acleanedupcommalist#1,,#2\relax{#1} - -% \def\removefromcommalist#1#2% -% {\expanded{\xsplitstring\noexpand#2{#1}}% -% \dodoglobal\edef#2% -% {\ifx\!!stringa\empty -% \!!stringb -% \else -% \@EA\acleanedupcommalist\!!stringa,,\relax -% \ifx\!!stringb\empty\else,\!!stringb\fi -% \fi}} - -\def\removefromcommalist#1#2% - {\rawdoifinsetelse{#1}#2% - {\expanded{\xsplitstring\noexpand#2{#1}}% - \dodoglobal\edef#2% - {\ifx\!!stringa\empty - \!!stringb - \else - \!!stringa\ifx\!!stringb\empty\else,\!!stringb\fi - \fi}} - \resetglobal} - -%D \macros -%D {substituteincommalist} -%D -%D Slow but seldom used, so for the moment we stick to this -%D implementation. -%D -%D \starttyping -%D \substituteincommalist{old}{new}{list} -%D \stoptyping - -\def\substituteincommalist#1#2#3% old, new, list (slooow) - {\edef\!!stringb{#1}% - \edef\!!stringd{#2}% - \let\!!stringa#3% - \let#3\empty - \def\dosubstituteincommalist##1% - {\edef\!!stringc{##1}% - \ifx\!!stringb\!!stringc - \ifx\!!stringd\empty\else - \edef#3{#3\ifx#3\empty\else,\fi\!!stringd}% - \fi - \def\docommand####1{\edef#3{#3,####1}}% - \else - \edef#3{#3\ifx#3\empty\else,\fi##1}% - \fi}% - \@EA\rawprocesscommacommand\@EA[\!!stringa]\dosubstituteincommalist} - -%D A not so useful macro: - -\def\dodofrontstrip[#1#2]#3% - {\ifx#1\space - \def#3{#2}% - \else - \def#3{#1#2}% - \fi} - -\def\dofrontstrip#1% - {\edef\!!stringa{#1}% - \ifx\!!stringa\empty \else - \@EA\dodofrontstrip\@EA[#1]#1% - \fi} - -%D \macros -%D {replaceincommalist} -%D -%D The next macro can be used to replace an indexed element -%D in a commalist: -%D -%D \starttyping -%D \replaceincommalist\MyList{2} -%D \stoptyping -%D -%D Element~2 will be replaced by the current meaning of the macro -%D \type {\newcommalistelement}. The old meaning is saved in -%D \type {\commalistelement}. The replacement honors grouped items, -%D like in: -%D -%D \starttyping -%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3} -%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3} -%D \def\MyList{a,{b,c},d,e,f} \replaceincommalist\MyList{3} -%D \def\MyList{a,b,c,{d,e,f}} \replaceincommalist\MyList{3} -%D \stoptyping - -\let\newcommalistelement\empty - -\def\replaceincommalist#1#2% #1 = commalistelement #2 = position starts at 1 - {\def\doreplaceincommalist##1% - {\ifnum\commalistcounter=#2\relax - \ifx\newcommalistelement\empty\else - \ifx\newcommalist\empty - \let\newcommalist\newcommalistelement - \else - \@EA\@EA\@EA\def\@EA\@EA\@EA\newcommalist\@EA\@EA\@EA - {\@EA\newcommalist\@EA,\newcommalistelement}% - \fi - \fi - \def\commalistelement{##1}% - \else - \ifx\newcommalist\empty - \ifx\nexttoken\bgroup % is known -) - \def\newcommalist{{##1}}% - \else - \def\newcommalist{##1}% - \fi - \else - \ifx\nexttoken\bgroup % is known -) - \@EA\def\@EA\newcommalist\@EA{\newcommalist,{##1}}% - \else - \@EA\def\@EA\newcommalist\@EA{\newcommalist,##1}% - \fi - \fi - \fi - \advance\commalistcounter\plusone}% - \let\commalistelement\empty - \let\newcommalist\empty - \commalistcounter\plusone - \@EA\processcommalist\@EA[#1]\doreplaceincommalist - \dodoglobal\let#1\newcommalist} - -%D \macros -%D {globalprocesscommalist} -%D -%D The commalist processing commands are characterized by the -%D fact that the way they handle expansion as well as the fact -%D that they can be nested. This makes them kind of useless for -%D handling comma lists in alignments. In these situations the -%D next macro can be of use. - -\def\globalprocesscommaitem#1,% - {\if]#1\else - \globalcommacommand{#1}% - \expandafter\globalprocesscommaitem - \fi} - -\def\globalprocesscommalist[#1]#2% - {\global\let\globalcommacommand#2% - \expandafter\globalprocesscommaitem#1,],} - -%D \macros -%D {startprocesscommalist,startprocesscommacommand} -%D -%D Two more: - -\long\def\startprocesscommalist[#1]#2\stopprocesscommalist - {\long\def\currentcommalistcommand##1{\def\currentcommalistitem{##1}#2}% - \processcommalist[#1]\currentcommalistcommand} - -\long\def\startprocesscommacommand[#1]#2\stopprocesscommacommand - {\long\def\currentcommalistcommand##1{\def\currentcommalistitem{##1}#2}% - \processcommacommand[#1]\currentcommalistcommand} - -%D \macros -%D {withoutpt,PtToCm, -%D numberofpoints,dimensiontocount} -%D -%D We can convert point into centimeters with: -%D -%D \starttyping -%D \PtToCm{dimension} -%D \stoptyping - -{\catcode`\.=\@@other - \catcode`\p=\@@other - \catcode`\t=\@@other - \gdef\WITHOUTPT#1pt{#1}} - -\def\withoutpt#1% - {\expandafter\WITHOUTPT#1} - -%D The capitals are needed because \type{p} and \type{t} have -%D \CATCODE~12, while macronames only permit tokens with the -%D \CATCODE~11. As a result we cannot use the \type{.group} -%D primitives. Those who want to know more about this kind of -%D manipulations, we advice to study the \TEX book in detail. -%D Because this macro does not do any assignment, we can use it -%D in the following way too. - -\def\PtToCm#1% - {\begingroup - \scratchdimen#1\relax - \scratchdimen0.0351459804\scratchdimen % 2.54/72.27 - \withoutpt\the\scratchdimen cm% - \endgroup} - -%D We also support: -%D -%D \starttyping -%D \numberofpoints {dimension} -%D \dimensiontocount {dimension} {\count} -%D \stoptyping -%D -%D Both macros return a rounded number. - -% \dimensiontocount{10.49pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.49pt} -% \dimensiontocount{10.51pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.51pt} - -\def\dimensiontocount#1#2{#2\numexpr\dimexpr#1\relax/\maxcard\relax} -\def\numberofpoints #1{\the\numexpr\dimexpr#1\relax/\maxcard\relax} - -%D \macros -%D {swapdimens,swapmacros} -%D -%D Simple but effective are the next two macros. There name -%D exactly states their purpose. The \type{\scratchdimen} and -%D \type{\!!stringa} can only be swapped when being the first -%D argument. - -\def\swapdimens#1#2% - {\scratchdimen #1\redoglobal #1#2\dodoglobal #2\scratchdimen} - -\def\swapmacros#1#2% - {\let\!!stringa#1\redoglobal\let#1#2\dodoglobal\let#2\!!stringa} - -%D \macros -%D {pushmacro,popmacro} -%D -%D Premature and a bit of beta, we offer: -%D -%D \starttyping -%D \pushmacro\macro -%D \popmacro\macro -%D \stoptyping -%D -%D Beware: global! - -% \def\@s@{@s@} -% -% \beginTEX -% -% \def\globalpushmacro#1% we can use a faster incement here -% {\@EA\doglobal\@EA\increment\csname\@s@*\string#1\endcsname -% \global\@EA\let\csname\csname\@s@*\string#1\endcsname*\string#1\endcsname#1} -% -% \def\globalpopmacro#1% \global\let -% {\global\@EA\let\@EA#1\csname\csname\@s@*\string#1\endcsname*\string#1\endcsname -% \@EA\doglobal\@EA\decrement\csname\@s@*\string#1\endcsname} -% -% \def\localpushmacro#1% this one can be used to push a value over an \egroup -% {\@EA\doglobal\@EA\increment\csname\@s@**\string#1\endcsname -% \global\@EA\let\csname\csname\@s@**\string#1\endcsname**\string#1\endcsname#1} -% -% \def\localpopmacro#1% \local\let -% {\@EA\let\@EA#1\csname\csname\@s@**\string#1\endcsname**\string#1\endcsname -% \global\@EA\decrement\csname\@s@**\string#1\endcsname} -% -% \endTEX -% -% \beginETEX \newcount -% -% \def\globalpushmacro#1% -% {\ifcsname\@s@*\string#1\endcsname \else -% \@EA\newcount\csname\@s@*\string#1\endcsname -% \fi -% \global\advance\csname\@s@*\string#1\endcsname \plusone -% \global\@EA\let\csname\the\csname\@s@*\string#1\endcsname*\string#1\endcsname#1} -% -% \def\globalpopmacro#1% \global\let -% {\global\@EA\let\@EA#1\csname\the\csname\@s@*\string#1\endcsname*\string#1\endcsname -% \global\advance\csname\@s@*\string#1\endcsname \minusone} -% -% \def\localpushmacro#1% this one can be used to push a value over an \egroup -% {\ifcsname\@s@**\string#1\endcsname \else -% \@EA\newcount\csname\@s@**\string#1\endcsname -% \fi -% \global\advance\csname\@s@**\string#1\endcsname \plusone -% \global\@EA\let\csname\the\csname\@s@**\string#1\endcsname**\string#1\endcsname#1} -% -% \def\localpopmacro#1% \local\let -% {\@EA\let\@EA#1\csname\the\csname\@s@**\string#1\endcsname**\string#1\endcsname -% \global\advance\csname\@s@**\string#1\endcsname \minusone } -% -% \endETEX -% -% some 5% faster (used a lot in typescripts, so ...) - -\def\@sl@{@sl@} -\def\@sg@{@sg@} - -\let\@@pushedmacro\empty - -\beginTEX - -\def\globalpushmacro#1% we can use a faster incement here - {\xdef\@@pushedmacro{\string#1}% - \@EA\doglobal\@EA\increment\csname\@sg@\@@pushedmacro\endcsname - \global\@EA\let\csname\csname\@sg@\@@pushedmacro\endcsname\@@pushedmacro\endcsname#1} - -\def\globalpopmacro#1% - {\xdef\@@pushedmacro{\string#1}% - \global\@EA\let\@EA#1\csname\csname\@sg@\@@pushedmacro\endcsname\@@pushedmacro\endcsname - \@EA\doglobal\@EA\decrement\csname\@sg@\@@pushedmacro\endcsname} - -\def\localpushmacro#1% this one can be used to push a value over an \egroup - {\xdef\@@pushedmacro{\string#1}% - \@EA\doglobal\@EA\increment\csname\@sl@\@@pushedmacro\endcsname - \global\@EA\let\csname\csname\@sl@\@@pushedmacro\endcsname\@@pushedmacro\endcsname#1} - -\def\localpopmacro#1% - {\xdef\@@pushedmacro{\string#1}% - \@EA\let\@EA#1\csname\csname\@sl@\@@pushedmacro\endcsname\@@pushedmacro\endcsname - \global\@EA\decrement\csname\@sl@\@@pushedmacro\endcsname} - -\endTEX - -\beginETEX - -\def\globalpushmacro#1% - {\xdef\@@pushedmacro{\string#1}% - \ifcsname\@sg@\@@pushedmacro\endcsname \else - \@EA\newcount\csname\@sg@\@@pushedmacro\endcsname - \fi - \global\advance\csname\@sg@\@@pushedmacro\endcsname \plusone - \global\@EA\let\csname\the\csname\@sg@\@@pushedmacro\endcsname\@@pushedmacro\endcsname#1} - -\def\globalpopmacro#1% - {\xdef\@@pushedmacro{\string#1}% - \global\@EA\let\@EA#1\csname\the\csname\@sg@\@@pushedmacro\endcsname\@@pushedmacro\endcsname - \global\advance\csname\@sg@\@@pushedmacro\endcsname \minusone} - -\def\localpushmacro#1% this one can be used to push a value over an \egroup - {\xdef\@@pushedmacro{\string#1}% - \ifcsname\@sl@\@@pushedmacro\endcsname \else - \@EA\newcount\csname\@sl@\@@pushedmacro\endcsname - \fi - \global\advance\csname\@sl@\@@pushedmacro\endcsname \plusone - \global\@EA\let\csname\the\csname\@sl@\@@pushedmacro\endcsname\@@pushedmacro\endcsname#1} - -\def\localpopmacro#1% - {\xdef\@@pushedmacro{\string#1}% - \@EA\let\@EA#1\csname\the\csname\@sl@\@@pushedmacro\endcsname\@@pushedmacro\endcsname - \global\advance\csname\@sl@\@@pushedmacro\endcsname \minusone } - -\endETEX - -% \let\pushmacro\globalpushmacro -% \let\popmacro \globalpopmacro - -\let\pushmacro\localpushmacro -\let\popmacro \localpopmacro - -%D \macros -%D {setlocalhsize} -%D -%D Sometimes we need to work with the \type{\hsize} that is -%D corrected for indentation and left and right skips. The -%D corrected value is available in \type{\localhsize}, which -%D needs to be calculated with \type{\setlocalhsize} first. -%D -%D \starttyping -%D \setlocalhsize \hbox to \localhsize{...} -%D \setlocalhsize[-1em] \hbox to \localhsize{...} -%D \setlocalhsize[.5ex] \hbox to \localhsize{...} -%D \stoptyping -%D -%D These examples show us that an optional can be used. The -%D value provided is added to \type{\localhsize}. - -\newdimen\localhsize - -\def\complexsetlocalhsize[#1]% don't change ! - {\localhsize\hsize - \ifnum\hangafter<\zerocount - \advance\localhsize\ifdim\hangindent>\zeropoint-\fi\hangindent - \fi - \advance\localhsize -\leftskip - \advance\localhsize -\rightskip - \advance\localhsize #1\relax} - -\def\simplesetlocalhsize - {\complexsetlocalhsize[\zeropoint]} - -\definecomplexorsimple\setlocalhsize - -%D \macros -%D {doifvalue,doifnotvalue,doifelsevalue, -%D doifnothing,doifsomething,doifelsenothing, -%D doifvaluenothing,doifvaluesomething,doifelsevaluenothing} -%D -%D These long named \type{\if} commands can be used to access -%D macros (or variables) that are normally accessed by using -%D \type{\getvalue}. Using these alternatives safes us three -%D tokens per call. Anyone familiar with the not||values -%D ones, can derive their meaning from the definitions. - - \def\doifvalue#1{\doif {\csname#1\endcsname}} - \def\doifnotvalue#1{\doifnot {\csname#1\endcsname}} - \def\doifelsevalue#1{\doifelse{\csname#1\endcsname}} - - \def\doifnothing#1{\doif {#1}{}} - \def\doifsomething#1{\doifnot {#1}{}} - \def\doifelsenothing#1{\doifelse{#1}{}} - - \def\doifvaluenothing#1{\doif {\csname#1\endcsname}{}} - \def\doifvaluesomething#1{\doifnot {\csname#1\endcsname}{}} -\def\doifelsevaluenothing#1{\doifelse{\csname#1\endcsname}{}} - -%D Faster but spoiling inheritance (copying parameters): -%D -%D \starttyping -%D \def\doifelsevaluesomething#1#2#3% -%D {\expandafter\ifx\csname#1\endcsname\empty#3\else#2\fi} -%D -%D \def\doifvaluesomething#1#2% -%D {\expandafter\ifx\csname#1\endcsname\empty\else#2\fi} -%D -%D \def\doifvaluenothing#1#2% -%D {\expandafter\ifx\csname#1\endcsname\empty#2\fi} -%D \stoptyping -%D -%D Slightly more efficient: - - \def\doifnothing{\doif \empty} - \def\doifsomething{\doifnot \empty} -\def\doifelsenothing{\doifelse\empty} - -%D The somewhat faster alternatives are: - -\long\def\doifvalue#1#2% - {\edef\!!stringa{\csname#1\endcsname}\edef\!!stringb{#2}% - \ifx\!!stringa\!!stringb - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\long\def\doifnotvalue#1#2% - {\edef\!!stringa{\csname#1\endcsname}\edef\!!stringb{#2}% - \ifx\!!stringa\!!stringb - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\long\def\doifelsevalue#1#2% - {\edef\!!stringa{\csname#1\endcsname}\edef\!!stringb{#2}% - \ifx\!!stringa\!!stringb - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\long\def\doifnothing#1% - {\edef\!!stringa{#1}% - \ifx\!!stringa\empty - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\long\def\doifsomething#1% - {\edef\!!stringa{#1}% - \ifx\!!stringa\empty - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\long\def\doifelsenothing#1% - {\edef\!!stringa{#1}% - \ifx\!!stringa\empty - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\long\def\doifsomethingelse#1% - {\edef\!!stringa{#1}% - \ifx\!!stringa\empty - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -\long\def\doifvaluenothing#1% - {\edef\!!stringa{\csname#1\endcsname}% - \ifx\!!stringa\empty - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\long\def\doifvaluesomething#1% - {\edef\!!stringa{\csname#1\endcsname}% - \ifx\!!stringa\empty - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\long\def\doifelsevaluenothing#1% - {\edef\!!stringa{\csname#1\endcsname}% - \ifx\!!stringa\empty - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -%D \macros -%D {doifemptyelsevalue, doifemptyvalue, doifnotemptyvalue} -%D -%D Also handy: - -\def\doifemptyelsevalue#1% - {\@EA\ifx\csname#1\endcsname\empty - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\def\doifemptyvalue#1% - {\@EA\ifx\csname#1\endcsname\empty - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\def\doifnotemptyvalue#1% - {\@EA\ifx\csname#1\endcsname\empty - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -%D \macros -%D {doifallcommonelse} -%D -%D A complete match of two sets can be tested with -%D \type {\doifallcommonelse}, where the first two -%D arguments are sets. - -%\def\doifallcommonelse#1#2#3#4% -% {\def\p!docommoncheck##1% -% {\doifnotinset{##1}{#2}{\donefalse}% -% \ifdone\else\quitcommalist\fi}% -% \donetrue -% \processcommalist[#1]\p!docommoncheck -% \ifdone#3\else#4\fi} - -\def\@@doifallcommonelse#1#2#3#4% slow - {\def\p!docommoncheck##1% - {\doifnotinset{##1}{#4}\donefalse - \ifdone\else\expandafter\quitcommalist\fi}% - \donetrue - \processcommalist[#3]\p!docommoncheck - \ifdone\expandafter#1\else\expandafter#2\fi} - -\def\doifallcommonelse - {\@@doifallcommonelse\firstoftwoarguments\secondoftwoarguments} - -\def\doifallcommon - {\@@doifallcommonelse\firstofonearguments\gobbleoneargument} - -\def\doifnotallcommon - {\@@doifallcommonelse\gobbleoneargument\firstofonearguments} - -%D \macros -%D {DOIF,DOIFELSE,DOIFNOT} -%D -%D \TEX\ is case sensitive. When comparing arguments, this -%D feature sometimes is less desirable, for instance when we -%D compare filenames. The next three alternatives upcase their -%D arguments before comparing them. -%D -%D \starttyping -%D \DOIF {string1} {string2} {...} -%D \DOIFNOT {string1} {string2} {...} -%D \DOIFELSE {string1} {string2} {then ...}{else ...} -%D \stoptyping -%D -%D We have to use a two||step implementation, because the -%D expansion has to take place outside \type{\uppercase}. - -\def\p!DOIF#1#2% - {\uppercase{\ifinstringelse{$#1$}{$#2$}}% - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\def\p!DOIFNOT#1#2% - {\uppercase{\ifinstringelse{$#1$}{$#2$}}% - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\def\p!DOIFELSE#1#2% - {\uppercase{\ifinstringelse{$#1$}{$#2$}}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\def\p!DOIFINSTRINGELSE#1#2% - {\uppercase{\ifinstringelse{#1}{#2}}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\def\DOIF {\ExpandBothAfter\p!DOIF} -\def\DOIFNOT {\ExpandBothAfter\p!DOIFNOT} -\def\DOIFELSE {\ExpandBothAfter\p!DOIFELSE} -\def\DOIFINSTRINGELSE {\ExpandBothAfter\p!DOIFINSTRINGELSE} - -%D \macros -%D {dosingleargumentwithset, -%D dodoubleargumentwithset,dodoubleemptywithset, -%D dotripleargumentwithset,dotripleemptywithset} -%D -%D These maybe too mysterious macros enable us to handle more -%D than one setup at once. -%D -%D \starttyping -%D \dosingleargumentwithset \command[#1] -%D \dodoubleargumentwithset \command[#1][#2] -%D \dotripleargumentwithset \command[#1][#2][#3] -%D \dodoubleemptywithset \command[#1][#2] -%D \dotripleemptywithset \command[#1][#2][#3] -%D \stoptyping -%D -%D The first macro calls \type{\command[##1]} for each string -%D in the set~\type{#1}. The second one calls for -%D \type{\commando[##1][#2]} and the third, well one may guess. -%D These commands support constructions like: -%D -%D \starttyping -%D \def\dodefinesomething[#1][#2]% -%D {\getparameters[\??xx#1][#2]} -%D -%D \def\definesomething% -%D {\dodoubleargumentwithset\dodefinesomething} -%D \stoptyping -%D -%D Which accepts calls like: -%D -%D \starttyping -%D \definesomething[alfa,beta,...][variable=...,...] -%D \stoptyping -%D -%D Now a whole bunch of variables like \type{\@@xxalfavariable} -%D and \type{\@@xxbetavariable} is defined. - -\def\dodoublewithset#1#2% - {\def\dododoublewithset[##1][##2]% - {\doifsomething{##1} - {\def\dodododoublewithset####1{#2[####1][##2]}% - \processcommalist[##1]\dodododoublewithset}}% - #1\dododoublewithset} - -\def\dodoubleemptywithset {\dodoublewithset\dodoubleempty} -\def\dodoubleargumentwithset{\dodoublewithset\dodoubleargument} - -\def\dotriplewithset#1#2% - {\def\dodotriplewithset[##1][##2][##3]% - {\doifsomething{##1} - {\def\dododotriplewithset####1{#2[####1][##2][##3]}% - \processcommalist[##1]\dododotriplewithset}}% - #1\dodotriplewithset} - -\def\dotripleemptywithset {\dotriplewithset\dotripleempty} -\def\dotripleargumentwithset{\dotriplewithset\dotripleargument} - -%D \macros -%D {stripcharacters,stripspaces} -%D -%D The next command was needed first when we implemented -%D the \CONTEXT\ interactivity macros. When we use labeled -%D destinations, we often cannot use all the characters we -%D want. We therefore strip some of the troublemakers, like -%D spaces, from the labels before we write them to the -%D \DVI||file, which passes them to for instance a PostScript -%D file. -%D -%D \starttyping -%D \stripspaces\from\one\to\two -%D \stoptyping -%D -%D Both the old string \type{\one} and the new one \type{\two} -%D are expanded. This command is a special case of: -%D -%D \starttyping -%D \stripcharacter\char\from\one\to\two -%D \stoptyping -%D -%D As we can see below, spaces following a control sequence are -%D to enclosed in \type{{}}. - -% keep this one: -% -% \def\stripcharacter#1\from#2\to#3% -% {\def\dostripcharacter##1#1##2\end -% {\edef\!!strippedstring{\!!strippedstring##1}% -% \doifnotempty{##2}{\dostripcharacter##2\end}}% -% \let\!!strippedstring\empty -% \edef\!!stringa{#2}% -% \@EA\dostripcharacter\!!stringa#1\end -% \dodoglobal\let#3\!!strippedstring} -% -% the following is better (comes from syst-loc): - -\def\stripcharacter#1\from#2\to#3% - {\def\dostripcharacter##1#1##2\end - {\edef\!!strippedstring{\!!strippedstring##1}% - \doifnotempty{##2}{\dostripcharacter##2\end}}% - \let\!!strippedstring\empty - \edef\!!stringa{#2}% - \@EA\dostripcharacter\!!stringa#1\end - \dodoglobal\let#3\!!strippedstring} - -\def\stripspaces\from#1\to#2% will become \unspacestring#1\from#2 - {\stripcharacter{ }\from#1\to#2} - -%D \macros -%D {unspacestring} -%D -%D The next macro does the same but is more compatible with other macros, -%D like \type {\convert...}. - -\def\unspacestring#1\to#2% - {\stripcharacter{ }\from#1\to#2} - -%D \macros -%D {executeifdefined} -%D -%D \CONTEXT\ uses one auxiliary file for all data concerning -%D tables of contents, references, two||pass optimizations, -%D sorted lists etc. This file is loaded as many times as -%D needed. During such a pass we skip the commands thate are of -%D no use at that moment. Because we don't want to come into -%D trouble with undefined auxiliary commands, we call the -%D macros in a way similar to \type{\getvalue}. The next macro -%D take care of such executions and when not defined, gobbles -%D the unwanted arguments. -%D -%D \starttyping -%D \executeifdefined{name}\gobbleoneargument -%D \stoptyping -%D -%D We can of course gobble more arguments using the -%D appropriate gobbling command. - -\newif\ifexecuted % general purpose - -\def\executeifdefined#1#2% - {\ifundefined{#1}% - \def\next{#2}% - \else - \def\next{\getvalue{#1}}% - \fi - \next} - -%D Just for fun I times the next alternative: it was roughly -%D timed about 15\% faster than the default (10+ sec to 9 sec)! - -\beginTEX - -\def\executeifdefined#1% #2 / never change this one again - {\ifundefined{#1}% - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi - {\csname#1\endcsname}} - -\endTEX - -\beginETEX - -% \def\executeifdefined#1% #2 / never change this one again -% {\ifcsname#1\endcsname -% \expandafter\firstoftwoarguments -% \else -% \expandafter\secondoftwoarguments -% \fi -% {\csname#1\endcsname}} - -\def\executeifdefined#1% #2 / never change this one again - {\ifcsname#1\endcsname - \csname#1\expandafter\expandafter\expandafter\endcsname\expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\endETEX - -% \letvalue{f }\firstofoneargument \def\executeifdefined#1{\csname\ifcsname#1\endcsname#1\else f \fi\endcsname} - -%D This one also has the advantage that it is fully -%D expandable and that it can be used after an assignment. - -%D \macros -%D {executeifdefinedcs} -%D -%D An also fully expandable variant is the following: -%D -%D \starttyping -%D \executeifdefinedcs{a}{b} -%D \stoptyping -%D -%D In dit geval zijn beide argumenten csnames. - -\def\executeifdefinedcs#1#2% - {\csname\ifundefined{#1}#2\else#1\fi\endcsname} - -%D We considered an alternative implementation accepting -%D commands directly, like: -%D -%D \starttyping -%D \executeifdefined\name\gobblefivearguments -%D \stoptyping -%D -%D For the moment we don't need this one, so we stick to the -%D faster one. - -%D \macros -%D {executeandforget} -%D -%D The following macros were requested by Simon. Watch the -%D global variant. -%D -%D \starttyping -%D \executeandforget\SomeCommand -%D \doglobal\executeandforget\AnotherCommand -%D \stoptyping - -\def\executeandforget#1% - {\global\let\@@expanded#1% - \dodoglobal\let#1\relax - \@@expanded} - -%D \macros -%D {doifsomespaceelse} -%D -%D The next command checks a string on the presence of a space -%D and executed a command accordingly. -%D -%D \starttyping -%D \doifsomespaceelse {tekst} {then ...} {else ...} -%D \stoptyping -%D -%D We use this command in \CONTEXT\ for determing if an -%D argument must be broken into words when made interactive. -%D Watch the use of \type{\noexpand}. - -%D Is this one still needed? - -% \long\def\doifsomespaceelse#1#2#3% -% {\def\p!doifsomespaceelse##1 ##2##3\war% -% {\if\noexpand##2@#3\else#2\fi}% -% \p!doifsomespaceelse#1 @ @\war} - -\def\p!doifsomespaceelse#1 #2#3\war{\if\noexpand#2@} - -\long\def\doifsomespaceelse#1% % #2#3% - {\p!doifsomespaceelse#1 @ @\war % #3\else#2\fi} - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -%D \macros -%D {adaptdimension,balancedimensions} -%D -%D Again we introduce some macros that are closely related to -%D an interface aspect of \CONTEXT. The first command can be -%D used to adapt a \DIMENSION. -%D -%D \starttyping -%D \adaptdimension {dimension} {value} -%D \stoptyping -%D -%D When the value is preceed by a \type{+} or minus, the -%D dimension is advanced accordingly, otherwise it gets the -%D value. - -% \def\doadaptdimension#1#2\\#3\\% -% {\if#1+% -% \dodoglobal\advance#3 #1#2\relax -% \else\if#1-% -% \dodoglobal\advance#3 #1#2\relax -% \else -% \dodoglobal#3=#1#2\relax -% \fi\fi} -% -% more fuzzy but also more efficient - -\def\doadaptdimension#1#2\\#3\\% - {\if#1+% - \dodoglobal\advance - \else\if#1-% - \dodoglobal\advance - \else - \dodoglobal - \fi\fi - #3 #1#2\relax} - -\def\adaptdimension#1#2% - {\expandafter\doadaptdimension#2\\#1\\} - -%D A second command takes two \DIMENSIONS. Both are adapted, -%D depending on the sign of the given value. -%D maat. This time we take the value as it is, and don't look -%D explicitly at the preceding sign. -%D -%D \starttyping -%D \balancedimensions {dimension 1} {dimension 2} {value} -%D \stoptyping -%D -%D When a positive value is given, the first dimension is -%D incremented, the second ond is decremented. A negative value -%D has the opposite result. - -\def\balancedimensions#1#2#3% - {\scratchdimen#3\relax - \redoglobal\advance#1 \scratchdimen - \dodoglobal\advance#2 -\scratchdimen} - -%D Both commands can be preceded by \type{\doglobal}. Here we -%D use \type{\redo} first, because \type{\dodo} resets the -%D global character. - -%D \macros -%D {processseparatedlist} -%D -%D Maybe a bit late, but here is a more general version of the -%D \type{\processcommalist} command. This time we don't handle -%D nesting but accept arbitrary seperators. -%D -%D \starttyping -%D \processseparatedlist[list][separator]\command -%D \stoptyping -%D -%D One can think of things like: -%D -%D \starttyping -%D \processseparatedlist[alfa+beta+gamma][+]\message -%D \stoptyping - -%D First we show the simple alternative: -%D -%D \starttyping -%D \def\processseparatedlist[#1][#2]#3% -%D {\def\doprocessseparatedlist##1##2#2% -%D {\if]##1% -%D \let\next=\relax -%D \else\if]##2% -%D \let\next=\relax -%D \else\ifx\blankspace##2% -%D #3{##1}% -%D \let\next=\doprocessseparatedlist -%D \else -%D #3{##1##2}% -%D \let\next=\doprocessseparatedlist -%D \fi\fi\fi -%D \next}% -%D \doprocessseparatedlist#1#2]#2} -%D \stoptyping -%D -%D However, we want to handle all situations, like: -%D -%D \startbuffer -%D \processseparatedlist[{aap noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} -%D \processseparatedlist[{aap} {noot}][ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} -%D \processseparatedlist[aap {noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} -%D \processseparatedlist[aap noot] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} -%D \stopbuffer -%D -%D \typebuffer \getbuffer -%D -%D Therefore we smuggle a \type {\relax} in front of the -%D argument, which we remove afterwards. - -% \def\doprocessseparatedlist#1]#2[#3]#4% -% {\def\dodoprocessseparatedlist##1##2#3% -% {\if]##1% -% \let\dodoprocessseparatedlist\relax -% \else\if]##2% -% \let\dodoprocessseparatedlist\relax -% \else\ifx\blankspace##2% -% #4{##1}% -% \else -% #4{##1##2}% -% \fi\fi\fi -% \dodoprocessseparatedlist}% -% \@EA\dodoprocessseparatedlist\gobbleoneargument#1#3]#3} - -% testcase Vit Zyka: -% -% \def\Do#1{(#1)} -% 1\processseparatedlist[{aap noot}] [ ]\Do \par -% 2\processseparatedlist[{aap} {noot}][ ]\Do \par -% 3\processseparatedlist[aap {noot}] [ ]\Do \par -% 4\processseparatedlist[aap noot] [ ]\Do \par -% 5\processseparatedlist[aap;noot;a noot;noot a; noot a noot][;]\Do \par -% 6\processseparatedlist[][;]\Do \par -% 7\processseparatedlist[;][;]\Do \par - -\def\doprocessseparatedlist#1]#2[#3]#4% - {\def\dodoprocessseparatedlist##1##2#3% - {\def\!!stringa{##2}% suggested by VZ - \if]##1% - \let\dodoprocessseparatedlist\relax - \else\ifx\blankspace\!!stringa - #4{##1}% - \else\if]##2% - \let\dodoprocessseparatedlist\relax - \else - #4{##1##2}% - \fi\fi\fi - \dodoprocessseparatedlist}% - \@EA\dodoprocessseparatedlist\gobbleoneargument#1#3]#3} - -\def\processseparatedlist[% - {\doprocessseparatedlist\relax} - -%D \macros -%D {processlist} -%D -%D An even more general list processing macro is the -%D following one: -%D -%D \starttyping -%D \processlist{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 \processlist(){=>}\docommand(a=>b=>c=>d) -%D \stoptyping - -\long\def\processlist#1#2#3#4% no blank skipping ! - {\def\doprocesslist##1#2% - {\def\dodoprocesslist####1####2#3% - {\ifx#2####1% - \let\dodoprocesslist\relax - \else\ifx#2####2% - \let\dodoprocesslist\relax - \else - #4{####1####2}% - \fi\fi - \dodoprocesslist}% - \expandafter\dodoprocesslist\gobbleoneargument##1#3#2#3}% - \def\dodoprocesslist#1% - {\doprocesslist\relax}% - \dodoprocesslist} - -% %D \macros -% %D {dohonorgroupedargument} -% %D -% %D The previous macro uses yet another auxiliary macro to -% %D handle the special case. -% -% \def\dohonorgroupedargument#1[% -% {\doifnextbgroupelse{\dodohonorgroupedargument#1}{#1[}} -% -% \def\dodohonorgroupedargument#1#2% -% {#1[{{#2}}} - -%D \macros -%D {processassignlist} -%D -%D Is possible to combine an assignment list with one -%D containing keywords. Assignments are treated accordingly, -%D keywords are treated by \type{\command}. -%D -%D \starttyping -%D \processassignlist[...=...,...=...,...]\commando -%D \stoptyping -%D -%D This command can be integrated in \type{\getparameters}, but -%D we decided best not to do so. - -\def\processassignlist#1[#2]#3% - {\def\p!dodogetparameter[##1=##2=##3]% - {\doifnot{##3}\relax{#3{##1}}}% - \def\p!dogetparameter##1% - {\p!dodogetparameter[##1==\relax]}% - \processcommalist[#2]\p!dogetparameter} - -% too ugly -% -% %D \macros -% %D {DoAfterFi,DoAfterFiFi} -% %D -% %D Sometimes \type{\fi}'s can get into the way. We can reach -% %D over such a troublemaker with: -% %D -% %D \starttyping -% %D \DoAfterFi{some commands} -% %D \DoAfterFiFi{some commands} -% %D \stoptyping -% %D -% %D It saves us a \type{\next} construction. Skipping -% %D \type{\else...\fi} is more tricky, so this one is not -% %D provided. -% -% \def\DoAfterFi#1\fi{\fi#1} -% \def\DoAfterFiFi#1\fi#2\fi{\fi\fi#1} - -%D \macros -%D {untextargument -%D untexcommand} -%D -%D When manipulating data(bases) and for instance generating -%D index entries, the next three macros can be of help: -%D -%D \starttyping -%D \untextargument{...}\to\name -%D \untexcommand {...}\to\name -%D \stoptyping -%D -%D They remove braces and backslashes and give us something to -%D sort. - -\def\untexsomething - {\begingroup - \catcode`\{=\@@ignore - \catcode`\}=\@@ignore - \escapechar\minusone - \dountexsomething} - -\long\def\dountexsomething#1#2\to#3% - {\doglobal#1#2\to\untexedargument - \endgroup - \let#3\untexedargument} - -\def\untexargument{\untexsomething\convertargument} -\def\untexcommand {\untexsomething\convertcommand} - -%D \macros -%D {ScaledPointsToBigPoints,ScaledPointsToWholeBigPoints} -%D -%D One characteristic of \POSTSCRIPT\ and \PDF\ is that both -%D used big points (\TEX's bp). The next macros convert points -%D and scaled points into big points. -%D -%D \starttyping -%D \ScaledPointsToBigPoints {number} \target -%D \ScaledPointsToWholeBigPoints {number} \target -%D \stoptyping -%D -%D The magic factor $72/72.27$ can be found in most \TEX\ -%D related books. - -% \def\ScaledPointsToBigPoints #1{\PointsToBigPoints {#1sp}} -% \def\ScaledPointsToWholeBigPoints#1{\PointsToWholeBigPoints{#1sp}} -% -% \def\PointsToBigPoints#1#2% -% {\scratchdimen#1% -% \scratchdimen.996264\scratchdimen -% \edef#2{\withoutpt\the\scratchdimen}} -% -% \def\PointsToWholeBigPoints#1#2% -% {\scratchdimen#1% -% \scratchdimen.996264\scratchdimen -% \scratchcounter\scratchdimen -% \advance\scratchcounter \medcard -% \divide\scratchcounter \maxcard -% \edef#2{\the\scratchcounter}} - -% \PointsToBigPoints{10.53940pt}\test \test -% \PointsToBigPoints{10.53941pt}\test \test -% \PointsToBigPoints{10.53942pt}\test \test - -% \PointsToWholeBigPoints{10.53940pt}\test \test -% \PointsToWholeBigPoints{10.53941pt}\test \test -% \PointsToWholeBigPoints{10.53942pt}\test \test - -\beginTEX - - \def\PointsToBigPoints#1#2% - {\scratchdimen#1% - \scratchdimen.996264\scratchdimen - \edef#2{\withoutpt\the\scratchdimen}} - - \def\PointsToWholeBigPoints#1#2% - {\scratchdimen#1% - \scratchdimen.996264\scratchdimen - \scratchcounter\scratchdimen - \advance\scratchcounter \medcard - \divide\scratchcounter \maxcard - \edef#2{\the\scratchcounter}} - -\endTEX - -\beginETEX \dimexpr \numexpr - -% \def\PointsToBigPoints#1#2% -% {\edef#2{\withoutpt\the\dimexpr(.996264\dimexpr(#1))}} - -% \def\PointsToWholeBigPoints#1#2% -% {\edef#2{\the\numexpr(\numexpr(\dimexpr(.996264\dimexpr(#1)))/\maxcard)}} - - \def\PointsToBigPoints#1#2% - {\edef#2{\withoutpt\the\dimexpr.996264\dimexpr#1\relax\relax}} - - \def\PointsToWholeBigPoints#1#2% - {\edef#2{\the\numexpr\dimexpr.996264\dimexpr#1\relax\relax/\maxcard\relax}} - -\endETEX - -\def\ScaledPointsToBigPoints #1{\PointsToBigPoints {\number#1\scaledpoint}} -\def\ScaledPointsToWholeBigPoints#1{\PointsToWholeBigPoints{\number#1\scaledpoint}} - -%D \macros -%D {PointsToReal} -%D -%D Points can be stripped from their suffix by using -%D \type{\withoutpt}. The next macro enveloppes this macro. -%D -%D \starttyping -%D \PointsToReal {dimension} \target -%D \stoptyping - -\def\PointsToReal#1#2% - {\scratchdimen#1% - \edef#2{\withoutpt\the\scratchdimen}} - -%D \macros -%D {dontleavehmode} -%D -%D Sometimes when we enter a paragraph with some command, the -%D first token gets the whole first line. We can prevent this -%D by saying: -%D -%D \starttyping -%D \dontleavehmode -%D \stoptyping -%D -%D This command is used in for instance the language module -%D \type{lang-ini}. The first version was: -%D -%D \starttyping -%D \def\dontleavehmode{\ifhmode\else\ifmmode\else$ $\fi\fi} -%D \stoptyping -%D -%D Next, Taco came with a better alternative (using mathsurround): -%D -%D \starttyping -%D \def\dontleavehmode -%D {\ifhmode\else \ifmmode\else -%D {\mathsurround\zeropoint\everymath\emptytoks$ $}% -%D \fi \fi} -%D \stoptyping -%D -%D And finaly we got the following alternative, one that avoids -%D interfering grouping at the cost of a box. - -\newbox\@@dlhbox - -\unexpanded \def\dontleavehmode - {\ifhmode\else \ifmmode\else - \setbox\@@dlhbox\hbox{\mathsurround\zeropoint\everymath\emptytoks$ $}\unhbox\@@dlhbox - \fi \fi} - -% Also ok, but more sensitive to lookahead expansion is: -% -% \def\dontleavehmode{\ifvmode \indent \fi} -% -% which assumes indent is kept unchanged. Protecting the macro is only -% possible in etex (watch out: \unexpanded in context is eq to \protected). -% -% \unexpanded \def\dontleavehmode{\ifvmode \indent \fi} % functional spec TH - -%D But, if you run a recent version of \TEX, we can use the new -%D primitive: - -\ifx\normalquitvmode\undefined \else \let\dontleavehmode\normalquitvmode \fi - -%D \macros -%D {uppercasestring,lowercasestring} -%D -%D The names tell what they do: -%D -%D \starttyping -%D \uppercasestring somestring\to\somestring -%D \lowercasestring somestring\to\somestring -%D \stoptyping -%D -%D the first argument may be a \type{\macro}. - -\def\uppercasestring#1\to#2% first @EA redundant - {\edef#2{#1}\@EA\uppercase\@EA{\@EA\dodoglobal\@EA\edef\@EA#2\@EA{#2}}} - -\def\lowercasestring#1\to#2% first @EA redundant - {\edef#2{#1}\@EA\lowercase\@EA{\@EA\dodoglobal\@EA\edef\@EA#2\@EA{#2}}} - -%D \macros -%D {handletokens} -%D -%D With the next macro we enter a critical area of macro -%D expansion. What we want is a macro that looks like: -%D -%D \starttyping -%D \handletokens some tokens\with \somemacro -%D \stoptyping -%D -%D At first sight the next implementation will suffice, but -%D running this one shows that we loose the spaces. This is no -%D surprise because we grab arguments and spaces preceding those -%D are just ignored. -%D -%D \starttyping -%D \def\nohandletokens#1\end% -%D {} -%D -%D \def\dohandletokens#1#2\end% -%D {\ifx#1\endoftoken -%D \expandafter\nohandletokens -%D \else -%D \docommand{#1}% -%D \expandafter\dohandletokens -%D \fi -%D #2\end} -%D -%D \long\def\handletokens#1\with#2% -%D {\let\docommand=#2\relax -%D \dohandletokens#1\endoftoken\end} -%D \stoptyping -%D -%D A second approach therefore grabs the individual characters -%D by using \type{\afterassignment}, in which case the space is -%D read in as space. -%D -%D \starttyping -%D \def\dodohandletokens% -%D {\ifx\next\end \else -%D \docommand{\next}% -%D \expandafter\dohandletokens -%D \fi} -%D -%D \def\dohandletokens -%D {\afterassignment\dodohandletokens\let\next= } -%D -%D \long\def\handletokens#1\with#2% -%D {\let\docommand=#2% -%D \dohandletokens#1\end} -%D \stoptyping - -%D A bonus example: -%D -%D \starttyping -%D \hbox{\handletokens tekst en meer tekst\with\ruledhbox} -%D -%D \def\weetikveel#1{\if#1\blankspace\space\else\ruledhbox{#1}\fi} -%D -%D \hbox{\handletokens tekst en meer tekst\with\weetikveel} -%D \stoptyping - -%D \macros -%D {counttoken,counttokens} -%D -%D For the few occasions that we want to know the number of -%D specific tokens in a string, we can use: -%D -%D \starttyping -%D \counttoken token\in string\to \count -%D \counttokens string\to \count -%D \stoptyping -%D -%D This macro, that for instance is used in \type{cont-tab}, -%D takes a real counter. The macro can be preceded by \type -%D {\doglobal}. - -\def\counttoken#1\in#2\to#3% - {\redoglobal#3\zerocount - \def\!!stringa{#1}% - \def\!!stringb{\end}% - \def\docounttoken##1% obeys {} - {\def\!!stringc{##1}% - \ifx\!!stringb\!!stringc \else - \ifx\!!stringa\!!stringc - \dodoglobal\advance#3 \plusone - \fi - \expandafter\docounttoken - \fi}% - \docounttoken#2\end - \resetglobal} - -% \def\counttoken#1\in#2\to#3% -% {\redoglobal#3\zerocount -% \def\!!stringa{#1}% -% \def\docounttoken##1% obeys {} -% {\def\!!stringb{##1}% -% \ifx\!!stringa\!!stringb -% \dodoglobal\advance#3\plusone -% \fi}% -% \handletokens#1\with\docounttoken -% \resetglobal} - -\def\counttokens#1\to#2% - {\redoglobal#2\zerocount - \def\docounttoken##1{\dodoglobal\advance#2\plusone}% - \handletokens#1\with\docounttoken - \resetglobal} - -%D \macros -%D {splitofftokens} -%D -%D Running this one not always gives the expected results. -%D Consider for instance the macro for which I originally -%D wrote this token handler. - -\long\def\splitofftokens#1\from#2\to#3% - {\ifnum#1>\zerocount - \scratchcounter#1\relax - \def\dosplitofftokens##1% - {\ifnum\scratchcounter>\zerocount - \advance\scratchcounter \minusone - \edef#3{#3##1}% - \fi}% - % \let#3\empty % #3 can be #2, so: - \@EA\let\@EA#3\@EA\empty - \@EA\handletokens#2\with\dosplitofftokens - \else - \edef#3{#2}% - \fi} - -%D This macro can be called like: -%D -%D \startbuffer[example] -%D \splitofftokens10\from01234567 890123456789\to\test [\test] -%D \stopbuffer -%D -%D However, the characters that we expect to find in -%D \type{\test} just don;t show up there. The reason for this -%D is not that logical but follows from \TEX's sometimes -%D mysterious way of expanding. Look at this: -%D -%D \startbuffer[next] -%D \def\next{a} \edef\test{\next} [\test] -%D \let\next=b \edef\test{\test\next} [\test] -%D \let\next=c \edef\test{\next} [\test] -%D \let\next=d \edef\test{\test\next} [\test] -%D \let\next=e \@EA\edef\@EA\test\@EA{\test\next} [\test] -%D \stopbuffer -%D -%D \typebuffer[next] -%D -%D Careful reading shows that inside an \type{\edef} macro's -%D that are \type{\let} are not expanded! -%D -%D \unprotect\getbuffer[next]\protect -%D -%D That's why we finally end up with a macro that looks -%D ahead by using an assignment, this time by using \type -%D {\futurelet}, and grabbing an argument as well. That -%D way we can handle the sentinal, a blank space and grouped -%D tokens. - -\def\dohandletokens % \nexthandledtoken is part of interface - {\futurelet\nexthandledtoken\dodohandletokens} - -\long\def\handletokens#1\with#2% - {\gdef\dododohandletokens{#2}% permits more complex #2's - \dohandletokens#1\end} - -%D A previous version said \type{\docommand=#2}, but to enable -%D use in alignments, I decided to use another placeholder, one -%D that is not sensitive to the global assignment. - -%D This alternatives does not handle grouped tokens well, so -%D next we had (for a short moment): -%D -%D \starttyping -%D \def\dodohandletokens#1% -%D {\ifx\nexthandledtoken\blankspace -%D \dododohandletokens{ }% -%D \fi -%D \ifx#1\end \else -%D \dododohandletokens{#1}% -%D \expandafter\dohandletokens -%D \fi} -%D \stoptyping -%D -%D This one failed on a trailing space, something we -%D encounter in \JAVASCRIPT\ cleaning. -%D -%D \starttyping -%D \def\dodohandletokens#1% -%D {\ifx\nexthandledtoken\blankspace -%D \dododohandletokens{ }% -%D \fi -%D \ifx\nexthandledtoken\end \else -%D \dododohandletokens{#1}% -%D \expandafter\dohandletokens -%D \fi} -%D \stoptyping -%D -%D So, now we have: - -\def\dodohandletokens % can be sped up - {\ifx\nexthandledtoken\blankspace - \def\next * {\dododohandletokens{ }\dohandletokens}% - \else\ifx\nexthandledtoken\end - \let\next\gobbletwoarguments - \else - \long\def\next *##1{\dododohandletokens{##1}\dohandletokens}% - \fi\fi - \next *} - -%D This macro is tested on: -%D -%D \def\xxx#1{[#1]} -%D -%D \startlines -%D \handletokens abc\with\xxx -%D \handletokens a b c\with\xxx -%D \handletokens a b c\with\xxx -%D \handletokens a{bc}d\with\xxx -%D \handletokens a\space bc \with\xxx -%D \stoplines -%D -%D And our previous example shows up as: -%D -%D \getbuffer[example] - -%D \macros -%D {iftrialtypesetting, ifvisible} -%D -%D The next boolean is at first sight a strange one. Sometimes -%D one does a trial typesetting run, for instance to determine -%D dimensions. Some mechanisms, like object inclusion, can fail -%D on such trials. Temporary setting the next boolean to true, -%D helps a lot. The second boolena can be used to inhibit -%D processing completely. - -\newif\iftrialtypesetting \trialtypesettingfalse -\newif\ifvisible \visibletrue - -%D \macros -%D {startlocal, startglobal} -%D -%D The next four macros are rather self explaining: -%D -%D \starttyping -%D \startlocal -%D whatever assignments -%D \stoplocal -%D -%D \startglobal -%D whatever assignments -%D \stopglobal -%D \stoptyping -%D -%D These macros are meant for those who know the difference -%D between local and global assignments and are aware of the -%D possible unwanted side effect - -\def\dostartglobaldefs#1#2% - {\edef\!!stringa{\the\globaldefs}% - \ifnum\globaldefs#10 - \globaldefs-\globaldefs - \fi - \advance\globaldefs#21 - \letvalue{@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} - -%D \macros -%D {twodigitrounding} -%D -%D When using \type {\special}s or \type {\pdfliteral}s, it -%D sometimes makes sense to limit the precission. The next -%D macro rounds a real number to two digits. It takes one -%D argument and only works in \ETEX. - -\beginTEX - - \let\integerrounding \firstofoneargument - \let\onedigitrounding \firstofoneargument - \let\twodigitrounding \firstofoneargument - \let\threedigitrounding\firstofoneargument - -\endTEX - -\beginETEX \dimexpr - - \def\dointegerrounding #1.#2\relax {#1} - \def\doonedigitrounding #1.#2#3\relax {\ifx#2*#1\else#1.#2\fi} - \def\dotwodigitrounding #1.#2#3#4\relax {\ifx#2*#1\else#1.#2#3\fi} - \def\dothreedigitrounding#1.#2#3#4#5\relax{\ifx#2*#1\else#1.#2#3#4\fi} - - \def\integerrounding#1% - {\@EA\@EA\@EA\dointegerrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.5\points \relax .\relax} - \def\onedigitrounding#1% - {\@EA\@EA\@EA\doonedigitrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.05\points \relax 00.*0\relax} - \def\twodigitrounding#1% - {\@EA\@EA\@EA\dotwodigitrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.005\points \relax 000.*00\relax} - \def\threedigitrounding#1% - {\@EA\@EA\@EA\dothreedigitrounding\@EA\WITHOUTPT\the\dimexpr#1\points+.0005\points\relax0000.*00\relax} - -% \def\dointegerrounding #1.#2\relax {#1} -% \def\doonedigitrounding #1.#2#3\relax {#1.#2} -% \def\dotwodigitrounding #1.#2#3#4\relax {#1.#2#3} -% \def\dothreedigitrounding#1.#2#3#4#5\relax{#1.#2#3#4} - -% \def\integerrounding #1{\@EA\@EA\@EA\dointegerrounding \@EA\WITHOUTPT\the\dimexpr #1\points+.5\points\relax \relax} -% \def\onedigitrounding #1{\@EA\@EA\@EA\doonedigitrounding \@EA\WITHOUTPT\the\dimexpr #1\points+.05\points\relax 0\relax} -% \def\twodigitrounding #1{\@EA\@EA\@EA\dotwodigitrounding \@EA\WITHOUTPT\the\dimexpr #1\points+.005\points\relax 00\relax} -% \def\threedigitrounding#1{\@EA\@EA\@EA\dothreedigitrounding\@EA\WITHOUTPT\the\dimexpr#1\points+.0005\points\relax000\relax} - -% \def\integerroundeddimen #1{\@EA\@EA\@EA\dointegerrounding \@EA\WITHOUTPT\the\dimexpr #1+.5\points\relax \relax} -% \def\onedigitroundeddimen #1{\@EA\@EA\@EA\doonedigitrounding \@EA\WITHOUTPT\the\dimexpr #1+.05\points\relax 0\relax} -% \def\twodigitroundeddimen #1{\@EA\@EA\@EA\dotwodigitrounding \@EA\WITHOUTPT\the\dimexpr #1+.005\points\relax 00\relax} -% \def\threedigitroundeddimen#1{\@EA\@EA\@EA\dothreedigitrounding\@EA\WITHOUTPT\the\dimexpr#1+.0005\points\relax000\relax} - -\endETEX - -%D \macros -%D {processcontent} -%D -%D This is the first occasion where \TEX\ and \ETEX\ are no -%D longer compatible, although in many cases things go ok. -%D Beware of verbatim, i.e. catcode changes. -%D -%D \starttyping -%D \def\starthans% -%D {\processcontent{stophans}\test{\message{\test}\wait}} -%D \stoptyping -%D -%D This macro is first used in the tabulation macros. - -\def\processcontent#1% - {\begingroup\@EA\doprocesscontent\csname#1\endcsname} - -%\beginTEX - -\def\doprocesscontent#1#2#3% - {\long\def\doprocesscontent##1#1% - {\endgroup\long\def#2{##1}#3}% - \doprocesscontent} - -%\endTEX - -% Hm. Side effect, spaces after \type{\test} in verbatim. -% must set eof token - -%\beginETEX \scantokens -% -%\def\doprocesscontent#1#2#3% -% {\long\def\doprocesscontent##1#1% -% {\egroup\long\def#2{\scantokens{##1}}#3}% -% \doprocesscontent} -% -%\endETEX - -%D \macros -%D {dogobblesingleempty, dogobbledoubleempty} -%D -%D These two macros savely grab and dispose two arguments. - -\def\dogobblesingleempty{\dosingleempty\dodogobblesingleempty} -\def\dogobbledoubleempty{\dodoubleempty\dodogobbledoubleempty} - -\def\dodogobblesingleempty [#1]{} -\def\dodogobbledoubleempty[#1][#2]{} - -\let\gobblesingleempty\dogobblesingleempty % also used -\let\gobbledoubleempty\dogobbledoubleempty % also used - -%D \macros -%D {sortcommalist,sortcommacommand, -%D donumericcompare,comparedresult} -%D -%D Sometimes we need to sort a commalist, so here is Taco's -%D solution. This will in many cases be a list that is stored -%D in a \type{\csname}, so both commalist and commacommands are -%D supported. The sorting algorithm is very simple, so the list -%D should not be too long or sorting will be very slow. -%D -%D \starttyping -%D \sortcommalist[10,2,4,5,6,1,2,3,4,10,20]\donumericcompare -%D -%D \def\test{10,2,4,5,6,1,2,3,4,10,20} -%D -%D \sortcommacommand[\test]\donumericcompare -%D \stoptyping -%D -%D In both cases, the result is available in the macro \type -%D {\sortedcommalist}. -%D -%D Parameter \type{#2} is a macro that should accept two -%D parameters, and it has to decide which one is larger, by -%D setting the counter \type{\comparedresult} to~0 (for equal), -%D 1~(if it's first argument is larger), or~2 (if it's second -%D argument is larger). -%D -%D As said, these macro are largely written by Taco, and are -%D (maybe therefore) also the first application of \type -%D {\replaceincommalist}. - -\newcount\comparedresult - -\def\sortcommacommand[#1]% - {\@EA\sortcommalist\@EA[#1]} - -\def\sortcommalist[#1]#2% - {\getcommalistsize[#1]% - \ifnum\commalistsize>1 - \let\sortedcommalist\empty - \let\comparecommand#2% - \processcommalist[#1]\dosortcommacommand - \else - \def\sortedcommalist{#1}% - \fi} - -\def\dosortcommacommand#1% - {\ifx\sortedcommalist\empty - \def\sortedcommalist{#1}% - \else - \def\!!tempa{#1}% - \ifx\!!tempa\empty\else - \scratchcounter\plusone - \@EA\getcommalistsize\@EA[\sortedcommalist]% - \@EA\processcommalist\@EA[\sortedcommalist]\docompareitems - \fi - \fi} - -%D All those \type{\expandafter}'s are there because I do not -%D want to use \type{\edef}. - -\def\docompareitems#1% - {\doifnotempty{#1} - {\@EA\comparecommand\@EA{\!!tempa}{#1}\relax - %\ifcase\compareresult % equal - \ifnum\comparedresult<2 - \ifnum\scratchcounter=\commalistsize - \@EA\@EA\@EA\def\@EA\@EA\@EA\sortedcommalist - \@EA\@EA\@EA{\@EA\sortedcommalist\@EA,\!!tempa}% - \fi - %\or % new element larger - % \ifnum\scratchcounter=\commalistsize - % \@EA\@EA\@EA\def\@EA\@EA\@EA\sortedcommalist - % \@EA\@EA\@EA{\@EA\sortedcommalist\@EA,\!!tempa}% - % \fi - \else % old element larger - \@EA\def\@EA\newcommalistelement\@EA{\!!tempa,#1}% - \replaceincommalist\sortedcommalist\scratchcounter - \expandafter\quitcommalist - \fi}% - \advance\scratchcounter \plusone} % bug, was \minusone - -%D The macro \type{\donumericcompare} considers everything -%D that is not a number to be larger than any number. - -\def\donumericcompare#1#2% - {\doifnumberelse{#1} - {\doifnumberelse{#2} - {\ifnum#1>#2\relax - \comparedresult\plusone % #1 is larger - \else\ifnum#1<#2\relax - \comparedresult\plustwo % #2 is larger - \else - \comparedresult\zerocount % both are equal - \fi\fi} - {\comparedresult\plustwo}} - {\comparedresult\plusone}} - -%D \macros -%D {@True, @False, @Not, @And} -%D -%D Some predicate logic functions, used in for instance the -%D math module. - -\def\@True {00} -\def\@False {01} -\def\@Not #1{0\ifcase#11 \or\@EA 1\else \@EA 0\fi} -\def\@And #1#2{0\ifcase#1#2 \@EA 0\else \@EA 1\fi} - -%D \macros -%D {setdimensionwithunit, freezedimensionwithunit} -%D -%D The next assignments are all valid: -%D -%D \starttyping -%D \setdimensionwithunit\scratchdimen{10} {cm} -%D \setdimensionwithunit\scratchdimen{10cm}{cm} -%D \setdimensionwithunit\scratchdimen{10cm}{} -%D \freezedimensionwithunit\SomeWidth{\textwidth} -%D \freezedimensionwithunit\SomeDepth{\dp\strutbox} -%D \stoptyping -%D -%D As an alternative for the next macro we can use a global -%D assignment inside a box. The \type{\empty}'s permits -%D gobbling while preventing spurious \type{\relax}'s. - -\def\setdimensionwithunit#1#2#3% number unit dimension / nice trick - {\afterassignment\gobblefourarguments#1=#2#3pt\relax\empty\empty\empty\empty} - -\def\freezedimensionwithunit#1#2% - {\setdimensionwithunit\scratchdimen#1{#2}\edef#1{\the\scratchdimen}} - -%D \macros -%D {doifsometokselse} -%D -%D Not that fast I guess, but here's a way to test for token -%D registers being empty. - -\def\doifsometokselse#1% % #2#3% - {\edef\!!stringa{\the#1}% - \ifx\!!stringa\empty % #3\else#2\fi} - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -%D \macros -%D {startstrictinspectnextcharacter} -%D -%D This one if for Taco's bibliography module: - -\let\normalinspectnextcharacter\inspectnextcharacter - -\def\strictinspectnextcharacter% no user macro ! - {\ifx\nexttoken\charactertoken - \expandafter\!!stringa - \else - \expandafter\!!stringb - \fi} - -% better: push/pop - -\def\startstrictinspectnextcharacter - {\let\inspectnextcharacter\strictinspectnextcharacter} - -\def\stopstrictinspectnextcharacter - {\let\inspectnextcharacter\normalinspectnextcharacter} - -\def\strictdoifnextoptionalelse#1#2% - {\startstrictinspectnextcharacter - \doifnextcharelse[{\stopstrictinspectnextcharacter#1}{\stopstrictinspectnextcharacter#2}} - -%D \macros -%D {gobblespacetokens} -%D -%D This macro needs a speed-up! - -%\def\gobblespacetokens -% {\doifnextcharelse\empty\donothing\donothing} % no {}\do\do ! - -\def\gobblespacetokens - {\afterassignment\nexttoken\let\nexttoken=} - -%D \macros -%D {verbatimargument} -%D -%D As the name says, this macro converts its argument to a -%D (rather safe) string. - -\def\verbatimstring#1% - {\convertargument#1\to\ascii\ascii} - -%D These are needed in ordinal number conversions: - -\def\lastdigit#1% - {\@EA\thelastdigit\number#1\relax} - -\def\thelastdigit#1#2% - {\ifx#2\relax#1\else\@EA\thelastdigit\@EA#2\fi} - -\def\lasttwodigits#1% - {\@EA\thelasttwodigits\@EA0\number#1\relax} - -\def\thelasttwodigits#1#2#3% 0 dig ... \relax - {\ifx#3\relax#1#2\else\@EA\thelasttwodigits\@EA#2\@EA#3\fi} - -%D \macros -%D {serializecommalist} -%D -%D Concatenate commalists: - -\def\serializecommalist[#1]% - {\let\serializedcommalist\empty - \def\docommand##1{\edef\serializedcommalist{\serializedcommalist##1}}% - \processcommacommand[#1]\docommand} - -%D \macros -%D {purenumber} -%D -%D Sometimes we need control over when \TEX\ stops reading a -%D number, especially in full expandable macros where using -%D \type {\relax} would lead to disasters. -%D -%D \starttyping -%D \ifodd\purenumber{...}\space ... \else ... \fi -%D \stoptyping -%D -%D Here we use a space as number delimiter in combination -%D with a space- and relax-less \type {\purenumber}. This -%D macro works ok with \type {\the}, \type {\number} as well -%D as \ETEX's \type {\numexpr}. - -\def\purenumber#1{\@EA\firstofoneargument\@EA{\number#1}} - -%D \macros -%D {filterfromvalue} -%D -%D \starttyping -%D \setvalue{xx}{{A}{B}{C}} -%D -%D \filterfromvalue{xx}{3}{3} -%D \filterfromvalue{xx}{3}{2} -%D \filterfromvalue{xx}{3}{1} -%D \stoptyping -%D -%D An alternative is to store 'max' in the list, say: -%D -%D \starttyping -%D \setvalue{xx}{3{A}{B}{C}} -%D -%D \filterfromvalues{3}{xx}{3} -%D \filterfromvalues{3}{xx}{2} -%D \filterfromvalues{3}{xx}{1} -%D \stoptyping -%D -%D I'll implement this when I'm in \quotation {writing dirty -%D macros mood}. - -\def\dofilterfromstr#1#2% max n - {\ifcase#1\or - \ifcase#2\or - \strippedcsname\firstofoneargument - \else - \strippedcsname\gobbleoneargument - \fi - \or - \ifcase#2\or - \strippedcsname\firstoftwoarguments - \or - \strippedcsname\secondoftwoarguments - \else - \strippedcsname\gobbletwoarguments - \fi - \or - \ifcase#2\or - \strippedcsname\firstofthreearguments - \or - \strippedcsname\secondofthreearguments - \or - \strippedcsname\thirdofthreearguments - \else - \strippedcsname\gobblethreearguments - \fi - \or - \ifcase#2\or - \strippedcsname\firstoffourarguments - \or - \strippedcsname\secondoffourarguments - \or - \strippedcsname\thirdoffourarguments - \or - \strippedcsname\fourthoffourarguments - \else - \strippedcsname\gobblefourarguments - \fi - \or - \ifcase#2\or - \strippedcsname\firstoffivearguments - \or - \strippedcsname\secondoffivearguments - \or - \strippedcsname\thirdoffivearguments - \or - \strippedcsname\fourthoffivearguments - \or - \strippedcsname\fifthoffivearguments - \else - \strippedcsname\gobblefivearguments - \fi - \fi} - -\def\filterfromvalue#1#2#3% value max n - {\@EA\@EAEAEA\csname % we use the fact that an - \@EA\ifx\csname#1\endcsname\relax % undefined cs has become \relax - \strippedcsname\gobbleoneargument % which we then gobble here - \else - \dofilterfromstr{#2}{#3}% - \fi - \endcsname\csname#1\endcsname} - -\def\filterfromnext#1#2% max n {..}{..}{..}{..} - {\csname\dofilterfromstr{#1}{#2}\endcsname} - -%D \macros -%D {definemeasure} -%D -%D \starttyping -%D \definemeasure[mywidth][\dimexpr(\textwidth-1cm)] -%D -%D ... \measure{mywidth} ... -%D \stoptyping - -\def\??dm{@@dm} % brrr - -\def\definemeasure - {\dodoubleargument\dodefinemeasure} - -\def\dodefinemeasure[#1][#2]% - {\setvalue{\??dm#1}{#2}} - -% #2 could be omitted, but we want to support spaces -% -% \setmeasure {x} {1cm} -% \setmeasure {xx} {1cm} -% \setmeasure {xxx}{1cm} - -\def\setmeasure #1#2{\setvalue{\??dm#1}{#2}} % quick way -\def\setemeasure#1#2{\setevalue{\??dm#1}{#2}} % quick way -\def\setgmeasure#1#2{\setgvalue{\??dm#1}{#2}} % quick way -\def\setxmeasure#1#2{\setxvalue{\??dm#1}{#2}} % quick way - -\def\measure#1% - {\ifcsname\??dm#1\endcsname\csname\??dm#1\endcsname\else\zeropoint\fi} - -%D \macros -%D {doifdimensionelse} -%D -%D This is a dirty one: we simply append a unit and discard it when needed. - -\def\doifdimensionelse#1% - {\afterassignment\dodoifdimensionelse\scratchdimen#1pt\relax} - -\def\dodoifdimensionelse#1% - {\ifx#1\relax - \expandafter\secondoftwoarguments - \else % #1=p ... t\relax - \expandafter\thirdoffourarguments - \fi} - -%D \macros -%D {comparedimension,comparedimensioneps} -%D -%D This is a dirty one: we simply append a unit and discard it when needed. - -\newdimen\roundingeps \roundingeps=10sp - -\def\comparedimension#1#2% - {\chardef\compresult - \ifdim#1<#2% - \zerocount - \else\ifdim#1<#2% - \plusone - \else - \plustwo - \fi\fi} - -\beginETEX - -\def\comparedimensioneps#1#2% - {\chardef\compresult - \ifdim\dimexpr#1-#2\relax<\roudingeps - \zerocount - \else\ifdim\dimexpr#2-#1\relax<\roudingeps - \zerocount - \else\ifdim#1<#2% - \plusone - \else - \plustwo - \fi\fi\fi} - -\endETEX - -\beginTEX - -\newdimen\comparedimen - -\def\comparedimensioneps#1#2% - {\comparedimen#1\advance\comparedimen-#2\relax - \chardef\compresult - \ifdim\comparedimen<\roudingeps - \zerocount - \else\ifdim-\comparedimen<\roudingeps - \zerocount - \else\ifdim#1<#2% - \plusone - \else - \plustwo - \fi\fi\fi} - -\endTEX - -\protect \endinput |