diff options
author | Karl Berry <karl@freefriends.org> | 2016-04-22 22:14:39 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2016-04-22 22:14:39 +0000 |
commit | fc4466b32ed330a956ac603b00fd145524cff49a (patch) | |
tree | 2c50e2b8de13aa9233b2c76dffe201558f169e86 /Master/texmf-dist/tex/context/base/syst-gen.mkii | |
parent | 50e2368597d5f6fe2057195d0ae6a9f2044923e4 (diff) |
context (22apr16)
git-svn-id: svn://tug.org/texlive/trunk@40691 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/syst-gen.mkii')
-rw-r--r-- | Master/texmf-dist/tex/context/base/syst-gen.mkii | 4459 |
1 files changed, 0 insertions, 4459 deletions
diff --git a/Master/texmf-dist/tex/context/base/syst-gen.mkii b/Master/texmf-dist/tex/context/base/syst-gen.mkii deleted file mode 100644 index 8b71b77d5fc..00000000000 --- a/Master/texmf-dist/tex/context/base/syst-gen.mkii +++ /dev/null @@ -1,4459 +0,0 @@ -%D \module -%D [ file=syst-gen, -%D version=1996.03.20, -%D title=\CONTEXT\ System Macros, -%D subtitle=General, -%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. - -% nagaan : \ifinstringelse in syst-ext.tex -% do => p! dodo pp! dododo ppp! -% todo: \donetrue etc local maken - -%D The following macros are responsible for the interaction -%D with \CONTEXT. These macros have proven their use. These -%D macros are optimized as far as possible within of course, -%D the know how of the author. -%D -%D In this module we also show some of the optimizations, -%D mainly because we don't want to forget them and start doing -%D things over and over again. If showing them has a learing -%D effect for others too, we've surved another purpose too. - -%D \macros -%D {abortinputifdefined} -%D -%D Because this module can be used in a different context, we -%D want to prevent it being loaded more than once. This can be -%D done using: -%D -%D \starttyping -%D \abortinputifdefined\command -%D \stoptyping -%D -%D where \type{\command} is a command defined in the module -%D to be loaded only once. -%D -%D \starttyping -%D \def\abortinputifdefined#1% -%D {\ifx#1\undefined -%D \let\next=\relax -%D \else -%D \let\next=\endinput -%D \fi -%D \next} -%D \stoptyping -%D -%D This macro can be speed up in terms of speed as well as -%D memory. Because this is a nice example of a bit strange -%D command (\type{\endinput}), we spend some more lines on this. -%D -%D If we perform such actions directly, we can say: -%D -%D \starttyping -%D \ifx\somecommand\undefined -%D \let\next=\relax -%D \else -%D \let\next=\endinput -%D \fi -%D \next -%D \stoptyping -%D -%D We need the \type{\next} because we need to end the -%D \type{\fi}. The efficient one is: -%D -%D \starttyping -%D \ifx\somecommand\undefined -%D \else -%D \expandafter\endinput -%D \fi -%D \stoptyping -%D -%D Because \type{\endinput} comes into action after the current -%D line, we can also say: -%D -%D \starttyping -%D \ifx\somecommand\undefined \else \endinput \fi -%D \stoptyping -%D -%D When we define a macro, we tend to use a format which -%D shows as besat as can how things are done. \TEX\ however -%D stores the definitions as a sequence of tokens, so in fact -%D we can use a formatted definition: - -\def\abortinputifdefined#1% - {\ifx#1\undefined \else - \endinput - \fi} - -%D which also works. Keep in mind that this is entirely due to -%D the fact that \type{\endinput} after the line, i.e. at the -%D end of the macro. We therefore can burry this primitive quite -%D deep in code. - -%D And because this module implements \type{\writestatus}, we -%D just say: - -% \abortinputifdefined\writestatus - -%D \macros -%D {overloaded, superseded, forwarded, predefined} -%D -%D This prefix is used as signal for the \CONTEXT\ dependency -%D checking features. The first four prefixes don't do anything -%D useful, apart from signaling parsers. - -\def\overloaded{} % local change at the macro level -\def\superseded{} % global change at the module level, replaces previous definitions -\def\predefined{} % defined (first) here, but may be redefined anytime (no need for \overloaded) -\def\forwarded {} % definition at the module level, only done when undefined - -\def\forwarded#1#2{\ifx#2\undefined\else\expandafter\gobbleforwarded\fi#1#2} - -\def\gobbleforwarded#1 - {} - -%D Normally we tell the users what module is being loaded. -%D However, the command that is needed for this is not yet -%D defined. -%D -%D \starttyping -%D \writestatus{laden}{Context Systeem Macros (a)} -%D \stoptyping - -%D The next few macros are needed in case this module is -%D used outside \CONTEXT. - -\ifx\beginTEX\undefined - \let\beginTEX\relax\let\endTEX\relax - \long\def\beginETEX #1\endETEX {} -\fi - -%D \macros -%D [protecting] -%D {protect,unprotect} -%D -%D We can shield macros from users by using some special -%D characters in their names. Some characters that are normally -%D no letters and therefore often used are: \type{@}, \type{!} -%D and \type{?}. Before and after the definition of protected -%D macros, we have to change the \CATCODE\ of these characters. -%D This is done by \type{\unprotect} and \type{\protect}, for -%D instance: -%D -%D \starttyping -%D \unprotect -%D \def\!test{test} -%D \protect -%D \stoptyping -%D -%D The defined command \type{\!test} can of course only be -%D called upon when we are in the \type{\unprotect}'ed state, -%D otherwise \TEX\ reads \type{\!} and probably complains -%D loudly about not being in math mode. -%D -%D Both commands can be used nested, but only the \CATCODE\ -%D of the outermost level is saved. We make use of -%D an auxilary macro \type{\doprotect} to prevent us from -%D conflicts with existing macro's \type{\protect}. When -%D nesting deeper than one level, the system shows the -%D protection level. - -\ifx\protectionlevel\undefined \newcount\protectionlevel \fi - -\ifx\protect\undefined - \def\protect{\writestatus{protection}{too much protection}} -\else - % a simple version is already defined -\fi - -\let\normalprotect\protect % only for latex - -%D Although we don't need the \type{%} after commands that -%D don't take arguments, unless lines are obeyed, I decided -%D to put it there as a reminder. I only mention this once. - -\ifx\unprotect\undefined - - \chardef\protectionthreshold=10 - - \def\saveprotectedcharacters - {\edef\doprotectcharacters - {\catcode`\noexpand @\the\catcode`@ - \catcode`\noexpand !\the\catcode`! - \catcode`\noexpand ?\the\catcode`? }} - - \def\setprotectedcharacters - {\catcode`@=11 - \catcode`!=11 - \catcode`?=11 } - - \def\unprotect - {\ifcase\protectionlevel - \saveprotectedcharacters - \let\protect\doprotect - \fi - \setprotectedcharacters - \advance\protectionlevel 1 - \ifnum\protectionlevel>\protectionthreshold - \reportunprotection - \fi} - - \def\doprotect - {\ifcase\protectionlevel\or - \doprotectcharacters - \let\doprotectcharacters\relax - \let\protect\normalprotect - \fi - \ifnum\protectionlevel>\protectionthreshold - \reportprotection - \fi - \advance\protectionlevel -1 } - - \def\reportunprotection {\writestatus{protection}{unprotect \protectionstate}} - \def\reportprotection {\writestatus{protection}{protect \protectionstate}} - \def\reportprotectionstate{\writestatus{protection}{state \protectionstate}} - - \def\protectionstate - {\the\protectionlevel - \ifcase\protectionthreshold - :\space - @=\the\catcode`@\space\space - !=\the\catcode`!\space\space - ?=\the\catcode`?% - \fi} - - \ifx\everyeof\undefined - \let\checkprotection\relax - \else - \def\checkprotection{\everyeof{\writestatus{protection}{state: \protectionstate}}} - \fi - -\else - - \let\reportprotectionstate\relax - -\fi - -%D Now it is defined, we can make use of this very useful -%D macro. - -\unprotect - -%D \macros -%D {@@escape,@@begingroup,@@endgroup,@@mathshift,@@alignment, -%D @@endofline,@@parameter,@@superscript,@@subscript, -%D @@ignore,@@space,@@letter,@@other,@@active,@@comment} -%D -%D In \CONTEXT\ we sometimes manipulate the \CATCODES\ of -%D certain characters. Because we are not that good at numbers, -%D we introduce some symbolic names. - -\chardef\@@escape = 0 -\chardef\@@begingroup = 1 -\chardef\@@endgroup = 2 -\chardef\@@mathshift = 3 -\chardef\@@alignment = 4 -\chardef\@@endofline = 5 -\chardef\@@parameter = 6 -\chardef\@@superscript = 7 -\chardef\@@subscript = 8 -\chardef\@@ignore = 9 -\chardef\@@space = 10 -\chardef\@@letter = 11 -\chardef\@@other = 12 \chardef\other = 12 -\chardef\@@active = 13 \chardef\active = 13 -\chardef\@@comment = 14 - -%D \macros -%D {normalspace} -%D -%D We often need a space as defined in \PLAIN\ \TEX. Because -%D we cannot be sure of \type{\space} is redefined, we define: - -\def\normalspace{ } - -%D \macros -%D {scratchcounter, -%D scratchdimen,scratchskip,scratchmuskip, -%D scratchbox, -%D scratchtoks} -%D -%D Because we often need counters on a temporary basis, we -%D define the \COUNTER\ \type{\scratchcounter}. This is a -%D real \COUNTER, and not a pseudo one, as we will meet -%D further on. We also define some other scratch registers. - -\chardef\newabovelimit=20 - -\def\stripnewabove#1% - {\ifnum10<9#1 #1\else\expandafter\stripnewabove\fi}% - -\def\newabove#1#2% \dimen \name - {#1#2% - \ifnum\expandafter\stripnewabove\meaning#2>\newabovelimit\else - \expandafter\newabove\expandafter#1\expandafter#2% - \fi} - -\newabove \newcount \scratchcounter \newabove \newcount \globalscratchcounter -\newabove \newdimen \scratchdimen \newabove \newdimen \globalscratchdimen -\newabove \newskip \scratchskip \newabove \newskip \globalscratchskip -\newabove \newmuskip \scratchmuskip \newabove \newmuskip \globalscratchmuskip -\newabove \newtoks \scratchtoks \newabove \newtoks \globalscratchtoks - \newbox \scratchbox \newbox \globalscratchbox - -\newdimen\scratchdimenone \newbox\scratchboxone \newcount\scratchcounterone -\newdimen\scratchdimentwo \newbox\scratchboxtwo \newcount\scratchcountertwo - -%D \macros -%D {ifdone} - -\newif\ifdone - -%D \macros -%D {ifCONTEXT} -%D -%D In the system and support modules we sometimes show examples -%D that make use of core commands. We can skip those parts of -%D the documentation when we use another macropackage. Of -%D course we default to false. - -\newif \ifCONTEXT - -%D \macros -%D {!!count, !!toks, !!dimen, !!box, -%D !!width, !!height, !!depth, !!string, !!done} -%D -%D We define some more \COUNTERS\ and \DIMENSIONS. We also -%D define some shortcuts to the local scatchregisters~0, 2, 4, -%D 6 and~8. - -\newcount\!!counta \toksdef\!!toksa=0 \dimendef\!!dimena= 0 \chardef\!!boxa =0 -\newcount\!!countb \toksdef\!!toksb=2 \dimendef\!!dimenb= 2 \chardef\!!boxb =2 -\newcount\!!countc \toksdef\!!toksc=4 \dimendef\!!dimenc= 4 \chardef\!!boxc =4 -\newcount\!!countd \toksdef\!!toksd=6 \dimendef\!!dimend= 6 \chardef\!!boxd =6 -\newcount\!!counte \toksdef\!!tokse=8 \dimendef\!!dimene= 8 \chardef\!!boxe =8 -\newcount\!!countf \dimendef\!!dimenf=10 %skipdef\!!skipa=0 - \dimendef\!!dimeng=12 %skipdef\!!skipb=2 - \dimendef\!!dimenh=14 %skipdef\!!skipc=4 - \dimendef\!!dimeni=16 %skipdef\!!skipd=6 - \dimendef\!!dimenj=18 %skipdef\!!skipe=8 - \dimendef\!!dimenk=20 %skipdef\!!skipf=10 - -\let\!!stringa\empty \let\!!stringb\empty \let\!!stringc\empty -\let\!!stringd\empty \let\!!stringe\empty \let\!!stringf\empty - -\newdimen\!!widtha \newdimen\!!heighta \newdimen\!!deptha -\newdimen\!!widthb \newdimen\!!heightb \newdimen\!!depthb -\newdimen\!!widthc \newdimen\!!heightc \newdimen\!!depthc - -\newif\if!!donea \newif\if!!doneb \newif\if!!donec -\newif\if!!doned \newif\if!!donee \newif\if!!donef - -\ifx\data\undefined \else \let\data \relax \fi % dep checker - -%D Beware: we don't reuse plain counters, too dangerous -%D when <= 20 (e.g. in supp-pdf this messed up things). - -\ifx\undefined\zeroskip \newskip \zeroskip \fi -\ifx\undefined\zeropoint \newdimen \zeropoint \fi -\ifx\undefined\zerocount \newcount \zerocount \fi -\ifx\undefined\minusone \newcount \minusone \fi \minusone = -1 -\ifx\undefined\minustwo \newcount \minustwo \fi \minustwo = -2 -\ifx\undefined\plusone \chardef \plusone = 1 \fi -\ifx\undefined\plustwo \chardef \plustwo = 2 \fi -\ifx\undefined\plusthree \chardef \plusthree = 3 \fi -\ifx\undefined\plusfour \chardef \plusfour = 4 \fi -\ifx\undefined\plusfive \chardef \plusfive = 5 \fi -\ifx\undefined\plusten \mathchardef \plusten = 10 \fi -\ifx\undefined\plushundred \mathchardef \plushundred = 100 \fi -\ifx\undefined\plusthousand \mathchardef \plusthousand = 1000 \fi -\ifx\undefined\plustenthousand \mathchardef \plustenthousand = 10000 \fi -\ifx\undefined\plustwentythousand \mathchardef \plustwentythousand = 20000 \fi - -%D \macros -%D {s!,c!,e!,p!,v!,@@,??} -%D -%D To save memory, we use constants (sometimes called -%D variables). Redefining these constants can have desastrous -%D results. - -\def\v!prefix! {v!} \def\c!prefix! {c!} -\def\s!prefix! {s!} \def\p!prefix! {p!} - -\def\s!next {next} \def\s!default {default} -\def\s!dummy {dummy} \def\s!unknown {unknown} - -\def\s!do {do} \def\s!dodo {dodo} - -\def\s!complex {complex} \def\s!start {start} -\def\s!simple {simple} \def\s!stop {stop} - -\def\s!empty {empty} - -%D \macros -%D {@EA,@EAEA,@EAEAEA,@EAEAEAEAEAEA,expanded,startexpanded} -%D -%D When in unprotected mode, to be entered with -%D \type{\unprotect}, one can use \type{\@EA} as equivalent -%D of \type{\expandafter}. - -\let\@NX\noexpand -\let\@EA\expandafter - -\def\@EAEA {\expandafter\expandafter} -\def\@EAEAEA{\expandafter\expandafter\expandafter} - -\def\@EAEAEAEAEAEA{\expandafter\@EAEAEA\expandafter} - -%D Sometimes we pass macros as arguments to commands that -%D don't expand them before interpretation. Such commands can -%D be enclosed with \type{\expanded}, like: -%D -%D \starttyping -%D \expanded{\setupsomething[\alfa]} -%D \stoptyping -%D -%D Such situations occur for instance when \type{\alfa} is a -%D commalist or when data stored in macros is fed to index of -%D list commands. If needed, one should use \type{\noexpand} -%D inside the argument. Later on we will meet some more clever -%D alternatives to this command. - -\long\def\@@expanded{} % always long; global (less restores) - -\long\def\expanded#1% - {\long\xdef\@@expanded{\noexpand#1}\@@expanded} - -%D Beware, the next one has no \type {\noexpand} before its -%D argument. - -\long\def\startexpanded#1\stopexpanded % see x-fo for example - {\long\xdef\@@expanded{#1}\@@expanded} - -%D \macros -%D {safeexpanded,everysafeexpanded} -%D -%D In addition we provide: - -\newtoks\everysafeexpanded - -\long\def\safeexpanded#1% why the \noexpand - {\begingroup - \the\everysafeexpanded\long\xdef\@@expanded{\noexpand#1}% - \endgroup - \@@expanded} - -\def\safeedef#1#2% - {\begingroup - \the\everysafeexpanded\long\xdef\@@expanded{\noexpand#2}% - \endgroup - \let#1\@@expanded} - -\def\safexdef#1#2% - {\begingroup - \the\everysafeexpanded\long\xdef\@@expanded{\noexpand#2}% - \endgroup - \global\let#1\@@expanded} - -%D You can append protective measures to the token register if -%D needed, as we will do later. - -%D \macros -%D {expandoneargafter,expandtwoargsafter} -%D -%D These two commands make macros more readable by hiding a -%D lot of \type {\expandafter}'s. They expand the arguments -%D after the first command. -%D -%D \starttyping -%D \expandoneargafter \command{\abc} -%D \expandtwoargsafter\command{\abc}{\def} -%D \stoptyping -%D -%D These commands expect the arguments to be macros. - -\def\expandoneargafter #1{\@EA#1\@EA} -\def\expandtwoargsafter#1#2{\@EA\@EA\@EA#1\@EA\@EA\@EA{\@EA#2\@EA}\@EA} - -%D These two do a full expansion: - -\def\fullexpandoneargafter #1#2{\long\xdef\@@expanded{\noexpand#1{#2}}\@@expanded} -\def\fullexpandtwoargsafter#1#2#3{\long\xdef\@@expanded{\noexpand#1{#2}{#3}}\@@expanded} - -%D \macros -%D {gobbleoneargument,gobble...arguments} -%D -%D The next set of macros just do nothing, except that they -%D get rid of a number of arguments. - -\long\def\gobbleoneargument #1{} -\long\def\gobbletwoarguments #1#2{} -\long\def\gobblethreearguments #1#2#3{} -\long\def\gobblefourarguments #1#2#3#4{} -\long\def\gobblefivearguments #1#2#3#4#5{} -\long\def\gobblesixarguments #1#2#3#4#5#6{} -\long\def\gobblesevenarguments #1#2#3#4#5#6#7{} -\long\def\gobbleeightarguments #1#2#3#4#5#6#7#8{} -\long\def\gobbleninearguments #1#2#3#4#5#6#7#8#9{} -\long\def\gobbletenarguments #1{\gobbleninearguments} - -%D \macros -%D {doifnextcharelse} -%D -%D When we started using \TEX\ in the late eighties, our -%D first experiences with programming concerned a simple shell -%D around \LATEX. The commands probably use most at \PRAGMA, -%D are the itemizing ones. One of those few shell commands took -%D care of an optional argument, that enabled us to specify -%D what kind of item symbol we wanted. Without understanding -%D anything we were able to locate a \LATEX\ macro that could -%D be used to inspect the next character. -%D -%D It's this macro that the ancester of the next one presented -%D here. It executes one of two actions, dependant of the next -%D character. Disturbing spaces and line endings, which are -%D normally interpreted as spaces too, are skipped. -%D -%D \starttyping -%D \doifnextcharelse {karakter} {then ...} {else ...} -%D \stoptyping -%D -%D This macro differs from the original in the use of \type -%D {\localnext} because we don't want clashes with \type -%D {\next}. - -\long\def\doifnextcharelse#1#2#3% #1 should not be {} ! - {\let\charactertoken=#1% = needed here - \def\!!stringa{#2}% - \def\!!stringb{#3}% - \futurelet\nexttoken\inspectnextcharacter} - -\def\inspectnextcharacter - {\ifx\nexttoken\blankspace - \@EA\reinspectnextcharacter - \else\ifx\nexttoken\charactertoken - \@EAEAEA\!!stringa - \else - \@EAEAEA\!!stringb - \fi\fi} - -%D Because we will mostly use this macro for testing if the next -%D character is \type {[}, we also make a slightly faster variant -%D as it is not uncommon to have tens of thousands of calls to this -%D test in a run. Of course it also is more convenient to read a -%D trace then. - -\let\nextoptionalcharactertoken=[ - -\long\def\doifnextoptionalelse#1#2% - {\def\nextoptionalcommandyes{#1}% - \def\nextoptionalcommandnop{#2}% - \futurelet\nexttoken\inspectnextoptionalcharacter} - -\def\inspectnextoptionalcharacter - {\ifx\nexttoken\blankspace - \@EA\reinspectnextoptionalcharacter - \else\ifx\nexttoken\nextoptionalcharactertoken - \@EAEAEA\nextoptionalcommandyes - \else - \@EAEAEA\nextoptionalcommandnop - \fi\fi} - -\let\nextbgroupcharactertoken\bgroup - -\long\def\doifnextbgroupelse#1#2% - {\def\nextbgroupcommandyes{#1}% - \def\nextbgroupcommandnop{#2}% - \futurelet\nexttoken\inspectnextbgroupcharacter} - -\def\inspectnextbgroupcharacter - {\ifx\nexttoken\blankspace - \@EA\reinspectnextbgroupcharacter - \else\ifx\nexttoken\nextbgroupcharactertoken - \@EAEAEA\nextbgroupcommandyes - \else - \@EAEAEA\nextbgroupcommandnop - \fi\fi} - -%D This macro uses some auxiliary macros. Although we were able -%D to program quite complicated things, I only understood these -%D after rereading the \TEX book. The trick is in using a -%D command with a one character name. Such commands differ from -%D the longer ones in the fact that trailing spaces are {\em -%D not} skipped. This enables us to indirectly define a long -%D named macro that gobbles a space. -%D -%D In the first line we define \type{\blankspace}. Next we -%D make \type{\:} equivalent to \type{\reinspect...}. This -%D one||character command is expanded before the next -%D \type{\def} comes into action. This way the space after -%D \type{\:} becomes a delimiter of the longer named -%D \type{\reinspectnextcharacter}. The chain reaction is -%D visually compatible with the next sequence: -%D -%D \starttyping -%D \expandafter\def\reinspectnextcharacter % -%D {\futurelet\nexttoken\inspectnextcharacter} -%D \stoptyping -%D -%D However complicated it may look, I'm still glad I stumbled -%D into this construction. Saving and restoring \type {\:} is -%D needed when we use \PPCHTEX\ in \LATEX. - -\let\next\: - -\def\:{\let\blankspace= } \: - -\def\:{\reinspectnextcharacter} -\expandafter\def\: {\futurelet\nexttoken\inspectnextcharacter} - -\def\:{\reinspectnextoptionalcharacter} -\expandafter\def\: {\futurelet\nexttoken\inspectnextoptionalcharacter} - -\def\:{\reinspectnextbgroupcharacter} -\expandafter\def\: {\futurelet\nexttoken\inspectnextbgroupcharacter} - -\let\:\next - -%D \macros -%D {setvalue,setgvalue,setevalue,setxvalue, -%D letvalue, -%D getvalue, -%D resetvalue} -%D -%D \TEX's primitive \type{\csname} can be used to construct -%D all kind of commands that cannot be defined with -%D \type{\def} and \type{\let}. Every macro programmer sooner -%D or later wants macros like these. -%D -%D \starttyping -%D \setvalue {name}{...} = \def\name{...} -%D \setgvalue {name}{...} = \gdef\name{...} -%D \setevalue {name}{...} = \edef\name{...} -%D \setxvalue {name}{...} = \xdef\name{...} -%D \letvalue {name}=\... = \let\name=\... -%D \letgvalue {name}=\... = \global\let\name=\... -%D \getvalue {name} = \name -%D \resetvalue {name} = \def\name{} -%D \stoptyping -%D -%D As we will see, \CONTEXT\ uses these commands many times, -%D which is mainly due to its object oriented and parameter -%D driven character. - -\def\setvalue #1{\expandafter \def\csname#1\endcsname} -\def\setgvalue #1{\expandafter\gdef\csname#1\endcsname} -\def\setevalue #1{\expandafter\edef\csname#1\endcsname} -\def\setxvalue #1{\expandafter\xdef\csname#1\endcsname} -\def\getvalue #1{\csname#1\endcsname} -\def\letvalue #1{\expandafter\let\csname#1\endcsname} -\def\letgvalue #1{\global\expandafter\let\csname#1\endcsname} -\def\resetvalue #1{\expandafter\let\csname#1\endcsname\empty} -\def\ignorevalue#1#2{\expandafter\let\csname#1\endcsname\empty} - -\def\setuvalue #1{\normalprotected\expandafter \def\csname#1\endcsname} -\def\setuevalue #1{\normalprotected\expandafter\edef\csname#1\endcsname} -\def\setugvalue #1{\normalprotected\expandafter\gdef\csname#1\endcsname} -\def\setuxvalue #1{\normalprotected\expandafter\xdef\csname#1\endcsname} - -%D \macros -%D {globallet,glet} -%D -%D In \CONTEXT\ of May 2000 using \type {\globallet} -%D instead of the two tokens will save us some -%D $300\times4=1200$ bytes of format file on a 32~bit -%D system. So: - -\def\globallet{\global\let} \let\glet\globallet - -%D \macros -%D {donottest,unexpanded} -%D -%D When expansion of a macro gives problems, we can precede it -%D by \type{\donottest}. It seems that protection is one of the -%D burdens of developers of packages, so maybe that's why in -%D \ETEX\ protection is solved in a more robust way. -%D -%D Sometimes prefixing the macro with \type{\donottest} leads -%D to defining an auxiliary macro, like -%D -%D \starttyping -%D \def\dosomecommand {... ... ...} -%D \def\somecommand {\donottest\dosomecommand} -%D \stoptyping -%D -%D This double definition can be made transparant by using -%D \type{\unexpanded}, as in: -%D -%D \starttyping -%D \unexpanded\def\somecommand{... ... ...} -%D \stoptyping -%D -%D The protection mechanism uses: - -\beginTEX - -\def\dontprocesstest#1{==} -\def\doprocesstest #1{#1} - -\let\donottest=\doprocesstest - -\endTEX - -\beginETEX \detokenize - -\def\donottest#1{#1} % {\detokenize{#1}} - -\endETEX - -%D By the way, we use a placeholder because we don't want -%D interference when testing on empty strings. Using a -%D placeholder of 8~characters increases the processing time -%D of simple \type{\doifelse} tests by about 10 \%. When we -%D process the test, we have to remove the braces and -%D therefore explictly gobble \type{#1}. - -%D \macros -%D {honorunexpanded,forceunexpanded} -%D -%D The fact that many macros have the same prefix, could have -%D a negative impact on searching in the hash table. Because -%D some simple testing does not show differences, we just use: -%D -%D \starttyping -%D \def\unexpanded#1#2% -%D {\@EA#1\@EA#2\@EA{\@EA\donottest\csname\s!do\string#2\endcsname}% -%D \@EA#1\csname\s!do\string#2\endcsname} -%D \stoptyping -%D -%D Well, in fact we use the bit more versatile alternative. The -%D \type {\honorunexpanded} can be used to \type {\string} -%D the protected command, which by the way is seldom needed -%D in \CONTEXT. - -\beginTEX - -\def\dosetunexpanded#1#2% - {\@EA#1\@EA{\@EA#2\@EA}% - \@EA{\@EA\donottest\csname\s!do\@EA\string\csname#2\endcsname\endcsname}% - \@EA#1\@EA{\@EA\s!do\@EA\string\csname#2\endcsname}} - -\def\docomunexpanded#1#2% - {\@EA#1\@EA#2\@EA{\@EA\donottest\csname\s!do\string#2\endcsname}% - \@EA#1\csname\s!do\string#2\endcsname} - -\def\unexpanded#1% - {\def\dounexpanded - {\ifx\next\bgroup - \@EA\dosetunexpanded - \else - \@EA\docomunexpanded - \fi#1}% - \futurelet\next\dounexpanded} - -\def\honorunexpanded% for writing to a file or message - {\def\donottest##1{\expandafter\gobblethreearguments\string##1}} - -\def\forceunexpanded% for preventing expansion in \xdef - {\def\donottest##1% - {\expandafter\noexpand\csname\expandafter\gobblefourarguments\string##1\endcsname}} - -\def\resetunexpanded% - {\let\donottest\doprocesstest} - -\endTEX - -\beginETEX \protected - -\let \unexpanded \normalprotected -\let \honorunexpanded \empty % \relax -\let \forceunexpanded \empty % \relax -\let \resetunexpanded \empty % \relax - -\endETEX - -%D This one accepts the more direct \type{\def} and cousins -%D as well as the \CONTEXT\ specific \type{\setvalue} ones. -%D -%D And so the definition in our example turns out to be: -%D -%D \starttyping -%D \def\csname do\somecommand\endcsname{... ... ...} -%D \def\somecommand{\donottest\csname do\somecommand\endcsname} -%D \stoptyping -%D -%D In which \type{do\somecommand} is hidden from the user and -%D cannot lead to confusion. It's still permitted to define -%D auxiliary macros like \type{\dosomecommand}. -%D -%D When we are going to use e-\TEX, we'll probably end up -%D redefining some commands, but we can probably keep the -%D \type{\unexpanded} ones unchanged. - -%D \macros -%D {doifundefined,doifdefined, -%D doifundefinedelse,doifdefinedelse, -%D doifalldefinedelse} -%D -%D The standard way of testing if a macro is defined is -%D comparing its meaning with another undefined one, usually -%D \type{\undefined}. To garantee correct working of the next -%D set of macros, \type{\undefined} may never be defined! -%D -%D \starttyping -%D \doifundefined {string} {...} -%D \doifdefined {string} {...} -%D \doifundefinedelse {string} {then ...} {else ...} -%D \doifdefinedelse {string} {then ...} {else ...} -%D \doifalldefinedelse {commalist} {then ...} {else ...} -%D \stoptyping -%D -%D Every macroname that \TEX\ builds gets an entry in the hash -%D table, which is of limited size. It is expected that e-\TeX\ -%D will offer a less memory||consuming alternative. - -%D Although it will probably never be a big problem, it is good -%D to be aware of the difference between testing on a macro -%D name to be build by using \type{\csname} and -%D \type{\endcsname} and testing the \type{\name} directly. -%D -%D \starttyping -%D \expandafter\ifx\csname NameA\endcsname\relax ... \else ... \fi -%D -%D \ifx\NameB\undefined ... \else ... \fi -%D \stoptyping -%D -%D I became aware of this when I mistakenly testen the first -%D one against \type{\undefined}. When \TEX\ build a name using -%D \type{\csname} it automatically sets it to \type{\relax}, -%D which is definitely not the same as \type{\undefined}. The -%D quickest way to check these things is asking \TEX\ to show -%D the meaning of the names: -%D -%D \starttyping -%D \expandafter\show\csname NameA\endcsname -%D -%D \show\NameB -%D \stoptyping -%D -%D The main reason why this never will be a big problem is that -%D when one uses the \type{\csname} way, one probably has to do -%D with some macroname that always is dealt with that way. -%D Confusion can however arise when one applies both testing -%D methods to the same macroname. By the way, the assignment -%D of \type{\relax} obeys grouping. - -%D The first one gets rid of \type{#1}, but still expands to -%D something and the second one expands to \type{#1}. Because -%D we accept arguments between \type{{}}, we have to get rid -%D of one level of braces. -%D -%D Our first implementation of \type{\ifundefined} was -%D straightforward and readable: -%D -%D \starttyping -%D \def\ifundefined#1% -%D {\expandafter\ifx\csname#1\endcsname\relax}% -%D -%D \def\doifundefinedelse#1#2#3% -%D {\let\donottest=\dontprocesstest -%D \ifundefined{#1}% -%D \let\donottest=\doprocesstest#2% -%D \else -%D \let\donottest=\doprocesstest#3% -%D \fi} -%D -%D \def\doifdefinedelse#1#2#3% -%D {\doifundefinedelse{#1}{#3}{#2}} -%D -%D \def\doifundefined#1#2% -%D {\doifundefinedelse{#1}{#2}{}} -%D -%D \def\doifdefined#1#2% -%D {\doifundefinedelse{#1}{}{#2}} -%D -%D \def\doifalldefinedelse#1#2#3% -%D {\begingroup -%D \donetrue -%D \def\checkcommand##1% -%D {\doifundefined{##1}{\donefalse}}% -%D \processcommalist[#1]\checkcommand -%D \ifdone -%D \endgroup#2% -%D \else -%D \endgroup#3% -%D \fi} -%D \stoptyping -%D -%D When this module was optimized, timing showed that the -%D next alternative can be upto twice as fast, especially when -%D longer arguments are used. Watch how we reach over the -%D \type {\else} and \type {\fi}: this way they cannot get -%D into the way (and we can avoid those \type {\next} -%D hacks); I started using this method after I did some -%D speed optimization tests in the xtag modules; the -%D efficiency of such hacks depends on the length of the -%D argument etc. etc.) - -\beginTEX - -\def\ifundefined#1% - {\expandafter\ifx\csname#1\endcsname\relax} - -\def\p!doifundefined#1% - {\let\donottest\dontprocesstest - \expandafter\ifx\csname#1\endcsname\relax} - -\def\doifundefinedelse#1% - {\p!doifundefined{#1}% - \let\donottest\doprocesstest\@EA\firstoftwoarguments - \else - \let\donottest\doprocesstest\@EA\secondoftwoarguments - \fi} - -\def\doifdefinedelse#1% - {\p!doifundefined{#1}% - \let\donottest\doprocesstest\@EA\secondoftwoarguments - \else - \let\donottest\doprocesstest\@EA\firstoftwoarguments - \fi} - -\def\doifundefined#1% - {\p!doifundefined{#1}% - \let\donottest\doprocesstest\@EA\firstofoneargument - \else - \let\donottest\doprocesstest\@EA\gobbleoneargument - \fi} - -\def\doifdefined#1% - {\p!doifundefined{#1}% - \let\donottest\doprocesstest\@EA\gobbleoneargument - \else - \let\donottest\doprocesstest\@EA\firstofoneargument - \fi} - -\endTEX - -\beginETEX \ifcsname - -\def\ifundefined#1% ongelukkige naam - {\unless\ifcsname#1\endcsname} - -\def\p!doifundefined#1% - {\edef\p!defined{#1}% - \unless\ifcsname\detokenize\@EA{\p!defined}\endcsname} - -\def\doifundefinedelse#1% - {\edef\p!defined{#1}% - \ifcsname\detokenize\@EA{\p!defined}\endcsname - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -\def\doifdefinedelse#1% - {\edef\p!defined{#1}% - \ifcsname\detokenize\@EA{\p!defined}\endcsname - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\def\doifundefined#1% - {\edef\p!defined{#1}% - \ifcsname\detokenize\@EA{\p!defined}\endcsname - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\def\doifdefined#1% - {\edef\p!defined{#1}% - \ifcsname\detokenize\@EA{\p!defined}\endcsname - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\endETEX - -%D \macros -%D {letbeundefined} -%D -%D Testing for being undefined comes down to testing on \type -%D {\relax} when we use \type {\csname}, but when using \type -%D {\ifx}, we test on being \type {\undefined}! In \ETEX\ we -%D have \type {\ifcsname} and that way of testing on existance -%D is not the same as the one described here. Therefore we -%D introduce: - -\beginTEX - -\def\letbeundefined#1% - {\expandafter\let\csname#1\endcsname\relax} - -\endTEX - -\beginETEX \undefined - -\def\letbeundefined#1% potential stack buildup when used \global - {\expandafter\let\csname#1\endcsname\undefined} - -\def\localundefine#1% conditional - {\ifcsname#1\endcsname\expandafter\let\csname#1\endcsname\undefined\fi} -\def\globalundefine#1% conditional - {\ifcsname#1\endcsname\expandafter\global\let\csname#1\endcsname\undefined\fi} - -\endETEX - -%D Beware, being \type {\undefined} in \ETEX\ means that the macro -%D {\em is} defined! - -%D Before we start using this variant, we used another one, -%D which is even a bit faster. This one looked like: -%D -%D \starttyping -%D \def\p!doifundefined% -%D {\begingroup -%D \let\donottest=\dontprocesstest -%D \ifundefined} -%D -%D \def\doifundefinedelse#1#2#3% -%D {\p!doifundefined{#1}% -%D \endgroup#2% -%D \else -%D \endgroup#3% -%D \fi} -%D \stoptyping -%D -%D A even more previous version used \type{\bgroup} and -%D \type {\egroup}. In math mode however, \type{$1{x}2$} differs -%D from \type{$1x2$}. This can been seen when one compares the -%D output of: -%D -%D \starttyping -%D $\kern10pt\showthe\lastkern$ -%D $\kern10pt{\showthe\lastkern}$ -%D $\kern10pt\begingroup\showthe\lastkern\endgroup$ -%D \stoptyping -%D -%D Also in math mode, one can better use \type {\begingroup} -%D and companion instead of \type {\bgroup}. -%D -%D When we were developing the scientific units module, we -%D encountered different behavior in text and math mode, which -%D was due to this grouping subtilities. We therefore decided -%D to use \type{\begingroup} instead of \type{\bgroup}. -%D Later, when we had optimized some macro's the grouped -%D solution turned out to be unsafe when typesetting this -%D documentation, especially when using \type{\globaldefs}. -%D -%D We still have to define \type{\doifalldefinedelse}. Watch -%D the use of grouping, which garantees local use of the -%D boolean \type{\ifdone}. - -\beginTEX - -\def\docheckonedefined#1% - {\ifundefined{#1}% - \donefalse - \fi} - -\def\doifalldefinedelse#1% - {\begingroup - \let\donottest\dontprocesstest - \donetrue - \processcommalist[#1]\docheckonedefined - \ifdone - \endgroup\let\donottest\doprocesstest - \expandafter\firstoftwoarguments - \else - \endgroup\let\donottest\doprocesstest - \expandafter\secondoftwoarguments - \fi} - -\endTEX - -\beginETEX \ifcsname - -\def\docheckonedefined#1% - {\unless\ifcsname#1\endcsname - \donefalse - \fi} - -\def\doifalldefinedelse#1% - {\begingroup - \donetrue \processcommalist[#1]\docheckonedefined - \ifdone - \endgroup\expandafter\firstoftwoarguments - \else - \endgroup\expandafter\secondoftwoarguments - \fi} - -\endETEX - -%D \macros -%D {doif,doifelse,doifnot, -%D donottest} -%D -%D Programming in \TEX\ differs from programming in procedural -%D languages like \MODULA. This means that one --- well, let me -%D speek for myself --- tries to do the things in the well -%D known way. Therefore the next set of \type{\ifthenelse} -%D commands were between the first ones we needed. A few years -%D later, the opposite became true: when programming in -%D \MODULA, I sometimes miss handy things like grouping, -%D runtime redefinition, expansion etc. While \MODULA\ taught -%D me to structure, \TEX\ taught me to think recursive. -%D -%D \starttyping -%D \doif {string1} {string2} {...} -%D \doifnot {string1} {string2} {...} -%D \doifelse {string1} {string2} {then ...}{else ...} -%D \stoptyping -%D -%D When expansion gives problems, we can precede the -%D troublemaker with \type{\donottest}. -%D -%D This implementatie does not use the construction which is -%D more robust for nested conditionals. -%D -%D \starttyping -%D \ifx\!!stringa\!!stringb -%D \def\next{#3}% -%D \else -%D \def\next{#4}% -%D \fi -%D \next -%D \stoptyping -%D -%D In practice, this alternative is at least 20\% slower than -%D the alternative used here. The few cases in which we -%D really need the \type{\next} construction, often need some -%D other precautions and or adaptions too. - -\beginTEX - -% \long\def\doif#1#2#3% -% {\let\donottest\dontprocesstest -% \edef\!!stringa{#1}% -% \edef\!!stringb{#2}% -% \let\donottest\doprocesstest -% \ifx\!!stringa\!!stringb -% #3% -% \fi} -% -% \long\def\doifnot#1#2#3% -% {\let\donottest\dontprocesstest -% \edef\!!stringa{#1}% -% \edef\!!stringb{#2}% -% \let\donottest\doprocesstest -% \ifx\!!stringa\!!stringb -% \else -% #3% -% \fi} -% -% \long\def\doifelse#1#2#3#4% -% {\let\donottest\dontprocesstest -% \edef\!!stringa{#1}% -% \edef\!!stringb{#2}% -% \let\donottest\doprocesstest -% \ifx\!!stringa\!!stringb -% #3% -% \else -% #4% -% \fi} - -%D Slightly faster on big arguments, as well as \type -%D {\next} avoiding: - -\long\def\doif#1#2% - {\let\donottest\dontprocesstest - \edef\!!stringa{#1}% - \edef\!!stringb{#2}% - \let\donottest\doprocesstest - \ifx\!!stringa\!!stringb - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\long\def\doifnot#1#2% - {\let\donottest\dontprocesstest - \edef\!!stringa{#1}% - \edef\!!stringb{#2}% - \let\donottest\doprocesstest - \ifx\!!stringa\!!stringb - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - - -\long\def\doifelse#1#2% - {\let\donottest\dontprocesstest - \edef\!!stringa{#1}% - \edef\!!stringb{#2}% - \let\donottest\doprocesstest - \ifx\!!stringa\!!stringb - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\endTEX - -\beginETEX \protected - -% \long\def\doif#1#2#3% -% {\edef\!!stringa{#1}\edef\!!stringb{#2}% -% \ifx\!!stringa\!!stringb#3\fi} -% -% \long\def\doifnot#1#2#3% -% {\edef\!!stringa{#1}\edef\!!stringb{#2}% -% \unless\ifx\!!stringa\!!stringb#3\fi} -% -% \long\def\doifelse#1#2#3#4% -% {\edef\!!stringa{#1}\edef\!!stringb{#2}% -% \ifx\!!stringa\!!stringb#3\else#4\fi} - -%D Slightly faster on big arguments, as well as \type -%D {\next} avoiding: - -\long\def\doif#1#2% - {\edef\!!stringa{#1}\edef\!!stringb{#2}% - \ifx\!!stringa\!!stringb - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\long\def\doifnot#1#2% - {\edef\!!stringa{#1}\edef\!!stringb{#2}% - \ifx\!!stringa\!!stringb - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\long\def\doifelse#1#2% - {\edef\!!stringa{#1}\edef\!!stringb{#2}% - \ifx\!!stringa\!!stringb - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\endETEX - -%D One could wonder why we don't follow the the same approach -%D as in \type{\doifdefined} c.s.\ and use \type{\begingroup} -%D and \type{\endgroup}. In this case, this alternative is -%D slower, which is probably due to the fact that more meanings -%D need to be restored. -%D -%D The in terms of memory more efficient alternative using a -%D auxiliary macro also proved to be slower, so we definitely -%D did not choose for: -%D -%D \starttyping -%D \def\p!doifelse#1#2% -%D {\let\donottest=\dontprocesstest -%D \edef\!!stringa{#1}% -%D \edef\!!stringb{#2}% -%D \let\donottest=\doprocesstest -%D \ifx\!!stringa\!!stringb} -%D -%D \long\def\doif#1#2#3% -%D {\p!doifelse{#1}{#2}#3\fi} -%D -%D \long\def\doifnot#1#2#3% -%D {\p!doifelse{#1}{#2}\else#3\fi} -%D -%D \long\def\doifelse#1#2#3#4% -%D {\p!doifelse{#1}{#2}#3\else#4\fi} -%D \stoptyping -%D -%D Optimizations like this are related of course to the -%D bottlenecks in \TEX. It seems that restoring saved meanings -%D and passing arguments takes some time. - -%D \macros -%D {doifempty,doifemptyelse,doifnotempty} -%D -%D We complete our set of conditionals with: -%D -%D \starttyping -%D \doifempty {string} {...} -%D \doifnotempty {string} {...} -%D \doifemptyelse {string} {then ...} {else ...} -%D \stoptyping -%D -%D This time, the string is not expanded. - -\long\def\doifemptyelse#1% - {\def\!!stringa{#1}% - \ifx\!!stringa\empty - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\long\def\doifempty#1% - {\def\!!stringa{#1}% - \ifx\!!stringa\empty - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\long\def\doifnotempty#1% - {\def\!!stringa{#1}% - \ifx\!!stringa\empty - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -%D \macros -%D {doifinset,doifnotinset,doifinsetelse} -%D -%D We can check if a string is present in a comma separated -%D set of strings. Depending on the result, some action is -%D taken. -%D -%D \starttyping -%D \doifinset {string} {string,...} {...} -%D \doifnotinset {string} {string,...} {...} -%D \doifinsetelse {string} {string,...} {then ...} {else ...} -%D \stoptyping -%D -%D The second argument is the comma separated set of strings. -%D -%D \starttyping -%D \long\def\doifinsetelse#1#2#3#4% -%D {\doifelse{#1}{} -%D {#4} -%D {\donefalse -%D \def\p!checkiteminset##1% -%D {\doif{#1}{##1} -%D {\donetrue -%D \let\p!checkiteminset=\gobbleoneargument}}% -%D \processcommalist[#2]\p!checkiteminset -%D \ifdone -%D #3% -%D \else -%D #4% -%D \fi}} -%D -%D \long\def\doifinset#1#2#3% -%D {\doifinsetelse{#1}{#2}{#3}{}} -%D -%D \long\def\doifnotinset#1#2#3% -%D {\doifinsetelse{#1}{#2}{}{#3}} -%D \stoptyping -%D -%D Because this macro is called quite often we've spent some -%D time optimizing it. This time, the gain in speed is due to -%D (1)~defining an external auxiliary macro, (2)~not calling -%D any other macros and (3)~minimizing the passing of -%D arguments. The gain in speed is impressive. - -% \def\p!dodocheckiteminset#1% -% {\edef\!!stringb{#1}% -% \ifx\!!stringa\!!stringb -% \donetrue -% \let\p!docheckiteminset\gobbleoneargument -% \fi} -% -% \beginTEX -% -% \def\p!doifinsetelse#1#2% -% {\let\donottest\dontprocesstest -% \donefalse -% \edef\!!stringa{#1}% -% \ifx\!!stringa\empty -% \else -% \let\p!docheckiteminset\p!dodocheckiteminset -% \processcommalist[#2]\p!docheckiteminset -% \fi -% \let\donottest\doprocesstest -% \ifdone} -% -% \endTEX -% -% \beginETEX \protected -% -% \def\p!doifinsetelse#1#2% -% {\donefalse -% \edef\!!stringa{#1}% -% \ifx\!!stringa\empty -% \else -% \let\p!docheckiteminset\p!dodocheckiteminset -% \processcommalist[#2]\p!docheckiteminset -% \fi -% \ifdone} -% -% \endETEX - -% then we had: -% -% \def\p!docheckiteminset#1% -% {\edef\!!stringb{#1}% -% \ifx\!!stringa\!!stringb -% \donetrue -% \expandafter\quitcommalist -% \fi} -% -% \beginTEX -% -% \def\p!doifinsetelse#1#2% -% {\let\donottest\dontprocesstest -% \donefalse -% \edef\!!stringa{#1}% -% \ifx\!!stringa\empty -% \else -% \processcommalist[#2]\p!docheckiteminset -% \fi -% \let\donottest\doprocesstest -% \ifdone} -% -% \endTEX -% -% % can be sped up with processnext... -% -% \beginETEX \protected -% -% \def\p!doifinsetelse#1#2% -% {\donefalse -% \edef\!!stringa{#1}% -% \ifx\!!stringa\empty -% \else -% \processcommalist[#2]\p!docheckiteminset -% \fi -% \ifdone} -% -% \endETEX -% -% \long\def\doifinsetelse#1#2% -% {\p!doifinsetelse{#1}{#2}% -% \expandafter\firstoftwoarguments -% \else -% \expandafter\secondoftwoarguments -% \fi} -% -% \long\def\doifinset#1#2% -% {\p!doifinsetelse{#1}{#2}% -% \expandafter\firstofoneargument -% \else -% \expandafter\gobbleoneargument -% \fi} -% -% \long\def\doifnotinset#1#2% -% {\p!doifinsetelse{#1}{#2}% -% \expandafter\gobbleoneargument -% \else -% \expandafter\firstofoneargument -% \fi} -% -% now we have - -\def\p!docheckiteminset#1% - {\edef\!!stringb{#1}% - \ifx\!!stringa\!!stringb - \donetrue - \expandafter\quitcommalist - \fi} - -\beginTEX - -\def\p!doifinsetelse#1#2#3#4% - {\let\donottest\dontprocesstest - \donefalse - \edef\!!stringa{#3}% - \ifx\!!stringa\empty - \else - \processcommalist[#4]\p!docheckiteminset - \fi - \let\donottest\doprocesstest - \ifdone\expandafter#1\else\expandafter#2\fi} - -\endTEX - -\beginETEX \protected - -\def\p!doifinsetelse#1#2#3#4% - {\donefalse - \edef\!!stringa{#3}% - \ifx\!!stringa\empty - \else - \processcommalist[#4]\p!docheckiteminset - \fi - \ifdone\expandafter#1\else\expandafter#2\fi} - -\endETEX - -\long\def\doifinsetelse - {\p!doifinsetelse\firstoftwoarguments\secondoftwoarguments} - -\long\def\doifinset - {\p!doifinsetelse\firstofoneargument\gobbleoneargument} - -\long\def\doifnotinset - {\p!doifinsetelse\gobbleoneargument\firstofoneargument} - -%D \macros -%D {doifcommon,doifnotcommon,doifcommonelse} -%D -%D Probably the most time consuming tests are those that test -%D for overlap in sets of strings. -%D -%D \starttyping -%D \doifcommon {string,...} {string,...} {...} -%D \doifnotcommon {string,...} {string,...} {...} -%D \doifcommonelse {string,...} {string,...} {then ...} {else ...} -%D \stoptyping -%D -%D We show the slower alternative first, because it shows us -%D how things are done. -%D -%D \starttyping -%D \long\def\doifcommonelse#1#2#3#4% -%D {\donefalse -%D \def\p!docommoncheck##1% -%D {\def\p!dodocommoncheck####1% -%D {\doif{####1}{##1} -%D {\donetrue -%D \def\commalistelement{##1}% -%D \let\p!docommoncheck=\gobbleoneargument -%D \let\p!dodocommoncheck=\gobbleoneargument}}% -%D \processcommalist[#2]\p!dodocommoncheck}% -%D \processcommalist[#1]\p!docommoncheck -%D \ifdone -%D #3% -%D \else -%D #4% -%D \fi} -%D -%D \long\def\doifcommon#1#2#3% -%D {\doifcommonelse{#1}{#2}{#3}{}} -%D -%D \long\def\doifnotcommon#1#2#3% -%D {\doifcommonelse{#1}{#2}{}{#3}} -%D \stoptyping -%D -%D The processing time is shortened by getting the auxiliary -%D macro to the outermost level and using less \type{\edef}'s. -%D Sometimes it makes more sence to define local macro's not -%D only because this way we can be sure that they are not -%D redefined, but also because it shows the dependance. In -%D compiled languages, this is no problem at all. It can even -%D save us bytes and processing time. In interpreted languages -%D like \TEX\ it nearly always slows down processing. - -% \def\p!dododocommoncheck#1% -% {\edef\!!stringb{#1}% -% \ifx\!!stringa\!!stringb -% \donetrue -% \let\p!docommoncheck\gobbleoneargument -% \let\p!dodocommoncheck\gobbleoneargument -% \fi} -% -% \beginTEX -% -% \def\p!doifcommonelse#1#2% -% {\donefalse -% \let\donottest\dontprocesstest -% \let\p!dodocommoncheck\p!dododocommoncheck -% \def\p!docommoncheck##1% -% {\edef\!!stringa{##1}% -% \def\commalistelement{##1}% -% \processcommalist[#2]\p!dodocommoncheck}% -% \processcommalist[#1]\p!docommoncheck -% \let\donottest\doprocesstest -% \ifdone} -% -% \endTEX -% -% \beginETEX \protected -% -% \def\p!doifcommonelse#1#2% -% {\donefalse -% \let\p!dodocommoncheck\p!dododocommoncheck -% \def\p!docommoncheck##1% -% {\edef\!!stringa{##1}% -% \def\commalistelement{##1}% -% \processcommalist[#2]\p!dodocommoncheck}% -% \processcommalist[#1]\p!docommoncheck -% \ifdone} -% -% \endETEX - -% \def\p!dodocommoncheck#1% -% {\edef\!!stringb{#1}% -% \ifx\!!stringa\!!stringb -% \donetrue -% \expandafter\quitprevcommalist -% \fi} -% -% \beginTEX -% -% \def\p!doifcommonelse#1#2% -% {\donefalse -% \let\donottest\dontprocesstest -% \def\p!docommoncheck##1% -% {\edef\!!stringa{##1}% -% \def\commalistelement{##1}% no let to stringa -% \processcommalist[#2]\p!dodocommoncheck}% -% \processcommalist[#1]\p!docommoncheck -% \let\donottest\doprocesstest -% \ifdone} -% -% \endTEX -% -% \beginETEX \protected -% -% \def\p!doifcommonelse#1#2% -% {\donefalse -% \def\p!docommoncheck##1% -% {\edef\!!stringa{##1}% -% \def\commalistelement{##1}% -% \processcommalist[#2]\p!dodocommoncheck}% -% \processcommalist[#1]\p!docommoncheck -% \ifdone} -% -% \endETEX -% -% \long\def\doifcommonelse#1#2% % #3#4% -% {\p!doifcommonelse{#1}{#2}% % #3\else#4\fi} -% \expandafter\firstoftwoarguments -% \else -% \expandafter\secondoftwoarguments -% \fi} -% -% \long\def\doifcommon#1#2% -% {\p!doifcommonelse{#1}{#2}% -% \expandafter\firstofoneargument -% \else -% \expandafter\gobbleoneargument -% \fi} -% -% \long\def\doifnotcommon#1#2% -% {\p!doifcommonelse{#1}{#2}% -% \expandafter\gobbleoneargument -% \else -% \expandafter\firstofoneargument -% \fi} - -% todo: use dedicated done - -\def\p!dodocommoncheck#1% - {\edef\!!stringb{#1}% - \ifx\!!stringa\!!stringb - \donetrue - \expandafter\quitprevcommalist - \fi} - -\beginTEX - -\def\p!doifcommonelse#1#2#3#4% - {\donefalse - \let\donottest\dontprocesstest - \def\p!docommoncheck##1% - {\edef\!!stringa{##1}% - \def\commalistelement{##1}% no let to stringa - \processcommalist[#4]\p!dodocommoncheck}% - \processcommalist[#3]\p!docommoncheck - \let\donottest\doprocesstest - \ifdone\expandafter#1\else\expandafter#2\fi} - -\endTEX - -\beginETEX \protected - -\def\p!doifcommonelse#1#2#3#4% - {\donefalse - \def\p!docommoncheck##1% - {\edef\!!stringa{##1}% - \def\commalistelement{##1}% - \processcommalist[#4]\p!dodocommoncheck}% - \processcommalist[#3]\p!docommoncheck - \ifdone\expandafter#1\else\expandafter#2\fi} - -\endETEX - -\def\doifcommonelse - {\p!doifcommonelse\firstoftwoarguments\secondoftwoarguments} - -\def\doifcommon - {\p!doifcommonelse\firstofoneargument \gobbleoneargument} - -\def\doifnotcommon - {\p!doifcommonelse\gobbleoneargument \firstofoneargument} - -%D \macros -%D {processcommalist,processcommacommand,quitcommalist, -%D processcommalistwithparameters} -%D -%D We've already seen some macros that take care of comma -%D separated lists. Such list can be processed with -%D -%D \starttyping -%D \processcommalist[string,string,...]\commando -%D \stoptyping -%D -%D The user supplied command \type{\commando} receives one -%D argument: the string. This command permits nesting and -%D spaces after commas are skipped. Empty sets are no problem. -%D -%D \startbuffer -%D \def\dosomething#1{(#1)} -%D -%D 1: \processcommalist [\hbox{$a,b,c,d,e,f$}] \dosomething \par -%D 2: \processcommalist [{a,b,c,d,e,f}] \dosomething \par -%D 3: \processcommalist [{a,b,c},d,e,f] \dosomething \par -%D 4: \processcommalist [a,b,{c,d,e},f] \dosomething \par -%D 5: \processcommalist [a{b,c},d,e,f] \dosomething \par -%D 6: \processcommalist [{a,b}c,d,e,f] \dosomething \par -%D 7: \processcommalist [] \dosomething \par -%D 8: \processcommalist [{[}] \dosomething \par -%D \stopbuffer -%D -%D \typebuffer -%D -%D Before we show the result, we present the macro's: - -\newcount\commalevel - -\def\dododoprocesscommaitem - {\csname\s!next\the\commalevel\endcsname} - -%\def\dodoprocesscommaitem% -% {\ifx\nexttoken\blankspace -% \let\nextcommaitem\redoprocesscommaitem -% \else\ifx\nexttoken]% -% \let\nextcommaitem\gobbleoneargument -% \else -% \let\nextcommaitem\dododoprocesscommaitem -% \fi\fi -% \nextcommaitem} -% -% faster ? - -\def\dodoprocesscommaitem - {\ifx\nexttoken\blankspace - \@EA\redoprocesscommaitem - \else\ifx\nexttoken]% - \@EAEAEA\gobbleoneargument - \else - \@EAEAEA\dododoprocesscommaitem - \fi\fi} - -\def\doprocesscommaitem - {\futurelet\nexttoken\dodoprocesscommaitem} - -%D Empty arguments are not processed. Empty items (\type{,,}) -%D however are treated. We have to check for the special case -%D \type{[{a,b,c}]}. -%D -%D \starttyping -%D \def\processcommalist[% -%D {\futurelet\nexttoken\docheckcommaitem} -%D -%D \def\docheckcommaitem% -%D {\ifx\nexttoken]% -%D \let\nextcommaitem\gobbletwoarguments -%D \else\ifx\nexttoken\bgroup -%D \let\nextcommaitem\doprocesscommalistA -%D \else -%D \let\nextcommaitem\doprocesscommalistB -%D \fi\fi -%D \nextcommaitem} -%D -%D \def\doprocesscommalistA#1#2]#3% -%D {\global\advance\commalevel 1 -%D \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,% -%D {#3{##1}\doprocesscommaitem}% -%D \doprocesscommaitem{#1}#2,]\relax -%D \global\advance\commalevel -1 } -%D -%D \def\doprocesscommalistB#1]#2% -%D {\global\advance\commalevel 1 -%D \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,% -%D {#2{##1}\doprocesscommaitem}% -%D \doprocesscommaitem#1,]\relax -%D \global\advance\commalevel -1 } -%D \stoptyping -%D -%D However, this is not a the most straightforward solution! -%D We can misuse one of \TEX's hidden features, and prepend -%D and remove a \type {\relax}. By the way, although it -%D involves less testing, this cleaner alternative is not -%D faster. - -\def\processcommalist[% - {\futurelet\nexttoken\docheckcommaitem} - -\def\docheckcommaitem - {\ifx\nexttoken]% - \expandafter\gobblethreearguments - \else - \expandafter\doprocesscommalist - \fi - \relax} % this one preserved the next {} - -\def\doprocesscommalist#1]#2% - {\global\advance\commalevel \plusone - \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,% - {#2{##1}\doprocesscommaitem}% - \@EA\dodoprocesscommaitem\gobbleoneargument#1,]\relax - \global\advance\commalevel \minusone } - -%D One way of quitting a commalist halfway is: - -\def\quitcommalist - {\begingroup\let\doprocesscommaitem\doquitcommalist} - -\def\doquitcommalist#1]% - {\endgroup} - -\def\quitprevcommalist - {\begingroup\let\doprocesscommaitem\doquitprevcommalist} - -\def\doquitprevcommalist#1]% - {\let\doprocesscommaitem\doquitcommalist} - -%D The hack we used for checking the next character -%D \type {\doifnextcharelse} is also used here. - -\def\:{\redoprocesscommaitem} - -\expandafter\def\: {\futurelet\nexttoken\dodoprocesscommaitem} - -%D The previous examples lead to: -%D -%D \getbuffer - -%D When a list is saved in a macro, we can use a construction -%D like: -%D -%D \starttyping -%D \expandafter\processcommalist\expandafter[\list]\command -%D \stoptyping -%D -%D Such solutions suit most situations, but we wanted a bit -%D more. -%D -%D \starttyping -%D \processcommacommand[string,\stringset,string]\commando -%D \stoptyping -%D -%D where \type{\stringset} is a predefined set, like: -%D -%D \starttyping -%D \def\first{aap,noot,mies} -%D \def\second{laatste} -%D -%D \processcommacommand[\first]\message -%D \processcommacommand[\first,second,third]\message -%D \processcommacommand[\first,between,\second]\message -%D \stoptyping -%D -%D Commands that are part of the list are expanded, so the -%D use of this macro has its limits. - -\def\processcommacommand[#1]% - {\expanded{\processcommalist[#1]}} - -%D The argument to \type{\command} is not delimited. Because -%D we often use \type{[]} as delimiters, we also have: -%D -%D \starttyping -%D \processcommalistwithparameters[string,string,...]\command -%D \stoptyping -%D -%D where \type{\command} looks like: -%D -%D \starttyping -%D \def\command[#1]{... #1 ...} -%D \stoptyping - -\def\processcommalistwithparameters[#1]#2% - {\def\docommand##1{#2[##1]}% - \processcommalist[#1]\docommand} - -%D \macros -%D {processaction, -%D processfirstactioninset, -%D processallactionsinset} -%D -%D \CONTEXT\ makes extensive use of a sort of case or switch -%D command. Depending of the presence of one or more provided -%D items, some actions is taken. These macros can be nested -%D without problems. -%D -%D \starttyping -%D \processaction [x] [a=>\a,b=>\b,c=>\c] -%D \processfirstactioninset [x,y,z] [a=>\a,b=>\b,c=>\c] -%D \processallactionsinset [x,y,z] [a=>\a,b=>\b,c=>\c] -%D \stoptyping -%D -%D We can supply both a \type{default} action and an action -%D to be undertaken when an \type{unknown} value is met: -%D -%D \starttyping -%D \processallactionsinset -%D [x,y,z] -%D [ a=>\a, -%D b=>\b, -%D c=>\c, -%D default=>\default, -%D unknown=>\unknown{... \commalistelement ...}] -%D \stoptyping -%D -%D When \type{#1} is empty, this macro scans list \type{#2} for -%D the keyword \type{default} and executed the related action -%D if present. When \type{#1} is non empty and not in the list, -%D the action related to \type{unknown} is executed. Both -%D keywords must be at the end of list \type{#2}. Afterwards, -%D the actually found keyword is available in -%D \type{\commalistelement}. An advanced example of the use of -%D this macro can be found in \PPCHTEX, where we completely -%D rely on \TEX\ for interpreting user supplied keywords like -%D \type{SB}, \type{SB1..6}, \type{SB125} etc. -%D -%D Even a quick glance at the macros below show some overlap, -%D which means that more efficient alternatives are possible. -%D Because these macro's are very sensitive to subtle changes, -%D we've decided to present the readable originals first -%D Maybe these these macros look complicated, but this is a -%D direct result of the support of nesting. Protection is only -%D applied in \type{\processaction}. -%D -%D \starttyping -%D \newcount\processlevel -%D -%D \def\processaction[#1]#2[#3]% -%D {\doifelse{#1}{} -%D {\def\p!compareprocessaction[##1=>##2]% -%D {\edef\!!stringa{##1}% -%D \ifx\!!stringa\s!default -%D \def\commalistelement{#1}% -%D ##2% -%D \fi}} -%D {\let\donottest=\dontprocesstest -%D \edef\!!stringb{#1}% -%D \let\donottest=\doprocesstest -%D \def\p!compareprocessaction[##1=>##2]% -%D {\edef\!!stringa{##1}% -%D \ifx\!!stringa\!!stringb -%D \def\commalistelement{#1}% -%D ##2% -%D \let\p!doprocessaction=\gobbleoneargument -%D \else\ifx\!!stringa\s!unknown -%D \def\commalistelement{#1}% -%D ##2% -%D \fi\fi}}% -%D \def\p!doprocessaction##1% -%D {\p!compareprocessaction[##1]}% -%D \processcommalist[#3]\p!doprocessaction} -%D -%D \def\processfirstactioninset[#1]#2[#3]% -%D {\doifelse{#1}{} -%D {\processaction[][#3]} -%D {\def\p!compareprocessaction[##1=>##2][##3]% -%D {\edef\!!stringa{##1}% -%D \edef\!!stringb{##3}% -%D \ifx\!!stringa\!!stringb -%D \def\commalistelement{##3}% -%D ##2% -%D \let\p!doprocessaction=\gobbleoneargument -%D \let\p!dodoprocessaction=\gobbleoneargument -%D \else\ifx\!!stringa\s!unknown -%D \def\commalistelement{##3}% -%D ##2% -%D \fi\fi}% -%D \def\p!doprocessaction##1% -%D {\def\p!dodoprocessaction####1% -%D {\p!compareprocessaction[####1][##1]}% -%D \processcommalist[#3]\p!dodoprocessaction}% -%D \processcommalist[#1]\p!doprocessaction}} -%D -%D \def\processallactionsinset[#1]#2[#3]% -%D {\doifelse{#1}{} -%D {\processaction[][#3]} -%D {\advance\processlevel by 1 -%D \def\p!compareprocessaction[##1=>##2][##3]% -%D {\edef\!!stringa{##1}% -%D \edef\!!stringb{##3}% -%D \ifx\!!stringa\!!stringb -%D \def\commalistelement{##3}% -%D ##2% -%D \let\p!dodoprocessaction=\gobbleoneargument -%D \else\ifx\!!stringa\s!unknown -%D \def\commalistelement{##3}% -%D ##2% -%D \fi\fi}% -%D \setvalue{\s!do\the\processlevel}##1% -%D {\def\p!dodoprocessaction####1% -%D {\p!compareprocessaction[####1][##1]}% -%D \processcommalist[#3]\p!dodoprocessaction}% -%D \processcommalist[#1]{\getvalue{\s!do\the\processlevel}}% -%D \advance\processlevel by -1 }} -%D \stoptyping -%D -%D The gain of speed in the (again) next implementation is -%D around 20\%, depending on the application. - -\newcount\processlevel - -\def\p!compareprocessactionA[#1=>#2][#3]% - {\edef\!!stringb{#1}% - \ifx\!!stringb\s!default - \let\commalistelement\empty - #2% - \fi} - -% \def\p!compareprocessactionB[#1=>#2][#3]% -% {\expandedaction\!!stringb{#1}% -% \ifx\!!stringa\!!stringb -% \def\commalistelement{#3}% -% #2% -% \let\p!doprocessaction\gobbleoneargument -% \else -% \edef\!!stringb{#1}% -% \ifx\!!stringb\s!unknown -% \def\commalistelement{#3}% beware of loops -% #2% -% \fi -% \fi} - -% met \quitcommalist tot meer dan 25\% sneller - -\def\p!compareprocessactionB[#1=>#2][#3]% - {\expandedaction\!!stringb{#1}% - \ifx\!!stringa\!!stringb - \def\commalistelement{#3}% - #2% - \expandafter\quitcommalist - \else - \edef\!!stringb{#1}% - \ifx\!!stringb\s!unknown - \def\commalistelement{#3}% beware of loops - #2% - \fi - \fi} - -\beginTEX - -\def\processaction[#1]#2[#3]% - {\let\donottest\dontprocesstest - \expandedaction\!!stringa{#1}% - \let\donottest\doprocesstest - \ifx\!!stringa\empty - \let\p!compareprocessaction\p!compareprocessactionA - \else - \let\p!compareprocessaction\p!compareprocessactionB - \fi - \def\p!doprocessaction##1% - {\p!compareprocessaction[##1][#1]}% - \processcommalist[#3]\p!doprocessaction - \expandactions} - -\endTEX - -\beginETEX \protected - -\def\processaction[#1]#2[#3]% faster version follows - {\expandedaction\!!stringa{#1}% - \ifx\!!stringa\empty - \let\p!compareprocessaction\p!compareprocessactionA - \else - \let\p!compareprocessaction\p!compareprocessactionB - \fi - \def\p!doprocessaction##1% - {\p!compareprocessaction[##1][#1]}% - \processcommalist[#3]\p!doprocessaction - \expandactions} - -\endETEX - -% \def\p!compareprocessactionC[#1=>#2][#3]% -% {\expandedaction\!!stringa{#1}% -% \expandedaction\!!stringb{#3}% -% \ifx\!!stringa\!!stringb -% \def\commalistelement{#3}% -% #2% -% \let\p!doprocessaction\gobbleoneargument -% \let\p!dodoprocessaction\gobbleoneargument -% \else -% \edef\!!stringa{#1}% -% \ifx\!!stringa\s!unknown -% \def\commalistelement{#3}% -% #2% -% \fi -% \fi} - -\def\p!compareprocessactionC[#1=>#2][#3]% - {\expandedaction\!!stringa{#1}% - \expandedaction\!!stringb{#3}% - \ifx\!!stringa\!!stringb - \def\commalistelement{#3}% - #2% - \expandafter\quitprevcommalist - \else - \edef\!!stringa{#1}% - \ifx\!!stringa\s!unknown - \def\commalistelement{#3}% - #2% - \fi - \fi} - -\def\processfirstactioninset[#1]#2[#3]% faster version follows - {\expandedaction\!!stringa{#1}% - \ifx\!!stringa\empty - \processaction[][#3]% - \else - \def\p!doprocessaction##1% - {\def\p!dodoprocessaction####1% - {\p!compareprocessactionC[####1][##1]}% - \processcommalist[#3]\p!dodoprocessaction}% - \processcommalist[#1]\p!doprocessaction - \fi - \expandactions} - -% \def\p!compareprocessactionD[#1=>#2][#3]% -% {\expandedaction\!!stringa{#1}% -% \expandedaction\!!stringb{#3}% -% \ifx\!!stringa\!!stringb -% \def\commalistelement{#3}% -% #2% -% \let\p!dodoprocessaction\gobbleoneargument -% \else -% \edef\!!stringa{#1}% -% \ifx\!!stringa\s!unknown -% \def\commalistelement{#3}% -% #2% -% \fi -% \fi} - -\def\p!compareprocessactionD[#1=>#2][#3]% - {\expandedaction\!!stringa{#1}% - \expandedaction\!!stringb{#3}% - \ifx\!!stringa\!!stringb - \def\commalistelement{#3}% - #2% - \expandafter\quitcommalist - \else - \edef\!!stringa{#1}% - \ifx\!!stringa\s!unknown - \def\commalistelement{#3}% - #2% - \fi - \fi} - -\def\doprocessallactionsinset - {\csname\s!do\the\processlevel\endcsname} - -\def\processallactionsinset[#1]#2[#3]% faster version follows - {\expandedaction\!!stringa{#1}% - \ifx\!!stringa\empty - \processaction[][#3]% - \else - \advance\processlevel \plusone - \expandafter\def\csname\s!do\the\processlevel\endcsname##1% - {\def\p!dodoprocessaction####1% - {\p!compareprocessactionD[####1][##1]}% - \processcommalist[#3]\p!dodoprocessaction}% - \processcommalist[#1]\doprocessallactionsinset - \advance\processlevel \minusone - \fi - \expandactions} - -%D We can speed up these macros a bit when we use a dedicated -%D commalist processor, one that avoids passing the (often) -%D big action list. - -\beginTEX - -\def\processaction[#1]#2[% - {\let\donottest\dontprocesstest - \expandedaction\!!stringa{#1}% - \let\donottest\doprocesstest - \ifx\!!stringa\empty - \let\p!compareprocessaction\p!compareprocessactionA - \else - \let\p!compareprocessaction\p!compareprocessactionB - \fi - \def\p!doprocessaction##1% - {\p!compareprocessaction[##1][#1]}% - \processnextcommalist\relax\expandactions\p!doprocessaction[} - -\endTEX - -\beginETEX - -\def\processaction[#1]#2[% - {\expandedaction\!!stringa{#1}% - \ifx\!!stringa\empty - \let\p!compareprocessaction\p!compareprocessactionA - \else - \let\p!compareprocessaction\p!compareprocessactionB - \fi - \def\p!doprocessaction##1% - {\p!compareprocessaction[##1][#1]}% - \processnextcommalist\relax\expandactions\p!doprocessaction[} - -\endETEX - -\def\processfirstactionsinset[#1]% - {\expandedaction\!!stringa{#1}% - \ifx\!!stringa\empty - \expandafter\processaction - \else - \expandafter\processfirstactionsinsetindeed - \fi - [#1]} - -\def\processfirstactioninsetindeed[#1]#2[#3]% - {\def\p!doprocessaction##1% - {\def\p!dodoprocessaction####1% - {\p!compareprocessactionC[####1][##1]}% - \processcommalist[#3]\p!dodoprocessaction}% - \processcommalist[#1]\p!doprocessaction - \expandactions} - -\def\processallactionsinset[#1]% - {\expandedaction\!!stringa{#1}% - \ifx\!!stringa\empty - \expandafter\processaction - \else - \expandafter\processallactionsinsetindeed - \fi - [#1]} - -\def\processallactionsinsetindeed[#1]#2[#3]% - {\advance\processlevel \plusone - \expandafter\def\csname\s!do\the\processlevel\endcsname##1% - {\def\p!dodoprocessaction####1% - {\p!compareprocessactionD[####1][##1]}% - \processcommalist[#3]\p!dodoprocessaction}% - \processcommalist[#1]\doprocessallactionsinset - \advance\processlevel \minusone - \expandactions} - -\def\processnextcommalist#1#2#3[#4#5]% - {#1% - \let\nexttoken#4% - \global\advance\commalevel \plusone - \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,% - {#3{##1}\doprocesscommaitem}% - \dodoprocesscommaitem#4#5,]\relax - \global\advance\commalevel \minusone - #2} - -%D I do have an even faster version (saving 3 sec on a 13 -%D sec run for 50K invocations, but normally we don't have -%D that many calls and that alternative uses more macros and is -%D even less readable. What we did add, was \type {\@EA}, so -%D that we can pass a command. - -%D \macros -%D {unexpandedprocessaction, -%D unexpandedprocessfirstactioninset, -%D unexpandedprocessallactionsinset} -%D -%D Now what are those expansion commands doing there. Well, -%D sometimes we want to compare actions that may consist off -%D commands (i.e. are no constants). In such occasions we can -%D use the a bit slower alternatives: - -\def\unexpandedprocessfirstactioninset{\dontexpandactions\processfirstactioninset} -\def\unexpandedprocessaction {\dontexpandactions\processaction} -\def\unexpandedprocessallactionsinset {\dontexpandactions\processallactionsinset} - -%D By default we expand actions: - -\def\expandactions{\let\expandedaction\edef} \expandactions - -%D But when needed we convert the strings to meaningful -%D sequences of characters. - -\def\unexpandedaction#1>{} - -\def\noexpandedaction#1#2% - {\def\@@convertedargument{#2}% - \@EA\edef\@EA#1\@EA{\@EA\unexpandedaction\meaning\@@convertedargument}} - -\def\dontexpandactions% - {\let\expandedaction\noexpandedaction} - -%D \macros -%D {getfirstcharacter, firstcharacter, remainingcharacters, doiffirstcharacter} -%D -%D Sometimes the action to be undertaken depends on the -%D next character. This macro get this character and puts it in -%D \type{\firstcharacter}. -%D -%D \starttyping -%D \getfirstcharacter {string} -%D \stoptyping -%D -%D A two step expansion is used to prevent problems with -%D complicated arguments, for instance arguments that -%D consist of two or more expandable tokens. - -\def\dogetfirstcharacter#1#2\relax - {\def\firstcharacter{#1}% - \def\remainingcharacters{#2}} - -\def\getfirstcharacter#1% - {\edef\!!stringa{#1}% - \expandafter\dogetfirstcharacter\!!stringa\relax} - -\def\doiffirstcharelse#1#2% char string -% kort (maar onleesbaar) -% {\expanded{\dogetfirstcharacter#2}\\\doifelse{#1}\firstcharacter} -% korter (en begrijpelijk)) - {\getfirstcharacter{#2}\doifelse{#1}\firstcharacter} -% snel (maar zelden gebruikt, dus niet zo belangrijk) -% {\getfirstcharacter{#2}% -% \edef\!!stringa{#1}% -% \ifx\!!stringa\firstcharacter -% \expandafter\firstoftwoarguments -% \else -% \expandafter\secondoftwoarguments -% \fi} - -%D \macros -%D {doifinstringelse, doifincsnameelse} -%D -%D We can check for the presence of a substring in a given -%D sequence of characters. -%D -%D \starttyping -%D \doifinsetelse {substring} {string} {then ...} {else ...} -%D \stoptyping -%D -%D An application of this command can be found further on. -%D Like before, we first show some alternatives, like the one -%D we started with: -%D -%D \starttyping -%D \long\def\p!doifinstringelse#1#2#3#4% -%D {\def\pp!doifinstringelse##1#1##2##3\war% -%D {\if##2@% -%D #4% -%D \else -%D #3% -%D \fi}% -%D \pp!doifinstringelse#2#1@@\war} -%D -%D \def\doifinstringelse% -%D {\ExpandBothAfter\p!doifinstringelse} -%D \stoptyping -%D -%D After this we came to: -%D -%D \starttyping -%D \def\p!doifinstringelse#1#2% -%D {\def\pp!doifinstringelse##1#1##2##3\war% -%D {\if##2@}% -%D \pp!doifinstringelse#2#1@@\war} -%D -%D \def\doifinstringelse#1#2#3#4% -%D {\ExpandBothAfter\p!doifinstringelse{#1}{#2}% -%D #4% -%D \else -%D #3% -%D \fi} -%D \stoptyping -%D -%D Sometimes the second argument is passed as a macro. By -%D postponing the expansion of this macro, we gain quite some -%D run time, simply because the less tokens we pass, the faster -%D \TEX\ runs. So finally the definition became: - -% \long\def\rawdoifinstringelse#1#2% ##2 can be {abc} -% {\long\def\pp!doifinstringelse##1#1##2##3\war{\if##2@}% -% \pp!doifinstringelse#2#1@@\war -% \expandafter\secondoftwoarguments -% \else -% \expandafter\firstoftwoarguments -% \fi} - -\long\def\doifinstringelse#1% - {\edef\@@@instring{#1}% expand #1 here - \ifx\@@@instring\empty - \@EA\thirdofthreearguments - \else - \@EA\dodoifinstringelse - \fi} - -\long\def\dodoifinstringelse#1% - {\p!doifinstringelse\@@@instring{#1}% - \@EA\firstoftwoarguments - \else - \@EA\secondoftwoarguments - \fi} - -\long\def\doifinstring#1%% - {\edef\@@@instring{#1}% expand #1 here - \ifx\@@@instring\empty - \@EA\gobbletwoarguments - \else - \@EA\dodoifinstring - \fi} - -\long\def\dodoifinstring#1% - {\p!doifinstringelse\@@@instring{#1}% - \@EA\firstofoneargument - \else - \@EA\gobbleoneargument - \fi} - -\long\def\doifnotinstring#1%% - {\edef\@@@instring{#1}% expand #1 here - \ifx\@@@instring\empty - \@EA\gobbletwoarguments - \else - \@EA\dodoifnotinstring - \fi} - -\long\def\dodoifnotinstring#1% - {\p!doifinstringelse\@@@instring{#1}% - \@EA\gobbleoneargument - \else - \@EA\firstofoneargument - \fi} - -%D \starttyping -%D \beginTEX -%D -%D \long\def\p!doifinstringelse#1#2% -%D {\long\def\pp!doifinstringelse##1#1##2##3\war% -%D {\csname if\if##2@fals\else tru\fi e\endcsname}% -%D \expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here -%D -%D \endTEX -%D -%D \beginETEX \unless -%D -%D \long\def\p!doifinstringelse#1#2% -%D {\long\def\pp!doifinstringelse##1#1##2##3\war% -%D {\unless\if##2@}% -%D \expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here -%D -%D \endETEX -%D \stoptyping -%D -%D And then \unknown\ after a couple of years, we ran into a -%D situation where \type {##2} was something \type {{bla}}. So -%D finally we need to use an auxiliary macro, otherwise we get -%D funny strings in the output. - -% \long\def\p!doifinstringelse#1#2% ##2 can be {abc} -% {\long\@EA\def\@EA\pp!doifinstringelse\@EA##\@EA1#1##2##3\war % expand #1 here -% {\ppp!doifinstringelse##2\war}% -% \expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here -% -% \beginTEX -% -% \def\ppp!doifinstringelse#1#2\war% -% {\csname if\ifx#1@fals\else tru\fi e\endcsname}% -% -% \endTEX -% -% \beginETEX \unless -% -% \def\ppp!doifinstringelse#1#2\war% -% {\unless\ifx#1@} -% -% \endETEX - -\beginETEX - -\long\def\p!doifinstringelse#1#2% ##2 can be {abc} - {\long\@EA\def\@EA\pp!doifinstringelse\@EA##\@EA1#1##2##3\war % expand #1 here - {\unless\if##2@}% -% \expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here - \expanded{\pp!doifinstringelse#2#1}@@\war} % expand #2 here - -\endETEX - -\beginTEX - -\long\def\p!doifinstringelse#1#2% ##2 can be {abc} - {\long\@EA\def\@EA\pp!doifinstringelse\@EA##\@EA1#1##2##3\war % expand #1 here - {\csname if\if##2@fals\else tru\fi e\endcsname}% - %\expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here - \expanded{\pp!doifinstringelse#2#1}@@\war} % expand #2 here - -\endTEX - -%D The next alternative proved to be upto twice as fast on -%D tasks like checking reserved words in pretty verbatim -%D typesetting! This is mainly due to the fact that passing -%D (expanded) strings is much slower that passing a macro. -%D -%D \starttyping -%D \doifincsnameelse {substring} {\string} {then ...} {else ...} -%D \stoptyping -%D -%D Where \type{\doifinstringelse} does as much expansion as -%D possible, the latter alternative does minimal (one level) -%D expansion. - -\beginTEX - -\long\def\p!doifincsnameelse#1#2% - {\long\def\pp!doifincsnameelse##1#1##2##3\war - {\csname if\if##2@fals\else tru\fi e\endcsname}% - \@EA\pp!doifincsnameelse#2#1@@\war} - -\endTEX - -\beginETEX \unless - -\long\def\p!doifincsnameelse#1#2% - {\long\def\pp!doifincsnameelse##1#1##2##3\war - {\unless\if##2@}% - \@EA\pp!doifincsnameelse#2#1@@\war} - -\endETEX - -\long\def\doifincsnameelse#1#2% % #3#4% - {\edef\@@@instring{#1}% - \@EA\p!doifincsnameelse\@EA{\@@@instring}{#2}% % #3\else#4\fi} - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -%D \macros -%D {doifnumberelse} -%D -%D The next macro executes a command depending of the outcome -%D of a test on numerals. This is probably one of the fastest -%D test possible, exept from a less robust 10||step -%D \type{\if}||ladder or some tricky \type{\lcode} checking. -%D -%D \starttyping -%D \doifnumberelse {string} {then ...} {else ...} -%D \stoptyping -%D -%D The macro accepts \type{123}, \type{abc}, \type{{}}, -%D \type{\getal} and \type{\the\count...}. This macro is a -%D rather dirty one. -%D -%D \starttyping -%D \long\def\doifnumberelse#1#2#3% -%D {\begingroup\donefalse -%D \ifcase1#1\or\or\or\or\or\or\or\or\or\else\donetrue\fi -%D \ifdone\endgroup#2\else\endgroup#3\fi} -%D \stoptyping -%D -%D Or better: -%D -%D \starttyping -%D \long\def\doifnumberelse#1% -%D {\begingroup\donefalse -%D \ifcase1#1\or\or\or\or\or\or\or\or\or\else\donetrue\fi -%D \ifdone -%D \endgroup\expandafter\firstoftwoarguments -%D \else -%D \endgroup\expandafter\secondoftwoarguments -%D \fi} -%D \stoptyping -%D -%D A previous implementation was: -%D -%D \starttyping -%D \long\def\doifnumberelse#1#2#3% -%D {\getfirstcharacter{#1}% -%D \@EA\p!doifinstringelse\@EA{\firstcharacter}{1234567890}% -%D #2% -%D \else -%D #3% -%D \fi} -%D \stoptyping -%D -%D And before we had \type{\p!doifinstringelse} available, we -%D used: -%D -%D \starttyping -%D \def\doifnumberelse#1% -%D {\getfirstcharacter{#1}% -%D \rawdoifinsetelse{\firstcharacter}{1,2,3,4,5,6,7,8,9,0}} -%D \stoptyping -%D -%D The implementation using \type {\ifcase} is much faster, but -%D the next one is not, not even when testing milion calls. -%D -%D \starttyping -%D \newif\ifitsanumber -%D -%D \long\def\isitanumber#1% -%D {\itsanumberfalse -%D \ifcase1#1\or\or\or\or\or\or\or\or\or\else\itsanumbertrue\fi} -%D -%D \long\def\doifnumberelse#1#2#3% -%D {\isitanumber{#1}\ifitsanumber#2\else#3\fi} -%D \stoptyping -%D -%D After a while the next evolved and this one is the one we -%D will use. This one is some 5\% faster than the group/done -%D one (partly because it does not have to pass arguments). -%D Even more important is that this alternative is fully -%D expandable! - -\long\def\doifnumberelse#1% does not accept counters - {\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - -%D \macros -%D {makerawcommalist, -%D rawdoinsetelse, -%D rawprocesscommalist, -%D rawprocessaction} -%D -%D Some of the commands mentioned earlier are effective but -%D slow. When one is desperately in need of faster alternatives -%D and when the conditions are predictable safe, the \type{\raw} -%D alternatives come into focus. A major drawback is that -%D they do not take \type{\c!constants} into account, simply -%D because no expansion is done. This is no problem with -%D \type{\rawprocesscommalist}, because this macro does not -%D compare anything. Expandable macros are permitted as search -%D string. -%D -%D \starttyping -%D \makerawcommalist[string,string,...]\stringlist -%D \rawdoifinsetelse{string}{string,...}{...}{...} -%D \rawprocesscommalist[string,string,...]\commando -%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c] -%D \stoptyping -%D -%D Spaces embedded in the list, for instance after commas, -%D spoil the search process. The gain in speed depends on the -%D length of the argument (the longer the argument, the less -%D we gain). -%D -%D The slow alternative looks like: -%D -%D \starttyping -%D \def\makerawcommalist[#1]#2% -%D {\def\appendtocommalist##1% -%D {\doifelse{#2}{} -%D {\edef#2{##1}} -%D {\edef#2{#2,##1}}}% -%D \def#2{}% -%D \processcommalist[#1]\appendtocommalist} -%D \stoptyping -%D -%D But we prefer: - -% \appendtocommalist is defined in syst-ext - -\def\makerawcommalist[#1]#2% use \processnext ... here - {\def\domakerawcommalist##1% we don't expand ##1 - {\ifx#2\empty - \def#2{##1}% - \else - \@EA\def\@EA#2\@EA{#2,##1}% - \fi}% - \let#2\empty - \processcommalist[#1]\domakerawcommalist} - -\def\rawprocesscommaitem#1,#2% #2 eats up preceding space - {\if]#1\else - \csname\s!next\the\commalevel\endcsname{#1}% - \expandafter\rawprocesscommaitem - \fi#2} - -\def\rawprocesscommalist[#1]#2% accepteert ook [\cs] - {\global\advance\commalevel \plusone - \expandafter\let\csname\s!next\the\commalevel\endcsname#2% - \expandafter\rawprocesscommaitem#1,],% \relax - \global\advance\commalevel \minusone } - -\def\rawprocesscommacommand[#1]% not really needed - {\expanded{\rawprocesscommalist[#1]}} - -% \def\rawdoifinsetelse#1#2{\doifinstringelse{,#1,}{,#2,}} -% \def\rawdoifinset #1#2{\doifinstring {,#1,}{,#2,}} - -\def\@@rawempty{,,} - -\long\def\rawdoifinsetelse#1% - {\edef\@@@instring{,#1,}% expand #1 here - \ifx\@@@instring\@@rawempty - \@EA\thirdofthreearguments - \else - \@EA\rawdodoifinsetelse - \fi} - -\long\def\rawdodoifinsetelse#1% - {\p!doifinstringelse\@@@instring{,#1,}% - \@EA\firstoftwoarguments - \else - \@EA\secondoftwoarguments - \fi} - -\long\def\rawdoifinset#1% - {\edef\@@@instring{,#1,}% expand #1 here - \ifx\@@@instring\@@rawempty - \@EA\gobbletwoarguments - \else - \@EA\rawdodoifinset - \fi} - -\long\def\rawdodoifinset#1%% - {\p!doifinstringelse\@@@instring{,#1,}% - \@EA\firstofoneargument - \else - \@EA\gobbleoneargument - \fi} - -%D Some more raw material: - -\def\p!rawprocessaction[#1][#2]% - {\def\pp!rawprocessaction##1,#1=>##2,##3\war% - {\if##3@\else - \def\!!processaction{##2}% - \fi}% - \pp!rawprocessaction,#2,#1=>,@\war} - -\def\rawprocessaction[#1]#2[#3]% - {\edef\!!stringa{#1}% - \edef\!!stringb{undefined}% better \!!undefined - \let\!!processaction\!!stringb - \ifx\!!stringa\empty - \@EA\p!rawprocessaction\@EA[\s!default][#3]% - \else - \expandafter\p!rawprocessaction\expandafter[\!!stringa][#3]% - \ifx\!!processaction\!!stringb - \@EA\p!rawprocessaction\@EA[\s!unknown][#3]% - \fi - \fi - \ifx\!!processaction\!!stringb - \else - \!!processaction - \fi} - -% not needed -% -% \def\rawprocessallactionsinset[#1]#2[#3]% -% {\def\docommand##1% -% {\rawprocessaction[##1][#3]}% -% \processcommalist[#1]\docommand} - -%D When we process the list \type{a,b,c,d,e}, the raw routine -%D takes over 30\% less time, when we feed $20+$ character -%D strings we gain about 20\%. Alternatives which use -%D \type{\futurelet} perform worse. Part of the speedup is -%D due to the \type{\let} and \type{\expandafter} in the test. - -% %D \macros -% %D {processunexpandedcommalist} -% %D -% %D When processing commalists, the arguments are expanded. The -% %D main reason for doing so lays in the fact that these -% %D macros are used for interfacing. The next alternative can be used -% %D for -% %D -% %D \starttyping -% %D \processunexpandedcommalist -% %D [\alfa\beta,\gamma,\delta\epsilon] -% %D \handleitem -% %D \stoptyping -% %D -% %D This time nesting is not supported. -% -% %\def\processunexpandedcommaitem#1,% -% % {\if]\noexpand#1% -% % \let\nextcommaitem\relax -% % \else -% % \handleunexpandedcommaitem{#1}% -% % \let\nextcommaitem\processunexpandedcommaitem -% \fi -% \nextcommaitem} -% -% faster: -% -% \def\processunexpandedcommaitem#1,% -% {\if]\noexpand#1\else -% \handleunexpandedcommaitem{#1}% -% \expandafter\processunexpandedcommaitem -% \fi} -% -% \def\processunexpandedcommalist[#1]#2% -% {\def\handleunexpandedcommaitem{#2}% -% \processunexpandedcommaitem#1,],}% \relax} -% -% %D Or faster: -% -% \def\processunexpandedcommaitem#1,% -% {\if]\noexpand#1\else -% \handleunexpandedcommaitem{#1}% -% \expandafter\processunexpandedcommaitem -% \fi} - -%D \macros -%D {dosetvalue,dosetevalue,dosetgvalue,docopyvalue,doresetvalue, -%D dogetvalue} -%D -%D When we are going to do assignments, we have to take -%D multi||linguality into account. For the moment we keep -%D things simple and single||lingual. -%D -%D \starttyping -%D \dosetvalue {label} {variable} {value} -%D \dosetevalue {label} {variable} {value} -%D \dosetgvalue {label} {variable} {value} -%D \docopyvalue {to label} {from label} {variable} -%D \doresetvalue {label} {variable} -%D \stoptyping -%D -%D These macros are in fact auxiliary ones and are not meant -%D for use outside the assignment macros. - -\def\dosetvalue#1#2% #3 - {\@EA\def\csname#1#2\endcsname} % {#3}} - -\def\dosetevalue#1#2% #3 - {\@EA\edef\csname#1#2\endcsname} % {#3}} - -\def\dosetgvalue#1#2% #3 - {\@EA\gdef\csname#1#2\endcsname} % {#3}} - -\def\doresetvalue#1#2% - {\@EA\let\csname#1#2\endcsname\empty} - -\def\doignorevalue#1#2#3% - {\@EA\let\csname#1#2\endcsname\empty} - -\def\docopyvalue#1#2#3% - {\@EA\def\csname#1#3\endcsname{\csname#2#3\endcsname}} - -%D \macros -%D {doassign,undoassign,doassignempty} -%D -%D Assignments are the backbone of \CONTEXT. Abhorred by the -%D concept of style file hacking, we took a considerable effort -%D in building a parameterized system. Unfortunately there is a -%D price to pay in terms of speed. Compared to other packages -%D and taking the functionality of \CONTEXT\ into account, the -%D total size of the format file is still very acceptable. Now -%D how are these assignments done. -%D -%D Assignments can be realized with: -%D -%D \starttyping -%D \doassign[label][variable=value] -%D \undoassign[label][variable=value] -%D \stoptyping -%D -%D and: -%D -%D \starttyping -%D \doassignempty[label][variable=value] -%D \stoptyping -%D -%D Assignments like \type{\doassign} are compatible with: -%D -%D \starttyping -%D \def\labelvariable{value} -%D \stoptyping -%D -%D We do check for the presence of an \type{=} and loudly -%D complain of it's missed. We will redefine this macro later -%D on, when a more advanced message mechanism is implemented. - -\newif\iferrorisfatal - -\def\waitonfatalerror - {\iferrorisfatal\wait\fi} - -\def\showassignerror#1#2% - {\writestatus{setup}{missing or ungrouped '=' after '#1' in line #2}% - \waitonfatalerror} - -%\def\p!doassign#1[#2][#3=#4=#5]% -% {\let\donottest\dontprocesstest -% \edef\!!stringa{#5}% -% \let\!!stringb\relax -% \let\donottest\doprocesstest -% \ifx\!!stringa\!!stringb -% \showassignerror{#3}% -% \else -% #1{#2}{#3}{#4}% -% \fi} - -\def\p!doassign#1[#2][#3=#4=#5]% - {\ifx\empty#3\else % and definitely not \ifx#3\empty - \ifx\relax#5% - \showassignerror{#3}{\the\inputlineno\space(#2)}% - \else - #1{#2}{#3}{#4}% - \fi - \fi} - -\def\doassign [#1][#2]{\p!doassign\dosetvalue [#1][#2==\relax]} -\def\doeassign [#1][#2]{\p!doassign\dosetevalue [#1][#2==\relax]} -\def\undoassign[#1][#2]{\p!doassign\doresetvalue[#1][#2==\relax]} - -\def\doassignempty[#1][#2=#3]% - {\ifundefined{#1#2}\dosetvalue{#1}{#2}{#3}\fi} - -%D \macros -%D {processassignmentlist,processassignmentcommand, -%D startprocessassignmentlist,startprocessassignmentcommand} -%D -%D For Wolfgang: -%D -%D \starttyping -%D \def\showpair#1#2{key:#1, value:#2\par} -%D \processassignmentlist[a=1,b=2]\showpair -%D \stoptyping - -\def\processassignmentlist[#1]#2% #2 == \command{key}{value] - {\def\doprocessassignmententry##1{#2}% {##2}{##3} % namespace is ignored - \dogetparameters\doprocessassignmententry[][#1]} - -\def\processassignmentcommand[#1]% - {\normalexpanded{\noexpand\processassignmentlist[#1]}} - -\long\def\startprocessassignmentlist[#1]#2\stopprocessassignmentlist - {\long\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}% - \processassignmentlist[#1]\currentassignmentlistcommand} - -\long\def\startprocessassignmentcommand[#1]#2\stopprocessassignmentcommand - {\long\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}% - \normalexpanded{\noexpand\processassignmentlist[#1]}\currentassignmentlistcommand} - -%D \macros -%D {getparameters,geteparameters,getgparameters, -%D forgetparameters} -%D -%D Using the assignment commands directly is not our -%D ideal of user friendly interfacing, so we take some further -%D steps. -%D -%D \starttyping -%D \getparameters [label] [...=...,...=...] -% %D \forgetparameters [label] [...=...,...=...] -%D \stoptyping -%D -%D Again, the label identifies the category a variable -%D belongs to. The second argument can be a comma separated -%D list of assignments. -%D -%D \starttyping -%D \getparameters -%D [demo] -%D [alfa=1, -%D beta=2] -%D \stoptyping -%D -%D is equivalent to -%D -%D \starttyping -%D \def\demoalfa{1} -%D \def\demobeta{2} -%D \stoptyping -%D -%D -%D In the pre||multi||lingual stadium \CONTEXT\ took the next -%D approach. With -%D -%D \starttyping -%D \def\??demo {@@demo} -%D \def\!!alfa {alfa} -%D \def\!!beta {beta} -%D \stoptyping -%D -%D calling -%D -%D \starttyping -%D \getparameters -%D [\??demo] -%D [\!!alfa=1, -%D \!!beta=2] -%D \stoptyping -%D -%D lead to: -%D -%D \starttyping -%D \def\@@demoalfa{1} -%D \def\@@demobeta{2} -%D \stoptyping -%D -%D Because we want to be able to distinguish the \type{!!} -%D pre||tagged user supplied variables from internal -%D counterparts, we will introduce a slightly different tag in -%D the multi||lingual modules. There we will use \type{c!} or -%D \type{v!}, depending on the context. -%D -%D By calling \type{\p!doassign} directly, we save ourselves -%D some argument passing and gain some speed. Whatever -%D optimizations we do, this command will always be one of the -%D bigger bottlenecks. -%D -%D The alternative \type{\geteparameters} --- it's funny to -%D see that this alternative saw the light so lately --- can be -%D used to do expanded assigments. - -\def\dogetparameters#1[#2]#3[#4]% - {\def\p!dogetparameter##1% - {\p!doassign#1[#2][##1==\relax]}% - \processcommalist[#4]\p!dogetparameter} - -\def\getparameters {\dogetparameters\dosetvalue} -\def\geteparameters {\dogetparameters\dosetevalue} -\def\getgparameters {\dogetparameters\dosetgvalue} -\def\forgetparameters{\dogetparameters\doignorevalue} - -\let\getexpandedparameters=\geteparameters - -%D This one is slightly faster: - -\def\dogetparameters#1[#2]#3[#4% - {\if\noexpand#4]% - \expandafter\gobbleoneargument - \else - \def\p!dogetparameter##1{\p!doassign#1[#2][##1==\relax]}% - \expandafter\xdogetparameters - \fi#4} - -\def\xdogetparameters#1]% - {\processcommalist[#1]\p!dogetparameter} - -%D The next alternative is much faster but also uglier. Because -%D in \XML\ processing we will probably set much more parameters -%D than normally we need this faster one. - -\def\dogetparameters#1[#2]#3[#4% - {\if\noexpand#4]% - \expandafter\gobbleoneargument - \else - \def\p!dogetparameter{\p!doassign#1#2}% - \expandafter\xdogetparameters - \fi#4} - -\def\xdogetparameters#1]% - {\xprocesscommaitem#1,],\@relax@} - -% \long\def\xprocesscommaitem#1,#2% #2 takes space before , -% {\if]#1% -% \expandafter\gobbleoneargument -% \else -% \p!dogetparameter\@relax@#1==\@relax@ -% \expandafter\xprocesscommaitem -% \fi#2} - -\long\def\xprocesscommaitem#1,#2% #2 takes space before , - {\if,#1,% dirty trick for testing #1=empty - \@EA\xprocesscommaitem - \else\if]#1% - \@EAEAEA\gobbleoneargument - \else - \p!dogetparameter\@relax@#1==\empty\@relax@ - \@EAEAEA\xprocesscommaitem - \fi\fi#2} - -%D Here we use a slightly different assignment macro: - -% \def\p!doassign#1#2\@relax@#3=#4=#5\@relax@ -% {\ifx\@relax@#5\@EA\xshowassignerror\else\@EA#1\fi{#2}{#3}{#4}} - -% \def\p!doassign#1#2\@relax@#3=#4=#5\@relax@ -% {\ifx#5\empty\@EA\xshowassignerror\else\@EA#1\fi{#2}{#3}{#4}} - -\def\p!doassign#1#2\@relax@#3=#4=#5#6\@relax@ - {\ifx#5\empty - \@EA\xshowassignerror - \else\ifx#5=% - \@EAEAEA#1% - \else - \@EAEAEA\xshowassignerror - \fi\fi - {#2}{#3}{#4}} - -\def\xshowassignerror#1#2#3% - {\showassignerror{#2}{\the\inputlineno\space(#1)}} - -%D Now we also have to change the other macros that depend -%D on this low level one. - -% \def\doassign [#1][#2]{\p!doassign\dosetvalue #1\@relax@#2==\@relax@} -% \def\doeassign [#1][#2]{\p!doassign\dosetevalue #1\@relax@#2==\@relax@} -% \def\undoassign[#1][#2]{\p!doassign\doresetvalue#1\@relax@#2==\@relax@} - -\def\doassign [#1][#2]{\p!doassign\dosetvalue #1\@relax@#2==\empty\@relax@} -\def\doeassign [#1][#2]{\p!doassign\dosetevalue #1\@relax@#2==\empty\@relax@} -\def\undoassign[#1][#2]{\p!doassign\doresetvalue#1\@relax@#2==\empty\@relax@} - -%D When someone asked on the mailing list if it's possible to -%D use the current value of a parameter, Taco posted a small module. His -%D method had the disadvantage of making all assignments expanded and thereby -%D fragile. The following alternative uses a prefix. - -%D \macros{currentvalue} -%D -%D Just in case a \type{\getparameter} argument itself ends up -%D inside a \type{\write} or other expandable location, our -%D new macro needs a default value. - -\let\currentvalue\empty - -% \def\p!n!doassign#1#2\@relax@#3=#4=#5#6\@relax@% normal -% {\ifx#5\empty -% \@EA\xshowassignerror -% \else\ifx#5=% -% \@EAEAEA#1% -% \else -% \@EAEAEA\xshowassignerror -% \fi\fi -% {#2}{#3}{#4}} - -\def\p!n!doassign#1#2\@relax@#3=#4=#5#6\@relax@ - {\ifx\empty#3\empty - \@EA\xshowassignerror - \else\ifx#5\empty - \@EAEAEA\xshowassignerror - \else - \@EAEAEA#1% - \fi\fi - {#2}{#3}{#4}} - -\beginTEX - -% \def\p!e!doassign#1#2\@relax@#3=#4=#5#6\@relax@ -% {\ifx#5\empty -% \@EA\xshowassignerror -% \else\ifx#5=% -% \@EA\ifx\csname#2#3\endcsname\relax -% \let\currentvalue\empty -% \else -% \@EA\let\@EA\currentvalue\csname#2#3\endcsname -% \fi -% \@EAEAEA#1% -% \else -% \@EAEAEA\xshowassignerror -% \fi\fi -% {#2}{#3}{#4}} - -\def\p!e!doassign#1#2\@relax@#3=#4=#5#6\@relax@ - {\ifx\empty#3\empty - \@EA\xshowassignerror - \else\ifx#5\empty - \@EAEAEA\xshowassignerror - \else - \@EA\ifx\csname#2#3\endcsname\relax - \let\currentvalue\empty - \else - \@EA\let\@EA\currentvalue\csname#2#3\endcsname - \fi - \@EAEAEA#1% - \fi\fi - {#2}{#3}{#4}} - -\endTEX - -\beginETEX - -% \def\p!e!doassign#1#2\@relax@#3=#4=#5#6\@relax@ -% {\ifx#5\empty -% \@EA\xshowassignerror -% \else\ifx#5=% -% \ifcsname#2#3\endcsname -% \@EA\let\@EA\currentvalue\csname#2#3\endcsname -% \else -% \let\currentvalue\empty -% \fi -% \@EAEAEA#1% -% \else -% \@EAEAEA\xshowassignerror -% \fi\fi -% {#2}{#3}{#4}} - -\def\p!e!doassign#1#2\@relax@#3=#4=#5#6\@relax@ - {\ifx\empty#3\empty - \@EA\xshowassignerror - \else\ifx#5\empty - \@EAEAEA\xshowassignerror - \else - \ifcsname#2#3\endcsname - \@EA\let\@EA\currentvalue\csname#2#3\endcsname - \else - \let\currentvalue\empty - \fi - \@EAEAEA#1% - \fi\fi - {#2}{#3}{#4}} - -\endETEX - -%D We default to: - -\let\p!doassign\p!n!doassign - -%D And set: - -\let\currentvalue\empty - -%D \macros {expandparameters} -%D -%D Example usage: -%D -%D \startbuffer -%D \getparameters[taco][name=taco] -%D \convertcommand\taconame\to\ascii \ascii -%D \expandparameters \getparameters[taco][name=\currentvalue\space hoekwater] -%D \convertcommand\taconame\to\ascii \ascii -%D \getparameters[taco][name=\currentvalue\space hoekwater] -%D \convertcommand\taconame\to\ascii \ascii -%D \stopbuffer -%D -%D \typebuffer -%D \startlines -%D \getbuffer -%D \stoplines - -%D Here we hook in the code (beware, this is the optimized get **): - -\def\xdoget@n@parameters#1]% - {\xprocesscommaitem#1,],\@relax@} - -\def\xdoget@e@parameters#1]% - {\let\dosetnvalue\dosetvalue - \let\dosetvalue\dosetevalue - \let\p!doassign\p!e!doassign - \xprocesscommaitem#1,],\@relax@ - \let\p!doassign\p!n!doassign - \let\dosetvalue\dosetnvalue - \let\xdogetparameters\xdoget@n@parameters - \let\currentvalue\empty} - -\let\xdogetparameters\xdoget@n@parameters % ** - -\def\expandparameters{\let\xdogetparameters\xdoget@e@parameters} - -%D \macros -%D {getemptyparameters} -%D -%D Sometimes we explicitly want variables to default to an -%D empty string, so we welcome: -%D -%D \starttyping -%D \getemptyparameters [label] [...=...,...=...] -%D \stoptyping - -\def\getemptyparameters[#1]#2[#3]% - {\def\p!dogetemptyparameter##1% - {\doassignempty[#1][##1]}% - \processcommalist[#3]\p!dogetemptyparameter} - -%D \macros -%D {copyparameters} -%D -%D Some \CONTEXT\ commands take their default setups from -%D others. All commands that are able to provide backgounds -%D or rules around some content, for instance default to the -%D standard command for ruled boxes. Is situations like this -%D we can use: -%D -%D \starttyping -%D \copyparameters [to-label] [from-label] [name1,name2,...] -%D \stoptyping -%D -%D For instance -%D -%D \starttyping -%D \copyparameters -%D [internal][external] -%D [alfa,beta] -%D \stoptyping -%D -%D Leads to: -%D -%D \starttyping -%D \def\internalalfa {\externalalfa} -%D \def\internalbeta {\externalbeta} -%D \stoptyping -%D -%D By using \type{\docopyvalue} we've prepared this command -%D for use in a multi||lingual environment. - -\def\copyparameters[#1]#2[#3]#4[#5]% - {\doifnot{#1}{#3} - {\def\docopyparameter{\docopyvalue{#1}{#3}}% - %\def\docopyparameter##1{\docopyvalue{#1}{#3}{##1}}% - \processcommalist[#5]\docopyparameter}} - -%D \macros -%D {ifparameters,checkparameters} -%D -%D A slightly different one is \type{\checkparameters}, which -%D also checks on the presence of a~\type{=}. -%D -%D The boolean \type{\ifparameters} can be used afterwards. -%D Combining both in one \type{\if}||macro would lead to -%D problems with nested \type{\if}'s. -%D -%D \starttyping -%D \checkparameters[argument] -%D \stoptyping - -\newif\ifparameters - -\def\p!checkparameters#1=#2#3\war% - {\if#2@\parametersfalse\else\parameterstrue\fi} - -\def\checkparameters[#1]% - {\p!checkparameters#1=@@\war} - -%D \macros -%D {getfromcommalist,getfromcommacommand, -%D commalistelement, -%D getcommalistsize,getcommacommandsize} -%D -%D It's possible to get an element from a commalist or a -%D command representing a commalist. -%D -%D \starttyping -%D \getfromcommalist [string] [n] -%D \getfromcommacommand [string,\strings,string,...] [n] -%D \stoptyping -%D -%D The difference betwee the two of them is the same as the -%D difference between \type{\processcomma...}. The found string -%D is stored in \type{\commalistelement}. -%D -%D We can calculate the size of a comma separated list by -%D using: -%D -%D \starttyping -%D \getcommalistsize [string,string,...] -%D \getcommacommandsize [string,\strings,string,...] -%D \stoptyping -%D -%D Afterwards, the length is available in the macro -%D \type{\commalistsize} (not a \COUNTER). - -\newcount\commalistcounter - -\def\commalistsize{0} - -\def\p!dogetcommalistsize#1% - {\advance\commalistcounter\plusone} - -\def\getcommalistsize#1]% don't loose [{#1}] - {\commalistcounter\zerocount - \processcommalist#1]\p!dogetcommalistsize % was [{#1}] - \edef\commalistsize{\the\commalistcounter}} - -\def\getcommacommandsize[#1]% - {\edef\commacommand{#1}% - \scratchtoks\expandafter{\expandafter[\commacommand]}% - \expandafter\getcommalistsize\the\scratchtoks } - -% to be tested first -% -% \def\getcommacommandsize[#1]% -% {\expanded{\getcommalistsize[#1]}} - -% \def\p!dogetfromcommalist#1% -% {\advance\commalistcounter \minusone -% \ifcase\commalistcounter -% \def\commalistelement{#1}% -% \begingroup\def\doprocesscommaitem##1]{\endgroup}% -% \fi} - -\def\p!dogetfromcommalist#1% - {\advance\commalistcounter \minusone - \ifcase\commalistcounter - \def\commalistelement{#1}% - \expandafter\quitcommalist - \fi} - -\def\getfromcommalist[#1]#2[#3]% - {\let\commalistelement\empty - \commalistcounter#3\relax - \processcommalist[#1]\p!dogetfromcommalist} - -% \def\getfromcommacommand[#1]% why so complicated, still needed? -% {\edef\commacommand{#1}% -% \toks0=\expandafter{\expandafter[\commacommand]}% -% \expandafter\getfromcommalist\the\toks0 } - -\def\getfromcommacommand[#1]% - {\expanded{\getfromcommalist[#1]}} - -%D Because 0, 1 and~2 are often asked for, we optimize this -%D macro for those cases. The indirect call however slows -%D down the other cases. -%D -%D \starttyping -%D \def\p!dogetfirstfromcommalist [#1,#2]{\def\commalistelement{#1}} -%D \def\p!dogetsecondfromcommalist[#1,#2,#3]{\def\commalistelement{#2}} -%D \let\p!dogetotherfromcommalist=\getfromcommalist -%D -%D \def\getfromcommalist[#1]#2[#3]% optimized for 0,1,2 -%D {\ifcase#3\relax -%D \let\commalistelement\empty -%D \or -%D \p!dogetfirstfromcommalist[#1,]% -%D \or -%D \p!dogetsecondfromcommalist[#1,,]% -%D \else -%D \p!dogetotherfromcommalist[#1][#3]% -%D \fi} -%D \stoptyping -%D -%D Even worse, this alternative does not strip preceding -%D spaces, which is what we want. So, we stick to the slow -%D alternative. - -%D Watertight (and efficient) solutions are hard to find, due -%D to the handling of braces during parameters passing and -%D scanning. Nevertheless: -%D -%D \startbuffer -%D \def\dosomething#1{(#1=\commalistsize) } -%D -%D \getcommalistsize [\hbox{$a,b,c,d,e,f$}] \dosomething 1 -%D \getcommalistsize [{a,b,c,d,e,f}] \dosomething 1 -%D \getcommalistsize [{a,b,c},d,e,f] \dosomething 4 -%D \getcommalistsize [a,b,{c,d,e},f] \dosomething 4 -%D \getcommalistsize [a{b,c},d,e,f] \dosomething 4 -%D \getcommalistsize [{a,b}c,d,e,f] \dosomething 4 -%D \getcommalistsize [] \dosomething 0 -%D \getcommalistsize [{[}] \dosomething 1 -%D \stopbuffer -%D -%D \typebuffer -%D -%D reports: -%D -%D \getbuffer - -%D \macros -%D {dogetcommalistelement,dogetcommacommandelement} -%D -%D For low level (fast) purposes, we can also use the next -%D alternative, which can handle 8~elements at most. -%D -%D \starttyping -%D \dogetcommalistelement1\from a,b,c\to\commalistelement -%D \stoptyping - -\def\dodogetcommalistelement#1\from#2,#3,#4,#5,#6,#7,#8\to#9% - {\edef#9{\ifcase#1\relax\or#2\or#3\or#4\or#5\or#6\or#7\or#8\fi}} - -% maybe better: -% -% {\@EA\edef\@EA#9\@EA{\ifcase#1\relax\or#2\or#3\or#4\or#5\or#6\or#7\or#8\fi}} - -\def\dogetcommalistelement#1\from#2\to% - {\dodogetcommalistelement#1\from#2,,,,,,\to} - -% check sources - -\def\dogetcommacommandelement#1\from#2\to% - {\@EA\dodogetcommalistelement\@EA#1\@EA\from#2,,,,,,\to} - -%D \macros -%D {dosingleargument,dodoubleargument,dotripleargument, -%D doquadrupleargument,doquintupleargument,dosixtupleargument, -%D doseventupleargument} -%D -%D When working with delimited arguments, spaces and -%D lineendings can interfere. The next set of macros uses -%D \TEX' internal scanner for grabbing everything between -%D arguments. Forgive me the funny names. -%D -%D \starttyping -%D \dosingleargument\commando = \commando[#1] -%D \dodoubleargument\commando = \commando[#1][#2] -%D \dotripleargument\commando = \commando[#1][#2][#3] -%D \doquadrupleargument\commando = \commando[#1][#2][#3][#4] -%D \doquintupleargument\commando = \commando[#1][#2][#3][#4][#5] -%D \dosixtupleargument\commando = \commando[#1][#2][#3][#4][#5][#6] -%D \doseventupleargument\command= \commando[#1][#2][#3][#4][#5][#6][#7] -%D \stoptyping -%D -%D These macros are used in the following way: -%D -%D \starttyping -%D \def\dosetupsomething[#1][#2]% -%D {... #1 ... #2 ...} -%D -%D \def\setupsomething% -%D {\dodoubleargument\dosetupsomething} -%D \stoptyping -%D -%D The implementation can be surprisingly simple and needs no -%D further explanation, like: -%D -%D \starttyping -%D \def\dosingleargument#1[#2]% -%D {#1[#2]} -%D \def\dotripleargument#1[#2]#3[#4]#5[#6]% -%D {#1[#2][#4][#6]} -%D \def\doquintupleargument#1% -%D {\def\dodoquintupleargument[##1]##2[##3]##4[##5]##6[##7]##8[##9]% -%D {#1[##1][##3][##5][##7][##9]}% -%D \dodoquintupleargument} -%D \stoptyping -%D -%D Because \TEX\ accepts 9~arguments at most, we have to use -%D two||step solution when getting five or more arguments. -%D -%D When developing more and more of the real \CONTEXT, we -%D started using some alternatives that provided empty -%D arguments (in fact optional ones) whenever the user failed -%D to supply them. Because this more complicated macros enable -%D us to do some checking, we reimplemented the non||empty -%D ones. - -\def\dosingleargument {\chardef\expectedarguments 1 \dosingleempty } -\def\dodoubleargument {\chardef\expectedarguments 2 \dodoubleempty } -\def\dotripleargument {\chardef\expectedarguments 3 \dotripleempty } -\def\doquadrupleargument {\chardef\expectedarguments 4 \doquadrupleempty } -\def\doquintupleargument {\chardef\expectedarguments 5 \doquintupleempty } -\def\dosixtupleargument {\chardef\expectedarguments 6 \dosixtupleempty } -\def\doseventupleargument{\chardef\expectedarguments 7 \doseventupleempty} - -%D \macros -%D {iffirstagument,ifsecondargument,ifthirdargument, -%D iffourthargument,iffifthargument,ifsixthargument, -%D ifseventhargument} -%D -%D We use some signals for telling the calling macros if all -%D wanted arguments are indeed supplied by the user. - -\newif\iffirstargument -\newif\ifsecondargument -\newif\ifthirdargument -\newif\iffourthargument -\newif\iffifthargument -\newif\ifsixthargument -\newif\ifseventhargument - -%D \macros -%D {dosingleempty,dodoubleempty,dotripleempty, -%D doquadrupleempty,doquintupleempty,dosixtupeempty, -%D doseventupleempty} -%D -%D The empty argument supplying macros mentioned before, look -%D like: -%D -%D \starttyping -%D \dosingleempty \command -%D \dodoubleempty \command -%D \dotripleempty \command -%D \doquadrupleempty \command -%D \doquintupleempty \command -%D \dosixtupleempty \command -%D \doseventupleempty\command -%D \stoptyping -%D -%D So \type{\dodoubleempty} leades to: -%D -%D \starttyping -%D \command[#1][#2] -%D \command[#1][] -%D \command[][] -%D \stoptyping -%D -%D Depending of the generousity of the user. Afterwards one can -%D use the \type{\if...argument} boolean. For novice: watch -%D the stepwise doubling of \type{#}'s - -% idea: \ignorespaces afterwards - -\chardef\noexpectedarguments=0 -\chardef\expectedarguments =0 - -\def\showargumenterror#1#2% - {\writestatus{systems}{#1 argument(s) expected in line #2}} - -% \long\def\dogetargument#1#2#3#4% redefined in mult-ini -% {\doifnextcharelse{#1} -% {\let\expectedarguments\noexpectedarguments -% #3\dodogetargument} -% {\ifnum\expectedarguments>\noexpectedarguments -% \showargumenterror{\expectedarguments} -% \fi -% \let\expectedarguments\noexpectedarguments -% #4\dodogetargument#1#2}} -% -% less to pass - -\def\doshowargumenterror - {\ifnum\expectedarguments>\noexpectedarguments - \showargumenterror{\number\expectedarguments}{\number\inputlineno}% - \fi - \noshowargumenterror} - -\def\noshowargumenterror - {\let\expectedarguments\noexpectedarguments} - -% \long\def\dogetargument#1#2#3#4% -% {\doifnextcharelse#1% -% {\noshowargumenterror#3\dodogetargument} -% {\doshowargumenterror#4\dodogetargument#1#2}} -% -% faster ? - -\long\def\dogetargument#1#2#3#4% - {\let\charactertoken=#1% - \def\!!stringa{\noshowargumenterror#3\dodogetargument}% - \def\!!stringb{\doshowargumenterror#4\dodogetargument#1#2}% - \futurelet\nexttoken\inspectnextcharacter} - -\def\getsingleempty#1#2#3% - {\def\dodogetargument% - {#3}% - \dogetargument#1#2\firstargumenttrue\firstargumentfalse} - -\def\getdoubleempty#1#2#3% - {\def\dodogetargument#1##1#2% - {\def\dodogetargument% - {#3#1{##1}#2}% - \dogetargument#1#2\secondargumenttrue\secondargumentfalse}% - \dogetargument#1#2\firstargumenttrue\firstargumentfalse} - -\def\gettripleempty#1#2#3% - {\def\dodogetargument#1##1#2% - {\def\dodogetargument#1####1#2% - {\def\dodogetargument% - {#3#1{##1}#2% - #1{####1}#2}% - \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}% - \dogetargument#1#2\secondargumenttrue\secondargumentfalse}% - \dogetargument#1#2\firstargumenttrue\firstargumentfalse} - -\def\getquadrupleempty#1#2#3% - {\def\dodogetargument#1##1#2% - {\def\dodogetargument#1####1#2% - {\def\dodogetargument#1########1#2% - {\def\dodogetargument% - {#3#1{##1}#2% - #1{####1}#2% - #1{########1}#2}% - \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}% - \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}% - \dogetargument#1#2\secondargumenttrue\secondargumentfalse}% - \dogetargument#1#2\firstargumenttrue\firstargumentfalse} - -\def\getquintupleempty#1#2#3% - {\def\dodogetargument#1##1#2% - {\def\dodogetargument#1####1#2% - {\def\dodogetargument#1########1#2% - {\def\dodogetargument#1################1#2% - {\def\dodogetargument% - {#3#1{##1}#2% - #1{####1}#2% - #1{########1}#2% - #1{################1}#2}% - \dogetargument#1#2\fifthargumenttrue\fifthargumentfalse}% - \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}% - \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}% - \dogetargument#1#2\secondargumenttrue\secondargumentfalse}% - \dogetargument#1#2\firstargumenttrue\firstargumentfalse} - -\def\getsixtupleempty#1#2#3% - {\def\dodogetargument#1##1#2% - {\def\dodogetargument#1####1#2% - {\def\dodogetargument#1########1#2% - {\def\dodogetargument#1################1#2% - {\def\dodogetargument#1################################1#2% - {\def\dodogetargument% - {#3#1{##1}#2% - #1{####1}#2% - #1{########1}#2% - #1{################1}#2% - #1{################################1}#2}% - \dogetargument#1#2\sixthargumenttrue\sixthargumentfalse}% - \dogetargument#1#2\fifthargumenttrue\fifthargumentfalse}% - \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}% - \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}% - \dogetargument#1#2\secondargumenttrue\secondargumentfalse}% - \dogetargument#1#2\firstargumenttrue\firstargumentfalse} - -\def\getseventupleempty#1#2#3% - {\def\dodogetargument#1##1#2% - {\def\dodogetargument#1####1#2% - {\def\dodogetargument#1########1#2% - {\def\dodogetargument#1################1#2% - {\def\dodogetargument#1################################1#2% - {\def\dodogetargument#1################################% - ################################1#2% - {\def\dodogetargument% - {#3#1{##1}#2% - #1{####1}#2% - #1{########1}#2% - #1{################1}#2% - #1{################################1}#2% - #1{################################% - ################################1}#2}% - \dogetargument#1#2\seventhargumenttrue\seventhargumentfalse}% - \dogetargument#1#2\sixthargumenttrue\sixthargumentfalse}% - \dogetargument#1#2\fifthargumenttrue\fifthargumentfalse}% - \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}% - \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}% - \dogetargument#1#2\secondargumenttrue\secondargumentfalse}% - \dogetargument#1#2\firstargumenttrue\firstargumentfalse} - -\def\dosingleempty {\getsingleempty []} -\def\dodoubleempty {\getdoubleempty []} -\def\dotripleempty {\gettripleempty []} -\def\doquadrupleempty {\getquadrupleempty []} -\def\doquintupleempty {\getquintupleempty []} -\def\dosixtupleempty {\getsixtupleempty []} -\def\doseventupleempty{\getseventupleempty[]} - -%D Because some of these are called quite often, we will now -%D replace the more general version by alternatives tuned for -%D speed. - -\def\dosingleempty#1% - {\noshowargumenterror % \relax % prevents lookahead, brr - \doifnextoptionalelse - {\firstargumenttrue#1} - {\dosinglefakeempty#1}} - -\def\dodoubleempty#1% - {\noshowargumenterror % \relax % prevents lookahead, brr - \doifnextoptionalelse - {\dodoubletestempty#1} - {\dodoublefakeempty#1}} - -\def\dotripleempty#1% - {\noshowargumenterror % \relax % prevents lookahead, brr - \doifnextoptionalelse - {\dotripletestempty#1} - {\dotriplefakeempty#1}} - -\def\dosinglefakeempty#1% - {\firstargumentfalse#1[]} - -\def\dodoublefakeempty#1% - {\firstargumentfalse\secondargumentfalse#1[][]} - -\def\dotriplefakeempty#1% - {\firstargumentfalse\secondargumentfalse\thirdargumentfalse#1[][][]} - -\long\def\dodoubletestempty#1[#2]% - {\firstargumenttrue - \doifnextoptionalelse - {\secondargumenttrue #1[{#2}]} - {\secondargumentfalse#1[{#2}][]}} - -\long\def\dotripletestempty#1[#2]% - {\firstargumenttrue - \doifnextoptionalelse - {\dotripletestemptyx #1[{#2}]} - {\secondargumentfalse - \thirdargumentfalse #1[{#2}][][]}} - -\long\def\dotripletestemptyx#1[#2][#3]% - {\secondargumenttrue - \doifnextoptionalelse - {\thirdargumenttrue #1[{#2}][{#3}]} - {\thirdargumentfalse#1[{#2}][{#3}][]}} - -%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}. - -\def\strippedcsname% - {\expandafter\gobbleoneargument\string} - -%D \macros -%D {complexorsimple,complexorsimpleempty} -%D -%D Setups can be optional. A command expecting a setup is -%D prefixed by \type{\complex}, a command without one gets the -%D prefix \type{\simple}. Commands like this can be defined by: -%D -%D \starttyping -%D \complexorsimple\command -%D \stoptyping -%D -%D When \type{\command} is followed by a \type{[setup]}, then -%D -%D \starttyping -%D \complexcommand [setup] -%D \stoptyping -%D -%D executes, else we get -%D -%D \starttyping -%D \simplecommand -%D \stoptyping -%D -%D An alternative for \type{\complexorsimple} is: -%D -%D \starttyping -%D \complexorsimpleempty {command} -%D \stoptyping -%D -%D Depending on the presence of \type{[setup]}, this one -%D leads to one of: -%D -%D \starttyping -%D \complexcommando [setup] -%D \complexcommando [] -%D \stoptyping -%D -%D Many \CONTEXT\ commands started as complex or simple ones, -%D but changed into more versatile (more object oriented) ones -%D using the \type{\get..argument} commands. - -% This method is needed when traditional tex is used with -% the efficient definition (marked **) below. - -% an old one: -% -% \def\setnameofcommand#1% handles {abc} as well as \abc -% {\begingroup -% \escapechar=-1 -% \globaldefs=0 % pretty important! -% \xdef\nameofcommand{\string#1}% -% \endgroup} -% -% \def\complexorsimple#1% -% {\setnameofcommand{#1}% -% \doifnextcharelse{[} -% {\firstargumenttrue \getvalue{\s!complex\nameofcommand}} -% {\firstargumentfalse\getvalue{\s!simple \nameofcommand}}} -% -% \def\complexorsimpleempty#1% -% {\setnameofcommand{#1}% -% \doifnextcharelse{[} -% {\firstargumenttrue \getvalue{\s!complex\nameofcommand}} -% {\firstargumentfalse\getvalue{\s!complex\nameofcommand}[]}} -% -% a newer one: - -\def\complexorsimple#1% - {% \relax % prevents lookahead, brrr - \doifnextoptionalelse - {\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname} - {\firstargumentfalse\csname\s!simple \strippedcsname#1\endcsname}} - -\def\complexorsimpleempty#1% - {% \relax % prevents lookahead, brrr - \doifnextoptionalelse - {\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname} - {\firstargumentfalse\csname\s!complex\strippedcsname#1\endcsname[]}} - -%D \macros -%D {definecomplexorsimple,definecomplexorsimpleempty} -%D -%D The previous commands are used that often that we found it -%D worthwile to offer two more alternatives. Watch the build -%D in protection. - -% See earlier. Because we don't want \type {\simple..} and -% \type {\complex..} commands to show up in expansions, we need -% to pass them as \type {simple..} and \type {complex..}. - -% \beginTEX -% -% \def\definewithnameofcommand#1#2% -% {\setnameofcommand{#2}% -% \@EA\def\@EA#2\@EA{\@EA\donottest\@EA#1\@EA{\nameofcommand}}} -% -% \def\definecomplexorsimple% -% {\definewithnameofcommand\complexorsimple} -% -% \def\definecomplexorsimpleempty% -% {\definewithnameofcommand\complexorsimpleempty} -% -% \endTEX -% -% \beginETEX \protected -% -% \def\definecomplexorsimple#1% -% {\normalprotected\def#1{\complexorsimple#1}} -% -% \def\definecomplexorsimpleempty#1% -% {\normalprotected\def#1{\complexorsimpleempty#1}} -% -% \endETEX - -% However, since this one uses an idirect method, things go -% okay (at the cost of extra macros). - -% \def\definecomplexorsimple#1% -% {\unexpanded\def#1{\complexorsimple#1}} -% -% \def\definecomplexorsimpleempty#1% -% {\unexpanded\def#1{\complexorsimpleempty#1}} -% -% faster, since no \strippedcsname needed in call, but more spacy - -\def\docomplexorsimple#1#2% - {\doifnextoptionalelse{\firstargumenttrue#1}{\firstargumentfalse#2}} - -\def\docomplexorsimpleempty#1% - {\doifnextoptionalelse{\firstargumenttrue#1}{\firstargumentfalse#1[]}} - -\def\definecomplexorsimple#1% - {\unexpanded\edef#1% - {\noexpand\docomplexorsimple - \@EA\noexpand\csname\s!complex\strippedcsname#1\endcsname - \@EA\noexpand\csname\s!simple \strippedcsname#1\endcsname}} - -\def\definecomplexorsimpleempty#1% - {\unexpanded\edef#1% - {\noexpand\docomplexorsimpleempty - \@EA\noexpand\csname\s!complex\strippedcsname#1\endcsname}} - -%D These commands are called as: -%D -%D \starttyping -%D \definecomplexorsimple\command -%D \stoptyping -%D -%D Of course, we must have available -%D -%D \starttyping -%D \def\complexcommand[#1]{...} -%D \def\simplecommand {...} -%D \stoptyping -%D -%D Using this construction saves a few string now and then. - -%D \macros -%D {definestartstopcommand} -%D -%D Those who get the creeps of expansion may skip the next -%D one. It's one of the most recent additions and concerns -%D \type{\start}||\type{\stop} pairs with complicated -%D arguments. -%D -%D We won't go into details here, but the general form of -%D this using this command is: -%D -%D \starttyping -%D \definestartstopcommand\somecommand\e!specifier{arg}{arg}% -%D {do something with arg} -%D \stoptyping -%D -%D This expands to something like: -%D -%D \starttyping -%D \def\somecommand arg \startspecifier arg \stopspecifier% -%D {do something with arg} -%D \stoptyping -%D -%D The arguments can be anything reasonable, but double -%D \type{#}'s are needed in the specification part, like: -%D -%D \starttyping -%D \definestartstopcommand\somecommand\e!specifier{[##1][##2]}{##3}% -%D {do #1 something #2 with #3 arg} -%D \stoptyping -%D -%D which becomes: -%D -%D \starttyping -%D \def\somecommand[#1][#2]\startspecifier#3\stopspecifier% -%D {do #1 something #2 with #3 arg} -%D \stoptyping -%D -%D We will see some real applications of this command in the -%D core modules. - -\def\definestartstopcommand#1#2#3#4% can be done with \expanded ot better, toks - {\def\!stringa{#3}% % but let's keep this unused one crappy - \def\!stringb{\e!start#2}% - \def\!stringc{#4}% - \def\!stringd{\e!stop#2}% - \@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA - \def\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA - #1\@EA\@EA\@EA\@EA\@EA\@EA\@EA - \!stringa\@EA\@EA\@EA - \csname\@EA\@EA\@EA\!stringb\@EA\@EA\@EA\endcsname\@EA - \!stringc - \csname\!stringd\endcsname} - -%D \macros -%D {dosinglegroupempty,dodoublegroupempty,dotriplegroupempty, -%D doquadruplegroupempty, doquintuplegroupempty} -%D -%D We've already seen some commands that take care of -%D optional arguments between \type{[]}. The next two commands -%D handle the ones with \type{{}}. They are called as: -%D -%D \starttyping -%D \dosinglegroupempty \ineedONEargument -%D \dodoublegroupempty \ineedTWOarguments -%D \dotriplegroupempty \ineedTHREEarguments -%D \doquadruplegroupempty \ineedFOURarguments -%D \doquintuplegroupempty \ineedFIVEarguments -%D \stoptyping -%D -%D where \type{\ineedONEargument} takes one and the others -%D two and three arguments. These macro's were first needed in -%D \PPCHTEX. -%D -%D \starttyping -%D \def\dogetgroupargument#1#2% redefined in mult-ini -%D {\def\nextnextargument% -%D {\ifx\nextargument\bgroup -%D \let\expectedarguments\noexpectedarguments -%D \def\nextargument{#1\dodogetargument}% -%D %\else\ifx\nextargument\lineending % this can be an option -%D % \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}% -%D %\else\ifx\nextargument\blankspace % but it may never be default -%D % \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}% -%D \else -%D \ifnum\expectedarguments>\noexpectedarguments -%D \writestatus -%D {setup} -%D {\the\expectedarguments\space argument(s) expected -%D in line \the\inputlineno\space}% -%D \fi -%D \let\expectedarguments\noexpectedarguments -%D \def\nextargument{#2\dodogetargument{}}% -%D \fi%\fi\fi % so let's get rid of it -%D \nextargument}% -%D \futurelet\nextargument\nextnextargument} -%D \stoptyping -%D -%D In order to catch \type {\nextargument}'s that expand to -%D \type {\if} and friends, in practice we will use a -%D slightly more complicated macro. - -\newtoks \everyrobusttest - -\everyrobusttest - {\let\if \relax - \let\ifcat \relax - \let\ifnum \relax - \let\ifdim \relax - \let\ifodd \relax - \let\ifvmode \relax - \let\ifhmode \relax - \let\ifmmode \relax - \let\ifinner \relax - \let\ifvoid \relax - \let\ifhbox \relax - \let\ifvbox \relax - \let\ifx \relax - \let\ifeof \relax - \let\iftrue \relax - \let\iffalse \relax - \let\ifcase \relax - \let\ifdefined \relax - \let\ifcsname \relax - \let\iffontchar \relax - \let\ifincsname \relax - \let\ifprimitive\relax - \let\ifabsnum \relax - \let\ifabsdim \relax - \let\else \relax - \let\or \relax - \let\fi \relax} - -\def\beginrobusttest - {\begingroup - \the\everyrobusttest} - -\let\endrobusttest\endgroup - -%D We can add additional definitions later when we have defined -%D \type {\appendtoks}. - -\def \permitspacesbetweengroups{\chardef\@@permitspacesbetweengroups=0 } -\def\dontpermitspacesbetweengroups{\chardef\@@permitspacesbetweengroups=1 } - -\dontpermitspacesbetweengroups - -% \def\dogetgroupargument#1#2% -% {\def\nextnextargument% -% {\normalifx\nextargument\bgroup -% \endrobusttest -% \noshowargumenterror -% \def\nextargument{#1\dodogetargument}% -% \normalelse -% \normalifcase\@@permitspacesbetweengroups -% \normalifx\nextargument\lineending -% \endrobusttest -% \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}% -% \normalelse\normalifx\nextargument\blankspace -% \endrobusttest -% \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}% -% \normalelse -% \endrobusttest -% \doshowargumenterror -% \def\nextargument{#2\dodogetargument{}}% -% \normalfi\normalfi -% \normalelse -% \endrobusttest -% \doshowargumenterror -% \def\nextargument{#2\dodogetargument{}}% -% \normalfi -% \normalfi -% \nextargument}% -% \beginrobusttest -% \futurelet\nextargument\nextnextargument} - -\def\dodogetgroupargument - {\normalifx\nextargument\bgroup - \endrobusttest - \noshowargumenterror - \def\nextargument{\dogroupargumentyes\dodogetargument}% - \normalelse - \normalifcase\@@permitspacesbetweengroups - \normalifx\nextargument\lineending - \endrobusttest - \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument\dogroupargumentyes\dogroupargumentnop}\\}% - \normalelse\normalifx\nextargument\blankspace - \endrobusttest - \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument\dogroupargumentyes\dogroupargumentnop}\\}% - \normalelse - \endrobusttest - \doshowargumenterror - \def\nextargument{\dogroupargumentnop\dodogetargument{}}% - \normalfi\normalfi - \normalelse - \endrobusttest - \doshowargumenterror - \def\nextargument{\dogroupargumentnop\dodogetargument{}}% - \normalfi - \normalfi - \nextargument}% - -\def\dogetgroupargument#1#2% - {\let\dogroupargumentyes#1% - \let\dogroupargumentnop#2% - \beginrobusttest\futurelet\nextargument\dodogetgroupargument} - -\def\dosinglegroupempty#1% - {\def\dodogetargument% - {\dontpermitspacesbetweengroups - #1}% - \dogetgroupargument\firstargumenttrue\firstargumentfalse} - -\def\dodoublegroupempty#1% - {\def\dodogetargument##1% - {\def\dodogetargument% - {\dontpermitspacesbetweengroups - #1{##1}}% - \dogetgroupargument\secondargumenttrue\secondargumentfalse}% - \dogetgroupargument\firstargumenttrue\firstargumentfalse} - -\def\dotriplegroupempty#1% - {\def\dodogetargument##1% - {\def\dodogetargument####1% - {\def\dodogetargument% - {\dontpermitspacesbetweengroups - #1{##1}{####1}}% - \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}% - \dogetgroupargument\secondargumenttrue\secondargumentfalse}% - \dogetgroupargument\firstargumenttrue\firstargumentfalse} - -\def\doquadruplegroupempty#1% - {\def\dodogetargument##1% - {\def\dodogetargument####1% - {\def\dodogetargument########1% - {\def\dodogetargument% - {\dontpermitspacesbetweengroups - #1{##1}{####1}{########1}}% - \dogetgroupargument\fourthargumenttrue\fourthargumentfalse}% - \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}% - \dogetgroupargument\secondargumenttrue\secondargumentfalse}% - \dogetgroupargument\firstargumenttrue\firstargumentfalse} - -\def\doquintuplegroupempty#1% - {\def\dodogetargument##1% - {\def\dodogetargument####1% - {\def\dodogetargument########1% - {\def\dodogetargument################1% - {\def\dodogetargument% - {\dontpermitspacesbetweengroups - #1{##1}{####1}{########1}{################1}}% - \dogetgroupargument\fifthargumenttrue\fifthargumentfalse}% - \dogetgroupargument\fourthargumenttrue\fourthargumentfalse}% - \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}% - \dogetgroupargument\secondargumenttrue\secondargumentfalse}% - \dogetgroupargument\firstargumenttrue\firstargumentfalse} - -%D These macros can explictly take care of spaces, which means -%D that the next definition and calls are valid: -%D -%D \starttyping -%D \def\test#1#2#3{[#1#2#3]} -%D -%D \dotriplegroupempty\test {a}{b}{c} -%D \dotriplegroupempty\test {a}{b} -%D \dotriplegroupempty\test {a} -%D \dotriplegroupempty\test -%D \dotriplegroupempty\test {a} {b} {c} -%D \dotriplegroupempty\test {a} {b} -%D \dotriplegroupempty\test -%D {a} -%D {b} -%D \stoptyping -%D -%D And alike. - -%D \macros -%D {firstofoneargument, firstoftwoarguments, firstofthreearguments -%D secondoftwoarguments, secondofthreearguments, -%D thirdofthreearguments} -%D -%D The next six macros (dedicated to Taco) can conveniently -%D used to select arguments. Their names explain their -%D functionality. - -\long\def\firstofoneargument#1{#1} - -\long\def\firstoftwoarguments #1#2{#1} -\long\def\secondoftwoarguments#1#2{#2} - -\long\def\firstofthreearguments #1#2#3{#1} -\long\def\secondofthreearguments#1#2#3{#2} -\long\def\thirdofthreearguments #1#2#3{#3} - -\long\def\firstoffourarguments #1#2#3#4{#1} -\long\def\secondoffourarguments#1#2#3#4{#2} -\long\def\thirdoffourarguments #1#2#3#4{#3} -\long\def\fourthoffourarguments#1#2#3#4{#4} - -\long\def\firstoffivearguments #1#2#3#4#5{#1} -\long\def\secondoffivearguments#1#2#3#4#5{#2} -\long\def\thirdoffivearguments #1#2#3#4#5{#3} -\long\def\fourthoffivearguments#1#2#3#4#5{#4} -\long\def\fifthoffivearguments #1#2#3#4#5{#5} - -\long\def\firstofsixarguments #1#2#3#4#5#6{#1} -\long\def\secondofsixarguments#1#2#3#4#5#6{#2} -\long\def\thirdofsixarguments #1#2#3#4#5#6{#3} -\long\def\fourthofsixarguments#1#2#3#4#5#6{#4} -\long\def\fifthofsixarguments #1#2#3#4#5#6{#5} -\long\def\sixthofsixarguments #1#2#3#4#5#6{#6} - -%D \macros -%D {globalletempty,letempty,letvalueempty,letgvalueempty} -%D -%D Trivial: - -\def\letempty #1{\let#1\empty} -\def\globalletempty#1{\global\let#1\empty} - -\def\letvalueempty #1{\expandafter\let\csname#1\endcsname\empty} -\def\letgvalueempty#1{\global\expandafter\let\csname#1\endcsname\empty} - -%D \macros -%D {wait} -%D -%D The next macro hardly needs explanation. Because no -%D nesting is to be expected, we can reuse \type{\wait} within -%D \type{\wait} itself. - -\def\wait - {\begingroup - \read16 to \wait - \endgroup} - -%D \macros -%D {writestring,writeline,writebanner, -%D writestatus,statuswidth,normalwritestatus} -%D -%D Maybe one didn't notice, but we've already introduced a -%D macro for showing messages. In the multi||lingual modules, -%D we will also introduce a mechanism for message passing. For -%D the moment we stick to the core macros: -%D -%D \starttyping -%D \writestring {string} -%D \writeline -%D \writestatus {category} {message} -%D \stoptyping -%D -%D Messages are formatted. One can provide the maximum with -%D of the identification string with the macro \type -%D {\statuswidth}. - -\chardef\statuswidth=15 -\chardef\statuswrite=16 - -\ifx\writestring\undefined - - \newtoks\everywritestring - - \def\writedirect {\immediate\write\statuswrite} - \def\writeline {\writedirect{}} - \def\writestring#1{\begingroup\the\everywritestring\writedirect{#1}\endgroup} - -\fi - -%D First we present the normal \TEX\ variant, later we will -%D show the \ETEX-way. - - -\beginTEX - - \newcount\statuscounter - - \def\dosplitstatus#1% - {\advance\statuscounter \minusone - \ifcase\statuscounter - \expandafter\nosplitstatus - \else - \scratchtoks\@EA{\the\scratchtoks#1}% - \expandafter\dosplitstatus - \fi} - - \def\nosplitstatus#1\end - {} - - \def\writestatus#1#2% - {\begingroup - \scratchtoks\emptytoks - \statuscounter\statuswidth - \expandafter\dosplitstatus#1% - \space\space\space\space\space\space\space - \space\space\space\space\space\space\space - \space\space\space\space\space\space\end - \@EA\writestring\@EA{\the\scratchtoks\space:\space#2}% - \endgroup} - -\endTEX - -%D Because we're grouped, we could have initialized at forehand: -%D -%D \starttyping -%D \statuscounter\statuswidth -%D \stoptyping -%D -%D The next implementation saves only some 10 words of format -%D memory, but we hardly gain any speed. -%D -%D \starttyping -%D \def\dosplitstatus#1#2#3#4#5#6#7#8#9% -%D {#1#2#3#4#5#6#7#8#9\dodosplitstatus} -%D -%D \def\dodosplitstatus#1#2#3#4#5#6\end -%D {#1#2#3#4#5} -%D -%D \def\writestatus#1#2% -%D {\writestring -%D {\expandafter\dosplitstatus#1% -%D \space\space\space\space\space -%D \space\space\space\space\space -%D \space\space\space\space\space\end -%D \space:\space#2}} -%D \stoptyping - -%D Okay then, more obscure but slightly faster: no split grabs -%D the do split part and skipping the else branch has to happen -%D anyway, so: - -\beginTEX - - \def\dosplitstatus#1% - {\advance\statuscounter \minusone - \ifcase\statuscounter - \expandafter\nosplitstatus - \fi - \scratchtoks\@EA{\the\scratchtoks#1}% - \dosplitstatus} - -\endTEX - -%D The next (\ETEX\ specific) variant is twice as fast in 5/40 -%D situations, only gains some speed when multiple runs of large docs -%D are done; fully expandable, no statuscounter needed, no restore (due -%D to grouping) needed etc. - -\beginETEX \numexpr - - \def\normalwritestatus#1#2% - {\writestring{\expandafter\dosplitstatus\expandafter\statuswidth#1% - \space\space\space\space\space\space\space - \space\space\space\space\space\space\space - \space\space\space\space\space\space\end - \space:\space#2}} - - \def\dosplitstatus#1#2% - {\ifcase#1 \expandafter\nosplitstatus\fi#2% - \expandafter\dosplitstatus\expandafter{\the\numexpr#1+\minusone\relax}} - - \def\nosplitstatus#1\end - {} - -\endETEX - -%D \macros -%D {emptytoks} -%D -%D For this we need an empty token register, analogous -%D to \type {\empty}. - -\newtoks\emptytoks - -%D \macros -%D {debuggerinfo} -%D -%D For debugging purposes we can enhance macros with the -%D next alternative. Here \type{debuggerinfo} stands for both -%D a macro accepting two arguments and a boolean (in fact a -%D few macro's too). - -\newif\ifdebuggerinfo - -\def\debuggerinfo#1#2% - {\ifdebuggerinfo - \writestatus{debugger}{#1:: #2}% - \fi} - -%D Finally we do what from now on will be done at the top of -%D the files: we tell the user what we are loading. - -% \ifx\writestatus\undefined \let\writestatus\normalwritestatus \fi -% \ifx\writebanner\undefined \def\writebanner{\writestring} \fi - -\ifx\normalwritestatus\undefined - % for use within latex - \ifx\writestatus\undefined - \def\writestatus#1#2{\immediate\write16{#1 : #2}} - \fi -\else - \let\writestatus\normalwritestatus -\fi - -\def\writebanner{\writestring} - -\writestatus{loading}{ConTeXt System Macros / General} - -%D Well, the real final command is the one that resets the -%D unprotected characters \type{@}, \type{?} and \type{!}. - -\protect \endinput |