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