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