supp-box.mkxl /size: 96 Kb    last modification: 2024-01-16 09:03
1%D \module
2%D   [       file=supp-box,
3%D        version=1995.10.10,
4%D          title=\CONTEXT\ Support Macros,
5%D       subtitle=Boxes,
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\writestatus{loading}{ConTeXt Support Macros / Boxes}
15
16\unprotect
17
18\permanent\integerdef\negatelistsigncode\numexpr
19    \negatexlistsigncode
20   +\negateylistsigncode
21\relax
22
23%D And some dimensions:
24
25\newdimension\strutht    % see above
26\newdimension\strutdp
27\newdimension\struthtdp
28
29\newdimension\givenwidth
30\newdimension\givenheight
31\newdimension\givendepth
32
33\newdimension\lastnaturalboxwd  % maybe alias !
34\newdimension\lastnaturalboxht
35\newdimension\lastnaturalboxdp
36
37\pushoverloadmode
38    \newuserunit\strutht   sh
39    \newuserunit\strutdp   sd
40    \newuserunit\struthtdp st
41\popoverloadmode
42
43\registerctxluafile{supp-box}{autosuffix}
44
45% \fixupboxesmode\plusone % gone: is now the default
46
47%D This module implements some box manipulation macros. Some are quite simple, some
48%D are more advanced and when understood well, all can be of use.
49%D
50%D \macros
51%D   {strutdp,strutht,strutwd}
52%D
53%D The next shortcuts save memory and keying. The width is normally zero points (if
54%D not, you're in trouble). These shortcuts can be used like a dimension, opposite
55%D to the core macros \type {\strutdepth} and alike, which are values.
56
57\iffalse
58    \def\strutdp  {\dp\strutbox}   % overloaded in spac-ver
59    \def\strutht  {\ht\strutbox}   % overloaded in spac-ver
60    \def\struthtdp{\htdp\strutbox} % overloaded in spac-ver
61\fi
62
63\permanent\protected\def\strutwd {\wd\strutbox}
64\permanent\protected\def\strutgap{\dimexpr\strutht-\strutdp\relax}
65
66%D \macros
67%D   {voidbox,nextbox}
68%D
69%D Let's start with an easy one. The next macro hides the ugly \type {@} in \type
70%D {\voidb@x}.
71
72\ifdefined\voidbox \else \newbox\voidbox \fi
73\ifdefined\nextbox \else \newbox\nextbox \fi
74
75%D \macros
76%D   {nextdepth}
77%D
78%D Let's start with a rather simple declaration. Sometimes we need to save the \TEX\
79%D \DIMENSION\ \type{\prevdepth} and append it later on. The name \type {\nextdepth}
80%D suits this purpose well.
81
82\newdimension\nextdepth
83
84%D \macros
85%D   {smashbox, smashboxed, smashedbox}
86%D
87%D Smashing is introduced in \PLAIN\ \TEX, and stands for reducing the dimensions of
88%D a box to zero. The most resolute one is presented first.
89
90% \permanent\protected\def\smashbox#1%
91%   {\wd#1\zeropoint
92%    \ht#1\zeropoint
93%    \dp#1\zeropoint}
94%
95% \permanent\protected\def\smashboxed#1%
96%   {\wd#1\zeropoint
97%    \ht#1\zeropoint
98%    \dp#1\zeropoint
99%    \box#1\relax}
100
101%D \macros
102%D   {hsmashbox,vsmashbox}
103%D
104%D Smashing can be used for overlaying boxes. Depending on the mode, horizontal or
105%D vertical, one can use:
106
107% \permanent\protected\def\hsmashbox#1%
108%   {\wd#1\zeropoint}
109%
110% \permanent\protected\def\vsmashbox#1%
111%   {\ht#1\zeropoint
112%    \dp#1\zeropoint}
113
114%D The next implementation is less sensitive for spurious spaces.
115
116\newinteger\c_boxes_register
117
118\permanent\protected\def\smashbox
119  {\afterassignment\syst_boxes_smash_boxes_register\c_boxes_register}
120
121\def\syst_boxes_smash_boxes_register
122  {\wd\c_boxes_register\zeropoint
123   \ht\c_boxes_register\zeropoint
124   \dp\c_boxes_register\zeropoint}
125
126\permanent\protected\def\hsmashbox
127  {\afterassignment\syst_boxes_hsmashed_boxes_register\c_boxes_register}
128
129\def\syst_boxes_hsmashed_boxes_register
130  {\wd\c_boxes_register\zeropoint}
131
132\permanent\protected\def\vsmashbox
133  {\afterassignment\syst_boxes_vsmashed_boxes_register\c_boxes_register}
134
135\def\syst_boxes_vsmashed_boxes_register
136  {\ht\c_boxes_register\zeropoint
137   \dp\c_boxes_register\zeropoint}
138
139\permanent\protected\def\smashedbox
140  {\afterassignment\syst_boxes_smashed_boxes_register\c_boxes_register}
141
142\protected\def\syst_boxes_smashed_boxes_register
143  {\wd\c_boxes_register\zeropoint
144   \ht\c_boxes_register\zeropoint
145   \dp\c_boxes_register\zeropoint
146   \box\c_boxes_register}
147
148\aliased\let\smashboxed\smashedbox
149
150%D \macros
151%D   {hsmash,vsmash,
152%D    hsmashed,vsmashed}
153%D
154%D While the previous macros expected a \BOX, the next act on a content. They are
155%D some subtle differences betreen the smash and smashed alternatives. The later
156%D ones reduce all dimensions to zero.
157
158\permanent\protected\def\hsmash  {\bgroup\dowithnextboxcs\syst_boxes_hsmashed_nextbox\hbox}
159\permanent\protected\def\vsmash  {\bgroup\dowithnextboxcs\syst_boxes_vsmashed_nextbox\vbox}
160\permanent\protected\def\hsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \hbox}
161\permanent\protected\def\vsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \vbox}
162
163\protected\def\syst_boxes_hsmashed_nextbox
164  {\wd\nextbox\zeropoint
165   \box\nextbox
166   \egroup}
167
168\protected\def\syst_boxes_vsmashed_nextbox
169  {\ht\nextbox\zeropoint
170   \dp\nextbox\zeropoint
171   \box\nextbox
172   \egroup}
173
174\protected\def\syst_boxes_smashed_nextbox
175  {\ht\nextbox\zeropoint
176   \dp\nextbox\zeropoint
177   \wd\nextbox\zeropoint
178   \box\nextbox
179   \egroup}
180
181%D \macros
182%D   {smashedhbox,smashedvbox}
183%D
184%D Also handy (all dimensions zeroed):
185%D
186%D \starttyping
187%D \smashedhbox to ... {...}
188%D \smashedvbox to ... {...}
189%D \stoptyping
190
191\permanent\protected\def\smashedhbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\hbox}
192\permanent\protected\def\smashedvbox{\vpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\vbox}
193
194%D \starttyping
195%D \startTEXpage[offset=1dk,width=4em]
196%D   \dontleavehmode \hbox    {0} 0\par
197%D   \dontleavehmode \vphantom{0} 0\par
198%D   \dontleavehmode \hphantom{0} 0\par
199%D   $\textstyle        \vphantom{0}$ $\textstyle 0$\par
200%D   $\scriptstyle      \vphantom{0}$ $\scriptstyle 0$\par
201%D   $\scriptscriptstyle\vphantom{0}$ $\scriptscriptstyle 0$\par
202%D \stopTEXpage
203%D \stoptyping
204
205% \newinteger\c_boxes_math_style
206%
207% \protected\def\syst_boxes_math_set_nextbox#1%
208%   {\c_boxes_math_style\normalmathstyle
209%    \setbox\nextbox\hbox{\normalstartimath\mathsurround\zeropoint\triggermathstyle\c_boxes_math_style{#1}\normalstopimath}}
210
211\protected\def\syst_boxes_math_set_nextbox#1%
212  {\setbox\nextbox\hbox\expandafter\bgroup
213     \expandafter\normalstartimath\expandafter\givenmathstyle\the\mathstackstyle
214     \mathsurround\zeropoint{#1}%
215     \normalstopimath
216   \egroup}
217
218%D \macros
219%D   {smash}
220%D
221%D This smash alternative takes an optional arg [whdtb] as well as is potentially
222%D catcode safer. It is needed by the math module (although the \type {\leavevmode}
223%D is not added here).
224
225\permanent\protected\def\smash
226  {\begingroup
227   \futureexpandis[\syst_boxes_smash_yes\syst_boxes_smash_nop}
228
229\def\syst_boxes_smash_nop
230  {\edef\m_boxes_smash_options{hd}%
231   \futurelet\nexttoken\syst_boxes_smash_indeed}
232
233\def\syst_boxes_smash_yes[#1]%
234  {\edef\m_boxes_smash_options{#1}%
235   \futurelet\nexttoken\syst_boxes_smash_indeed}
236
237\def\syst_boxes_smash_indeed
238  {\ifmmode
239     \expandafter\syst_boxes_smash_math
240   \orelse\ifx\nexttoken\bgroup
241     \expandafter\syst_boxes_smash_hbox
242   \else
243     \expandafter\syst_boxes_smash_text
244   \fi}
245
246\def\syst_boxes_smash_math#1%
247  {\syst_boxes_math_set_nextbox{#1}%
248   \syst_boxes_smash_process}
249
250\def\syst_boxes_smash_hbox
251  {\dowithnextboxcs\syst_boxes_smash_process\hbox}
252
253\def\syst_boxes_smash_text#1%
254  {\setbox\nextbox\hbox{#1}%
255   \syst_boxes_smash_process}
256
257\def\syst_boxes_smash_process
258  {\expandafter\syst_boxes_smash_process_option\m_boxes_smash_options\relax
259   \box\nextbox
260   \endgroup}
261
262\installcorenamespace {smashoptions}
263
264\defcsname\??smashoptions   w\endcsname{\wd\nextbox\zeropoint}
265\defcsname\??smashoptions   h\endcsname{\ht\nextbox\zeropoint}
266\defcsname\??smashoptions   d\endcsname{\dp\nextbox\zeropoint}
267\defcsname\??smashoptions   t\endcsname{\ht\nextbox\zeropoint}
268\defcsname\??smashoptions   b\endcsname{\dp\nextbox\zeropoint}
269\defcsname\??smashoptions  hd\endcsname{\ht\nextbox\zeropoint\dp\nextbox\zeropoint}
270\defcsname\??smashoptions whd\endcsname{\wd\nextbox\zeropoint\ht\nextbox\zeropoint\dp\nextbox\zeropoint}
271
272\def\syst_boxes_smash_process_option#1%
273  {\ifx#1\relax\else
274     \begincsname\??smashoptions#1\endcsname
275     \expandafter\syst_boxes_smash_process_option
276   \fi}
277
278\def\syst_boxes_lower_nextbox_dp
279  {\setbox\nextbox\hpack{\lower\dp\nextbox\box\nextbox}}
280
281%D \starttabulate[|l|l|]
282%D \NC w   \NC \ruledhbox{\smash  [w]{This is some great smashing, isn't it?}} \NC \NR
283%D \NC h   \NC \ruledhbox{\smash  [h]{This is some great smashing, isn't it?}} \NC \NR
284%D \NC d   \NC \ruledhbox{\smash  [d]{This is some great smashing, isn't it?}} \NC \NR
285%D \NC tb  \NC \ruledhbox{\smash [tb]{This is some great smashing, isn't it?}} \NC \NR
286%D \NC whd \NC \ruledhbox{\smash[whd]{This is some great smashing, isn't it?}} \NC \NR
287%D \stoptabulate
288
289%D \macros
290%D   {phantom, hphantom, vphantom, mathstrut}
291%D
292%D The next implementation of \type {\phantom} cum suis does not grab an argument in
293%D the non||math case, which is better.
294%D
295%D Due to a complicated call to \type {\mathpallete} and thereby \type
296%D {\mathchoice}, the next macro looks ugly. We also take care of non||braced
297%D arguments.
298
299\permanent\protected\def\phantom {\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed  }
300\permanent\protected\def\vphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_v}
301\permanent\protected\def\hphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_h}
302
303\def\syst_boxes_phantom_math  #1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make  }
304\def\syst_boxes_phantom_math_v#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_v}
305\def\syst_boxes_phantom_math_h#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_h}
306
307\def\syst_boxes_phantom_hbox  {\dowithnextboxcs\syst_boxes_phantom_make  \hbox} % always hbox
308\def\syst_boxes_phantom_hbox_v{\dowithnextboxcs\syst_boxes_phantom_make_v\hbox} % always hbox
309\def\syst_boxes_phantom_hbox_h{\dowithnextboxcs\syst_boxes_phantom_make_h\hbox} % always hbox
310
311\def\syst_boxes_phantom_text  #1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make  } % always hbox
312\def\syst_boxes_phantom_text_v#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_v} % always hbox
313\def\syst_boxes_phantom_text_h#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_h} % always hbox
314
315\def\syst_boxes_phantom_indeed
316  {\ifmmode
317     \expandafter\syst_boxes_phantom_math
318   \orelse\ifx\nexttoken\bgroup
319     \expandafter\syst_boxes_phantom_hbox
320   \else
321     \expandafter\syst_boxes_phantom_text
322   \fi}
323
324\def\syst_boxes_phantom_indeed_v
325  {\ifmmode
326     \expandafter\syst_boxes_phantom_math_v
327   \orelse\ifx\nexttoken\bgroup
328     \expandafter\syst_boxes_phantom_hbox_v
329   \else
330     \expandafter\syst_boxes_phantom_text_v
331   \fi}
332
333\def\syst_boxes_phantom_indeed_h
334  {\ifmmode
335     \expandafter\syst_boxes_phantom_math_h
336   \orelse\ifx\nexttoken\bgroup
337     \expandafter\syst_boxes_phantom_hbox_h
338   \else
339     \expandafter\syst_boxes_phantom_text_h
340   \fi}
341
342\def\syst_boxes_phantom_make
343  {\setbox\scratchbox\emptyhbox
344   \ht\scratchbox\ht\nextbox
345   \dp\scratchbox\dp\nextbox
346   \wd\scratchbox\wd\nextbox
347   \box\scratchbox
348   \endgroup}
349
350\def\syst_boxes_phantom_make_v
351  {\setbox\scratchbox\emptyhbox
352   \ht\scratchbox\ht\nextbox
353   \dp\scratchbox\dp\nextbox
354   \box\scratchbox
355   \endgroup}
356
357\def\syst_boxes_phantom_make_h
358  {\setbox\scratchbox\emptyhbox
359   \wd\scratchbox\wd\nextbox
360   \box\scratchbox
361   \endgroup}
362
363%D We also define plain's \type {\mathstrut}.
364
365\permanent\protected\def\mathstrut{\mathstack{\vphantom(}} % can be made faster by inlining
366
367%D \macros
368%D   {getboxheight}
369%D
370%D Although often needed, \TEX\ does not support arithmics like:
371%D
372%D \starttyping
373%D \dimen0 = \ht0 + \dp0
374%D \stoptyping
375%D
376%D so we implemented:
377%D
378%D \starttyping
379%D \getboxheight ... \of \box...
380%D \stoptyping
381%D
382%D For instance,
383%D
384%D \starttyping
385%D \getboxheight \dimen0 \of \box0
386%D \getboxheight \someheight \of \box \tempbox
387%D \stoptyping
388%D
389%D The implementation is rather stupid:
390%D
391%D \starttyping
392%D \def\getboxheight#1\of#2\box#3%
393%D   {#1\ht#3\advanceby#1\dp#3\relax}
394%D \stoptyping
395%D
396%D The next alternative is slightly more clever, since it accepts \type {{12}} as
397%D well as \type {12} as box number.
398
399\permanent\protected\def\getboxheight#1\of#2\box#3%
400  {\def\next{#1\htdp\c_boxes_register}%
401   \afterassignment\next\c_boxes_register=#3}
402
403%D For a long time the following three macros were part of the grid snapping core
404%D module, but it makes more sense to have them here so that users can see them.
405%D
406%D \macros
407%D   {getnoflines, getroundednoflines, getrawnoflines}
408%D
409%D Het commando \type {\getnoflines} converteert een hoogte (dimensie) in een aantal
410%D regels en kent dit toe aan \type {\noflines}.
411%D
412%D \starttyping
413%D \getnoflines{dimensie}
414%D \stoptyping
415%D
416%D Er wordt gedeeld door \type {\openlineheight} en een hoogte van~0pt komt overeen
417%D met 0~regels. The raw alternative does not round. See the \MKII\ and \MKIV\ files
418%D for historic variants.
419
420\ifdefined\roundingeps \else \newdimension\roundingeps \roundingeps=10sp \fi
421
422\newinteger  \noflines
423\newdimension\noflinesheight
424
425\permanent\protected\def\getnoflines#1%
426  {\noflinesheight#1\relax
427   \ifzeropt\noflinesheight
428     \noflines\zerocount
429   \orelse\ifdim\noflinesheight>\zeropoint
430     \advanceby\noflinesheight-\roundingeps
431     \divideby\noflinesheight\openlineheight
432     \noflines\noflinesheight
433     \advanceby\noflines\plusone
434   \else
435     \advanceby\noflinesheight\roundingeps
436     \divideby\noflinesheight\openlineheight
437     \noflines\noflinesheight
438     \advanceby\noflines\minusone
439   \fi}
440
441\permanent\protected\def\getroundednoflines#1%
442  {\noflinesheight#1\relax
443   \ifzeropt\noflinesheight
444     \noflines\zerocount
445   \orelse\ifdim\noflinesheight>\zeropoint
446     \advanceby\noflinesheight\roundingeps
447     \divideby\noflinesheight\openlineheight
448     \noflines\noflinesheight
449   \else
450     \advanceby\noflinesheight-\roundingeps
451     \divideby\noflinesheight\openlineheight
452     \noflines\noflinesheight
453   \fi}
454
455\permanent\protected\def\getrawnoflines#1%
456  {\noflinesheight#1\relax
457   \ifzeropt\noflinesheight
458     \noflines\zerocount
459   \orelse\ifdim\noflinesheight>\zeropoint
460     \advanceby\noflinesheight\roundingeps
461     \advanceby\noflinesheight.5\openlineheight
462     \divideby\noflinesheight\openlineheight
463     \noflines\noflinesheight
464   \else
465     \advanceby\noflinesheight-\roundingeps
466     \advanceby\noflinesheight-.5\openlineheight
467     \divideby\noflinesheight\openlineheight
468     \noflines\noflinesheight
469   \fi}
470
471%D Let's proof that it works:
472%D
473%D \startbuffer
474%D \scratchdimen\dimexpr(3pt)               \getnoflines\scratchdimen  1=\the\noflines \endgraf
475%D \scratchdimen\dimexpr(10\lineheight)     \getnoflines\scratchdimen 10=\the\noflines \endgraf
476%D \scratchdimen\dimexpr(10.1\lineheight)   \getnoflines\scratchdimen 11=\the\noflines \endgraf
477%D \scratchdimen\dimexpr(10.5\lineheight)   \getnoflines\scratchdimen 11=\the\noflines \endgraf
478%D \scratchdimen\dimexpr(10.9\lineheight)   \getnoflines\scratchdimen 11=\the\noflines \endgraf
479%D \scratchdimen\dimexpr(10\lineheight+3pt) \getnoflines\scratchdimen 11=\the\noflines \endgraf
480%D \scratchdimen\dimexpr(10\lineheight+3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf
481%D \scratchdimen\dimexpr(10\lineheight-3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf
482%D
483%D \scratchdimen\dimexpr(3pt)               \getrawnoflines\scratchdimen  0=\the\noflines \endgraf
484%D \scratchdimen\dimexpr(10\lineheight)     \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
485%D \scratchdimen\dimexpr(10.1\lineheight)   \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
486%D \scratchdimen\dimexpr(10.5\lineheight)   \getrawnoflines\scratchdimen 11=\the\noflines \endgraf
487%D \scratchdimen\dimexpr(10.9\lineheight)   \getrawnoflines\scratchdimen 11=\the\noflines \endgraf
488%D \scratchdimen\dimexpr(10\lineheight+3pt) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
489%D \scratchdimen\dimexpr(10\lineheight+3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
490%D \scratchdimen\dimexpr(10\lineheight-3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
491%D \stopbuffer
492%D
493%D \typebuffer \getbuffer
494
495%D \macros
496%D   {determinenoflines}
497%D
498%D The next macro determines the number of lines and returns it it \type
499%D {\noflines}. The macro works reasonable well as long as the content can be
500%D unboxed.
501%D
502%D \starttyping
503%D \determinenoflines{test\\test}
504%D \determinenoflines{\bfd test\\test}
505%D \determinenoflines{\definedfont[Sans at 40pt]test\\test}
506%D \stoptyping
507
508% \def\syst_boxes_determine_noflines % can be mkiv'd
509%   {\beginofshapebox
510%      \unvbox\nextbox
511%    \endofshapebox
512%    \globalscratchcounter\zerocount
513%    \reshapebox{\global\advanceby\globalscratchcounter\plusone}%
514%    \expandafter\egroup\expandafter\noflines\the\globalscratchcounter\relax}
515
516\def\syst_boxes_determine_noflines
517  {\expandafter\egroup\expandafter\noflines\noflinesinbox\nextbox\relax}
518
519\permanent\protected\def\determinenoflines
520  {\bgroup
521   \forgetall
522   \enforced\let\crlf\endgraf
523   \enforced\let\\\endgraf
524   \dowithnextboxcs\syst_boxes_determine_noflines\vbox}
525
526\def\determinednoflines#1%
527  {\localcontrolled{\determinenoflines{#1}}\noflines}
528
529%D \macros
530%D   {doiftextelse, doiftext}
531%D
532%D When \type {\doifelse} cum suis hopelessly fail, for instance because we pass
533%D data, we can fall back on the next macro:
534%D
535%D \starttyping
536%D \doiftextelse {data} {then branch} {else branch}
537%D \doiftext     {data} {then branch}
538%D \stoptyping
539
540% performance:
541%
542% \ifcondition\validtext {...}T\else F\fi   4.47
543% \doifelsetext          {...}{T}{F}        4.91
544% \iftext                {...}T\else F\fi   5.01
545%
546% \ifcondition\validtext {}T\else F\fi      0.22
547% \doifelsetext          {}{T}{F}           1.02
548% \iftext                {}T\else F\fi      0.39
549
550\permanent\protected\def\doifelsetext#1%
551  {\begingroup
552   \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
553     {\settrialtypesetting
554      \ignorespaces#1\removeunwantedspaces}%
555   \ifzeropt\wd\scratchbox
556     \endgroup\expandafter\secondoftwoarguments
557   \else
558     \endgroup\expandafter\firstoftwoarguments
559   \fi}
560
561\permanent\protected\def\doiftext#1%
562  {\begingroup
563   \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
564     {\settrialtypesetting
565      \ignorespaces#1\removeunwantedspaces}%
566   \ifzeropt\wd\scratchbox
567     \endgroup\expandafter\gobbleoneargument
568   \else
569     \endgroup\expandafter\firstofoneargument
570   \fi}
571
572\permanent\protected\def\validtext#1%
573  {\ifparameter#1\or
574     \begingroup
575     \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
576       {\settrialtypesetting
577        \ignorespaces#1\removeunwantedspaces}%
578     \normalexpanded{\endgroup\noexpand\expandafter\ifzeropt\wd\scratchbox\if_false\else\if_true\fi}%
579   \else
580     \expandafter\if_false
581   \fi}
582
583% \iftext{xx}     YES\else NOP\fi
584% \iftext{}       YES\else NOP\fi
585% \iftext{\strut} YES\else NOP\fi
586% \iftext{ }      YES\else NOP\fi
587
588% more efficient but maybe fragile: \nospacing#1
589
590\aliased\let\doiftextelse\doifelsetext
591
592%D \macros
593%D   {dowithnextbox,nextbox}
594%D
595%D Sometimes we want a macro to grab a box and do something on the content. One
596%D could pass an argument to a box, but this can violate the specific \CATCODES\ of
597%D its content and leads to unexpected results. The next macro treats the following
598%D braced text as the content of a box and manipulates it afterwards in a predefined
599%D way.
600%D
601%D The first argument specifies what to do with the content. This content is
602%D available in \type {\nextbox}. The second argument is one of \type {\hbox}, \type
603%D {\vbox} or \type {\vtop}. The third argument must be grouped with \type {\bgroup}
604%D and \type {\egroup}, \type {{...}} or can be a \type {\box} specification.
605%D
606%D In \CONTEXT\ this macro is used for picking up a box and treating it according to
607%D earlier specifications. We use for instance something like:
608%D
609%D \starttyping
610%D \def\getfloat%
611%D   {\def\handlefloat{...\box\nextbox...}
612%D    \dowithnextboxcs\handlefloat\vbox}
613%D \stoptyping
614%D
615%D instead of:
616%D
617%D \starttyping
618%D \def\getfloat#1%
619%D   {...#1...}
620%D \stoptyping
621%D
622%D In this implementation the \type {\aftergroup} construction is needed because
623%D \type {\afterassignment} is executed inside the box.
624
625\let\syst_boxes_with_next_box\relax
626
627\permanent\protected\def\dowithnextbox#1%
628  {\def\syst_boxes_with_next_box{#1}%
629   \afterassignment\syst_boxes_with_next_box_indeed
630   \setbox\nextbox}
631
632\def\syst_boxes_with_next_box_indeed
633  {\aftergroup\syst_boxes_with_next_box}
634
635\permanent\protected\def\dowithnextboxcs#1%
636  {\let\syst_boxes_with_next_box#1%
637   \afterassignment\syst_boxes_with_next_box_indeed
638   \setbox\nextbox}
639
640%D So in fact we get:
641%D
642%D \starttyping
643%D \setbox\nextbox { \aftergroup\syst_boxes_with_next_box ... }
644%D \stoptyping
645%D
646%D or
647%D
648%D \starttyping
649%D \setbox\nextbox { ... } \syst_boxes_with_next_box
650%D \stoptyping
651%D
652%D A slower but more versatile implementation is:
653%D
654%D \starttyping
655%D \protected\def\dowithnextbox#1#2%
656%D   {\def\syst_boxes_with_next_box{#1}%
657%D    \ifx#2\hbox
658%D      \afterassignment\syst_boxes_with_next_box_indeed
659%D    \orelse\ifx#2\vbox
660%D      \afterassignment\syst_boxes_with_next_box_indeed
661%D    \orelse\ifx#2\vtop
662%D      \afterassignment\syst_boxes_with_next_box_indeed
663%D    \orelse\ifx#2\normalvcenter
664%D      \afterassignment\syst_boxes_with_next_box_indeed
665%D    \else
666%D      \afterassignment\syst_boxes_with_next_box
667%D    \fi
668%D    \setbox\nextbox#2}
669%D \stoptyping
670%D
671%D This alternative also accepts \type {\box0} and alike, but we don't really need
672%D this functionality now.
673
674%D \macros
675%D   {nextboxht,nextboxwd,nextboxdp,flushnextbox}
676%D
677%D The next couple of shortcuts saves us memory as well as \type {{}}'s in passing
678%D parameters.
679
680\permanent\def\nextboxht  {\ht\nextbox}
681\permanent\def\nextboxwd  {\wd\nextbox}
682\permanent\def\nextboxdp  {\dp\nextbox}
683\permanent\def\nextboxhtdp{\htdp\nextbox}
684
685\permanent\protected\def\flushnextbox{\box\nextbox}
686
687%D \macros
688%D   {dowithnextboxcontent}
689%D
690%D But, occasionally we do need to pass some local settings without wanting to use
691%D additional grouping. Therefore we provide:
692%D
693%D \starttyping
694%D \dowithnextboxcontent{inside}{after}{box content}
695%D \stoptyping
696%D
697%D {\em todo: Search source for potential usage!}
698
699% \protected\def\dowithnextboxcontent#1#2% inside, after
700%   {\def\syst_boxes_with_next_box_one{#2}%
701%    \def\syst_boxes_with_next_box_two{#1}%
702%    \afterassignment\syst_boxes_with_next_box_content_indeed
703%    \setbox\nextbox}
704%
705% \protected\def\dowithnextboxcontentcs#1#2% inside, after
706%   {\let\syst_boxes_with_next_box_one#2%
707%    \let\syst_boxes_with_next_box_two#1%
708%    \afterassignment\syst_boxes_with_next_box_content_indeed
709%    \setbox\nextbox}
710%
711% \def\syst_boxes_with_next_box_content_indeed
712%   {\syst_boxes_with_next_box_two\aftergroup\syst_boxes_with_next_box_one}
713
714\permanent\protected\def\dowithnextboxcontent#1#2% inside, after
715  {\afterassigned{#1\aftergrouped{#2}}%
716   \setbox\nextbox}
717
718\permanent\protected\def\dowithnextboxcontentcs#1#2% inside, after
719  {\afterassigned{#1\aftergroup#2}%
720   \setbox\nextbox}
721
722%D \macros
723%D   {llap, rlap, tlap, blap, clap}
724%D
725%D Some well known friends, but we implement them our own way. We want the macros to
726%D work in both math and text mode.
727
728\def\syst_boxes_do_rlap{\hpack to \zeropoint{\box\nextbox\hss}\endgroup}
729\def\syst_boxes_do_llap{\hpack to \zeropoint{\hss\box\nextbox}\endgroup}
730\def\syst_boxes_do_clap{\hpack to \zeropoint{\hss\box\nextbox\hss}\endgroup}
731\def\syst_boxes_do_tlap{\vpack to \zeropoint{\vss\box\nextbox}\endgroup}
732\def\syst_boxes_do_blap{\vpack to \zeropoint{\box\nextbox\vss}\endgroup}
733
734\protected\def\syst_boxes_rlap{\begingroup\dowithnextboxcs\syst_boxes_do_rlap\hbox}
735\protected\def\syst_boxes_llap{\begingroup\dowithnextboxcs\syst_boxes_do_llap\hbox}
736\protected\def\syst_boxes_clap{\begingroup\dowithnextboxcs\syst_boxes_do_clap\hbox}
737
738% \def\syst_boxes_do_math_clap#1#2{\syst_boxes_clap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
739% \def\syst_boxes_do_math_llap#1#2{\syst_boxes_llap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
740% \def\syst_boxes_do_math_rlap#1#2{\syst_boxes_rlap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
741%
742% \def\syst_boxes_math_clap{\mathpalette\syst_boxes_do_math_clap}
743% \def\syst_boxes_math_llap{\mathpalette\syst_boxes_do_math_llap}
744% \def\syst_boxes_math_rlap{\mathpalette\syst_boxes_do_math_rlap}
745
746\def\syst_boxes_math_xlap#1#2%
747  {\normalexpanded{#1\bgroup\normalstartimath\givenmathstyle\the\mathstyle}%
748 %{\expandafter#1\expandafter\bgroup\expandafter\normalstartimath\expandafter\givenmathstyle\the\mathstyle
749     \mathsurround\zeropoint#2%
750   \normalstopimath\egroup}
751
752\def\syst_boxes_math_clap{\syst_boxes_math_xlap\syst_boxes_clap}
753\def\syst_boxes_math_llap{\syst_boxes_math_xlap\syst_boxes_llap}
754\def\syst_boxes_math_rlap{\syst_boxes_math_xlap\syst_boxes_rlap}
755
756\permanent\protected\def\rlap{\mathortext\syst_boxes_math_rlap\syst_boxes_rlap}
757\permanent\protected\def\llap{\mathortext\syst_boxes_math_llap\syst_boxes_llap}
758\permanent\protected\def\clap{\mathortext\syst_boxes_math_clap\syst_boxes_clap}
759
760\permanent\protected\def\tlap{\begingroup\dowithnextboxcs\syst_boxes_do_tlap\vbox}
761\permanent\protected\def\blap{\begingroup\dowithnextboxcs\syst_boxes_do_blap\vbox}
762
763%D in \LMTX\ this mechanism is obsolete! Use boxlines instead!
764
765%D \macros
766%D   {beginofshapebox,
767%D    reshapebox, doreshapebox,
768%D    flushshapebox,
769%D    innerflushshapebox,
770%D    shapebox,
771%D    ifreshapingbox}
772%D
773%D The next utility macro originates from some linenumbering mechanism. Due to
774%D \TEX's advanced way of typesetting paragraphs, it's not easy to do things on a
775%D line||by||line basis. This macro is able to reprocess a given box and can act
776%D upon its vertical boxed components, such as lines. The unwinding sequence in this
777%D macro is inspired by a \NTG\ workshop of David Salomon in June 1992.
778%D
779%D First we have to grab the piece of text we want to act upon. This is done by
780%D means of the duo macros:
781%D
782%D \starttyping
783%D \beginofshapebox
784%D a piece of text
785%D \endofshapebox
786%D \stoptyping
787%D
788%D When all texts is collected, we can call \type {\reshapebox} and do something
789%D with it's vertical components. We can make as much passes as needed. When we're
790%D done, the box can be unloaded with \type {\flushshapebox}. The only condition in
791%D this scheme is that \type {\reshapebox} must somehow unload the \BOX\ \type
792%D {\shapebox}.
793%D
794%D An important aspect is that the content is unrolled bottom||up. The next example
795%D illustrates this maybe unexpected characteristic.
796%D
797%D \startbuffer
798%D \beginofshapebox
799%D \em \input tufte
800%D \endofshapebox
801%D
802%D \newcounter\LineNumber
803%D
804%D \reshapebox
805%D   {\doglobal\increment\LineNumber
806%D    \hbox{\llap{\LineNumber\hskip2em}\box\shapebox}}
807%D
808%D \flushshapebox
809%D \stopbuffer
810%D
811%D \typebuffer
812%D
813%D \getbuffer
814%D
815%D As we can see, when some kind of numbering is done, we have to add a second pass.
816%D
817%D \startbuffer
818%D \newcounter\LineNumber
819%D \newcounter\NumberOfLines
820%D
821%D \reshapebox
822%D   {\doglobal\increment\NumberOfLines
823%D    \box\shapebox}
824%D
825%D \reshapebox
826%D   {\doglobal\increment\LineNumber
827%D    \hbox
828%D      {\llap{\LineNumber\ (\NumberOfLines)\hskip2em}%
829%D       \box\shapebox}%
830%D    \doglobal\decrement\NumberOfLines}
831%D
832%D \flushshapebox
833%D \stopbuffer
834%D
835%D \typebuffer
836%D
837%D \getbuffer
838%D
839%D This example shows that the content of the box is still available after flushing.
840%D Another feature is that only the last reshaping counts. Multiple reshaping can be
841%D done by:
842%D
843%D \startbuffer
844%D \beginofshapebox
845%D \flushshapebox
846%D \endofshapebox
847%D
848%D \reshapebox
849%D   {\doglobal\increment\LineNumber
850%D    \hbox{\llap{$\star$\hskip1em}\box\shapebox}%
851%D    \doglobal\decrement\NumberOfLines}
852%D
853%D \flushshapebox
854%D \stopbuffer
855%D
856%D \typebuffer
857%D
858%D \getbuffer
859%D
860%D The macros are surprisingly easy to follow and in fact introduce no new concepts.
861%D Nearly all books on \TEX\ show similar solutions for unwinding \BOXES.
862%D
863%D Some macros, like footnote ones, can be sensitive for reshaping, which can result
864%D in an endless loop. We therefore offer:
865%D
866%D \starttyping
867%D \ifreshapingbox
868%D \stoptyping
869%D
870%D Some \CONTEXT\ commands are protected this way. Anyhow, reshaping is aborted
871%D after 100 dead cycles.
872%D
873%D By the way, changing the height and depth of \BOX\ \type {\shapebox} results in
874%D bad spacing. This means that for instance linenumbers etc. should be given zero
875%D height and depth before being lapped into the margin. The previous examples
876%D ignore this side effect, but beware!
877%D
878%D This is ancient stuff and proably not used any more but we keep it around or
879%D maybe turn it into a module some day. It shows the kind of struggling that we
880%D needed before \LUATEX\ came around.
881
882\newif    \ifsomeshapeleft
883\newif    \ifreshapingbox
884\newif    \ifreshapingfailed % may save redundant runs
885
886\newbox      \shapebox
887\newinteger  \shapepenalty
888\newdimension\shapekern
889\newgluespec \shapeskip
890\newbox      \newshapebox
891\newbox      \oldshapebox
892\newbox      \tmpshapebox
893\newinteger  \shapecounter
894\newevery    \everyshapebox \relax
895
896\permanent\dimensiondef\shapesignal.12345678pt % or 12345sp
897
898\permanent\protected\def\reshapebox#1%
899  {\doreshapebox
900     {#1}%
901     {\penalty\shapepenalty}%
902     {\kern   \shapekern   }%
903     {\vskip  \shapeskip   }}
904
905\permanent\protected\def\doreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
906  {\global\reshapingfailedfalse
907   \ifzeropt\ht\oldshapebox
908     \setbox\newshapebox\emptyvbox
909   \else
910     \setbox\newshapebox\vbox % can be \vpack
911       {\unvcopy\oldshapebox
912        \setbox\newshapebox\emptybox
913        \shapecounter\zerocount
914        \doloop{\dodoreshapebox{#1}{#2}{#3}{#4}}}%
915     \setbox\newshapebox\box\tmpshapebox
916   \fi}
917
918% We will turn this into a \MKIV\ variant (we can use \type {\vpack} too).
919
920\permanent\protected\def\insertshapesignal
921  {\hpack to \shapesignal{\strut\hss}% plus \strut
922   \prevdepth\strutdp} % never \nointerlineskip
923
924\permanent\protected\def\restoreshapebox % compensates for the signal
925  {\global\setbox\tmpshapebox\vbox{\vskip-\lineheight\unvcopy\oldshapebox}}
926
927\permanent\def\dodoreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
928  {\ifnum\lastnodetype=\gluenodecode
929     \shapeskip\lastskip
930     \global\setbox\tmpshapebox\vbox{#4\unvbox\tmpshapebox}%
931     \unskip
932   \orelse\ifnum\lastnodetype=\kernnodecode
933     \shapekern\lastkern
934     \global\setbox\tmpshapebox\vbox{#3\unvbox\tmpshapebox}%
935     \unkern
936   \orelse\ifnum\lastnodetype=\penaltynodecode
937     \shapepenalty\lastpenalty
938     \global\setbox\tmpshapebox\vbox{#2\unvbox\tmpshapebox}%
939     \unpenalty
940   \orelse\ifnum\lastnodetype<\zeropoint
941     \exitloop
942   \else
943     \setbox\shapebox\lastbox
944     \ifvoid\shapebox
945     \orelse\ifdim\wd\shapebox=\shapesignal\relax
946       \exitloop
947     \else
948       \shapecounter\zerocount
949       \global\setbox\tmpshapebox\vbox{#1\unvbox\tmpshapebox}%
950     \fi
951   \fi
952   \ifnum\shapecounter>100 % can be less
953     \global\reshapingfailedtrue
954     \message{!!forced exit from shapebox \the\lastnodetype !!}%
955     \restoreshapebox
956     \exitloop
957   \else
958     \advanceby\shapecounter \plusone
959   \fi}
960
961\permanent\protected\def\beginofshapebox
962  {\setbox\oldshapebox\vbox
963     \bgroup
964     \reshapingboxtrue
965     \expand\everyshapebox
966     \insertshapesignal}
967
968\permanent\protected\def\endofshapebox
969  {\endgraf
970   \egroup}
971
972\aliased\let\beginshapebox\beginofshapebox
973\aliased\let\endshapebox  \endofshapebox
974
975\permanent\protected\def\flushshapebox
976  {\bgroup
977   \ifzeropt\ht\newshapebox
978   \else
979     % make \prevdepth legal
980     % \par before the next \vskip gives far worse results
981     \ifdim\parskip>\zeropoint\vskip\parskip\else\par\fi
982     % and take a look
983     \ifdim\prevdepth=-\thousandpoint % or <=
984       \prevdepth\zeropoint
985     \fi
986     \ifdim\prevdepth<\zeropoint\relax
987       % something like a line or a signal or ...
988       \donetrue
989     \orelse\ifinner
990       % not watertight and not ok
991       \donefalse
992     \orelse\ifdim\pagegoal=\maxdimen
993       \donetrue
994     \else
995       % give the previous line a normal depth
996       \donetrue
997       {\forgeteverypar\verticalstrut}\nobreak
998       \kern-\struttotal % geen \vskip
999       \kern-\parskip
1000     % \vskip-\strutdp
1001     \fi
1002     \scratchdimen\dp\newshapebox
1003     \unvbox\newshapebox
1004     % \prevdepth=0pt and \dp\newshapebox depend on last line
1005     \kern-\scratchdimen % ??
1006     % now \prevdepth=0pt
1007     \ifdone
1008       \kern\strutdp
1009       \prevdepth\strutdp
1010     \fi
1011   \fi
1012   \egroup}
1013
1014%D In real inner situations we can use:
1015%D
1016%D \starttyping
1017%D \flushinnershapebox
1018%D \stoptyping
1019%D
1020%D This one is used in \type{\framed}.
1021
1022% The kern fails on for instance:
1023%
1024% \omlijnd[offset=0pt,hoogte=8mm,uitlijnen={rechts,laho}]{\bfa test}
1025
1026\permanent\protected\def\innerflushshapebox
1027  {\ifzeropt\ht\newshapebox \else
1028     \unvcopy\newshapebox\relax % unvcopy ! else spacing problem
1029   % \kern-\dp\newshapebox\relax
1030   \fi}
1031
1032%D For absolute control, one can use \type {\doreshapebox} directly. This macro
1033%D takes four arguments, that take care of:
1034%D
1035%D \startitemize[n,packed]
1036%D \item \type{\shapebox}
1037%D \item \type{\shapepenalty}
1038%D \item \type{\shapekern}
1039%D \item \type{\shapeskip}
1040%D \stopitemize
1041
1042%D \macros
1043%D   {shapedhbox}
1044%D
1045%D When constructing a new box, using the content of \type {\shapebox}, one can best
1046%D use \type {\shapedhbox} instead of \type {\hbox}, since it manages the height and
1047%D depth of the line.
1048
1049\permanent\protected\def\shapedhbox % lines with non strutted dimensions have
1050  {\normalexpanded{\dowithnextbox         % interlineskip so if we want the original
1051     {\ht\nextbox\the\ht\shapebox   % spacing, we need to preserve the original
1052      \dp\nextbox\the\dp\shapebox   % height and depth which is definitely
1053      \box\nextbox}}                % needed if we apply struts to the 'new'
1054   \hbox}                           % box or do something that changed ist size
1055
1056%D Till here obsolete.
1057
1058%D \macros
1059%D   {hyphenatedword,
1060%D    hyphenatedpar,
1061%D    hyphenatedfile,
1062%D    dohyphenateword}
1063%D
1064%D We no longer use the pure \TEX\ variant. In due time we will report some more
1065%D advanced statistics.
1066%D
1067%D \starttyping
1068%D \showhyphens{dohyphenatedword}
1069%D \stoptyping
1070
1071\permanent\protected\def\doshowhyphenatednextbox
1072  {\clf_showhyphenatedinlist\nextbox}
1073
1074\permanent\protected\def\showhyphens % hpack: so no processing (we hyphenate in lua)
1075  {\dowithnextboxcs\doshowhyphenatednextbox\hpack}
1076
1077%D The following macros are seldom used but handy for tracing.
1078%D
1079%D \starttyping
1080%D \hyphenatedword{dohyphenatedword}
1081%D \hyphenatedpar {\dorecurse{10}{dohyphenatedword }}
1082%D \hyphenatedfile{tufte}
1083%D \stoptyping
1084
1085\def\syst_boxes_hyphenatednextbox     {\clf_hyphenatedlist\nextbox false\relax\unhbox\nextbox}
1086\def\syst_boxes_hyphenatednextboxcolor{\clf_hyphenatedlist\nextbox true \relax\unhbox\nextbox}
1087
1088\permanent\protected\def\hyphenatedword       {\dowithnextboxcs\syst_boxes_hyphenatednextbox\hbox}
1089\permanent\protected\def\hyphenatedpar        {\dowithnextboxcs\syst_boxes_hyphenatednextbox\hbox}
1090\permanent\protected\def\hyphenatedfile     #1{\dowithnextboxcs\syst_boxes_hyphenatednextbox\hbox{\readfile{#1}\donothing\donothing}}
1091\permanent\protected\def\hyphenatedcoloredword{\dowithnextboxcs\syst_boxes_hyphenatednextboxcolor\hbox}
1092
1093%D \macros
1094%D   {processtokens}
1095%D
1096%D We fully agree with (most) typographers that inter||letter spacing is only
1097%D permitted in fancy titles, we provide a macro that can be used to do so. Because
1098%D this is (definitely and fortunately) no feature of \TEX, we have to step through
1099%D the token list ourselves.
1100%D
1101%D \starttyping
1102%D \processtokens {before} {between} {after} {space} {tokens}
1103%D \stoptyping
1104%D
1105%D An example of a call is:
1106%D
1107%D \startbuffer
1108%D \processtokens {[} {+} {]} {\space} {hello world}
1109%D \stopbuffer
1110%D
1111%D \typebuffer
1112%D
1113%D This results in:
1114%D
1115%D \getbuffer
1116%D
1117%D The list of tokens may contain spaces, while \type {\\}, \type {{}} and \type {\
1118%D } are handled as space too.
1119
1120%D This can be done in a more modern way but for nostalgic reasons we keep it.
1121
1122\mutable\lettonothing\nextprocessedtoken
1123
1124\mutable\let\before \relax % for now mutable
1125%mutable\let\between\relax % is a math character
1126\mutable\let\after  \relax % for now mutable
1127\mutable\let\white  \relax % for now mutable
1128
1129\permanent\protected\def\processtokens#1#2#3#4#5%
1130  {\begingroup
1131   \enforced\permanent\def\space{ }%
1132   \enforced\let\\\space
1133   \enforced\def\before {#1}%
1134   \enforced\def\between{#2}%
1135   \enforced\def\after  {#3}%
1136   \enforced\def\white  {#4}%
1137   \enforced\let\m_syst_boxes_before\before
1138   \syst_boxes_processtokens#5\s!e_o_t_token
1139   \endgroup}
1140
1141\def\syst_boxes_processtokens% the space after = is essential
1142  {\afterassignment\syst_boxes_do_processtokens\let\nextprocessedtoken= }
1143
1144\def\syst_boxes_redo_processedtoken
1145  {\dowithnextbox
1146     {\before{\copy\nextbox}% \before can use nextbox several times
1147      \enforced\let\before\between
1148      \syst_boxes_processtokens}
1149      \hbox\bgroup}
1150
1151\def\syst_boxes_do_processtokens
1152  {\ifx\nextprocessedtoken\s!e_o_t_token
1153     \after
1154   \orelse\ifx\nextprocessedtoken\bgroup
1155     \expandafter\syst_boxes_redo_processedtoken
1156   \else
1157     \expandafter\if\space\nextprocessedtoken
1158       \after\white
1159       \enforced\let\before\m_syst_boxes_before
1160     \else
1161       \before\nextprocessedtoken
1162       \enforced\let\before\between
1163     \fi
1164     \expandafter\syst_boxes_processtokens
1165   \fi}
1166
1167%D \macros
1168%D   {doboundtext}
1169%D
1170%D Sometimes there is not enough room to show the complete (line of) text. In such a
1171%D situation we can strip of some characters by using \type {\doboundtext}. When the
1172%D text is wider than the given width, it's split and the third argument is
1173%D appended. When the text to be checked is packed in a command, we'll have to use
1174%D \type {\expandafter}.
1175%D
1176%D \starttyping
1177%D \doboundtext{a very, probably to long, text}{3cm}{...}
1178%D \stoptyping
1179%D
1180%D When calculating the room needed, we take the width of the third argument into
1181%D account, which leads to a bit more complex macro than needed at first sight.
1182%D
1183%D Sort of obsolete I guess:
1184
1185\def\syst_boxes_boundtext#1%
1186  {\setbox\scratchboxone\hbox{#1}%
1187   \advanceby\scratchdimen -\wd\scratchboxone
1188   \ifdim\scratchdimen>\zeropoint\relax#1\fi}
1189
1190\permanent\protected\def\doboundtext#1#2#3% still used?
1191  {\hbox
1192     {\setbox\scratchbox\hbox{#1}%
1193      \scratchdimen#2\relax
1194      \ifdim\wd\scratchbox>\scratchdimen
1195        \setbox\scratchbox\hbox{#3}%
1196        \advanceby\scratchdimen -\wd\scratchbox
1197        \handletokens#1\with\syst_boxes_boundtext
1198      \fi
1199      \box\scratchbox}}
1200
1201%D \macros
1202%D   {limitatetext}
1203%D
1204%D A bit more beautiful alternative for the previous command is the next one. This
1205%D command is more robust because we let \TEX\ do most of the job. The previous
1206%D command works better on text that cannot be hyphenated.
1207%D
1208%D \starttyping
1209%D \limitatetext {text}  {width} {sentinel}
1210%D \limitatetext {text} {-width} {prelude}
1211%D \stoptyping
1212%D
1213%D When no width is given, the whole text comes available. The sentinel is optional.
1214%D This is about the third version.
1215
1216\ifdefined\fakecompoundhyphen\else \let\fakecompoundhyphen\relax      \fi
1217\ifdefined\veryraggedright   \else \def\veryraggedright{\raggedright} \fi
1218
1219%D See \MKIV\ file for the older implementation.
1220
1221\lettonothing\m_syst_boxes_left
1222\lettonothing\m_syst_boxes_right
1223
1224\permanent\protected\def\limitatetext#1#2#3%
1225  {% we could also split in \LUA
1226   \splitatcomma{#2}\m_syst_boxes_left\m_syst_boxes_right
1227   \limitated
1228  \ifempty\m_syst_boxes_left\else
1229      left     \m_syst_boxes_left
1230  \fi
1231  \ifempty\m_syst_boxes_right\else
1232      right    \m_syst_boxes_right
1233  \fi
1234      strip    true
1235      sentinel {#3}
1236      text     {#1}
1237   \relax}
1238
1239%D Undocumented bonus (see wiki):
1240%D
1241%D \starttyping
1242%D \limitatefirstline{\input tufte\relax}{10cm}{\unknown}
1243%D \stoptyping
1244
1245\permanent\protected\def\limitatefirstline#1#2#3%
1246  {\hbox\bgroup\strut % \hpack
1247   \setbox\scratchbox\hbox{\begstrut#1\endstrut}%
1248   \ifdim\wd\scratchbox>#2\relax
1249     \setbox\scratchbox\hbox{#3}%
1250     \hsize#2\relax
1251     \advanceby\hsize-\wd\scratchbox
1252     \setbox\scratchbox\vbox{\forgetall\veryraggedright#1}%
1253     \setbox\scratchbox\vsplit\scratchbox to \lineheight
1254     \vbox
1255       {\unvbox\scratchbox
1256        \global\setbox\plusone\lastbox
1257        \global\setbox\plusone\hbox{\strut\unhbox\plusone}%
1258        \hbox % to #2 % \hpack
1259          {\unless\ifdefined\clip
1260             \box\plusone
1261           \orelse\ifdim\wd\plusone>\hsize
1262             \lower\strutdepth\hpack{\clip[\c!width=\hsize,\c!height=\lineheight]{\hpack{\raise\strutdepth\box\plusone}}}%
1263           \else
1264             \box\plusone
1265           \fi
1266           \removeunwantedspaces#3}}% \removeunwantedspaces\hss#3}}%
1267   \else
1268     #1%
1269   \fi
1270   \egroup}
1271
1272%D \macros
1273%D   {processisolatedwords,processisolatedchars}
1274%D
1275%D \startbuffer
1276%D \processisolatedchars{some more words}           \ruledhbox \par
1277%D \processisolatedchars{and some $x + y = z$ math} \ruledhbox \par
1278%D \processisolatedchars{and a \hbox{$x + y = z$}}  \ruledhbox \par
1279%D \processisolatedwords{some more words}           \ruledhbox \par
1280%D \processisolatedwords{and some $x + y = z$ math} \ruledhbox \par
1281%D \processisolatedwords{and a \hbox{$x + y = z$}}  \ruledhbox \par
1282%D \stopbuffer
1283%D
1284%D \typebuffer \blank \getbuffer \blank
1285
1286% todo: provide variant with #1 picked up as box
1287
1288\permanent\protected\def\processisolatedchars#1#2%
1289  {\dontleavehmode
1290   \begingroup
1291   \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
1292   \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
1293   \clf_applytobox
1294     method  {char}%
1295     box     \scratchbox
1296     command {\csstring#2}%
1297     nested  true%
1298   \relax
1299   \endgroup}
1300
1301\permanent\protected\def\processisolatedwords#1#2%
1302  {\dontleavehmode
1303   \begingroup
1304   \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
1305   \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
1306   \clf_applytobox
1307     method  {word}%
1308     box     \scratchbox
1309     command {\csstring#2}%
1310     nested  true%
1311   \relax
1312   \endgroup}
1313
1314%D A variant:
1315
1316\permanent\protected\def\applytocharacters#1%
1317  {\dontleavehmode
1318   \dowithnextbox{\clf_applytobox
1319     method  {char}%
1320     box     \nextbox
1321     command {\csstring#1}%
1322     nested  true%
1323   \relax}%
1324   \hbox}
1325
1326\permanent\protected\def\applytowords#1%
1327  {\dontleavehmode
1328   \dowithnextbox{\clf_applytobox
1329     method  {word}%
1330     box     \nextbox
1331     command {\csstring#1}%
1332     nested  true%
1333   \relax}%
1334   \hbox}
1335
1336%D The old call:
1337
1338\permanent\protected\def\processwords#1%
1339  {\processisolatedwords{#1}\processword}
1340
1341\mutable\let\processword\relax
1342
1343\permanent\protected\def\applytosplitstringchar#1#2%
1344  {\dontleavehmode\clf_processsplit
1345     data    {#2}%
1346     command {\csstring#1}%
1347     method  {char}%
1348   \relax}
1349
1350\permanent\protected\def\applytosplitstringword#1#2%
1351  {\dontleavehmode\clf_processsplit
1352     data    {#2}%
1353     command {\csstring#1}%
1354     method  {word}%
1355   \relax}
1356
1357\permanent\protected\def\applytosplitstringline#1#2%
1358  {\dontleavehmode\clf_processsplit
1359     data    {#2}%
1360     command {\csstring#1}%
1361     method  {line}%
1362   \relax}
1363
1364\permanent\protected\def\applytosplitstringcharspaced#1#2%
1365  {\dontleavehmode\clf_processsplit
1366     data    {#2}%
1367     command {\csstring#1}%
1368     method  {char}%
1369     spaced  true%
1370   \relax}
1371
1372\permanent\protected\def\applytosplitstringwordspaced#1#2%
1373  {\dontleavehmode\clf_processsplit
1374     data    {#2}%
1375     command {\csstring#1}%
1376     method  {word}%
1377     spaced  true%
1378   \relax}
1379
1380\permanent\protected\def\applytosplitstringlinespaced#1#2%
1381  {\dontleavehmode\clf_processsplit
1382     data    {#2}%
1383     command {\csstring#1}%
1384     method  {line}%
1385     spaced  true%
1386   \relax}
1387
1388%D \macros
1389%D   {sbox}
1390%D
1391%D This is a rather strange command. It grabs some box content and and limits the
1392%D size to the height and depth of a \type {\strut}. The resulting bottom||alligned
1393%D box can be used aside other ones, without disturbing the normal baseline
1394%D distance.
1395%D
1396%D \startbuffer
1397%D \ruledhbox to .5\hsize{\sbox{eerste\par tweede \par derde}}
1398%D \stopbuffer
1399%D
1400%D \typebuffer
1401%D
1402%D Shows up as:
1403%D
1404%D \startexample
1405%D \vskip3\baselineskip
1406%D \getbuffer
1407%D \stopexample
1408%D
1409%D Before displaying the result we added some skip, otherwise the first two lines
1410%D would have ended up in the text. This macro can be useful when building
1411%D complicated menus, headers and footers and|/|or margin material.
1412
1413\permanent\protected\def\sbox
1414  {\vpack\bgroup
1415   \dowithnextboxcs\syst_boxes_sbox_finish\vbox}
1416
1417\def\syst_boxes_sbox_finish
1418  {\boxyoffset\nextbox-\strutdp
1419   \dp\nextbox\strutdp
1420   \ht\nextbox\strutht
1421   \box\nextbox
1422   \egroup}
1423
1424%D A variant on this:
1425%D
1426%D \starttyping
1427%D xx \ruledhbox{\inlinedbox{\tfd test}} xx
1428%D \stoptyping
1429
1430\permanent\protected\def\inlinedbox
1431  {\bgroup
1432   \dowithnextboxcs\syst_boxes_inlined_finish\hbox}
1433
1434\def\syst_boxes_inlined_finish
1435  {\boxyoffset\nextbox-\dimexpr(\htdp\nextbox-\lineheight)/\plustwo+\strutdp\relax
1436   \ht\nextbox\strutht
1437   \dp\nextbox\strutdp
1438   \box\nextbox
1439   \egroup}
1440
1441%D \macros
1442%D   {struttedbox}
1443%D
1444%D This boxing macro limits the height and depth to those of a strut.
1445
1446\permanent\protected\def\struttedbox
1447  {\hpack\bgroup
1448   \dowithnextboxcs\syst_boxes_struttedbox_finish\hbox}
1449
1450\def\syst_boxes_struttedbox_finish
1451  {\dp\nextbox\strutdepth
1452   \ht\nextbox\strutheight
1453   \box\nextbox
1454   \egroup}
1455
1456%D \macros
1457%D   {topskippedbox}
1458%D
1459%D This macro compensates the difference between the topskip and strutheight. Watch
1460%D how we preserve the depth when it equals strutdepth.
1461
1462\permanent\protected\def\topskippedbox
1463  {\hpack\bgroup\dowithnextboxcs\syst_boxes_topskippedbox_finish\hbox}
1464
1465\def\syst_boxes_topskippedbox_finish
1466  {\edef\m_boxes_tmp{\ifdim\strutdepth=\dp\nextbox\dp\nextbox\the\dp\nextbox\fi}%
1467   \lower\topskip\hpack{\raise\strutheight\box\nextbox}%
1468   \m_boxes_tmp
1469   \egroup}
1470
1471%D \macros
1472%D   {centeredbox, centerednextbox}
1473%D
1474%D Here is another strange one. This one offers a sort of overlay with positive or
1475%D negative offsets. This command can be used in well defined areas where no offset
1476%D options are available. We first used it when building a button inside the margin
1477%D footer, where the button should have a horizontal offset and should be centered
1478%D with respect to the surrounding box. The last of the three examples we show below
1479%D says:
1480%D
1481%D \starttyping
1482%D \vsize=3cm
1483%D \hsize=3cm
1484%D \ruledvbox to \vsize
1485%D   {\centeredbox height .5cm width -1cm
1486%D      {\vrule width \hsize height \vsize}}}
1487%D \stoptyping
1488%D
1489%D Here the \type {\ruledvbox} just shows the surrounding box and \type {\vrule} is
1490%D used to show the centered box.
1491%D
1492%D \def\AnExample#1#2%
1493%D   {\vsize=3cm
1494%D    \hsize=3cm
1495%D    \ruledvbox to \vsize
1496%D      {\centeredbox height #1 width #2
1497%D         {\color[green]{\vrule width \hsize height \vsize}}}}
1498%D
1499%D \startlinecorrection
1500%D \startcombination[3*1]
1501%D   {\AnExample {-1cm}  {.5cm}} {}
1502%D   {\AnExample {.5cm}  {-1cm}} {}
1503%D   {\AnExample {-1cm} {-.5cm}} {}
1504%D \stopcombination
1505%D \stoplinecorrection
1506%D
1507%D This command takes two optional arguments: \type {width} and \type {height}.
1508%D Observing readers can see that we use \TEX's own scanner for grabbing these
1509%D arguments: \type {#1#} reads everyting till the next brace and passes it to both
1510%D rules. The setting of the box dimensions at the end is needed for special cases.
1511%D The dimensions of the surrounding box are kept intact. This commands handles
1512%D positive and negative dimensions (which is why we need two boxes with rules).
1513
1514\permanent\protected\def\centeredbox#1#%   height +/-dimen width +/-dimen
1515  {\bgroup
1516   \dontcomplain
1517   \forgetall
1518   \scangivendimensions#1\relax
1519   \advanceby\vsize\givenheight
1520   \advanceby\hsize\givenwidth
1521   \dowithnextboxcs\syst_boxes_centered_finish
1522   \hbox}
1523
1524\def\syst_boxes_centered_finish
1525  {\boxxoffset\nextbox.5\dimexpr
1526      \hsize
1527     -\wd\nextbox
1528     -\givenwidth
1529   \relax
1530   \boxyoffset\nextbox.5\dimexpr
1531      \vsize
1532     -\ht\nextbox
1533     +\dp\nextbox
1534     -\givenheight
1535   \relax
1536   \wd\nextbox\dimexpr\hsize-\givenwidth \relax
1537   \ht\nextbox\dimexpr\vsize-\givenheight\relax
1538   \dp\nextbox\zeropoint
1539   \box\nextbox
1540   \egroup}
1541
1542%D For those who don't want to deal with \type {\hsize} and \type {\vsize}, we have:
1543%D
1544%D \starttyping
1545%D \centerednextbox width 2bp height 2bp
1546%D   {\framed[width=100bp,height=100bp]{}}
1547%D \stoptyping
1548%D
1549%D Do you see why we call this one \type {next}?
1550
1551\permanent\protected\def\centerednextbox#1#%
1552  {\bgroup
1553   \dowithnextbox
1554     {\hsize\wd\nextbox
1555      \vsize\ht\nextbox
1556      \centeredbox#1{\box\nextbox}%
1557      \egroup}
1558   \hbox}
1559
1560%D \macros
1561%D   {centerbox}
1562%D
1563%D Centering on the available space is done by:
1564%D
1565%D \starttyping
1566%D \centerbox <optional specs> {content}
1567%D \stoptyping
1568%D
1569%D When omitted, the current \type {\hsize} and \type {\vsize} are used. Local
1570%D dimensions are supported.
1571
1572\permanent\protected\def\centerbox#1#%   optional height +/-dimen width +/-dimen
1573  {\bgroup
1574   \dowithnextbox
1575     {\setlocalhsize
1576      \setbox\scratchbox\hpack{\vrule\s!width \zeropoint#1}%
1577      \ifzeropt\wd\scratchbox\else\hsize\wd\scratchbox\fi
1578      \setbox\scratchbox\vpack{\hrule\s!height\zeropoint#1}%
1579      \ifzeropt\ht\scratchbox\else\vsize\ht\scratchbox\fi
1580      \vpack to \vsize{\vss\hpack to \hsize{\hss\box\nextbox\hss}\vss}%
1581      \egroup}%
1582     \hbox}
1583
1584%D \macros
1585%D   {setrigidcolumnhsize,rigidcolumnbalance,rigidcolumnlines}
1586%D
1587%D These macros are copied from the \TEX book, page~397, and extended by a macro
1588%D that sets the \type {\hsize}.
1589%D
1590%D \starttyping
1591%D \setrigidcolumnhsize {total width} {distance} {n}
1592%D \rigidcolumnbalance  {box}
1593%D \stoptyping
1594%D
1595%D Both these macros are for instance used in typesetting footnotes. The following
1596%D flags influence the process.
1597
1598\newif\ifalignrigidcolumns
1599\newif\ifstretchrigidcolumns
1600\newif\iftightrigidcolumns    % if true: just a vbox, no depth/noflines/gridsnap corrrections
1601
1602\mutable\let\rigidcolumnlines\!!zerocount
1603
1604\newbox      \rigidcolumnbox
1605\newdimension\rigidhsize
1606\newinteger  \rigidcolumns
1607
1608\permanent\protected\def\setrigidcolumnhsize#1#2#3% todo: \dimexpr
1609  {\global\rigidhsize\hsize
1610   \global\rigidcolumns#3\relax
1611   \hsize#1\relax
1612   \scratchdimen -#2\relax
1613   \multiplyby\scratchdimen #3\relax
1614   \advanceby\scratchdimen  #2\relax
1615   \advanceby\hsize \scratchdimen
1616   \divideby\hsize #3\relax}
1617
1618% ==
1619%
1620% \def\setrigidcolumnhsize#1#2#3%
1621%   {\global\rigidhsize\hsize
1622%    \rigidcolumns#3\relax
1623%    \hsize\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax}
1624
1625\permanent\protected\def\rigidcolumnbalance#1%
1626  {\ifnum\rigidcolumns=1 % tzt ook h/d correctie
1627     \ifinner\ifhmode\box\else\unvbox\fi\else\unvbox\fi#1\relax
1628   \else
1629     \vbox % \vpack
1630       {\forgetall
1631        \nopenalties
1632        \dontcomplain
1633        \setbox\rigidcolumnbox\vbox
1634          {\line{}\goodbreak\unvbox#1\removebottomthings}%
1635        \splittopskip\openstrutheight
1636        \setbox\scratchbox\vsplit\rigidcolumnbox to \zeropoint
1637        \ifcase\rigidcolumnlines\relax
1638          % \iffalse
1639          %  % maybe some day an option
1640          %  \scratchskip\ht\rigidcolumnbox
1641          %  \advanceby\scratchskip\dp\rigidcolumnbox
1642          %  \getnoflines\scratchskip
1643          %  \ifodd\noflines
1644          %    \advanceby\noflines\plusone
1645          %  \fi
1646          %  \divideby\noflines\rigidcolumns
1647          %\else
1648            \scratchdimen\ht\rigidcolumnbox
1649            \divideby\scratchdimen \rigidcolumns
1650            \getnoflines\scratchdimen
1651          %\fi
1652        \else
1653          \noflines\rigidcolumnlines % to be sure
1654        \fi
1655        \scratchdimen\noflines\lineheight
1656        % new: we now loop so that we don't loose content
1657        % since in practice we also use this macro for
1658        % funny lineheights and border cases
1659        \setbox0=\box\rigidcolumnbox
1660        \ifvoid0\else
1661          \doloop
1662            {\setbox\rigidcolumnbox=\copy0
1663             \setbox\scratchbox\hpack to \rigidhsize
1664               {\dorecurse\rigidcolumns
1665                  {\setbox\scratchbox\vsplit\rigidcolumnbox to \scratchdimen
1666                     \dp\scratchbox\openstrutdepth
1667                     \setbox\scratchbox\vtop
1668                       \ifalignrigidcolumns to
1669                         \ifstretchrigidcolumns\vsize\else\scratchdimen\fi
1670                       \fi
1671                       {\unvbox\scratchbox}%
1672                   \wd\scratchbox\hsize
1673                   \box\scratchbox
1674                   \hfill}%
1675                \hfillneg}%
1676            \ifvoid\rigidcolumnbox\exitloop\else\advanceby\scratchdimen\lineheight\fi}%
1677         \iftightrigidcolumns
1678           \setbox\scratchbox\hpack{\raise\dp\scratchbox\box\scratchbox}%
1679         \else
1680           \advanceby\scratchdimen -\openstrutdepth
1681           \setbox\scratchbox\hpack{\raise\scratchdimen\box\scratchbox}%
1682           \dp\scratchbox\openstrutdepth
1683           \ht\scratchbox\scratchdimen
1684         \fi
1685         \box\scratchbox
1686       \fi}%
1687   \fi}
1688
1689%D \macros
1690%D   {startvboxtohbox,stopvboxtohbox,convertvboxtohbox}
1691%D
1692%D Here is another of Knuth's dirty tricks, as presented on pages 398 and 399 of the
1693%D \TEX book. These macros can be used like:
1694%D
1695%D \starttyping
1696%D \vbox
1697%D   \bgroup
1698%D     \startvboxtohbox ... \stopvboxtohbox
1699%D     \startvboxtohbox ... \stopvboxtohbox
1700%D     \startvboxtohbox ... \stopvboxtohbox
1701%D   \egroup
1702%D
1703%D \vbox
1704%D   \bgroup
1705%D     \convertvboxtohbox
1706%D   \egroup
1707%D \stoptyping
1708%D
1709%D These macros are used in reformatting footnotes, so they do what they're meant
1710%D for.
1711
1712\newdimension\vboxtohboxslack
1713\newdimension\hboxestohboxslack
1714
1715%D Create line and fake height of paragraph by messing with heights: a nice hack by
1716%D DEK himself.
1717
1718%\protected\def\setvboxtohbox
1719%  {\bgroup
1720%   \ifdim\baselineskip<16pt \relax
1721%     \scratchdimen\baselineskip
1722%     \multiplyby\scratchdimen 1024
1723%   \else
1724%     \message{cropping \baselineskip to 16pt}%
1725%     \scratchdimen\maxdimen
1726%   \fi
1727%   \divideby\scratchdimen \hsize
1728%   \multiplyby\scratchdimen 64
1729%   \xdef\vboxtohboxfactor{\toscaled\scratchdimen}%
1730%   \egroup}
1731%
1732% \protected\def\startvboxtohbox
1733%  {\bgroup
1734%   \setvboxtohbox
1735%   \setbox\scratchbox\hbox\bgroup}
1736%
1737% \protected\def\stopvboxtohbox
1738%   {\ifcase\vboxtohboxslack\else\hskip\zeropoint\s!minus\vboxtohboxslack\fi
1739%    \egroup
1740%    \dp\scratchbox\zeropoint
1741%    \ht\scratchbox\vboxtohboxfactor\wd\scratchbox
1742%    \box\scratchbox
1743%    \egroup}
1744
1745% More modern:
1746
1747% \definesystemattribute[vboxtohboxseparator][public]
1748
1749%newbox\d_syst_boxes_vboxtohbox
1750\newbox\d_syst_boxes_separator
1751
1752\permanent\protected\def\startvboxtohboxseparator
1753  {\setbox\d_syst_boxes_separator\hbox attr \vboxtohboxseparatorattribute\plusone\bgroup}
1754
1755\permanent\protected\def\stopvboxtohboxseparator
1756  {\egroup}
1757
1758\permanent\protected\def\startvboxtohbox
1759  {\begingroup
1760   \setbox\scratchbox\hbox\bgroup}
1761
1762\permanent\protected\def\stopvboxtohbox
1763  {\ifvoid\d_syst_boxes_separator
1764     \hskip\zeropoint\ifcase\vboxtohboxslack\else\s!minus\vboxtohboxslack\fi % we really need a skip
1765   \else
1766     \box\d_syst_boxes_separator
1767   \fi
1768   \egroup
1769   \clf_hboxtovbox\scratchbox
1770   \box\scratchbox
1771   \endgroup}
1772
1773% A possible reconstruction:
1774
1775\permanent\protected\def\convertvboxtohbox
1776  {\makehboxofhboxes
1777   \setbox\scratchboxone\hpack{\unhbox\scratchboxone\removehboxes}% \hpack
1778   \noindent\unhbox\scratchboxone\par}
1779
1780\permanent\protected\def\makehboxofhboxes
1781  {\setbox\scratchboxone\emptyhbox
1782   \loop % \doloop { .. \exitloop .. }
1783     \setbox\scratchboxtwo\lastbox
1784     \ifhbox\scratchboxtwo
1785       \setbox\scratchboxone\hpack{\box\scratchboxtwo\unhbox\scratchboxone}%
1786   \repeat}
1787
1788\permanent\protected\def\removehboxes
1789  {\setbox\scratchboxone\lastbox
1790   \ifhbox\scratchboxone
1791     {\removehboxes}\unhbox\scratchboxone
1792   \fi}
1793
1794% And one special for notes:
1795
1796\permanent\protected\def\starthboxestohbox
1797  {\bgroup
1798   \setbox\scratchbox\vbox\bgroup}
1799
1800\permanent\protected\def\stophboxestohbox
1801  {\egroup
1802   \clf_vboxlisttohbox\scratchbox\nextbox\dimexpr\hboxestohboxslack\relax
1803   \dontleavehmode
1804   \unhbox\nextbox
1805   \removeunwantedspaces
1806   \par
1807   \egroup}
1808
1809%D \macros
1810%D   {unhhbox}
1811%D
1812%D The next macro is used in typesetting inline headings. Let's first look at the
1813%D macro and then show an example. As many other helpers here, it is no longer
1814%D used in the core and dates from \MKII\ times, but we keep it here just in case
1815%D some use style uses it. Eventually we might moev this to a load|-|on|-|demand
1816%D module.
1817
1818\newbox      \unhhedbox
1819\newbox      \hhbox
1820\newdimension\lasthhboxwidth
1821\newgluespec \hhboxindent
1822
1823\permanent\protected\def\unhhbox#1\with#2%
1824  {\bgroup
1825   \nopenalties
1826   \dontcomplain
1827   \forgetall
1828   \setbox\unhhedbox\vbox{\hskip\hhboxindent\strut\unhbox#1}% => \hsize
1829   \doloop
1830     {\setbox\hhbox\vsplit\unhhedbox to \lineheight
1831      \ifvoid\unhhedbox
1832        \setbox\hhbox\hbox{\strut\hboxofvbox\hhbox}% \hpack
1833      \fi
1834      \ht\hhbox\strutht
1835      \dp\hhbox\strutdp
1836      \ifzeropt\hhboxindent\else
1837        \setbox\hhbox\hpack{\kern-\hhboxindent\box\hhbox}%
1838        \hhboxindent\zeropoint
1839      \fi
1840      \global\lasthhboxwidth\wd\hhbox
1841      #2\relax
1842      \ifvoid\unhhedbox
1843        \exitloop
1844      \else
1845        \hskip\zeropoint \s!plus \zeropoint
1846      \fi}%
1847   \egroup}
1848
1849\def\syst_boxes_hboxofvbox
1850  {\setbox0\vpack{\unvbox\scratchcounter\global\setbox1\lastbox}%
1851   \unhbox1
1852   \egroup}
1853
1854\permanent\protected\def\hboxofvbox
1855  {\bgroup
1856   \afterassignment\syst_boxes_hboxofvbox
1857   \scratchcounter=}
1858
1859%D This macro can be used to break a paragraph apart and treat each line seperately,
1860%D for instance, making it clickable. The main complication is that we want to be
1861%D able to continue the paragraph, something that's needed in the in line section
1862%D headers.
1863%D
1864%D \startbuffer
1865%D \setbox0=\hbox{\input tufte \relax}
1866%D \setbox2=\hbox{\input knuth \relax}
1867%D \unhhbox0\with{\ruledhbox{\box\hhbox}}
1868%D \hskip1em plus 1em minus 1em
1869%D \hhboxindent=\lasthhboxwidth
1870%D \advanceby\hhboxindent by \lastskip
1871%D \unhhbox2\with{\ruledhbox{\box\hhbox}}
1872%D \stopbuffer
1873%D
1874%D \getbuffer
1875%D
1876%D This piece of text was typeset by saying:
1877%D
1878%D \typebuffer
1879%D
1880%D Not that nice a definition, but effective. Note the stretch we've build in the
1881%D line that connects the two paragraphs.
1882
1883%D \macros
1884%D   {doifcontent}
1885%D
1886%D When processing depends on the availability of content, one can give the next
1887%D macro a try.
1888%D
1889%D \starttyping
1890%D \doifcontent{pre content}{post content}{no content}\somebox
1891%D \stoptyping
1892%D
1893%D Where \type {\somebox} is either a \type {\hbox} or \type {\vbox}. If the
1894%D dimension of this box suggest some content, the resulting box is unboxed and
1895%D surrounded by the first two arguments, else the third arguments is executed.
1896
1897\permanent\protected\def\doifcontent#1#2#3%
1898  {\dowithnextbox
1899     {\ifhbox\nextbox
1900        \ifdim\wd\nextbox>\zeropoint
1901          #1\unhbox\nextbox#2\relax
1902        \else
1903          #3\relax
1904        \fi
1905      \else
1906        \ifdim\ht\nextbox>\zeropoint
1907          #1\unvbox\nextbox#2\relax
1908        \else
1909          #3\relax
1910        \fi
1911      \fi}}
1912
1913%D So when we say:
1914%D
1915%D \startbuffer
1916%D \doifcontent{[}{]}{}\hbox{content sensitive typesetting}
1917%D
1918%D \doifcontent{}{\page}{}\vbox{content sensitive typesetting}
1919%D
1920%D \doifcontent{}{}{\message{Didn't you forget something?}}\hbox{}
1921%D \stopbuffer
1922%D
1923%D \typebuffer
1924%D
1925%D We get:
1926%D
1927%D \getbuffer
1928%D
1929%D Where the last call of course does not show up in this document, but definitely
1930%D generates a confusing message.
1931
1932%D \macros
1933%D   {processboxes}
1934%D
1935%D The next macro gobble boxes and is for instance used for overlays. First we show
1936%D the general handler.
1937
1938\newbox\processbox % public : this is the one where \nextbox's end up in
1939
1940\let\syst_boxes_process_indeed\relax
1941
1942\permanent\protected\def\processboxes#1%
1943  {\bgroup
1944   \def\syst_boxes_process_indeed{#1}% #1 can be redefined halfway
1945   \setbox\processbox\emptybox
1946   \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}
1947
1948\def\syst_boxes_process_yes
1949  {\dowithnextboxcs\syst_boxes_process_content\hbox}
1950
1951\def\syst_boxes_process_content
1952  {\removeunwantedspaces
1953   \syst_boxes_process_indeed % takes \nextbox makes \processbox
1954   \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}
1955
1956\protected\def\syst_boxes_process_nop
1957  {\removeunwantedspaces
1958   \box\processbox
1959   \egroup}
1960
1961%D \macros
1962%D   {startoverlay}
1963%D
1964%D We can overlay boxes by saying:
1965%D
1966%D \startbuffer
1967%D \startoverlay
1968%D   {\framed{hans}}
1969%D   {\framed[width=3cm]{ton}}
1970%D   {\framed[height=2cm]{oeps}}
1971%D \stopoverlay
1972%D \stopbuffer
1973%D
1974%D \typebuffer
1975%D
1976%D shows up as:
1977%D
1978%D \leavevmode\getbuffer
1979
1980\permanent\def\boxisempty#1%
1981  {\ifdim\wd#1=\zeropoint
1982     \ifdim\ht#1=\zeropoint
1983       \ifdim\dp#1=\zeropoint
1984         \zerocount
1985       \else
1986         \plusone
1987       \fi
1988     \else
1989       \plusone
1990     \fi
1991   \else
1992     \plusone
1993   \fi}
1994
1995\def\syst_boxes_overlay_process
1996  {\ifcase\boxisempty\nextbox\else
1997     \syst_boxes_overlay_process_indeed
1998   \fi}
1999
2000\def\syst_boxes_overlay_process_indeed
2001  {%\removeunwantedspaces % already done
2002   \scratchdepth\dp\ifdim\dp\nextbox>\dp\processbox\nextbox\else\processbox\fi
2003   \ifdim\ht\nextbox>\ht\processbox
2004     \setbox\processbox\vpack to \ht\nextbox   {\dp\processbox\zeropoint\vss\box\processbox\vss}%
2005   \else
2006     \setbox\nextbox   \vpack to \ht\processbox{\dp\nextbox   \zeropoint\vss\box\nextbox   \vss}%
2007   \fi
2008   \dp\nextbox   \scratchdepth
2009   \dp\processbox\scratchdepth
2010   \scratchwidth\wd\ifdim\wd\nextbox>\wd\processbox\nextbox\else\processbox\fi
2011   \setbox\processbox\hpack to \scratchwidth
2012     {\hpack to \scratchwidth{\hss\box\processbox\hss}%
2013      \kern-\scratchwidth
2014      \hpack to \scratchwidth{\hss\box\nextbox   \hss}}}
2015
2016\permanent\protected\def\startoverlay
2017  {\vbox\bgroup % we remove unwanted spaces so we want to prevent the pre-overlay gobble
2018   \enforced\aliased\let\stopoverlay\egroup
2019   \processboxes\syst_boxes_overlay_process}
2020
2021\permanent\protected\lettonothing\stopoverlay
2022
2023%D \macros
2024%D   {fakebox}
2025%D
2026%D The next macro is a rather silly one, but saves space.
2027%D
2028%D \starttyping
2029%D \hbox{\fakebox0}
2030%D \stoptyping
2031%D
2032%D returns an empty box with the dimensions of the box specified, here being zero.
2033
2034\permanent\protected\def\fakebox
2035  {\bgroup
2036   \afterassignment\syst_boxes_fakebox_finish\scratchcounter}
2037
2038\def\syst_boxes_fakebox_finish
2039  {\setbox\scratchbox\ifhbox\scratchcounter\emptyhbox\else\emptyvbox\fi
2040   \wd\scratchbox\wd\scratchcounter
2041   \ht\scratchbox\ht\scratchcounter
2042   \dp\scratchbox\dp\scratchcounter
2043   \box\scratchbox
2044   \egroup}
2045
2046%D \macros
2047%D   {lbox,rbox,cbox,tbox,bbox}
2048%D
2049%D Here are some convenient alternative box types:
2050%D
2051%D \starttyping
2052%D \lbox{text ...}
2053%D \cbox{text ...}
2054%D \rbox{text ...}
2055%D \stoptyping
2056%D
2057%D Are similar to \type {\vbox}, which means that they also accept something like
2058%D \type {to 3cm}, but align to the left, middle and right. These box types can be
2059%D used to typeset paragraphs.
2060
2061\def\syst_boxes_lrc_process#1%
2062  {\bgroup
2063   \forgetall
2064   \enforced\let\\\endgraf
2065   #1%
2066   \let\nexttoken}
2067
2068\permanent\protected\def\lbox#1#{\vbox#1\syst_boxes_lrc_process\raggedleft  }
2069\permanent\protected\def\cbox#1#{\vbox#1\syst_boxes_lrc_process\raggedcenter}
2070\permanent\protected\def\rbox#1#{\vbox#1\syst_boxes_lrc_process\raggedright }
2071
2072\permanent\protected\def\ltop#1#{\vtop#1\syst_boxes_lrc_process\raggedleft  }
2073\permanent\protected\def\ctop#1#{\vtop#1\syst_boxes_lrc_process\raggedcenter}
2074\permanent\protected\def\rtop#1#{\vtop#1\syst_boxes_lrc_process\raggedright }
2075
2076%D The alternatives \type {\tbox} and \type {\bbox} can be used to properly align
2077%D boxes, like in:
2078%D
2079%D \setupexternalfigures[directory={../sample}]
2080%D \startbuffer
2081%D \starttable[|||]
2082%D \HL
2083%D \VL \tbox{\externalfigure[cow][height=3cm,frame=on]} \VL top aligned    \VL\SR
2084%D \HL
2085%D \VL \bbox{\externalfigure[cow][height=3cm,frame=on]} \VL bottom aligned \VL\SR
2086%D \HL
2087%D \stoptable
2088%D \stopbuffer
2089%D
2090%D \typebuffer
2091%D
2092%D The positioning depends on the strut settings:
2093%D
2094%D \getbuffer
2095
2096\permanent\protected\def\tbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_tbox_finish\hbox}
2097\permanent\protected\def\bbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_bbox_finish\hbox}
2098
2099\def\syst_boxes_tbox_finish
2100  {\scratchheight\strutht
2101   \scratchdepth\dimexpr\htdp\nextbox-\scratchheight\relax
2102   \ht\nextbox\scratchheight
2103   \dp\nextbox\scratchdepth
2104   \boxyoffset\nextbox-\scratchdepth
2105   \box\nextbox
2106   \egroup}
2107
2108\def\syst_boxes_bbox_finish
2109  {\scratchdepth\strutdp
2110   \scratchheight\dimexpr\htdp\nextbox-\scratchdepth\relax
2111   \dp\nextbox\scratchdepth
2112   \ht\nextbox\scratchheight
2113   \boxyoffset\nextbox-\scratchdepth
2114   \box\nextbox
2115   \egroup}
2116
2117%D \macros
2118%D   {lhbox,mhbox,rhbox}
2119%D
2120%D A few more boxes.
2121
2122\def\syst_boxes_lhbox{\hpack to \hsize{\box\nextbox\hss    }}
2123\def\syst_boxes_mhbox{\hpack to \hsize{\hss\box\nextbox\hss}}
2124\def\syst_boxes_rhbox{\hpack to \hsize{\hss\box\nextbox    }}
2125
2126\permanent\protected\def\lhbox{\dowithnextboxcs\syst_boxes_lhbox\hbox}
2127\permanent\protected\def\mhbox{\dowithnextboxcs\syst_boxes_mhbox\hbox}
2128\permanent\protected\def\rhbox{\dowithnextboxcs\syst_boxes_rhbox\hbox}
2129
2130\aliased\let\lefthbox \lhbox
2131\aliased\let\midhbox  \mhbox
2132\aliased\let\righthbox\rhbox
2133
2134%D \macros
2135%D   {boxofsize}
2136%D
2137%D Sometimes we need to construct a box with a height or width made up of several
2138%D dimensions. Instead of cumbersome additions, we can use:
2139%D
2140%D \starttyping
2141%D \boxofsize \vbox 10cm 3cm -5cm {the text to be typeset}
2142%D \stoptyping
2143%D
2144%D This example demonstrates that one can use positive and negative values.
2145%D Dimension registers are also accepted.
2146
2147\newdimension\sizeofbox
2148
2149\permanent\protected\def\boxofsize#1%
2150  {\bgroup
2151   \sizeofbox\zeropoint
2152   \scratchdimen\zeropoint
2153   \def\docommand
2154     {\advanceby\sizeofbox\scratchdimen
2155      \futurelet\nexttoken\dodocommand}%
2156   \def\dodocommand
2157     {\ifx\nexttoken\bgroup
2158        \normalexpanded{\egroup#1 to \the\sizeofbox}%
2159      \else
2160        \expandafter\afterassignment\expandafter\docommand\expandafter\scratchdimen
2161      \fi}%
2162   \docommand}
2163
2164%D Some new, still undocumented features:
2165
2166% limitatetext -> beter {text} als laatste !!
2167%
2168% \limitvbox
2169% \limithbox
2170
2171\permanent\protected\def\limitatelines#1#2% size sentinel
2172  {\dowithnextbox
2173     {\scratchdimen#1\hsize
2174      \ifdim\wd\nextbox>\scratchdimen
2175        \setbox\nextbox\hbox
2176          {\advanceby\scratchdimen -.1\hsize
2177           \limitatetext{\unhbox\nextbox}{\scratchdimen}{\nobreak#2}}%
2178      \fi
2179      \unhbox\nextbox}
2180     \hbox}
2181
2182\permanent\protected\def\fittoptobaselinegrid % weg hier
2183  {\dowithnextbox
2184     {\bgroup
2185      \par
2186      \scratchdimen\ht\nextbox
2187      \ht\nextbox\strutht
2188      \dp\nextbox\strutdp
2189      \hpack{\box\nextbox}
2190      \prevdepth\strutdp
2191      \doloop
2192        {\advanceby\scratchdimen -\lineheight
2193         \ifdim\scratchdimen<\zeropoint
2194           \exitloop
2195         \else
2196           \nobreak
2197           \hpack{\strut}
2198         \fi}
2199      \egroup}
2200     \vbox}
2201
2202%D Some more undocumented macros (used in m-chart).
2203
2204\newif\iftraceboxplacement % \traceboxplacementtrue
2205
2206\newbox\fakedboxcursor
2207
2208\setbox\fakedboxcursor\hpack
2209  {\vrule\s!width\zeropoint\s!height\zeropoint\s!depth\zeropoint}
2210
2211\permanent\protected\def\boxcursor % overloaded in core-vis
2212  {\iftraceboxplacement
2213     \bgroup
2214     \scratchdimen2\onepoint
2215     \setbox\scratchbox\hpack to \zeropoint
2216       {\hss
2217        \vrule
2218          \s!width \scratchdimen
2219          \s!height\scratchdimen
2220          \s!depth \scratchdimen
2221        \hss}%
2222     \smashedbox\scratchbox
2223     \egroup
2224   \else
2225     \copy\fakedboxcursor
2226   \fi}
2227
2228\permanent\protected\def\placedbox
2229  {\iftraceboxplacement\ruledhbox\else\hbox\fi}
2230
2231\newdimension\boxoffset
2232\newdimension\boxhdisplacement
2233\newdimension\boxvdisplacement
2234
2235\permanent\protected\def\rightbox      {\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbox_finish      \placedbox}
2236\permanent\protected\def\leftbox       {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbox_finish       \placedbox}
2237\permanent\protected\def\topbox        {\hpack\bgroup\dowithnextboxcs\syst_boxes_topbox_finish        \placedbox}
2238\permanent\protected\def\bottombox     {\hpack\bgroup\dowithnextboxcs\syst_boxes_bottombox_finish     \placedbox}
2239\permanent\protected\def\lefttopbox    {\hpack\bgroup\dowithnextboxcs\syst_boxes_lefttopbox_finish    \placedbox}
2240\permanent\protected\def\righttopbox   {\hpack\bgroup\dowithnextboxcs\syst_boxes_righttopbox_finish   \placedbox}
2241\permanent\protected\def\leftbottombox {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbottombox_finish \placedbox}
2242\permanent\protected\def\rightbottombox{\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbottombox_finish\placedbox}
2243
2244\aliased\let\topleftbox    \lefttopbox
2245\aliased\let\toprightbox   \righttopbox
2246\aliased\let\bottomleftbox \leftbottombox
2247\aliased\let\bottomrightbox\rightbottombox
2248
2249\def\syst_boxes_rightbox_finish
2250  {\global\boxhdisplacement\boxoffset
2251   \global\boxvdisplacement.5\dimexpr\ht\nextbox-\dp\nextbox\relax
2252   \boxcursor
2253   \boxxmove\nextbox \boxhdisplacement
2254   \boxymove\nextbox-\boxvdisplacement
2255   \box\nextbox
2256   \egroup}
2257
2258\def\syst_boxes_leftbox_finish
2259  {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
2260   \global\boxvdisplacement.5\dimexpr\ht\nextbox-\dp\nextbox\relax
2261   \boxcursor
2262   \boxxmove\nextbox \boxhdisplacement
2263   \boxymove\nextbox-\boxvdisplacement
2264   \box\nextbox
2265   \egroup}
2266
2267\def\syst_boxes_topbox_finish
2268  {\global\boxhdisplacement-.5\wd\nextbox
2269   \global\boxvdisplacement\dimexpr-\dp\nextbox-\boxoffset\relax
2270   \boxcursor
2271   \boxxmove\nextbox \boxhdisplacement
2272   \boxymove\nextbox-\boxvdisplacement
2273   \box\nextbox
2274   \egroup}
2275
2276\def\syst_boxes_bottombox_finish
2277  {\global\boxhdisplacement-.5\wd\nextbox
2278   \global\boxvdisplacement\dimexpr\ht\nextbox+\boxoffset\relax
2279   \boxcursor
2280   \boxxmove\nextbox \boxhdisplacement
2281   \boxymove\nextbox-\boxvdisplacement
2282   \box\nextbox
2283   \egroup}
2284
2285\def\syst_boxes_lefttopbox_finish
2286  {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
2287   \global\boxvdisplacement\dimexpr-\dp\nextbox-\boxoffset\relax
2288   \boxcursor
2289   \boxxmove\nextbox \boxhdisplacement
2290   \boxymove\nextbox-\boxvdisplacement
2291   \box\nextbox
2292   \egroup}
2293
2294\def\syst_boxes_righttopbox_finish
2295  {\global\boxhdisplacement\boxoffset
2296   \global\boxvdisplacement\dimexpr-\dp\nextbox-\boxoffset\relax
2297   \boxcursor
2298   \boxxmove\nextbox \boxhdisplacement
2299   \boxymove\nextbox-\boxvdisplacement
2300   \box\nextbox
2301   \egroup}
2302
2303\def\syst_boxes_leftbottombox_finish
2304  {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
2305   \global\boxvdisplacement\dimexpr\ht\nextbox+\boxoffset\relax
2306   \boxcursor
2307   \boxxmove\nextbox \boxhdisplacement
2308   \boxymove\nextbox-\boxvdisplacement
2309   \box\nextbox
2310   \egroup}
2311
2312\def\syst_boxes_rightbottombox_finish
2313  {\global\boxhdisplacement\boxoffset
2314   \global\boxvdisplacement\dimexpr\ht\nextbox+\boxoffset\relax
2315   \boxcursor
2316   \boxxmove\nextbox \boxhdisplacement
2317   \boxymove\nextbox-\boxvdisplacement
2318   \box\nextbox
2319   \egroup}
2320
2321\permanent\protected\def\middlebox        {\hpack\bgroup\dowithnextboxcs\syst_boxes_middlebox_finish        \placedbox}
2322\permanent\protected\def\baselinemiddlebox{\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinemiddlebox_finish\placedbox}
2323\permanent\protected\def\baselineleftbox  {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselineleftbox_finish  \placedbox}
2324\permanent\protected\def\baselinerightbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinerightbox_finish \placedbox}
2325
2326\def\syst_boxes_middlebox_finish
2327  {\global\boxhdisplacement-.5\wd\nextbox
2328   \global\boxvdisplacement.5\dimexpr\ht\nextbox-\dp\nextbox\relax
2329   \boxcursor
2330   \boxxmove\nextbox \boxhdisplacement
2331   \boxymove\nextbox-\boxvdisplacement
2332   \box\nextbox
2333   \egroup}
2334
2335\def\syst_boxes_baselinemiddlebox_finish
2336  {\global\boxhdisplacement\dimexpr-.5\wd\nextbox-\boxoffset\relax
2337   \global\boxvdisplacement-\boxoffset
2338   \boxcursor
2339   \boxxmove\nextbox \boxhdisplacement
2340   \boxymove\nextbox-\boxvdisplacement
2341   \box\nextbox
2342   \egroup}
2343
2344\def\syst_boxes_baselineleftbox_finish
2345  {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
2346   \global\boxvdisplacement-\boxoffset
2347   \boxcursor
2348   \boxxmove\nextbox \boxhdisplacement
2349   \boxymove\nextbox-\boxvdisplacement
2350   \box\nextbox
2351   \egroup}
2352
2353\def\syst_boxes_baselinerightbox_finish
2354  {\global\boxhdisplacement\boxoffset
2355   \global\boxvdisplacement-\boxoffset
2356   \boxcursor
2357   \boxxmove\nextbox \boxhdisplacement
2358   \boxymove\nextbox-\boxvdisplacement
2359   \box\nextbox
2360   \egroup}
2361
2362%D \macros
2363%D   {obox}
2364%D
2365%D Experimental, not yet frozen:
2366
2367\permanent\protected\def\lrtbbox#1#2#3#4% l r t b
2368  {\bgroup
2369   \dowithnextboxcontent
2370     {\advanceby\hsize-#1\advanceby\hsize-#2\relax
2371      \advanceby\vsize-#3\advanceby\vsize-#4\relax}
2372     {\forgetall\vpack to \vsize{\vskip#3\hpack to \hsize{\hskip#1\box\nextbox\hss}\vss}\egroup}
2373     \vbox}
2374
2375%D \macros
2376%D   {toplinebox}
2377%D
2378%D See core-tbl.tex for an example of its usage:
2379
2380\permanent\protected\def\toplinebox
2381  {\dowithnextboxcs\syst_boxes_toplinebox_finish\tbox}
2382
2383\def\syst_boxes_toplinebox_finish
2384  {\ifdim\dp\nextbox>\strutdepth
2385     \scratchdimen\dp\nextbox
2386     \advanceby\scratchdimen-\strutdepth
2387     \getnoflines\scratchdimen
2388     \struttedbox{\box\nextbox}%
2389     \dorecurse\noflines\verticalstrut
2390   \else
2391     \box\nextbox
2392   \fi}
2393
2394%D \macros
2395%D   {initializeboxstack,savebox,foundbox}
2396%D
2397%D At the cost of some memory, but saving box registers, we have implemented a box
2398%D repository.
2399%D
2400%D \starttyping
2401%D \initializeboxstack{one}
2402%D
2403%D \savebox{one}{a}{test a}
2404%D \savebox{one}{p}{test p}
2405%D \savebox{one}{q}{test q}
2406%D
2407%D \hbox{a:\foundbox{one}{a}} \par
2408%D \hbox{q:\foundbox{one}{q}} \par
2409%D \hbox{p:\foundbox{one}{p}} \par
2410%D \hbox{x:\foundbox{one}{x}} \par
2411%D \hbox{y:\foundbox{two}{a}} \par
2412%D \stoptyping
2413
2414%D Kind of obsolete:
2415
2416\installcorenamespace {stackbox}
2417\installcorenamespace {stacklst}
2418
2419\permanent\protected\def\setstackbox#1#2%
2420  {\ifcsname\??stackbox#1:#2\endcsname\else
2421     \expandafter\newbox\csname\??stackbox#1:#2\endcsname
2422   \fi
2423   \global\setbox\csname\??stackbox#1:#2\endcsname\vbox}
2424
2425\permanent\protected\def\initializeboxstack#1%
2426  {\def\docommand##1{\setstackbox{#1}{##1}{}}%
2427   \ifcsname\??stacklst#1\endcsname
2428     \expandafter\processcommacommand\expandafter[\lastnamedcs]\docommand
2429   \fi
2430   \gletcsname\??stacklst#1\endcsname\empty}
2431
2432\permanent\protected\def\savebox#1#2% stack name
2433  {% beware, \setxvalue defines the cs beforehand so we cannot use the test inside the { }
2434   \ifcsname\??stacklst#1\endcsname
2435     \xdefcsname\??stacklst#1\expandafter\endcsname\expandafter{\lastnamedcs,#2}%
2436   \else
2437     \xdefcsname\??stacklst#1\endcsname{#2}%
2438   \fi
2439   \setstackbox{#1}{#2}}
2440
2441\permanent\protected\def\flushbox#1#2% unwrapped
2442  {\ifcsname\??stackbox#1:#2\endcsname
2443     \box\lastnamedcs
2444   \else
2445     \emptybox
2446   \fi}
2447
2448\permanent\protected\def\restorebox#1#2% unwrapped
2449  {\ifcsname\??stackbox#1:#2\endcsname
2450     \copy\lastnamedcs
2451   \else
2452     \emptybox
2453   \fi}
2454
2455\permanent\protected\def\foundbox#1#2% wrapped
2456  {\vpack
2457     {\ifcsname\??stackbox#1:#2\endcsname
2458        \copy\lastnamedcs
2459      \fi}}
2460
2461\permanent\protected\def\doifelsebox#1#2%
2462  {\unless\ifcsname\??stackbox#1:#2\endcsname
2463     \expandafter\secondoftwoarguments
2464   \orelse\ifvoid\lastnamedcs
2465     \expandafter\secondoftwoarguments
2466   \else
2467     \expandafter\firstoftwoarguments
2468   \fi}
2469
2470\aliased\let\doifboxelse\doifelsebox
2471
2472%D This one is cheaper (the above is no longer used that much):
2473
2474\installcorenamespace {boxstack}
2475
2476\newinteger\c_syst_boxes_stack
2477
2478\mutable\let\b_syst_boxes_stack\relax
2479
2480\protected\def\syst_boxes_stack_allocate
2481  {\newbox\b_syst_boxes_stack
2482   \letcsname\??boxstack\the\c_syst_boxes_stack\endcsname\b_syst_boxes_stack}
2483
2484\protected\def\syst_boxes_push#1#2%
2485  {\global\advanceby\c_syst_boxes_stack\plusone
2486   \expandafter\let\expandafter\b_syst_boxes_stack\csname\??boxstack\the\c_syst_boxes_stack\endcsname
2487   \ifrelax\b_syst_boxes_stack % cheaper then csname check as in most cases it's defined
2488      \syst_boxes_stack_allocate
2489   \fi
2490   #1\setbox\b_syst_boxes_stack\box#2\relax}
2491
2492\protected\def\syst_boxes_pop#1#2%
2493  {#1\setbox#2\box\csname\??boxstack\the\c_syst_boxes_stack\endcsname
2494   \global\advanceby\c_syst_boxes_stack\minusone}
2495
2496\permanent\protected\def\localpushbox {\syst_boxes_push\relax}
2497\permanent\protected\def\localpopbox  {\syst_boxes_pop \relax}
2498
2499\permanent\protected\def\globalpushbox{\syst_boxes_push\global}
2500\permanent\protected\def\globalpopbox {\syst_boxes_pop \global}
2501
2502%D And here is a more modern one (not yet in i-*):
2503%D
2504%D \starttyping
2505%D \dorecurse {100} {
2506%D     \setbox\zerocount\hbox{test \recurselevel}
2507%D     \putboxincache{foo}{\recurselevel}\zerocount
2508%D     \copyboxfromcache{foo}{\recurselevel}\zerocount
2509%D     \iftrue
2510%D         \setbox\zerocount\hbox{\directboxfromcache{foo}{\recurselevel}}%
2511%D     \else
2512%D         \getboxfromcache{foo}{\recurselevel}\zerocount
2513%D     \fi
2514%D }
2515%D % \startMPcode draw rawtexbox("category","name") ; \stopMPcode
2516%D \resetboxesincache{foo}
2517%D \stoptyping
2518
2519% \putboxincache          % {category} {name} number
2520% \getboxfromcache        % {category} {name} number
2521% \doifelseboxincache     % {category} {name}
2522% \copyboxfromcache       % {category} {name} number
2523% \directboxfromcache     % {category} {name}
2524% \directcopyboxfromcache % {category} {name}
2525% \resetboxesincache      % {category}
2526% \putnextboxincache      % {category} {name} box
2527% \getboxwdfromcache      % {category} {name}
2528% \getboxhtfromcache      % {category} {name}
2529% \getboxdpfromcache      % {category} {name}
2530% \getboxhtdpfromcache    % {category} {name}
2531
2532%D \macros
2533%D   {removedepth, obeydepth}
2534%D
2535%D While \type {\removedepth} removes the preceding depth, \type {\obeydepth} makes
2536%D sure we have depth. Both macros leave the \type {\prevdepth} untouched.
2537
2538\permanent\protected\def\removedepth
2539  {\ifvmode
2540     \ifdim\prevdepth>\zeropoint
2541       \kern-\prevdepth
2542     \fi
2543   \fi}
2544
2545\permanent\protected\def\obeydepth
2546  {\par % watch out for changes in math formulas
2547   \ifvmode\ifdim\prevdepth<\zeropoint\orelse\ifdim\prevdepth<\strutdp
2548     \kern\dimexpr\strutdp-\prevdepth\relax
2549     \prevdepth\strutdp
2550   \fi\fi}
2551
2552\permanent\protected\def\undepthed
2553  {\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\hbox}
2554
2555%D \macros
2556%D   {removebottomthings, removelastskip}
2557%D
2558%D A funny (but rather stupid) one, plus a redefinition.
2559
2560% \permanent\protected\def\removebottomthings
2561%   {\dorecurse\plusfive{\unskip\unkern\unpenalty}}
2562
2563\permanent\protected\def\removebottomthings
2564  {\localcontrolledloop\plusone\plusfive\plusone{\unskip\unkern\unpenalty}}
2565
2566\permanent\protected\def\removelastskip % \ifvmode the plain tex one \fi, overloaded to \permanent in spac-ver
2567  {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi}
2568
2569%D \macros
2570%D   {makestrutofbox}
2571%D
2572%D This macro sets the dimensions of a box to those of a strut. Sort of obsolete so
2573%D it will go away.
2574
2575\permanent\protected\def\makestrutofbox % not used
2576  {\afterassignment\syst_boxes_makestrutofbox\c_boxes_register}
2577
2578\def\syst_boxes_makestrutofbox
2579  {\ht\c_boxes_register\strutht
2580   \dp\c_boxes_register\strutdp
2581   \wd\c_boxes_register\zeropoint}
2582
2583%D \macros
2584%D   {raisebox,lowerbox}
2585%D
2586%D Some more box stuff, related to positioning (under construction). Nice stuff for
2587%D a tips and tricks maps article.
2588%D
2589%D \starttyping
2590%D \raisebox{100pt}\hbox{test}
2591%D \hsmash{\raisebox{100pt}\hbox{test}}
2592%D \stoptyping
2593
2594\permanent\protected\def\raisebox#1{\bgroup\afterassignment\syst_boxes_raise_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted
2595\permanent\protected\def\lowerbox#1{\bgroup\afterassignment\syst_boxes_lower_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted
2596
2597\def\syst_boxes_raise_indeed{\dowithnextboxcs\syst_boxes_raise_finish}
2598\def\syst_boxes_lower_indeed{\dowithnextboxcs\syst_boxes_lower_finish}
2599
2600\def\syst_boxes_raise_finish
2601  {\boxyoffset\nextbox\scratchdimen
2602   \ht\nextbox\strutht
2603   \dp\nextbox\strutdp
2604   \box\nextbox
2605   \egroup}
2606
2607\def\syst_boxes_lower_finish
2608  {\boxyoffset\nextbox-\scratchdimen
2609   \ht\nextbox\strutht
2610   \dp\nextbox\strutdp
2611   \box\nextbox
2612   \egroup}
2613
2614% vcenter in text, we kunnen vcenter overloaden
2615
2616\permanent\protected\def\halfwaybox
2617  {\hpack\bgroup
2618   \dowithnextboxcs\syst_boxes_halfwaybox_finish\hbox}
2619
2620\def\syst_boxes_halfwaybox_finish
2621  {\dp\nextbox\zeropoint
2622   \lower.5\ht\nextbox\box\nextbox
2623   \egroup}
2624
2625\permanent\protected\def\depthonlybox
2626  {\tpack\bgroup
2627   \dowithnextboxcs\syst_boxes_depthonlybox_finish\vbox}
2628
2629\def\syst_boxes_depthonlybox_finish
2630  {\hsize\wd\nextbox
2631   \kern\zeropoint\box\nextbox
2632   \egroup}
2633
2634%D New:
2635
2636\permanent\def\setdimentoatleast#1#2{\ifdim#1>\zeropoint\else#1=#2\fi}
2637\permanent\def\setdimentoatmost #1#2{\ifdim#1>#2\relax  \else#1=#2\fi}
2638
2639%D And even rawer:
2640
2641\aliased\let\naturalvcenter\normalvtop % will go away
2642
2643% \appendtoks \let\vcenter\normalvcenter \to \everymathematics
2644
2645%D \macros
2646%D   {frozenhbox}
2647%D
2648%D A not so well unhboxable box can be made with:
2649
2650\permanent\protected\def\frozenhbox
2651  {\hpack\bgroup
2652   \dowithnextboxcs\syst_boxes_frozenhbox_finish\hbox}
2653
2654\def\syst_boxes_frozenhbox_finish
2655  {\hpack{\hpack{\box\nextbox}}%
2656   \egroup}
2657
2658%D \macros
2659%D   {setboxllx,setboxlly,gsetboxllx,gsetboxlly,getboxllx,getboxlly}
2660%D
2661%D A prelude to an extended \TEX\ feature:
2662
2663\installcorenamespace {box_x}
2664\installcorenamespace {box_y}
2665
2666\permanent\protected\def\setboxllx #1#2{\edefcsname\??box_x\number#1\endcsname{\the\dimexpr#2\relax}}
2667\permanent\protected\def\setboxlly #1#2{\edefcsname\??box_y\number#1\endcsname{\the\dimexpr#2\relax}}
2668
2669\permanent\protected\def\gsetboxllx#1#2{\xdefcsname\??box_x\number#1\endcsname{\the\dimexpr#2\relax}}
2670\permanent\protected\def\gsetboxlly#1#2{\xdefcsname\??box_y\number#1\endcsname{\the\dimexpr#2\relax}}
2671
2672\permanent\def\getboxllx#1{\ifcsname\??box_x\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
2673\permanent\def\getboxlly#1{\ifcsname\??box_y\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
2674
2675\permanent\def\directgetboxllx#1{\csname\??box_x\number#1\endcsname} % use when sure existence
2676\permanent\def\directgetboxlly#1{\csname\??box_y\number#1\endcsname} % use when sure existence
2677
2678%D \macros
2679%D   {shownextbox}
2680%D
2681%D Handy for tracing
2682%D
2683%D \starttyping
2684%D \shownextbox\vbox{test}
2685%D \shownextbox\vbox{test\endgraf}
2686%D \shownextbox\vbox{test\endgraf\strut\endgraf}
2687%D \shownextbox\vbox{test\endgraf\thinrule}
2688%D \shownextbox\vbox{\setupwhitespace[big]test\endgraf\thinrule}
2689%D \stoptyping
2690
2691\permanent\protected\def\shownextbox % seldom used
2692  {\dowithnextbox
2693     {\bgroup
2694      \showboxbreadth\maxcount
2695      \showboxdepth  \maxcount
2696      \scratchcounter\interactionmode
2697      \batchmode
2698      \showbox\nextbox
2699      \box\nextbox
2700      \interactionmode\scratchcounter
2701      \egroup}}
2702
2703\permanent\protected\def\spreadhbox#1% rebuilds \hbox{<box><hss><box><hss><box>}
2704  {\bgroup
2705   \ifhbox#1\relax
2706     \setbox\scratchboxtwo\emptybox
2707     \unhbox#1%
2708     \doloop
2709       {\unpenalty\unskip\unpenalty\unskip\unpenalty\unskip
2710        \setbox\scratchboxone\lastbox
2711        \ifvoid\scratchboxone
2712          \exitloop
2713        \else
2714          \setbox\scratchboxtwo\hbox
2715            {\ifhbox\scratchboxone \spreadhbox\scratchboxone\else\box\scratchboxone\fi
2716             \ifvoid\scratchboxtwo \else\hss\unhbox\scratchboxtwo\fi}%
2717        \fi}%
2718     \ifvoid\scratchboxtwo\else\unhbox\scratchboxtwo\fi
2719   \else
2720     \box#1%
2721   \fi
2722   \egroup}
2723
2724% \showboxbreadth\plusthousand
2725% \showboxdepth  \plusthousand
2726
2727%D Moved from cont-new:
2728%D
2729%D \starttyping
2730%D \minimalhbox 100pt {test}
2731%D \stoptyping
2732
2733\permanent\protected\def\minimalhbox#1#%
2734  {\dowithnextbox
2735     {\bgroup
2736      \setbox\scratchbox\hpack#1{\hss}%
2737      \ifdim\wd\nextbox<\wd\scratchbox\wd\nextbox\wd\scratchbox\fi
2738      \box\nextbox
2739      \egroup}
2740     \hbox}
2741
2742%D A bit dirty:
2743
2744% \permanent\protected\def\nodestostring#1#2% more tolerant for #2=\cs
2745%   {\begingroup
2746%    \setbox\nextbox\hbox{#2}%
2747%    \normalexpanded{\endgroup\edef\noexpand#1{\boxtostring\nextbox}}}
2748%
2749% \permanent\def\tostring
2750%   {\beginlocalcontrol
2751%    \dowithnextbox{\endlocalcontrol\boxtostring\nextbox}\hbox}
2752%
2753% \permanent\def\tostring
2754%   {\beginlocalcontrol\begingroup
2755%    \dowithnextbox{\normalexpanded{\endgroup\endlocalcontrol\boxtostring\nextbox}}\hbox}
2756
2757\def\syst_boxes_contenttostring
2758  {\normalexpanded{\endgroup\endlocalcontrol\boxtostring\nextbox}}
2759
2760\permanent\def\contenttostring
2761  {\beginlocalcontrol\begingroup
2762   \dowithnextboxcs\syst_boxes_contenttostring\hbox}
2763
2764\newtoks \everypreroll
2765\newif   \ifprerolling
2766
2767\appendtoks
2768    \prerollingtrue
2769\to \everypreroll
2770
2771\let\prerolltostring\firstofoneargument % we need to bypass initializations
2772
2773% This fails on an empty document (probably some mode issue):
2774
2775% \appendtoks
2776%     \permanent\def\prerolltostring
2777%       {\beginlocalcontrol\begingroup
2778%        \expand\everypreroll
2779%        \dowithnextboxcs\syst_boxes_contenttostring\hbox}
2780% \to \everydump
2781%
2782% So we do this instead:
2783
2784\newbox\b_syst_boxes
2785
2786\appendtoks
2787    \permanent\def\prerolltostring#1%
2788      {\beginlocalcontrol
2789       \setbox\b_syst_boxes\hbox{\expand\everypreroll#1}%
2790       \normalexpanded
2791         {\setbox\b_syst_boxes\emptybox
2792          \endlocalcontrol
2793          \boxtostring\b_syst_boxes}}
2794\to \everydump
2795
2796% depricated:
2797
2798\permanent\protected\def\nodestostring#1#2% more tolerant for #2=\cs
2799  {\edef#2{\contenttostring{#1}}}
2800
2801%D Even more dirty:
2802
2803\aliased\let\hyphenatedhbox\hbox % was a macro in mkii
2804
2805%D We can do this:
2806%D
2807%D \starttyping
2808%D \setbox0\hbox to 10cm{foo} \setbox2\hbox{\unhbox0} \the\wd2
2809%D \stoptyping
2810%D
2811%D But this saves a copy (and hpack pass):
2812%D
2813%D \starttyping
2814%D \setbox0\hbox to 10cm{foo} \the\naturalwd0
2815%D \stoptyping
2816
2817% \newdimension\lastnaturalboxwd
2818% \newdimension\lastnaturalboxht
2819% \newdimension\lastnaturalboxdp
2820
2821%D We can define these public in lua:
2822
2823% \aliased\let\getnaturaldimensions\clf_getnaturaldimensions % sets three dimensions
2824% \aliased\let\naturalwd           \clf_naturalwd            % calculates and returns wd
2825
2826% \aliased\let\getnaturalwd\clf_getnaturalwd % no intermediate
2827% \aliased\let\setnaturalwd\clf_setnaturalwd % no intermediate
2828
2829\permanent\protected\def\doifelserighttoleftinbox{\clf_doifelserighttoleftinbox}
2830
2831\aliased\let\doifrighttoleftinboxelse\doifelserighttoleftinbox
2832
2833%D New, used in high/low:
2834
2835\definesystemattribute [runningtext] [public]
2836
2837\permanent\protected\def\runninghbox{\hbox attr \runningtextattribute \fontid\font} % not yet in i-*
2838
2839%D To complement lua (yet undocumented):
2840
2841\permanent\protected\def\beginhbox{\hbox\bgroup}  \aliased\let\endhbox\egroup
2842\permanent\protected\def\beginvbox{\vbox\bgroup}  \aliased\let\endvbox\egroup
2843\permanent\protected\def\beginvtop{\vtop\bgroup}  \aliased\let\endvtop\egroup
2844
2845\permanent\protected\def\sethboxregister#1{\setbox#1\hbox}
2846\permanent\protected\def\setvboxregister#1{\setbox#1\vbox}
2847\permanent\protected\def\setvtopregister#1{\setbox#1\vtop}
2848
2849\permanent\protected\def\flushboxregister#1{\box\numexpr#1\relax}
2850
2851\permanent\protected\def\starthboxregister#1{\setbox#1\hbox\bgroup}  \aliased\let\stophboxregister\egroup
2852\permanent\protected\def\startvboxregister#1{\setbox#1\vbox\bgroup}  \aliased\let\stopvboxregister\egroup
2853\permanent\protected\def\startvtopregister#1{\setbox#1\vtop\bgroup}  \aliased\let\stopvtopregister\egroup
2854
2855% %D For whatever third party package needs it:
2856% %D
2857% %D \starttyping
2858% %D \newlocalbox\BoxOne
2859% %D \newlocalbox\BoxTwo
2860% %D
2861% %D \setbox\BoxOne\hbox{Box One}
2862% %D \setbox\BoxTwo\hbox{Box Two}
2863% %D
2864% %D [\box\BoxTwo] [\box\BoxOne]
2865% %D \stoptyping
2866%
2867% \installcorenamespace{localbox}
2868%
2869% \permanent\protected\def\newlocalbox#1%
2870%   {\expandafter\let\expandafter#1\csname\??localbox\string#1\endcsname
2871%    \ifrelax#1%
2872%      \syst_aux_new_localbox#1%
2873%    \fi}
2874%
2875% \def\syst_aux_new_localbox#1%
2876%   {\expandafter\newbox\csname\??localbox\string#1\endcsname
2877%    \newlocalbox#1}
2878
2879%D Who knows when this comes in handy:
2880
2881\permanent\protected\def\lastlinewidth{\dimexpr\clf_lastlinewidth\scaledpoint\relax}
2882
2883%D Keep as reference:
2884
2885% \protected\def\tightvbox{\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\vbox}
2886% \protected\def\tightvtop{\dowithnextbox{\ht\nextbox\zeropoint\box\nextbox}\vtop}
2887
2888%D This one keeps dimensions and sets the shift field (and so it's more for testing
2889%D than for real usage):
2890
2891\permanent\protected\def\shiftbox  {\clf_shiftbox}
2892\permanent\protected\def\vpackbox  {\clf_vpackbox}
2893\permanent\protected\def\hpackbox  {\clf_hpackbox}
2894\permanent\protected\def\vpackedbox{\clf_vpackedbox}
2895\permanent\protected\def\hpackedbox{\clf_hpackedbox}
2896
2897%D This one has been moved from a 2 decade old file. It makes something boxed
2898%D sit on the baseline.
2899
2900\permanent\protected\def\linebox
2901  {\hpack\bgroup\dowithnextbox
2902     {\scratchdimen\dimexpr\dimexpr\htdp\nextbox-\lineheight\relax/2+\strutdp\relax
2903      \setbox\nextbox\hpack{\lower\scratchdimen\box\nextbox}%
2904      \ht\nextbox\strutht
2905      \dp\nextbox\strutdp
2906      \box\nextbox
2907      \egroup}
2908     \hbox}
2909
2910%D \macros
2911%D   {widthuptohere}
2912%D
2913%D Implemented at the \LUA\ end:
2914%D
2915%D \startbuffer
2916%D widthuptohere:\the\widthuptohere\crlf
2917%D widthuptohere : \the\widthuptohere (space without stretch or shrink!)
2918%D \stopbuffer
2919%D
2920%D \typebuffer \blank \getbuffer \blank
2921%D
2922%D Implemented elsewhere:
2923%D
2924%D \starttyping
2925%D \boxlines    <box>
2926%D \boxline     <box> <line>
2927%D \copyboxline <box> <line>
2928%D \setboxline  <box> <line>
2929%D \boxlineht   <box> <line> [<dimen>]
2930%D \boxlinedp   <box> <line> [<dimen>]
2931%D \boxlinewd   <box> <line> [<dimen>]
2932%D \boxlinels   <box> <line>
2933%D \boxliners   <box> <line>
2934%D \boxlinelh   <box> <line>
2935%D \boxlinerh   <box> <line>
2936%D \boxlinelp   <box> <line>
2937%D \boxlinerp   <box> <line>
2938%D \boxlinein   <box> <line>
2939%D \boxrangeht  <box> <first line> <last line>
2940%D \boxrangedp  <box> <first line> <last line>
2941%D \boxrangewd  <box> <first line> <last line>
2942%D \stoptyping
2943
2944% To be discussed with ws.
2945%
2946% \installcorenamespace{namedboxes}
2947%
2948% \protected\def\newnamedbox#1%
2949%   {\ifcsname\??namedboxes#1\endcsname\else
2950%      \expandafter\newbox\csname\??namedboxes#1\endcsname
2951%    \fi}
2952%
2953% \protected\def\namedbox#1{\csname\??namedboxes#1\endcsname}
2954
2955%D Implemented elsewhere:
2956%D
2957%D \startbuffer
2958%D \setbox0\hbox{test \footnote{test}} (\prelistbox0) (\postlistbox0)
2959%D \setprelistbox0\hbox{BEFORE} \setpostlistbox0\hbox{AFTER}
2960%D \box0
2961%D \stopbuffer
2962%D
2963%D \typebuffer \blank \getbuffer \blank
2964%D
2965%D \starttyping
2966%D \prelistbox     <box>
2967%D \postlistbox    <box>
2968%D \prelistcopy    <box>
2969%D \postlistcopy   <box>
2970%D \setprelistbox  <box> <hbox|vbox|vtop|somebox>
2971%D \setpostlistbox <box> <hbox|vbox|vtop|somebox>
2972%D \stoptyping
2973
2974%D Defined in lua:
2975%D
2976%D setsplitlisthtdp\scratchbox\struthp\strutdp
2977
2978%D Handy but I'll probably forget it:
2979%D
2980%D \starttyping
2981%D \setbox0\hbox{!!!!!}
2982%D \showbox     0
2983%D \showboxhere 0 % always on console, less clutter
2984%D \stoptyping
2985
2986\untraced\permanent\protected\def\showboxhere{\showbox nolevels content online all }
2987
2988% % possible extra interface, currently disabled
2989%
2990% \permanent\tolerant\protected\def\registeranchorbox[#1]#*[#2]%
2991%   {\dowithnextbox
2992%      {\clf_registeranchorbox
2993%         \namedboxanchor{#1}%
2994%         \ifcstok{#2}\v!before\minusone\else\plusone\fi
2995%         \box\nextbox}}
2996
2997%D \macros{doifelseindented}
2998%D
2999%D This test macro is defined at the \LUA\ end:
3000%D
3001%D \startbuffer
3002%D test \doifelseindented{yes}{nop} test\par
3003%D \setupindenting[3em] \indenting[yes]
3004%D test \doifelseindented{yes}{nop} test\par
3005%D \stopbuffer
3006%D
3007%D \typebuffer \blank \startpacked \getbuffer \stoppacked \blank
3008
3009% \definedasluacommand\noflinesinbox
3010
3011%D \macros{boxfixstretch}
3012%D
3013%D This is relative new one and a wrapper around \typ {\boxlimitate} but with a
3014%D criterium.
3015%D
3016%D \startbuffer
3017%D \setbox2\copy0 \boxfixstretch 20pt      2 \box2
3018%D \setbox2\copy0 \boxfixstretch 30pt      2 \box2
3019%D \setbox2\copy0 \boxfixstretch 40pt      2 \box2
3020%D \setbox2\copy0 \boxfixstretch  0pt      2 \box2 % \boxlimitate 2 0pt
3021%D \setbox2\copy0 \boxfixstretch \maxdimen 2 \box2
3022%D \stopbuffer
3023%D
3024%D \setbox0\ruledvbox to 2cm \bgroup
3025%D     test\vskip10pt plus 10pt minus 5pt\relax test%
3026%D \egroup
3027%D
3028%D \startlinecorrection
3029%D \getbuffer
3030%D \stoplinecorrection
3031%D
3032%D \setbox0\ruledhbox to 3cm \bgroup
3033%D     test\hskip10pt plus 10pt minus 5pt\relax test%
3034%D \egroup \getbuffer
3035%D
3036%D \startlinecorrection
3037%D \getbuffer
3038%D \stoplinecorrection
3039
3040\newconditional\boxstretchfixed
3041\newdimension  \boxstretchdelta
3042
3043\permanent\protected\def\boxfixstretch
3044  {\begingroup
3045   \afterassignment\syst_boxes_fixstretch_a\scratchdimen}
3046
3047\permanent\protected\def\syst_boxes_fixstretch_a
3048  {\afterassignment\syst_boxes_fixstretch_b\scratchcounter}
3049
3050\permanent\protected\def\syst_boxes_fixstretch_b
3051  {\scratchdimenone  \ifvbox\scratchcounter\ht\else\wd\fi\scratchcounter % current size
3052   \scratchdimentwo  \boxrepack\scratchcounter                           % natural
3053   \scratchdimenthree\boxstretch\scratchcounter                          % stretch
3054   \scratchdistance  \dimexpr\scratchdimenone-\scratchdimentwo\relax
3055   % if size - natural > stretch
3056   \unless\ifdim\scratchdistance>\scratchdimenthree
3057     % we don't stretch beyond what is acceptable
3058     \global\boxstretchfixed\conditionalfalse
3059     \global\boxstretchdelta\zeropoint
3060   \orelse\ifdim\scratchdistance>\scratchdimen
3061     % we are below the criterium
3062     \boxlimitate\scratchcounter\zerocount
3063     \global\boxstretchfixed\conditionaltrue
3064     \global\boxstretchdelta\dimexpr\ifvbox\scratchcounter\ht\else\wd\fi\scratchcounter-\boxrepack\scratchcounter\relax
3065   \else
3066     % we are above the criterium
3067     \global\boxstretchfixed\conditionalfalse
3068     \global\boxstretchdelta\zeropoint
3069   \fi
3070% \writestatus{PAGE}{stretch:#L
3071%   size \the\scratchdimenone,#L
3072%   natural \the\scratchdimentwo,#L
3073%   stretch \the\scratchdimenthree,#L
3074%   distance \the\scratchdistance,#L
3075%   criterium \the\scratchdimen,#L
3076%   fixed case
3077%    \unless\ifdim\scratchdistance>\scratchdimenthree
3078%      1:false,#L
3079%    \orelse\ifdim\scratchdistance<\scratchdimen
3080%      2:true,#L
3081%    \else
3082%      4:false,#L
3083%    \fi
3084%    delta \the\boxstretchdelta
3085% }%
3086   \endgroup}
3087
3088\protect \endinput
3089
3090% alternative
3091
3092% \newdimension\d_syst_boxes_target_size
3093% \newdimension\d_syst_boxes_natural_size
3094% \newdimension\d_syst_boxes_stretch
3095% \newdimension\d_syst_boxes_available
3096% \newdimension\d_syst_boxes_limit
3097%
3098% \permanent\protected\def\boxfixstretch
3099%   {\begingroup
3100%    \afterassignment\syst_boxes_fixstretch_a\d_syst_boxes_limit}
3101%
3102% \permanent\protected\def\syst_boxes_fixstretch_a
3103%   {\afterassignment\Xsyst_boxes_fixstretch_b\scratchcounter}
3104%
3105% \permanent\protected\def\syst_boxes_fixstretch_b
3106%   {\d_syst_boxes_target_size \ifvbox\scratchcounter\ht\else\wd\fi\scratchcounter % current size
3107%    \d_syst_boxes_natural_size\boxrepack\scratchcounter                           % natural
3108%    \d_syst_boxes_stretch     \boxstretch\scratchcounter                          % stretch
3109%    \d_syst_boxes_available   \dimexpr\d_syst_boxes_target_size-\d_syst_boxes_natural_size\relax
3110%    \ifdim\d_syst_boxes_available>\d_syst_boxes_stretch
3111%      % we don't stretch beyond what is acceptable
3112% %      \boxlimitate\scratchcounter\zerocount
3113%      \boxfinalize\scratchcounter-1000
3114% % \boxfreeze\scratchcounter1
3115%      \global\boxstretchfixed\conditionalfalse
3116%      \global\boxstretchdelta\zeropoint
3117%    \orelse\ifdim\d_syst_boxes_available>\d_syst_boxes_limit
3118%      % we are below the criterium
3119% %      \boxfinalize\scratchcounter1000
3120% \boxfreeze\scratchcounter\zerocount
3121% % \boxfreeze\scratchcounter1
3122% % \boxlimitate\scratchcounter\zerocount
3123%      \global\boxstretchfixed\conditionaltrue
3124%      \global\boxstretchdelta\dimexpr\ifvbox\scratchcounter\ht\else\wd\fi\scratchcounter-\boxrepack\scratchcounter\relax
3125%    \else
3126%      % we are above the criterium
3127%      \global\boxstretchfixed\conditionalfalse
3128%      \global\boxstretchdelta\zeropoint
3129%    \fi
3130% % \writestatus{PAGE}{%
3131% %   page      \the\realpageno,#L
3132% %   size      \the\d_syst_boxes_target_size,#L
3133% %   natural   \the\d_syst_boxes_natural_size,#L
3134% %   stretch   \the\d_syst_boxes_stretch,#L
3135% %   distance  \the\d_syst_boxes_available,#L
3136% %   criterium \the\d_syst_boxes_limit,#L
3137% %   fixed case
3138% %    \unless\ifdim\d_syst_boxes_available>\d_syst_boxes_stretch
3139% %             1:false,#L
3140% %    \orelse\ifdim\d_syst_boxes_available>\d_syst_boxes_limit
3141% %             2:true,#L
3142% %    \else
3143% %             4:false,#L
3144% %    \fi
3145% %    delta    \the\boxstretchdelta
3146% % }%
3147%    \endgroup}
3148
3149% a bit of test code:
3150
3151% \hbox \bgroup
3152%     \ruledvbox                {\hbox{\strut gans}}
3153%     \ruledvbox to \lineheight {\hbox{\strut gans}}
3154%     \ruledvbox to \lineheight {\hbox       {gans}}
3155%     \ruledvbox to \strutheight{\hbox       {gans}}
3156%     \ruledvbox to \strutheight{\hbox{\strut gans}}
3157%     \ruledvbox to \strutheight{\vss\hbox{gans}}
3158% \egroup
3159
3160% to be considered
3161
3162% \startluacode
3163%
3164%     local spacer = lpeg.patterns.spacer
3165%
3166%     function commands.withwords(command,str)
3167%         if str then
3168%             command = command or "ruledhbox"
3169%             local done = false
3170%             local function apply(s)
3171%                 if done then
3172%                     context.space()
3173%                     done = true
3174%                 else
3175%                     context.dontleavehmode()
3176%                 end
3177%                 context[command](s)
3178%             end
3179%             lpeg.match(lpeg.splitter(spacer,apply),str)
3180%         end
3181%
3182%     end
3183%
3184% \stopluacode
3185%
3186% \unprotect
3187%
3188% \protected\def\withwordsinstring#1#2% command str
3189%   {\ctxcommand{withwords(\!!bs#1\!!es,\!!bs#2\!!es)}}
3190%
3191% \protected\def\withwordsinfile#1#2% command name
3192%   {\ctxcommand{withwords(\!!bs#1\!!es,io.loaddata(resolvers.findfile("#2")))}}
3193%
3194% \protect
3195%
3196% \starttext
3197%
3198%     \defineframed[colored][foregroundcolor=red,foregroundstyle=\bfc\underbar,location=low]
3199%
3200%     \withwordsinstring{colored}{bla bla}
3201%     \withwordsinfile{colored}{ward.tex}
3202%
3203% \stoptext
3204