mult-aux.mkxl /size: 58 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=mult-aux,
3%D        version=2010.08.2,
4%D          title=\CONTEXT\ Multilingual Macros,
5%D       subtitle=Helpers,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14%D A generalization of \MKIV-like inheritance. Just something to play with
15%D (interface might change). The code here evolved in an email exchange between me
16%D and Wolgang Schuster.
17
18%D We use constant definitions here because we don't need to expand the keywords
19%D which saves a little on the stack (read: memory access). The gain in performance
20%D is normally not noticeable unless one has plenty of parameter checking, which
21%D can happen in some scenarios. Even then the gain is only there when one has
22%D thousands of runs on e.g. virtual platforms.
23
24\writestatus{loading}{ConTeXt Multilingual Macros / Helpers}
25
26\registerctxluafile{mult-aux}{}
27
28\unprotect
29
30\immutable\cdef\??empty{\tocharacter25}  \immutable\letvalue{\tocharacter25}\empty % hex 19
31
32% \edef\s!parent{\tocharacter29} % inlining  is ugly, a tiny bit faster, but neglectable on a run
33
34%D \starttyping
35%D \unprotect
36%D     \def\????aa{@@@@aa}
37%D
38%D     \installparameterhandler   \????aa {whatever}
39%D     \installsetuphandler       \????aa {whatever}
40%D     \installdefinehandler      \????aa {whatever} \????aa % #3 == defaultroot
41%D     \installfontandcolorhandler\????aa {whatever}
42%D
43%D   % \installcommandhandler     \????aa {whatever} \????aa
44%D \protect
45%D
46%D % \whateverparameter \c!test
47%D % \whateverparameterhash \c!test
48%D % \namedwhateverparameter \mycurrentwhatever \c!test
49%D % \usewhateverstyleandcolor \c!style \c!color
50%D % \everydefinewhatever (sets \currentwhatever)
51%D % \everypresetwhatever (can be used to reset parameters as we can redefine)
52%D % \everysetupwhatever (sets \currentwhatever)
53%D
54%D \starttext
55%D     \definewhatever[first] \definewhatever[second][first]
56%D                                           test: \def\currentwhatever{first}  \whateverparameter{method} \par
57%D     \setupwhatever        [method=unset]  test: \def\currentwhatever{first}  \whateverparameter{method} \par
58%D     \setupwhatever[first] [method=first]  test: \def\currentwhatever{first}  \whateverparameter{method} \par
59%D                                           test: \def\currentwhatever{second} \whateverparameter{method} \par
60%D     \setupwhatever[second][method=second] test: \def\currentwhatever{second} \whateverparameter{method} \par
61%D \stoptext
62%D \stoptyping
63
64% problem: every* could clash
65%
66% There can be less {} in the following definitions if we assume \??aa and \c!somecs
67%
68% watch the push/pop and predefinition of current .. this is needed for nested
69% definitions and overloaded defines using the predefined one
70
71% todo: add (relaxed) postsetup and postdefine hooks, just after the everys
72
73%D Start of experimental code: especially tables can have many assignments and
74%D although most time is spent in the typesetting anyway, we can squeeze out a
75%D little bit. Of course having 500 rows of 50 columns each with some setting does
76%D not happen that often. One should keep in mind that in the average document
77%D having some 500 assignments is no exception but there we're talking of
78%D neglectable runtime for them. Of course in the definitions below there is no real
79%D gain, only in the generated \setup* commands. Another situation with many
80%D assignments is \XML\ where we can pass attributes and normally don't do testing
81%D of them making sense.
82%
83% \testfeatureonce{100000}{\getparameters[bla][a=111,b=222,c=333]}% 1.669s
84% \testfeatureonce{100000}{\mult_interfaces_get_parameters{bla} [a=111,b=222,c=333]}% 1.529s
85% \testfeatureonce{100000}{\def\m_mult_interfaces_namespace{bla}\mult_interfaces_get_parameters_indeed[a=111,b=222,c=333]}% 1.466s
86
87% KEEP THIS:
88%
89% \lettonothing\m_mult_interfaces_namespace
90%
91% \def\mult_interfaces_get_parameters#1[#2%
92%   {\if\noexpand#2]%
93%      \expandafter\gobbleoneargument
94%    \else
95%      \def\m_mult_interfaces_namespace{#1}%
96%      \expandafter\mult_interfaces_get_parameters_indeed
97%    \fi#2}
98%
99% \def\mult_interfaces_get_parameters_indeed#1]% namespace already set
100%   {\mult_interfaces_get_parameters_item#1,],^^^^0004}
101%
102% \def\mult_interfaces_get_parameters_item#1,#2% #2 takes space before ,
103%   {\if,#1,% dirty trick for testing #1=empty
104%      \expandafter\mult_interfaces_get_parameters_item
105%    \orelse\if]#1%
106%      \expandafter\gobbleoneargument
107%    \else
108%      \mult_interfaces_get_parameters_assign#1==\empty^^^^0004%
109%    % \expandafter\mult_interfaces_get_parameters_item % saves skipping when at end
110%    \fi#2}
111%
112% \def\mult_interfaces_get_parameters_error#1#2% #3%
113%   {\mult_interfaces_get_parameters_error_indeed{#1}{#2}%
114%    \gobbleoneargument}
115%
116% \def\mult_interfaces_get_parameters_error_indeed#1#2%
117%   {\showassignerror{#2}{\the\inputlineno\space(#1)}}
118%
119% \def\mult_interfaces_get_parameters_assign#1=#2=#3#0^^^^0004%
120%   {\ifx\empty#1\empty
121%      \expandafter\mult_interfaces_get_parameters_error
122%    \orelse\ifx#3\empty
123%      \expandafter\mult_interfaces_get_parameters_error
124%    \else
125%      \expandafter\mult_interfaces_adef % assignment def
126%    \fi
127%    \m_mult_interfaces_namespace{#1}{#2}%
128%    \doubleexpandafter\mult_interfaces_get_parameters_item}
129%
130% \startinterface english
131%
132%     % some 10% faster
133%
134%     \let\mult_interfaces_get_parameters_error\undefined
135%
136%     \def\mult_interfaces_get_parameters_error_one#0\csname#2#3\endcsname#0%
137%       {\mult_interfaces_get_parameters_error_indeed{#2}{#3}\iftrue}
138%
139%     \def\mult_interfaces_get_parameters_error_two#0\csname#2#3\endcsname#0%
140%       {\mult_interfaces_get_parameters_error_indeed{#2}{#3}}
141%
142%     \def\mult_interfaces_get_parameters_assign#1=#2=#3#0^^^^0004%
143%       {\ifx\empty#1\empty
144%          \mult_interfaces_get_parameters_error_one
145%        \orelse\ifx#3\empty
146%          \mult_interfaces_get_parameters_error_two
147%        \else
148%          \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
149%        \fi
150%        \doubleexpandafter\mult_interfaces_get_parameters_item}
151%
152% \stopinterface
153%
154% \newif\ifassignment
155%
156% \def\mult_check_for_assignment_indeed#0=#2#0^^^^0004%
157%   {\if#2^^^^0003\assignmentfalse\else\assignmenttrue\fi}
158%
159% \def\mult_check_for_assignment_indeed_begin_#0=#2#0^^^^0004%
160%   {\if#2^^^^0003}
161%
162% \def\mult_check_for_assignment#1%
163%   {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
164%
165% % End of experimental code.
166
167%D We keep the above as reference, but from now on experiment with the following
168%D implementation. In principle this one is faster, but because normally we don't
169%D have that many assignments it doesn't get noticed. For instance, the \LUAMETATEX\
170%D manual does less than 6000 assignments and the payoff starts around a tenfold of
171%D that. But \unknown\ it's less tracing, so that's another benefit.
172
173%D Watch out: we accept that a \[k=v,,k=v] will generate a case where a key can become
174%D a comma and trigger a warning but we intercept that elsewhere. The alternative is
175%D to skip to the comma first which takes more time.
176
177\lettonothing\m_mult_interfaces_namespace
178
179% \def\mult_interfaces_get_parameters#1[%
180%   {\def\m_mult_interfaces_namespace{#1}%
181%    \futureexpandis]\gobbleoneargument\mult_interfaces_get_parameters_indeed}
182%
183% \def\mult_interfaces_get_parameters_indeed#1]%
184%   {\mult_interfaces_get_parameters_item#1\ignorearguments\ignorearguments}
185%
186% \def\mult_interfaces_get_parameters_item#*#1,%
187%   {\ifarguments
188%    \else
189%      \mult_interfaces_get_parameters_item_okay#1,\ignorearguments
190%      \expandafter\mult_interfaces_get_parameters_item
191%    \fi}
192%
193% \def\mult_interfaces_get_parameters_item_okay#1=#2,%
194%   {\ifarguments
195%      % done
196%    \or
197%      \mult_interfaces_get_parameters_item_error
198%    \else
199%      \mult_interfaces_adef\m_mult_interfaces_namespace{#1}{#2}%
200%    \fi}
201%
202% \def\mult_interfaces_get_parameters_item_error#-#-#-#1#2%
203%   {\if,#2\else\mult_interfaces_get_parameters_error_indeed{#1}{#2}\fi}
204%
205% \startinterface english
206%
207%     \def\mult_interfaces_get_parameters_item_okay#1=#2,%
208%       {\ifarguments
209%          % done
210%        \or
211%          \mult_interfaces_get_parameters_item_error
212%        \else
213%          \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
214%        \fi}
215%
216%     \def\mult_interfaces_get_parameters_item_error#-\defcsname#1#2\endcsname#-%
217%       {\if,#2\else\mult_interfaces_get_parameters_error_indeed{#1}{#2}\fi}
218%
219% \stopinterface
220
221% cheap with no checking
222%
223% \def\mult_interfaces_get_parameters#1[#S#2]%
224%   {\cdef\m_mult_interfaces_namespace{#1}%
225%    \mult_interfaces_get_parameters_item_okay#2\ignorearguments\ignorearguments}
226%
227% \tolerant\def\mult_interfaces_get_parameters_item_okay#*#1=#S#2,#M,%
228%   {\ifparameter#2\or
229%      \ifcsname\k!prefix!#1\endcsname
230%        \defcsname\m_mult_interfaces_namespace\lastnamedcs\endcsname{#2}%
231%      \else
232%        \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
233%      \fi
234%    \orelse\ifparameter#1\or
235%      \ifcsname\k!prefix!#1\endcsname
236%        \letcsname\m_mult_interfaces_namespace\lastnamedcs\endcsname\empty
237%      \else
238%        \letcsname\m_mult_interfaces_namespace#1\endcsname\empty
239%      \fi
240%    \else
241%      \expandafter\gobbleoneargument
242%    \fi
243%    \mult_interfaces_get_parameters_item_okay}
244%
245% \startinterface english
246%
247%    \tolerant\def\mult_interfaces_get_parameters_item_okay#*#1=#S#2,#M,%
248%      {\ifparameter#2\or
249%         % k=v
250%         \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
251%       \orelse\ifparameter#1\or
252%         % k=
253%         \letcsname\m_mult_interfaces_namespace#1\endcsname\empty
254%       \else
255%         \expandafter\gobbleoneargument
256%       \fi
257%       \mult_interfaces_get_parameters_item_okay}
258%
259% \stopinterface
260
261%D Still not nice
262
263% \def\mult_interfaces_get_parameters#1[%
264%   {\cdef\m_mult_interfaces_namespace{#1}%
265%    \futureexpandis]\gobbleoneargument\mult_interfaces_get_parameters_indeed}
266%
267% \def\mult_interfaces_get_parameters_indeed#S#1]%
268%   {\mult_interfaces_get_parameters_item#1\ignorearguments\ignorearguments}
269
270\def\mult_interfaces_get_parameters#1[#S#2]%
271  {\cdef\m_mult_interfaces_namespace{#1}%
272   \mult_interfaces_get_parameters_item#2\ignorearguments\ignorearguments}
273
274% \def\mult_interfaces_get_parameters_item#*#S#1,%
275%   {\ifarguments
276%    \else
277%      \mult_interfaces_get_parameters_item_okay#1,\ignorearguments
278%      \expandafter\mult_interfaces_get_parameters_item
279%    \fi}
280
281\def\mult_interfaces_get_parameters_item#*#S#1,%
282  {\ifarguments
283     \expandafter\gobbleoneargument
284   \else
285     \mult_interfaces_get_parameters_item_okay#1,\ignorearguments
286   \fi
287   \mult_interfaces_get_parameters_item}
288
289% \tolerant\def\mult_interfaces_get_parameters_item_okay#1=#S#2,%
290%   {\ifarguments
291%      % done
292%    \or
293%      \mult_interfaces_get_parameters_item_error
294%    \else
295%      \mult_interfaces_adef\m_mult_interfaces_namespace{#1}{#2}%
296%    \fi}
297
298% \tolerant\def\mult_interfaces_get_parameters_item_okay#1=#S#2,%
299%   {\ifarguments
300%      % done
301%    \or
302%      \mult_interfaces_get_parameters_item_error{#1}%
303%    \orelse\ifcsname\k!prefix!#1\endcsname
304%      \defcsname\m_mult_interfaces_namespace\lastnamedcs\endcsname{#2}%
305%    \else
306%      \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
307%    \fi}
308
309\tolerant\def\mult_interfaces_get_parameters_item_okay#1=#S#2,%
310  {\ifarguments
311     % done
312   \or
313     \mult_interfaces_get_parameters_item_error{#1}%
314   \or
315     \defcsname
316       \m_mult_interfaces_namespace
317       \ifcsname\k!prefix!#1\endcsname\lastnamedcs\else#1\fi
318     \endcsname{#2}%
319   \fi}
320
321\def\mult_interfaces_get_parameters_item_error#1%
322  {\if,#1\else\mult_interfaces_get_parameters_error_indeed\m_mult_interfaces_namespace{#1}\fi}
323
324\startinterface english
325
326    \def\mult_interfaces_get_parameters_item_okay#1=#S#2,%
327      {\ifarguments
328         % done
329       \or
330         \mult_interfaces_get_parameters_item_error{#1}%
331       % \mult_interfaces_get_parameters_item_error
332       % \if,#1\else\mult_interfaces_get_parameters_item_error\fi
333       \else
334         \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
335       \fi}
336
337  % \def\mult_interfaces_get_parameters_item_error#-\defcsname#1#2\endcsname#-%
338  %   {\if,#2\else\mult_interfaces_get_parameters_error_indeed{#1}{#2}\fi}
339
340  % \def\mult_interfaces_get_parameters_item_error#-\defcsname#-#1\endcsname#-%
341  %   {\if,#1\else\mult_interfaces_get_parameters_error_indeed\m_mult_interfaces_namespace{#1}\fi}
342
343    \def\mult_interfaces_get_parameters_item_error#1%
344      {\if,#1\else\mult_interfaces_get_parameters_error_indeed\m_mult_interfaces_namespace{#1}\fi}
345
346  % \def\mult_interfaces_get_parameters_item_error
347  %    {\mult_interfaces_get_parameters_error_indeed
348  %       {\m_mult_interfaces_namespace}
349  %       {\expandparameter\plusthree}}
350
351\stopinterface
352
353% % No longer used:
354%
355% \def\mult_check_for_assignment_indeed#-=#1#-^^^^0004%
356%   {\if#1^^^^0003\assignmentfalse\else\assignmenttrue\fi}
357%
358% \def\mult_check_for_assignment_indeed_begin_#-=#1#-^^^^0004%
359%   {\if#1^^^^0003}
360%
361% \def\mult_check_for_assignment#1%
362%   {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
363
364%D Beware, zero arguments is an assignment!
365
366\def\mult_aux_no_assignment_indeed#1=#2]{\ifcase\ifarguments\plusone\or\zerocount\else\plusone\fi}
367\def\mult_aux_no_assignment#1]{\mult_aux_no_assignment_indeed#1\ignorearguments\relax}
368
369%D This can give wrong results when we pass e.g. \type{\c!format}, so either we need
370%D to use the \type {\k!} ones, but these are not defined in the english interface
371%D so from now on we assume that the low level ones are used with the symbolic names
372%D and that only the high level setup commands are used with language specific
373%D interfaces.
374
375% \startinterface english
376    \protected\def\mult_interfaces_let #1#2{\letcsname#1#2\endcsname}
377    \protected\def\mult_interfaces_lete#1#2{\letcsname#1#2\endcsname\empty}
378    \protected\def\mult_interfaces_def #1#2{\defcsname#1#2\endcsname}
379    \protected\def\mult_interfaces_edef#1#2{\edefcsname#1#2\endcsname}
380    \protected\def\mult_interfaces_gdef#1#2{\gdefcsname#1#2\endcsname}
381    \protected\def\mult_interfaces_xdef#1#2{\xdefcsname#1#2\endcsname}
382% \stopinterface
383
384%D Do, we only interface the assignment definition:
385
386\protected\def\mult_interfaces_adef#1#2{\defcsname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
387%protected\def\mult_interfaces_adef#1#2{\defcsname#1\ifcsname\k!prefix!#2\endcsname\csname\csnamestring\endcsname\else#2\fi\endcsname}
388
389\startinterface english
390    \protected\def\mult_interfaces_adef#1#2{\defcsname#1#2\endcsname}
391\stopinterface
392
393% the commented detokenized variant that backtracks ... needs testing usage first
394%
395% \let\whatever\relax
396%
397% \definetest[oeps][bagger=\whatever]
398%
399% \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{bagger}}\meaning\hans\par
400% \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{reggab}}\meaning\hans\par
401%
402% slower: \def#3##1{\csname\ifcsname#1#2:##1\endcsname\expandafter\csstring\lastnamedcs\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}%
403
404%D pre-expansion can be a bit faster but handly any effect on a normal run so let's
405%D go for saving some memory.
406
407%def\mult_interfaces_detokenize{\expandafter\expandafter\expandafter\detokenize\expandafter\expandafter\expandafter}
408
409% \protected\def\mult_interfaces_install_parameter_handler#1#2#3#4#5#6#7#8#9%
410%   {\frozen\def#3##1{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}%
411%    \frozen\def#4##1##2{\ifcsname##1:##2\endcsname##1:##2\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}%
412%    \frozen\edef#5##1##2{\noexpand\ifrelax##1\??empty\noexpand\else\noexpand#4##1{##2}\noexpand\fi}% is {} needed around ##1 ?
413%    \frozen\def#6##1##2{\csname\ifcsname#1##1:##2\endcsname#1##1:##2\else\expandafter#5\csname#1##1:\s!parent\endcsname{##2}\fi\endcsname}%
414%   %\frozen\def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2:##1\endcsname}}% always root, no backtrack
415%    \frozen\def#7##1{\expandafter\detokened\csname#1#2:##1\endcsname}% always root, no backtrack
416%    \frozen\def#8##1{\begincsname#1#2:##1\endcsname}%
417%    % TODO
418%    \frozen\def#9##1##2{\expandafter\let\expandafter##1\csname\ifcsname#1#2:##2\endcsname#1#2:##2\else\expandafter#5\csname#1#2:\s!parent\endcsname{##2}\fi\endcsname}}
419
420\protected\def\mult_interfaces_install_parameter_handler#1#2#3#4#5#6#7#8#9%
421  {\frozen\def#3##1{\csname\ifcsname#1#2:##1\endcsname\csnamestring\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}%
422   \frozen\def#4##1##2{\ifcsname##1:##2\endcsname\csnamestring\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}%
423   \frozen\edef#5##1##2{\noexpand\ifrelax##1\??empty\noexpand\else\noexpand#4##1{##2}\noexpand\fi}% is {} needed around ##1 ?
424   \frozen\def#6##1##2{\csname\ifcsname#1##1:##2\endcsname\csnamestring\else\expandafter#5\csname#1##1:\s!parent\endcsname{##2}\fi\endcsname}%
425  %\frozen\def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2:##1\endcsname}}% always root, no backtrack
426   \frozen\def#7##1{\expandafter\detokened\csname#1#2:##1\endcsname}% always root, no backtrack
427   \frozen\def#8##1{\begincsname#1#2:##1\endcsname}%
428   % TODO
429   \frozen\def#9##1##2{\expandafter\let\expandafter##1\csname\ifcsname#1#2:##2\endcsname\csnamestring\else\expandafter#5\csname#1#2:\s!parent\endcsname{##2}\fi\endcsname}}
430
431\permanent\protected\def\installparameterhandler#1#2%
432  {\mutable\constant\letcsname current#2\endcsname\empty
433   \normalexpanded
434     {\mult_interfaces_install_parameter_handler
435        {\noexpand#1}% \??aa
436        \expandafter\noexpand\csname current#2\endcsname
437        \expandafter\noexpand\csname #2parameter\endcsname
438        \expandafter\noexpand\csname do#2parameter\endcsname        % or: #2_parameter
439        \expandafter\noexpand\csname do#2parentparameter\endcsname  % or: #2_parent_parameter
440        \expandafter\noexpand\csname named#2parameter\endcsname
441        \expandafter\noexpand\csname detokenized#2parameter\endcsname
442        \expandafter\noexpand\csname direct#2parameter\endcsname
443        \expandafter\noexpand\csname letfrom#2parameter\endcsname}} % strict#2parameter is gone
444
445\protected\def\mult_interfaces_install_root_parameter_handler#1#2#3%
446 %{\frozen\def#2##1{\detokenize\expandafter\expandafter\expandafter{\csname#1:##1\endcsname}}% always root
447  {\frozen\def#2##1{\expandafter\detokened\csname#1:##1\endcsname}% always root
448   \frozen\def#3##1{\begincsname#1:##1\endcsname}}
449
450\permanent\protected\def\installrootparameterhandler#1#2%
451  {\normalexpanded
452     {\mult_interfaces_install_root_parameter_handler
453        {\noexpand#1}% \??aa
454        \expandafter\noexpand\csname detokenizedroot#2parameter\endcsname
455        \expandafter\noexpand\csname root#2parameter\endcsname}}
456
457\protected\def\mult_interfaces_install_parameter_hash_handler#1#2#3#4#5#6#7#8#9%
458  {\frozen\def#3##1{#1#4{#1#2}{##1}:}% leading #1 was missing .. is this one used?
459   \frozen\def#4##1##2{\ifcsname##1:##2\endcsname##1\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}%
460   \frozen\def#5##1##2{\ifrelax##1\else#4##1{##2}\fi}%
461   \frozen\def#6{#1#2:}%
462   \frozen\def#7##1{#1##1:}%
463% won't work unless we also save the name of an undefined but called seldom (so no \else for now)
464%  \frozen\def#8{\ifempty#2\orelse\ifcsname#1#2:\s!parent\endcsname\else\letcsname\csnamestring\endcsname#1\fi}%
465   \frozen\def#8{\ifempty#2\orelse\ifcsname#1#2:\s!parent\endcsname\else\letcsname#1#2:\s!parent\endcsname#1\fi}%
466   \frozen\protected\def#9##1{\edefcsname#1##1:\s!parent\endcsname{#1#2}}}
467
468\permanent\protected\def\installparameterhashhandler#1#2%
469  {\mutable\letcsname current#2\endcsname\empty
470   \immutable\letcsname#2namespace\endcsname#1%
471   \normalexpanded
472     {\mult_interfaces_install_parameter_hash_handler
473        {\noexpand#1}% \??aa
474        \expandafter\noexpand\csname current#2\endcsname
475        \expandafter\noexpand\csname #2parameterhash\endcsname
476        \expandafter\noexpand\csname do#2parameterhash\endcsname         % or : #2_parameter_hash
477        \expandafter\noexpand\csname do#2parentparameterhash\endcsname   % or : #2_parent_parameter_hash
478        \expandafter\noexpand\csname current#2hash\endcsname
479        \expandafter\noexpand\csname named#2hash\endcsname
480        \expandafter\noexpand\csname check#2parent\endcsname
481        \expandafter\noexpand\csname chaintocurrent#2\endcsname}}
482
483%D In \MKIV\ we can probably use the english variant for all other languages too.
484
485% todo: inline the def/let
486
487% \startinterface english
488    \protected\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6%
489      {\frozen\protected\def#3##1{\defcsname#1#2:##1\endcsname}%        ##1 {##2} (braces are mandate)
490       \frozen\protected\def#4##1{\edefcsname#1#2:##1\endcsname}%       ##1 {##2} (braces are mandate)
491       \frozen\protected\def#5##1{\letcsname#1#2:##1\endcsname}%        ##1 ##2
492       \frozen\protected\def#6##1{\letcsname#1#2:##1\endcsname\empty}}% ##1
493% \stopinterface
494
495\permanent\protected\def\installparametersethandler#1#2%
496  {\mutable\letcsname current#2\endcsname\empty
497   \normalexpanded
498     {\mult_interfaces_install_parameter_set_handler
499        {\noexpand#1}% \??aa
500        \expandafter\noexpand\csname current#2\endcsname
501        \expandafter\noexpand\csname set#2parameter\endcsname
502        \expandafter\noexpand\csname setexpanded#2parameter\endcsname
503        \expandafter\noexpand\csname let#2parameter\endcsname
504        \expandafter\noexpand\csname reset#2parameter\endcsname}}
505
506\mutable\let\dousecurrentstyleparameter\relax
507\mutable\let\dousecurrentcolorparameter\relax
508
509\mutable\lettonothing\currentstyleparameter
510\mutable\lettonothing\currentcolorparameter
511
512% maybe we should have \names ones too
513
514\protected\def\mult_interfaces_install_style_and_color_handler#1#2#3#4%
515  {\frozen\protected\def#2##1##2% style color
516     {\cdef\currentstyleparameter{#1{##1}}% this name is public (can also set color e.g. in underline)
517      \ifempty\currentstyleparameter\else\dousecurrentstyleparameter\fi
518      \cdef\currentcolorparameter{#1{##2}}% this name is public (so we do this after the style switch)
519      \ifempty\currentcolorparameter\else\dousecurrentcolorparameter\fi}%
520   \frozen\protected\def#3##1% style
521     {\cdef\currentstyleparameter{#1{##1}}% this name is public
522      \ifempty\currentstyleparameter\else\dousecurrentstyleparameter\fi}%
523   \frozen\protected\def#4##1% color
524     {\cdef\currentcolorparameter{#1{##1}}% this name is public
525      \ifempty\currentcolorparameter\else\dousecurrentcolorparameter\fi}}
526
527\permanent\protected\def\installstyleandcolorhandler#1#2%
528  {\normalexpanded
529     {\mult_interfaces_install_style_and_color_handler
530        \expandafter\noexpand\csname #2parameter\endcsname
531        \expandafter\noexpand\csname use#2styleandcolor\endcsname % maybe an alias use#2styleandcolorparameters
532        \expandafter\noexpand\csname use#2styleparameter\endcsname
533        \expandafter\noexpand\csname use#2colorparameter\endcsname}}
534
535\def\mult_check_for_parent#1#2#3#4%
536  {\ifcsname#1#4:\s!parent\endcsname\orelse\ifx#4\empty\else
537     \writestatus\m!system{error: invalid parent #4 for #3, #4 defined too (best check it)}%
538     \cdefcsname#1#4:\s!parent\endcsname{#2}%
539   \fi}
540
541          \def\mult_interfaces_chain#1#2{\ifcsname#1#2:\s!chain\endcsname\lastnamedcs\space\fi}
542\permanent\def\getparentchain       #1#2{\begincsname#1#2:\s!chain\endcsname}
543\permanent\def\getcurrentparentchain#1#2{\begincsname#1#2:\s!chain\endcsname}
544
545% we could have a \setcurrent... macro and then always make them a frozen
546% but it might have a little impact on performance ... something to leave
547% to when we're done with the transition (it's kind of massive)
548
549\protected\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8%
550  {\newtoks#5%
551   \newtoks#6%
552   \frozen\tolerant\protected\def#2[##1]##*[##S##2]##*[##S##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child]
553     {\let#8#4%
554      % watch out: no \edef#4{##1} before the ifarguments because #1 can have macros
555      \ifarguments
556        \lettonothing#4%
557        \expand#5% predefine
558        \lettonothing#7%
559        \letcsname#1#4:\s!chain\endcsname\empty
560        \cdefcsname#1#4:\s!parent\endcsname{#3}%
561      \or
562        \cdef#4{##1}%
563        \expand#5% predefine
564        \lettonothing#7%
565        \cdefcsname#1#4:\s!chain\endcsname{##1}%
566        \cdefcsname#1#4:\s!parent\endcsname{#3}%
567      \or
568        \cdef#4{##1}%
569        \expand#5% predefine
570        \relax
571        \ifhastok={##2}%
572          \lettonothing#7%
573          \cdefcsname#1#4:\s!chain\endcsname{##1}%
574          \cdefcsname#1#4:\s!parent\endcsname{#3}%
575          \mult_interfaces_get_parameters{#1#4:}[##2]%
576        \else
577          \cdef#7{##2}%
578          \ifempty#7%
579            \cdefcsname#1#4:\s!chain\endcsname{##1}%
580            \cdefcsname#1#4:\s!parent\endcsname{#3}%
581          \else
582            \mult_check_for_parent{#1}{#3}#4#7%
583            \cdefcsname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
584            \cdefcsname#1#4:\s!parent\endcsname{#1##2}%
585          \fi
586        \fi
587      \or
588        \cdef#4{##1}%
589        \expand#5% predefine
590        \cdef#7{##2}%
591        \mult_check_for_parent{#1}{#3}#4#7%
592        \cdefcsname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
593        \cdefcsname#1#4:\s!parent\endcsname{#1##2}%
594        \mult_interfaces_get_parameters{#1#4:}[##3]%
595      \fi
596      \expand#6%
597      \let#4#8}}
598
599\permanent\protected\def\installdefinehandler#1#2#3%
600  {\mutable\letcsname current#2\endcsname\empty
601   \mutable\letcsname current#2parent\endcsname\empty
602   \normalexpanded
603     {\mult_interfaces_install_define_handler
604        {\noexpand#1}% \??aa
605        \expandafter\noexpand\csname define#2\endcsname
606        {\noexpand#3}% root
607        \expandafter\noexpand\csname current#2\endcsname
608        \expandafter\noexpand\csname everypreset#2\endcsname
609        \expandafter\noexpand\csname everydefine#2\endcsname
610        \expandafter\noexpand\csname current#2parent\endcsname
611        \expandafter\noexpand\csname saved_defined_#2\endcsname}}
612
613\protected\def\mult_interfaces_install_setup_handler#1#2#3#4#5#6#7#8%
614  {\newtoks#4%
615   \newtoks#7%
616   \frozen\protected\def#5{\mult_interfaces_get_parameters{#1#3:}}% no every ! don't change it
617   \frozen\tolerant\protected\def#2[##S##1]##*[##S##2]% maybe helper
618     {\let#6#3%
619      \ifnum\lastarguments=\plustwo
620        \def#8####1% we will have a simple one as well
621          {\cdef#3{####1}%
622           \mult_interfaces_get_parameters{#1#3:}[##2]%
623           \expand#4}%
624        \processcommalist[##1]#8%
625      \else
626        \lettonothing#3%
627        \mult_interfaces_get_parameters{#1:}[##1]%
628        \expand#4%
629      \fi
630      \let#3#6%
631      \expand#7}}
632
633\permanent\protected\def\installsetuphandler#1#2%
634  {\mutable\letcsname current#2\endcsname\empty
635   \normalexpanded
636     {\mult_interfaces_install_setup_handler
637        {\noexpand#1}% \??aa
638        \expandafter\noexpand\csname setup#2\endcsname
639        \expandafter\noexpand\csname current#2\endcsname
640        \expandafter\noexpand\csname everysetup#2\endcsname
641        \expandafter\noexpand\csname setupcurrent#2\endcsname
642        \expandafter\noexpand\csname saved_setup_current#2\endcsname
643        \expandafter\noexpand\csname everysetup#2root\endcsname
644        \expandafter\noexpand\csname nested_setup_current#2\endcsname}}
645
646\aliased\let\doingrootsetupnamed\plusone    % \setuplayout[name][key=value]
647\aliased\let\doingrootsetuproot \plustwo    % \setuplayout      [key=value]
648\aliased\let\doingrootsetnamed  \plusthree  % \setuplayout[name]
649\aliased\let\doingrootsetroot   \plusfour   % \setuplayout
650
651% \protected\def\mult_interfaces_install_switch_setup_handler_a#1#2#3%
652%   {\frozen\protected\def#3{\mult_interfaces_get_parameters{#1#2:}}}
653
654% \protected\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9%
655%   {\newtoks#5%
656%    \newconstant#2%
657%    \newtoks#8%
658%    \newtoks#9%
659%    \frozen\tolerant\protected\def#4[##1]##*[##2]% maybe helper
660%      {\ifarguments
661%         % \setuplayout
662%         \let#6#3%      % previous becomes current
663%         \lettonothing#3%   % current becomes empty
664%         #2\doingrootsetroot
665%         \expand#5%
666%         \expand#8% switchsetups
667%       \or
668%         \ifhastok={##1}%
669%           % \setuplayout[key=value]
670%           \let#7#3%
671%           \let#6#3%
672%           \lettonothing#3%
673%           #2\doingrootsetuproot
674%           \mult_interfaces_get_parameters{#1:}[##1]%
675%           \expand#5%
676%           \expand#8% switchsetups
677%           \let#3#7%
678%         \else
679%           % \setuplayout[whatever]
680%           \let#6#3%   % previous becomes current
681%           \cdef#3{##1}% this will catch reset so one needs to test for it
682%           \ifempty#3%
683%             \let#7#6%
684%             #2\doingrootsetuproot
685%             \expand#5%
686%             \expand#8% switchsetups
687%             \let#3#7%
688%           \else
689%             #2\doingrootsetnamed
690%             \expand#5%     % we can check for previous vs current
691%             \expand#8% switchsetups
692%           \fi
693%         \fi
694%       \or
695%         % \setuplayout[whatever][key=value]
696%         \let#7#3%
697%         \let#6#3%
698%         \cdef#3{##1}%
699%         #2\doingrootsetupnamed
700%         \mult_interfaces_get_parameters{#1#3:}[##2]%
701%         \expand#5%
702%         \ifx#3#6\expand#8\fi % only switchsetups if previous == current
703%         \let#3#7%
704%       \fi
705%       #2\zerocount % mode is always zero at the end
706%       \expand#9}}
707
708% \permanent\protected\def\installswitchsetuphandler#1#2%
709%   {\mutable\letcsname current#2\endcsname\empty
710%    \mutable\letcsname previous#2\endcsname\empty
711%    \normalexpanded
712%      {\mult_interfaces_install_switch_setup_handler_a
713%         {\noexpand#1}% \??aa
714%         \expandafter\noexpand\csname current#2\endcsname
715%         \expandafter\noexpand\csname setupcurrent#2\endcsname
716%       \mult_interfaces_install_switch_setup_handler_b
717%         {\noexpand#1}% \??aa
718%         \expandafter\noexpand\csname #2setupmode\endcsname
719%         \expandafter\noexpand\csname current#2\endcsname
720%         \expandafter\noexpand\csname setup#2\endcsname
721%         \expandafter\noexpand\csname everysetup#2\endcsname
722%         \expandafter\noexpand\csname previous#2\endcsname
723%         \expandafter\noexpand\csname saved_setup_current#2\endcsname
724%         \expandafter\noexpand\csname everyswitch#2\endcsname
725%         \expandafter\noexpand\csname everysetup#2root\endcsname}}
726
727\protected\def\mult_interfaces_install_switch_setup_handler#1#2#3#4#5#6#7#8#9#A%
728  {\newtoks#5%
729   \newconstant#2%
730   \newtoks#8%
731   \newtoks#9%
732   \frozen\tolerant\protected\def#4[##S##1]##*[##S##2]% maybe helper
733     {\ifarguments
734        % \setuplayout
735        \let#6#3%      % previous becomes current
736        \lettonothing#3%   % current becomes empty
737        #2\doingrootsetroot
738        \expand#5%
739        \expand#8% switchsetups
740      \or
741        \ifhastok={##1}%
742          % \setuplayout[key=value]
743          \let#7#3%
744          \let#6#3%
745          \lettonothing#3%
746          #2\doingrootsetuproot
747          \mult_interfaces_get_parameters{#1:}[##1]%
748          \expand#5%
749          \expand#8% switchsetups
750          \let#3#7%
751        \else
752          % \setuplayout[whatever]
753          \let#6#3%   % previous becomes current
754          \cdef#3{##1}% this will catch reset so one needs to test for it
755          \ifempty#3%
756            \let#7#6%
757            #2\doingrootsetuproot
758            \expand#5%
759            \expand#8% switchsetups
760            \let#3#7%
761          \else
762            #2\doingrootsetnamed
763            \expand#5%     % we can check for previous vs current
764            \expand#8% switchsetups
765          \fi
766        \fi
767      \or
768        % \setuplayout[whatever][key=value]
769        \let#7#3%
770        \let#6#3%
771        \cdef#3{##1}%
772        #2\doingrootsetupnamed
773        \mult_interfaces_get_parameters{#1#3:}[##2]%
774        \expand#5%
775        \ifx#3#6\expand#8\fi % only switchsetups if previous == current
776        \let#3#7%
777      \fi
778      #2\zerocount % mode is always zero at the end
779      \expand#9}%
780    \frozen\protected\def#A{\mult_interfaces_get_parameters{#1#3:}}}
781
782\permanent\protected\def\installswitchsetuphandler#1#2%
783  {\mutable\letcsname current#2\endcsname\empty
784   \mutable\letcsname previous#2\endcsname\empty
785   \normalexpanded
786     {\mult_interfaces_install_switch_setup_handler
787        {\noexpand#1}% \??aa
788        \expandafter\noexpand\csname #2setupmode\endcsname
789        \expandafter\noexpand\csname current#2\endcsname
790        \expandafter\noexpand\csname setup#2\endcsname
791        \expandafter\noexpand\csname everysetup#2\endcsname
792        \expandafter\noexpand\csname previous#2\endcsname
793        \expandafter\noexpand\csname saved_setup_current#2\endcsname
794        \expandafter\noexpand\csname everyswitch#2\endcsname
795        \expandafter\noexpand\csname everysetup#2root\endcsname
796        \expandafter\noexpand\csname setupcurrent#2\endcsname}}
797
798
799\protected\def\mult_interfaces_install_auto_setup_handler#1#2#3#4#5#6#7#8%
800  {\newtoks#4%
801   \frozen\protected\def#5{\mult_interfaces_get_parameters{#1#3:}}%
802   \frozen\tolerant\protected\def#2[##S##1]##*[##S##2]##*[##S##3]%
803     {\let#7#3%
804      \ifarguments
805        \lettonothing#3%
806        \expand#4%
807      \or
808        \lettonothing#3%
809        \mult_interfaces_get_parameters{#1:}[##1]%
810        \expand#4%
811      \or
812        \def#8####1%
813          {\cdef#3{####1}%
814           #6% checks parent and sets if needed
815           \mult_interfaces_get_parameters{#1#3:}[##2]%
816           \expand#4}%
817        \processcommalist[##1]#8%
818      \or
819        \def#8####1%
820          {\cdef#3{####1}%
821           \cdefcsname#1#3:\s!parent\endcsname{#1##2}%
822           \mult_interfaces_get_parameters{#1#3:}[##3]% always sets parent
823           \expand#4}%
824        \processcommalist[##1]#8%
825      \fi
826      \let#3#7}}
827
828\permanent\protected\def\installautosetuphandler#1#2%
829  {\mutable\letcsname current#2\endcsname\empty
830   \normalexpanded
831     {\mult_interfaces_install_auto_setup_handler
832        {\noexpand#1}% \??aa
833        \expandafter\noexpand\csname setup#2\endcsname
834        \expandafter\noexpand\csname current#2\endcsname
835        \expandafter\noexpand\csname everysetup#2\endcsname
836        \expandafter\noexpand\csname setupcurrent#2\endcsname
837        \expandafter\noexpand\csname check#2parent\endcsname
838        \expandafter\noexpand\csname saved_setup_current#2\endcsname
839        \expandafter\noexpand\csname nested_setup_current#2\endcsname}}
840
841\permanent\protected\def\installbasicparameterhandler#1#2%
842  {\installparameterhandler    {#1}{#2}%
843   \installparameterhashhandler{#1}{#2}%
844   \installparametersethandler {#1}{#2}%
845   \installrootparameterhandler{#1}{#2}}
846
847\permanent\protected\def\installbasicautosetuphandler#1#2% \??self name \??parent (can be \??self)
848  {\installbasicparameterhandler{#1}{#2}%
849   \installautosetuphandler     {#1}{#2}}
850
851\permanent\protected\def\installstylisticautosetuphandler#1#2% \??self name \??parent (can be \??self)
852  {\installbasicparameterhandler{#1}{#2}%
853   \installautosetuphandler     {#1}{#2}%
854   \installstyleandcolorhandler {#1}{#2}}
855
856\permanent\protected\def\installcommandhandler#1#2#3% \??self name \??parent (can be \??self)
857  {\installbasicparameterhandler{#1}{#2}%
858   \installdefinehandler        {#1}{#2}{#3}%
859   \installsetuphandler         {#1}{#2}%
860   \installstyleandcolorhandler {#1}{#2}}
861
862\permanent\protected\def\installswitchcommandhandler#1#2#3% \??self name \??parent (can be \??self)
863  {\installbasicparameterhandler{#1}{#2}%
864   \installdefinehandler        {#1}{#2}{#3}%
865   \installswitchsetuphandler   {#1}{#2}%
866   \installstyleandcolorhandler {#1}{#2}}
867
868\permanent\protected\def\installautocommandhandler#1#2#3% automatically defined cloned setups
869  {\installbasicparameterhandler{#1}{#2}%
870   \installdefinehandler        {#1}{#2}{#3}%
871   \installautosetuphandler     {#1}{#2}%
872   \installstyleandcolorhandler {#1}{#2}}
873
874\permanent\protected\def\installsimplecommandhandler#1#2#3% no define (experiment) - use \check*parent when defining
875  {\installbasicparameterhandler{#1}{#2}%
876   \installsetuphandler         {#1}{#2}%
877   \installstyleandcolorhandler {#1}{#2}}
878
879%D Many mechanisms have some kind of inheritance in place, and these are the
880%D speed||critical ones. Therefore there is no reason to stick to \type {\@@xxkey}
881%D for the sake of performance. For this reason we also provide a direct variant.
882%D This permits a more consistent treatment of namespaces. A \type
883%D {\whateverparameter} call is three times slower and a \type
884%D {\directwhateverparameter} call two times but for some 100K expansions we only
885%D loose some .1 second which is neglectable given the small amount of expansions in
886%D real runs.
887
888%D We don't need colons for such simple cases.
889
890\protected\def\mult_interfaces_install_direct_parameter_handler#1#2#3#4#5%
891  {\frozen\def#3##1{\begincsname#1##1\endcsname}%
892  %\frozen\def#4##1{\detokenize\expandafter\expandafter\expandafter{\csname#1##1\endcsname}}%
893   \frozen\def#4##1{\expandafter\detokened\csname#1##1\endcsname}%
894   \frozen\def#5##1{\begincsname#1##1\endcsname}}
895
896\permanent\protected\def\installdirectparameterhandler#1#2%
897  {\mutable\letcsname current#2\endcsname\empty
898   \normalexpanded
899     {\mult_interfaces_install_direct_parameter_handler
900        {\noexpand#1}%
901        \expandafter\noexpand\csname current#2\endcsname
902        \expandafter\noexpand\csname #2parameter\endcsname
903        \expandafter\noexpand\csname detokenized#2parameter\endcsname
904        \expandafter\noexpand\csname direct#2parameter\endcsname}}
905
906\protected\def\mult_interfaces_install_direct_setup_handler#1#2#3#4%
907  {\newtoks#4%
908   \frozen\tolerant\protected\def#2[##S##1]{\mult_interfaces_get_parameters#1[##1]\expand#4}%
909   \frozen\protected\def#3{\mult_interfaces_get_parameters#1}}
910
911\permanent\protected\def\installdirectsetuphandler#1#2%
912  {\normalexpanded
913     {\mult_interfaces_install_direct_setup_handler
914        {\noexpand#1}% \??aa
915        \expandafter\noexpand\csname setup#2\endcsname
916        \expandafter\noexpand\csname setupcurrent#2\endcsname % no \every (we use 'current' for consistency)
917        \expandafter\noexpand\csname everysetup#2\endcsname}}
918
919% \startinterface english
920    \protected\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5%
921      {\frozen\protected\def#2##1{\defcsname#1##1\endcsname}%
922       \frozen\protected\def#3##1{\edefcsname#1##1\endcsname}%
923       \frozen\protected\def#4##1{\letcsname#1##1\endcsname}%
924       \frozen\protected\def#5##1{\letcsname#1##1\endcsname\empty}}%
925% \stopinterface
926
927\permanent\protected\def\installdirectparametersethandler#1#2%
928  {\normalexpanded
929     {\mult_interfaces_install_direct_parameter_set_handler
930        {\noexpand#1}% \??aa
931        \expandafter\noexpand\csname set#2parameter\endcsname
932        \expandafter\noexpand\csname setexpanded#2parameter\endcsname
933        \expandafter\noexpand\csname let#2parameter\endcsname
934        \expandafter\noexpand\csname reset#2parameter\endcsname}}
935
936\aliased\let\installdirectstyleandcolorhandler\installstyleandcolorhandler
937
938\permanent\protected\def\installdirectcommandhandler#1#2%
939  {\installdirectparameterhandler    {#1}{#2}%
940   \installdirectsetuphandler        {#1}{#2}%
941   \installdirectparametersethandler {#1}{#2}%
942   \installdirectstyleandcolorhandler{#1}{#2}}
943
944\permanent\protected\def\installsetuponlycommandhandler#1#2%
945  {\installdirectparameterhandler   {#1}{#2}%
946   \installdirectsetuphandler       {#1}{#2}%
947   \installdirectparametersethandler{#1}{#2}}
948
949% Experiment:
950
951% \installcorenamespace {one}
952% \installcorenamespace {two}
953%
954% \installcommandhandler \??one {one} \??one
955% \installcommandhandler \??two {two} \??two
956%
957% \defineone[test] \setupone[test][alpha=first]
958% \definetwo[test] \setuptwo[test][beta=second]
959%
960% \protect
961%
962% \def\currentone{test}
963% \def\currenttwo{test}
964%
965% \relateparameterhandlers {two} {test} {one} {test}
966%
967% yes:\oneparameter{alpha}\par
968% nop:\oneparameter{beta}\par
969% yes:\twoparameter{alpha}\par
970% yes:\twoparameter{beta}\par
971
972\permanent\protected\def\relateparameterhandlers#1#2#3#4% {from} {instance} {to} {instance}
973  {\immutable\edefcsname\csname#1namespace\endcsname#2:\s!parent\endcsname{\csname#3namespace\endcsname#4}}
974
975\permanent\protected\def\relateparameterhandlersbyns#1#2#3#4% {from} {instance} {to} {instance}
976  {\cdefcsname#1#2:\s!parent\endcsname{#3#4}}
977
978%D Here is another experiment:
979
980\protected\def\mult_interfaces_install_action_handler#1#2#3%
981  {\frozen\tolerant\protected\defcsname#1\endcsname[##S##1]##*[##S##2]%
982     {\begingroup
983      \ifarguments
984        \lettonothing#2%
985      \or
986       %\ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004%
987      % \ifcondition\mult_aux_no_assignment_indeed##1\ignorearguments
988      %   \cdef#2{##1}%
989      % \else
990      %   \lettonothing#2%
991      %   #3[##1]%
992      % \fi
993        \ifhastok={##1}%
994          \lettonothing#2%
995          #3[##1]%
996        \else
997          \cdef#2{##1}%
998        \fi
999      \or
1000        \cdef#2{##1}%
1001        #3[##2]%
1002      \fi
1003      \directsetup{handler:action:#1}%
1004      \endgroup}}
1005
1006\permanent\protected\def\installactionhandler#1%
1007  {\mutable\letcsname current#1\endcsname\empty
1008   \normalexpanded
1009     {\mult_interfaces_install_action_handler
1010        {#1}%
1011        \expandafter\noexpand\csname current#1\endcsname
1012        \expandafter\noexpand\csname setupcurrent#1\endcsname}}
1013
1014% First we had, in tune with the regular system variables:
1015%
1016% \starttyping
1017% \protected\def\installnamespace#1{\defcsname ????#1\endcsname{@@@@#1}}
1018% \stoptyping
1019%
1020% The following variant is nicer and in principle faster but that gets unnoticed
1021% unless lots of expansion happens. Also, we can use long tags but the internal
1022% expansion will be relatively small (and unlikely more than 4 characters). For
1023% instance, \??xx used to expand to @@xx but now becomes for instance 123::. This
1024% is one character more but in quite some cases we had : after such a tag in the
1025% old situation. In the new situation we create more namespaces and don't need that
1026% : any more, so we end up with on the average the same amount of tokens and
1027% definitely less when we consider cases like \??xx:\c!align: which now is just
1028% \??somealign and therefore has length 5 now (instead of 4+1+5+1=10).
1029%
1030% Eventualy we will have a verbose \blablanamespace and the difference between core
1031% and regular can go ... after all, \xxxparameter can already clash between the two
1032% prefix groups .. if users use this mechanism a lot they should use verbose names
1033% anyway (the old two character names were mostly an optimization as they also
1034% expanded to these characters).
1035
1036% todo: register namespaces at lua end for logging and reverse resolve
1037% todo: move this to syst-ini so that we can use it real early
1038
1039\newinteger\c_mult_interfaces_n_of_namespaces
1040
1041\def\v_interfaces_prefix_template{\the\c_mult_interfaces_n_of_namespaces>}
1042
1043\permanent\protected\def\installnamespace#1% for modules and users
1044  {\ifcsname ????#1\endcsname
1045     \writestatus\m!system{duplicate user namespace '#1'}\wait
1046   \else
1047     \global\advanceby\c_mult_interfaces_n_of_namespaces\plusone
1048     \global\immutable\cdefcsname ????#1\endcsname{\v_interfaces_prefix_template}%
1049   \fi}
1050
1051\permanent\protected\def\installcorenamespace#1%
1052  {\ifcsname ??#1\endcsname
1053     \writestatus\m!system{duplicate core namespace '#1'}\wait
1054   \else
1055     \global\advanceby\c_mult_interfaces_n_of_namespaces\plusone
1056     \global\immutable\cdefcsname ??#1\endcsname{\v_interfaces_prefix_template}%
1057     \clf_registernamespace\c_mult_interfaces_n_of_namespaces{#1}%
1058   \fi}
1059
1060% \permanent\protected\def\installnamespace#1% for modules and users
1061%   {\ifcsname ????#1\endcsname
1062%      \writestatus\m!system{duplicate user namespace '#1'}\wait
1063%    \else
1064%      \global\advanceby\c_mult_interfaces_n_of_namespaces\plusone
1065%      \global\immutable\expandafter\stringdef\csname ????#1\endcsname\c_mult_interfaces_n_of_namespaces
1066%      \clf_registernamespace\c_mult_interfaces_n_of_namespaces{#1}%
1067%    \fi}
1068
1069% \permanent\protected\def\installcorenamespace#1%
1070%   {\ifcsname ??#1\endcsname
1071%      \writestatus\m!system{duplicate core namespace '#1'}\wait
1072%    \else
1073%      \global\advanceby\c_mult_interfaces_n_of_namespaces\plusone
1074%      \global\immutable\expandafter\stringdef\csname ??#1\endcsname\c_mult_interfaces_n_of_namespaces
1075%      \clf_registernamespace\c_mult_interfaces_n_of_namespaces{#1}%
1076%    \fi}
1077
1078\def\mult_interfaces_get_parameters_error_indeed#1#2%
1079  {\clf_showassignerror{#1}{#2}\inputlineno}
1080
1081% We install two core namespaces here, as we want nice error messages. Maybe
1082% we will reserve the first 9.
1083
1084\installcorenamespace{fontinstanceready}
1085\installcorenamespace{fontinstancebasic}
1086\installcorenamespace{fontinstanceclass}
1087
1088%D The next one is handy for local assignments.
1089
1090\installcorenamespace{dummy}
1091
1092\letvalue\??dummy\empty
1093
1094\permanent          \def\dummyparameter           #1{\begincsname\??dummy#1\endcsname}
1095\permanent          \def\directdummyparameter     #1{\begincsname\??dummy#1\endcsname}
1096\permanent\protected\def\setdummyparameter        #1{\defcsname\??dummy#1\endcsname}
1097\permanent\protected\def\setexpandeddummyparameter#1{\edefcsname\??dummy#1\endcsname}
1098\permanent\protected\def\letdummyparameter        #1{\letcsname\??dummy#1\endcsname}
1099\permanent\protected\def\resetdummyparameter      #1{\letcsname\??dummy#1\endcsname\empty}
1100
1101\edef\mult_interfaces_dummy{\??dummy} % nor immutable
1102
1103% \permanent\protected\def\getdummyparameters[#S#1%
1104%   {\if\noexpand#1]%
1105%      \expandafter\gobbleoneargument
1106%    \else
1107%      \let\m_mult_interfaces_namespace\mult_interfaces_dummy
1108%      \expandafter\mult_interfaces_get_parameters_indeed
1109%    \fi#1}
1110
1111% \permanent\protected\def\getdummyparameters[#S#1]%
1112%   {\let\m_mult_interfaces_namespace\mult_interfaces_dummy
1113%    \mult_interfaces_get_parameters_item_okay#1\ignorearguments\ignorearguments}
1114
1115\permanent\protected\def\getdummyparameters[#S#1]%
1116  {\let\m_mult_interfaces_namespace\mult_interfaces_dummy
1117   \mult_interfaces_get_parameters_item#1\ignorearguments\ignorearguments}
1118
1119\mult_interfaces_install_style_and_color_handler
1120  \directdummyparameter
1121  \usedummystyleandcolor
1122  \usedummystyleparameter
1123  \usedummycolorparameter
1124
1125% Maybe a \definecorenamespace[name][directparameter,directsetup][parent] but we
1126% don't gain much. Actually we might just inline all definitions.
1127
1128% \enabletrackers[interfaces.namespaces,context.flush]
1129%
1130% \definenamespace
1131%   [xy]
1132%   [type=module,
1133%    comment=test module,
1134%    version=1,
1135%    name=test,
1136%    style=yes,
1137%    command=yes,
1138%    setup=list,
1139%    set=yes,
1140%    parent=xy]
1141%
1142% \unprotect
1143% \getparameters
1144%   [\????xy]
1145%   [text=]
1146% \protect
1147%
1148% \definetest[one]
1149%
1150% \starttext
1151%
1152%   “\testparameter{text}”
1153%
1154%   \setuptest[text=foo]
1155%
1156%   “\testparameter{text}”
1157%
1158%   \setuptest[one][text=bar]
1159%
1160%   “\testparameter{text}”
1161%
1162% \stoptext
1163%
1164% This is a user (module) command:
1165
1166\permanent\tolerant\protected\def\definenamespace[#1]#*[#2]% namespace settings
1167  {\clf_definenamespace{#1}{#2}}
1168
1169\permanent\protected\def\listnamespaces
1170  {\clf_listnamespaces}
1171
1172%D Helper:
1173%D
1174%D \starttyping
1175%D \showparentchain{@@am}{left}
1176%D \stoptyping
1177
1178\permanent\protected\def\showparentchain#1#2%
1179  {\writestatus\m!system{chain: [ \mult_interfaces_show_parent_chain{#1#2}]}}
1180
1181\def\mult_interfaces_show_parent_chain#1%
1182  {#1 => %
1183   \ifcsname#1:\s!parent\endcsname
1184      \expandafter\mult_interfaces_show_parent_chain\lastnamedcs
1185   \fi}
1186
1187%D Another helper (needs to be applied):
1188
1189\permanent\protected\def\doifelsecommandhandler#1#2% namespace name
1190  {\ifcsname#1#2:\s!parent\endcsname
1191     \expandafter\firstoftwoarguments
1192   \else
1193     \expandafter\secondoftwoarguments
1194   \fi}
1195
1196\aliased\let\doifcommandhandlerelse\doifelsecommandhandler
1197
1198\permanent\protected\def\doifcommandhandler#1#2% namespace name
1199  {\ifcsname#1#2:\s!parent\endcsname
1200     \expandafter\firstofoneargument
1201   \else
1202     \expandafter\gobbleoneargument
1203   \fi}
1204
1205\permanent\protected\def\doifnotcommandhandler#1#2% namespace name
1206  {\ifcsname#1#2:\s!parent\endcsname
1207     \expandafter\gobbleoneargument
1208   \else
1209     \expandafter\firstofoneargument
1210   \fi}
1211
1212\permanent\def\ifcommandhandler#1#2% namespace name
1213  {\ifcsname#1#2:\s!parent\endcsname}
1214
1215% another set of (fast) helpers (grep for usage):
1216
1217\permanent\def\expandnamespaceparameter#1#2#3% \??xx \getp \c!xx \v!yy
1218  {\csname#1\ifcsname#1\expandafter\expandafter\expandafter\mult_aux_expand_namespace_parameter#2#3}
1219
1220\def\mult_aux_expand_namespace_parameter#1#2% \cs \v!yy
1221  {#1\endcsname#1\else#2\fi\endcsname}
1222
1223\permanent\def\expandnamespacemacro#1#2#3% \??xx \some_edefed_cs \c!yy
1224  {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname}
1225
1226\permanent\def\expandnamespacevalue#1#2% \??xx {...} \c!yy == optimized \expandcheckedcsname
1227  {\csname#1\ifcsname#1\normalexpanded{\noexpand\syst_helpers_expand_checked_value{#2}}}
1228
1229\def\syst_helpers_expand_checked_value#1#2%
1230  {#1\endcsname#1\else#2\fi\endcsname}
1231
1232%D Conventions:
1233%D
1234%D \starttyping
1235%D \newinteger     \c_class_whatever
1236%D \newconditional \c_class_whatever
1237%D \newconstant    \c_class_whatever
1238%D \newdimension   \d_class_whatever
1239%D \newgluespec    \s_class_whatever
1240%D \newmuskip      \s_class_whatever
1241%D \newbox         \b_class_whatever
1242%D \newtoks        \t_class_whatever
1243%D
1244%D \edef\p_class_whatever{\classparameter\c!whatever}
1245%D \edef\m_class_whatever{whatever}
1246%D \stoptyping
1247
1248% experiment: in principle this is faster but not that noticeable as we don't do that
1249% many assignments and mechanism that do are also slow; the advantage is mostly nicer
1250% in tracing
1251
1252\mutable\let\c_mult_set\relax
1253
1254\protected\def\mult_interfaces_install_definition_set#1#2#3#4#5#6#7%
1255  {\newinteger#3%
1256   \lettonothing#6%
1257   \protected\def#2%
1258     {\expandafter\let\expandafter\c_mult_set\csname #1_t_#6\endcsname
1259      \ifrelax\c_mult_set
1260        \expandafter\newtoks\c_mult_set
1261        \letcsname#1_t_#6\endcsname\c_mult_set
1262      \fi}
1263   \frozen\protected\def#4##1%
1264     {\pushmacro#6%
1265      \advanceby#3\plusone
1266      \cdef#6{##1}%
1267      \unprotect}%
1268   \frozen\protected\def#5%
1269     {\protect
1270      \advanceby#3\minusone
1271      \popmacro#6}%
1272   \frozen\protected\def#7##1%
1273     {\cdef#6{##1}%
1274      #2%
1275      \the\c_mult_set\relax}}
1276
1277\permanent\protected\def\installdefinitionset#1#2%
1278  {\normalexpanded
1279     {\mult_interfaces_install_definition_set
1280        {\noexpand#1}% \??aa
1281        \expandafter\noexpand\csname set_#2_toks\endcsname
1282        \expandafter\noexpand\csname #2_nesting_depth\endcsname
1283        \expandafter\noexpand\csname push#2\endcsname
1284        \expandafter\noexpand\csname pop#2\endcsname
1285        \expandafter\noexpand\csname current#2\endcsname
1286        \expandafter\noexpand\csname use#2\endcsname}}
1287
1288\protected\def\mult_interfaces_install_definition_set_member#1#2#3#4#5#6#7#8#9% no everysetups etc
1289  {\let#5#2%
1290   \frozen\protected\def#2%
1291     {\ifcase#4\relax\expandafter#5\else\expandafter#6\fi}%
1292   \tolerant\protected\def#6[##S##1]##*[##S##2]%
1293     {\ifarguments\or
1294        #3\toksapp\c_mult_set{#7[##1]}%
1295      \or
1296        #3\toksapp\c_mult_set{#8[##1][##2]}%
1297      \fi}}
1298
1299\permanent\protected\def\installdefinitionsetmember#1#2#3#4%
1300  {\normalexpanded
1301     {\mult_interfaces_install_definition_set_member
1302        {\noexpand#3}% \??aa
1303        \expandafter\noexpand\csname setup#4\endcsname
1304        \expandafter\noexpand\csname set_#2_toks\endcsname
1305        \expandafter\noexpand\csname #2_nesting_depth\endcsname
1306        \expandafter\noexpand\csname normal_setup_#4\endcsname
1307        \expandafter\noexpand\csname delayed_setup_#4\endcsname
1308        \expandafter\noexpand\csname setup#4_\s!single\endcsname
1309        \expandafter\noexpand\csname setup#4_\s!double\endcsname}}
1310
1311%D Another experiment:
1312
1313\protected\def\mult_interfaces_install_parent_injector#1#2#3#4%
1314  {\frozen\protected\def#4##1%
1315     {\ifempty#3%
1316        \cdefcsname#1#2:\s!parent\endcsname{#1##1}% was def
1317      \fi}}
1318
1319\permanent\protected\def\installparentinjector#1#2%
1320  {\normalexpanded{\mult_interfaces_install_parent_injector
1321     {\noexpand#1}%
1322     \expandafter\noexpand\csname current#2\endcsname
1323     \expandafter\noexpand\csname current#2parent\endcsname
1324     \expandafter\noexpand\csname inject#2parent\endcsname}}
1325
1326%D Cheaper (assumes grouping at some point):
1327
1328\permanent\protected\def\mult_interfaces_install_local_current_injector#1#2#3#4#5%
1329  {\lettonothing#4% \currentglobalXXX
1330   \protected\def#5##1%
1331     {\advanceby#2\plusone
1332      \cdef#3{##1:\the#2}% \currentXXX
1333      \cdef#4{##1}% \currentglobalXXX
1334      \cdefcsname#1#3:\s!parent\endcsname{#1##1}}}
1335
1336\permanent\protected\def\installlocalcurrenthandler#1#2% \??XXX {XXX}
1337  {\expandafter\newinteger\csname#1:\s!counter\endcsname
1338   \normalexpanded{\mult_interfaces_install_local_current_injector
1339     {\noexpand#1}%
1340     \expandafter\noexpand\csname #1:\s!counter\endcsname
1341     \expandafter\noexpand\csname current#2\endcsname
1342     \expandafter\noexpand\csname currentglobal#2\endcsname
1343     \expandafter\noexpand\csname setlocal#2current\endcsname}}
1344
1345%  \unprotect
1346%
1347%  \installcorenamespace {test} \installcommandhandler \??test {test} \??test
1348%  \protected\def\TestMeA[#1]%
1349%    {\edef\currenttest{#1}
1350%     \edef\p_before{\testparameter\c!before}%
1351%     \ifempty\p_before \relax \else \relax \fi}
1352%  \protected\def\TestMeB[#1]%
1353%    {\edef\currenttest{#1}
1354%     \doifelsenothing{\testparameter\c!before}\relax\relax}
1355%  \protected\def\TestMeC[#1]%
1356%    {\edef\currenttest{#1}
1357%     \expandafter\expandafter\expandafter\ifempty\testparameter\c!before \relax \else \relax \fi}
1358%  \protected\def\TestMeD[#1]%
1359%    {\edef\currenttest{#1}
1360%     \doubleexpandafter\ifempty\testparameter\c!before \relax \else \relax \fi}
1361%
1362%  \protect
1363%
1364%  \starttext
1365%    \definetest[foo] \definetest[bar][foo] \setuptest[bar][before=indeed]
1366%    \testfeatureonce{100000}{\TestMeA[bar]} A:\elapsedtime \par % 0.502
1367%    \testfeatureonce{100000}{\TestMeB[bar]} B:\elapsedtime \par % 0.530
1368%    \testfeatureonce{100000}{\TestMeC[bar]} C:\elapsedtime \par % 0.487
1369%    \testfeatureonce{100000}{\TestMeD[bar]} D:\elapsedtime \par % 0.493
1370%  \stoptext
1371
1372% There is no real demand for this ... even if this is two to three times as fast we
1373% only gain a few milliseconds:
1374%
1375% \starttyping
1376% \protected\def\foo#1{[foo:#1]}
1377%
1378% \installcommalistprocessor                        {foo} \foo
1379% \installcommalistprocessorcommand \processfoolist \foo
1380%
1381% \infofont
1382%
1383% \commalistprocessor{foo}[a,b,c,{x,y,z},d]\par
1384% \processfoolist[a, b, c, {x,y,z}, d]\par
1385% \processcommalist[{x,y,z}]\foo\blank
1386%
1387% \commalistprocessor{foo}[{x,y,z},a]\par
1388% \commalistprocessor{foo}[{x,y,z}]\par
1389% \processfoolist[{x,y,z},a]\par
1390% \processfoolist[{x,y,z}]\par
1391% \processcommalist[{x,y,z}]\foo\blank
1392%
1393% \protected\def\foo#1{}
1394%
1395% \testfeatureonce{400000}{\processfoolist         [fixed,middle,bar]}     \elapsedtime\quad
1396%%\testfeatureonce{400000}{\commalistprocessor{foo}[fixed,middle,bar]}     \elapsedtime\quad
1397% \testfeatureonce{400000}{\processcommalist       [fixed,middle,bar]\foo} \elapsedtime\quad
1398% \stoptyping
1399%
1400% For instance the luatex manual only has some 3000 calls. But I keep this around as one
1401% never knows when we might need it.
1402
1403\installcorenamespace{commalistprocessor}
1404\installcorenamespace{commalistprocessoraction}
1405
1406% \installcorenamespace{commalistprocessorwrap}
1407% \installcorenamespace{commalistprocessorfirst}
1408% \installcorenamespace{commalistprocessornext}
1409%
1410% \permanent\protected\def\installcommalistprocessor#1#2% 5 macro names overhead
1411%   {\protected\edefcsname\??commalistprocessor#1\endcsname[%
1412%      {\csname\??commalistprocessorwrap#1\endcsname\relax}% \relax preserves {}
1413%    \protected\edefcsname\??commalistprocessorwrap#1\endcsname##1]%
1414%      {\csname\??commalistprocessorfirst#1\endcsname##S##1,]}%
1415%    \protected\edefcsname\??commalistprocessorfirst#1\endcsname\relax
1416%      {\csname\??commalistprocessornext#1\endcsname}%
1417%    \protected\edefcsname\??commalistprocessornext#1\endcsname
1418%      {\noexpand\futureexpandis]%
1419%         \noexpand\gobbleoneargument
1420%         \csname\??commalistprocessoraction#1\endcsname}
1421%    \protected\edefcsname\??commalistprocessoraction#1\endcsname##1,%
1422%      {\noexpand#2{##1}%
1423%       \csname\??commalistprocessornext#1\endcsname}}
1424
1425\permanent\protected\def\installcommalistprocessor#1#2% 2 macro names overhead
1426  {\tolerant\protected\edefcsname\??commalistprocessor#1\endcsname[##S##1]%
1427     {\csname\??commalistprocessoraction#1\endcsname##1\ignorearguments\ignorearguments}%
1428   \tolerant\protected\edefcsname\??commalistprocessoraction#1\endcsname##S##1,%
1429     {\noexpand\ifarguments\noexpand\or
1430        \noexpand#2{##1}%
1431        \noexpand\expandafter\csname\??commalistprocessoraction#1\endcsname
1432      \noexpand\fi}}
1433
1434\permanent\protected\def\installcommalistprocessorcommand#1#2% \processor \action
1435  {\cdef\p_name{\csstring#2}%
1436   \installcommalistprocessor\p_name{#2}%
1437   \expandafter\let\expandafter#1\csname\??commalistprocessor\p_name\endcsname}
1438
1439\permanent\protected\def\commalistprocessor#1{\csname\??commalistprocessor#1\endcsname}
1440
1441%D This is a special one, used in \METAPOST\ graphic support. It is english only because
1442%D we have no multilingual interface in \METAFUN.
1443
1444\startinterface english
1445    \let\mult_interfaces_install_native_auto_setup_handler\mult_interfaces_install_auto_setup_handler
1446    \aliased\let\installbasicnativeautosetuphandler\installbasicsetuphandler
1447\stopinterface
1448
1449\ifdefined\installnativebasicsetuphandler \else
1450
1451              \let\mult_interfaces_adef_yes\mult_interfaces_adef
1452    \protected\def\mult_interfaces_adef_nop#1#2{\defcsname#1#2\endcsname}
1453
1454    \protected\def\mult_interfaces_install_native_auto_setup_handler#1#2#3#4#5#6#7#8%
1455      {\newtoks#4%
1456       \frozen\protected\def#5{\mult_interfaces_get_parameters{#1#3:}}%
1457       \frozen\tolerant\protected\def#2[##S##1]##*[##S##2]##*[##S##3]%
1458         {\let#7#3%
1459          \ifarguments
1460            \lettonothing#3%
1461            \expand#4%
1462          \or
1463            \lettonothing#3%
1464            \let\mult_interfaces_adef\mult_interfaces_adef_nop
1465            \mult_interfaces_get_parameters{#1:}[##1]%
1466            \let\mult_interfaces_adef\mult_interfaces_adef_yes
1467            \expand#4%
1468          \or
1469            \def#8####1%
1470              {\cdef#3{####1}%
1471               #6% checks parent and sets if needed
1472               \let\mult_interfaces_adef\mult_interfaces_adef_nop
1473               \mult_interfaces_get_parameters{#1#3:}[##2]%
1474               \let\mult_interfaces_adef\mult_interfaces_adef_yes
1475               \expand#4}%
1476            \processcommalist[##1]#8%
1477          \or
1478            \def#8####1%
1479              {\cdef#3{####1}%
1480               \cdefcsname#1#3:\s!parent\endcsname{#1##2}%
1481               \let\mult_interfaces_adef\mult_interfaces_adef_nop
1482               \mult_interfaces_get_parameters{#1#3:}[##3]% always sets parent
1483               \let\mult_interfaces_adef\mult_interfaces_adef_yes
1484               \expand#4}%
1485            \processcommalist[##1]#8%
1486          \fi
1487          \let#3#7}}
1488
1489    \permanent\protected\def\installnativeautosetuphandler#1#2%
1490      {\mutable\letcsname current#2\endcsname\empty
1491       \normalexpanded
1492         {\mult_interfaces_install_native_auto_setup_handler
1493            {\noexpand#1}% \??aa
1494            \expandafter\noexpand\csname setup#2\endcsname
1495            \expandafter\noexpand\csname current#2\endcsname
1496            \expandafter\noexpand\csname everysetup#2\endcsname
1497            \expandafter\noexpand\csname setupcurrent#2\endcsname
1498            \expandafter\noexpand\csname check#2parent\endcsname
1499            \expandafter\noexpand\csname saved_setup_current#2\endcsname
1500            \expandafter\noexpand\csname nested_setup_current#2\endcsname}}
1501
1502    \permanent\protected\def\installbasicnativeautosetuphandler#1#2%
1503      {\installbasicparameterhandler {#1}{#2}%
1504       \installnativeautosetuphandler{#1}{#2}}
1505
1506\fi
1507
1508\protect \endinput
1509