syst-aux.mkxl /size: 237 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=syst-aux, % merge of syst-gen cum suis
3%D        version=1996.03.20,
4%D          title=\CONTEXT\ System Macros,
5%D       subtitle=General,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14%D In the process of being adapted to \LMTX\ flags so a bit of a mess now. Also
15%D our playground.
16
17\registerctxluafile{syst-aux}{autosuffix}
18\registerctxluafile{syst-mac}{autosuffix}
19
20%D This file is a follow up in \type {syst-aux.mkii} and \type {syst-aux.mkiv} where
21%D you can find some more pure \TEX\ or \LUATEX\ variants. There are quite some
22%D helpers here and many no longer are used but we keep them around because they
23%D have always been there. However, the implementation in \LMTX\ can be somewhat
24%D different that in \MKIV, because it's also a kind of a playground for new
25%D features. Of course nostalgia also plays a role.
26%D
27%D For the original code we refer to \type {syst-aux.mkii} and its follow up \type
28%D {syst-aux.mkiv}. These also have historic versions. As usual, the upgrade went
29%D through stages. First I wrote variants usign the new \type {\ignorearguments}
30%D feature, then I decided to implement a few more conditionals and new fancy code
31%D could be ditched before it was even published. I kept some as examples.
32%D
33%D Of course I couldn't do this without Wolfgang looking over my shoulder. Changing
34%D core code is kind of tricky.
35%D
36%D There are quite some helpers here that are effectively obsolete (read: there is no
37%D need for them). Examples are \type {setflag} and \type {\uppercasestring} and their
38%D relatives. We keep them around as illustration and possible usage in old styles.
39
40\unprotect
41
42%D These are for local helpers, the names are historic:
43
44\mutable\let\docommand  \relax
45\mutable\let\dodocommand\relax
46
47%D \macros
48%D   {unexpanded}
49%D
50%D Because we use this module only in \MKIV, we have removed the old protection
51%D code.
52%D
53%D \starttyping
54%D \protected\def\somecommand{... ... ...}
55%D \stoptyping
56%D
57%D This overloads the \ETEX\ primitive but as we already had an \MKII\ solution we
58%D keep the same name for a similar mechanism. So, effectively we have two ways to
59%D protect a macro.
60%D
61%D In \LMTX\ we try to avoid this and use \type {\protected} instead, which is
62%D possible because over time we got rid of using the \CONTEXT\ macro with that
63%D name.
64
65\pushoverloadmode
66
67\aliased\let\unexpanded\normalprotected
68
69\popoverloadmode
70
71%D We're definitely in \LMTX\ mode here.
72
73\permanent\protected\lettonothing\startlmtxmode
74\permanent\protected\lettonothing\stoplmtxmode
75\permanent                   \def\startmkivmode#-\stopmkivmode{}
76\permanent\protected\lettonothing\stopmkivmode
77
78%D As we don't have namespace definers yet, we use a special one. Later we will
79%D do a better job.
80
81\ifdefined\c_syst_helpers_n_of_namespaces
82
83    % lets plug in a better error message
84
85\else
86
87    \newinteger\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes
88
89    \def\v_interfaces_prefix_template_system{\the       \c_syst_helpers_n_of_namespaces>>}
90    %def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet
91
92\fi
93
94\permanent\protected\def\installsystemnamespace#1% maybe move this to syst-ini
95  {\ifcsname ??#1\endcsname
96     \writestatus\m!system{duplicate system namespace '#1'}\wait
97   \else
98     \global\advanceby\c_syst_helpers_n_of_namespaces\plusone
99     \immutable\edefcsname ??#1\endcsname{\v_interfaces_prefix_template_system}%
100   \fi}
101
102%D \macros
103%D   {normalspace}
104%D
105%D There is already \type{\space} but just to be sure we also provide this one:
106
107\permanent\def\normalspace{ }
108
109\newif\if!!donea   \newif\if!!doneb    \newif\if!!donec  % soon obsolete in lmtx
110\newif\if!!doned   \newif\if!!donee    \newif\if!!donef  % soon obsolete in lmtx
111
112\immutable\def\!!zerocount {0} % alongside \zerocount
113\immutable\def\!!minusone {-1} % ...
114\immutable\def\!!plusone   {1} % ...
115\immutable\def\!!plustwo   {2} % ...
116\immutable\def\!!plusthree {3} % ...
117\immutable\def\!!plusfour  {4} % ...
118\immutable\def\!!plusfive  {5} % ...
119\immutable\def\!!plussix   {6} % ...
120\immutable\def\!!plusseven {7} % ...
121\immutable\def\!!pluseight {8} % ...
122\immutable\def\!!plusnine  {9} % alongside \plusnine
123
124\setnewconstant   \uprotationangle    0
125\setnewconstant\rightrotationangle   90
126\setnewconstant \downrotationangle  180
127\setnewconstant \leftrotationangle  270
128
129%D \macros
130%D   {s!,c!,e!,p!,v!,@@,??}
131%D
132%D To save memory, we use constants (sometimes called variables). Redefining these
133%D constants can have disastrous results. Of course, expanding them costs time, so
134%D that's the price to pay. More are defined elsewhere. Of course we later pay a
135%D price when they need to be expanded.
136
137% \def\v!prefix! {v!}
138% \def\c!prefix! {c!}
139% \def\s!prefix! {s!}
140%
141% \def\s!next    {next}
142% \def\s!default {default}
143% \def\s!dummy   {dummy}
144% \def\s!unknown {unknown}
145%
146% \def\s!do      {do}
147% \def\s!dodo    {dodo}
148%
149% \def\s!complex {complex}
150% \def\s!simple  {simple}
151%
152% \def\s!start{start}
153% \def\s!stop {stop}
154
155% \immutable\def\s!empty {empty}
156
157%D Sometimes we pass macros as arguments to commands that don't expand them before
158%D interpretation. Such commands can be enclosed with \type {\expanded}, like:
159%D
160%D \starttyping
161%D \expanded{\setupsomething[\alfa]}
162%D \stoptyping
163%D
164%D Such situations occur for instance when \type {\alfa} is a commalist or when data
165%D stored in macros is fed to index of list commands. If needed, one should use
166%D \type {\noexpand} inside the argument. Later on we will meet some more clever
167%D alternatives to this command. Beware, only the simple one has \type {\noexpand}
168%D before its argument.
169
170\lettonothing\m_syst_helpers_expanded
171
172\pushoverloadmode
173
174\permanent\protected\def\expanded#1%
175  {\xdef\m_syst_helpers_expanded{\noexpand#1}\m_syst_helpers_expanded}
176
177\popoverloadmode
178
179\permanent\protected\def\startexpanded#1\stopexpanded
180  {\xdef\m_syst_helpers_expanded{#1}\m_syst_helpers_expanded}
181
182\permanent\protected\lettonothing\stopexpanded
183
184%D Recent \TEX\ engines have a primitive \type {\expanded} and we will use that when
185%D possible. After all, we can make not expandable macros now. The name clash is an
186%D unfortunate fact and in retrospect I should nto have agreed to a primitive having
187%D that same name.
188
189% We cannot use the next variant as first we need to adapt \type {##}'s in callers:
190%
191% \def\expanded#1%
192%   {\normalexpanded{\noexpand#1}}
193%
194% \def\startexpanded#1\stopexpanded
195%   {\normalexpanded{#1}}
196
197%D \macros
198%D   {gobbleoneargument,gobble...arguments}
199%D
200%D The next set of macros just do nothing, except that they get rid of a number of
201%D arguments. These zero references prevent intermediate storage. In principle that
202%D is more efficient but it probably won't be noticed. It's anyway cheaper on memory
203%D access. We use versions that don't even store the arguments.
204
205%permanent\def\gobbleoneargument               #-{}
206\permanent\def\gobbletwoarguments            #-#-{}
207\permanent\def\gobblethreearguments        #-#-#-{}
208\permanent\def\gobblefourarguments       #-#-#-#-{}
209\permanent\def\gobblefivearguments       #-#-#-#-{}
210\permanent\def\gobblesixarguments        #-#-#-#-{}
211\permanent\def\gobblesevenarguments    #-#-#-#-#-{}
212\permanent\def\gobbleeightarguments  #-#-#-#-#-#-{}
213\permanent\def\gobbleninearguments #-#-#-#-#-#-#-{}
214
215\permanent\tolerant\def\gobbleoneoptional   [#S#-]{}
216\permanent\tolerant\def\gobbletwooptionals  [#S#-]#*[#S#-]{}
217\permanent\tolerant\def\gobblethreeoptionals[#S#-]#*[#S#-]#*[#S#-]{}
218\permanent\tolerant\def\gobblefouroptionals [#S#-]#*[#S#-]#*[#S#-]#*[#S#-]{}
219\permanent\tolerant\def\gobblefiveoptionals [#S#-]#*[#S#-]#*[#S#-]#*[#S#-]#*[#S#-]{}
220
221%D Reserved macros for tests:
222
223%D A \type \type {\let} is more efficient than a \type {\def} so we often let something
224%D to relax or do nothing. However, we then loose the name in tracing. For that we now
225%D have \type {\lettonothing \foo} which is efficient but also keeps the name. Of course
226%D this is no solution for commands that take arguments but at least it helps tracing a
227%D bit. We keep of course \type {\donothing}.
228
229%D Maybe even nicer is a let that aliases but keeps the name.
230
231       % \lettonothing\donothing
232         \immutable\def\donothing        {} % better in tracing
233%untraced\immutable\def\untraceddonothing{}
234
235\lettonothing\m_syst_string_one
236\lettonothing\m_syst_string_two
237\lettonothing\m_syst_string_three
238\lettonothing\m_syst_string_four
239
240\lettonothing\m_syst_action_yes
241\lettonothing\m_syst_action_nop
242
243%D \macros
244%D   {doifnextcharelse}
245%D
246%D This macro has a long history. Among the things we had to deal with was ignoring
247%D blank spaces but in the meantime we can use some \LUATEX\ trickery. Older versions
248%D use more code and can be find in the \MKIV\ and \MKII\ files.
249
250% \mutable\let\next          \relax
251% \mutable\let\nextnext      \relax % kind of obsolete
252% \mutable\let\nextnextnext  \relax % kind of obsolete
253% \mutable\let\nexttoken     \relax
254
255\permanent\protected\def\doifelsenextchar#1#2#3% #1 should not be {} !
256  {\def\m_syst_action_yes{#2}%
257   \def\m_syst_action_nop{#3}%
258   \futureexpandis#1\m_syst_action_yes\m_syst_action_nop}
259
260\permanent\protected\def\doifelsenextcharcs % #1#2#3% #1 should not be {} !
261  {\futureexpandis}
262
263\aliased\let\doifnextcharelse  \doifelsenextchar
264\aliased\let\doifnextcharcselse\doifelsenextcharcs
265
266%D Because we will mostly use this macro for testing if the next character is \type
267%D {[}, we also make a slightly faster variant as it is not uncommon to have tens of
268%D thousands of calls to this test in a run. Of course it also is more convenient to
269%D read a trace then. Here we use a lookahead primitive that ignores (blank) spaces
270%D which makes for less tracing clutter than the original definition. It's also
271%D faster bit that will probably go unnoticed. Of course, hard||core \TEX ies whose
272%D reputations depends on understanding obscure macro definitions will love the more
273%D low level variants.
274
275\permanent\protected\def\doifelsenextoptional#1#2%
276  {\def\m_syst_action_yes{#1}%
277   \def\m_syst_action_nop{#2}%
278   \futureexpandis[\m_syst_action_yes\m_syst_action_nop}
279
280\permanent\protected\def\doifelsenextoptionalcs
281  {\futureexpandis[}
282
283\aliased\let\doifnextoptionalelse  \doifelsenextoptional
284\aliased\let\doifnextoptionalcselse\doifelsenextoptionalcs
285
286\permanent\protected\def\doifelsenextbgroup#1#2%
287  {\def\m_syst_action_yes{#1}%
288   \def\m_syst_action_nop{#2}%
289   \futureexpandis\bgroup\m_syst_action_yes\m_syst_action_nop}
290
291\permanent\protected\def\doifelsenextbgroupcs % #1#2
292  {\futureexpandis\bgroup}
293
294\aliased\let\doifnextbgroupelse  \doifelsenextbgroup
295\aliased\let\doifnextbgroupcselse\doifelsenextbgroupcs
296
297\permanent\protected\def\doifelsenextparenthesis#1#2%
298  {\def\m_syst_action_yes{#1}%
299   \def\m_syst_action_nop{#2}%
300   \futureexpandis(\m_syst_action_yes\m_syst_action_nop}
301
302\aliased\let\doifnextparenthesiselse\doifelsenextparenthesis
303
304%D The next one is handy in predictable situations:
305
306\permanent\protected\def\doifelsefastoptionalcheck#1#2%
307  {\def\m_syst_action_yes{#1}%
308   \def\m_syst_action_nop{#2}%
309   \futureexpandis[\m_syst_action_yes\m_syst_action_nop}
310
311\permanent\protected\def\doifelsefastoptionalcheckcs
312  {\futureexpandis[}
313
314\aliased\let\doiffastoptionalcheckelse  \doifelsefastoptionalcheck
315\aliased\let\doiffastoptionalcheckcselse\doifelsefastoptionalcheckcs
316
317%D Here's one for skipping spaces and pars, handy for:
318%D
319%D \starttyping
320%D \hbox
321%D
322%D   {a few lines later}
323%D \stoptyping
324%D
325%D like:
326%D
327%D \starttyping
328%D \def\somecommand{\dowithnextbox{\box\nextbox}\ruledhbox}
329%D
330%D \assumelongusagecs\somecommand
331%D
332%D \bgroup
333%D     oeps
334%D \egroup
335%D \stoptyping
336%D
337%D The original kind of clumsy but working version is now replaced by a simple
338%D macro. And it can be even less code in \LUAMETATEX:
339
340\aliased\let\assumelongusagecs\expandafterpars % so we can replace it
341
342%D It's used to skip over empty lines in some constructs that we like to set up
343%D spacy. We already permit par tokens (and equivalents) in math and some other
344%D places visa engine features. And, \type {\long} stuff has been dropped for a long
345%D time already (it is still optional in \lUATEX). But the \quote  {long} in the
346%D name kind of stuck.
347
348%D \macros
349%D   {blankspace}
350%D
351%D Here is how this works. The \type {\let} primitive first picks up the to be let
352%D name. Then it scans for an optional equal and when that is found it will skip the
353%D next space, which is why we need an extra one to achieve our goal. Such a \type
354%D {\blankspace} has the meaning \typ {blank space}. A typical \TEX ie definition:
355
356\normalexpanded{\permanent\let\noexpand\blankspace=\space\space}
357
358%D this is the same as \type {\relaxedspace} in \type {syst-ini.mkxl} but we had
359%D it (name) from the start of \CONTEXT\ so we keep it; it is also a name used in
360%D logging.
361
362%D \macros
363%D   {setvalue,setgvalue,setevalue,setxvalue,
364%D    letvalue,letgvalue,getvalue,resetvalue,
365%D    undefinevalue,ignorevalue}
366%D
367%D \TEX's primitive \type {\csname} can be used to construct all kind of commands
368%D that cannot be defined with \type {\def} and \type {\let}. Every macro programmer
369%D sooner or later wants macros like these.
370%D
371%D \starttyping
372%D \setvalue   {name}{...} = \def\name{...}
373%D \setgvalue  {name}{...} = \gdef\name{...}
374%D \setevalue  {name}{...} = \edef\name{...}
375%D \setxvalue  {name}{...} = \xdef\name{...}
376%D \letvalue   {name}=\... = \let\name=\...
377%D \letgvalue  {name}=\... = \glet\name=\...
378%D \getvalue   {name}      = \name
379%D \resetvalue {name}      = \def\name{}
380%D \stoptyping
381%D
382%D As we will see, \CONTEXT\ uses these commands many times, which is mainly due to
383%D its object oriented and parameter driven character.
384
385\permanent\def\setvalue     #1{\defcsname #1\endcsname}
386\permanent\def\setgvalue    #1{\gdefcsname#1\endcsname}
387\permanent\def\setevalue    #1{\edefcsname#1\endcsname}
388\permanent\def\setxvalue    #1{\xdefcsname#1\endcsname}
389\permanent\def\getvalue     #1{\begincsname#1\endcsname}
390\permanent\def\letvalue     #1{\letcsname #1\endcsname}
391\permanent\def\letgvalue    #1{\gletcsname#1\endcsname}
392\permanent\def\resetvalue   #1{\letcsname#1\endcsname\empty}
393\permanent\def\undefinevalue#1{\letcsname#1\endcsname\undefined}
394\permanent\def\ignorevalue#1#2{\letcsname#1\endcsname\empty}
395
396\permanent\def\setuvalue    #1{\protected\defcsname #1\endcsname}
397\permanent\def\setuevalue   #1{\protected\edefcsname#1\endcsname}
398\permanent\def\setugvalue   #1{\protected\gdefcsname#1\endcsname}
399\permanent\def\setuxvalue   #1{\protected\xdefcsname#1\endcsname}
400
401\permanent\protected\def\getuvalue#1{\begincsname#1\endcsname}
402
403%D \macros
404%D   {globallet,glet}
405%D
406%D In \CONTEXT\ of May 2000 using \type {\globallet} instead of the two tokens will
407%D save us some $300\times4=1200$ bytes of format file on a 32~bit system. Not that
408%D it matters much today. But nowadays we can just alias to a primitive:
409
410\aliased\let\globallet\glet
411
412%D \macros
413%D   {doifundefined,doifdefined,
414%D    doifundefinedelse,doifdefinedelse,
415%D    doifalldefinedelse}
416%D
417%D The standard way of testing if a macro is defined is comparing its meaning with
418%D another undefined one, usually \type {\undefined}. To garantee correct working of
419%D the next set of macros, \type {\undefined} may never be defined!
420%D
421%D \starttyping
422%D \doifundefined      {string}    {...}
423%D \doifdefined        {string}    {...}
424%D \doifundefinedelse  {string}    {then ...} {else ...}
425%D \doifdefinedelse    {string}    {then ...} {else ...}
426%D \doifalldefinedelse {commalist} {then ...} {else ...}
427%D \stoptyping
428%D
429%D Every macroname that \TEX\ builds gets an entry in the hash table, which is of
430%D limited size. It is expected that \ETEX\ will offer a less memory||consuming
431%D alternative.
432%D
433%D Although it will probably never be a big problem, it is good to be aware of the
434%D difference between testing on a macro name to be build by using \type {\csname} and
435%D \type {\endcsname} and testing the \type {\name} directly.
436%D
437%D \starttyping
438%D \expandafter\ifrelax\csname NameA\endcsname ... \else ... \fi
439%D
440%D \ifundefined\NameB ... \else ... \fi
441%D \stoptyping
442%D
443%D Suppression of errors while constructing a control sequence is one of the (few)
444%D things that I remember being discussed in the perspective of \ETEX\ but it was
445%D rejected because it was not considered useful. Well, in \LUATEX\ we can surpress
446%D it and that is what we do in \MKIV. We're probably the only macro package that
447%D needs it. That kind of configuration happens elsewhere. These macros are (mostly
448%D for historic reasons) fully expandable.
449
450\permanent\def\doifelseundefined#1%
451  {\ifcsname#1\endcsname
452     \expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments
453   \fi}
454
455\permanent\def\doifelsedefined#1%
456  {\ifcsname#1\endcsname
457     \expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments
458   \fi}
459
460\permanent\def\doifundefined#1%
461  {\ifcsname#1\endcsname
462     \expandafter\gobbleoneargument\else\expandafter\firstofoneargument
463   \fi}
464
465\permanent\def\doifdefined#1%
466  {\ifcsname#1\endcsname
467     \expandafter\firstofoneargument\else\expandafter\gobbleoneargument
468   \fi}
469
470\aliased\let\doifundefinedelse\doifelseundefined
471\aliased\let\doifdefinedelse  \doifelsedefined
472
473%D \macros
474%D   {letbeundefined}
475%D
476%D Testing for being undefined comes down to testing on \type {\relax} when we use
477%D \type {\csname}, but when using \type {\ifx}, we test on being \type
478%D {\undefined}! In \ETEX\ we have \type {\ifcsname} and that way of testing on
479%D existance is not the same as the one described here. Therefore we introduce:
480
481\permanent\protected\def\letbeundefined#1%
482  {\letcsname#1\endcsname\undefined}
483
484\permanent\protected\def\localundefine#1% conditional
485  {\ifcsname#1\endcsname\letcsname#1\endcsname\undefined\fi}
486
487\permanent\protected\def\globalundefine#1% conditional
488  {\ifcsname#1\endcsname\gletcsname#1\endcsname\undefined\fi}
489
490%D Beware, being \type {\undefined} in \ETEX\ means that the macro {\em is} defined!
491%D
492%D When we were developing the scientific units module, we encountered different
493%D behavior in text and math mode, which was due to this grouping subtilities. We
494%D therefore decided to use \type {\begingroup} instead of \type {\bgroup}.
495%D
496%D \stoptyping
497%D \doifelsealldefined  {foo,ofo}  {YES}{NOP}
498%D \doifelseallundefined{foo,ofo}  {YES}{NOP}
499%D \doifelsealldefined  {relax,ofo}{YES}{NOP}
500%D \doifelseallundefined{foo,relax}{YES}{NOP}
501%D \stoptyping
502
503\def\syst_helpers_do_if_all_defined_else#1%
504  {\ifcsname#1\endcsname\else
505     \donefalse
506     \expandafter\quitcommalist % added
507   \fi}
508
509\def\syst_helpers_do_if_all_undefined_else#1%
510  {\ifcsname#1\endcsname
511     \donefalse
512     \expandafter\quitcommalist
513   \fi}
514
515\permanent\protected\def\syst_helpers_do_if_all_else#1#2%
516  {\begingroup
517   \donetrue % we could use a reserved one and avoid the group
518   \processcommalist[#2]#1%
519   \ifdone
520     \endgroup\expandafter\firstoftwoarguments
521   \else
522     \endgroup\expandafter\secondoftwoarguments
523   \fi}
524
525\permanent\protected\def\doifelsealldefined  {\syst_helpers_do_if_all_else\syst_helpers_do_if_all_defined_else}
526\permanent\protected\def\doifelseallundefined{\syst_helpers_do_if_all_else\syst_helpers_do_if_all_undefined_else}
527
528\aliased\let\doifalldefinedelse  \doifelsealldefined
529\aliased\let\doifallundefinedelse\doifelseallundefined
530
531%D \macros
532%D   {doif,doifelse,doifnot}
533%D
534%D Programming in \TEX\ differs from programming in procedural languages like
535%D \MODULA. This means that one --- well, let me speek for myself --- tries to do
536%D the things in the well known way. Therefore the next set of \type {ifthenelse}
537%D commands were between the first ones we needed. A few years later, the opposite
538%D became true: when programming in \MODULA, I sometimes miss handy things like
539%D grouping, runtime redefinition, expansion etc. While \MODULA\ taught me to
540%D structure, \TEX\ taught me to think recursive.
541%D
542%D \starttyping
543%D \doif     {string1} {string2} {...}
544%D \doifnot  {string1} {string2} {...}
545%D \doifelse {string1} {string2} {then ...}{else ...}
546%D \stoptyping
547%D
548%D Again, we use some of the new primitives in \LUAMETATEX. Using straightforward
549%D \type {\edef}'s and \type {\ifx} comparison works as well, but this saves tokens
550%D and, more important, tracing clutter.
551
552\permanent\protected\def\doifelse#1#2%
553  {\iftok{#1}{#2}%
554     \expandafter\firstoftwoarguments
555   \else
556     \expandafter\secondoftwoarguments
557   \fi}
558
559\permanent\protected\def\doif#1#2%
560  {\iftok{#1}{#2}%
561     \expandafter\firstofoneargument
562   \else
563     \expandafter\gobbleoneargument
564   \fi}
565
566\permanent\protected\def\doifnot#1#2%
567  {\iftok{#1}{#2}%
568     \expandafter\gobbleoneargument
569   \else
570     \expandafter\firstofoneargument
571   \fi}
572
573%D \macros
574%D   {doifempty,doifemptyelse,doifnotempty}
575%D
576%D We complete our set of conditionals with:
577%D
578%D \starttyping
579%D \doifempty     {string} {...}
580%D \doifnotempty  {string} {...}
581%D \doifemptyelse {string} {then ...} {else ...}
582%D \stoptyping
583%D
584%D This time, the string is not expanded, but we use the dedicated empty checker
585%D here.
586
587\permanent\protected\def\doifelseempty#1%
588  {\def\m_syst_string_one{#1}%
589   \ifempty\m_syst_string_one
590     \expandafter\firstoftwoarguments
591   \else
592     \expandafter\secondoftwoarguments
593   \fi}
594
595% or (test this):
596%
597% \permanent\protected\def\processallactionsinset[#1]%
598%   {\ifempty{#1}%
599%      \expandafter\processaction
600%    \else
601%      \expandafter\syst_helpers_process_all_actions_in_set_indeed
602%    \fi[#1]}
603
604\aliased\let\doifemptyelse\doifelseempty
605
606\permanent\protected\def\doifempty#1%
607  {\def\m_syst_string_one{#1}%
608   \ifempty\m_syst_string_one
609     \expandafter\firstofoneargument
610   \else
611     \expandafter\gobbleoneargument
612   \fi}
613
614\permanent\protected\def\doifnotempty#1%
615  {\def\m_syst_string_one{#1}%
616   \ifempty\m_syst_string_one
617     \expandafter\gobbleoneargument
618   \else
619     \expandafter\firstofoneargument
620   \fi}
621
622%D \macros
623%D   {doifinset,doifnotinset,doifinsetelse}
624%D
625%D We can check if a string is present in a comma separated set of strings.
626%D Depending on the result, some action is taken.
627%D
628%D \starttyping
629%D \doifinset     {string} {string,...} {...}
630%D \doifnotinset  {string} {string,...} {...}
631%D \doifinsetelse {string} {string,...} {then ...} {else ...}
632%D \stoptyping
633
634% !0nop=\doifinsetelse{ccc}{,}{yes}{nop}
635% !0nop=\doifinsetelse{ccc}{,,}{yes}{nop}
636% !0nop=\doifinsetelse{ccc}{,,,}{yes}{nop}
637
638% !1nop=\doifinsetelse{}{}{yes}{nop}
639% !2yes=\doifinsetelse{aaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop}
640% !3nop=\doifinsetelse{aaa}{bbb}{yes}{nop}
641% !4yes=\doifinsetelse{aaa}{aaa}{yes}{nop}
642% !5nop=\doifinsetelse{aaaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop}
643% !6nop=\doifinsetelse{}{}{yes}{nop}
644% !7nop=\doifinsetelse{}{aaa}{yes}{nop}
645% !8nop=\doifinsetelse{aaa}{}{yes}{nop}
646
647% !1=\doifinset{}{}{yes}
648% !2yes=\doifinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes}
649% !3=\doifinset{aaa}{bbb}{yes}
650% !4yes=\doifinset{aaa}{aaa}{yes}
651% !5=\doifinset{}{}{yes}
652% !6=\doifinset{aaa}{}{yes}
653
654% !1yes=\doifnotinset{}{}{yes}
655% !2=\doifnotinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes}
656% !3yes=\doifnotinset{aaa}{bbb}{yes}
657% !4=\doifnotinset{aaa}{aaa}{yes}
658% !5yes=\doifnotinset{}{}{yes}
659% !6yes=\doifnotinset{aaa}{}{yes}
660
661%D These are normally only used for keywords, i.e.\ strings so we can delegate
662%D the work to \LUA:
663
664%protected\def\doifelseinset#1#2{\clf_doifelseinset{#1}{#2}}
665%protected\def\doifinset    #1#2{\clf_doifinset    {#1}{#2}}
666%protected\def\doifnotinset #1#2{\clf_doifnotinset {#1}{#2}}
667%       % \let\firstinset        \clf_firstinset
668
669% These don't accept spaces after commas:
670%
671% \protected\def\doifelseinset#1#2%
672%   {\ifhasxtoks{,#1,}{,#2,}%
673%      \expandafter\firstoftwoarguments
674%    \else
675%      \expandafter\secondoftwoarguments
676%    \fi}
677
678% \protected\def\doifinset#1#2%
679%   {\ifhasxtoks{,#1,}{,#2,}%
680%      \expandafter\firstofoneargument
681%    \else
682%      \expandafter\gobbleoneargument
683%    \fi}
684
685% \protected\def\doifnotinset#1#2%
686%   {\ifhasxtoks{,#1,}{,#2,}%
687%      \expandafter\gobbleoneargument
688%    \else
689%      \expandafter\firstofoneargument
690%    \fi}
691
692% But these do:
693
694\immutable\edef\a!comma{\expandtoken \ignorecatcode \commaasciicode}
695\immutable\edef\a!space{\expandtoken \ignorecatcode \spaceasciicode}
696
697\normalexpanded {
698
699    \permanent \protected \def \noexpand \doifelseinset#1#2%
700      {\noexpand\ifhasxtoks{,\a!space#1,}{,#2,}%
701         \noexpand\expandafter\noexpand\firstoftwoarguments
702       \noexpand\else
703         \noexpand\expandafter\noexpand\secondoftwoarguments
704       \noexpand\fi}
705
706    \permanent \protected \def \noexpand \doifinset#1#2%
707      {\noexpand\ifhasxtoks{,\a!space#1,}{,#2,}%
708         \noexpand\expandafter\noexpand\firstofoneargument
709       \noexpand\else
710         \noexpand\expandafter\noexpand\gobbleoneargument
711       \noexpand\fi}
712
713    \permanent \protected \def \noexpand \doifnotinset#1#2%
714      {\noexpand\ifhasxtoks{,\a!space#1,}{,#2,}%
715         \noexpand\expandafter\noexpand\gobbleoneargument
716       \noexpand\else
717         \noexpand\expandafter\noexpand\firstofoneargument
718       \noexpand\fi}
719
720}
721
722%D Done.
723
724\aliased\let\doifinsetelse\doifelseinset
725
726%D \macros
727%D   {doifcommon,doifnotcommon,doifcommonelse}
728%D
729%D Probably the most time consuming tests are those that test for overlap in sets
730%D of strings.
731%D
732%D \starttyping
733%D \doifcommon     {string,...} {string,...} {...}
734%D \doifnotcommon  {string,...} {string,...} {...}
735%D \doifcommonelse {string,...} {string,...} {then ...} {else ...}
736%D \stoptyping
737
738% !1yes=\doifcommonelse{aaa,bbb,ccc}{aaa,bbb,ccc}{yes}{nop}
739% !2nop=\doifcommonelse{aaa,bbb,ccc}{ddd,eee,fff}{yes}{nop}
740% !3nop=\doifcommonelse{aaa}{ddd,eee,fff}{yes}{nop}
741% !4yes=\doifcommonelse{aaa}{aaa}{yes}{nop}
742% !5nop=\doifcommonelse{bbb}{aaa}{yes}{nop}
743% !6nop=\doifcommonelse{}{aaa,bbb,ccc}{yes}{nop}
744% !7nop=\doifcommonelse{aaa,bbb,ccc}{}{yes}{nop}
745% !8nop=\doifcommonelse{}{}{yes}{nop}
746
747% !9nop=\doifcommonelse{,,}{,,}{yes}{nop}
748% !9yes=\doifcommonelse{,a,}{,a,}{yes}{nop}
749% !9yes=\doifcommonelse{,,a,}{,a,}{yes}{nop}
750% !9yes=\doifcommonelse{,a,}{,,a,}{yes}{nop}
751% !9yes=\doifcommonelse{,a,}{,,,a,}{yes}{nop}
752% !9yes=\doifcommonelse{,,a,}{,,,a,}{yes}{nop}
753
754% \permanent\protected\def\doifelsecommon#1#2{\clf_doifelsecommon{#1}{#2}} % todo: define in lua
755% \permanent\protected\def\doifcommon    #1#2{\clf_doifcommon    {#1}{#2}} % todo: define in lua
756% \permanent\protected\def\doifnotcommon #1#2{\clf_doifnotcommon {#1}{#2}} % todo: define in lua
757
758\permanent\protected\def\doifelsecommon#1#2{\clf_if_common{#1}{#2}\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
759\permanent\protected\def\doifcommon    #1#2{\clf_if_common{#1}{#2}\expandafter\firstofoneargument \else\expandafter\gobbleoneargument   \fi}
760\permanent\protected\def\doifnotcommon #1#2{\clf_if_common{#1}{#2}\expandafter\gobbleoneargument  \else\expandafter\firstofoneargument  \fi}
761
762\aliased\let\doifcommonelse\doifelsecommon
763
764%D \macros
765%D   {processcommalist,processcommacommand,quitcommalist,
766%D    processcommalistwithparameters}
767%D
768%D We've already seen some macros that take care of comma separated lists. Such
769%D list can be processed with
770%D
771%D \starttyping
772%D \processcommalist[string,string,...]\commando
773%D \stoptyping
774%D
775%D The user supplied command \type{\commando} receives one argument: the string.
776%D This command permits nesting and spaces after commas are skipped. Empty sets
777%D are no problem.
778%D
779%D \startbuffer
780%D \def\dosomething#1{(#1)}
781%D
782%D 1: \processcommalist [\hbox{$a,b,c,d,e,f$}] \dosomething \par
783%D 2: \processcommalist [{a,b,c,d,e,f}]        \dosomething \par
784%D 3: \processcommalist [{a,b,c},d,e,f]        \dosomething \par
785%D 4: \processcommalist [a,b,{c,d,e},f]        \dosomething \par
786%D 5: \processcommalist [a{b,c},d,e,f]         \dosomething \par
787%D 6: \processcommalist [{a,b}c,d,e,f]         \dosomething \par
788%D 7: \processcommalist []                     \dosomething \par
789%D 8: \processcommalist [{[}]                  \dosomething \par
790%D \stopbuffer
791%D
792%D \typebuffer
793%D
794%D Or expanded:
795%D
796%D \blank \getbuffer \blank
797%D
798%D The original definitions can be found elsewhere and need a bit more code. In case of
799%D issues, consult the \MKIV\ variant or previous \LMTX\ variants in the repository.
800%D
801%D When a list is saved in a macro, we can use a construction like:
802%D
803%D \starttyping
804%D \expandafter\processcommalist\expandafter[\list]\command
805%D \stoptyping
806%D
807%D Such solutions suit most situations, but we wanted a bit more.
808%D
809%D \starttyping
810%D \processcommacommand[string,\stringset,string]\commando
811%D \stoptyping
812%D
813%D where \type{\stringset} is a predefined set, like:
814%D
815%D \starttyping
816%D \def\first{aap,noot,mies}
817%D \def\second{laatste}
818%D
819%D \processcommacommand[\first]\message
820%D \processcommacommand[\first,second,third]\message
821%D \processcommacommand[\first,between,\second]\message
822%D \stoptyping
823%D
824%D Commands that are part of the list are expanded, so the use of this macro has its
825%D limits. We use a new \LUAMETATEX\ feature that intercepts invalid macro arguments
826%D by quitting when \type {\ignorearguments} is seen. That's why we act on the
827%D arguments state. Again it permits leaner and meaner macro definitions with a bit
828%D less clutter in tracing.
829
830\mutable\lettonothing\commalistcommand
831
832% \protected\def\syst_helpers_process_comma_item#+,%
833%   {\ifarguments
834%      \expandafter\syst_helpers_process_comma_item_gobble
835%    \orelse\ifparameter#1\or
836%      \commalistcommand{#1}%
837%      \expandafter\syst_helpers_process_comma_item_next
838%    \else
839%      \expandafter\syst_helpers_process_comma_item_gobble
840%    \fi}
841
842% \def\syst_helpers_process_comma_item_next
843%   {\expandafterspaces\syst_helpers_process_comma_item}
844
845% \protected\def\processcommalist[#1]#2%
846%   {\pushmacro\commalistcommand
847%    \def\commalistcommand{#2}%
848%    \expandafterspaces\syst_helpers_process_comma_item#1,\ignorearguments\ignorearguments\ignorearguments
849%    \popmacro\commalistcommand}
850
851% \protected\def\processcommacommand[#1]#2%
852%   {\pushmacro\commalistcommand
853%    \def\commalistcommand{#2}%
854%    \normalexpanded{\noexpand\expandafterspaces\syst_helpers_process_comma_item#1,}\ignorearguments\ignorearguments\ignorearguments
855%    \popmacro\commalistcommand}
856
857% \permanent\protected\def\processcommalist[#*#+]#2%
858%   {\pushmacro\commalistcommand
859%    \def\commalistcommand{#2}%
860%    \expandafterspaces\syst_helpers_process_comma_item#1,\ignorearguments\ignorearguments\ignorearguments
861%    \popmacro\commalistcommand}
862%
863% \permanent\protected\def\processcommacommand[#*#+]#2%
864%   {\pushmacro\commalistcommand
865%    \def\commalistcommand{#2}%
866%    \normalexpanded{\noexpand\expandafterspaces\syst_helpers_process_comma_item#1,}\ignorearguments\ignorearguments\ignorearguments
867%    \popmacro\commalistcommand}
868
869\tolerant\protected\def\syst_helpers_process_comma_item#*#1,%
870  {\ifarguments\or
871     \commalistcommand{#1}%
872     \expandafter\syst_helpers_process_comma_item_next
873   \fi}
874
875\def\syst_helpers_process_comma_item_next
876  {\expandafterspaces\syst_helpers_process_comma_item}
877
878\permanent\protected\def\processcommalist[#1]#2%
879  {\pushmacro\commalistcommand
880   \def\commalistcommand{#2}%
881   \syst_helpers_process_comma_item#1\ignorearguments\ignorearguments\ignorearguments
882   \popmacro\commalistcommand}
883
884\permanent\protected\def\processcommacommand[#1]#2%
885  {\pushmacro\commalistcommand
886   \def\commalistcommand{#2}%
887   \normalexpanded{\syst_helpers_process_comma_item#1}\ignorearguments\ignorearguments\ignorearguments
888   \popmacro\commalistcommand}
889
890% \let\syst_helpers_process_comma_item_next_a                                                            \syst_helpers_process_comma_item_next
891% \def\syst_helpers_process_comma_item_next_b#-\ignorearguments{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_a}
892% \def\syst_helpers_process_comma_item_next_c#-\ignorearguments{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_b}
893% \def\syst_helpers_process_comma_item_gobble#-\ignorearguments{}
894
895\let\syst_helpers_process_comma_item_next_a                                                            \syst_helpers_process_comma_item_next
896\def\syst_helpers_process_comma_item_next_b#-\ignorearguments{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_a}
897\def\syst_helpers_process_comma_item_next_c#-\ignorearguments{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_b}
898\def\syst_helpers_process_comma_item_gobble#-\ignorearguments{}
899
900\permanent\protected\def\quitcommalist    {\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_b}
901\permanent\protected\def\quitprevcommalist{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_c}
902
903%D \startbuffer
904%D \def\foo#1{(#1)}
905%D <\processcommalist[a,b,c,d]\foo>
906%D
907%D \def\foo#1{(#1)}
908%D \def\oof#1{<\processcommalist[#1]\foo>}
909%D <\processcommalist[{a,b},{c,d}]\oof>
910%D
911%D \def\foo#1{(#1)\quitcommalist}
912%D <\processcommalist[a,b,c,d]\foo>
913%D
914%D \def\foo#1{(#1)}
915%D \def\oof#1{<\processcommalist[#1]\foo\quitcommalist>}
916%D <\processcommalist[{a,b},{c,d}]\oof>
917%D
918%D \def\foo#1{(#1)\quitcommalist}
919%D \def\oof#1{<\processcommalist[#1]\foo>}
920%D <\processcommalist[{a,b},{c,d},{e,f}]\oof>
921%D
922%D \def\foo#1{(#1)\quitprevcommalist}
923%D \def\oof#1{<\processcommalist[#1]\foo>}
924%D <\processcommalist[{a,b},{c,d},{e,f}]\oof>
925%D \stopbuffer
926%D
927%D \typebuffer \blank \getbuffer \blank
928
929%D The argument to \type{\command} is not delimited. Because we often use \type {[]}
930%D as delimiters, we also have:
931%D
932%D \starttyping
933%D \processcommalistwithparameters[string,string,...]\command
934%D \stoptyping
935%D
936%D where \type{\command} looks like:
937%D
938%D \starttyping
939%D \def\command[#1]{... #1 ...}
940%D \stoptyping
941
942\let\syst_helpers_do_process_comma_list_with_parameters\gobbleoneargument
943
944\permanent\protected\def\processcommalistwithparameters[#1]#2%
945  {\def\syst_helpers_do_process_comma_list_with_parameters##1{#2[##1]}%
946   \processcommalist[#1]\syst_helpers_do_process_comma_list_with_parameters}
947
948%D \macros
949%D   {startprocesscommalist,startprocesscommacommand}
950%D
951%D Two more:
952
953\let\syst_helpers_comma_list_step\relax
954
955\mutable\lettonothing\currentcommalistitem
956
957\permanent\protected\def\startprocesscommalist[#1]#2\stopprocesscommalist
958  {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}%
959   \processcommalist[#1]\syst_helpers_comma_list_step}
960
961\permanent\protected\def\startprocesscommacommand[#1]#2\stopprocesscommacommand
962  {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}%
963   \normalexpanded{\processcommalist[#1]}\syst_helpers_comma_list_step}
964
965\permanent\protected\lettonothing\stopprocesscommalist
966\permanent\protected\lettonothing\stopprocesscommacommand
967
968%D \macros
969%D   {processaction,
970%D    processfirstactioninset,
971%D    processallactionsinset}
972%D
973%D \CONTEXT\ makes extensive use of a sort of case or switch command. Depending of
974%D the presence of one or more provided items, some actions is taken. These macros
975%D can be nested without problems.
976%D
977%D \starttyping
978%D \processaction           [x]     [x=>a,y=>b,z=>c]
979%D \processfirstactioninset [x,y,z] [x=>a,y=>b,z=>c]
980%D \processallactionsinset  [x,y,z] [x=>a,y=>b,z=>c]
981%D \stoptyping
982%D
983%D We can supply both a \type {default} action and an action to be undertaken when
984%D an \type {unknown} value is met:
985%D
986%D \starttyping
987%D \processallactionsinset
988%D   [x,y,z]
989%D   [      a=>\a,
990%D          b=>\b,
991%D          c=>\c,
992%D    default=>\default,
993%D    unknown=>\unknown{... \commalistelement ...}]
994%D \stoptyping
995%D
996%D When \type {#1} is empty, this macro scans list \type {#2} for the keyword \type
997%D {default} and executed the related action if present. When \type {#1} is non
998%D empty and not in the list, the action related to \type {unknown} is executed.
999%D Both keywords must be at the end of list \type{#2}. Afterwards, the actually
1000%D found keyword is available in \type {\commalistelement}. An advanced example of
1001%D the use of this macro can be found in \PPCHTEX, where we completely rely on \TEX\
1002%D for interpreting user supplied keywords like \type {SB}, \type {SB1..6}, \type
1003%D {SB125} etc.
1004%D
1005%D In the meantime we follow a different approach, often somewhat more heavy on the
1006%D number of control sequences used, but that is no lomger a real issue. The code
1007%D has been simplified and nwo uses the macro stack mechanism. If needed I can make
1008%D this more hip and a bit faster now but \unknown\ it's seldom used nowadays as we
1009%D have better ways now.
1010
1011\mutable\lettonothing\commalistelement
1012
1013\lettonothing\m_syst_string_one
1014\lettonothing\m_syst_string_two
1015
1016\let\syst_helpers_do_compare_process_action\relax
1017
1018\protected\def\syst_helpers_do_compare_process_action_a[#1=>#2][#3]%
1019  {\edef\m_syst_string_two{#1}%
1020   \ifx\m_syst_string_two\s!default
1021     \lettonothing\commalistelement
1022     #2%
1023   \fi}
1024
1025\protected\def\syst_helpers_do_compare_process_action_b[#1=>#2][#3]%
1026  {\edef\m_syst_string_two{#1}%
1027   \ifx\m_syst_string_one\m_syst_string_two
1028     \def\commalistelement{#3}%
1029     #2%
1030     \expandafter\quitcommalist
1031   \orelse\ifx\m_syst_string_two\s!unknown
1032     \def\commalistelement{#3}% beware of loops
1033     #2%
1034   \fi}
1035
1036\permanent\protected\def\processaction[#1]#2[%
1037  {\edef\m_syst_string_one{#1}%
1038   \ifempty\m_syst_string_one
1039     \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_a
1040   \else
1041     \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_b
1042   \fi
1043   \edef\syst_helpers_do_process_action##1{\syst_helpers_do_compare_process_action[##1][#1]}% expands #1
1044   \processnextcommalist\syst_helpers_do_process_action[}
1045
1046\protected\def\syst_helpers_do_compare_process_action_c[#1=>#2][#3]%
1047  {\edef\m_syst_string_one{#1}%
1048   \edef\m_syst_string_two{#3}%
1049   \ifx\m_syst_string_one\m_syst_string_two
1050     \def\commalistelement{#3}%
1051     #2%
1052     \expandafter\quitprevcommalist
1053   \else
1054     \edef\m_syst_string_one{#1}%
1055     \ifx\m_syst_string_one\s!unknown
1056       \def\commalistelement{#3}%
1057       #2%
1058     \fi
1059   \fi}
1060
1061\permanent\protected\def\processfirstactioninset[#1]%
1062  {\edef\m_syst_string_one{#1}%
1063   \ifempty\m_syst_string_one
1064     \expandafter\processaction
1065   \else
1066     \expandafter\syst_helpers_process_first_action_in_set_indeed
1067   \fi
1068   [#1]}
1069
1070\let\syst_helpers_do_process_action   \gobbleoneargument
1071\let\syst_helpers_do_do_process_action\gobbleoneargument
1072
1073\tolerant\protected\def\syst_helpers_process_first_action_in_set_indeed[#1]#*[#2]%
1074  {\def\syst_helpers_do_process_action##1%
1075     {\def\syst_helpers_do_do_process_action####1{\syst_helpers_do_compare_process_action_c[####1][##1]}%
1076      \processcommalist[#2]\syst_helpers_do_do_process_action}%
1077   \normalexpanded{\processcommalist[#1]}\syst_helpers_do_process_action}
1078
1079\protected\def\syst_helpers_do_compare_process_action_d[#1=>#2][#3]%
1080  {\edef\m_syst_string_one{#1}%
1081   \edef\m_syst_string_two{#3}%
1082   \ifx\m_syst_string_one\m_syst_string_two
1083     \def\commalistelement{#3}%
1084     #2%
1085     \expandafter\quitcommalist
1086   \else
1087     \edef\m_syst_string_one{#1}%
1088     \ifx\m_syst_string_one\s!unknown
1089       \def\commalistelement{#3}%
1090       #2%
1091     \fi
1092   \fi}
1093
1094\let\syst_process_action_in_set_all\relax
1095
1096\tolerant\protected\def\syst_helpers_process_all_actions_in_set_indeed[#1]#*[#2]%
1097  {\globalpushmacro\syst_process_action_in_set_all
1098   \def\syst_process_action_in_set##1%
1099     {\def\syst_process_action_in_set_one####1{\syst_helpers_do_compare_process_action_d[####1][##1]}%
1100      \processcommalist[#2]\syst_process_action_in_set_one}%
1101      \processcommacommand[#1]\syst_process_action_in_set
1102   \globalpopmacro\syst_process_action_in_set_all}
1103
1104\permanent\protected\def\processallactionsinset[#1]%
1105  {\edef\m_syst_string_one{#1}%
1106   \ifempty\m_syst_string_one
1107     \expandafter\processaction
1108   \else
1109     \expandafter\syst_helpers_process_all_actions_in_set_indeed
1110   \fi[#1]}
1111
1112%D These macros use:
1113
1114% \protected\def\processnextcommalist#1[#2#3]%
1115%   {\pushmacro\commalistcommand
1116%    \def\commalistcommand{#1}%
1117%    \expandafterspaces\syst_helpers_process_comma_item#2#3\ignorearguments\ignorearguments\ignorearguments
1118%    \popmacro\commalistcommand}
1119
1120\permanent\protected\def\processnextcommalist#1[#2#3]% watch out: mkiv has two extra initial arguments
1121  {\pushmacro\commalistcommand
1122   \def\commalistcommand{#1}%
1123   \expandafterspaces\syst_helpers_process_comma_item#2#3\ignorearguments\ignorearguments\ignorearguments
1124   \popmacro\commalistcommand}
1125
1126%D \macros
1127%D   {getfirstcharacter, firstcharacter, remainingcharacters, doiffirstcharacter}
1128%D
1129%D Sometimes the action to be undertaken depends on the next character. This macro
1130%D get this character and puts it in \type {\firstcharacter}.
1131%D
1132%D \starttyping
1133%D \getfirstcharacter {string}
1134%D \stoptyping
1135%D
1136%D A two step expansion is used to prevent problems with complicated arguments, for
1137%D instance arguments that consist of two or more expandable tokens.
1138
1139\mutable\lettonothing\firstcharacter
1140\mutable\lettonothing\remainingcharacters
1141
1142\permanent\protected\def\getfirstcharacter     #1{\clf_getfirstcharacter{#1}}
1143\permanent\protected\def\doifelsefirstchar   #1#2{\clf_doifelsefirstchar{#1}{#2}}
1144\permanent\protected\def\thefirstcharacter     #1{\clf_thefirstcharacter{#1}}
1145\permanent\protected\def\theremainingcharacters#1{\clf_theremainingcharacters{#1}}
1146
1147\aliased\let\doiffirstcharelse\doifelsefirstchar
1148
1149%D \macros
1150%D   {doifinstringelse, doifincsnameelse}
1151%D
1152%D We can check for the presence of a substring in a given sequence of characters.
1153%D
1154%D \starttyping
1155%D \doifinstringelse {substring} {string} {then ...} {else ...}
1156%D \stoptyping
1157%D
1158%D \startbuffer
1159%D \doifinstringelse{abc}{foo bar abc}{Y}{N}=Y\par
1160%D \doifinstringelse{abc}{foo bar cab}{Y}{N}=N\par
1161%D \doifinstring    {abc}{foo bar abc}{Y}=Y\par
1162%D \doifinstring    {abc}{foo bar cab}{Y}\par
1163%D \doifnotinstring {abc}{foo bar abc}{Y}\par
1164%D \doifnotinstring {abc}{foo bar cab}{Y}=Y\par
1165%D \doifinstringelse{}{foo bar abc}{Y}{N}=N\par
1166%D \doifinstring    {}{foo bar abc}{N}\par
1167%D \doifnotinstring {}{foo bar abc}{Y}=Y\par
1168%D \doifinstringelse{x}{}{Y}{N}=N\par
1169%D \doifinstring    {x}{}{N}\par
1170%D \doifnotinstring {x}{}{Y}=Y\par
1171%D \doifinstringelse{}{}{Y}{N}=N\par
1172%D \doifinstring    {}{}{N}\par
1173%D \doifnotinstring {}{}{Y}=Y\par
1174%D \stopbuffer
1175%D
1176%D \typebuffer \blank \getbuffer \blank
1177
1178%D I keep the following as example code:
1179
1180% \let\syst_helpers_do_do_if_in_string_else\relax
1181% \let\syst_helpers_do_do_if_in_string     \relax
1182% \let\syst_helpers_do_do_if_not_in_string \relax
1183%
1184% \lettonothing\m_syst_sub_string
1185%
1186% \protected\def\doifelseinstring#1%
1187%   {\edef\m_syst_sub_string{#1}% expand #1 here
1188%    \ifempty\m_syst_sub_string
1189%      \expandafter\thirdofthreearguments
1190%    \else
1191%      \expandafter\syst_helpers_do_if_in_string_else
1192%    \fi}
1193%
1194% \let\doifinstringelse\doifelseinstring
1195%
1196% \protected\def\syst_helpers_do_if_in_string_else#1% ##2 can be {abc}
1197%   {\normalexpanded{\protected\def\syst_helpers_do_do_if_in_string_else##1\m_syst_sub_string##2}%
1198%      {\ifarguments
1199%       \or
1200%         \expandafter\syst_helpers_do_if_in_string_else_nop
1201%       \or
1202%         \expandafter\syst_helpers_do_if_in_string_else_yes
1203%       \fi}%
1204%    \normalexpanded{\syst_helpers_do_do_if_in_string_else#1}\s!e_o_t_token\ignorearguments\ignorearguments}
1205%
1206% \protected\def\syst_helpers_do_if_in_string_else_delimited#1% ##2 can be {abc}
1207%   {\normalexpanded{\protected\def\syst_helpers_do_do_if_in_string_else##1,\m_syst_sub_string,##2}%
1208%      {\ifarguments
1209%       \or
1210%         \expandafter\syst_helpers_do_if_in_string_else_nop
1211%       \or
1212%         \expandafter\syst_helpers_do_if_in_string_else_yes
1213%       \fi}%
1214%    \normalexpanded{\syst_helpers_do_do_if_in_string_else,#1,}\s!e_o_t_token\ignorearguments\ignorearguments}
1215%
1216% \protected\def\doifinstring#1%
1217%   {\edef\m_syst_sub_string{#1}% expand #1 here
1218%    \ifempty\m_syst_sub_string
1219%      \expandafter\gobbletwoarguments
1220%    \else
1221%      \expandafter\syst_helpers_do_if_in_string
1222%    \fi}
1223%
1224% \protected\def\syst_helpers_do_if_in_string#1% ##2 can be {abc}
1225%   {\normalexpanded{\protected\def\syst_helpers_do_do_if_in_string##1\m_syst_sub_string##2}%
1226%      {\ifarguments
1227%       \or
1228%         \expandafter\syst_helpers_do_if_in_string_nop
1229%       \or
1230%         \expandafter\syst_helpers_do_if_in_string_yes
1231%       \fi}%
1232%    \normalexpanded{\syst_helpers_do_do_if_in_string#1}\s!e_o_t_token\ignorearguments\ignorearguments}
1233%
1234% \protected\def\doifnotinstring#1%
1235%   {\edef\m_syst_sub_string{#1}% expand #1 here
1236%    \ifempty\m_syst_sub_string
1237%      \expandafter\secondoftwoarguments
1238%    \else
1239%      \expandafter\syst_helpers_do_if_not_in_string
1240%    \fi}
1241%
1242% \protected\def\syst_helpers_do_if_not_in_string#1% ##2 can be {abc}
1243%   {\normalexpanded{\protected\def\syst_helpers_do_do_if_not_in_string##1\m_syst_sub_string##2}%
1244%      {\ifarguments
1245%       \or
1246%         \expandafter\syst_helpers_do_if_not_in_string_nop
1247%       \or
1248%         \expandafter\syst_helpers_do_if_not_in_string_yes
1249%       \fi}%
1250%    \normalexpanded{\syst_helpers_do_do_if_not_in_string#1}\s!e_o_t_token\ignorearguments\ignorearguments}
1251%
1252% \def\syst_helpers_do_if_in_string_else_yes#0\ignorearguments\ignorearguments#2#0{#2} % of #- and #1
1253% \def\syst_helpers_do_if_in_string_else_nop#0\ignorearguments#0#3{#3}
1254% \def\syst_helpers_do_if_in_string_yes     #0\ignorearguments\ignorearguments#2{#2}
1255% \def\syst_helpers_do_if_in_string_nop     #0\ignorearguments#0{}
1256% \def\syst_helpers_do_if_not_in_string_yes #0\ignorearguments\ignorearguments#0{}
1257% \def\syst_helpers_do_if_not_in_string_nop #0\ignorearguments#2{#2}
1258
1259\permanent\protected\def\doifelseinstring#1#2%
1260  {\ifhasxtoks{#1}{#2}%
1261     \expandafter\firstoftwoarguments
1262   \else
1263     \expandafter\secondoftwoarguments
1264   \fi}
1265
1266\permanent\protected\def\doifinstring#1#2%
1267  {\ifhasxtoks{#1}{#2}%
1268     \expandafter\firstofoneargument
1269   \else
1270     \expandafter\gobbleoneargument
1271   \fi}
1272
1273\permanent\protected\def\doifnotinstring#1#2%
1274  {\ifhasxtoks{#1}{#2}%
1275     \expandafter\gobbleoneargument
1276   \else
1277     \expandafter\firstofoneargument
1278   \fi}
1279
1280\aliased\let\doifinstringelse\doifelseinstring
1281
1282%D The next one one of those variants that we used when speed was more of an issue
1283%D that today. Now we just expand the lot. We just use an alias now:
1284
1285\aliased\let\doifelseincsname\doifelseinstring
1286\aliased\let\doifincsnameelse\doifinstringelse
1287
1288%D \macros
1289%D   {doifnumberelse,doifnumber,doifnotnumber}
1290%D
1291%D The next macro executes a command depending of the outcome of a test on numerals.
1292%D We now use a \LUATEX\ feature that permits a more robust checking, but you might
1293%D want to take a look at the originals. It's typically one of these new features
1294%D that probably only \CONTEXT\ will use, which is probably true for more such
1295%D features that no one ever asked for (but they are pretty generic in nature
1296%D anyway).
1297
1298\permanent\def\doifelsenumber#1%
1299  {\ifchknum#1\or
1300     \expandafter\firstoftwoarguments
1301   \else
1302     \expandafter\secondoftwoarguments
1303   \fi}
1304
1305\permanent\def\doifnumber#1%
1306  {\ifchknum#1\or
1307     \expandafter\firstoftwoarguments
1308   \else
1309     \expandafter\gobbleoneargument
1310   \fi}
1311
1312\permanent\def\doifnotnumber#1%
1313  {\ifchknum#1\or
1314     \expandafter\gobbleoneargument
1315   \else
1316     \expandafter\firstofoneargument
1317   \fi}
1318
1319\aliased\let\doifnumberelse\doifelsenumber
1320
1321%D \macros
1322%D   {setpercentdimen}
1323%D
1324%D \starttyping
1325%D \scratchdimen=100pt \setpercentdimen\scratchdimen{10\letterpercent}
1326%D \scratchdimen=100pt \setpercentdimen\scratchdimen{5pt}
1327%D \scratchdimen       \percentdimen   \hsize       {10\letterpercent}
1328%D \stoptyping
1329
1330% todo: use the push back dimen trickery
1331
1332\permanent\def\percentdimen#1#2% dimen percentage (with %)
1333  {\dimexpr\clf_percentageof{#2}{#1}\relax}
1334
1335\permanent\protected\def\setpercentdimen#1#2% dimen percentage (with %)
1336  {#1=\clf_percentageof{#2}{#1}}
1337
1338%D \macros
1339%D   {makerawcommalist,
1340%D    rawdoinsetelse,
1341%D    rawprocesscommalist,
1342%D    rawprocessaction}
1343%D
1344%D Some of the commands mentioned earlier are effective but slow. When one is
1345%D desperately in need of faster alternatives and when the conditions are
1346%D predictable safe, the \type {\raw} alternatives come into focus. A major drawback
1347%D is that they do not take \type {\c!constants} into account, simply because no
1348%D expansion is done. This is no problem with \type {\rawprocesscommalist}, because
1349%D this macro does not compare anything. Expandable macros are permitted as search
1350%D string.
1351%D
1352%D \starttyping
1353%D \makerawcommalist[string,string,...]\stringlist
1354%D \rawdoifelseinset{string}{string,...}{...}{...}
1355%D \rawprocesscommalist[string,string,...]\commando
1356%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c]
1357%D \stoptyping
1358%D
1359%D Spaces embedded in the list, for instance after commas, spoil the search process.
1360%D The gain in speed depends on the length of the argument (the longer the argument,
1361%D the less we gain). The question is: do we still need these raw variants?
1362
1363\let\syst_helpers_do_make_raw_comma_list\gobbleoneargument
1364
1365\permanent\protected\def\makerawcommalist[#1]#2% use \processnext ... here
1366  {\scratchtoks\emptytoks
1367   \def\syst_helpers_do_make_raw_comma_list##1{\ifempty\scratchtoks\scratchtoks{##1}\else\toksapp\scratchtoks{,##1}\fi}%
1368   \processcommalist[#1]\syst_helpers_do_make_raw_comma_list
1369   \edef#2{\the\scratchtoks}}
1370
1371% beware: in mkiv { } were lost so it was not compatible with the non raw
1372
1373\aliased\let\rawprocesscommalist   \processcommalist    % can go
1374\aliased\let\rawprocesscommacommand\processcommacommand % can go
1375
1376%D Here is one without nesting .. still needed? Only used for modes (no nesting
1377%D there).
1378
1379\mutable\let\fastcommalistcommand\relax
1380
1381\protected\def\syst_helpers_process_fast_comma_item#1,%
1382  {\ifarguments
1383     \expandafter\syst_helpers_process_comma_item_gobble
1384   \or
1385     \fastcommalistcommand{#1}%
1386     \expandafter\syst_helpers_process_fast_comma_item_next
1387   \fi}
1388
1389\protected\def\syst_helpers_process_fast_comma_item_next
1390  {\expandafterspaces\syst_helpers_process_fast_comma_item}
1391
1392\permanent\protected\def\fastprocesscommalist[#1]#2%
1393  {\let\fastcommalistcommand#2%
1394   \expandafterspaces\syst_helpers_process_fast_comma_item#1\ignorearguments\ignorearguments\ignorearguments}
1395
1396\permanent\protected\def\fastprocesscommacommand[#1]#2%
1397  {\let\fastcommalistcommand#2%
1398   \normalexpanded{\noexpand\expandafterspaces\syst_helpers_process_fast_comma_item#1}\ignorearguments\ignorearguments\ignorearguments}
1399
1400% \def\rawdoifelseinset#1#2{\doifinstringelse{,#1,}{,#2,}}
1401% \def\rawdoifinset    #1#2{\doifinstring    {,#1,}{,#2,}}
1402
1403\def\syst_helpers_do_if_else_in_set#1%
1404  {\ifhasxtoks{,\m_syst_sub_string,}{,#1,}%
1405     \expandafter\firstoftwoarguments
1406   \else
1407     \expandafter\secondoftwoarguments
1408   \fi}
1409
1410\permanent\protected\def\rawdoifelseinset#1%
1411  {\edef\m_syst_sub_string{#1}% expand #1 here
1412   \ifempty\m_syst_sub_string
1413     \expandafter\thirdofthreearguments
1414   \else
1415     \expandafter\syst_helpers_do_if_else_in_set
1416   \fi}
1417
1418\aliased\let\rawdoifinsetelse\rawdoifelseinset
1419
1420\def\syst_helpers_do_if_in_set#1%
1421  {\ifhasxtoks{,\m_syst_sub_string,}{,#1,}%
1422     \expandafter\firstofoneargument
1423   \else
1424     \expandafter\gobbleoneargument
1425   \fi}
1426
1427\permanent\protected\def\rawdoifinset#1% or just alias this one
1428  {\edef\m_syst_sub_string{#1}% expand #1 here
1429   \ifx\m_syst_sub_string\m_syst_two_commas
1430     \expandafter\gobbletwoarguments
1431   \else
1432     \expandafter\syst_helpers_do_if_in_set
1433   \fi}
1434
1435%D Some more raw material:
1436
1437% probably never used
1438%
1439% \def\syst_helpers_raw_process_action#1=>#2,%
1440%   {\ifarguments
1441%     %\expandafter\syst_helpers_raw_process_action_gobble
1442%    \or
1443%      \expandafter\syst_helpers_raw_process_action_gobble
1444%    \or
1445%      \edef\m_syst_string_two{#1}%
1446%      \ifx\m_syst_string_one\m_syst_string_two
1447%        \def\m_syst_helpers_process_action{#2}%
1448%        \expandafter\expandafter\expandafter\syst_helpers_raw_process_action_gobble
1449%      \else
1450%        \ifx\s!unknown\m_syst_string_two
1451%          \def\m_syst_helpers_process_action_unknown{#2}%
1452%        \fi
1453%        \expandafter\expandafter\expandafter\syst_helpers_raw_process_action_next
1454%      \fi
1455%    \fi}
1456%
1457% \def\syst_helpers_raw_process_action_gobble#-\ignorearguments
1458%   {}
1459%
1460% \def\syst_helpers_raw_process_action_next
1461%   {\expandafterspaces\syst_helpers_raw_process_action}
1462%
1463% \permanent\protected\def\xrawprocessaction[#1]#*[#2]%
1464%   {\edef\m_syst_string_one{#1}%
1465%    \ifempty\m_syst_string_one
1466%       \let\m_syst_string_one\s!default
1467%    \fi
1468%    \let\m_syst_helpers_process_action\relax
1469%    \let\m_syst_helpers_process_action_unknown\relax
1470%    \syst_helpers_raw_process_action#2\ignorearguments\ignorearguments\ignorearguments
1471%    \ifrelax\m_syst_helpers_process_action
1472%      \m_syst_helpers_process_action_unknown
1473%    \else
1474%      \m_syst_helpers_process_action
1475%    \fi}
1476
1477%D When we process the list \type {a,b,c,d,e}, the raw routine takes over 30\% less
1478%D time, when we feed $20+$ character strings we gain about 20\%. Alternatives which
1479%D use \type {\futurelet} perform worse. Part of the speedup is due to the \type
1480%D {\let} and \type {\expandafter} in the test.
1481%D
1482%D \macros
1483%D   {dosetvalue,dosetevalue,dosetgvalue,docopyvalue,doresetvalue,
1484%D    dogetvalue}
1485%D
1486%D When we are going to do assignments, we have to take multi||linguality into account.
1487%D For the moment we keep things simple and single||lingual.
1488%D
1489%D \starttyping
1490%D \dosetvalue   {label}    {variable}   {value}
1491%D \dosetevalue  {label}    {variable}   {value}
1492%D \dosetgvalue  {label}    {variable}   {value}
1493%D \docopyvalue  {to label} {from label} {variable}
1494%D \doresetvalue {label}    {variable}
1495%D \stoptyping
1496%D
1497%D These macros are in fact auxiliary ones and are not meant for use outside the
1498%D assignment macros.
1499
1500\def\dosetvalue     #1#2{\defcsname        #1#2\endcsname} % takes #3
1501\def\dosetevalue    #1#2{\edefcsname       #1#2\endcsname} % takes #3
1502\def\dosetgvalue    #1#2{\global\edefcsname#1#2\endcsname} % takes #3
1503\def\doresetvalue   #1#2{\letcsname        #1#2\endcsname\empty}
1504\def\doignorevalue#1#2#3{\letcsname        #1#2\endcsname\empty}
1505\def\docopyvalue  #1#2#3{\defcsname        #1#3\endcsname{\csname#2#3\endcsname}}
1506
1507%D \macros
1508%D   {doassign,undoassign,doassignempty}
1509%D
1510%D Assignments are the backbone of \CONTEXT. Abhorred by the concept of style file
1511%D hacking, we took a considerable effort in building a parameterized system.
1512%D Unfortunately there is a price to pay in terms of speed. Compared to other
1513%D packages and taking the functionality of \CONTEXT\ into account, the total size
1514%D of the format file is still very acceptable. Now how are these assignments done.
1515%D
1516%D Assignments can be realized with:
1517%D
1518%D \starttyping
1519%D \doassign[label][variable=value]
1520%D \undoassign[label][variable=value]
1521%D \stoptyping
1522%D
1523%D and:
1524%D
1525%D \starttyping
1526%D \doassignempty[label][variable=value]
1527%D \stoptyping
1528%D
1529%D Assignments like \type{\doassign} are compatible with:
1530%D
1531%D \starttyping
1532%D \def\labelvariable{value}
1533%D \stoptyping
1534%D
1535%D We do check for the presence of an \type{=} and loudly complain of it's missed. We
1536%D will redefine this macro later on, when a more advanced message mechanism is
1537%D implemented.
1538
1539\protected\def\showassignerror#1#2%
1540  {\writestatus{setup}{missing or ungrouped '=' after '#1' in line #2}}
1541
1542\permanent\protected\def\doassignempty[#1][#2=#3]% kind of obsolete
1543  {\ifcsname#1#2\endcsname\else\dosetvalue{#1}{#2}{#3}\fi}
1544
1545%D \macros
1546%D   {getparameters,geteparameters,getgparameters,
1547%D    forgetparameters}
1548%D
1549%D Using the assignment commands directly is not our ideal of user friendly interfacing,
1550%D so we take some further steps.
1551%D
1552%D \starttyping
1553%D \getparameters    [label] [...=...,...=...]
1554%D \forgetparameters [label] [...=...,...=...]
1555%D \stoptyping
1556%D
1557%D Again, the label identifies the category a variable belongs to. The second argument
1558%D can be a comma separated list of assignments.
1559%D
1560%D \starttyping
1561%D \getparameters
1562%D   [demo]
1563%D   [alfa=1,
1564%D    beta=2]
1565%D \stoptyping
1566%D
1567%D is equivalent to
1568%D
1569%D \starttyping
1570%D \def\demoalfa{1}
1571%D \def\demobeta{2}
1572%D \stoptyping
1573%D
1574%D
1575%D In the pre||multi||lingual stadium \CONTEXT\ took the next approach. With
1576%D
1577%D \starttyping
1578%D \def\??demo {@@demo}
1579%D \def\!!alfa {alfa}
1580%D \def\!!beta {beta}
1581%D \stoptyping
1582%D
1583%D calling
1584%D
1585%D \starttyping
1586%D \getparameters
1587%D   [\??demo]
1588%D   [\!!alfa=1,
1589%D    \!!beta=2]
1590%D \stoptyping
1591%D
1592%D lead to:
1593%D
1594%D \starttyping
1595%D \def\@@demoalfa{1}
1596%D \def\@@demobeta{2}
1597%D \stoptyping
1598%D
1599%D Because we want to be able to distinguish the \type{!!} pre||tagged user supplied
1600%D variables from internal counterparts, we will introduce a slightly different tag
1601%D in the multi||lingual modules. There we will use \type{c!} or \type{v!},
1602%D depending on the context.
1603%D
1604%D By calling \type{doassign} directly, we save ourselves some argument passing
1605%D and gain some speed. Whatever optimizations we do, this command will always be
1606%D one of the bigger bottlenecks. The alternative \type{\geteparameters} --- it's
1607%D funny to see that this alternative saw the light so lately --- can be used to do
1608%D expanded assigments.
1609
1610% \mutable\lettonothing\currentvalue % only mkii
1611
1612% \permanent\protected\def\getparameters   {\dogetparameters\dosetvalue}
1613% \permanent\protected\def\geteparameters  {\dogetparameters\dosetevalue}
1614% \permanent\protected\def\getgparameters  {\dogetparameters\dosetgvalue}
1615% \permanent\protected\def\getxparameters  {\dogetparameters\dosetxvalue}
1616% \permanent\protected\def\forgetparameters{\dogetparameters\doignorevalue}
1617%
1618% \aliased\let\getexpandedparameters\geteparameters
1619%
1620% \def\syst_helpers_grab_parameter_error#1%
1621%   {\showassignerror{#1}{\the\inputlineno\space(\m_syst_parameter_n)}}
1622%
1623% \def\syst_helpers_grab_parameter#1,%
1624%   {\ifarguments
1625%      % done
1626%    \else
1627%      \syst_helpers_grab_parameter_okay#1,\ignorearguments
1628%      \expandafter\syst_helpers_grab_parameter_next
1629%    \fi}
1630%
1631% \def\syst_helpers_grab_parameter_okay#1=#2,%
1632%   {\ifarguments
1633%    \or
1634%      \syst_helpers_grab_parameter_error{#1}%
1635%    \or
1636%      \m_syst_parameter_s\m_syst_parameter_n{#1}{#2}%
1637%    \fi}
1638%
1639% \def\syst_helpers_grab_parameter_next
1640%   {\expandafterspaces\syst_helpers_grab_parameter}
1641%
1642% \permanent\protected\def\dogetparameters#1[#2]#*[#3]%
1643%   {\def\m_syst_parameter_n{#2}%
1644%    \let\m_syst_parameter_s#1%
1645%    \expandafterspaces\syst_helpers_grab_parameter#3\ignorearguments\ignorearguments}
1646
1647% Doesn't work with single entry empty values [foo=]
1648%
1649% \tolerant\def\syst_get_parameters_n#*#1=#S#2,#M,%
1650%   {\ifarguments             \expandafter\gobbleoneargument
1651%    \or                      \mult_interfaces_get_parameters_error_indeed\m_syst_parameter{#1}%
1652%    \orelse\ifparameter#2\or \defcsname\m_syst_parameter#1\endcsname{#2}%
1653%    \else                    \letcsname\m_syst_parameter#1\endcsname\empty
1654%    \fi                      \syst_get_parameters_n}
1655%
1656% so we do this instead (and also silently recover).
1657
1658\tolerant\def\syst_get_parameters_n#*#1=#S#2,#M,%
1659  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
1660   \orelse\ifparameter#2\or\defcsname\m_syst_parameter#1\endcsname{#2}%
1661   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
1662   \fi                     \syst_get_parameters_n}
1663\tolerant\def\syst_get_parameters_e#*#1=#S#2,#M,%
1664  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
1665   \orelse\ifparameter#2\or\edefcsname\m_syst_parameter#1\endcsname{#2}%
1666   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
1667   \fi                     \syst_get_parameters_e}
1668\tolerant\def\syst_get_parameters_g#*#1=#S#2,#M,%
1669  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
1670   \orelse\ifparameter#2\or\gdefcsname\m_syst_parameter#1\endcsname{#2}%
1671   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
1672   \fi                     \syst_get_parameters_g}
1673\tolerant\def\syst_get_parameters_x#*#1=#S#2,#M,%
1674  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
1675   \orelse\ifparameter#2\or\xdefcsname\m_syst_parameter#1\endcsname{#2}%
1676   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
1677   \fi                     \syst_get_parameters_x}
1678\tolerant\def\syst_get_parameters_f#*#1=#S#2,#M,%
1679  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
1680   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
1681   \fi                     \syst_get_parameters_f}
1682
1683\permanent\protected\def\getparameters   [#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_n#2\ignorearguments\ignorearguments}
1684\permanent\protected\def\geteparameters  [#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_e#2\ignorearguments\ignorearguments}
1685\permanent\protected\def\getgparameters  [#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_g#2\ignorearguments\ignorearguments}
1686\permanent\protected\def\getxparameters  [#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_x#2\ignorearguments\ignorearguments}
1687\permanent\protected\def\forgetparameters[#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_f#2\ignorearguments\ignorearguments}
1688
1689\aliased\let\getexpandedparameters\geteparameters
1690
1691%D \macros
1692%D   {getemptyparameters}
1693%D
1694%D Sometimes we explicitly want variables to default to an empty string, so we
1695%D welcome:
1696%D
1697%D \starttyping
1698%D \getemptyparameters [label] [...=...,...=...]
1699%D \stoptyping
1700
1701% \let\syst_helpers_get_empty_parameters\gobbleoneargument
1702%
1703% \permanent\protected\def\getemptyparameters[#1]#*[#2]%
1704%   {\def\syst_helpers_get_empty_parameters##1{\doassignempty[#1][##1]}%
1705%    \processcommalist[#2]\syst_helpers_get_empty_parameters}
1706
1707\let\syst_helpers_copy_parameter\relax
1708
1709\permanent\protected\def\getemptyparameters[#1]#*[#2]%
1710  {\def\syst_helpers_copy_parameter##1{\letcsname#1##1\endcsname\empty}%
1711   \processcommalist[#2]\syst_helpers_get_empty_parameters}
1712
1713%D We now just alias these as there is no need for a speedup. These have not been used
1714%D for a long time in core code.
1715
1716\aliased\let\doassign  \getparameters    % obsolete, these will go
1717\aliased\let\doeassign \geteparameters   % obsolete, these will go
1718\aliased\let\undoassign\forgetparameters % obsolete, these will go
1719
1720%D \macros
1721%D   {processassignmentlist,processassignmentcommand,
1722%D    startprocessassignmentlist,startprocessassignmentcommand}
1723%D
1724%D For Wolfgang:
1725%D
1726%D \starttyping
1727%D \def\showpair#1#2{key:#1, value:#2\par}
1728%D \processassignmentlist[a=1,b=2]\showpair
1729%D \stoptyping
1730%D
1731%D We can optimize this one if needed but it's not a core macro so hardly worth the
1732%D trouble and tokens.
1733
1734\mutable\let\currentassignmentlistcommand\gobbletwoarguments
1735
1736\mutable\lettonothing\currentassignmentlistkey
1737\mutable\lettonothing\currentassignmentlistvalue
1738
1739\let\syst_helpers_process_assign_entry\gobbleoneargument
1740
1741% \permanent\protected\def\processassignmentlist[#1]#2% #2 == \command{key}{value]
1742%   {\def\syst_helpers_process_assign_entry##1{#2}% {##2}{##3} % namespace is ignored
1743%    \dogetparameters\syst_helpers_process_assign_entry[][#1]}
1744
1745\tolerant\def\syst_helpers_process_assign_value#*#1=#S#2,#M,%
1746  {\ifarguments
1747     \expandafter\gobbleoneargument
1748   \or
1749     \mult_interfaces_get_parameters_error_indeed\empty{#1}%
1750   \else
1751     \syst_helpers_process_assign_entry{#1}{#2}%
1752   \fi
1753   \syst_helpers_process_assign_value}
1754
1755\permanent\protected\def\processassignmentlist[#S#1]#2% #2 == \command{key}{value]
1756  {\def\syst_helpers_process_assign_entry{#2}%
1757   \syst_helpers_process_assign_value#1\ignorearguments\ignorearguments}
1758
1759\permanent\protected\def\processassignmentcommand[#1]%
1760  {\normalexpanded{\processassignmentlist[#1]}}
1761
1762\permanent\protected\def\startprocessassignmentlist[#1]#2\stopprocessassignmentlist
1763  {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}%
1764   \processassignmentlist[#1]\currentassignmentlistcommand}
1765
1766\permanent\protected\lettonothing\stopprocessassignmentlist
1767
1768\permanent\protected\def\startprocessassignmentcommand[#1]#2\stopprocessassignmentcommand
1769  {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}%
1770   \normalexpanded{\processassignmentlist[#1]}\currentassignmentlistcommand}
1771
1772\permanent\protected\lettonothing\stopprocessassignmentcommand
1773
1774%D \macros
1775%D   {currentvalue}
1776%D
1777%D Just in case a \type{\getparameter} argument itself ends up inside a \type
1778%D {\write} or other expandable location, our new macro needs a default value.
1779%D
1780%D \starttyping
1781%D \getparameters[xxx][aaa=bbb]\par
1782%D \getparameters[xxx][=bbb]\par
1783%D \getparameters[xxx][aaa=]\par
1784%D \getparameters[xxx][=]\par
1785%D \getparameters[xxx][aaa]\par
1786%D \stoptyping
1787
1788%D \macros
1789%D   {copyparameters}
1790%D
1791%D Some \CONTEXT\ commands take their default setups from others. All commands that
1792%D are able to provide backgounds or rules around some content, for instance default
1793%D to the standard command for ruled boxes. Is situations like this we can use:
1794%D
1795%D \starttyping
1796%D \copyparameters [to-label] [from-label] [name1,name2,...]
1797%D \stoptyping
1798%D
1799%D For instance
1800%D
1801%D \starttyping
1802%D \copyparameters
1803%D   [internal][external]
1804%D   [alfa,beta]
1805%D \stoptyping
1806%D
1807%D Leads to:
1808%D
1809%D \starttyping
1810%D \def\internalalfa {\externalalfa}
1811%D \def\internalbeta {\externalbeta}
1812%D \stoptyping
1813%D
1814%D By using \type {\docopyvalue} we've prepared this command for use in a
1815%D multi||lingual environment.
1816
1817% \let\syst_helpers_copy_parameter\relax
1818%
1819% \permanent\protected\def\copyparameters[#1]#*[#2]#*[#3]%
1820%   {\iftok{#1}{#2}\else
1821%      \def\syst_helpers_copy_parameter{\docopyvalue{#1}{#2}}% ##1
1822%      \processcommalist[#3]\syst_helpers_copy_parameter
1823%    \fi}
1824
1825\let\syst_helpers_copy_parameter\relax
1826
1827\permanent\protected\def\copyparameters[#1]#*[#2]#*[#3]%
1828  {\iftok{#1}{#2}\else
1829     \def\syst_helpers_copy_parameter##1{\defcsname#1##1\endcsname{\begincsname#2##1\endcsname}}%
1830     \processcommalist[#3]\syst_helpers_copy_parameter
1831   \fi}
1832
1833% %D \macros
1834% %D   {ifparameters,checkparameters}
1835% %D
1836% %D A slightly different one is \type {\checkparameters}, which also checks on the
1837% %D presence of a~\type {=}.
1838% %D
1839% %D The boolean \type {\ifparameters} can be used afterwards. Combining both in one
1840% %D \type {\if}||macro would lead to problems with nested \type {\if}'s.
1841% %D
1842% %D \starttyping
1843% %D \checkparameters[argument]
1844% %D \stoptyping
1845
1846% \newif\ifparameters
1847
1848% \protected\def\checkparameters[#1]%
1849%   {\ifhastok={#1}\parameterstrue\else\parametersfalse\fi}
1850
1851%D \macros
1852%D   {getfromcommalist,getfromcommacommand,
1853%D    commalistelement,
1854%D    getcommalistsize,getcommacommandsize}
1855%D
1856%D It's possible to get an element from a commalist or a command representing
1857%D a commalist.
1858%D
1859%D \starttyping
1860%D \getfromcommalist    [string] [n]
1861%D \getfromcommacommand [string,\strings,string,...] [n]
1862%D \stoptyping
1863%D
1864%D The difference betwee the two of them is the same as the difference between
1865%D \type {\processcomma...}. The found string is stored in \type
1866%D {\commalistelement}.
1867%D
1868%D We can calculate the size of a comma separated list by using:
1869%D
1870%D \starttyping
1871%D \getcommalistsize    [string,string,...]
1872%D \getcommacommandsize [string,\strings,string,...]
1873%D \stoptyping
1874%D
1875%D Afterwards, the length is available in the macro \type {\commalistsize}
1876%D (not a \COUNTER).
1877
1878\newinteger\commalistcounter
1879
1880\mutable\def\commalistsize{0}
1881
1882\def\syst_helpers_get_comma_list_size#0,% no #- as we need to count
1883  {\ifarguments\or
1884     \advanceby\commalistcounter\plusone
1885     \expandafter\syst_helpers_get_comma_list_size
1886   \fi}
1887
1888\permanent\protected\def\getcommalistsize[%
1889  {\futureexpand]\syst_helpers_get_comma_list_size_nop\syst_helpers_get_comma_list_size_yes}
1890
1891\def\syst_helpers_get_comma_list_size_yes#+]%
1892  {\commalistcounter\zerocount
1893   \syst_helpers_get_comma_list_size #1,\ignorearguments\ignorearguments
1894   \edef\commalistsize{\the\commalistcounter}}
1895
1896\def\syst_helpers_get_comma_list_size_nop]%
1897  {\commalistcounter\zerocount
1898   \let\commalistsize\!!zerocount}
1899
1900\permanent\protected\def\getcommacommandsize[#1]%
1901  {\normalexpanded{\getcommalistsize[#1]}}
1902
1903\permanent\def\getcommalistcount[#1]%
1904  {\beginlocalcontrol
1905   \getcommalistsize[#1]%
1906   \endlocalcontrol
1907   \the\commalistcounter}
1908
1909\permanent\def\getcommacommandcount[#1]%
1910  {\beginlocalcontrol
1911   \getcommacommandsize[#1]%
1912   \endlocalcontrol
1913   \the\commalistcounter}
1914
1915%D Filters:
1916
1917% \def\syst_helpers_gobble_comma_list#0\ignorearguments{}
1918
1919\def\syst_helpers_gobble_comma_list#-\ignorearguments{}
1920
1921\def\syst_helpers_get_from_comma_list#1,%
1922  {\ifarguments \or
1923     \advanceby\commalistcounter \minusone
1924     \ifcase\commalistcounter
1925       \def\commalistelement{#1}%
1926       \expandafter\expandafter\expandafter\syst_helpers_gobble_comma_list
1927     \else
1928       \expandafter\expandafter\expandafter\syst_helpers_get_from_comma_list_next
1929     \fi
1930   \fi}
1931
1932\def\syst_helpers_get_from_comma_list_next
1933  {\expandafterspaces\syst_helpers_get_from_comma_list}
1934
1935\permanent\protected\def\getfromcommalist[#1]#*[#2]%
1936  {\lettonothing\commalistelement
1937   \commalistcounter#2\relax
1938   \expandafterspaces\syst_helpers_get_from_comma_list#1\ignorearguments\ignorearguments}
1939
1940\permanent\protected\def\getfromcommacommand[#1]%
1941  {\normalexpanded{\getfromcommalist[#1]}}
1942
1943%D Watertight (and efficient) solutions are hard to find, due to the handling of
1944%D braces during parameters passing and scanning. Nevertheless:
1945%D
1946%D \startbuffer
1947%D \def\dosomething#1{(#1=\commalistsize) }
1948%D
1949%D \getcommalistsize [\hbox{$a,b,c,d,e,f$}] \dosomething 1
1950%D \getcommalistsize [{a,b,c,d,e,f}]        \dosomething 1
1951%D \getcommalistsize [{a,b,c},d,e,f]        \dosomething 4
1952%D \getcommalistsize [a,b,{c,d,e},f]        \dosomething 4
1953%D \getcommalistsize [a{b,c},d,e,f]         \dosomething 4
1954%D \getcommalistsize [{a,b}c,d,e,f]         \dosomething 4
1955%D \getcommalistsize []                     \dosomething 0
1956%D \getcommalistsize [{[}]                  \dosomething 1
1957%D \stopbuffer
1958%D
1959%D \typebuffer
1960%D
1961%D reports:
1962%D
1963%D \getbuffer
1964
1965%D \macros
1966%D   {dogetcommalistelement,dogetcommacommandelement}
1967%D
1968%D For low level (fast) purposes, we can also use the next alternative, which can
1969%D handle 9~elements at most.
1970%D
1971%D \starttyping
1972%D \dogetcommalistelement1\from a,b,c\to\commalistelement
1973%D \stoptyping
1974
1975\def\syst_helpers_get_comma_list_element#1,#2,#3,#4,#5,#6,#7,#8,#9,%
1976  {\ifcase\scratchcounter\or#1\or#2\or#3\or#4\or#5\or#6\or#7\or#8\or#9\fi
1977   \syst_helpers_gobble_comma_list}
1978
1979\permanent\protected\def\dogetcommacommandelement#1\from#2\to#3%
1980  {\scratchcounter#1\relax
1981   \edef#3{\normalexpanded{\syst_helpers_get_comma_list_element#2\ignorearguments\ignorearguments}}}
1982
1983%D \macros
1984%D   {dosingleargument,dodoubleargument,dotripleargument,
1985%D    doquadrupleargument,doquintupleargument,dosixtupleargument,
1986%D    doseventupleargument}
1987%D
1988%D When working with delimited arguments, spaces and lineendings can interfere. The
1989%D next set of macros uses \TEX' internal scanner for grabbing everything between
1990%D arguments. Forgive me the funny names.
1991%D
1992%D \starttyping
1993%D \dosingleargument    \command = \command[#1]
1994%D \dodoubleargument    \command = \command[#1][#2]
1995%D \dotripleargument    \command = \command[#1][#2][#3]
1996%D \doquadrupleargument \command = \command[#1][#2][#3][#4]
1997%D \doquintupleargument \command = \command[#1][#2][#3][#4][#5]
1998%D \dosixtupleargument  \command = \command[#1][#2][#3][#4][#5][#6]
1999%D \doseventupleargument\command = \command[#1][#2][#3][#4][#5][#6][#7]
2000%D \stoptyping
2001%D
2002%D These macros can be used in the following way:
2003%D
2004%D \starttyping
2005%D \def\dosetupsomething[#1][#2]%
2006%D   {... #1 ... #2 ...}
2007%D
2008%D \protected\def\setupsomething
2009%D   {\dodoubleargument\dosetupsomething}
2010%D \stoptyping
2011%D
2012%D The implementation can be surprisingly simple and needs no further explanation,
2013%D like:
2014%D
2015%D \starttyping
2016%D \def\dosingleargument#1[#2]%
2017%D   {#1[#2]}
2018%D \def\dotripleargument#1[#2]#3[#4]#5[#6]%
2019%D   {#1[#2][#4][#6]}
2020%D \def\doquintupleargument#1%
2021%D   {\def\dodoquintupleargument[##1]##2[##3]##4[##5]##6[##7]##8[##9]%
2022%D      {#1[##1][##3][##5][##7][##9]}%
2023%D    \dodoquintupleargument}
2024%D \stoptyping
2025%D
2026%D Because \TEX\ accepts 9~arguments at most, we have to use two||step solution when
2027%D getting five or more arguments.
2028%D
2029%D When developing more and more of the real \CONTEXT, we started using some
2030%D alternatives that provided empty arguments (in fact optional ones) whenever the
2031%D user failed to supply them. Because this more complicated macros enable us to do
2032%D some checking, we reimplemented the non||empty ones.
2033
2034%D \macros
2035%D   {iffirstagument,ifsecondargument,ifthirdargument,
2036%D    iffourthargument,iffifthargument,ifsixthargument,
2037%D    ifseventhargument}
2038%D
2039%D We use some signals for telling the calling macros if all wanted arguments are
2040%D indeed supplied by the user.
2041
2042\newinteger\nofarguments
2043
2044\newif\iffirstargument
2045\newif\ifsecondargument
2046\newif\ifthirdargument
2047\newif\iffourthargument
2048\newif\iffifthargument
2049\newif\ifsixthargument
2050\newif\ifseventhargument
2051
2052%D \macros
2053%D   {dosingleempty,dodoubleempty,dotripleempty,
2054%D    doquadrupleempty,doquintupleempty,dosixtupeempty,
2055%D    doseventupleempty}
2056%D
2057%D The empty argument supplying macros mentioned before, look like:
2058%D
2059%D \starttyping
2060%D \dosingleempty    \command
2061%D \dodoubleempty    \command
2062%D \dotripleempty    \command
2063%D \doquadrupleempty \command
2064%D \doquintupleempty \command
2065%D \dosixtuple_empty  \command
2066%D \doseventupleempty\command
2067%D \stoptyping
2068%D
2069%D So \type{\dodoubleempty} leads to:
2070%D
2071%D \starttyping
2072%D \command[#1][#2]
2073%D \command[#1][]
2074%D \command[][]
2075%D \stoptyping
2076%D
2077%D Depending of the generousity of the user. Afterwards one can use the \type
2078%D {\if...argument} boolean. For novice: watch the stepwise doubling of \type {#}'s.
2079
2080%D NB : experimental versions in cont-exp.mkiv
2081
2082%D Common:
2083
2084\newtoks\t_syst_aux
2085
2086% \def\syst_helpers_single_empty_one_yes      {\firstargumenttrue  \the\t_syst_aux}
2087% \def\syst_helpers_double_empty_two_yes      {\secondargumenttrue \the\t_syst_aux}
2088% \def\syst_helpers_triple_empty_three_yes    {\thirdargumenttrue  \the\t_syst_aux}
2089% \def\syst_helpers_quadruple_empty_four_yes  {\fourthargumenttrue \the\t_syst_aux}
2090% \def\syst_helpers_quintuple_empty_five_yes  {\fifthargumenttrue  \the\t_syst_aux}
2091% \def\syst_helpers_sixtuple_empty_six_yes    {\sixthargumenttrue  \the\t_syst_aux}
2092% \def\syst_helpers_seventuple_empty_seven_yes{\seventhargumenttrue\the\t_syst_aux}
2093%
2094% %D Single:
2095%
2096% \protected\def\dosingleempty#1%
2097%   {\t_syst_aux{#1}%
2098%    \futureexpand[\syst_helpers_single_empty_one_yes\syst_helpers_single_empty_one_nop}
2099%
2100% \def\syst_helpers_single_empty_one_nop
2101%   {\firstargumentfalse
2102%    \the\t_syst_aux[]}
2103%
2104% %D Double
2105%
2106% \protected\def\dodoubleempty#1%
2107%   {\t_syst_aux{#1}%
2108%    \futureexpand[\syst_helpers_double_empty_one_yes\syst_helpers_double_empty_one_nop}
2109%
2110% % \def\syst_helpers_double_empty_one_yes[#1]%
2111% %   {\firstargumenttrue
2112% %    \toksapp\t_syst_aux{[{#1}]}%
2113% %    \futureexpand[\syst_helpers_double_empty_two_yes\syst_helpers_double_empty_two_nop}
2114% %
2115% % nicer is:
2116%
2117% \def\syst_helpers_double_empty_one_yes[#+]%
2118%   {\firstargumenttrue
2119%    \toksapp\t_syst_aux{[#1]}%
2120%    \futureexpand[\syst_helpers_double_empty_two_yes\syst_helpers_double_empty_two_nop}
2121%
2122% \def\syst_helpers_double_empty_one_nop
2123%   {\firstargumentfalse
2124%    \secondargumentfalse
2125%    \the\t_syst_aux[][]}
2126%
2127% \def\syst_helpers_double_empty_two_nop
2128%   {\secondargumentfalse
2129%    \the\t_syst_aux[]}
2130%
2131% % Triple
2132%
2133% \protected\def\dotripleempty#1%
2134%   {\t_syst_aux{#1}%
2135%    \futureexpand[\syst_helpers_triple_empty_one_yes\syst_helpers_triple_empty_one_nop}
2136%
2137% \def\syst_helpers_triple_empty_one_yes[#+]%
2138%   {\firstargumenttrue
2139%    \toksapp\t_syst_aux{[#1]}%
2140%    \futureexpand[\syst_helpers_triple_empty_two_yes\syst_helpers_triple_empty_two_nop}
2141%
2142% \def\syst_helpers_triple_empty_two_yes[#+]%
2143%   {\secondargumenttrue
2144%    \toksapp\t_syst_aux{[#1]}%
2145%    \futureexpand[\syst_helpers_triple_empty_three_yes\syst_helpers_triple_empty_three_nop}
2146%
2147% \def\syst_helpers_triple_empty_one_nop
2148%   {\firstargumentfalse
2149%    \secondargumentfalse
2150%    \thirdargumentfalse
2151%    \the\t_syst_aux[][][]}
2152%
2153% \def\syst_helpers_triple_empty_two_nop
2154%   {\secondargumentfalse
2155%    \thirdargumentfalse
2156%    \the\t_syst_aux[][]}
2157%
2158% \def\syst_helpers_triple_empty_three_nop
2159%   {\thirdargumentfalse
2160%    \the\t_syst_aux[]}
2161%
2162% %D Quadruple:
2163%
2164% \protected\def\doquadrupleempty#1%
2165%   {\t_syst_aux{#1}%
2166%    \futureexpand[\syst_helpers_quadruple_empty_one_yes\syst_helpers_quadruple_empty_one_nop}
2167%
2168% \def\syst_helpers_quadruple_empty_one_yes[#+]%
2169%   {\firstargumenttrue
2170%    \toksapp\t_syst_aux{[#1]}%
2171%    \futureexpand[\syst_helpers_quadruple_empty_two_yes\syst_helpers_quadruple_empty_two_nop}
2172%
2173% \def\syst_helpers_quadruple_empty_two_yes[#+]%
2174%   {\secondargumenttrue
2175%    \toksapp\t_syst_aux{[#1]}%
2176%    \futureexpand[\syst_helpers_quadruple_empty_three_yes\syst_helpers_quadruple_empty_three_nop}
2177%
2178% \def\syst_helpers_quadruple_empty_three_yes[#+]%
2179%   {\thirdargumenttrue
2180%    \toksapp\t_syst_aux{[#1]}%
2181%    \futureexpand[\syst_helpers_quadruple_empty_four_yes\syst_helpers_quadruple_empty_four_nop}
2182%
2183% \def\syst_helpers_quadruple_empty_one_nop
2184%   {\firstargumentfalse
2185%    \secondargumentfalse
2186%    \thirdargumentfalse
2187%    \fourthargumentfalse
2188%    \the\t_syst_aux[][][][]}
2189%
2190% \def\syst_helpers_quadruple_empty_two_nop
2191%   {\secondargumentfalse
2192%    \thirdargumentfalse
2193%    \fourthargumentfalse
2194%    \the\t_syst_aux[][][]}
2195%
2196% \def\syst_helpers_quadruple_empty_three_nop
2197%   {\thirdargumentfalse
2198%    \fourthargumentfalse
2199%    \the\t_syst_aux[][]}
2200%
2201% \def\syst_helpers_quadruple_empty_four_nop
2202%   {\fourthargumentfalse
2203%    \the\t_syst_aux[]}
2204%
2205% %D Quintuple:
2206%
2207% \protected\def\doquintupleempty#1%
2208%   {\t_syst_aux{#1}%
2209%    \futureexpand[\syst_helpers_quintuple_empty_one_yes\syst_helpers_quintuple_empty_one_nop}
2210%
2211% \def\syst_helpers_quintuple_empty_one_yes[#+]%
2212%   {\firstargumenttrue
2213%    \toksapp\t_syst_aux{[#1]}%
2214%    \futureexpand[\syst_helpers_quintuple_empty_two_yes\syst_helpers_quintuple_empty_two_nop}
2215%
2216% \def\syst_helpers_quintuple_empty_two_yes[#+]%
2217%   {\secondargumenttrue
2218%    \toksapp\t_syst_aux{[#1]}%
2219%    \futureexpand[\syst_helpers_quintuple_empty_three_yes\syst_helpers_quintuple_empty_three_nop}
2220%
2221% \def\syst_helpers_quintuple_empty_three_yes[#+]%
2222%   {\thirdargumenttrue
2223%    \toksapp\t_syst_aux{[#1]}%
2224%    \futureexpand[\syst_helpers_quintuple_empty_four_yes\syst_helpers_quintuple_empty_four_nop}
2225%
2226% \def\syst_helpers_quintuple_empty_four_yes[#+]%
2227%   {\fourthargumenttrue
2228%    \toksapp\t_syst_aux{[#1]}%
2229%    \futureexpand[\syst_helpers_quintuple_empty_five_yes\syst_helpers_quintuple_empty_five_nop}
2230%
2231% \def\syst_helpers_quintuple_empty_one_nop
2232%   {\firstargumentfalse
2233%    \secondargumentfalse
2234%    \thirdargumentfalse
2235%    \fourthargumentfalse
2236%    \fifthargumentfalse
2237%    \the\t_syst_aux[][][][][]}
2238%
2239% \def\syst_helpers_quintuple_empty_two_nop
2240%   {\secondargumentfalse
2241%    \thirdargumentfalse
2242%    \fourthargumentfalse
2243%    \fifthargumentfalse
2244%    \the\t_syst_aux[][][][]}
2245%
2246% \def\syst_helpers_quintuple_empty_three_nop
2247%   {\thirdargumentfalse
2248%    \fourthargumentfalse
2249%    \fifthargumentfalse
2250%    \the\t_syst_aux[][][]}
2251%
2252% \def\syst_helpers_quintuple_empty_four_nop
2253%   {\fourthargumentfalse
2254%    \fifthargumentfalse
2255%    \the\t_syst_aux[][]}
2256%
2257% \def\syst_helpers_quintuple_empty_five_nop
2258%   {\fifthargumentfalse
2259%    \the\t_syst_aux[]}
2260%
2261% %D Sixtuple:
2262%
2263% \protected\def\dosixtupleempty#1%
2264%   {\t_syst_aux{#1}%
2265%    \futureexpand[\syst_helpers_sixtuple_empty_one_yes\syst_helpers_sixtuple_empty_one_nop}
2266%
2267% \def\syst_helpers_sixtuple_empty_one_yes[#+]%
2268%   {\firstargumenttrue
2269%    \toksapp\t_syst_aux{[#1]}%
2270%    \futureexpand[\syst_helpers_sixtuple_empty_two_yes\syst_helpers_sixtuple_empty_two_nop}
2271%
2272% \def\syst_helpers_sixtuple_empty_two_yes[#+]%
2273%   {\secondargumenttrue
2274%    \toksapp\t_syst_aux{[#1]}%
2275%    \futureexpand[\syst_helpers_sixtuple_empty_three_yes\syst_helpers_sixtuple_empty_three_nop}
2276%
2277% \def\syst_helpers_sixtuple_empty_three_yes[#+]%
2278%   {\thirdargumenttrue
2279%    \toksapp\t_syst_aux{[#1]}%
2280%    \futureexpand[\syst_helpers_sixtuple_empty_four_yes\syst_helpers_sixtuple_empty_four_nop}
2281%
2282% \def\syst_helpers_sixtuple_empty_four_yes[#+]%
2283%   {\fourthargumenttrue
2284%    \toksapp\t_syst_aux{[#1]}%
2285%    \futureexpand[\syst_helpers_sixtuple_empty_five_yes\syst_helpers_sixtuple_empty_five_nop}
2286%
2287% \def\syst_helpers_sixtuple_empty_five_yes[#+]%
2288%   {\fifthargumenttrue
2289%    \toksapp\t_syst_aux{[#1]}%
2290%    \futureexpand[\syst_helpers_sixtuple_empty_six_yes\syst_helpers_sixtuple_empty_six_nop}
2291%
2292% \def\syst_helpers_sixtuple_empty_one_nop
2293%   {\firstargumentfalse
2294%    \secondargumentfalse
2295%    \thirdargumentfalse
2296%    \fourthargumentfalse
2297%    \fifthargumentfalse
2298%    \sixthargumentfalse
2299%    \the\t_syst_aux[][][][][][]}
2300%
2301% \def\syst_helpers_sixtuple_empty_two_nop
2302%   {\secondargumentfalse
2303%    \thirdargumentfalse
2304%    \fourthargumentfalse
2305%    \fifthargumentfalse
2306%    \sixthargumentfalse
2307%    \the\t_syst_aux[][][][][]}
2308%
2309% \def\syst_helpers_sixtuple_empty_three_nop
2310%   {\thirdargumentfalse
2311%    \fourthargumentfalse
2312%    \fifthargumentfalse
2313%    \sixthargumentfalse
2314%    \the\t_syst_aux[][][][]}
2315%
2316% \def\syst_helpers_sixtuple_empty_four_nop
2317%   {\fourthargumentfalse
2318%    \fifthargumentfalse
2319%    \sixthargumentfalse
2320%    \the\t_syst_aux[][][]}
2321%
2322% \def\syst_helpers_sixtuple_empty_five_nop
2323%   {\fifthargumentfalse
2324%    \sixthargumentfalse
2325%    \the\t_syst_aux[][]}
2326%
2327% \def\syst_helpers_sixtuple_empty_six_nop
2328%   {\sixthargumentfalse
2329%    \the\t_syst_aux[]}
2330%
2331% %D Seventuple:
2332%
2333% \protected\def\doseventupleempty#1%
2334%   {\t_syst_aux{#1}%
2335%    \futureexpand[\syst_helpers_seventuple_empty_one_yes\syst_helpers_seventuple_empty_one_nop}
2336%
2337% \def\syst_helpers_seventuple_empty_one_yes[#+]%
2338%   {\firstargumenttrue
2339%    \toksapp\t_syst_aux{[#1]}%
2340%    \futureexpand[\syst_helpers_seventuple_empty_two_yes\syst_helpers_seventuple_empty_two_nop}
2341%
2342% \def\syst_helpers_seventuple_empty_two_yes[#+]%
2343%   {\secondargumenttrue
2344%    \toksapp\t_syst_aux{[#1]}%
2345%    \futureexpand[\syst_helpers_seventuple_empty_three_yes\syst_helpers_seventuple_empty_three_nop}
2346%
2347% \def\syst_helpers_seventuple_empty_three_yes[#+]%
2348%   {\thirdargumenttrue
2349%    \toksapp\t_syst_aux{[#1]}%
2350%    \futureexpand[\syst_helpers_seventuple_empty_four_yes\syst_helpers_seventuple_empty_four_nop}
2351%
2352% \def\syst_helpers_seventuple_empty_four_yes[#+]%
2353%   {\fourthargumenttrue
2354%    \toksapp\t_syst_aux{[#1]}%
2355%    \futureexpand[\syst_helpers_seventuple_empty_five_yes\syst_helpers_seventuple_empty_five_nop}
2356%
2357% \def\syst_helpers_seventuple_empty_five_yes[#+]%
2358%   {\fifthargumenttrue
2359%    \toksapp\t_syst_aux{[#1]}%
2360%    \futureexpand[\syst_helpers_seventuple_empty_six_yes\syst_helpers_seventuple_empty_six_nop}
2361%
2362% \def\syst_helpers_seventuple_empty_six_yes[#+]%
2363%   {\sixthargumenttrue
2364%    \toksapp\t_syst_aux{[#1]}%
2365%    \futureexpand[\syst_helpers_seventuple_empty_seven_yes\syst_helpers_seventuple_empty_seven_nop}
2366%
2367% \def\syst_helpers_seventuple_empty_one_nop
2368%   {\firstargumentfalse
2369%    \secondargumentfalse
2370%    \thirdargumentfalse
2371%    \fourthargumentfalse
2372%    \fifthargumentfalse
2373%    \sixthargumentfalse
2374%    \seventhargumentfalse
2375%    \the\t_syst_aux[][][][][][][]}
2376%
2377% \def\syst_helpers_seventuple_empty_two_nop
2378%   {\secondargumentfalse
2379%    \thirdargumentfalse
2380%    \fourthargumentfalse
2381%    \fifthargumentfalse
2382%    \sixthargumentfalse
2383%    \seventhargumentfalse
2384%    \the\t_syst_aux[][][][][][]}
2385%
2386% \def\syst_helpers_seventuple_empty_three_nop
2387%   {\thirdargumentfalse
2388%    \fourthargumentfalse
2389%    \fifthargumentfalse
2390%    \sixthargumentfalse
2391%    \seventhargumentfalse
2392%    \the\t_syst_aux[][][][][]}
2393%
2394% \def\syst_helpers_seventuple_empty_four_nop
2395%   {\fourthargumentfalse
2396%    \fifthargumentfalse
2397%    \sixthargumentfalse
2398%    \seventhargumentfalse
2399%    \the\t_syst_aux[][][][]}
2400%
2401% \def\syst_helpers_seventuple_empty_five_nop
2402%   {\fifthargumentfalse
2403%    \sixthargumentfalse
2404%    \seventhargumentfalse
2405%    \the\t_syst_aux[][][]}
2406%
2407% \def\syst_helpers_seventuple_empty_six_nop
2408%   {\sixthargumentfalse
2409%    \seventhargumentfalse
2410%    \the\t_syst_aux[][]}
2411%
2412% \def\syst_helpers_seventuple_empty_seven_nop
2413%   {\seventhargumentfalse
2414%    \the\t_syst_aux[]}
2415
2416\tolerant\def\syst_single_empty#1\relax[#S#2]%
2417  {\ifarguments
2418   \or\firstargumentfalse
2419   \or\firstargumenttrue
2420   \fi
2421   #1[#2]}
2422
2423\tolerant\def\syst_double_empty#1\relax[#S#+]#*[#S#+]%
2424  {\ifarguments
2425   \or\firstargumentfalse\secondargumentfalse
2426   \or\firstargumenttrue \secondargumentfalse
2427   \or\firstargumenttrue \secondargumenttrue
2428   \fi
2429   #1[#2][#3]}
2430
2431\tolerant\def\syst_triple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]%
2432  {\ifarguments
2433   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse
2434   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse
2435   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse
2436   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue
2437   \fi
2438   #1[#2][#3][#4]}
2439
2440\tolerant\def\syst_quadruple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]%
2441  {\ifarguments
2442   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse
2443   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse
2444   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse
2445   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse
2446   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue
2447   \fi
2448   #1[#2][#3][#4][#5]}
2449
2450\tolerant\def\syst_quintuple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]%
2451  {\ifarguments
2452   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
2453   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
2454   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
2455   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse\fifthargumentfalse
2456   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumentfalse
2457   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue
2458   \fi
2459   #1[#2][#3][#4][#5][#6]}
2460
2461\tolerant\def\syst_sixtuple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]%
2462  {\ifarguments
2463   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse
2464   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse
2465   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse
2466   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse\fifthargumentfalse\sixthargumentfalse
2467   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumentfalse\sixthargumentfalse
2468   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumentfalse
2469   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumenttrue
2470   \fi
2471   #1[#2][#3][#4][#5][#6][#7]}
2472
2473\tolerant\def\syst_seventuple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]%
2474  {\ifarguments
2475   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
2476   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
2477   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
2478   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse\fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
2479   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
2480   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumentfalse\seventhargumentfalse
2481   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumenttrue \seventhargumentfalse
2482   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumenttrue \seventhargumenttrue
2483   \fi
2484   #1[#2][#3][#4][#5][#6][#7][#8]}
2485
2486\permanent\protected\def\dosingleempty    #1{\syst_single_empty    #1\relax}
2487\permanent\protected\def\dodoubleempty    #1{\syst_double_empty    #1\relax}
2488\permanent\protected\def\dotripleempty    #1{\syst_triple_empty    #1\relax}
2489\permanent\protected\def\doquadrupleempty #1{\syst_quadruple_empty #1\relax}
2490\permanent\protected\def\doquintupleempty #1{\syst_quintuple_empty #1\relax}
2491\permanent\protected\def\dosixtupleempty  #1{\syst_sixtuple_empty  #1\relax}
2492\permanent\protected\def\doseventupleempty#1{\syst_seventuple_empty#1\relax}
2493
2494%D Aliases:
2495
2496\aliased\let\dosingleargument    \dosingleempty
2497\aliased\let\dodoubleargument    \dodoubleempty
2498\aliased\let\dotripleargument    \dotripleempty
2499\aliased\let\doquadrupleargument \doquadrupleempty
2500\aliased\let\doquintupleargument \doquintupleempty
2501\aliased\let\dosixtupleargument  \dosixtupleempty
2502\aliased\let\doseventupleargument\doseventupleempty
2503
2504%D \macros
2505%D   {strippedcsname}
2506%D
2507%D The next macro can be very useful when using \type{\csname} like in:
2508%D
2509%D \starttyping
2510%D \csname if\strippedcsname\something\endcsname
2511%D \stoptyping
2512%D
2513%D This expands to \type{\ifsomething}.
2514
2515\aliased\let\strippedcsname\csstring
2516
2517%D \macros
2518%D   {complexorsimple,complexorsimpleempty}
2519%D
2520%D Setups can be optional. A command expecting a setup is prefixed by \type
2521%D {\complex}, a command without one gets the prefix \type {\simple}. Commands like
2522%D this can be defined by:
2523%D
2524%D \starttyping
2525%D \complexorsimple\command
2526%D \stoptyping
2527%D
2528%D When \type{\command} is followed by a \type{[setup]}, then
2529%D
2530%D \starttyping
2531%D \complexcommand [setup]
2532%D \stoptyping
2533%D
2534%D executes, else we get
2535%D
2536%D \starttyping
2537%D \simplecommand
2538%D \stoptyping
2539%D
2540%D An alternative for \type{\complexorsimple} is:
2541%D
2542%D \starttyping
2543%D \complexorsimpleempty {command}
2544%D \stoptyping
2545%D
2546%D Depending on the presence of \type{[setup]}, this one leads to one of:
2547%D
2548%D \starttyping
2549%D \complexcommando [setup]
2550%D \complexcommando []
2551%D \stoptyping
2552%D
2553%D Many \CONTEXT\ commands started as complex or simple ones, but changed into more
2554%D versatile (more object oriented) ones using the \type {\get..argument} commands.
2555
2556\permanent\protected\def\complexorsimple#1%
2557  {\doifelsenextoptional
2558     {\firstargumenttrue \csname\s!complex\csstring#1\endcsname}
2559     {\firstargumentfalse\csname\s!simple \csstring#1\endcsname}}
2560
2561\permanent\protected\def\complexorsimpleempty#1%
2562  {\doifelsenextoptional
2563     {\firstargumenttrue \csname\s!complex\csstring#1\endcsname}
2564     {\firstargumentfalse\csname\s!complex\csstring#1\endcsname[]}}
2565
2566%D \macros
2567%D   {definecomplexorsimple,definecomplexorsimpleempty}
2568%D
2569%D The previous commands are used that often that we found it worthwile to offer two
2570%D more alternatives. Watch the build in protection.
2571
2572\protected\def\syst_helpers_complex_or_simple#1#2%
2573  {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#2}}
2574
2575\protected\def\syst_helpers_complex_or_simple_empty#1%
2576  {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#1[]}}
2577
2578\permanent\protected\def\definecomplexorsimple#1%
2579  {\protected\edef#1{\syst_helpers_complex_or_simple
2580     \expandafter\noexpand\csname\s!complex\csstring#1\endcsname
2581     \expandafter\noexpand\csname\s!simple \csstring#1\endcsname}}
2582
2583\permanent\protected\def\definecomplexorsimpleempty#1%
2584  {\protected\edef#1{\syst_helpers_complex_or_simple_empty
2585     \expandafter\noexpand\csname\s!complex\csstring#1\endcsname}}
2586
2587%D These commands are called as:
2588%D
2589%D \starttyping
2590%D \definecomplexorsimple\command
2591%D \stoptyping
2592%D
2593%D Of course, we must have available
2594%D
2595%D \starttyping
2596%D \def\complexcommand[#1]{...}
2597%D \def\simplecommand     {...}
2598%D \stoptyping
2599%D
2600%D Using this construction saves a few string now and then.
2601
2602%D \macros
2603%D   {dosinglegroupempty,dodoublegroupempty,dotriplegroupempty,
2604%D    doquadruplegroupempty, doquintuplegroupempty}
2605%D
2606%D We've already seen some commands that take care of
2607%D optional arguments between \type{[]}. The next two commands
2608%D handle the ones with \type{{}}. They are called as:
2609%D
2610%D \starttyping
2611%D \dosinglegroupempty    \ineedONEargument
2612%D \dodoublegroupempty    \ineedTWOarguments
2613%D \dotriplegroupempty    \ineedTHREEarguments
2614%D \doquadruplegroupempty \ineedFOURarguments
2615%D \doquintuplegroupempty \ineedFIVEarguments
2616%D \stoptyping
2617%D
2618%D We can add additional definitions later when we have defined \type {\appendtoks}.
2619
2620\newconditional\c_syst_helpers_permit_spaces_between_groups
2621
2622\permanent\protected\def    \permitspacesbetweengroups{\c_syst_helpers_permit_spaces_between_groups\conditionaltrue}
2623\permanent\protected\def\dontpermitspacesbetweengroups{\c_syst_helpers_permit_spaces_between_groups\conditionalfalse}
2624
2625\dontpermitspacesbetweengroups
2626
2627%D We can avoid the nasty if handling in \type {syst-gen} by splitting the lot in
2628%D pieces so that we have no nested \type {\nextarguments} potentially being an
2629%D \type {conditional} token. Okay, these macros are not called that often but it
2630%D saves crap when tracing.
2631
2632% \protected\def\dosinglegroupempty#1%
2633%   {\t_syst_aux{#1}%
2634%    \futureexpand\bgroup\syst_helpers_single_empty_one_yes\syst_helpers_single_group_empty_one_nop}
2635%
2636% \def\syst_helpers_single_group_empty_one_nop
2637%   {\firstargumentfalse
2638%    \the\t_syst_aux{}}
2639%
2640% \protected\def\dodoublegroupempty#1%
2641%   {\t_syst_aux{#1}%
2642%    \futureexpand\bgroup\syst_helpers_group_double_empty_one_yes\syst_helpers_group_double_empty_one_nop}
2643%
2644% % \def\syst_helpers_group_double_empty_one_yes#1%
2645% %   {\firstargumenttrue
2646% %    \toksapp\t_syst_aux{{#1}}%
2647% %    \futureexpand\bgroup\syst_helpers_double_empty_two_yes\syst_helpers_group_double_empty_two_nop}
2648% %
2649% % nicer is:
2650%
2651% \def\syst_helpers_group_double_empty_one_yes#+%
2652%   {\firstargumenttrue
2653%    \toksapp\t_syst_aux{#1}%
2654%    \futureexpand\bgroup\syst_helpers_double_empty_two_yes\syst_helpers_group_double_empty_two_nop}
2655%
2656% \def\syst_helpers_group_double_empty_one_nop
2657%   {\firstargumentfalse
2658%    \secondargumentfalse
2659%    \the\t_syst_aux{}{}}
2660%
2661% \def\syst_helpers_group_double_empty_two_nop
2662%   {\secondargumentfalse
2663%    \the\t_syst_aux{}}
2664%
2665% \protected\def\dotriplegroupempty#1%
2666%   {\t_syst_aux{#1}%
2667%    \futureexpand\bgroup\syst_helpers_group_triple_empty_one_yes\syst_helpers_group_triple_empty_one_nop}
2668%
2669% \def\syst_helpers_group_triple_empty_one_yes#+%
2670%   {\firstargumenttrue
2671%    \toksapp\t_syst_aux{#1}%
2672%    \futureexpand\bgroup\syst_helpers_group_triple_empty_two_yes\syst_helpers_group_triple_empty_two_nop}
2673%
2674% \def\syst_helpers_group_triple_empty_two_yes#+%
2675%   {\secondargumenttrue
2676%    \toksapp\t_syst_aux{#1}%
2677%    \futureexpand\bgroup\syst_helpers_triple_empty_three_yes\syst_helpers_group_triple_empty_three_nop}
2678%
2679% \def\syst_helpers_group_triple_empty_one_nop
2680%   {\firstargumentfalse
2681%    \secondargumentfalse
2682%    \thirdargumentfalse
2683%    \the\t_syst_aux{}{}{}}
2684%
2685% \def\syst_helpers_group_triple_empty_two_nop
2686%   {\secondargumentfalse
2687%    \thirdargumentfalse
2688%    \the\t_syst_aux{}{}}
2689%
2690% \def\syst_helpers_group_triple_empty_three_nop
2691%   {\thirdargumentfalse
2692%    \the\t_syst_aux{}}
2693%
2694% \protected\def\doquadruplegroupempty#1%
2695%   {\t_syst_aux{#1}%
2696%    \futureexpand\bgroup\syst_helpers_group_quadruple_empty_one_yes\syst_helpers_group_quadruple_empty_one_nop}
2697%
2698% \def\syst_helpers_group_quadruple_empty_one_yes#+%
2699%   {\firstargumenttrue
2700%    \toksapp\t_syst_aux{#1}%
2701%    \futureexpand\bgroup\syst_helpers_group_quadruple_empty_two_yes\syst_helpers_group_quadruple_empty_two_nop}
2702%
2703% \def\syst_helpers_group_quadruple_empty_two_yes#+%
2704%   {\secondargumenttrue
2705%    \toksapp\t_syst_aux{#1}%
2706%    \futureexpand\bgroup\syst_helpers_group_quadruple_empty_three_yes\syst_helpers_group_quadruple_empty_three_nop}
2707%
2708% \def\syst_helpers_group_quadruple_empty_three_yes#+%
2709%   {\thirdargumenttrue
2710%    \toksapp\t_syst_aux{#1}%
2711%    \futureexpand\bgroup\syst_helpers_quadruple_empty_four_yes\syst_helpers_group_quadruple_empty_four_nop}
2712%
2713% \def\syst_helpers_group_quadruple_empty_one_nop
2714%   {\firstargumentfalse
2715%    \secondargumentfalse
2716%    \thirdargumentfalse
2717%    \fourthargumentfalse
2718%    \the\t_syst_aux{}{}{}{}}
2719%
2720% \def\syst_helpers_group_quadruple_empty_two_nop
2721%   {\secondargumentfalse
2722%    \thirdargumentfalse
2723%    \fourthargumentfalse
2724%    \the\t_syst_aux{}{}{}}
2725%
2726% \def\syst_helpers_group_quadruple_empty_three_nop
2727%   {\thirdargumentfalse
2728%    \fourthargumentfalse
2729%    \the\t_syst_aux{}{}}
2730%
2731% \def\syst_helpers_group_quadruple_empty_four_nop
2732%   {\fourthargumentfalse
2733%    \the\t_syst_aux{}}
2734%
2735% \protected\def\doquintuplegroupempty#1%
2736%   {\t_syst_aux{#1}%
2737%    \futureexpand\bgroup\syst_helpers_group_quintuple_empty_one_yes\syst_helpers_group_quintuple_empty_one_nop}
2738%
2739% \def\syst_helpers_group_quintuple_empty_one_yes#+%
2740%   {\firstargumenttrue
2741%    \toksapp\t_syst_aux{#1}%
2742%    \futureexpand\bgroup\syst_helpers_group_quintuple_empty_two_yes\syst_helpers_group_quintuple_empty_two_nop}
2743%
2744% \def\syst_helpers_group_quintuple_empty_two_yes#+%
2745%   {\secondargumenttrue
2746%    \toksapp\t_syst_aux{#1}%
2747%    \futureexpand\bgroup\syst_helpers_group_quintuple_empty_three_yes\syst_helpers_group_quintuple_empty_three_nop}
2748%
2749% \def\syst_helpers_group_quintuple_empty_three_yes#+%
2750%   {\thirdargumenttrue
2751%    \toksapp\t_syst_aux{#1}%
2752%    \futureexpand\bgroup\syst_helpers_group_quintuple_empty_four_yes\syst_helpers_group_quintuple_empty_four_nop}
2753%
2754% \def\syst_helpers_group_quintuple_empty_four_yes#+%
2755%   {\fourthargumenttrue
2756%    \toksapp\t_syst_aux{#1}%
2757%    \futureexpand\bgroup\syst_helpers_quintuple_empty_five_yes\syst_helpers_group_quintuple_empty_five_nop}
2758%
2759% \def\syst_helpers_group_quintuple_empty_one_nop
2760%   {\firstargumentfalse
2761%    \secondargumentfalse
2762%    \thirdargumentfalse
2763%    \fourthargumentfalse
2764%    \fifthargumentfalse
2765%    \the\t_syst_aux{}{}{}{}{}}
2766%
2767% \def\syst_helpers_group_quintuple_empty_two_nop
2768%   {\secondargumentfalse
2769%    \thirdargumentfalse
2770%    \fourthargumentfalse
2771%    \fifthargumentfalse
2772%    \the\t_syst_aux{}{}{}{}}
2773%
2774% \def\syst_helpers_group_quintuple_empty_three_nop
2775%   {\thirdargumentfalse
2776%    \fourthargumentfalse
2777%    \fifthargumentfalse
2778%    \the\t_syst_aux{}{}{}}
2779%
2780% \def\syst_helpers_group_quintuple_empty_four_nop
2781%   {\fourthargumentfalse
2782%    \fifthargumentfalse
2783%    \the\t_syst_aux{}{}}
2784%
2785% \def\syst_helpers_group_quintuple_empty_five_nop
2786%   {\fifthargumentfalse
2787%    \the\t_syst_aux{}}
2788
2789\tolerant\def\syst_single_group_empty#1\relax#_%
2790  {\ifarguments
2791   \or\firstargumentfalse
2792   \or\firstargumenttrue
2793   \fi
2794   #1#2}
2795
2796\tolerant\def\syst_double_group_empty#1\relax#_#*#_%
2797  {\ifarguments
2798   \or\firstargumentfalse\secondargumentfalse
2799   \or\firstargumenttrue \secondargumentfalse
2800   \or\firstargumenttrue \secondargumenttrue
2801   \fi
2802   #1#2#3}
2803
2804\tolerant\def\syst_triple_group_empty#1\relax#_#*#_#*#_%
2805  {\ifarguments
2806   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse
2807   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse
2808   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse
2809   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue
2810   \fi
2811   #1#2#3#4}
2812
2813\tolerant\def\syst_quadruple_group_empty#1\relax#_#*#_#*#_#*#_%
2814  {\ifarguments
2815   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse
2816   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse
2817   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse
2818   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse
2819   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue
2820   \fi
2821   #1#2#3#4#5}
2822
2823\tolerant\def\syst_quintuple_group_empty#1\relax#_#*#_#*#_#*#_#*#_%
2824  {\ifarguments
2825   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
2826   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
2827   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
2828   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse\fifthargumentfalse
2829   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumentfalse
2830   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue
2831   \fi
2832   #1#2#3#4#5#6}
2833
2834\permanent\protected\def\dosinglegroupempty    #1{\syst_single_group_empty    #1\relax}
2835\permanent\protected\def\dodoublegroupempty    #1{\syst_double_group_empty    #1\relax}
2836\permanent\protected\def\dotriplegroupempty    #1{\syst_triple_group_empty    #1\relax}
2837\permanent\protected\def\doquadruplegroupempty #1{\syst_quadruple_group_empty #1\relax}
2838\permanent\protected\def\doquintuplegroupempty #1{\syst_quintuple_group_empty #1\relax}
2839
2840%D These macros can explictly take care of spaces, which means that the next
2841%D definition and calls are valid:
2842%D
2843%D \starttyping
2844%D \def\test#1#2#3{[#1#2#3]}
2845%D
2846%D \dotriplegroupempty\test {a}{b}{c}
2847%D \dotriplegroupempty\test {a}{b}
2848%D \dotriplegroupempty\test {a}
2849%D \dotriplegroupempty\test
2850%D \dotriplegroupempty\test {a} {b} {c}
2851%D \dotriplegroupempty\test {a} {b}
2852%D \dotriplegroupempty\test
2853%D   {a}
2854%D   {b}
2855%D \stoptyping
2856%D
2857%D And alike.
2858
2859%D \macros
2860%D   {firstofoneargument, firstoftwoarguments, firstofthreearguments
2861%D    secondoftwoarguments, secondofthreearguments,
2862%D    thirdofthreearguments}
2863%D
2864%D The next six macros (dedicated to Taco) can conveniently used to select
2865%D arguments. Their names explain their functionality.
2866
2867\permanent\def\firstofoneargument            #1{#1}
2868
2869\permanent\def\firstoftwoarguments         #1#-{#1}
2870\permanent\def\secondoftwoarguments        #-#1{#1}
2871
2872\permanent\def\firstofthreearguments     #1#-#-{#1}
2873\permanent\def\secondofthreearguments    #-#1#-{#1}
2874\permanent\def\thirdofthreearguments     #-#-#1{#1}
2875
2876\permanent\def\firstoffourarguments    #1#-#-#-{#1}
2877\permanent\def\secondoffourarguments   #-#1#-#-{#1}
2878\permanent\def\thirdoffourarguments    #-#-#1#-{#1}
2879\permanent\def\fourthoffourarguments   #-#-#-#1{#1}
2880
2881\permanent\def\firstoffivearguments  #1#-#-#-#-{#1}
2882\permanent\def\secondoffivearguments #-#1#-#-#-{#1}
2883\permanent\def\thirdoffivearguments  #-#-#1#-#-{#1}
2884\permanent\def\fourthoffivearguments #-#-#-#1#-{#1}
2885\permanent\def\fifthoffivearguments  #-#-#-#-#1{#1}
2886
2887\permanent\def\firstofsixarguments #1#-#-#-#-#-{#1}
2888\permanent\def\secondofsixarguments#-#1#-#-#-#-{#1}
2889\permanent\def\thirdofsixarguments #-#-#1#-#-#-{#1}
2890\permanent\def\fourthofsixarguments#-#-#-#1#-#-{#1}
2891\permanent\def\fifthofsixarguments #-#-#-#-#1#-{#1}
2892\permanent\def\sixthofsixarguments #-#-#-#-#-#1{#1}
2893
2894\permanent\protected\def\firstofoneunexpanded       #1{#1}
2895
2896\permanent\protected\def\firstoftwounexpanded     #1#-{#1}
2897\permanent\protected\def\secondoftwounexpanded    #-#1{#1}
2898
2899\permanent\protected\def\firstofthreeunexpanded #1#-#-{#1}
2900\permanent\protected\def\secondofthreeunexpanded#-#1#-{#1}
2901\permanent\protected\def\thirdofthreeunexpanded #-#-#1{#1}
2902
2903%D \macros
2904%D   {globalletempty,letempty,
2905%D    letvalueempty,letgvalueempty,
2906%D    letvaluerelax,letgvaluerelax}
2907%D
2908%D Trivial:
2909
2910\permanent\protected\def\letempty      #1{\lettonothing #1}
2911\permanent\protected\def\globalletempty#1{\glettonothing#1}
2912
2913\permanent\protected\def\letvalueempty #1{\letcsname #1\endcsname\empty}
2914\permanent\protected\def\letgvalueempty#1{\gletcsname#1\endcsname\empty}
2915\permanent\protected\def\letvaluerelax #1{\letcsname #1\endcsname\relax}
2916\permanent\protected\def\letgvaluerelax#1{\gletcsname#1\endcsname\relax}
2917
2918\permanent\protected\def\relaxvalueifundefined#1%
2919  {\ifcsname#1\endcsname \else
2920     \aliased\letcsname#1\endcsname\relax
2921   \fi}
2922
2923%D \macros
2924%D   {wait}
2925%D
2926%D The next macro hardly needs explanation. Because no nesting is to be expected, we
2927%D can reuse \type {\wait} within \type {\wait} itself.
2928
2929\permanent\protected\def\wait
2930  {\begingroup
2931   \read16 to \wait
2932   \endgroup}
2933
2934% %D \macros
2935% %D   {writestring,writeline,writestatus}
2936% %D
2937% %D Maybe one didn't notice, but we've already introduced a macro for showing
2938% %D messages. In the multi||lingual modules, we will also introduce a mechanism for
2939% %D message passing. For the moment we stick to the core macros:
2940% %D
2941% %D \starttyping
2942% %D \writestring {string}
2943% %D \writeline
2944% %D \writestatus {category} {message}
2945% %D \stoptyping
2946% %D
2947% %D Messages are formatted. One can provide the maximum with of the identification
2948% %D string with the macro \type {\statuswidth}.
2949%
2950% \setnewconstant\statuswidth  15
2951% \setnewconstant\statuswrite 128 % \pluscxxviii
2952%
2953% \ifdefined\writestring \else
2954%
2955%     \protected\def\writestring{\immediate\write\statuswrite}
2956%     \protected\def\writeline  {\writestring{}}
2957%
2958% \fi
2959%
2960% \protected\def\normalwritestatus#1#2%
2961%   {\writestring{\expandafter\syst_helpers_split_status_yes\expandafter\statuswidth#1%
2962%      \space\space\space\space\space\space\space
2963%      \space\space\space\space\space\space\space
2964%      \space\space\space\space\space\space\end
2965%      \space:\space#2}}
2966%
2967% \def\syst_helpers_split_status_yes#1#2%
2968%   {\ifcase#1 \expandafter\syst_helpers_split_status_nop\fi#2%
2969%    \expandafter\syst_helpers_split_status_yes\expandafter{\the\numexpr#1+\minusone\relax}}
2970%
2971% \def\syst_helpers_split_status_nop#1\end
2972%   {}
2973
2974%D \macros
2975%D   {immediatemessage}
2976%D
2977%D A fully expandable message:
2978
2979% \immediatemessage % {} mandate / defined at the lua end
2980
2981%D \macros
2982%D   {rawgetparameters}
2983%D
2984%D A raw and dirty alternative for \type {\getparameters}; no checking is done!
2985
2986\def\syst_helpers_grab_raw_parameter#1=#2,%
2987  {\ifarguments\or\or
2988     \defcsname\m_syst_parameter_n#1\endcsname{#2}%
2989     \expandafter\syst_helpers_grab_raw_parameter_next
2990   \fi}
2991
2992\def\syst_helpers_grab_raw_parameter_next
2993  {\expandafterspaces\syst_helpers_grab_raw_parameter}
2994
2995\permanent\protected\def\rawgetparameters#1[#2]#*[#3]%
2996  {\def\m_syst_parameter_n{#2}%
2997  %\expandafterspaces\syst_helpers_grab_raw_parameter#3\ignorearguments\ignorearguments}
2998   \expandafter\expandafterspaces\expandafter\syst_helpers_grab_raw_parameter#3\ignorearguments\ignorearguments}
2999
3000%D \macros
3001%D   {doglobal,
3002%D    redoglobal,dodoglobal,resetglobal}
3003%D
3004%D The two macros \type {\redoglobal} and \type{\dodoglobal} are used in this and
3005%D some other modules to enforce a user specified \type {\doglobal} action. The last
3006%D and often only global assignment in a macro is done with \type {\dodoglobal}, but
3007%D all preceding ones with \type {\redoglobal}. When using only alternatives, one
3008%D can reset this mechanism with \type {\resetglobal}.
3009
3010\permanent\protected\def\resetglobal
3011  {\enforced\let\redoglobal\relax
3012   \enforced\let\dodoglobal\relax}
3013
3014\resetglobal
3015
3016\permanent\protected\def\doglobal
3017  {\ifrelax\redoglobal
3018     \enforced\let\redoglobal\global
3019     \enforced\let\dodoglobal\syst_helpers_dodo_global
3020   \fi}
3021
3022\def\syst_helpers_dodo_global
3023  {\resetglobal\global}
3024
3025\let\syst_helpers_redo_global\relax
3026
3027\permanent\protected\def\saveglobal
3028  {\let\syst_helpers_dodo_global\dodoglobal
3029   \let\syst_helpers_redo_global\redoglobal}
3030
3031\permanent\protected\def\restoreglobal
3032  {\enforced\let\redoglobal\syst_helpers_redo_global
3033   \enforced\let\dodoglobal\syst_helpers_dodo_global}
3034
3035% Maybe:
3036%
3037% \installmacrostack\globaldefs
3038%
3039% \protected\def\start_global
3040%   {\push_macro_globaldefs
3041%    \globaldefs\plusone}
3042%
3043% \protected\def\stop_global
3044%   {\pop_macro_globaldefs}
3045
3046%D Whatever (will be overloaded):
3047
3048\protected\def\define#1%
3049  {\ifdefined#1%
3050     \message{[\noexpand#1is already defined]}%
3051     \protected\expandafter\def\expandafter\gobbleddefinition
3052   \else
3053     \protected\expandafter\def
3054   \fi#1}
3055
3056\protected\def\redefine#1%
3057  {\ifdefined#1%
3058     \message{[\noexpand#1is redefined]}%
3059   \fi
3060   \protected\def#1}
3061
3062% \permanent\protected\def\definemacro#1%
3063%   {\ifdefined#1%
3064%      \message{[\noexpand#1is already defined]}%
3065%      \protected\expandafter\def\expandafter\gobbleddefinition
3066%    \else
3067%      \protected\expandafter\def
3068%    \fi#1}
3069
3070% \define\hans{hans}
3071% \redefine\hans{hans}
3072% \define\hans#1[]#2#3{hans}
3073
3074%D The next variant fits nicely in the setups syntax:
3075%D
3076%D \starttyping
3077%D \starttexdefinition bagger [#1] #2
3078%D     oeps
3079%D     #1
3080%D     oeps
3081%D \stoptexdefinition
3082%D
3083%D \bagger [a] {b}
3084%D \stoptyping
3085
3086% \starttexdefinition test
3087% oeps
3088% \stoptexdefinition
3089%
3090% [\test]
3091
3092%D When okay the parameter hack will also go into \MKIV.
3093
3094\integerdef\c_syst_parameter_catcode\parametercatcode
3095
3096% \catcode\endoflineasciicode\activecatcode\letcharcode\endoflineasciicode\par
3097
3098\bgroup
3099
3100\catcode\endoflineasciicode\activecatcode%
3101\letcharcode\endoflineasciicode\par%
3102
3103\permanent\protected\gdef\starttexdefinition%
3104  {\integerdef\c_syst_parameter_catcode\catcode\hashasciicode%
3105   \catcode\hashasciicode\parametercatcode%
3106   \bgroup%
3107   \catcode\endoflineasciicode\activecatcode%
3108   \letcharcode\endoflineasciicode\par%
3109   \syst_helpers_start_tex_definition}
3110
3111\gdef\syst_helpers_start_tex_definition#1
3112  {%catcodetable\ctxcatcodes% can be adapted
3113   \catcode\endoflineasciicode\ignorecatcode%
3114   \clf_texdefinition_one{#1}}
3115
3116\permanent\protected\glettonothing\stoptexdefinition
3117
3118\permanent\gdef\dostarttexdefinition#1\stoptexdefinition%
3119  {\egroup%
3120   \clf_texdefinition_two{#1}%
3121   \catcode\hashasciicode\c_syst_parameter_catcode}
3122
3123\egroup
3124
3125% \protected\def\texdefinition#1{\csname\ifcsname#1\endcsname#1\else donothing\fi\endcsname} % todo: a nop cs: char 0 or some corenamespace
3126
3127\permanent\protected\def\texdefinition#1{\begincsname#1\endcsname}
3128
3129%D \macros
3130%D   {newcounter,
3131%D    increment,decrement}
3132%D
3133%D Unfortunately the number of \COUNTERS\ in \TEX\ is limited, but fortunately we
3134%D can store numbers in a macro. We can increment such pseudo \COUNTERS\ with \type
3135%D {\increment}.
3136%D
3137%D \starttyping
3138%D \increment(\counter,20)
3139%D \increment(\counter,-4)
3140%D \increment(\counter)
3141%D \increment\counter
3142%D \stoptyping
3143%D
3144%D After this sequence of commands, the value of \type {\counter} is 20, 16, 17
3145%D and~18. Of course there is also the complementary command \type {\decrement}.
3146%D
3147%D Global assignments are possible too, using \type{\doglobal}:
3148%D
3149%D \starttyping
3150%D \doglobal\increment\counter
3151%D \stoptyping
3152%D
3153%D When \type {\counter} is undefined, it's value is initialized at~0. It is
3154%D nevertheless better to define a \COUNTER\ explicitly. One reason could be that
3155%D the \COUNTER\ can be part of a test with \type {\ifnum} and this conditional does
3156%D not accept undefined macro's. The \COUNTER\ in our example can for instance be
3157%D defined with:
3158%D
3159%D \starttyping
3160%D \newcounter\counter
3161%D \stoptyping
3162%D
3163%D The command \type {\newcounter} must not be confused with \type {\newcount}! Of
3164%D course this mechanism is much slower than using \TEX's \COUNTERS\ directly. In
3165%D practice \COUNTERS\ (and therefore our pseudo counters too) are seldom the
3166%D bottleneck in the processing of a text. Apart from some other incompatilities we
3167%D want to mention a pitfal when using \type {\ifnum}.
3168%D
3169%D \starttyping
3170%D \ifnum\normalcounter=\pseudocounter \doif \else \doelse \fi
3171%D \ifnum\pseudocounter=\normalcounter \doif \else \doelse \fi
3172%D \stoptyping
3173%D
3174%D In the first test, \TEX\ continues it's search for the second number after
3175%D reading \type {\pseudocounter}, while in the second test, it stops reading after
3176%D having encountered a real one. Tests like the first one therefore can give
3177%D unexpected results, for instance execution of \type {\doif} even if both numbers
3178%D are unequal.
3179
3180\immutable\def\zerocountervalue{0}
3181
3182\permanent\protected\def\newcounter#1%
3183  {\dodoglobal\let#1\zerocountervalue}
3184
3185%D Nowadays we don't mind a few more tokens if we can gain a bit of speed.
3186
3187\def\syst_helpers_do_increment#1{\dodoglobal\edef#1{\tointeger{\ifdefined#1\ifrelax#1\else#1\fi\fi+\plusone }}}
3188\def\syst_helpers_do_decrement#1{\dodoglobal\edef#1{\tointeger{\ifdefined#1\ifrelax#1\else#1\fi\fi+\minusone}}}
3189
3190\def\syst_helpers_do_do_do_increment#1,#2){\dodoglobal\edef#1{\tointeger{\ifdefined#1\ifrelax#1\else#1\fi\fi+#2}}}
3191\def\syst_helpers_do_do_do_decrement#1,#2){\dodoglobal\edef#1{\tointeger{\ifdefined#1\ifrelax#1\else#1\fi\fi-#2}}}
3192
3193\def\syst_helpers_do_do_increment(#1%
3194  {\def\m_syst_action_yes{\syst_helpers_do_do_do_increment#1}%
3195   \def\m_syst_action_nop{\syst_helpers_do_do_do_increment#1,\plusone}%
3196   \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop}
3197
3198\def\syst_helpers_do_do_decrement(#1%
3199  {\def\m_syst_action_yes{\syst_helpers_do_do_do_decrement#1}%
3200   \def\m_syst_action_nop{\syst_helpers_do_do_do_decrement#1,\plusone}%
3201   \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop}
3202
3203\permanent\protected\def\increment{\doifelsenextcharcs(\syst_helpers_do_do_increment\syst_helpers_do_increment}
3204\permanent\protected\def\decrement{\doifelsenextcharcs(\syst_helpers_do_do_decrement\syst_helpers_do_decrement}
3205
3206\permanent\protected\def\fastincrement#1{\dodoglobal\edef#1{\tointeger{#1+\plusone }}}
3207\permanent\protected\def\fastdecrement#1{\dodoglobal\edef#1{\tointeger{#1+\minusone}}}
3208
3209\permanent\protected\def\incrementvalue#1{\expandafter\increment\csname#1\endcsname}
3210\permanent\protected\def\decrementvalue#1{\expandafter\decrement\csname#1\endcsname}
3211
3212%D \macros
3213%D  {newsignal}
3214%D
3215%D When writing advanced macros, we cannot do without signaling. A signal is a small
3216%D (invisible) kern or penalty that signals the next macro that something just
3217%D happened. This macro can take any action depending on the previous signal.
3218%D Signals must be unique and the next macro takes care of that.
3219%D
3220%D \starttyping
3221%D \newsignal\somesignal
3222%D \stoptyping
3223%D
3224%D Signals old dimensions and can be used in skips, kerns and tests like \type
3225%D {\ifdim}.
3226
3227\newdimension\d_syst_maximum_signal % step is about 0.00025pt
3228
3229\permanent\protected\def\newsignal#1%
3230  {\ifdefined#1\else
3231     \advanceby\d_syst_maximum_signal2\scaledpoint % to be save in rounding
3232     \immutable\dimensiondef#1\d_syst_maximum_signal
3233   \fi}
3234
3235%D \macros
3236%D   {strippedcsname}
3237%D
3238%D The next macro can be very useful when using \type {\csname} like in:
3239%D
3240%D \starttyping
3241%D \csname if\strippedcsname\something\endcsname
3242%D \stoptyping
3243
3244\aliased\let\checkedstrippedcsname\csstring
3245
3246%D \macros
3247%D   {savenormalmeaning}
3248%D
3249%D We will use this one in:
3250
3251\permanent\protected\def\savenormalmeaning#1%
3252  {\ifcsname normal\csstring#1\endcsname \else
3253     \aliased\letcsname normal\csstring#1\endcsname#1%
3254   \fi}
3255
3256%D \macros
3257%D   {dorecurse,recurselevel,recursedepth,
3258%D    dostepwiserecurse}
3259%D
3260%D \TEX\ does not offer us powerfull for||loop mechanisms. On the other hand its
3261%D recursion engine is quite unique. We therefore identify the for||looping macros
3262%D by this method. The most simple alternative is the one that only needs a number.
3263%D
3264%D \starttyping
3265%D \dorecurse {n} {whatever we want}
3266%D \stoptyping
3267%D
3268%D This macro can be nested without problems and therefore be used in situations
3269%D where \PLAIN\ \TEX's \type {\loop} macro ungracefully fails. The current value of
3270%D the counter is available in \type {\recurselevel}, before as well as after the
3271%D \typ {whatever we wat} stuff.
3272%D
3273%D \starttyping
3274%D \dorecurse               % inner loop
3275%D   {10}
3276%D   {\recurselevel:          % outer value
3277%D      \dorecurse          % inner loop
3278%D        {\recurselevel}     % outer value
3279%D        {\recurselevel}     % inner value
3280%D      \dorecurse          % inner loop
3281%D        {\recurselevel}     % outer value
3282%D        {\recurselevel}     % inner value
3283%D    \endgraf}
3284%D \stoptyping
3285%D
3286%D In this example the first, second and fourth \type {\recurselevel} concern the
3287%D outer loop, while the third and fifth one concern the inner loop. The depth of
3288%D the nesting is available for inspection in \type {\recursedepth}.
3289%D
3290%D Both \type {\recurselevel} and \type {\recursedepth} are macros. The real
3291%D \COUNTERS\ are hidden from the user because we don't want any interference.
3292%D
3293%D We now use the macro stack which is somewhat leaner and meaner and a little
3294%D faster too.
3295
3296\newinteger\outerrecurse
3297\newinteger\innerrecurse
3298
3299% \mutable\def\recursedepth{\the\outerrecurse}
3300% \mutable\def\recurselevel{0}
3301
3302\mutable\untraced\def\recursedepth{\the\outerrecurse}
3303\mutable\untraced\def\recurselevel{0}
3304
3305\mutable\let\recurseaction\relax
3306
3307\mutable\lettonothing\recursestring
3308
3309%% \protected\def\syst_helpers_stepwise_recurse#1#2#3% from to step
3310%%   {\ifnum#1>#2\relax
3311%%      \expandafter\gobblefourarguments
3312%%    \else
3313%%      \def\recurselevel{#1}%
3314%%      \doubleexpandafter\syst_helpers_stepwise_recurse_yes
3315%%    \fi\expandafter{\the\numexpr\recurselevel+#3\relax}{#2}{#3}}
3316%%
3317%% \protected\def\syst_helpers_stepwise_recurse_yes
3318%%   {\syst_helpers_recurse_content
3319%%    \syst_helpers_stepwise_recurse}
3320%%
3321%% \protected\def\syst_helpers_stepwise_reverse#1#2#3% from to step
3322%%   {\ifnum#1<#2\relax
3323%%      \expandafter\gobblefourarguments
3324%%    \else
3325%%      \def\recurselevel{#1}%
3326%%      \innerrecurse#1\relax
3327%%      \advanceby\innerrecurse#3\relax
3328%%      \doubleexpandafter\syst_helpers_stepwise_reverse_yes
3329%%    \fi\expandafter{\the\numexpr\recurselevel+#3\relax}{#2}{#3}}
3330%%
3331%% \protected\def\syst_helpers_stepwise_reverse_yes
3332%%   {\syst_helpers_recurse_content
3333%%    \syst_helpers_stepwise_reverse}
3334%%
3335%% \permanent\def\doexpandedrecurse#1#2% user macro (also was \doxprecurse)
3336%%   {\ifnum#1>\zerocount
3337%%      #2\expandafter\doexpandedrecurse\expandafter{\the\numexpr#1-\plusone\relax}{#2}%
3338%%    \fi}
3339
3340%D The next one might replace the above and provides the current step in \type {#1}
3341%D like \type {\dorecurse} do, but it comes with a tiny performance hit.
3342
3343%% \installsystemnamespace{expandedrecurse}
3344%%
3345%% \mutable\let\m_expanded_recursed\gobbleoneargument
3346%%
3347%% \permanent\def\doexpandedrecursed#1#2% this might replace: \doexpandedrecurse
3348%%   {\beginlocalcontrol
3349%%    \localpushmacro\m_expanded_recursed
3350%%    \def\m_expanded_recursed##1{#2}%
3351%%    \endlocalcontrol
3352%%    \syst_do_expanded_recursed{1}{#1}{#2}% no \plusone !
3353%%    \beginlocalcontrol
3354%%    \localpopmacro\m_expanded_recursed
3355%%    \endlocalcontrol}
3356%%
3357%% \def\syst_do_expanded_recursed#1#2#3%
3358%%   {\ifnum#1>#2\norelax
3359%%      \expandafter\gobblethreearguments
3360%%    \else
3361%%      \m_expanded_recursed{#1}\doubleexpandafter\syst_do_expanded_recursed
3362%%    \fi
3363%%    {\the\numexpr#1+\plusone\relax}{#2}{#3}}
3364
3365%D As we can see here, the simple command \type{\dorecurse} is a special case of the
3366%D more general:
3367%D
3368%D \starttyping
3369%D \dostepwiserecurse {from} {to} {step} {action}
3370%D \stoptyping
3371%D
3372%D This commands accepts positive and negative steps. Illegal values are handles as
3373%D good as possible and the macro accepts numbers and \COUNTERS.
3374%D
3375%D \starttyping
3376%D \dostepwiserecurse  {1} {10}  {2} {...}
3377%D \dostepwiserecurse {10}  {1} {-2} {...}
3378%D \stoptyping
3379%D
3380%D Because the simple case (n=1) is used often, we implement it more efficiently:
3381
3382%% \permanent\protected\def\dorecurse#1%
3383%%   {\ifcase#1\relax
3384%%      \expandafter\gobbletwoarguments
3385%%    \or
3386%%      \expandafter\syst_helpers_recurse_y
3387%%    \else
3388%%      \expandafter\syst_helpers_recurse_x
3389%%    \fi{#1}}
3390%%
3391%% \protected\def\syst_helpers_recurse_indeed#1#2% from to
3392%% % {\ifnum#1>#2 %
3393%%   {\ifnum#1>#2\relax
3394%%      \expandafter\syst_helpers_recurse_indeed_nop
3395%%    \else
3396%%      \def\recurselevel{#1}%
3397%%      \innerrecurse#1\advanceby\innerrecurse\plusone
3398%%      \doubleexpandafter\syst_helpers_recurse_indeed_yes
3399%%    \fi\expandafter{\the\innerrecurse}{#2}}
3400%%
3401%% \protected\def\syst_helpers_recurse_indeed_yes
3402%%   {\syst_helpers_recurse_content
3403%%    \syst_helpers_recurse_indeed}
3404%%
3405%% \protected\def\syst_helpers_recurse_indeed_nop#0#0#0%
3406%%   {}
3407
3408%D \macros
3409%D   {dowith}
3410%D
3411%D Here's a loop over whatever is in a list:
3412%D
3413%D \starttyping
3414%D \dowith{a,b,c}{[#1]}
3415%D \stoptyping
3416
3417\let\syst_helpers_with\gobbleoneargument
3418
3419\permanent\protected\def\dowith#1#2%
3420  {\def\syst_helpers_with##1{#2}%
3421   \normalexpanded{\processcommalist[#1]}\syst_helpers_with}
3422
3423%D \macros
3424%D   {doloop,exitloop}
3425%D
3426%D Sometimes loops are not determined by counters, but by (a combinations of)
3427%D conditions. We therefore implement a straightforward loop, which can only be left
3428%D when we explictly exit it. Nesting is supported. First we present a more
3429%D extensive alternative.
3430%D
3431%D \starttyping
3432%D \doloop
3433%D   {Some kind of typesetting punishment \par
3434%D    \ifnum\pageno>100 \exitloop \fi}
3435%D \stoptyping
3436%D
3437%D When needed, one can call for \type {\looplevel} and \type {\loopdepth}.
3438
3439% \aliased\let\endofloop\donothing % maybe \syst_helpers_loop_end
3440%
3441% \permanent\protected\def\doloop#1%
3442%   {\global\advanceby\outerrecurse \plusone
3443%    \push_macro_recurseaction
3444%    \push_macro_recurselevel
3445%    \protected\gdef\recurseaction##1##2{#1}%
3446%    \enforced\let\endofloop\syst_helpers_loop
3447%    \syst_helpers_loop1}% no \plusone else \recurselevel wrong
3448%
3449% \protected\def\syst_helpers_loop#1%
3450%   {\def\recurselevel{#1}%
3451%    \expandafter\syst_helpers_loop_yes\expandafter{\the\numexpr\recurselevel+\plusone\relax}}
3452%
3453% %% \protected\def\syst_helpers_loop_yes
3454% %%   {\syst_helpers_recurse_content
3455% %%    \endofloop}
3456%
3457% \protected\def\syst_helpers_loop_yes
3458%   {\normalexpanded{\recurseaction{\recurselevel}{\the\outerrecurse}}%
3459%    \endofloop}
3460%
3461% \protected\def\syst_helpers_loop_nop#-%
3462%   {\enforced\let\endofloop\syst_helpers_loop
3463%    \pop_macro_recurselevel
3464%    \pop_macro_recurseaction
3465%    \global\advanceby\outerrecurse\minusone}
3466%
3467% \permanent\protected\def\exitloop                % \exitloop quits at end
3468%   {\enforced\let\endofloop\syst_helpers_loop_nop}
3469%
3470% \permanent\protected\def\exitloopnow#-\endofloop % \exitloopnow quits directly
3471%   {\syst_helpers_loop_nop}
3472
3473\permanent\protected\def\doloop#1%
3474  {\push_macro_recurseaction
3475   \push_macro_recurselevel
3476   \push_macro_recursedepth
3477   \protected\gdef\recurseaction##1##2{#1}%
3478   \untraced\edef\recurselevel{\noexpand\the\nestedloopiterator\the\currentloopnesting\space}%
3479   \untraced\edef\recursedepth{\tointeger{\currentloopnesting+\plusone}}%
3480   \localcontrolledendless
3481     {%\edef\recurselevel{\the\currentloopiterator}%
3482      %\edef\recursedepth{\the\currentloopnesting}%
3483      \normalexpanded{\recurseaction{\the\currentloopiterator}{\the\currentloopnesting}}}%
3484   \pop_macro_recursedepth
3485   \pop_macro_recurselevel
3486   \pop_macro_recurseaction}
3487
3488\aliased\let\exitloop   \quitloop
3489\aliased\let\exitloopnow\quitloopnow
3490
3491%D The loop is executed at least once, so beware of situations like:
3492%D
3493%D \starttyping
3494%D \doloop {\exitloop some commands}
3495%D \stoptyping
3496%D
3497%D It's just a matter of putting the text into the \type {\if} statement that should
3498%D be there anyway, like in:
3499%D
3500%D \starttyping
3501%D \doloop {\ifwhatever \exitloop \else some commands\fi}
3502%D \stoptyping
3503%D
3504%D You can also quit a loop immediately, by using \type
3505%D {\exitloopnow} instead. Beware, this is more sensitive
3506%D for conditional errors.
3507
3508%D Krzysztof Leszczynski suggested to provide access to the level by means of a
3509%D \type {#1}. I decided to pass the more frequently used level as \type {#1} and
3510%D the less favoured depth as \type {#2}. The intended usage is:
3511%D
3512%D \starttyping
3513%D \dorecurse{3}{\definesymbol[test-#1][xx-#1]}
3514%D
3515%D \def\test{\dorecurse{3}{\definesymbol[test-##1][xx-##1]}} \test
3516%D
3517%D \symbol[test-1]\quad\symbol[test-2]\quad\symbol[test-3]
3518%D \stoptyping
3519%D
3520%D Since the hashed arguments are expanded, we don't need tricky expansion here.
3521%D
3522%D \starttyping
3523%D \dorecurse{3}{\expanded{\definesymbol[test-\recurselevel][xx-\recurselevel]}}
3524%D \stoptyping
3525
3526%% \def\syst_helpers_recurse_content
3527%%   {\normalexpanded{\recurseaction{\recurselevel}{\the\outerrecurse}}}
3528%%
3529%% \protected\def\syst_helpers_recurse_x#1#2%
3530%%   {\global\advanceby\outerrecurse\plusone
3531%%    \globalpushmacro\recurseaction
3532%%    \globalpushmacro\recurselevel
3533%%    \protected\gdef\recurseaction##1##2{#2}%
3534%%    \expandafter\syst_helpers_recurse_indeed\expandafter1\expandafter{\number#1}%
3535%%    \globalpopmacro\recurselevel
3536%%    \globalpopmacro\recurseaction
3537%%    \global\advanceby\outerrecurse\minusone}
3538%%
3539%% \protected\def\syst_helpers_recurse_y#1#2%
3540%%   {\global\advanceby\outerrecurse\plusone
3541%%    \globalpushmacro\recurseaction
3542%%    \globalpushmacro\recurselevel
3543%%    \let\recurselevel\!!plusone
3544%%    \protected\gdef\recurseaction##1##2{#2}%
3545%%    \syst_helpers_recurse_content
3546%%    \globalpopmacro\recurselevel
3547%%    \globalpopmacro\recurseaction
3548%%    \global\advanceby\outerrecurse\minusone}
3549%%
3550%% \permanent\protected\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4 ... todo: remove unused helpers
3551%%   {\global\advanceby\outerrecurse \plusone
3552%%    \globalpushmacro\recurseaction
3553%%    \globalpushmacro\recurselevel
3554%%    \protected\gdef\recurseaction##1##2{#4}%
3555%%    \normalexpanded{\ifcmpnum#3\zerocount
3556%%      \ifnum#1<#2\relax\relax % so we catch \the\numexpr xx without \relax's
3557%%        \doubleexpandafter\gobbletwoarguments
3558%%      \else
3559%%        \tripleexpandafter\syst_helpers_stepwise_reverse
3560%%      \fi
3561%%    \or
3562%%      \doubleexpandafter\gobbletwoarguments
3563%%    \orelse\ifnum#2<#1\relax\relax % so we catch \the\numexpr xx without \relax's
3564%%      \doubleexpandafter\gobbletwoarguments
3565%%    \else
3566%%      \doubleexpandafter\syst_helpers_stepwise_recurse
3567%%    \fi\normalexpanded{{\number#1}{\number#2}{\number#3}}}%
3568%%    \globalpopmacro\recurselevel
3569%%    \globalpopmacro\recurseaction
3570%%    \global\advanceby\outerrecurse\minusone}
3571
3572\newinteger\fastloopindex
3573\newinteger\fastloopfinal
3574
3575\let\m_syst_helpers_fast_loop_cs\relax
3576
3577\permanent\protected\def\dofastloopcs#1% kind of obsolete
3578  {\fastloopfinal{#1}%
3579   \ifcase\fastloopfinal
3580     \expandafter\gobbleoneargument
3581   \else
3582     \expandafter\syst_helpers_fast_loop_cs
3583   \fi}
3584
3585\protected\def\syst_helpers_fast_loop_cs#1%
3586  {\let\m_syst_helpers_fast_loop_cs#1%
3587   \fastloopindex\plusone
3588   \syst_helpers_fast_loop_cs_step}
3589
3590\protected\def\syst_helpers_fast_loop_cs_step
3591  {\ifnum\fastloopindex>\fastloopfinal
3592     \let\m_syst_helpers_fast_loop_cs\relax
3593   \else
3594     \m_syst_helpers_fast_loop_cs
3595     \advanceby\fastloopindex\plusone
3596     \expandafter\syst_helpers_fast_loop_cs_step
3597   \fi}
3598
3599%D Here are the more modern implementations:
3600
3601\permanent\protected\def\installmacrostack#1%
3602  {\ifdefined#1\else\mutable\lettonothing#1\fi
3603   \protected\gdefcsname push_macro_\csstring#1\endcsname{\localpushmacro#1}%
3604   \protected\gdefcsname  pop_macro_\csstring#1\endcsname{\localpopmacro #1}}
3605
3606\permanent\protected\def\installglobalmacrostack#1%
3607  {\ifdefined#1\else\mutable\glettonothing#1\fi
3608   \protected\gdefcsname push_macro_\csstring#1\endcsname{\globalpushmacro#1}%
3609   \protected\gdefcsname  pop_macro_\csstring#1\endcsname{\globalpopmacro #1}}
3610
3611\installglobalmacrostack \recurseaction
3612\installglobalmacrostack \recurselevel
3613\installglobalmacrostack \recursedepth
3614\installglobalmacrostack \recursestring
3615
3616% \showmacrostack can be used to see if there are different entries
3617
3618\permanent\protected\def\dostepwiserecurse#1#2#3#4%
3619  {\push_macro_recurseaction
3620   \push_macro_recurselevel
3621   \push_macro_recursedepth
3622   \protected\gdef\recurseaction##1##2{#4}%
3623%    \untraced\edef\recurselevel{\noexpand\the\nestedloopiterator\the\currentloopnesting\space}%
3624%    \untraced\edef\recursedepth{\the\numexpr\currentloopnesting+\plusone}%
3625%    \localcontrolledloop=#1=#2=#3%
3626\untraced\edef\recurselevel{\noexpand\tointeger\nestedloopiterator{\the\currentloopnesting}}%
3627\untraced\edef\recursedepth{\tointeger{\currentloopnesting+\plusone}}%
3628   \localcontrolledloop{#1}{#2}{#3}%
3629     {%\edef\recurselevel{\the\currentloopiterator}%
3630      %\edef\recursedepth{\the\currentloopnesting}%
3631      \normalexpanded{\recurseaction{\the\currentloopiterator}{\the\currentloopnesting}}}%
3632   \pop_macro_recursedepth
3633   \pop_macro_recurselevel
3634   \pop_macro_recurseaction}
3635
3636\permanent\protected\def\dorecurse#1#2%
3637  {\push_macro_recurseaction
3638   \push_macro_recurselevel
3639   \push_macro_recursedepth
3640   \protected\gdef\recurseaction##1##2{#2}%
3641%    \untraced\edef\recurselevel{\noexpand\the\nestedloopiterator\the\currentloopnesting\space}%
3642%    \untraced\edef\recursedepth{\the\numexpr\currentloopnesting+\plusone}%
3643%    \localcontrolledrepeat=#1%
3644   \untraced\edef\recurselevel{\noexpand\tointeger\nestedloopiterator{\the\currentloopnesting}}%
3645   \untraced\edef\recursedepth{\tointeger{\currentloopnesting+\plusone}}%
3646   \localcontrolledrepeat{#1}%
3647     {%\edef\recurselevel{\the\currentloopiterator}%
3648      %\edef\recursedepth{\the\currentloopnesting}%
3649      \normalexpanded{\recurseaction{\the\currentloopiterator}{\the\currentloopnesting}}}%
3650   \pop_macro_recursedepth
3651   \pop_macro_recurselevel
3652   \pop_macro_recurseaction}
3653
3654\permanent\def\doexpandedrecurse#1#2% user macro (also was \doxprecurse)
3655  {\expandedloop\plusone#1\plusone{#2}}
3656
3657\mutable\let\m_expanded_recursed\gobbleoneargument
3658
3659\installmacrostack\m_expanded_recursed
3660
3661\permanent\def\doexpandedrecursed#1#2% this might replace: \doexpandedrecurse
3662  {\beginlocalcontrol
3663   \push_macro_m_expanded_recursed
3664   \def\m_expanded_recursed##1{#2}%
3665   \endlocalcontrol
3666   \expandedrepeat{#1}{\expandafter\m_expanded_recursed\expandafter{\the\currentloopiterator}}%
3667   \beginlocalcontrol
3668   \pop_macro_m_expanded_recursed
3669   \endlocalcontrol}
3670
3671% Helper:
3672
3673% \permanent\protected\def\resetrecurselevel{\let\recurselevel\!!zerocount}
3674
3675\permanent\protected\def\resetrecurselevel{\untraced\let\recurselevel\!!zerocount}
3676
3677% \appendtoks \resetrecurselevel \to \everydump
3678
3679%D \macros
3680%D   {doloopoverlist}
3681%D
3682%D \starttyping
3683%D \doloopoverlist {red,green,blue} {
3684%D      \setuppalet[\recursestring]
3685%D      \doloopoverlist {light,normal,dark} {
3686%D          \blackrule[color=\recursestring,width=20cm,height=2cm,depth=0cm]\par
3687%D      }
3688%D  }
3689%D \stoptyping
3690%D
3691%D or:
3692%D
3693%D \starttyping
3694%D \doloopoverlist {red,green,blue} {
3695%D      \setuppalet[#1]
3696%D      \doloopoverlist {light,normal,dark} {
3697%D          \blackrule[color=##1,width=20cm,height=2cm,depth=0cm]\par
3698%D      }
3699%D  }
3700%D \stoptyping
3701
3702\permanent\protected\def\doloopoverlist#1#2%
3703  {\global\advanceby\outerrecurse\plusone
3704%    \globalpushmacro\recurseaction
3705%    \globalpushmacro\recursestring
3706   \push_macro_recurseaction
3707   \push_macro_recursestring
3708   \protected\gdef\recurseaction##1{\edef\recursestring{##1}#2}%
3709   \processcommacommand[#1]\recurseaction
3710%    \globalpopmacro\recursestring
3711%    \globalpopmacro\recurseaction
3712   \pop_macro_recursestring
3713   \pop_macro_recurseaction
3714   \global\advanceby\outerrecurse\minusone}
3715
3716%D This is some \LMTX\ experiment:
3717%D
3718%D Think of:
3719%D
3720%D \starttyping
3721%D \doloopovermatch {(\letterpercent w+) *(\letterpercent w*)} {aa bb cc dd} {
3722%D     [
3723%D     \doloopovermatch{(\letterpercent w)(\letterpercent w)} {#1} {(##1 ##2)}
3724%D     \doloopovermatch{(\letterpercent w)(\letterpercent w)} {#2} {(##1 ##2)}
3725%D     ]
3726%D }
3727%D
3728%D and:
3729%D
3730%D \stoptyping
3731%D
3732%D \starttyping
3733%D \def\MyMacro#1{(#1)} \ctxluamatch \MyMacro {(.)} {abcd}
3734%D \stoptyping
3735
3736\aliased\let\matchloopcommand\relax
3737
3738\permanent\protected\def\doloopovermatch#1#2#3%
3739  {\pushmacro\matchloopcommand
3740   \enforced\def\matchloopcommand##1##2##3##4##5##6##7##8##9##A##B##C##D##E{#3}%
3741   \ctxluamatch\matchloopcommand{#1}{#2}%
3742   \popmacro\matchloopcommand}
3743
3744\permanent\def\doloopovermatched#1#2#3%
3745  {\beginlocalcontrol
3746     \pushmacro\matchloopcommand
3747     \enforced\def\matchloopcommand##1##2##3##4##5##6##7##8##9##A##B##C##D##E{#3}%
3748   \endlocalcontrol
3749   \the\ctxluamatch\matchloopcommand{#1}{#2}%
3750   \beginlocalcontrol
3751     \popmacro\matchloopcommand
3752   \endlocalcontrol}
3753
3754% \defineatluaend\ctxluamatch
3755% \defineatluaend\ctxluamatchfile
3756
3757%D \starttyping
3758%D \ctxluamatch
3759%D     \Whatever
3760%D     {(\letterpercent S+) *(\letterpercent S+) *(\letterpercent S+) *(\letterpercent S+)\letterpercent s*}
3761%D     {\cldloadfile{crap.txt}}
3762%D \ctxluamatchfile
3763%D     \Whatever
3764%D     {(\letterpercent S+) *(\letterpercent S+) *(\letterpercent S+) *(\letterpercent S+)\letterpercent s*}
3765%D     {crap.txt}
3766%D \stoptyping
3767
3768%D \macros
3769%D   {newevery,everyline,EveryLine,EveryPar}
3770%D
3771%D Lets skip to something quite different. It's common use to use \type {\everypar}
3772%D for special purposes. In \CONTEXT\ we use this primitive for locating sidefloats.
3773%D This means that when user assignments to \type {\everypar} can interfere with
3774%D those of the package. We therefore introduce \type {\EveryPar}.
3775%D
3776%D The same goes for \type {\EveryLine}. Because \TEX\ offers no \type {\everyline}
3777%D primitive, we have to call for \type {\everyline} when we are working on a line
3778%D by line basis. Just by calling \type {\EveryPar{}} and \type {\EveryLine{}} we
3779%D restore the old situation.
3780
3781% \dorecurse{2}{
3782%     \expanded{\everypar{before \recurselevel\space}}
3783%     \EveryPar{x } [before \recurselevel\space x] \par
3784%     \EveryPar{y } [before \recurselevel\space y] \par
3785%     \EveryPar{}   [before \recurselevel]   \par
3786%     \EveryPar{x } \EveryPar{y } \EveryPar{} [before \recurselevel] \par
3787%     \EveryPar{y } \everypar{before } [before] \par
3788% }
3789
3790\installsystemnamespace{extraevery}
3791
3792\permanent\protected\def\newevery#1#2%
3793  {\ifx#1\everypar\else\newtoks#1\fi% we test for redefinition elsewhere
3794   \ifrelax#2\orelse\ifdefined#2\else
3795     \expandafter\newtoks\csname\??extraevery\csstring#1\endcsname
3796     \frozen\protected\edef#2{\syst_helpers_every#1\csname\??extraevery\csstring#1\endcsname}%
3797   \fi}
3798
3799\protected\def\syst_helpers_every#1#2%
3800  {\removetoks\the#2\from#1%
3801   \appendtoks\the#2\to  #1%
3802   #2}
3803
3804%D This one permits definitions like:
3805
3806\newevery \everypar  \EveryPar  % we get a warning which is ok
3807\newevery \everyline \EveryLine
3808
3809%D and how about:
3810
3811\newtoks \neverypar
3812
3813\permanent\protected\def\forgeteverypar
3814  {\everypar{\expand\neverypar}}
3815
3816%D Which we're going to use indeed! When the second argument equals \type {\relax},
3817%D the first token list is created unless it is already defined.
3818%D
3819%D Technically spoken we could have used the method we are going to present in the
3820%D visual debugger. First we save the primitive \type{\everypar}:
3821%D
3822%D \starttyping
3823%D \let\normaleverypar=\everypar
3824%D \stoptyping
3825%D
3826%D Next we allocate a \TOKENLIST\ named \type{\everypar}, which means that
3827%D \type{\everypar} is no longer a primitive but something like \type{\toks44}.
3828%D
3829%D \starttyping
3830%D \newtoks\everypar
3831%D \stoptyping
3832%D
3833%D Because \TEX\ now executes \type{\normaleverypar} instead of \type{\everypar}, we
3834%D are ready to assign some tokens to this internally known and used \TOKENLIST.
3835%D
3836%D \starttyping
3837%D \normaleverypar={all the things the system wants to do \the\everypar}
3838%D \stoptyping
3839%D
3840%D Where the user can provide his own tokens to be expanded every time he expects
3841%D them to expand.
3842%D
3843%D \starttyping
3844%D \everypar={something the user wants to do}
3845%D \stoptyping
3846%D
3847%D We don't use this method because it undoubtly leads to confusing situations,
3848%D especially when other packages are used, but it's this kind of tricks that make
3849%D \TEX\ so powerful.
3850
3851%D \macros
3852%D   {convertargument,convertcommand,convertvalue}
3853%D
3854%D Some persistent experimenting led us to the next macro. This macro converts a
3855%D parameter or an expanded macro to it's textual meaning.
3856%D
3857%D \starttyping
3858%D \convertargument ... \to \command
3859%D \stoptyping
3860%D
3861%D For example,
3862%D
3863%D \starttyping
3864%D \convertargument{one \two \three{four}}\to\ascii
3865%D \stoptyping
3866%D
3867%D The resulting macro \type{\ascii} can be written to a file or the terminal
3868%D without problems. In \CONTEXT\ we use this macro for generating registers and
3869%D tables of contents.
3870%D
3871%D The second conversion alternative accepts a command:
3872%D
3873%D \starttyping
3874%D \convertcommand\command\to\ascii
3875%D \stoptyping
3876%D
3877%D Both commands accept the prefix \type{\doglobal} for global assignments.
3878
3879\permanent\protected\def\convertvalue#1\to
3880  {\expandafter\convertcommand\csname#1\endcsname\to}
3881
3882\permanent\protected\def\defconvertedvalue#1#2% less sensitive for \to
3883  {\expandafter\defconvertedcommand\expandafter#1\csname#2\endcsname}
3884
3885%D \macros
3886%D   {doifassignmentelse}
3887%D
3888%D A lot of \CONTEXT\ commands take optional arguments, for instance:
3889%D
3890%D \starttyping
3891%D \dothisorthat[alfa,beta]
3892%D \dothisorthat[first=foo,second=bar]
3893%D \dothisorthat[alfa,beta][first=foo,second=bar]
3894%D \stoptyping
3895%D
3896%D Although a combined solution is possible, we prefer a seperation. The next
3897%D command takes care of propper handling of such multi||faced commands.
3898%D
3899%D \starttyping
3900%D \doifassignmentelse {...} {then ...} {else ...}
3901%D \stoptyping
3902%D
3903%D So
3904%D \startbuffer
3905%D \doifelseassignment{a=b}{Y}{N}
3906%D \doifelseassignment{a+b}{Y}{N}
3907%D
3908%D \ifcondition\validassignment  {a=b}Y\else N\fi
3909%D \ifcondition\novalidassignment{a=b}N\else Y\fi
3910%D \ifcondition\novalidassignment {ab}Y\else N\fi
3911%D \stopbuffer
3912%D
3913%D \typebuffer gives: \blank \getbuffer \blank
3914
3915\permanent\protected\def\doifelseassignment#1%
3916  {\ifhastok={#1}%
3917     \expandafter\firstoftwoarguments
3918   \else
3919     \expandafter\secondoftwoarguments
3920   \fi}
3921
3922\permanent\protected\def\doifelseassignmentcs#1#2#3%
3923  {\ifhastok={#1}%
3924     \expandafter#2%
3925   \else
3926     \expandafter#3%
3927   \fi}
3928
3929\aliased\let\doifassignmentelse  \doifelseassignment
3930\aliased\let\doifassignmentelsecs\doifelseassignmentcs
3931
3932\newif\ifassignment
3933
3934\permanent\protected\def\docheckassignment#1%
3935  {\ifhastok={#1}%
3936     \assignmenttrue
3937   \else
3938     \assignmentfalse
3939   \fi}
3940
3941\permanent\protected\def\validassignment  #1{\ifhastok={#1}} % can become: {\ifhastok=} as we enforce {}
3942\permanent\protected\def\novalidassignment#1{\ifnum\ifhastok={#1}\zerocount\else\plusone\fi=\plusone} % or use unless
3943
3944%D In \ETEX\ we can use \type {\detokenize} and gain some speed, but in general far
3945%D less that 1\% for \type {\convertargument} and nil for \type {\convertcommand}.
3946%D This macro is more robust than the pure \TEX\ one, something I found out when
3947%D primitives like \type {\jobname} were fed (or something undefined).
3948
3949\permanent\protected\def\convertargument#1\to#2{\dodoglobal\edef#2{\detokenize{#1}}}
3950\permanent\protected\def\convertcommand #1\to#2{\dodoglobal\edef#2{\expandafter\detokenize\expandafter{#1}}} % hm, only second is also ok
3951
3952\permanent\protected\def\defconvertedargument #1#2{\edef#1{\detokenize{#2}}}
3953\permanent\protected\def\defconvertedcommand  #1#2{\edef#1{\detokenize\expandafter{#2}}}
3954\permanent\protected\def\edefconvertedargument#1#2{\edef#1{#2}%
3955                                                   \edef#1{\detokenize\expandafter{#1}}}
3956\permanent\protected\def\gdefconvertedargument#1#2{\xdef#1{\detokenize{#2}}}
3957\permanent\protected\def\gdefconvertedcommand #1#2{\xdef#1{\detokenize\expandafter{#2}}}
3958\permanent\protected\def\xdefconvertedargument#1#2{\xdef#1{#2}%
3959                                                   \xdef#1{\detokenize\expandafter{#1}}}
3960
3961%D When you try to convert a primitive command, you'll find out that the \ETEX\
3962%D method fails on for instance \type {\jobname} in the sense that it returns the
3963%D filename instead of just \type {\jobname}. So far this does not give real
3964%D problems.
3965
3966%D This is typically a macro that one comes to after reading the \TEX book
3967%D carefully. Even then, the definite solution was found after rereading the \TEX
3968%D book. The first implementation was:
3969%D
3970%D \starttyping
3971%D \def\doconvertargument#1->#2\\\\{#2}
3972%D \stoptyping
3973%D
3974%D The \type {-}, the delimiter \type {\\\\} and the the second argument are
3975%D completely redundant.
3976
3977%D \macros
3978%D   {showvalue}
3979%D
3980%D Ahandy macro, for testing purposes only:
3981
3982\permanent\protected\def\showvalue#1%
3983  {\ifcsname#1\endcsname
3984     \expandafter\show\csname#1\endcsname
3985   \else
3986     \show\undefined
3987   \fi}
3988
3989%D \macros
3990%D   {doifmeaningelse}
3991%D
3992%D We can use both commands in testing, but alas, not all meanings expand to
3993%D something \type {->}. This is no problem in the \ETEX\ implementation, but since
3994%D we want compatibility, we need:
3995%D
3996%D \starttyping
3997%D \doifmeaningelse {\next} {\something} {true} {false}
3998%D \stoptyping
3999%D
4000%D Watch the one level expansion of the second argument.
4001
4002% This is only used in \spac_lines_between .. pretty ugly. Never change
4003% this one!
4004
4005\permanent\protected\def\doifelsemeaning#1#2%
4006  {\edef\m_syst_string_one{\normalmeaning#1}%
4007   \def \m_syst_string_two{#2}%
4008   \edef\m_syst_string_two{\normalmeaning\m_syst_string_two}%
4009   \ifx\m_syst_string_one\m_syst_string_two
4010     \expandafter\firstoftwoarguments
4011   \else
4012     \expandafter\secondoftwoarguments
4013   \fi}
4014
4015\aliased\let\doifmeaningelse\doifelsemeaning
4016
4017%D \macros
4018%D   {doifsamestringselse,doifsamestring,doifnotsamestring}
4019%D
4020%D The next comparison macro converts the arguments into expanded strings. This
4021%D command can be used to compare for instance \type {\jobname} with a name stored
4022%D in a macro.
4023%D
4024%D \starttyping
4025%D \doifelse          {\jobname}{oeps}{YES}{NO}
4026%D \doifsamestringelse{\jobname}{oeps}{YES}{NO}
4027%D \stoptyping
4028
4029\def\syst_helpers_if_samestring_else#1#2#3#4%
4030  {\edef\m_syst_string_one{\detokenize\expandafter{\normalexpanded{#3}}}%
4031   \edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#4}}}%
4032   \ifx\m_syst_string_one\m_syst_string_two\expandafter#1\else\expandafter#2\fi}
4033
4034\permanent\protected\def\doifelsesamestring{\syst_helpers_if_samestring_else\firstoftwoarguments\secondoftwoarguments}
4035\permanent\protected\def\doifsamestring    {\syst_helpers_if_samestring_else\firstofoneargument \gobbleoneargument   }
4036\permanent\protected\def\doifnotsamestring {\syst_helpers_if_samestring_else\gobbleoneargument  \firstofoneargument  }
4037
4038\aliased\let\doifsamestringelse\doifelsesamestring
4039
4040%D These are obsolete in MTX:
4041%D
4042%D \starttyping
4043%D \ConvertToConstant    #1#2#3
4044%D \CheckConstantAfter   #1#2
4045%D \ConvertConstantAfter #1#2#3
4046%D \stoptyping
4047
4048%D \macros
4049%D   {assignifempty}
4050%D
4051%D We can assign a default value to an empty macro using:
4052%D
4053%D \starttyping
4054%D \assignifempty \macros {default value}
4055%D \stoptyping
4056%D
4057%D We don't explicitly test if the macro is defined.
4058
4059\permanent\protected\def\assignifempty#1#2%
4060  {\ifempty{#1}\def#1{#2}\fi}
4061
4062%D \macros
4063%D   {gobbleuntil,grabuntil,gobbleuntilrelax,
4064%D    processbetween,processuntil}
4065%D
4066%D In \TEX\ gobbling usually stand for skipping arguments, so here are our gobbling
4067%D macros.
4068%D
4069%D In \CONTEXT\ we use a lot of \type {\start}||\type {\stop} like constructions.
4070%D Sometimes, the \type {\stop} is used as a hard coded delimiter like in: %D
4071%D \starttyping
4072%D \protected\def\startcommand#1\stopcommand%
4073%D   {... #1 ...}
4074%D \stoptyping
4075%D
4076%D In many cases the \type {\start}||\type {\stop} pair is defined at format
4077%D generation time or during a job. This means that we cannot hardcode the \type
4078%D {\stop} criterium. Only after completely understanding \type {\csname} and \type
4079%D {\expandafter} I was able to to implement a solution, starting with:
4080%D
4081%D \starttyping
4082%D \grabuntil{stop}\command
4083%D \stoptyping
4084%D
4085%D This commands executes, after having encountered \type {\stop} the command \type
4086%D {\command}. This command receives as argument the text preceding the \type
4087%D {\stop}. This means that:
4088%D
4089%D \starttyping
4090%D \protected\def\starthello%
4091%D   {\grabuntil{stophello}\message}
4092%D
4093%D \starthello Hello world!\stophello
4094%D \stoptyping
4095%D
4096%D results in: \type{\message{Hello world!}}.
4097
4098\let\syst_helpers_grab_indeed\relax
4099
4100\protected\def\syst_helpers_grab#1#2%
4101  {\def\syst_helpers_grab_indeed##1#1{#2{##1}}\syst_helpers_grab_indeed}
4102
4103\permanent\protected\def\grabuntil#1%
4104  {\expandafter\syst_helpers_grab\expandafter{\csname#1\endcsname}}
4105
4106%D The next command build on this mechanism:
4107%D
4108%D \starttyping
4109%D \processbetween{string}\command
4110%D \stoptyping
4111%D
4112%D Here:
4113%D
4114%D \starttyping
4115%D \processbetween{hello}\message
4116%D \starthello Hello again!\stophello
4117%D \stoptyping
4118%D
4119%D leads to: \type{\message{Hello again!}}. The command
4120%D
4121%D \starttyping
4122%D \gobbleuntil{sequence}
4123%D \stoptyping
4124%D
4125%D is related to these commands. This one simply throws away
4126%D everything preceding \type{\command}.
4127
4128\let\syst_helpers_gobble_indeed\relax
4129
4130\permanent\protected\def\processbetween#1#2%
4131  {\setvalue{\s!start#1}{\grabuntil{\s!stop#1}{#2}}}
4132
4133% \protected\def\gobbleuntil#1%
4134%   {\def\syst_helpers_gobble_indeed##1#1{}\syst_helpers_gobble_indeed}
4135%
4136% \protected\def\gobbleuntilrelax#1\relax
4137%   {}
4138
4139\permanent\protected\def\gobbleuntil#1%
4140  {\def\syst_helpers_gobble_indeed##-#1{}\syst_helpers_gobble_indeed}
4141
4142\permanent\protected\def\gobbleuntilandfinalize#1%
4143  {\def\syst_helpers_gobble_indeed##-#1{#1}\syst_helpers_gobble_indeed}
4144
4145\permanent\protected\def\gobbleuntilrelax#-\relax
4146  {}
4147
4148%D The next one simply expands the pickup up tokens.
4149%D
4150%D \starttyping
4151%D \processuntil{sequence}
4152%D \stoptyping
4153
4154\let\syst_helpers_until_indeed\relax
4155
4156\permanent\protected\def\processuntil#1%
4157  {\def\syst_helpers_until_indeed##1#1{##1}\syst_helpers_until_indeed}
4158
4159%D \macros
4160%D   {groupedcommand}
4161%D
4162%D Commands often manipulate argument as in:
4163%D
4164%D \starttyping
4165%D \def\doezomaarwat#1{....#1....}
4166%D \stoptyping
4167%D
4168%D A disadvantage of this approach is that the tokens that form \type{#1} are fixed
4169%D the the moment the argument is read in. Normally this is no problem, but for
4170%D instance verbatim environments adapt the \CATCODES\ of characters and therefore
4171%D are not always happy with already fixed tokens.
4172%D
4173%D Another problem arises when the argument is grouped not by \type {{}} but by
4174%D \type {\bgroup} and \type {\egroup}. Such an argument fails, because the \type
4175%D {\bgroup} is een as the argument (which is quite normal).
4176%D
4177%D The next macro offers a solution for both unwanted situations:
4178%D
4179%D \starttyping
4180%D \groupedcommand {before} {after}
4181%D \stoptyping
4182%D
4183%D Which can be used like:
4184%D
4185%D \starttyping
4186%D \def\cite%
4187%D   {\groupedcommand{\rightquote\rightquote}{\leftquote\leftquote}}
4188%D \stoptyping
4189%D
4190%D This command is equivalent to, but more 'robust' than:
4191%D
4192%D \starttyping
4193%D \def\cite#1%
4194%D   {\rightquote\rightquote#1\leftquote\leftquote}
4195%D \stoptyping
4196%D
4197%D \starttyping
4198%D \def\rightword%
4199%D   {\groupedcommand{\hfill\hbox}{\parfillskip\zeropoint}}
4200%D
4201%D .......... \rightword{the right way}
4202%D \stoptyping
4203%D
4204%D Here \TEX\ typesets \type {\bf the right way} unbreakable at the end of the line.
4205%D The solution mentioned before does not work here. We also handle
4206%D
4207%D \starttyping
4208%D to be \bold{bold} or not, that's the question
4209%D \stoptyping
4210%D
4211%D and
4212%D
4213%D \starttyping
4214%D to be {\bold bold} or not, that's the question
4215%D \stoptyping
4216%D
4217%D This alternative checks for a \type {\bgroup} token first. The internal
4218%D alternative does not accept the box handling mentioned before, but further
4219%D nesting works all right. The extra \type {\bgroup}||\type {\egroup} is needed to
4220%D keep \type {\m_syst_helpers_handle_group_after} both into sight and local.
4221
4222%D Todo: use more modern features like atendofgroup
4223
4224\let\m_syst_helpers_handle_group_after \relax
4225\let\m_syst_helpers_handle_group_before\relax
4226
4227\protected\def\syst_helpers_handle_group_nop
4228  {\ifnum\currentgrouptype=\semisimplegroupcode
4229     \expandafter\syst_helpers_handle_group_nop_a
4230   \else
4231     \expandafter\syst_helpers_handle_group_nop_b
4232   \fi}
4233
4234\def\syst_helpers_handle_group_nop_a
4235  {\begingroup
4236   \aftergroup\m_syst_helpers_handle_group_a
4237   \aftergroup\endgroup
4238   \m_syst_helpers_handle_group_b}
4239
4240\def\syst_helpers_handle_group_nop_b
4241  {\beginsimplegroup
4242   \aftergroup\m_syst_helpers_handle_group_a
4243   \aftergroup\egroup
4244   \m_syst_helpers_handle_group_b}
4245
4246\protected\def\syst_helpers_handle_group_normal
4247  {\beginsimplegroup
4248   \afterassignment\m_syst_helpers_handle_group_normal_before
4249   \let\next=}
4250
4251\def\m_syst_helpers_handle_group_normal_before
4252  {\beginsimplegroup
4253   \m_syst_helpers_handle_group_b
4254   \bgroup
4255   \aftergroup\m_syst_helpers_handle_group_a
4256   \aftergroup\egroup
4257   \aftergroup\egroup}
4258
4259\protected\def\syst_helpers_handle_group_simple% no inner group (so no kerning interference)
4260  {\beginsimplegroup
4261   \afterassignment\m_syst_helpers_handle_group_simple_before
4262   \let\next=}
4263
4264\def\m_syst_helpers_handle_group_simple_before
4265  {\beginsimplegroup
4266   \aftergroup\m_syst_helpers_handle_group_simple_after
4267   \m_syst_helpers_handle_group_b}
4268
4269\def\m_syst_helpers_handle_group_simple_after
4270  {\m_syst_helpers_handle_group_a
4271   \egroup}
4272
4273\protected\def\syst_helpers_handle_group_pickup% no inner group (so no kerning interference)
4274  {\beginsimplegroup
4275   \afterassignment\m_syst_helpers_handle_group_pickup_before
4276   \let\next=}
4277
4278\def\m_syst_helpers_handle_group_pickup_before
4279  {\beginsimplegroup
4280   \aftergroup\m_syst_helpers_handle_group_a
4281   \aftergroup\egroup
4282   \aftergroup\m_syst_helpers_handle_group_p
4283   \m_syst_helpers_handle_group_b}
4284
4285\protected\def\syst_helpers_handle_group_nop_x
4286  {% why this ...
4287   \ifnum\currentgrouptype=\semisimplegroupcode
4288     \begingroup
4289     \aftergroup\endgroup
4290   \else
4291     \beginsimplegroup
4292     \aftergroup\egroup
4293   \fi
4294   % ... till here
4295   \m_syst_helpers_handle_group_b}
4296
4297\protected\def\syst_helpers_handle_group_normal_x
4298  {\beginsimplegroup
4299   \afterassignment\m_syst_helpers_handle_group_normal_before_x
4300   \let\next=}
4301
4302\def\m_syst_helpers_handle_group_normal_before_x
4303  {\beginsimplegroup
4304   \expandafter\m_syst_helpers_handle_group_b
4305   \ifmmode\beginsimplegroup\else\bgroup\fi % is this save enough? also the other ones?
4306   \aftergroup\egroup
4307   \aftergroup\egroup}
4308
4309%D I considered it a nuisance that
4310%D
4311%D \starttyping
4312%D \color[green]
4313%D   {as grass}
4314%D \stoptyping
4315%D
4316%D was not interpreted as one would expect. This is due to the fact that \type
4317%D {\futurelet} obeys blank spaces, and a line||ending token is treated as a blank
4318%D space. So the final implementation became:
4319
4320\permanent\protected\def\groupedcommand#1#2%
4321  {\def\m_syst_helpers_handle_group_b{#1}%
4322   \def\m_syst_helpers_handle_group_a{#2}%
4323   \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop}
4324
4325\permanent\protected\def\groupedcommandcs#1#2%
4326  {\let\m_syst_helpers_handle_group_b#1%
4327   \let\m_syst_helpers_handle_group_a#2%
4328   \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop}
4329
4330\permanent\protected\def\simplegroupedcommand#1#2%
4331  {\def\m_syst_helpers_handle_group_b{#1}%
4332   \def\m_syst_helpers_handle_group_a{#2}%
4333   \futureexpandis\bgroup\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop}
4334
4335\permanent\protected\def\simplegroupedcommandcs#1#2%
4336  {\let\m_syst_helpers_handle_group_b#1%
4337   \let\m_syst_helpers_handle_group_a#2%
4338   \futureexpandis\bgroup\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop}
4339
4340\permanent\protected\def\pickupgroupedcommand#1#2#3%
4341  {\def\m_syst_helpers_handle_group_b{#1}%
4342   \def\m_syst_helpers_handle_group_a{#2}%
4343   \def\m_syst_helpers_handle_group_p{#3}%
4344   \futureexpandis\bgroup\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop}
4345
4346\permanent\protected\def\pickupgroupedcommandcs#1#2#3%
4347  {\let\m_syst_helpers_handle_group_b#1%
4348   \let\m_syst_helpers_handle_group_a#2%
4349   \let\m_syst_helpers_handle_group_p#3%
4350   \futureexpandis\bgroup\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop}
4351
4352\permanent\protected\def\triggergroupedcommand#1%
4353  {\def\m_syst_helpers_handle_group_b{#1}%
4354   \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x}
4355
4356\permanent\protected\def\triggergroupedcommandcs#1%
4357  {\let\m_syst_helpers_handle_group_b#1%
4358   \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x}
4359
4360%D Users should be aware of the fact that grouping can interfere with ones paragraph
4361%D settings that are executed after the paragraph is closed. One should therefore
4362%D explictly close the paragraph with \type {\par}, else the settings will be
4363%D forgotten and not applied. So it's:
4364%D
4365%D \starttyping
4366%D \def\BoldRaggedCenter%
4367%D   {\groupedcommand{\raggedcenter\bf}{\par}}
4368%D \stoptyping
4369%D
4370%D In \LUAMETATEX\ this is less of an issue as we can save the state (and do so in
4371%D \CONTEXT).
4372
4373%D For math we use this:
4374
4375\permanent\protected\def\mathgroupedcommandcs#1%
4376  {\let\m_syst_helpers_handle_group_b#1%
4377   \futureexpandis\bgroup\syst_helpers_handle_math_group_normal\syst_helpers_handle_math_group_nop}
4378
4379\protected\def\syst_helpers_handle_math_group_normal#1%
4380  {\beginmathgroup
4381   \m_syst_helpers_handle_group_b
4382   #1%
4383   \endmathgroup}
4384
4385\protected\def\syst_helpers_handle_math_group_nop
4386  {\m_syst_helpers_handle_group_b}
4387
4388% %D \macros
4389% %D   {checkdefined}
4390% %D
4391% %D The bigger the system, the greater the change that user defined commands collide
4392% %D with those that are part of the system. The next macro gives a warning when a
4393% %D command is already defined. We considered blocking the definition, but this is
4394% %D not always what we want.
4395% %D
4396% %D \starttyping
4397% %D \checkdefined {category} {class} {command}
4398% %D \stoptyping
4399% %D
4400% %D The user is warned with the suggestion to use \type {CAPITALS}. This suggestion
4401% %D is feasible, because \CONTEXT only defines lowcased macros. These are obsolete:
4402%
4403% \protected\def\showdefinederror#1#2%
4404%   {\writestatus\m!system{#1 #2 replaces a macro, use CAPITALS!}}
4405%
4406% \protected\def\checkdefined#1#2#3%
4407%   {\doifdefined{#3}{\showdefinederror{#2}{#3}}}
4408
4409%D \macros
4410%D   {GotoPar,GetPar}
4411%D
4412%D Typesetting a paragraph in a special way can be done by first grabbing the
4413%D contents of the paragraph and processing this contents grouped. The next macro
4414%D for instance typesets a paragraph in boldface.
4415%D
4416%D \starttyping
4417%D \def\remark#1\par%
4418%D   {\bgroup\bf#1\egroup}
4419%D \stoptyping
4420%D
4421%D This macro has to be called like
4422%D
4423%D \starttyping
4424%D \remark some text ... ending with \par
4425%D \stoptyping
4426%D
4427%D Instead of \type {\par} we can of course use an empty line. When we started
4428%D typesetting with \TEX, we already had produced lots of text in plain \ASCII. In
4429%D producing such simple formatted texts, we adopted an open layout, and when
4430%D switching to \TEX, we continued this open habit. Although \TEX\ permits a cramped
4431%D and badly formatted source, it adds to confusion and sometimes introduces errors.
4432%D So we prefer:
4433%D
4434%D \starttyping
4435%D \remark
4436%D
4437%D some text ... ending with an empty line
4438%D \stoptyping
4439%D
4440%D We are going to implement a mechanism that allows such open specifications. The
4441%D definition of the macro handling \type {\remark} becomes:
4442%D
4443%D \starttyping
4444%D \def\remark%
4445%D   {\BeforePar{\bgroup\bf}%
4446%D    \AfterPar{\egroup}%
4447%D    \GetPar}
4448%D \stoptyping
4449%D
4450%D A macro like \type {\GetPar} can be defined in several ways. The recent version,
4451%D the fourth one in a row, originally was far more complicated, but some
4452%D functionality has been moved to other macros.
4453%D
4454%D We start with the more simple but in some cases more appropriate alternative is
4455%D \type {\GotoPar}. This one leaves \type {\par} unchanged and is therefore more
4456%D robust. On the other hand, \type {\AfterPar} is not supported.
4457
4458\let\syst_helpers_par_before\relax
4459\let\syst_helpers_par_around\relax
4460
4461% \permanent\protected\def\dowithpar#1#2%
4462%   {\globalpushmacro\syst_helpers_par_around
4463%    \def\syst_helpers_par_around##1\par{#1##1#2\globalpopmacro\syst_helpers_par_around}%
4464%    \expandafter\syst_helpers_par_around\ignorepars}
4465
4466% \permanent\protected\def\dogotopar#1%
4467%   {\globalpushmacro\syst_helpers_par_before
4468%    \def\syst_helpers_par_before{#1\globalpopmacro\syst_helpers_par_before}%
4469%    \expandafter\syst_helpers_par_before\ignorepars}
4470
4471\permanent\protected\def\dowithpar#1#2%
4472  {\begingroup\aftergrouped{#1\dontleavehmode\wrapuppar{#2}}\expandafter\endgroup\ignorepars}
4473
4474\permanent\protected\def\dogotopar#1%
4475  {\begingroup\aftergrouped{#1}\expandafter\endgroup\ignorepars}
4476
4477\aliased\let\dogotoparcs\dogotopar
4478
4479\permanent\protected\def\dogotoparstart
4480  {\ignorepars}
4481
4482%D This is old and kind of obsolete:
4483
4484\newtoks\BeforePar
4485\newtoks\AfterPar
4486
4487\permanent\protected\def\GetPar
4488  {\normalexpanded
4489     {\dowithpar
4490        {\the\BeforePar
4491         \BeforePar\emptytoks}
4492        {\the\AfterPar
4493         \BeforePar\emptytoks
4494         \AfterPar\emptytoks}}}
4495
4496\permanent\protected\def\GotoPar
4497  {\normalexpanded
4498     {\dogotopar
4499        {\the\BeforePar
4500         \BeforePar\emptytoks}}}
4501
4502%D \macros
4503%D   {dowithpargument,dowithwargument}
4504%D
4505%D The next macros are a variation on \type {\GetPar}. When macros expect an
4506%D argument, it interprets a grouped sequence of characters a one token. While this
4507%D adds to robustness and less ambiguous situations, we sometimes want to be a bit
4508%D more flexible, or at least want to be a bit more tolerant to user input.
4509%D
4510%D We start with a commands that acts on paragraphs. This
4511%D command is called as:
4512%D
4513%D \starttyping
4514%D \dowithpargument\command
4515%D \dowithpargument{\command ... }
4516%D \stoptyping
4517%D
4518%D In \CONTEXT\ we use this one to read in the titles of chapters, sections etc. The
4519%D commands responsible for these activities accept several alternative ways of
4520%D argument passing. In these examples, the \type {\par} can be omitted when an
4521%D empty line is present.
4522%D
4523%D \starttyping
4524%D \command{...}
4525%D \command ... \par
4526%D \command
4527%D   {...}
4528%D \command
4529%D   ... \par
4530%D \stoptyping
4531
4532\let\syst_helpers_next_par\relax
4533\let\syst_helpers_next_arg\relax
4534
4535\permanent\protected\def\dowithpargument#1%
4536  {\def\syst_helpers_next_par##1 \par{#1{##1}}%
4537   \def\syst_helpers_next_arg##1{#1{##1}}%
4538   \doifelsenextbgroup\syst_helpers_next_arg{\doifelsenextchar\par{#1{}}\syst_helpers_next_par}}
4539
4540%D The \type {p} in the previous command stands for paragraph. When we want to act
4541%D upon words we can use the \type{w} alternative.
4542%D
4543%D \starttyping
4544%D \dowithwargument\command
4545%D \dowithwargument{... \command ...}
4546%D \stoptyping
4547%D
4548%D The main difference bwteen two alternatives is in the handling of \type {\par}'s.
4549%D This time the space token acts as a delimiter.
4550%D
4551%D \starttyping
4552%D \command{...}
4553%D \command ...
4554%D \command
4555%D   {...}
4556%D \command
4557%D   ...
4558%D \stoptyping
4559
4560\let\syst_helpers_next_war\relax
4561\let\syst_helpers_next_arg\relax
4562
4563\permanent\protected\def\dowithwargument#1%
4564  {\def\syst_helpers_next_war##1 {#1{##1}}%
4565   \def\syst_helpers_next_arg##1{#1{##1}}%
4566   \doifelsenextbgroup\syst_helpers_next_arg\syst_helpers_next_war}
4567
4568%D \macros
4569%D   {dorepeat,dorepeatwithcommand}
4570%D
4571%D When doing repetitive tasks, we stromgly advice to use \type {\dorecurse}. The
4572%D next alternative however, suits better some of the \CONTEXT\ interface commands.
4573%D
4574%D \starttyping
4575%D \dorepeat[n*\command]
4576%D \stoptyping
4577%D
4578%D The value of the used \COUNTER\ can be called within
4579%D \type{\command} by \type{\repeater}.
4580%D
4581%D A slightly different alternative is:
4582%D
4583%D \starttyping
4584%D \dorepeatwithcommand[n*{...}]\command
4585%D \stoptyping
4586%D
4587%D When we call for something like:
4588%D
4589%D \starttyping
4590%D \dorepeatwithcommand[3*{Hello}]\message
4591%D \stoptyping
4592%D
4593%D we get ourselves three \type {\message{Hello}} messages in a row. In both
4594%D commands, the \type {n*} is optional. When this specification is missing, the
4595%D command executes once.
4596
4597\permanent\protected\def\dorepeatwithcommand[#1]%
4598  {\syst_helpers_repeat_with_command#1*\empty*\relax}
4599
4600\def\syst_helpers_repeat_with_command#1*#2#3*#4\relax#5%
4601  {\ifx#2\empty\syst_helpers_repeat_with_command_again[#1]#5\else\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5\fi}
4602
4603\def\syst_helpers_repeat_with_command_indeed#1#2#3#4%
4604  {\ifx#2\empty % redundant but gives cleaner extensions
4605     #4{#1}%
4606   \orelse\ifnum#1<\zerocount
4607    %\normalexpanded{\dorecurse{\number-\number#1}}{#4{-#2#3}}%
4608     \dorecurse{-#1}{#4{-#2#3}}%
4609   \orelse\ifx#2+%
4610     \dorecurse{#1}{#4{#3}}%
4611   \else
4612     \dorecurse{#1}{#4{#2#3}}%
4613   \fi}
4614
4615\def\syst_helpers_repeat_with_command_again[#1]#2%
4616  {#2{#1}}
4617
4618%D The extension hook permits something like:
4619%D
4620%D \starttyping
4621%D \bgroup
4622%D
4623%D \catcode`\*=\superscriptcatcode
4624%D
4625%D \gdef\syst_helpers_repeat_with_command_again[#1]%
4626%D   {\redodorepeatwithcommand#1*\empty*\relax}
4627%D
4628%D \gdef\redodorepeatwithcommand#1*#2#3*#4\relax#5%
4629%D   {\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5}
4630%D
4631%D \egroup
4632%D \stoptyping
4633%D
4634%D although one may wonder if changing the catcode of \type {*} is wise.
4635
4636%D \macros
4637%D   {doifstringinstringelse}
4638%D
4639%D The next macro is meant for situations where both strings are macros. This save
4640%D some unneeded expansion. But now we just alias.
4641
4642\aliased\let\doifelsestringinstring\doifelseinstring
4643\aliased\let\doifstringinstringelse\doifelseinstring
4644
4645%D \macros
4646%D   {appendtoks,prependtoks,appendtoksonce,prependtoksonce,
4647%D    doifintokselse,flushtoks,dotoks}
4648%D
4649%D We use tokenlists sparsely within \CONTEXT, because the comma separated lists are
4650%D more suitable for the user interface. Nevertheless we have:
4651%D
4652%D \starttyping
4653%D (\doglobal) \appendtoks ... \to\tokenlist
4654%D (\doglobal) \prependtoks ... \to\tokenlist
4655%D (\doglobal) \flushtoks\tokenlist
4656%D             \dotoks\tokenlist
4657%D \stoptyping
4658%D
4659%D These macros are clones of the ones implemented in page~378 of Knuth's \TEX book.
4660
4661\newtoks\t_syst_helpers_scratch
4662
4663\lettonothing\m_syst_helpers_scratch
4664
4665\permanent\protected\def\appendtoks#1\to#2%
4666  {\ifrelax\dodoglobal
4667     \expandafter\toksapp
4668   \else
4669     \resetglobal
4670     \expandafter\gtoksapp
4671   \fi#2{#1}}
4672
4673\permanent\protected\def\prependtoks#1\to#2%
4674  {\ifrelax\dodoglobal
4675     \expandafter\tokspre
4676   \else
4677     \resetglobal
4678     \expandafter\gtokspre
4679   \fi#2{#1}}
4680
4681\permanent\protected\def\appendtoksonce#1\to#2%
4682  {\ifhasxtoks{#1}#2\else
4683     \toksapp#2{#1}%
4684   \fi}
4685
4686\permanent\protected\def\prependtoksonce#1\to#2%
4687  {\ifhasxtoks{#1}#2\else
4688     \tokspre#2{#1}%
4689   \fi}
4690
4691% Soon (check usage):
4692%
4693% \permanent\protected\def\appendtoks #1\to#2{\toksapp#2{#1}}
4694% \permanent\protected\def\prependtoks#1\to#2{\tokspre#2{#1}}
4695%
4696% \permanent\protected\def\appendtoksonce #1\to#2{\ifhasxtoks{#1}#2\else\toksapp#1{#1}\fi}
4697% \permanent\protected\def\prependtoksonce#1\to#2{\ifhasxtoks{#1}#2\else\tokspre#2{#1}\fi}
4698
4699%D The test macro:
4700
4701\permanent\protected\def\doifelseintoks#1#2% #1 en #2 zijn toks
4702  {\ifhasxtoks#1#2%
4703     \expandafter\firstoftwoarguments
4704   \else
4705     \expandafter\secondoftwoarguments
4706   \fi}
4707
4708\aliased\let\doifintokselse\doifelseintoks
4709
4710%D Moved from \type {lxml-ini.tex} to here. This one is for generators that collect
4711%D stuff piecewise, which is sometimes hard on mechanisms that grab content using
4712%D delimiters:
4713%D
4714%D \starttyping
4715%D \startcollecting
4716%D \startcollect \bTABLE \stopcollect
4717%D     \startcollect \bTR \stopcollect
4718%D         \startcollect \bTD \stopcollect
4719%D         \startcollect   foo\stopcollect
4720%D         \startcollect \eTD \stopcollect
4721%D         \startcollect \bTD \stopcollect
4722%D         \startcollect   bar\stopcollect
4723%D         \startcollect \eTD \stopcollect
4724%D     \startcollect \eTR \stopcollect
4725%D \startcollect \eTABLE \stopcollect
4726%D \stopcollecting
4727%D \stoptyping
4728
4729\newtoks \collectingtoks
4730
4731\permanent\protected\lettonothing\stopcollect
4732\permanent\protected\lettonothing\stopexpandedcollect
4733
4734\permanent\protected\def\startcollect        #1\stopcollect        {\toksapp \collectingtoks{#1}}
4735\permanent\protected\def\startexpandedcollect#1\stopexpandedcollect{\etoksapp\collectingtoks{#1}}
4736
4737\permanent\protected\def\startcollecting{\collectingtoks\emptytoks}
4738\permanent\protected\def\stopcollecting {\the\collectingtoks}
4739
4740\permanent\protected\def\collect        {\toksapp \collectingtoks}
4741\permanent\protected\def\collectexpanded{\etoksapp\collectingtoks}
4742
4743%D A nice one too:
4744
4745% {\scratchtoks{abc} \removetoks b\from\scratchtoks [\the\scratchtoks]}
4746% {\scratchtoks{abc} \removetoks x\from\scratchtoks [\the\scratchtoks]}
4747% {\scratchtoks{} \removetoks x\from\scratchtoks [\the\scratchtoks]}
4748% {\scratchtoks{xaa} \removetoks x\from\scratchtoks [\the\scratchtoks]}
4749% {\scratchtoks{a\relax b} \removetoks \relax\from\scratchtoks [\showthe\scratchtoks]}
4750
4751\let\syst_helpers_remove_toks\relax
4752
4753\permanent\protected\def\removetoks#1\from#2%
4754  {\def\syst_helpers_remove_toks##1#1##2\empty\empty\empty##3^^^^0004%
4755     {\def\m_syst_string_one{##3}%
4756      \ifempty\m_syst_string_one#2{##1}\else#2{##1##2}\fi}%
4757   \expandafter\syst_helpers_remove_toks\the#2\empty\empty\empty#1\empty\empty\empty^^^^0004}
4758
4759%D Also:
4760
4761\permanent\protected\def\appendetoks#1\to#2%
4762  {\ifrelax\dodoglobal
4763     \expandafter\etoksapp
4764   \else
4765     \resetglobal
4766     \expandafter\xtoksapp
4767   \fi#2{#1}}
4768
4769\permanent\protected\def\prependetoks#1\to#2%
4770  {\ifrelax\dodoglobal
4771     \expandafter\etokspre
4772   \else
4773     \resetglobal
4774     \expandafter\xtokspre
4775   \fi#2{#1}}
4776
4777%D Hm.
4778
4779\permanent\protected\def\flushtoks#1% nb: can reassign to #1 again, hence the indirectness
4780  {\t_syst_helpers_scratch#1\relax
4781   \dodoglobal#1\emptytoks
4782   \the\t_syst_helpers_scratch\relax}
4783
4784\aliased\let\dotoks\the
4785
4786%D \macros
4787%D   {beforesplitstring,aftersplitstring}
4788%D
4789%D These both commands split a string at a given point in two
4790%D parts, so \type{x.y} becomes \type{x} or \type{y}.
4791%D
4792%D \starttyping
4793%D \beforesplitstring test.tex\at.\to\filename
4794%D \aftersplitstring  test.tex\at.\to\extension
4795%D \stoptyping
4796%D
4797%D The first routine looks (and is indeed) a bit simpler than the second one. The
4798%D alternative looking more or less like the first one did not always give the
4799%D results we needed. Both implementations show some insight in the manipulation of
4800%D arguments.
4801
4802\let\syst_helpers_split_string\relax
4803
4804\permanent\protected\def\beforesplitstring#1\at#2\to#3%
4805  {\def\syst_helpers_split_string##1#2##0^^^^0004% no #- as we need to count
4806     {\ifarguments
4807        \lettonothing#3%
4808      \or
4809        \lettonothing#3%
4810      \else
4811        \def#3{##1}%
4812     \fi}%
4813   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}
4814
4815\permanent\protected\def\aftersplitstring#1\at#2\to#3%
4816  {\def\syst_helpers_split_string##0#2##2^^^^0004% no #- as we need to count
4817     {\ifarguments
4818        \lettonothing#3%
4819      \or
4820        \def#3{#1}%
4821      \else
4822        \def#3{##2}%
4823     \fi}%
4824   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}
4825
4826%D \macros
4827%D   {splitstring,greedysplitstring}
4828%D
4829%D A bonus macro.
4830
4831\permanent\protected\def\splitstring#1\at#2\to#3\and#4%
4832  {\def\syst_helpers_split_string##1#2##2^^^^0004%
4833     {\ifarguments
4834        \lettonothing#3*
4835        \lettonothing#4*
4836      \or
4837        \def#3{#1}%
4838        \lettonothing#4%
4839      \else
4840        \def#3{##1}%
4841        \def#4{##2}%
4842     \fi}%
4843   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}
4844
4845\permanent\protected\def\greedysplitstring#1\at#2\to#3\and#4%
4846  {\def\syst_helpers_split_string##1#2##2^^^^0004%
4847     {\ifarguments
4848        \lettonothing#3%
4849        \lettonothing#4%
4850      \or
4851        \def#3{#1}%
4852        \lettonothing#4%
4853      \else
4854        \def#3{##1}%
4855        \def#4{##2}%
4856        \def\syst_helpers_split_string####1#2####2^^^^0004%
4857          {\ifarguments
4858           \or
4859           \else
4860             \expandafter\def\expandafter#3\expandafter{#3####1}%
4861             \def#4{####2}%
4862             \syst_helpers_split_string####2^^^^0004\ignorearguments\ignorearguments
4863          \fi}%
4864        \syst_helpers_split_string##2^^^^0004\ignorearguments\ignorearguments
4865     \fi}%
4866   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}
4867
4868%D \macros
4869%D   {beforetestandsplitstring,
4870%D    aftertestandsplitstring,
4871%D    testandsplitstring}
4872
4873\aliased\let\beforetestandsplitstring\beforesplitstring
4874
4875\permanent\protected\def\aftertestandsplitstring#1\at#2\to#3%
4876  {\def\syst_helpers_split_string##0#2##2^^^^0004% no #- as we need to count
4877     {\ifarguments
4878        \lettonothing#3%
4879      \or
4880        \lettonothing#3%
4881      \else
4882        \def#3{##2}%
4883     \fi}%
4884   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}
4885
4886\permanent\protected\def\testandsplitstring#1\at#2\to#3\and#4%
4887  {\def\syst_helpers_split_string##1#2##2^^^^0004%
4888     {\ifarguments
4889        \lettonothing#3%
4890        \lettonothing#4%
4891      \or
4892        \lettonothing#3%
4893        \lettonothing#4%
4894      \else
4895        \def#3{##1}%
4896        \def#4{##2}%
4897     \fi}%
4898   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}
4899
4900%D \macros
4901%D   {splitatperiod, splitatcomma, splitatasterisk, splitatcolon, splitatcolons}
4902
4903\protected\def\syst_helpers_splitatperiod    #1.#2.#-^^^^0004#3#4{\def #3{#1}\def #4{#2}}
4904\protected\def\syst_helpers_splitatcomma     #1,#2,#-^^^^0004#3#4{\def #3{#1}\def #4{#2}}
4905\protected\def\syst_helpers_splitatasterisk  #1*#2*#-^^^^0004#3#4{\def #3{#1}\def #4{#2}}
4906\protected\def\syst_helpers_splitatcolon     #1:#2:#-^^^^0004#3#4{\def #3{#1}\def #4{#2}}
4907\protected\def\syst_helpers_splitatcolons  #1::#2::#-^^^^0004#3#4{\edef#3{#1}\edef#4{#2}}
4908
4909\permanent\protected\def\splitatperiod  #1{\normalexpanded{\syst_helpers_splitatperiod  #1}..^^^^0004}
4910\permanent\protected\def\splitatcomma   #1{\normalexpanded{\syst_helpers_splitatcomma   #1},,^^^^0004}    % not at ", "
4911\permanent\protected\def\splitatasterisk#1{\normalexpanded{\syst_helpers_splitatasterisk#1}**^^^^0004}
4912\permanent\protected\def\splitatcolon   #1{\normalexpanded{\syst_helpers_splitatcolon   #1}::^^^^0004}
4913\permanent\protected\def\splitatcolons  #1{\normalexpanded{\syst_helpers_splitatcolons  #1}::::^^^^0004}
4914
4915%D \macros
4916%D   {removesubstring}
4917%D
4918%D A first application of the two routines defined above is:
4919%D
4920%D \starttyping
4921%D \removesubstring-\from first-last\to\nothyphenated
4922%D \stoptyping
4923%D
4924%D Which in terms of \TEX\ looks like:
4925
4926\permanent\protected\def\removesubstring#1\from#2\to#3%
4927  {\splitstring#2\at#1\to\m_syst_string_one\and\m_syst_string_two
4928   \dodoglobal\def#3{\m_syst_string_one\m_syst_string_two}}
4929
4930%D \macros
4931%D   {appendtocommalist,prependtocommalist,
4932%D    addtocommalist,removefromcommalist}
4933%D
4934%D When working with comma separated lists, one sooner or later want the tools to
4935%D append or remove items from such a list. When we add an item, we first check if
4936%D it's already there. This means that every item in the list is unique.
4937%D
4938%D \starttyping
4939%D \addtocommalist      {alfa}  \name
4940%D \addtocommalist      {beta}  \name
4941%D \addtocommalist      {gamma} \name
4942%D \removefromcommalist {beta}  \name
4943%D \stoptyping
4944%D
4945%D These commands can be prefixed with \type {\doglobal}. The implementation of the
4946%D second command is more complecated, because we have to take leading spaces into
4947%D account. Keep in mind that users may provide lists with spaces after the commas.
4948%D When one item is left, we also have to get rid of trailing spaces.
4949%D
4950%D \starttyping
4951%D \def\words{alfa, beta, gamma, delta}
4952%D \def\words{alfa,beta,gamma,delta}
4953%D \stoptyping
4954%D
4955%D Removing an item takes more time than adding one. A fast appending alternative,
4956%D without any testing, is also provided:
4957%D
4958%D \starttyping
4959%D \appendtocommalist  {something} \name
4960%D \prependtocommalist {something} \name
4961%D \stoptyping
4962%D
4963%D This can be implemented as follows:
4964%D
4965%D \starttyping
4966%D \def\appendtocommalist#1#2%
4967%D   {\ifx#2\empty
4968%D      \dodoglobal\edef#2{#1}%
4969%D    \else % no test on empty
4970%D      \dodoglobal\edef#2{#2,#1}%
4971%D    \fi}
4972%D
4973%D \def\prependtocommalist#1#2%
4974%D   {\ifx#2\empty
4975%D      \dodoglobal\edef#2{#1}%
4976%D    \else % no test on empty
4977%D      \dodoglobal\edef#2{#1,#2}%
4978%D    \fi}
4979%D \stoptyping
4980%D
4981%D The faster alternatives are:
4982
4983\permanent\protected\def\appendtocommalist#1#2%
4984  {\dodoglobal\edef#2{\ifempty#2\else#2,\fi#1}}
4985
4986\permanent\protected\def\prependtocommalist#1#2%
4987  {\dodoglobal\edef#2{#1\ifempty#2\else,#2\fi}}
4988
4989\permanent\protected\def\addtocommalist#1#2% {item} \cs
4990  {\rawdoifelseinset{#1}#2\resetglobal
4991     {\dodoglobal\edef#2{\ifempty#2\else#2,\fi#1}}}
4992
4993\permanent\protected\def\pretocommalist#1#2% {item} \cs
4994  {\rawdoifelseinset{#1}#2\resetglobal
4995     {\dodoglobal\edef#2{#1\ifempty#2\else,#2\fi}}}
4996
4997\permanent\protected\def\robustdoifelseinset#1#2%
4998  {\edef\m_syst_string_one{\detokenize\expandafter{\normalexpanded{#1}}}%
4999   \edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#2}}}%
5000   \rawdoifelseinset\m_syst_string_one\m_syst_string_two}
5001
5002\aliased\let\robustdoifinsetelse\robustdoifelseinset
5003
5004\permanent\protected\def\robustaddtocommalist#1#2% {item} \cs
5005  {\robustdoifelseinset{#1}#2\resetglobal
5006     {\dodoglobal\edef#2{\ifempty#2\else#2,\fi#1}}}
5007
5008\permanent\protected\def\robustpretocommalist#1#2% {item} \cs
5009  {\robustdoifelseinset{#1}#2\resetglobal
5010     {\dodoglobal\edef#2{#1\ifempty#2\else,#2\fi}}}
5011
5012\permanent\protected\def\xsplitstring#1#2% \cs {str}
5013  {\def\syst_helpers_split_string##1,#2,##2,#2,##-\\%
5014     {\edef\m_syst_string_one{\syst_cleanedup_commalist_b##1\empty\empty\relax}%
5015      \edef\m_syst_string_two{\syst_cleanedup_commalist_a##2,,\relax}}%
5016   \expandafter\syst_helpers_split_string\expandafter,#1,,#2,,#2,\\}
5017
5018\def\syst_cleanedup_commalist_b#1#2\relax{\if#1,\else#1\fi#2}
5019\def\syst_cleanedup_commalist_a#1,,#-\relax{#1}
5020
5021\permanent\protected\def\removefromcommalist#1#2% to be sped up
5022  {\rawdoifelseinset{#1}#2%
5023     {\normalexpanded{\xsplitstring\noexpand#2{#1}}%
5024      \dodoglobal\edef#2%
5025        {\ifempty\m_syst_string_one
5026           \m_syst_string_two
5027         \else
5028           \m_syst_string_one\ifempty\m_syst_string_two\else,\m_syst_string_two\fi
5029         \fi}}
5030     \resetglobal}
5031
5032%D \macros
5033%D   {substituteincommalist}
5034%D
5035%D Slow but seldom used, so for the moment we stick to this implementation.
5036%D
5037%D \starttyping
5038%D \substituteincommalist{old}{new}{list}
5039%D \stoptyping
5040
5041\def\syst_helpers_substitute_in_comma_list_step#1%
5042  {\edef\m_syst_string_three{#1}%
5043   \ifx\m_syst_string_one\m_syst_string_three
5044     \ifempty\m_syst_string_two \else
5045       \edef\m_syst_string_four{\ifempty\m_syst_string_four\else\m_syst_string_four,\fi\m_syst_string_two}%
5046     \fi
5047   \else
5048     \edef\m_syst_string_four{\ifempty\m_syst_string_four\else\m_syst_string_four,\fi#1}%
5049   \fi}
5050
5051\permanent\protected\def\substituteincommalist#1#2#3% old, new, list (slooow)
5052  {\edef\m_syst_string_one{#1}%
5053   \edef\m_syst_string_two{#2}%
5054   \lettonothing\m_syst_string_four
5055   \normalexpanded{\rawprocesscommacommand[#3]}\syst_helpers_substitute_in_comma_list_step
5056   \let#3\m_syst_string_four}
5057
5058%D \macros
5059%D   {replaceincommalist}
5060%D
5061%D The next macro can be used to replace an indexed element in a commalist:
5062%D
5063%D \starttyping
5064%D \replaceincommalist\MyList{2}
5065%D \stoptyping
5066%D
5067%D Element~2 will be replaced by the current meaning of the macro \type
5068%D {\newcommalistelement}. The old meaning is saved in \type {\commalistelement}.
5069%D The replacement honors grouped items, like in:
5070%D
5071%D \starttyping
5072%D \def\MyList{a,b,c,d,e,f}   \replaceincommalist\MyList{3}
5073%D \def\MyList{a,b,c,d,e,f}   \replaceincommalist\MyList{3}
5074%D \def\MyList{a,{b,c},d,e,f} \replaceincommalist\MyList{3}
5075%D \def\MyList{a,b,c,{d,e,f}} \replaceincommalist\MyList{3}
5076%D \stoptyping
5077%D
5078%D This macro was used in the bibtex code (and is probably no longer needed).
5079
5080\newinteger\c_syst_helpers_comma_list_index
5081
5082\lettonothing\m_syst_helpers_comma_list_target
5083
5084\mutable\lettonothing\newcommalistelement
5085
5086\def\syst_helpers_replace_in_comma_list_step#1% we can use #+ here too
5087  {\ifnum\commalistcounter=\c_syst_helpers_comma_list_index\relax
5088     \ifempty\newcommalistelement\else
5089       \ifempty\m_syst_helpers_comma_list_target
5090         \let\m_syst_helpers_comma_list_target\newcommalistelement
5091       \else
5092         \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter
5093           \m_syst_helpers_comma_list_target\expandafter\expandafter\expandafter
5094             {\expandafter\m_syst_helpers_comma_list_target\expandafter,\newcommalistelement}%
5095       \fi
5096     \fi
5097     \def\commalistelement{#1}%
5098   \else
5099     \ifempty\m_syst_helpers_comma_list_target
5100       \ifx\nexttoken\bgroup % is known -)
5101         \def\m_syst_helpers_comma_list_target{{#1}}%
5102       \else
5103         \def\m_syst_helpers_comma_list_target{#1}%
5104       \fi
5105     \else
5106       \ifx\nexttoken\bgroup % is known -)
5107         \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,{#1}}%
5108       \else
5109         \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,#1}%
5110       \fi
5111     \fi
5112   \fi
5113   \advanceby\commalistcounter\plusone}
5114
5115\permanent\protected\def\replaceincommalist#1#2% #1 = commalistelement #2 = position starts at 1
5116  {\c_syst_helpers_comma_list_index#2\relax
5117   \lettonothing\m_syst_helpers_comma_list_target
5118   \lettonothing\commalistelement
5119   \commalistcounter\plusone
5120   \expandafter\processcommalist\expandafter[#1]\syst_helpers_replace_in_comma_list_step
5121   \dodoglobal\let#1\m_syst_helpers_comma_list_target}
5122
5123%D \macros
5124%D   {globalprocesscommalist}
5125%D
5126%D The commalist processing commands are characterized by the fact that the way they
5127%D handle expansion as well as the fact that they can be nested. This makes them
5128%D kind of useless for handling comma lists in alignments. In these situations the
5129%D next macro can be of use.
5130
5131\lettonothing\m_syst_helpers_comma_list_command_global
5132
5133\def\syst_helpers_comma_list_command_global_step#1,%
5134  {\if]#1\else
5135     \m_syst_helpers_comma_list_command_global{#1}%
5136     \expandafter\syst_helpers_comma_list_command_global_step
5137   \fi}
5138
5139\permanent\protected\def\globalprocesscommalist[#1]#2%
5140  {\glet\m_syst_helpers_comma_list_command_global#2%
5141   \expandafter\syst_helpers_comma_list_command_global_step#1,],}
5142
5143%D \macros
5144%D   {withoutpt,PtToCm,
5145%D    numberofpoints,dimensiontocount}
5146%D
5147%D We can convert point into centimeters with:
5148%D
5149%D \starttyping
5150%D \PtToCm{dimension}
5151%D \stoptyping
5152
5153% {\catcode`\.=\othercatcode
5154%  \catcode`\p=\othercatcode
5155%  \catcode`\t=\othercatcode
5156%  \gdef\WITHOUTPT#1pt{#1}}
5157%
5158% \def\withoutpt#1%
5159%   {\expandafter\WITHOUTPT#1}
5160%
5161% Okay, not really an impressive extension to the engine, but better than some macro
5162% that is demonstrating deeper understanding of \TEX. It's anyway a trivial extension
5163% anyway. There are actually many examples of very advanced macros and exposure of
5164% how clever one is that could be done cheap in the engine. It's just that at the time
5165% that \TEX\ was written, it made no sense to add a lot of that. After decades we know
5166% what extras we need.
5167
5168% \permanent\def\withoutpt#1{\thewithoutunit\dimexpr#1}
5169
5170\aliased\let\withoutpt\toscaled
5171
5172%D The capitals are needed because \type {p} and \type {t} have catcode~12, while
5173%D macronames only permit tokens with the catcode~11. As a result we cannot use the
5174%D \type {.group} primitives. Those who want to know more about this kind of
5175%D manipulations, we advice to study the \TEX book in detail. Because this macro
5176%D does not do any assignment, we can use it in the following way too.
5177
5178% \permanent\def\PtToCm#1{\thewithoutunit\dimexpr0.0351459804\dimexpr#1\relax\relax cm}
5179
5180\permanent\def\PtToCm#1{\toscaled\dimexpr0.0351459804\dimexpr#1\relax\relax cm}
5181
5182%D We also support:
5183%D
5184%D \starttyping
5185%D \numberofpoints   {dimension}
5186%D \dimensiontocount {dimension} {\count}
5187%D \stoptyping
5188%D
5189%D Both macros return a rounded number.
5190
5191% \dimensiontocount{10.49pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.49pt}
5192% \dimensiontocount{10.51pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.51pt}
5193
5194\permanent\def\dimensiontocount#1#2{#2\numexpr\dimexpr#1\relax/\maxcard\relax}
5195\permanent\def\numberofpoints    #1{\tointeger{\dimexpr#1\relax/\maxcard}}
5196
5197%D \macros
5198%D   {swapdimens,swapskips,swapcounts,swapmacros,
5199%D    globalswapdimens,globalswapcounts,globalswapmacros}
5200%D
5201%D Simple but effective are the next two macros. There name exactly states their
5202%D purpose.
5203
5204\newdimension\d_syst_helpers_swapped
5205\newgluespec \s_syst_helpers_swapped
5206\newinteger  \c_syst_helpers_swapped
5207\let         \m_syst_helpers_swapped\relax
5208
5209% \protected\def\swapdimens#1#2{\d_syst_helpers_swapped#1#1#2#2\d_syst_helpers_swapped}
5210% \protected\def\swapskips #1#2{\s_syst_helpers_swapped#1#1#2#2\s_syst_helpers_swapped}
5211% \protected\def\swapcounts#1#2{\c_syst_helpers_swapped#1#1#2#2\c_syst_helpers_swapped}
5212% \protected\def\swapmacros#1#2{\let\m_syst_helpers_swapped#1\let#1#2\let#2\m_syst_helpers_swapped}
5213
5214\aliased\let\swapdimens\swapcsvalues
5215\aliased\let\swapskips \swapcsvalues
5216\aliased\let\swapcounts\swapcsvalues
5217\aliased\let\swapmacros\swapcsvalues
5218
5219% \protected\def\globalswapdimens#1#2{\d_syst_helpers_swapped#1\global#1#2\global#2\d_syst_helpers_swapped}
5220% \protected\def\globalswapskips #1#2{\s_syst_helpers_swapped#1\global#1#2\global#2\s_syst_helpers_swapped}
5221% \protected\def\globalswapcounts#1#2{\c_syst_helpers_swapped#1\global#1#2\global#2\c_syst_helpers_swapped}
5222% \protected\def\globalswapmacros#1#2{\let\m_syst_helpers_swapped#1\glet#1#2\glet#2\m_syst_helpers_swapped}
5223
5224\permanent\protected\def\globalswapdimens{\global\swapcsvalues}
5225\permanent\protected\def\globalswapskips {\global\swapcsvalues}
5226\permanent\protected\def\globalswapcounts{\global\swapcsvalues}
5227\permanent\protected\def\globalswapmacros{\global\swapcsvalues}
5228
5229%D \macros
5230%D   {pushmacro,popmacro}
5231%D
5232%D Premature and a bit of beta, we offer:
5233%D
5234%D \starttyping
5235%D \pushmacro\macro
5236%D \popmacro\macro
5237%D \stoptyping
5238
5239\permanent\let\pushmacro\localpushmacro
5240\permanent\let\popmacro \localpopmacro
5241
5242%D \macros
5243%D   {setlocalhsize,distributedhsize}
5244%D
5245%D Sometimes we need to work with the \type{ \hsize} that is corrected for
5246%D indentation and left and right skips. The corrected value is available in \type
5247%D {\localhsize}, which needs to be calculated with \type {\setlocalhsize} first. %D
5248%D
5249%D \starttyping
5250%D \setlocalhsize        \hbox to \localhsize{...}
5251%D \setlocalhsize[-1em]  \hbox to \localhsize{...}
5252%D \setlocalhsize[.5ex]  \hbox to \localhsize{...}
5253%D \stoptyping
5254%D
5255%D These examples show us that an optional can be used. The value provided is added
5256%D to \type {\localhsize}.
5257
5258\newdimension\localhsize
5259
5260\permanent\protected\def\setlocalhsize % don't change !
5261  {\doifelsenextoptional
5262     \syst_helpers_set_local_hsize_yes
5263     \syst_helpers_set_local_hsize_nop}
5264
5265\def\syst_helpers_set_local_hsize_nop
5266  {\localhsize\availablehsize}
5267
5268\def\syst_helpers_set_local_hsize_yes[#1]%
5269  {\syst_helpers_set_local_hsize_nop
5270   \advanceby\localhsize#1\relax}
5271
5272\permanent\def\availablehsize
5273  {\dimexpr
5274     \hsize-\leftskip-\rightskip
5275     \ifnum\hangafter<\zerocount
5276       \ifdim\hangindent>\zeropoint-\else+\fi\hangindent
5277     \fi
5278   \relax}
5279
5280\permanent\def\distributedhsize#1#2#3%
5281  {\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax}
5282
5283\permanent\def\hsizefraction#1#2%
5284  {\dimexpr#1/#2\relax}
5285
5286%D \macros
5287%D   {doifvalue,doifnotvalue,doifelsevalue,
5288%D    doifnothing,doifsomething,doifelsenothing,
5289%D    doifvaluenothing,doifvaluesomething,doifelsevaluenothing}
5290%D
5291%D These \type {\if} commands can be used to access macros (or variables) that are
5292%D normally accessed by using \type {\getvalue}. Using these alternatives safes us
5293%D three tokens per call. Anyone familiar with the not||values ones, can derive
5294%D their meaning from the definitions.
5295
5296\permanent\protected\def\doifvalue#1#2%
5297  {\iftok{\csname#1\endcsname}{#2}%
5298     \expandafter\firstofoneargument
5299   \else
5300     \expandafter\gobbleoneargument
5301   \fi}
5302
5303\permanent\protected\def\doifnotvalue#1#2%
5304  {\iftok{\csname#1\endcsname}{#2}%
5305     \expandafter\gobbleoneargument
5306   \else
5307     \expandafter\firstofoneargument
5308   \fi}
5309
5310\permanent\protected\def\doifelsevalue#1#2%
5311  {\iftok{\csname#1\endcsname}{#2}%
5312     \expandafter\firstoftwoarguments
5313   \else
5314     \expandafter\secondoftwoarguments
5315   \fi}
5316
5317\permanent\protected\def\doifnothing#1%
5318  {\ifempty{#1}%
5319     \expandafter\firstofoneargument
5320   \else
5321     \expandafter\gobbleoneargument
5322   \fi}
5323
5324\permanent\protected\def\doifsomething#1%
5325  {\ifempty{#1}%
5326     \expandafter\gobbleoneargument
5327   \else
5328     \expandafter\firstofoneargument
5329   \fi}
5330
5331\permanent\protected\def\doifelsenothing#1%
5332  {\ifempty{#1}%
5333     \expandafter\firstoftwoarguments
5334   \else
5335     \expandafter\secondoftwoarguments
5336   \fi}
5337
5338\permanent\protected\def\doifelsesomething#1%
5339  {\ifempty{#1}%
5340     \expandafter\secondoftwoarguments
5341   \else
5342     \expandafter\firstoftwoarguments
5343   \fi}
5344
5345\permanent\protected\def\doifvaluenothing#1%
5346  {\ifempty{\csname#1\endcsname}%
5347     \expandafter\firstofoneargument
5348   \else
5349     \expandafter\gobbleoneargument
5350   \fi}
5351
5352\permanent\protected\def\doifvaluesomething#1%
5353  {\ifempty{\csname#1\endcsname}%
5354     \expandafter\gobbleoneargument
5355   \else
5356     \expandafter\firstofoneargument
5357   \fi}
5358
5359\permanent\protected\def\doifelsevaluenothing#1%
5360  {\ifempty{\csname#1\endcsname}%
5361     \expandafter\firstoftwoarguments
5362   \else
5363     \expandafter\secondoftwoarguments
5364   \fi}
5365
5366\aliased\let\doifvalueelse       \doifelsevalue
5367\aliased\let\doifnothingelse     \doifelsenothing
5368\aliased\let\doifsomethingelse   \doifelsesomething
5369\aliased\let\doifvaluenothingelse\doifelsevaluenothing
5370
5371%D \macros
5372%D   {doifemptyelsevalue, doifemptyvalue, doifnotemptyvalue}
5373%D
5374%D Also handy:
5375
5376\permanent\def\doifelseemptyvalue#1%
5377  {\expandafter\ifempty\csname#1\endcsname
5378     \expandafter\firstoftwoarguments
5379   \else
5380     \expandafter\secondoftwoarguments
5381   \fi}
5382
5383\aliased\let\doifemptyvalueelse\doifelseemptyvalue
5384
5385\permanent\def\doifemptyvalue#1%
5386  {\expandafter\ifempty\csname#1\endcsname
5387     \expandafter\firstofoneargument
5388   \else
5389     \expandafter\gobbleoneargument
5390   \fi}
5391
5392\permanent\def\doifnotemptyvalue#1%
5393  {\expandafter\ifempty\csname#1\endcsname
5394     \expandafter\gobbleoneargument
5395   \else
5396     \expandafter\firstofoneargument
5397   \fi}
5398
5399%D \macros
5400%D   {doifallcommonelse}
5401%D
5402%D A complete match of two sets can be tested with \type {\doifallcommonelse}, where
5403%D the first two arguments are sets.
5404
5405\let\syst_helpers_do_common_check_all\gobbleoneargument
5406
5407\def\syst_helpers_do_if_all_common_else#1#2#3#4% slow
5408  {\def\syst_helpers_do_common_check_all##1%
5409     {\ifinset{##1}{#4}\else\donefalse\fi
5410      \ifdone\else\expandafter\quitcommalist\fi}%
5411   \donetrue
5412   \processcommalist[#3]\syst_helpers_do_common_check_all
5413   \ifdone\expandafter#1\else\expandafter#2\fi}
5414
5415\permanent\protected\def\doifelseallcommon{\syst_helpers_do_if_all_common_else\firstoftwoarguments\secondoftwoarguments}
5416\permanent\protected\def\doifallcommon    {\syst_helpers_do_if_all_common_else\firstofoneargument \gobbleoneargument   }
5417\permanent\protected\def\doifnotallcommon {\syst_helpers_do_if_all_common_else\gobbleoneargument  \firstofoneargument  }
5418
5419\aliased\let\doifallcommonelse\doifelseallcommon
5420
5421%D \macros
5422%D   {DOIF,DOIFELSE,DOIFNOT}
5423%D
5424%D \TEX\ is case sensitive. When comparing arguments, this feature sometimes is less
5425%D desirable, for instance when we compare filenames. The next three alternatives
5426%D upcase their arguments before comparing them.
5427%D
5428%D \starttyping
5429%D \DOIF     {string1} {string2} {...}
5430%D \DOIFNOT  {string1} {string2} {...}
5431%D \DOIFELSE {string1} {string2} {then ...}{else ...}
5432%D \stoptyping
5433%D
5434%D We have to use a two||step implementation, because the
5435%D expansion has to take place outside \type{\uppercase}.
5436%D
5437%D These might end up as \LUA based helpers (i.e. consider these
5438%D obsolete:
5439
5440\protected\def\syst_helpers_do_IF#1#2%
5441  {\uppercase{\iftok{#1}{#2}}%
5442     \expandafter\firstofoneargument
5443   \else
5444     \expandafter\gobbleoneargument
5445   \fi}
5446
5447\protected\def\syst_helpers_do_IF_NOT#1#2%
5448  {\uppercase{\iftok{#1}{#2}}%
5449     \expandafter\gobbleoneargument
5450   \else
5451     \expandafter\firstofoneargument
5452   \fi}
5453
5454\protected\def\syst_helpers_do_IF_ELSE#1#2%
5455  {\uppercase{\iftok{#1}{#2}}%
5456     \expandafter\firstoftwoarguments
5457   \else
5458     \expandafter\secondoftwoarguments
5459   \fi}
5460
5461\protected\def\syst_helpers_do_IF_INSTRING_ELSE#1#2%
5462  {\uppercase{\doifelseinstring{#1}{#2}}}
5463
5464\permanent\protected\def\DOIF             #1#2{\normalexpanded{\syst_helpers_do_IF              {#1}{#2}}}% will become obsolete
5465\permanent\protected\def\DOIFNOT          #1#2{\normalexpanded{\syst_helpers_do_IF_NOT          {#1}{#2}}}% will become obsolete
5466\permanent\protected\def\DOIFELSE         #1#2{\normalexpanded{\syst_helpers_do_IF_ELSE         {#1}{#2}}}% will become obsolete
5467\permanent\protected\def\DOIFINSTRINGELSE #1#2{\normalexpanded{\syst_helpers_do_IF_INSTRING_ELSE{#1}{#2}}}% will become obsolete
5468
5469%D \macros
5470%D   {dosingleargumentwithset,
5471%D    dodoubleargumentwithset,dodoubleemptywithset,
5472%D    dotripleargumentwithset,dotripleemptywithset}
5473%D
5474%D These maybe too mysterious macros enable us to handle more than one setup at once.
5475%D
5476%D \starttyping
5477%D \dosingleargumentwithset \command[#1]
5478%D \dodoubleargumentwithset \command[#1][#2]
5479%D \dotripleargumentwithset \command[#1][#2][#3]
5480%D \dodoubleemptywithset    \command[#1][#2]
5481%D \dotripleemptywithset    \command[#1][#2][#3]
5482%D \stoptyping
5483%D
5484%D The first macro calls \type {\command[##1]} for each string in the set~\type
5485%D {#1}. The second one calls for \typ {\command [##1][#2]} and the third, well one
5486%D may guess. These commands support constructions like:
5487%D
5488%D \starttyping
5489%D \def\dodefinesomething[#1][#2]%
5490%D   {\getparameters[\??xx#1][#2]}
5491%D
5492%D \protected\def\definesomething%
5493%D   {\dodoubleargumentwithset\dodefinesomething}
5494%D \stoptyping
5495%D
5496%D Which accepts calls like:
5497%D
5498%D \starttyping
5499%D \definesomething[alfa,beta,...][variable=...,...]
5500%D \stoptyping
5501
5502\let\syst_helpers_with_set_step\relax % maybe push pop
5503
5504\permanent\tolerant\protected\def\dodoubleemptywithset#1#*[#2]#*[#3]%
5505  {\ifempty{#2}\else
5506     \def\syst_helpers_with_set_step##1{#1[##1][#3]}%
5507     \processcommalist[#2]\syst_helpers_with_set_step
5508   \fi}
5509
5510\permanent\tolerant\protected\def\dotripleemptywithset#1#*[#2]#*[#3]#*[#4]%
5511  {\ifempty{#2}\else
5512     \def\syst_helpers_with_set_step##1{#1[##1][#3][#4]}%
5513     \processcommalist[#2]\syst_helpers_with_set_step
5514   \fi}
5515
5516\aliased\let\dodoubleargumentwithset\dodoubleemptywithset
5517\aliased\let\dotripleargumentwithset\dotripleemptywithset
5518
5519%D \macros
5520%D   {stripcharacters,stripspaces}
5521%D
5522%D The next command was needed first when we implemented the \CONTEXT\ interactivity
5523%D macros. When we use labeled destinations, we often cannot use all the characters
5524%D we want. We therefore strip some of the troublemakers, like spaces, from the
5525%D labels before we write them to the \DVI||file, which passes them to for instance
5526%D a \POSTSCRIPT\ file.
5527%D
5528%D \starttyping
5529%D \stripspaces\from\one\to\two
5530%D \stoptyping
5531%D
5532%D Both the old string \type {\one} and the new one \type {\two} are expanded. This
5533%D command is a special case of:
5534%D
5535%D \starttyping
5536%D \stripcharacter\char\from\one\to\two
5537%D \stoptyping
5538%D
5539%D As we can see below, spaces following a control sequence are to enclosed in \type
5540%D {{}}.
5541
5542\let\syst_helpers_strip_character\relax
5543
5544\lettonothing\m_syst_helpers_strip_character
5545
5546\permanent\protected\def\stripcharacter#1\from#2\to#3%
5547  {\def\syst_helpers_strip_character##1#1##2\end
5548     {\edef\m_syst_helpers_strip_character{\m_syst_helpers_strip_character##1}%
5549      \doifnotempty{##2}{\syst_helpers_strip_character##2\end}}%
5550   \lettonothing\m_syst_helpers_strip_character
5551   \edef\m_syst_string_one{#2}%
5552   \expandafter\syst_helpers_strip_character\m_syst_string_one#1\end
5553   \dodoglobal\let#3\m_syst_helpers_strip_character}
5554
5555\permanent\protected\def\stripspaces\from#1\to#2% will become \unspacestring#1\from#2
5556  {\stripcharacter{ }\from#1\to#2}
5557
5558%D \macros
5559%D   {unspacestring}
5560%D
5561%D The next macro does the same but is more compatible with other macros, like \type
5562%D {\convert...}.
5563
5564\permanent\protected\def\unspacestring#1\to#2%
5565  {\stripcharacter{ }\from#1\to#2}
5566
5567%D \macros
5568%D   {executeifdefined}
5569%D
5570%D \CONTEXT\ uses one auxiliary file for all data concerning tables of contents,
5571%D references, two||pass optimizations, sorted lists etc. This file is loaded as
5572%D many times as needed. During such a pass we skip the commands thate are of no use
5573%D at that moment. Because we don't want to come into trouble with undefined
5574%D auxiliary commands, we call the macros in a way similar to \type {\getvalue}. The
5575%D next macro take care of such executions and when not defined, gobbles the
5576%D unwanted arguments.
5577%D
5578%D \starttyping
5579%D \executeifdefined{name}\gobbleoneargument
5580%D \stoptyping
5581%D
5582%D We can of course gobble more arguments using the appropriate gobbling command.
5583
5584\permanent\def\executeifdefined#1% #2 / never change this one again
5585  {\ifcsname#1\endcsname
5586     \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument
5587   \else
5588     \expandafter\firstofoneargument
5589   \fi}
5590
5591%D This one also has the advantage that it is fully expandable and that it can be
5592%D used after an assignment.
5593
5594%D \macros
5595%D   {doifsomespaceelse}
5596%D
5597%D The next command checks a string on the presence of a space and executed a
5598%D command accordingly.
5599%D
5600%D \starttyping
5601%D \doifsomespaceelse {tekst} {then ...} {else ...}
5602%D \stoptyping
5603%D
5604%D We use this command in \CONTEXT\ for determing if an argument must be broken into
5605%D words when made interactive. Watch the use of \type {\noexpand}.
5606
5607%D Is this one still needed?
5608
5609% \def\syst_helpers_if_some_space_else#1 #2#3^^^^0004{\if\noexpand#2@}
5610%
5611% \def\doifelsesomespace#1%                     % #2#3%
5612%   {\syst_helpers_if_some_space_else#1 @ @^^^^0004% #3\else#2\fi}
5613%      \expandafter\secondoftwoarguments
5614%    \else
5615%      \expandafter\firstoftwoarguments
5616%    \fi}
5617
5618\permanent\edef\doifelsesomespace#1%
5619  {\noexpand\ifhastok\space{#1}%
5620     \noexpand\expandafter\noexpand\firstoftwoarguments
5621   \noexpand\else
5622     \noexpand\expandafter\noexpand\secondoftwoarguments
5623   \noexpand\fi}
5624
5625\aliased\let\doifsomespaceelse\doifelsesomespace
5626
5627%D \macros
5628%D   {processseparatedlist}
5629%D
5630%D Maybe a bit late, but here is a more general version of the \type
5631%D {\processcommalist} command. This time we don't handle nesting but accept
5632%D arbitrary seperators.
5633%D
5634%D \starttyping
5635%D \processseparatedlist[list][separator]\command
5636%D \stoptyping
5637%D
5638%D One can think of things like:
5639%D
5640%D \starttyping
5641%D \processseparatedlist[alfa+beta+gamma][+]\message
5642%D \stoptyping
5643%D
5644%D We want to handle all situations, like:
5645%D
5646%D \startbuffer
5647%D \processseparatedlist[{aap noot}]  [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
5648%D \processseparatedlist[{aap} {noot}][ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
5649%D \processseparatedlist[aap {noot}]  [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
5650%D \processseparatedlist[aap noot]    [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
5651%D \stopbuffer
5652%D
5653%D \typebuffer \getbuffer
5654%D
5655%D Therefore we smuggle a \type {\relax} in front of the argument, which we remove
5656%D afterwards.
5657
5658\let\syst_helpers_process_separated_list_step\relax
5659
5660% \def\syst_helpers_process_separated_list#1]#*[#2]#3%
5661%    {\def\syst_helpers_process_separated_list_step##1##2#2%
5662%       {\def\m_syst_string_one{##2}% suggested by VZ
5663%        \if]##1%
5664%          \let\syst_helpers_process_separated_list_step\relax
5665%        \orelse\ifx\blankspace\m_syst_string_one
5666%          #3{##1}%
5667%        \orelse\if]##2%
5668%          \let\syst_helpers_process_separated_list_step\relax
5669%        \else
5670%          #3{##1##2}%
5671%        \fi
5672%        \syst_helpers_process_separated_list_step}%
5673%     \expandafter\syst_helpers_process_separated_list_step\gobbleoneargument#1#2]#2}
5674
5675% \def\syst_helpers_process_separated_list#1]#*[#2]#3%
5676%    {\def\syst_helpers_process_separated_list_step##1##2#2%
5677%       {\def\m_syst_string_one{##2}% suggested by VZ
5678%        \if]##1%
5679%        \orelse\ifx\blankspace\m_syst_string_one
5680%          #3{##1}%
5681%          \expandafter\syst_helpers_process_separated_list_step
5682%        \orelse\if]##2%
5683%        \else
5684%          #3{##1##2}%
5685%          \expandafter\syst_helpers_process_separated_list_step
5686%        \fi
5687%        }%
5688%     \expandafter\syst_helpers_process_separated_list_step\gobbleoneargument#1#2]#2}
5689
5690% \permanent\protected\def\processseparatedlist[%
5691%   {\syst_helpers_process_separated_list\relax}
5692
5693\permanent\protected\def\processseparatedlist[#+]#*[#2]#3%
5694   {\tolerant\def\syst_helpers_process_separated_list_step##1#2%
5695      {\ifarguments\or
5696         #3{##1}%
5697         \expandafter\syst_helpers_process_separated_list_step
5698       \fi}%
5699    \syst_helpers_process_separated_list_step#1\ignorearguments\ignorearguments}
5700
5701%D \macros
5702%D   {processlist}
5703%D
5704%D An even more general list processing macro is the following one:
5705%D
5706%D \starttyping
5707%D \processlist{beginsym}{endsym}{separator}\docommand list
5708%D \stoptyping
5709%D
5710%D This one supports arbitrary open and close symbols as well as user defined
5711%D separators.
5712%D
5713%D \starttyping
5714%D \processlist(){=>}\docommand(a=>b=>c=>d)
5715%D \stoptyping
5716
5717\let\syst_helpers_process_any_list       \relax
5718\let\syst_helpers_process_any_list_indeed\relax
5719\let\syst_helpers_process_any_list_step  \relax
5720
5721\permanent\protected\def\processlist#1#2#3#4% no blank skipping !
5722  {\def\syst_helpers_process_any_list_indeed##1#2%
5723     {\def\syst_helpers_process_any_list_step####1####2#3%
5724        {\ifx#2####1%
5725           \let\syst_helpers_process_any_list_step\relax
5726         \orelse\ifx#2####2%
5727           \let\syst_helpers_process_any_list_step\relax
5728         \else
5729           #4{####1####2}%
5730         \fi
5731         \syst_helpers_process_any_list_step}%
5732      \expandafter\syst_helpers_process_any_list_step\gobbleoneargument##1#3#2#3}%
5733   \def\syst_helpers_process_any_list#1%
5734     {\syst_helpers_process_any_list_indeed\relax}%
5735    \syst_helpers_process_any_list}
5736
5737%D \macros
5738%D   {processassignlist}
5739%D
5740%D Is possible to combine an assignment list with one containing keywords.
5741%D Assignments are treated accordingly, keywords are treated by \type {\command}.
5742%D
5743%D \starttyping
5744%D \processassignlist[...=...,...=...,...]\commando
5745%D \stoptyping
5746%D
5747%D This command can be integrated in \type {\getparameters}, but we decided best not
5748%D to do so.
5749
5750\let\syst_helpers_process_assign_list_assign\gobbleoneoptional
5751\let\syst_helpers_process_assign_list_step  \gobbleoneargument
5752
5753\permanent\protected\def\processassignlist#1[#2]#3%
5754  {\def\syst_helpers_process_assign_list_assign[##1=##-=##2]%
5755     {\iftok{##2}{\relax}#3{##1}\fi}%
5756   \def\syst_helpers_process_assign_list_step##1%
5757     {\syst_helpers_process_assign_list_assign[##1==\relax]}%
5758   \processcommalist[#2]\syst_helpers_process_assign_list_step}
5759
5760%D \macros
5761%D   {untextargument
5762%D    untexcommand}
5763%D
5764%D When manipulating data(bases) and for instance generating index entries, the next
5765%D three macros can be of help:
5766%D
5767%D \starttyping
5768%D \untextargument{...}\to\name
5769%D \untexcommand  {...}\to\name
5770%D \stoptyping
5771%D
5772%D They remove braces and backslashes and give us something to sort.
5773
5774\lettonothing\m_syst_helpers_untexed
5775
5776\permanent\protected\def\untexsomething
5777  {\begingroup
5778   \catcode\leftbraceasciicode \ignorecatcode
5779   \catcode\rightbraceasciicode\ignorecatcode
5780   \escapechar\minusone
5781   \syst_helpers_untex_something}
5782
5783\def\syst_helpers_untex_something#1#2\to#3%
5784  {\doglobal#1#2\to\m_syst_helpers_untexed
5785   \endgroup
5786   \let#3\m_syst_helpers_untexed}
5787
5788\permanent\protected\def\untexargument{\untexsomething\convertargument}
5789\permanent\protected\def\untexcommand {\untexsomething\convertcommand}
5790
5791%D \macros
5792%D   {ScaledPointsToBigPoints,ScaledPointsToWholeBigPoints}
5793%D
5794%D One characteristic of \POSTSCRIPT\ and \PDF\ is that both used big points (\TEX's
5795%D bp). The next macros convert points and scaled points into big points. The magic
5796%D factor $72/72.27$ can be found in most \TEX\ related books.
5797%D
5798%D \starttyping
5799%D \ScaledPointsToBigPoints      {number} \target
5800%D \ScaledPointsToWholeBigPoints {number} \target
5801%D \stoptyping
5802
5803\aliased\let\tobigpoints     \clf_tobigpoints      % todo: permanent at lua end
5804\aliased\let\towholebigpoints\clf_towholebigpoints % todo: permanent at lua end
5805
5806\permanent\protected\def\PointsToBigPoints           #1#2{\edef#2{\tobigpoints     #1}}             % can be avoided
5807\permanent\protected\def\PointsToWholeBigPoints      #1#2{\edef#2{\towholebigpoints#1}}             % can be avoided
5808\permanent\protected\def\ScaledPointsToBigPoints     #1#2{\edef#2{\tobigpoints     #1\scaledpoint}} % obsolete
5809\permanent\protected\def\ScaledPointsToWholeBigPoints#1#2{\edef#2{\towholebigpoints#1\scaledpoint}} % obsolete
5810
5811%D \macros
5812%D   {PointsToReal}
5813%D
5814%D Points can be stripped from their suffix by using \type {\withoutpt}. The next
5815%D macro enveloppes this macro.
5816%D
5817%D \starttyping
5818%D \PointsToReal {dimension} \target
5819%D \stoptyping
5820
5821% \permanent\protected\def\PointsToReal#1#2{\edef#2{\thewithoutunit\dimexpr#1}}
5822
5823\permanent\protected\def\PointsToReal#1#2{\edef#2{\toscaled#1}}
5824
5825%D \macros
5826%D  {dontleavehmode}
5827%D
5828%D Sometimes when we enter a paragraph with some command, the first token gets the
5829%D whole first line. We can prevent this by saying:
5830%D
5831%D \starttyping
5832%D \dontleavehmode
5833%D \stoptyping
5834%D
5835%D This command is used in for instance the language module \type {lang-ini}. The
5836%D first version was:
5837%D
5838%D \starttyping
5839%D \def\dontleavehmode{\ifhmode\orelse\ifmmode\else$ $\fi}
5840%D \stoptyping
5841%D
5842%D Next, Taco came with a better alternative (using mathsurround):
5843%D
5844%D \starttyping
5845%D \def\dontleavehmode
5846%D   {\ifhmode\orelse\ifmmode\else
5847%D      {\mathsurround\zeropoint\everymath\emptytoks$ $}%
5848%D    \fi}
5849%D \stoptyping
5850%D
5851%D And finaly we got the following alternative, one that avoids interfering grouping
5852%D at the cost of a box.
5853%D
5854%D \starttyping
5855%D \newbox\b_syst_helpers_dlh
5856%D
5857%D \protected\def\dontleavehmode
5858%D   {\ifhmode\orelse\ifmmode\else
5859%D      \setbox\b_syst_helpers_dlh\hbox{\mathsurround\zeropoint\everymath\emptytoks$ $}\unhbox\b_syst_helpers_dlh
5860%D    \fi}
5861%D \stoptyping
5862%D
5863%D But, as we run a recent version of \TEX, we can use the new primitive:
5864
5865% \untraced\aliased\let\dontleavehmode\quitvmode % defined in syst-ini.mkxl
5866
5867%D \macros
5868%D   {utfupper, utflower, uppercasestring, lowercasestring}
5869%D
5870%D The names tell what they do:
5871%D
5872%D \starttyping
5873%D \uppercasestring somestring\to\somestring
5874%D \lowercasestring somestring\to\somestring
5875%D \stoptyping
5876%D
5877%D The first argument may be a \type{\macro}.
5878%D
5879%D These macros are sort of obsolete as we never use uppercase this way. But
5880%D nevertheless we provide them:
5881
5882\permanent\def\utfupper#1{\clf_upper{#1}} % expandable
5883\permanent\def\utflower#1{\clf_lower{#1}} % expandable
5884
5885\permanent\protected\def\uppercasestring#1\to#2{\dodoglobal\edef#2{\clf_upper{#1}}}
5886\permanent\protected\def\lowercasestring#1\to#2{\dodoglobal\edef#2{\clf_lower{#1}}}
5887
5888%D \macros
5889%D   {handletokens}
5890%D
5891%D With the next macro we enter a critical area of macro expansion. What we want is
5892%D a macro that looks like:
5893%D
5894%D \starttyping
5895%D \handletokens some tokens\with \somemacro
5896%D \stoptyping
5897%D
5898%D A bonus example:
5899%D
5900%D \starttyping
5901%D \hbox{\handletokens tekst en meer tekst\with\ruledhbox}
5902%D
5903%D \def\weetikveel#1{\if#1\blankspace\space\else\ruledhbox{#1}\fi}
5904%D
5905%D \hbox{\handletokens tekst en meer tekst\with\weetikveel}
5906%D \stoptyping
5907
5908%D \macros
5909%D   {counttoken,counttokens}
5910%D
5911%D For the few occasions that we want to know the number of specific tokens in a
5912%D string, we can use:
5913%D
5914%D \starttyping
5915%D \counttoken  token\in string\to \somecount
5916%D \counttokens          string\to \somecount
5917%D \stoptyping
5918%D
5919%D This macro, that for instance is used in \type {cont-tab}, takes a real counter.
5920%D The macro can be preceded by \type {\doglobal}.
5921
5922\def\syst_helpers_count_token#1% obeys {}
5923  {\def\m_syst_string_three{#1}%
5924   \ifx\m_syst_string_two\m_syst_string_three \else
5925     \ifx\m_syst_string_one\m_syst_string_three
5926       \advanceby\privatescratchcounter\plusone
5927     \fi
5928     \expandafter\syst_helpers_count_token
5929   \fi}
5930
5931\permanent\protected\def\counttoken#1\in#2\to#3%
5932  {\privatescratchcounter\zerocount
5933   \def\m_syst_string_one{#1}%
5934   \def\m_syst_string_two{\end}%
5935   \syst_helpers_count_token#2\end
5936   \dodoglobal#3\privatescratchcounter}
5937
5938\permanent\protected\def\counttokens#1\to#2%
5939  {\privatescratchcounter\zerocount
5940   \def\syst_helpers_count_token##1{\advanceby\privatescratchcounter\plusone}%
5941   \handletokens#1\with\syst_helpers_count_token
5942   \dodoglobal#2\privatescratchcounter}
5943
5944%D \macros
5945%D   {splitofftokens}
5946%D
5947%D Running this one not always gives the expected results. Consider for instance the
5948%D macro for which I originally wrote this token handler.
5949
5950\let\syst_helpers_split_off_tokens\gobbleoneargument
5951
5952\permanent\protected\def\splitofftokens#1\from#2\to#3% slow but hardly used
5953  {\ifnum#1>\zerocount
5954     \privatescratchcounter#1\relax
5955     \def\syst_helpers_split_off_tokens##1%
5956       {\ifnum\privatescratchcounter>\zerocount
5957          \advanceby\privatescratchcounter \minusone
5958          \edef#3{#3##1}%
5959        \fi}%
5960   % \lettonothing#3% #3 can be #2, so:
5961     \expandafter\let\expandafter#3\expandafter\empty
5962     \expandafter\handletokens#2\with\syst_helpers_split_off_tokens
5963   \else
5964     \edef#3{#2}%
5965   \fi}
5966
5967%D This macro can be called like:
5968%D
5969%D \startbuffer[example]
5970%D \splitofftokens10\from01234567 890123456789\to\test [\test]
5971%D \stopbuffer
5972%D
5973%D up there. The reason for this is not that logical but follows from \TEX's
5974%D However, the characters that we expect to find in \type {\test} just don't show
5975%D sometimes mysterious way of expanding. Look at this:
5976%D
5977%D \startbuffer[next]
5978%D \def\next{a} \edef\test{\next}                                          [\test]
5979%D \let\next=b  \edef\test{\test\next}                                     [\test]
5980%D \let\next=c  \edef\test{\next}                                          [\test]
5981%D \let\next=d  \edef\test{\test\next}                                     [\test]
5982%D \let\next=e  \expandafter\edef\expandafter\test\expandafter{\test\next} [\test]
5983%D \stopbuffer
5984%D
5985%D \typebuffer[next]
5986%D
5987%D Careful reading shows that inside an \type {\edef} macro's that are \type {\let}
5988%D are not expanded!
5989%D
5990%D \unprotect\getbuffer[next]\protect
5991%D
5992%D That's why we finally end up with a macro that looks ahead by using an
5993%D assignment, this time by using \type {\futurelet}, and grabbing an argument as
5994%D well. That way we can handle the sentinal, a blank space and grouped tokens.
5995
5996\mutable\lettonothing\nexthandledtoken % part of public interface
5997
5998\let\syst_helpers_handle_tokens_command\relax
5999
6000\protected\def\syst_helpers_handle_tokens
6001  {\futurelet\nexthandledtoken\syst_helpers_handle_tokens_indeed}
6002
6003\permanent\protected\def\handletokens#1\with#2%
6004  {\gdef\syst_helpers_handle_tokens_command{#2}% permits more complex #2's
6005   \syst_helpers_handle_tokens#1\end}
6006
6007\def\syst_helpers_handle_tokens_indeed
6008  {\ifx\nexthandledtoken\blankspace
6009     \expandafter\syst_helpers_handle_tokens_indeed_one
6010   \orelse\ifx\nexthandledtoken\end
6011     \expandafter\gobbletwoarguments % also gobble the \end
6012   \else
6013     \expandafter\syst_helpers_handle_tokens_indeed_two
6014   \fi *}
6015
6016\def\syst_helpers_handle_tokens_indeed_one * %
6017  {\syst_helpers_handle_tokens_command{ }\syst_helpers_handle_tokens}
6018
6019\def\syst_helpers_handle_tokens_indeed_two *#1%
6020  {\syst_helpers_handle_tokens_command{#1}\syst_helpers_handle_tokens}
6021
6022%D This macro is tested on:
6023%D
6024%D \def\xxx#1{[#1]}
6025%D
6026%D \startlines
6027%D \handletokens         abc\with\xxx
6028%D \handletokens       a b c\with\xxx
6029%D \handletokens     a  b  c\with\xxx
6030%D \handletokens      a{bc}d\with\xxx
6031%D \handletokens a\space bc \with\xxx
6032%D \stoplines
6033%D
6034%D And our previous example shows up as:
6035%D
6036%D \getbuffer[example]
6037
6038%D \macros
6039%D   {iftrialtypesetting, ifvisible}
6040%D
6041%D The next boolean is at first sight a strange one. Sometimes one does a trial
6042%D typesetting run, for instance to determine dimensions. Some mechanisms, like
6043%D object inclusion, can fail on such trials. Temporary setting the next boolean to
6044%D true, helps a lot. The second boolena can be used to inhibit processing
6045%D completely.
6046
6047\newif\ifvisible \visibletrue
6048
6049\newtoks\everysettrialtypesetting
6050\newtoks\everyresettrialtypesetting
6051
6052\permanent\protected\def\settrialtypesetting  {\expand\everysettrialtypesetting  } % obeys grouping so
6053\permanent\protected\def\resettrialtypesetting{\expand\everyresettrialtypesetting} % this one is seldom needed
6054
6055\aliased\let\iftrialtypesetting\iffalse % so we have no \trialtypesettingtrue|false in mkiv !
6056
6057\appendtoks \enforced\aliased\let\iftrialtypesetting\iftrue  \to \everysettrialtypesetting
6058\appendtoks \enforced\aliased\let\iftrialtypesetting\iffalse \to \everyresettrialtypesetting
6059
6060%D \macros
6061%D   {twodigitrounding}
6062%D
6063%D The next macro rounds a real number to two digits. They are probably no longer needed
6064%D but we keep them around for a while.
6065
6066\permanent\def\integerrounding   #1{\clf_rounded\zerocount{#1}}
6067\permanent\def\onedigitrounding  #1{\clf_rounded\plusone  {#1}}
6068\permanent\def\twodigitrounding  #1{\clf_rounded\plustwo  {#1}}
6069\permanent\def\threedigitrounding#1{\clf_rounded\plusthree{#1}}
6070
6071%D \macros
6072%D   {processcontent}
6073%D
6074%D This macro is first used in the tabulation macros.
6075%D
6076%D \starttyping
6077%D \protected\def\starthans%
6078%D   {\processcontent{stophans}\test{\message{\test}\wait}}
6079%D \stoptyping
6080
6081% \starttabulate[|||]
6082%     \NC \type{#} \NC # \NC \NR
6083% \stoptabulate
6084%
6085% \def\test#1%
6086%   {\starttabulate[|||]
6087%      \NC \type{#1} \NC #1 \NC \NR
6088%    \stoptabulate}
6089%
6090% \test{!}
6091
6092%% \permanent\protected\def\processcontent#1%
6093%%   {\begingroup\expandafter\syst_helpers_process_content\csname#1\endcsname}
6094
6095\protected\def\syst_helpers_process_content#1#2#3%
6096  {\protected\def\syst_helpers_process_content##1#1%
6097     {\endgroup\def#2{##1}#3}%
6098   \syst_helpers_process_content}
6099
6100\permanent\protected\def\processcontent#1%
6101  {\begingroup
6102   \catcode\hashasciicode\othercatcode
6103   \expandafter\syst_helpers_process_content\csname#1\endcsname}
6104
6105%D \macros
6106%D   {dogobblesingleempty, dogobbledoubleempty}
6107%D
6108%D These two macros savely grab and dispose two arguments. We also have a few
6109%D private ones defined earlier.
6110
6111\permanent\tolerant\protected\def\dogobbledoubleempty[#S#-]#*[#S#-]{}
6112\permanent\tolerant\protected\def\dogobblesingleempty        [#S#-]{}
6113
6114\aliased\let\gobblesingleempty\dogobblesingleempty % also used
6115\aliased\let\gobbledoubleempty\dogobbledoubleempty % also used
6116
6117%D \macros
6118%D   {setdimensionwithunit, freezedimensionwithunit}
6119%D
6120%D The next assignments are all valid:
6121%D
6122%D \starttyping
6123%D \setdimensionwithunit\scratchdimen{10}  {cm}
6124%D \setdimensionwithunit\scratchdimen{10cm}{cm}
6125%D \setdimensionwithunit\scratchdimen{10cm}{}
6126%D \freezedimensionwithunit\SomeWidth{\textwidth}
6127%D \freezedimensionwithunit\SomeDepth{\strutdp}
6128%D \stoptyping
6129%D
6130%D As an alternative for the next macro we can use a global assignment inside a box.
6131%D The \type {\empty}'s permits gobbling while preventing spurious \type {\relax}'s.
6132
6133\permanent\protected\def\setdimensionwithunit#1#2#3% number unit dimension / nice trick
6134  {\afterassignment\gobblefourarguments#1=#2#3pt\relax\empty\empty\empty\empty}
6135
6136\permanent\protected\def\freezedimensionwithunit#1#2%
6137  {\setdimensionwithunit\privatescratchdimen#1{#2}\edef#1{\the\privatescratchdimen}}
6138
6139%D \macros
6140%D   {doifsometokselse, doifsometoks}
6141%D
6142%D Not that fast I guess, but here's a way to test for token registers being empty.
6143
6144\permanent\protected\def\doifelsesometoks#1%
6145  {\iftok#1\emptytoks
6146     \expandafter\secondoftwoarguments
6147   \else
6148     \expandafter\firstoftwoarguments
6149   \fi}
6150
6151\permanent\protected\def\doifsometoks#1%
6152  {\iftok#1\emptytoks
6153     \expandafter\gobbleoneargument
6154   \else
6155     \expandafter\firstofoneargument
6156   \fi}
6157
6158\permanent\protected\def\doifemptytoks#1%
6159  {\iftok#1\emptytoks
6160     \expandafter\firstofoneargument
6161   \else
6162     \expandafter\gobbleoneargument
6163   \fi}
6164
6165\aliased\let\doifsometokselse\doifelsesometoks
6166
6167%D \macros
6168%D   {startstrictinspectnextcharacter}
6169%D
6170%D This one is for the bibliography module (still?):
6171
6172\let\syst_helpers_strict_inspect_next_character[
6173
6174\def\syst_helpers_strict_inspect_next_character% no user macro !
6175  {\ifx\nexttoken[%
6176     \expandafter\m_syst_action_yes
6177   \else
6178     \expandafter\m_syst_action_nop
6179   \fi}
6180
6181\permanent\protected\def\strictdoifelsenextoptional#1#2%
6182  {\def\m_syst_action_yes{#1}%
6183   \def\m_syst_action_nop{#2}%
6184   \futurelet\nexttoken\syst_helpers_strict_inspect_next_character}
6185
6186\aliased\let\strictdoifnextoptionalelse\strictdoifelsenextoptional
6187
6188%D \macros
6189%D   {gobblespacetokens}
6190%D
6191%D This macro needs a speed-up!
6192
6193%\def\gobblespacetokens
6194%  {\doifnextcharelse\empty\donothing\donothing} % no {}\do\do !
6195
6196\permanent\def\gobblespacetokens
6197  {\afterassignment\nexttoken\let\nexttoken=}
6198
6199%D \macros
6200%D   {verbatimargument}
6201%D
6202%D As the name says, this macro converts its argument to a (rather safe) string.
6203
6204\aliased\let\verbatimstring\detokenize
6205
6206%D These are needed in ordinal number conversions:
6207
6208\permanent\def\lastdigit#1%
6209  {\expandafter\thelastdigit\number#1\relax}
6210
6211\permanent\def\thelastdigit#1#2%
6212  {\ifrelax#2#1\else\expandafter\thelastdigit\expandafter#2\fi}
6213
6214\permanent\def\lasttwodigits#1%
6215  {\expandafter\thelasttwodigits\expandafter0\number#1\relax}
6216
6217\permanent\def\thelasttwodigits#1#2#3% 0 dig ... \relax
6218  {\ifrelax#3#1#2\else\expandafter\thelasttwodigits\expandafter#2\expandafter#3\fi}
6219
6220%D \macros
6221%D   {serializecommalist}
6222%D
6223%D Concatenate commalists:
6224
6225\let\syst_helpers_serialize_comma_list_step\relax
6226
6227\mutable\lettonothing\serializedcommalist
6228
6229\def\syst_helpers_serialize_comma_list_step#1%
6230  {\edef\serializedcommalist{\serializedcommalist#1}}
6231
6232\permanent\protected\def\serializecommalist[#1]%
6233  {\lettonothing\serializedcommalist
6234   \processcommacommand[#1]\syst_helpers_serialize_comma_list_step}
6235
6236%D \macros
6237%D   {purenumber}
6238%D
6239%D Sometimes we need control over when \TEX\ stops reading a number, especially in
6240%D full expandable macros where using \type {\relax} would lead to disasters.
6241%D
6242%D \starttyping
6243%D \ifodd\purenumber{...}\space ... \else ... \fi
6244%D \stoptyping
6245%D
6246%D Here we use a space as number delimiter in combination with a space- and
6247%D relax-less \type {\purenumber}. This macro works ok with \type {\the}, \type
6248%D {\number} as well as \ETEX's \type {\numexpr}.
6249
6250\permanent\def\purenumber#1{\expandafter\firstofoneargument\expandafter{\number#1}}
6251
6252%D \macros
6253%D   {filterfromvalue, filterfromnext}
6254%D
6255%D \starttyping
6256%D \setvalue{xx}{{A}{B}{C}}
6257%D
6258%D \filterfromvalue{xx}{3}{3}
6259%D \filterfromvalue{xx}{3}{2}
6260%D \filterfromvalue{xx}{3}{1}
6261%D \stoptyping
6262
6263% can be sped up with ignored arguments
6264
6265\def\syst_filter_from_next_yes#1%
6266  {\advanceby\scratchcounterone\plusone
6267   \ifnum\scratchcounterone=\scratchcountertwo
6268     \scratchtoks{#1}%
6269   \fi
6270   \ifnum\scratchcounterone=\scratchcounterthree
6271     \expandafter\syst_filter_from_next_nop
6272   \else
6273     \expandafter\syst_filter_from_next_yes
6274   \fi}
6275
6276\def\syst_filter_from_next_nop
6277  {\expandafter\endgroup
6278   \expandafter\endlocalcontrol
6279   \the\scratchtoks}
6280
6281\permanent\def\filterfromnext#1#2% max n {..}{..}{..}{..}
6282  {\beginlocalcontrol
6283   \begingroup
6284   \scratchcounterone   \zerocount
6285   \scratchcountertwo   #2%
6286   \scratchcounterthree #1%
6287   \syst_filter_from_next_yes}
6288
6289\permanent\def\filterfromvalue#1#2#3% max n {..}{..}{..}{..}
6290  {\beginlocalcontrol
6291   \begingroup
6292   \scratchcounterone   \zerocount
6293   \scratchcountertwo   #3%
6294   \scratchcounterthree #2%
6295   \expandafter\expandafter\expandafter\syst_filter_from_next_yes\csname#1\endcsname}
6296
6297%D \macros
6298%D   {definemeasure}
6299%D
6300%D \starttyping
6301%D \definemeasure[mywidth][\dimexpr(\textwidth-1cm)]
6302%D
6303%D ... \measure{mywidth} ...
6304%D \stoptyping
6305
6306\installsystemnamespace{measure}
6307
6308\permanent\tolerant\protected\def\definemeasure[#1]#*[#2]{\defcsname \??measure#1\endcsname{#2}}
6309\permanent\tolerant\protected\def\freezemeasure[#1]#*[#2]{\edefcsname\??measure#1\endcsname{\todimension{#2}}}
6310
6311\permanent\protected\def\setmeasure #1#2{\defcsname \??measure#1\endcsname{#2}}               % quick way
6312\permanent\protected\def\setgmeasure#1#2{\gdefcsname\??measure#1\endcsname{#2}}               % quick way
6313\permanent\protected\def\setemeasure#1#2{\edefcsname\??measure#1\endcsname{\todimension{#2}}} % quick way
6314\permanent\protected\def\setxmeasure#1#2{\xdefcsname\??measure#1\endcsname{\todimension{#2}}} % quick way
6315
6316\permanent\def\measure #1{\todimension{\ifcsname\??measure#1\endcsname\lastnamedcs\else\zeropoint\fi}}
6317\permanent\def\measured#1{\dimexpr    {\ifcsname\??measure#1\endcsname\lastnamedcs\else\zeropoint\fi}}
6318
6319% #2 could be omitted, but we want to support spaces
6320%
6321% \setmeasure {x}  {1cm}
6322% \setmeasure {xx} {1cm}
6323% \setmeasure {xxx}{1cm}
6324
6325%D \macros
6326%D   {definequantity}
6327%D
6328%D These do the same but for numbers.
6329
6330\installsystemnamespace{quantity}
6331
6332\permanent\tolerant\protected\def\definequantity[#1]#*[#2]{\defcsname \??quantity#1\endcsname{#2}}
6333\permanent\tolerant\protected\def\freezequantity[#1]#*[#2]{\edefcsname\??quantity#1\endcsname{\tointeger{#2}}}
6334
6335\permanent\protected\def\setquantity #1#2{\defcsname \??quantity#1\endcsname{#2}}             % quick way
6336\permanent\protected\def\setgquantity#1#2{\gdefcsname\??quantity#1\endcsname{#2}}             % quick way
6337\permanent\protected\def\setequantity#1#2{\edefcsname\??quantity#1\endcsname{\tointeger{#2}}} % quick way
6338\permanent\protected\def\setxquantity#1#2{\xdefcsname\??quantity#1\endcsname{\tointeger{#2}}} % quick way
6339
6340\permanent\def\quantity        {\the\quantitied}
6341\permanent\def\quantitied    #1{\numexpr\ifcsname\??quantity#1\endcsname\lastnamedcs\else\zeropoint\fi\relax}
6342\permanent\def\directquantity#1{\tointeger{#1}}
6343
6344% let\quantified\quantitied
6345
6346%D \macros
6347%D   {dividedsize}
6348%D
6349%D This one can be used inside a measure (used in m4all):
6350%D
6351%D \starttyping
6352%D \definemeasure[columnwidth][\dividebydsize\textwidth{1em}{3}]
6353%D \stoptyping
6354
6355\permanent\def\dividebydsize#1#2#3% size gap n
6356  {\dimexpr
6357     \ifnum\dimexpr#1\relax>\plusone
6358       (\dimexpr#1\relax-\numexpr#3-\plusone\relax\dimexpr#2\relax)/#3\else#1%
6359     \fi
6360   \relax}
6361
6362%D \macros
6363%D   {doifdimensionelse}
6364%D
6365%D This is a dirty one: we simply append a unit and discard it when needed. We no longer
6366%D use this in core code because we just use th econditional.
6367
6368\permanent\def\doifelsedimension#1%
6369  {\ifchkdim#1\or % or \ifchkdimension
6370     \expandafter\firstoftwoarguments
6371   \else
6372     \expandafter\secondoftwoarguments
6373   \fi}
6374
6375\aliased\let\doifdimensionelse\doifelsedimension
6376
6377%D Ok, here's another one, slower but seldom used. This one scans the text.
6378%D
6379%D \starttabulate[|Tc|Tc|]
6380%D \NC pt      \NC  \doifdimenstringelse     {pt}{yes}{no} \NC \NR
6381%D \NC 12pt    \NC  \doifdimenstringelse  {-12pt}{yes}{no} \NC \NR
6382%D \NC 1pt     \NC  \doifdimenstringelse    {1pt}{yes}{no} \NC \NR
6383%D \NC 12pt    \NC  \doifdimenstringelse   {12pt}{yes}{no} \NC \NR
6384%D \NC 12.0pt  \NC  \doifdimenstringelse {12.0pt}{yes}{no} \NC \NR
6385%D \NC -.12pt  \NC  \doifdimenstringelse {-.12pt}{yes}{no} \NC \NR
6386%D \NC .12pt   \NC  \doifdimenstringelse  {.12pt}{yes}{no} \NC \NR
6387%D \NC -12pt   \NC  \doifdimenstringelse  {-12pt}{yes}{no} \NC \NR
6388%D \NC -12.0pt \NC  \doifdimenstringelse{-12.0pt}{yes}{no} \NC \NR
6389%D \NC big     \NC  \doifdimenstringelse    {big}{yes}{no} \NC \NR
6390%D \NC 10      \NC  \doifdimenstringelse     {10}{yes}{no} \NC \NR
6391%D \NC 1       \NC  \doifdimenstringelse      {1}{yes}{no} \NC \NR
6392%D \stoptabulate
6393
6394\aliased\let\doifelsedimenstring\doifelsedimension
6395\aliased\let\doifdimenstringelse\doifelsedimenstring
6396
6397%D \macros
6398%D   {comparedimension,comparedimensioneps}
6399%D
6400%D We no longer use the \MKIV\ dirty trick. These are obsolete anyway.
6401
6402\newdimension\roundingeps \roundingeps=10sp
6403\newconstant \compresult
6404
6405\permanent\protected\def\comparedimension#1#2%
6406  {\compresult
6407     \ifcmpdim#1#2 % space wil be skipped
6408       \zerocount
6409     \or
6410       \plusone
6411     \else
6412       \plustwo
6413     \fi}
6414
6415\permanent\protected\def\comparedimensioneps#1#2% todo: use eps feature
6416  {\compresult
6417     \ifabsdim{(#1)-(#2)}<\roundingeps
6418       \zerocount
6419     \orelse\ifdim{#1}<{#2}%
6420       \plusone
6421     \else
6422       \plustwo
6423     \fi}
6424
6425% pretty ugly but fast
6426
6427% \copycsname xxx\endcsname\csname ..\endcsname
6428
6429\permanent\protected\def\copycsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter\csname}
6430
6431% \letcscsname    \crap               \csname ..\endcsname
6432% \letcsnamecs    \csname ..\endcsname\crap
6433% \letcsnamecsname\csname ..\endcsname\csname ..\endcsname
6434
6435\permanent\protected\def\letcscsname    {\expandafter\let\expandafter}
6436\permanent\protected\def\letcsnamecs    {\expandafter\let}
6437\permanent\protected\def\letcsnamecsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter}
6438
6439% Another one, add an item to a commalist, was only used in definesymbol
6440
6441\permanent\protected\def\addvalue#1#2% cs item
6442  {\ifcsname#1\endcsname\else\letcsname#1\endcsname\empty\fi
6443   \normalexpanded{\addtocommalist{#2}\expandafter\noexpand\csname#1\endcsname}}
6444
6445%D Are these ever used? Anyway, these variants are somewhat more efficient than
6446%D the \MKIV variants for larger strings.
6447
6448% A variant:
6449%
6450% \permanent\def\unspaced#1%
6451%   {\localcontrolled{\begingroup\catcode\spaceasciicode\ignorecatcode}%
6452%    \tokenized{#1}%
6453%    \localcontrolled{\endgroup}}
6454%
6455% but we can also do this:
6456
6457\permanent\def\unspaced#1%
6458  {\tokenized \s!catcodetable \ctdcatcodes {#1}}
6459
6460\permanent\protected\def\unspaceargument#1\to#2%
6461  {\edef#2{\tokenized \s!catcodetable \ctdcatcodes {#1}}}
6462
6463\permanent\protected\def\unspaceafter#1#2%
6464  {\expandafter#1\expandafter{\tokenized \s!catcodetable \ctdcatcodes {#2}}}
6465
6466\permanent\protected\def\doifelsehasspace#1%
6467  {\expandafter\ifhastok\space{#1}%
6468     \expandafter\firstoftwoarguments
6469   \else
6470     \expandafter\secondoftwoarguments
6471   \fi}
6472
6473\aliased\let\doifhasspaceelse\doifelsehasspace
6474
6475% this will replace loadfile once and alike !!! todo
6476
6477\installsystemnamespace{flag}
6478
6479\permanent\protected\def\setflag  #1{\dodoglobal\letcsname\??flag#1\endcsname\zerocount}
6480\permanent\protected\def\resetflag#1{\dodoglobal\letcsname\??flag#1\endcsname\plusone}
6481
6482\permanent\def\flag#1{\csname\??flag#1\endcsname}
6483
6484\permanent\def\doifelseflagged#1%
6485  {\expandafter\ifrelax\csname\??flag#1\endcsname
6486     \expandafter\secondoftwoarguments
6487   \orelse\ifcase\csname\??flag#1\endcsname
6488     \expandafter\firstoftwoarguments
6489   \else
6490     \expandafter\secondoftwoarguments
6491   \fi}
6492
6493\aliased\let\doifflaggedelse\doifelseflagged
6494
6495\permanent\def\doifnotflagged#1%
6496  {\expandafter\ifrelax\csname\??flag#1\endcsname
6497     \expandafter\firstofoneargument
6498   \orelse\ifcase\csname\??flag#1\endcsname
6499     \expandafter\gobbleoneargument
6500   \else
6501     \expandafter\firstofoneargument
6502   \fi}
6503
6504\permanent\protected\def\inheritparameter[#1]#2[#3]#4[#5]% tag tokey fromkey
6505  {\defcsname#1#3\expandafter\endcsname\expandafter{\csname#1#5\endcsname}}
6506
6507\def\syst_helpers_if_non_zero_positive_else#1#2\end % #3#4%
6508  {\ifrelax#1%
6509     \ifcase\privatescratchcounter
6510       \endgroup
6511       \doubleexpandafter\secondoftwoarguments
6512     \else
6513       \endgroup
6514       \doubleexpandafter\firstoftwoarguments
6515     \fi
6516   \else
6517      \endgroup
6518      \expandafter\secondoftwoarguments
6519   \fi}
6520
6521% used ?
6522
6523\permanent\def\doifelsenonzeropositive#1%
6524  {\begingroup\afterassignment\syst_helpers_if_non_zero_positive_else\privatescratchcounter=0#1\relax\empty\end}
6525
6526\aliased\let\doifnonzeropositiveelse\doifelsenonzeropositive
6527
6528%D Some old|-|time favourites:
6529
6530% \permanent\protected\def\dosetrawvalue #1#2#3{\defcsname #1#2\endcsname{#3}}
6531% \permanent\protected\def\dosetrawevalue#1#2#3{\edefcsname#1#2\endcsname{#3}}
6532% \permanent\protected\def\dosetrawgvalue#1#2#3{\gdefcsname#1#2\endcsname{#3}}
6533% \permanent\protected\def\dosetrawxvalue#1#2#3{\xdefcsname#1#2\endcsname{#3}}
6534%
6535% \permanent\protected\def\getrawparameters      {\dogetparameters\dosetrawvalue }
6536% \permanent\protected\def\getraweparameters     {\dogetparameters\dosetrawevalue}
6537% \permanent\protected\def\getrawgparameters     {\dogetparameters\dosetrawgvalue}
6538% \permanent\protected\def\getrawxparameters     {\dogetparameters\dosetrawxvalue}
6539%
6540% \permanent\protected\def\globalgetrawparameters{\dogetparameters\dosetrawgvalue} % obsolete
6541
6542\aliased\let\getrawparameters \getparameters  % obsolete
6543\aliased\let\getraweparameters\geteparameters % obsolete
6544\aliased\let\getrawgparameters\getgparameters % obsolete
6545\aliased\let\getrawxparameters\getxparameters % obsolete
6546
6547%D Sort of obsolete:
6548
6549\newinteger\c_syst_helpers_mod
6550
6551\permanent\protected\def\dosetmodulo#1#2#3%
6552  {\c_syst_helpers_mod#1\divideby\c_syst_helpers_mod#2\multiplyby\c_syst_helpers_mod#2%
6553   #3#1\advanceby#3-\c_syst_helpers_mod}
6554
6555\permanent\protected\def\dosetdivision#1#2#3%
6556  {#3#1\divideby#3 #2\relax}
6557
6558\permanent\protected\def\DoMod#1by#2to#3{\dosetmodulo  {#1}{#2}{#3}}
6559\permanent\protected\def\DoDiv#1by#2to#3{\dosetdivision{#1}{#2}{#3}}
6560
6561%D This is obsolete, just use \type {\unprotect} and \type {\protect} instead.
6562
6563% \def\syst_helpers_unprotected#1\par
6564%   {#1\protect}
6565%
6566% \permanent\protected\def\unprotected
6567%   {\unprotect
6568%    \syst_helpers_unprotected}
6569
6570\aliased\let\resettimer    \clf_resettimer  % todo: at lua end
6571\aliased\let\elapsedtime   \clf_elapsedtime % todo: at lua end
6572\aliased\let\elapsedseconds\elapsedtime
6573
6574\aliased\let\elapsedsteps\!!zerocount
6575
6576\permanent\protected\def\elapsedsteptime % unexpanded ! a bit useless but who knows ...
6577  {\clf_elapsedsteptime\elapsedsteps\relax}
6578
6579\newinteger\c_syst_helpers_test_feature_n
6580\newinteger\c_syst_helpers_test_feature_m
6581
6582\let\syst_helpers_test_feature_yes\relax
6583\let\syst_helpers_test_feature_nop\relax
6584
6585\permanent\def\currentfeaturetest{\the\c_syst_helpers_test_feature_n}
6586
6587\permanent\protected\def\testfeature#1#2%
6588  {\c_syst_helpers_test_feature_m\ifparameter#1\or#1\else\maxiterator\fi\relax
6589   \enforced\xdef\elapsedsteps{\the\c_syst_helpers_test_feature_m}%
6590   \def\syst_helpers_test_feature_yes
6591     {\advanceby\c_syst_helpers_test_feature_n\plusone
6592      \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else
6593        #2\expandafter\syst_helpers_test_feature_yes
6594      \fi}%
6595   \def\syst_helpers_test_feature_nop
6596     {\advanceby\c_syst_helpers_test_feature_n\plusone
6597      \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else
6598        \expandafter\syst_helpers_test_feature_nop
6599      \fi}%
6600   \retestfeature}
6601
6602\permanent\protected\def\retestfeature % timer support is new per 10/5/2005
6603  {\bgroup
6604   \ifcase\interactionmode\enforced\let\wait\relax\fi
6605   \clf_resettimer
6606   \c_syst_helpers_test_feature_n\zerocount
6607   \syst_helpers_test_feature_nop
6608   \clf_benchmarktimer
6609   \writestatus\m!system
6610     {starting feature test: %
6611      \the\c_syst_helpers_test_feature_m\space steps}%
6612   \c_syst_helpers_test_feature_n\zerocount
6613   \syst_helpers_test_feature_yes
6614   \writestatus\m!system
6615     {feature test done: %
6616      \the\c_syst_helpers_test_feature_m\space steps, %
6617      \clf_elapsedtime\space seconds, %
6618      \clf_elapsedsteptime\elapsedsteps\space\space per step}%
6619   \egroup}
6620
6621\permanent\protected\def\showtimer#1%
6622  {\writestatus{runtime}{\elapsedseconds\space s / #1}}
6623
6624\permanent\protected\def\testfeatureonce#1#2%
6625  {\begingroup
6626   \enforced\let\wait\relax
6627   \testfeature{#1}{#2}%
6628   \endgroup}
6629
6630%D \macros
6631%D   {freezedimenmacro}
6632%D
6633%D This macro is use as:
6634%D
6635%D \starttyping
6636%D \freezedimenmacro\leftmargindistance
6637%D \stoptyping
6638
6639\permanent\protected\def\freezedimenmacro#1%
6640  {\edef#1{\todimension{#1}}}
6641
6642%D The next macro negates a macro (dimension or number, or actually, whatever. It's
6643%D a typical example of \type {\if} usage:
6644%D
6645%D \starttyping
6646%D \if-\whatever \else-\whatever\fi => else => -whatever
6647%D \if--\whatever\else-\whatever\fi => then =>  whatever
6648%D \stoptyping
6649%D
6650%D Do we still need this? If not it will go away:
6651
6652\permanent\def\negated#1{\if-#1\else-#1\fi} % does only work in macros or text
6653
6654% \def\gobbleassigndimen#1\\{}
6655%
6656% \permanent\def\assigndimen#1#2%
6657%   {\afterassignment\gobbleassigndimen#1=#2\zeropoint\\}
6658
6659%D Maybe ... toksapp should deal with this ...
6660
6661\permanent\protected\def\appendvalue#1#2%
6662  {\edefcsname#1\endcsname{%
6663     \normalunexpanded\expandafter\expandafter\expandafter{\begincsname#1\endcsname}%
6664     \normalunexpanded{#2}}}
6665
6666\permanent\protected\def\prependvalue#1#2%
6667  {\edefcsname#1\endcsname{%
6668     \normalunexpanded{#2}%
6669     \normalunexpanded\expandafter\expandafter\expandafter{\begincsname#1\endcsname}}}
6670
6671\permanent\protected\def\appendgvalue #1#2{\global\appendvalue}
6672\permanent\protected\def\prependgvalue#1#2{\global\prependvalue}
6673
6674%D \macros
6675%D   {dowithrange}
6676%D
6677%D This one is for Mojca Miklavec, who made me aware of the fact that \type
6678%D {page-imp.tex} was not the best place to hide it.
6679%D
6680%D \startbuffer
6681%D \def\DoSomething#1{ [item #1] }
6682%D
6683%D \processranges[1,4:5]\DoSomething \par
6684%D \dowithrange  {1,4:5}\DoSomething \par
6685%D \stopbuffer
6686%D
6687%D \typebuffer \blank \getbuffer \blank
6688
6689%D We have a better splitter at the \LUA\ end.
6690
6691\integerdef\c_helpers_range_min    \zerocount
6692\integerdef\c_helpers_range_max    \zerocount
6693\integerdef\c_helpers_range_abs_min\zerocount
6694\integerdef\c_helpers_range_abs_max\zerocount
6695
6696\lettonothing\m_helpers_range_action
6697
6698\def\syst_helpers_with_range#1%
6699  {\splitstring#1\at:\to\m_syst_helpers_range_from\and\m_syst_helpers_range_to
6700   \ifx\m_syst_helpers_range_from\wildcardsymbol
6701     \edef\m_syst_helpers_range_from{\number\c_helpers_range_min}%
6702   \fi
6703   \ifx\m_syst_helpers_range_to\wildcardsymbol
6704     \edef\m_syst_helpers_range_to{\number\c_helpers_range_max}%
6705   \fi
6706   \ifempty\m_syst_helpers_range_to
6707     \let\m_syst_helpers_range_to\m_syst_helpers_range_from
6708   \fi
6709   \dostepwiserecurse\m_syst_helpers_range_from\m_syst_helpers_range_to\plusone{\m_helpers_range_action{##1}}}%
6710
6711\permanent\protected\def\processranges[#1]#2% #1= n:m,p,q:r
6712  {\def\m_helpers_range_action{#2}%
6713   \integerdef\c_helpers_range_min\zerocount
6714   \integerdef\c_helpers_range_max\zerocount
6715   \processcommacommand[#1]\syst_helpers_with_range}
6716
6717\permanent\protected\def\dowithrange#1#2% set action
6718  {\def\m_helpers_range_action{#2}%
6719   \integerdef\c_helpers_range_min\zerocount
6720   \integerdef\c_helpers_range_max\zerocount
6721   \processcommacommand[#1]\syst_helpers_with_range}
6722
6723\permanent\protected\def\dowithminmaxrange#1#2#3#4% min max set action
6724  {\def\m_helpers_range_action{#4}%
6725   \integerdef\c_helpers_range_min#1\relax
6726   \integerdef\c_helpers_range_max#2\relax
6727   \processcommacommand[#3]\syst_helpers_with_range}
6728
6729% todo: use the helper that we made in lua (sets)
6730
6731\def\syst_helpers_with_range_slice#1%
6732  {\splitstring#1\at:\to\m_syst_helpers_range_from\and\m_syst_helpers_range_to
6733   \ifx\m_syst_helpers_range_from\wildcardsymbol
6734     \edef\m_syst_helpers_range_from{\number\c_helpers_range_min}%
6735   \fi
6736   \ifx\m_syst_helpers_range_to\wildcardsymbol
6737     \edef\m_syst_helpers_range_to{\number\c_helpers_range_max}%
6738   \fi
6739   \ifempty\m_syst_helpers_range_to
6740     \let\m_syst_helpers_range_to\m_syst_helpers_range_from
6741   \fi
6742   \ifnum\m_syst_helpers_range_from<\zerocount
6743     \dostepwiserecurse
6744       \m_syst_helpers_range_from
6745       \m_syst_helpers_range_to
6746       {\ifnum\m_syst_helpers_range_from>\m_syst_helpers_range_to\minusone\else\plusone\fi}%
6747       {%(\the\numexpr\c_helpers_range_abs_max+##1+\plusone\relax)
6748        \m_helpers_range_action{\tointeger{\c_helpers_range_abs_max+##1+\plusone}}}%
6749   \else
6750     \dostepwiserecurse
6751       \m_syst_helpers_range_from
6752       \m_syst_helpers_range_to
6753       {\ifnum\m_syst_helpers_range_from>\m_syst_helpers_range_to\minusone\else\plusone\fi}
6754       {%(\the\numexpr\c_helpers_range_abs_min+##1-\plusone\relax)
6755        \m_helpers_range_action{\tointeger{\c_helpers_range_abs_min+##1-\plusone}}}%
6756   \fi}
6757
6758\permanent\protected\def\dowithminmaxrangeslice#1#2#3#4#5#6% absmin absmax min max set action
6759  {\def\m_helpers_range_action{#6}%
6760   \integerdef\c_helpers_range_abs_min#1\relax
6761   \integerdef\c_helpers_range_abs_max#2\relax
6762   \integerdef\c_helpers_range_min    #3\relax
6763   \integerdef\c_helpers_range_max    #4\relax
6764   \processcommacommand[#5]\syst_helpers_with_range_slice}
6765
6766% \def\DoSomething#1{ [item #1] }
6767% \dowithrange[1,4:5]\DoSomething
6768
6769%D \macros
6770%D   {ignoreimplicitspaces}
6771%D
6772%D \startbuffer
6773%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignorespaces}
6774%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b}
6775%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignoreimplicitspaces}
6776%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b}
6777%D \stopbuffer
6778%D
6779%D \typebuffer \getbuffer
6780
6781\permanent\protected\def\ignoreimplicitspaces
6782  {\doifelsenextchar\relax\relax\relax}
6783
6784% %D \macros
6785% %D   {processwords}
6786% %D
6787% %D Not that sophisticated but sometimes users (like in metafun).
6788%
6789% %D This will be overloaded.
6790%
6791% \def\syst_helpers_process_word#1 #2\s!e_o_t_token
6792%   {\doifsomething{#1}{\processword{#1} \syst_helpers_process_word#2 \s!e_o_t_token}}
6793%
6794% \def\processwords#1%
6795%   {\syst_helpers_process_word#1 \s!e_o_t_token}% no \unskip
6796%
6797% \let\processword\relax
6798
6799%D \macros
6800%D   {startnointerference}
6801%D
6802%D \starttyping
6803%D \startnointerference
6804%D all kind of code
6805%D \stopnointerference
6806%D \stoptyping
6807
6808\newbox\b_syst_helpers_no_interference
6809
6810\permanent\protected\def\startnointerference % not even grouped !
6811  {\setbox\b_syst_helpers_no_interference\vbox
6812   \bgroup}
6813
6814\permanent\protected\def\stopnointerference
6815  {\egroup
6816   \setbox\b_syst_helpers_no_interference\emptybox}
6817
6818%D A variant for \type {\executeifdefined}:
6819
6820\permanent\def\expandcheckedcsname#1#2% #2 is often a \xxxparameter  so let's expand it once
6821  {\normalexpanded{\noexpand\syst_helpers_expand_checked_csname{#1}{#2}}}
6822
6823\def\syst_helpers_expand_checked_csname#1#2#3%
6824  {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname}
6825
6826%D Signal. Some fonts have a char0 rendering so we need to make sure that it is not
6827%D set in the font! (This will be overloaded)
6828
6829\protected\def\signalcharacter{\char\zerocount} % \zwj
6830
6831% %D A few secial variants of commands defined here. Some more will be moved here
6832% %D e.g.from the table modules. This code is no longer needed.
6833%
6834% \permanent\def\dodirectdoubleempty#1#2% used in math (lookahead issues)
6835%   {\ifx#2[%
6836%      \expandafter\syst_helpers_direct_double_empty_one_yes
6837%    \else
6838%      \expandafter\syst_helpers_direct_double_empty_one_nop
6839%    \fi#1#2}
6840%
6841% \def\syst_helpers_direct_double_empty_one_yes#1[#2]#3%
6842%   {\ifx#3[\else\expandafter\syst_helpers_direct_double_empty_two_nop\fi#1[#2]#3}
6843%
6844% \def\syst_helpers_direct_double_empty_one_nop#1{#1[][]}
6845% \def\syst_helpers_direct_double_empty_two_nop#1[#2]{#1[#2][]}
6846
6847% %D Used in math definitions (in an \type {\edef}). This will be replaced.
6848% %D
6849% %D \startbuffer
6850% %D [\docheckedpair{}]
6851% %D [\docheckedpair{a}]
6852% %D [\docheckedpair{a,b}]
6853% %D [\docheckedpair{a,b,c}]
6854% %D \stopbuffer
6855% %D
6856% %D \typebuffer \startlines \getbuffer \stoplines
6857%
6858% \permanent\def\docheckedpair#1%
6859%   {\syst_helpers_checked_pair#1,,\s!e_o_t_token}
6860%
6861% \def\syst_helpers_checked_pair#1,#2,#-\s!e_o_t_token
6862%   {#1,#2}
6863
6864%D Here are some nasty helpers. They can be used to fill often expanded token
6865%D lists efficiently (see tabulate for an example).
6866
6867\permanent\def\constantnumber#1%
6868  {\ifcase#1\zerocount
6869   \or      \plusone
6870   \or      \plustwo
6871   \or      \plusthree
6872   \or      \plusfour
6873   \or      \plusfive
6874   \or      \plussix
6875   \or      \plusseven
6876   \or      \pluseight
6877   \or      \plusnine
6878   \or      \plusten
6879   \else    \number#1\relax\fi}
6880
6881\permanent\def\constantnumberargument#1%
6882  {\ifcase#1\zerocount
6883   \or      \plusone
6884   \or      \plustwo
6885   \or      \plusthree
6886   \or      \plusfour
6887   \or      \plusfive
6888   \or      \plussix
6889   \or      \plusseven
6890   \or      \pluseight
6891   \or      \plusnine
6892   \or      \plusten
6893   \else    {\number#1}\fi}
6894
6895% \permanent\def\constantdimen#1% takes register
6896%   {\ifdim#1=\zeropoint
6897%      \zeropoint
6898%    \else
6899%      \the#1\relax
6900%    \fi}
6901
6902\permanent\def\constantdimen#1% takes register
6903  {\ifzeropt#1\norelax
6904     \zeropoint
6905   \else
6906     \todimension#1\norelax
6907   \fi}
6908
6909% \permanent\def\constantdimenargument#1% takes register
6910%   {\ifdim#1=\zeropoint
6911%      \zeropoint
6912%    \else
6913%      {\the#1}%
6914%    \fi}
6915
6916\permanent\def\constantdimenargument#1%
6917  {\ifzeropt#1%\norelax
6918     \zeropoint
6919   \else
6920     {\todimension#1}%
6921   \fi}
6922
6923\permanent\def\constantemptyargument#1%
6924  {\ifempty#1%
6925     \noexpand\empty
6926   \else
6927     {#1}%
6928   \fi}
6929
6930%D \macros
6931%D   {getsubstring}
6932%D \startbuffer
6933%D
6934%D \getsubstring{4}{}{Who Wants This}
6935%D \getsubstring{4}{9}{Who Wants This}
6936%D \getsubstring{9}{-2}{Who Wants This}
6937%D \getsubstring{1}{5}{Who Wants This}
6938%D \stopbuffer
6939%D
6940%D \typebuffer
6941%D
6942%D \startlines
6943%D \getbuffer
6944%D \stoplines
6945
6946% expandable:
6947
6948\permanent\def\getsubstring#1#2#3{\clf_getsubstring{#3}{#1}{#2}}
6949
6950%D Other dimensions than pt (used in mb-mp)
6951
6952\permanent\def\converteddimen#1#2{\clf_converteddimen{#1}{#2}}
6953
6954%D Maybe (looks ugly):
6955%D
6956%D \starttyping
6957%D \doifcase {foo}
6958%D     {bar}     {BAR}
6959%D     {foo}     {FOO}
6960%D     {default} {DEFAULT}
6961%D
6962%D \doifcase {foo}
6963%D     {bar}     {BAR}
6964%D     {foo}     {\doifcase {bar}
6965%D                     {bar}     {BAR}
6966%D                     {foo}     {FOO}
6967%D                     {default} {DEFAULT}
6968%D               }
6969%D     {default} {DEFAULT}
6970%D \stoptyping
6971
6972% \doifcase {\btxfoundname{author}}
6973%     {author}  {\btxflush{author}}
6974%     {editor}  {\texdefinition{btx:apa:editor-or-editors}}
6975%     {title}   {\texdefinition{btx:apa:title-subtitle-type}}
6976%     {default} {\btxflush{author}}
6977
6978% \protected\def\doifcase#1%
6979%   {\edef\m_case_asked{#1}%
6980%    \syst_aux_case}
6981%
6982% \def\syst_aux_case#1%
6983%   {\edef\m_case_temp{#1}%
6984%    \ifx\m_case_temp\m_case_asked
6985%       \expandafter\syst_aux_case_yes
6986%    \orelse\ifx\m_case_temp\s!default
6987%       \expandafter\firstofoneargument
6988%    \else
6989%       \expandafter\syst_aux_case_nop
6990%    \fi}
6991%
6992% \def\syst_aux_skip#1#2%
6993%   {\edef\m_case_temp{#1}%
6994%    \ifx\m_case_temp\s!default
6995%      \expandafter\syst_aux_done
6996%    \else
6997%      \expandafter\syst_aux_skip
6998%    \fi}
6999%
7000% \def\syst_aux_case_yes#1%
7001%   {\def\syst_aux_done{#1}%
7002%    \syst_aux_skip}
7003%
7004% \def\syst_aux_case_nop#1%
7005%   {\syst_aux_case}
7006
7007%D \macros
7008%D   {ntimes}
7009%D
7010%D some repetition:
7011%D
7012%D \startbuffer
7013%D \ntimes{*}{20}
7014%D \stopbuffer
7015%D
7016%D \typebuffer \blank gives: \getbuffer \blank
7017%D
7018%D This is not real fast but quite okay:
7019
7020%def\ntimes#1#2{\ifnum#2>\zerocount#1\ntimes{#1}{\numexpr#2-\plusone\relax}\fi} % 1.72
7021\permanent\def\ntimes#1#2{\clf_ntimes{#1}{#2}}                                  % 0.33
7022
7023%D Experiment (sometimes looks nicer in code):
7024
7025\permanent\protected\def\sameargumentscondition#1#2%
7026  {\edef\m_syst_string_one{#1}%
7027   \edef\m_syst_string_two{#2}%
7028   \ifx\m_syst_string_one\m_syst_string_two}
7029
7030\permanent\protected\def\emptyargumentcondition#1%
7031  {\edef\m_syst_string_one{#1}%
7032   \ifempty\m_syst_string_one}
7033
7034%D New (also serves as an example):
7035%D
7036%D \starttyping
7037%D \commandflags\defineframed
7038%D \stoptyping
7039
7040\permanent\def\commandflags#1%
7041  {\beginlocalcontrol\begingroup\scratchtoks\emptytoks\donefalse
7042     \ifflags#1=   \frozenflagcode\etoksapp\scratchtoks{\ifdone \space\fi    frozen}\donetrue\fi
7043     \ifflags#1=\permanentflagcode\etoksapp\scratchtoks{\ifdone \space\fi permanent}\donetrue\fi
7044     \ifflags#1=\immutableflagcode\etoksapp\scratchtoks{\ifdone \space\fi immutable}\donetrue\fi
7045     \ifflags#1=\primitiveflagcode\etoksapp\scratchtoks{\ifdone \space\fi primitive}\donetrue\fi
7046     \ifflags#1=  \mutableflagcode\etoksapp\scratchtoks{\ifdone \space\fi   mutable}\donetrue\fi
7047     \ifflags#1=\noalignedflagcode\etoksapp\scratchtoks{\ifdone \space\fi noaligned}\donetrue\fi
7048     \ifflags#1= \instanceflagcode\etoksapp\scratchtoks{\ifdone \space\fi  instance}\donetrue\fi
7049    %\ifflags#1= \reservedflagcode\etoksapp\scratchtoks{\ifdone \space\fi  reserved}\donetrue\fi
7050     \ifflags#1= \tolerantflagcode\etoksapp\scratchtoks{\ifdone \space\fi  tolerant}\donetrue\fi
7051     \ifflags#1=\protectedflagcode\etoksapp\scratchtoks{\ifdone \space\fi protected}\donetrue\fi
7052   \expandafter\endgroup\expandafter\endlocalcontrol\the\scratchtoks}
7053
7054%D \macros
7055%D   {resetmacros}
7056%D
7057%D The next macro can be used to reset a macro:
7058%D
7059%D \starttyping
7060%D \resetmacros[startfoo,\stopfoo]
7061%D \stoptyping
7062
7063\permanent\protected\def\syst_reset_macro#1%
7064  {\overloaded\letcsname\csstring#1\endcsname\undefined} % so only frozen (instances(
7065
7066\permanent\protected\def\resetmacros[#1]%
7067  {\processcommalist[#1]\syst_reset_macro}
7068
7069%D These demos are for hvdm who needs ways to manipulate arguments but
7070%D in a fully expandable way (some explanation is given in the low level
7071%D expansion manual).
7072%D
7073%D \startbuffer
7074%D \edef\xxx{[\wipetokens {123}{abc123abc123abc123abc123abc}]}1 : \meaningless\xxx\par
7075%D \edef\xxx{[\wipetokens {123}{abc}]}                        2 : \meaningless\xxx\par
7076%D \edef\xxx{[\wipetokens {123}{123}]}                        3 : \meaningless\xxx\par
7077%D \edef\xxx{[\wipetokens {123}{123123}]}                     4 : \meaningless\xxx\par
7078%D \edef\xxx{[\wipetokens {123}{}]}                           5 : \meaningless\xxx\par
7079%D \edef\xxx{[\wipetokens {}{123}]}                           6 : \meaningless\xxx\par
7080%D \edef\xxx{[\wipetokens {\relax}{1\relax2\relax3}]}         7 : \meaningless\xxx\par
7081%D \edef\xxx{[\wipetokens {1}{1{2}3}]}                        8 : \meaningless\xxx\par
7082%D \edef\xxx{[\wipedtokens{{1}}{{1}23}]}                      9 : \meaningless\xxx\par
7083%D \edef\xxx{[\wipedtokens{{1}}{123}]}                        0 : \meaningless\xxx\par
7084%D \stopbuffer
7085%D
7086%D \typebuffer \startpacked \getbuffer \stoppacked
7087
7088\lettonothing\syst_helpers_wipe_tokens_yes
7089
7090\def\syst_helpers_wipe_tokens_nop#-^^04{}%
7091
7092\permanent\def\wipetokens#1#2%
7093  {\beginlocalcontrol
7094   \tolerant\def\syst_helpers_wipe_tokens_yes##1#1##2^^04%
7095     {##1%
7096      \ifparameter##2\or
7097        \expandafter\syst_helpers_wipe_tokens_yes
7098      \else
7099        \expandafter\syst_helpers_wipe_tokens_nop
7100      \fi
7101      ##2^^04}%
7102   \endlocalcontrol
7103   \syst_helpers_wipe_tokens_yes#2#1^^04}
7104
7105\permanent\def\wipedtokens#1#2%
7106  {\tokenized{\normalexpanded{\noexpand\wipetokens{\detokenize{#1}}{\detokenize{#2}}}}}
7107
7108%D \startbuffer
7109%D                \def\abc{abc}
7110%D \semiprotected \def\xyz{xyz}
7111%D               \edef\pqr{\expandtoken\notcatcodes`p%
7112%D                         \expandtoken\notcatcodes`q%
7113%D                         \expandtoken\notcatcodes`r}
7114%D
7115%D 1: \ifcondition\similartokens{abc} {def}YES\else NOP\fi (NOP) \quad
7116%D 2: \ifcondition\similartokens{abc}{\abc}YES\else NOP\fi (YES)
7117%D
7118%D 3: \ifcondition\similartokens{xyz} {pqr}YES\else NOP\fi (NOP) \quad
7119%D 4: \ifcondition\similartokens{xyz}{\xyz}YES\else NOP\fi (YES)
7120%D
7121%D 5: \ifcondition\similartokens{pqr} {pqr}YES\else NOP\fi (YES) \quad
7122%D 6: \ifcondition\similartokens{pqr}{\pqr}YES\else NOP\fi (YES)
7123%D \stopbuffer
7124%D
7125%D \typebuffer \startpacked \getbuffer \stoppacked
7126
7127\permanent\protected\def\similartokens#1#2%
7128 %{\normalexpanded{\noexpand\iftok{\noexpand\detokenize{#1}}{\noexpand\detokenize{#2}}}}
7129  {\semiexpanded{\noexpand\iftok{\noexpand\detokenize{#1}}{\noexpand\detokenize{#2}}}}
7130
7131\permanent\protected\def\doifelsesimilartokens#1#2%
7132  {\ifcondition\similartokens{#1}{#2}%
7133     \expandafter\firstoftwoarguments
7134   \else
7135     \expandafter\secondoftwoarguments
7136   \fi}
7137
7138%D This one is used in math-frc so don't change it
7139
7140\untraced\permanent\protected\def\glyphscaled#1% name will change
7141  {\dimexpr#1*\plusthousand/\glyphscale\relax}
7142
7143%D \macros {nologbuffering, linebuffering}
7144%D
7145%D This saves one sec on luametatex manual in console. And in the case of an error
7146%D no buffering will make sure what is cached gets flushed too. We define these two
7147%D at the LUA end: \typ {\nologbuffering} and \typ {\linebuffering}.
7148
7149\protect \endinput
7150