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