%D \module
%D   [       file=supp-box,
%D        version=1995.10.10,
%D          title=\CONTEXT\ Support Macros,
%D       subtitle=Boxes,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

\writestatus{loading}{ConTeXt Support Macros / Boxes}

\unprotect

\permanent\integerdef\negatelistsigncode\numexpr
    \negatexlistsigncode
   +\negateylistsigncode
\relax

%D And some dimensions:

\newdimension\strutht    % see above
\newdimension\strutdp
\newdimension\struthtdp

\newdimension\givenwidth
\newdimension\givenheight
\newdimension\givendepth

\newdimension\lastnaturalboxwd  % maybe alias !
\newdimension\lastnaturalboxht
\newdimension\lastnaturalboxdp

\pushoverloadmode
    \newuserunit\strutht   sh
    \newuserunit\strutdp   sd
    \newuserunit\struthtdp st
\popoverloadmode

\registerctxluafile{supp-box}{autosuffix}

% \fixupboxesmode\plusone % gone: is now the default

%D This module implements some box manipulation macros. Some are quite simple, some
%D are more advanced and when understood well, all can be of use.
%D
%D \macros
%D   {strutdp,strutht,strutwd}
%D
%D The next shortcuts save memory and keying. The width is normally zero points (if
%D not, you're in trouble). These shortcuts can be used like a dimension, opposite
%D to the core macros \type {\strutdepth} and alike, which are values.

\iffalse
    \def\strutdp  {\dp\strutbox}   % overloaded in spac-ver
    \def\strutht  {\ht\strutbox}   % overloaded in spac-ver
    \def\struthtdp{\htdp\strutbox} % overloaded in spac-ver
\fi

\permanent\protected\def\strutwd {\wd\strutbox}
\permanent\protected\def\strutgap{\dimexpr\strutht-\strutdp\relax}

%D \macros
%D   {voidbox,nextbox}
%D
%D Let's start with an easy one. The next macro hides the ugly \type {@} in \type
%D {\voidb@x}.

\ifdefined\voidbox \else \newbox\voidbox \fi
\ifdefined\nextbox \else \newbox\nextbox \fi

%D \macros
%D   {nextdepth}
%D
%D Let's start with a rather simple declaration. Sometimes we need to save the \TEX\
%D \DIMENSION\ \type{\prevdepth} and append it later on. The name \type {\nextdepth}
%D suits this purpose well.

\newdimension\nextdepth

%D \macros
%D   {smashbox, smashboxed, smashedbox}
%D
%D Smashing is introduced in \PLAIN\ \TEX, and stands for reducing the dimensions of
%D a box to zero. The most resolute one is presented first.

% \permanent\protected\def\smashbox#1%
%   {\wd#1\zeropoint
%    \ht#1\zeropoint
%    \dp#1\zeropoint}
%
% \permanent\protected\def\smashboxed#1%
%   {\wd#1\zeropoint
%    \ht#1\zeropoint
%    \dp#1\zeropoint
%    \box#1\relax}

%D \macros
%D   {hsmashbox,vsmashbox}
%D
%D Smashing can be used for overlaying boxes. Depending on the mode, horizontal or
%D vertical, one can use:

% \permanent\protected\def\hsmashbox#1%
%   {\wd#1\zeropoint}
%
% \permanent\protected\def\vsmashbox#1%
%   {\ht#1\zeropoint
%    \dp#1\zeropoint}

%D The next implementation is less sensitive for spurious spaces.

\newinteger\c_boxes_register

\permanent\protected\def\smashbox
  {\afterassignment\syst_boxes_smash_boxes_register\c_boxes_register}

\def\syst_boxes_smash_boxes_register
  {\wd\c_boxes_register\zeropoint
   \ht\c_boxes_register\zeropoint
   \dp\c_boxes_register\zeropoint}

\permanent\protected\def\hsmashbox
  {\afterassignment\syst_boxes_hsmashed_boxes_register\c_boxes_register}

\def\syst_boxes_hsmashed_boxes_register
  {\wd\c_boxes_register\zeropoint}

\permanent\protected\def\vsmashbox
  {\afterassignment\syst_boxes_vsmashed_boxes_register\c_boxes_register}

\def\syst_boxes_vsmashed_boxes_register
  {\ht\c_boxes_register\zeropoint
   \dp\c_boxes_register\zeropoint}

\permanent\protected\def\smashedbox
  {\afterassignment\syst_boxes_smashed_boxes_register\c_boxes_register}

\protected\def\syst_boxes_smashed_boxes_register
  {\wd\c_boxes_register\zeropoint
   \ht\c_boxes_register\zeropoint
   \dp\c_boxes_register\zeropoint
   \box\c_boxes_register}

\aliased\let\smashboxed\smashedbox

%D \macros
%D   {hsmash,vsmash,
%D    hsmashed,vsmashed}
%D
%D While the previous macros expected a \BOX, the next act on a content. They are
%D some subtle differences betreen the smash and smashed alternatives. The later
%D ones reduce all dimensions to zero.

\permanent\protected\def\hsmash  {\bgroup\dowithnextboxcs\syst_boxes_hsmashed_nextbox\hbox}
\permanent\protected\def\vsmash  {\bgroup\dowithnextboxcs\syst_boxes_vsmashed_nextbox\vbox}
\permanent\protected\def\hsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \hbox}
\permanent\protected\def\vsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \vbox}

\protected\def\syst_boxes_hsmashed_nextbox
  {\wd\nextbox\zeropoint
   \box\nextbox
   \egroup}

\protected\def\syst_boxes_vsmashed_nextbox
  {\ht\nextbox\zeropoint
   \dp\nextbox\zeropoint
   \box\nextbox
   \egroup}

\protected\def\syst_boxes_smashed_nextbox
  {\ht\nextbox\zeropoint
   \dp\nextbox\zeropoint
   \wd\nextbox\zeropoint
   \box\nextbox
   \egroup}

%D \macros
%D   {smashedhbox,smashedvbox}
%D
%D Also handy (all dimensions zeroed):
%D
%D \starttyping
%D \smashedhbox to ... {...}
%D \smashedvbox to ... {...}
%D \stoptyping

\permanent\protected\def\smashedhbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\hbox}
\permanent\protected\def\smashedvbox{\vpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\vbox}

%D \starttyping
%D \startTEXpage[offset=1dk,width=4em]
%D   \dontleavehmode \hbox    {0} 0\par
%D   \dontleavehmode \vphantom{0} 0\par
%D   \dontleavehmode \hphantom{0} 0\par
%D   $\textstyle        \vphantom{0}$ $\textstyle 0$\par
%D   $\scriptstyle      \vphantom{0}$ $\scriptstyle 0$\par
%D   $\scriptscriptstyle\vphantom{0}$ $\scriptscriptstyle 0$\par
%D \stopTEXpage
%D \stoptyping

\protected\def\syst_boxes_math_set_nextbox#1%
  {\setbox\nextbox\hbox\expandafter\bgroup
     \expandafter\Ustartmathmode\the\mathstyle
     \mathsurround\zeropoint{#1}%
     \Ustopmathmode
   \egroup}

%D \macros
%D   {smash}
%D
%D This smash alternative takes an optional arg [whdtb] as well as is potentially
%D catcode safer. It is needed by the math module (although the \type {\leavevmode}
%D is not added here).

\permanent\protected\def\smash
  {\begingroup
   \futureexpandis[\syst_boxes_smash_yes\syst_boxes_smash_nop}

\lettonothing\m_boxes_smash_options

\def\syst_boxes_smash_nop
  {\edef\m_boxes_smash_options{hd}%
   \futurelet\nexttoken\syst_boxes_smash_indeed}

\def\syst_boxes_smash_yes[#1]%
  {\edef\m_boxes_smash_options{#1}%
   \futurelet\nexttoken\syst_boxes_smash_indeed}

\def\syst_boxes_smash_indeed
  {\ifmmode
     \expandafter\syst_boxes_smash_math
   \orelse\ifx\nexttoken\bgroup
     \expandafter\syst_boxes_smash_hbox
   \else
     \expandafter\syst_boxes_smash_text
   \fi}

\def\syst_boxes_smash_math#1%
  {\syst_boxes_math_set_nextbox{#1}%
   \syst_boxes_smash_process}

\def\syst_boxes_smash_hbox
  {\dowithnextboxcs\syst_boxes_smash_process\hbox}

\def\syst_boxes_smash_text#1%
  {\setbox\nextbox\hbox{#1}%
   \syst_boxes_smash_process}

\def\syst_boxes_smash_process
  {\expandafter\syst_boxes_smash_process_option\m_boxes_smash_options\relax
   \box\nextbox
   \endgroup}

\installcorenamespace {smashoptions}

\defcsname\??smashoptions   w\endcsname{\wd\nextbox\zeropoint}
\defcsname\??smashoptions   h\endcsname{\ht\nextbox\zeropoint}
\defcsname\??smashoptions   d\endcsname{\dp\nextbox\zeropoint}
\defcsname\??smashoptions   t\endcsname{\ht\nextbox\zeropoint}
\defcsname\??smashoptions   b\endcsname{\dp\nextbox\zeropoint}
\defcsname\??smashoptions  hd\endcsname{\ht\nextbox\zeropoint\dp\nextbox\zeropoint}
\defcsname\??smashoptions whd\endcsname{\wd\nextbox\zeropoint\ht\nextbox\zeropoint\dp\nextbox\zeropoint}

\def\syst_boxes_smash_process_option#1%
  {\ifx#1\relax\else
     \begincsname\??smashoptions#1\endcsname
     \expandafter\syst_boxes_smash_process_option
   \fi}

\def\syst_boxes_lower_nextbox_dp
  {\setbox\nextbox\hpack{\lower\dp\nextbox\box\nextbox}}

%D \starttabulate[|l|l|]
%D \NC w   \NC \ruledhbox{\smash  [w]{This is some great smashing, isn't it?}} \NC \NR
%D \NC h   \NC \ruledhbox{\smash  [h]{This is some great smashing, isn't it?}} \NC \NR
%D \NC d   \NC \ruledhbox{\smash  [d]{This is some great smashing, isn't it?}} \NC \NR
%D \NC tb  \NC \ruledhbox{\smash [tb]{This is some great smashing, isn't it?}} \NC \NR
%D \NC whd \NC \ruledhbox{\smash[whd]{This is some great smashing, isn't it?}} \NC \NR
%D \stoptabulate

%D \macros
%D   {phantom, hphantom, vphantom, mathstrut}
%D
%D The next implementation of \type {\phantom} cum suis does not grab an argument in
%D the non||math case, which is better.
%D
%D Due to a complicated call to \type {\mathpallete} and thereby \type
%D {\mathchoice}, the next macro looks ugly. We also take care of non||braced
%D arguments.

\permanent\protected\def\phantom {\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed  }
\permanent\protected\def\vphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_v}
\permanent\protected\def\hphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_h}

\def\syst_boxes_phantom_math  #1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make  }
\def\syst_boxes_phantom_math_v#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_v}
\def\syst_boxes_phantom_math_h#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_h}

\def\syst_boxes_phantom_hbox  {\dowithnextboxcs\syst_boxes_phantom_make  \hbox} % always hbox
\def\syst_boxes_phantom_hbox_v{\dowithnextboxcs\syst_boxes_phantom_make_v\hbox} % always hbox
\def\syst_boxes_phantom_hbox_h{\dowithnextboxcs\syst_boxes_phantom_make_h\hbox} % always hbox

\def\syst_boxes_phantom_text  #1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make  } % always hbox
\def\syst_boxes_phantom_text_v#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_v} % always hbox
\def\syst_boxes_phantom_text_h#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_h} % always hbox

\def\syst_boxes_phantom_indeed
  {\ifmmode
     \expandafter\syst_boxes_phantom_math
   \orelse\ifx\nexttoken\bgroup
     \expandafter\syst_boxes_phantom_hbox
   \else
     \expandafter\syst_boxes_phantom_text
   \fi}

\def\syst_boxes_phantom_indeed_v
  {\ifmmode
     \expandafter\syst_boxes_phantom_math_v
   \orelse\ifx\nexttoken\bgroup
     \expandafter\syst_boxes_phantom_hbox_v
   \else
     \expandafter\syst_boxes_phantom_text_v
   \fi}

\def\syst_boxes_phantom_indeed_h
  {\ifmmode
     \expandafter\syst_boxes_phantom_math_h
   \orelse\ifx\nexttoken\bgroup
     \expandafter\syst_boxes_phantom_hbox_h
   \else
     \expandafter\syst_boxes_phantom_text_h
   \fi}

\def\syst_boxes_phantom_make
  {\setbox\scratchbox\emptyhbox
   \ht\scratchbox\ht\nextbox
   \dp\scratchbox\dp\nextbox
   \wd\scratchbox\wd\nextbox
   \box\scratchbox
   \endgroup}

\def\syst_boxes_phantom_make_v
  {\setbox\scratchbox\emptyhbox
   \ht\scratchbox\ht\nextbox
   \dp\scratchbox\dp\nextbox
   \box\scratchbox
   \endgroup}

\def\syst_boxes_phantom_make_h
  {\setbox\scratchbox\emptyhbox
   \wd\scratchbox\wd\nextbox
   \box\scratchbox
   \endgroup}

%D We also define plain's \type {\mathstrut}. It will be replaced in \typ {math-ini}.

\permanent\protected\def\mathstrut{\mathstack{\vphantom(}} % can be made faster by inlining

%D \macros
%D   {getboxheight}
%D
%D Although often needed, \TEX\ does not support arithmics like:
%D
%D \starttyping
%D \dimen0 = \ht0 + \dp0
%D \stoptyping
%D
%D so we implemented:
%D
%D \starttyping
%D \getboxheight ... \of \box...
%D \stoptyping
%D
%D For instance,
%D
%D \starttyping
%D \getboxheight \dimen0 \of \box0
%D \getboxheight \someheight \of \box \tempbox
%D \stoptyping
%D
%D The implementation is rather stupid:
%D
%D \starttyping
%D \def\getboxheight#1\of#2\box#3%
%D   {#1\ht#3\advanceby#1\dp#3\relax}
%D \stoptyping
%D
%D The next alternative is slightly more clever, since it accepts \type {{12}} as
%D well as \type {12} as box number.

\permanent\protected\def\getboxheight#1\of#2\box#3%
  {\def\next{#1\htdp\c_boxes_register}%
   \afterassignment\next\c_boxes_register=#3}

%D For a long time the following three macros were part of the grid snapping core
%D module, but it makes more sense to have them here so that users can see them.
%D
%D \macros
%D   {getnoflines, getroundednoflines, getrawnoflines}
%D
%D Het commando \type {\getnoflines} converteert een hoogte (dimensie) in een aantal
%D regels en kent dit toe aan \type {\noflines}.
%D
%D \starttyping
%D \getnoflines{dimension}
%D \stoptyping
%D
%D Er wordt gedeeld door \type {\openlineheight} en een hoogte van~0pt komt overeen
%D met 0~regels. The raw alternative does not round. See the \MKII\ and \MKIV\ files
%D for historic variants.

\ifdefined\roundingeps \else \newdimension\roundingeps \roundingeps=10sp \fi

\newinteger  \noflines
\newdimension\noflinesheight

\permanent\protected\def\getnoflines#1%
  {\noflinesheight{#1}%
   \ifzeropt\noflinesheight
     \noflines\zerocount
   \orelse\ifdim\noflinesheight>\zeropoint
     \advanceby\noflinesheight-\roundingeps
     \divideby\noflinesheight\openlineheight
     \noflines\noflinesheight
     \advanceby\noflines\plusone
   \else
     \advanceby\noflinesheight\roundingeps
     \divideby\noflinesheight\openlineheight
     \noflines\noflinesheight
     \advanceby\noflines\minusone
   \fi}

\permanent\protected\def\getroundednoflines#1%
  {\noflinesheight{#1}%
   \ifzeropt\noflinesheight
     \noflines\zerocount
   \orelse\ifdim\noflinesheight>\zeropoint
     \advanceby\noflinesheight\roundingeps
     \divideby\noflinesheight\openlineheight
     \noflines\noflinesheight
   \else
     \advanceby\noflinesheight-\roundingeps % what does this mean, negative \noflines
     \divideby\noflinesheight\openlineheight
     \noflines\noflinesheight
   \fi}

\permanent\protected\def\getrawnoflines#1%
  {\noflinesheight{#1}%
   \ifzeropt\noflinesheight
     \noflines\zerocount
   \orelse\ifdim\noflinesheight>\zeropoint
     \advanceby\noflinesheight\roundingeps
     \advanceby\noflinesheight.5\openlineheight
     \divideby\noflinesheight\openlineheight
     \noflines\noflinesheight
   \else
     \advanceby\noflinesheight-\roundingeps
     \advanceby\noflinesheight-.5\openlineheight
     \divideby\noflinesheight\openlineheight
     \noflines\noflinesheight
   \fi}

%D Let's proof that it works:
%D
%D \startbuffer
%D \scratchdimen\dimexpr(3pt)               \getnoflines\scratchdimen  1=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10\lineheight)     \getnoflines\scratchdimen 10=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10.1\lineheight)   \getnoflines\scratchdimen 11=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10.5\lineheight)   \getnoflines\scratchdimen 11=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10.9\lineheight)   \getnoflines\scratchdimen 11=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10\lineheight+3pt) \getnoflines\scratchdimen 11=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10\lineheight+3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10\lineheight-3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf
%D
%D \scratchdimen\dimexpr(3pt)               \getrawnoflines\scratchdimen  0=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10\lineheight)     \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10.1\lineheight)   \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10.5\lineheight)   \getrawnoflines\scratchdimen 11=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10.9\lineheight)   \getrawnoflines\scratchdimen 11=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10\lineheight+3pt) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10\lineheight+3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
%D \scratchdimen\dimexpr(10\lineheight-3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
%D \stopbuffer
%D
%D \typebuffer \getbuffer

%D \macros
%D   {determinenoflines}
%D
%D The next macro determines the number of lines and returns it it \type
%D {\noflines}. The macro works reasonable well as long as the content can be
%D unboxed.
%D
%D \starttyping
%D \determinenoflines{test\\test}
%D \determinenoflines{\bfd test\\test}
%D \determinenoflines{\definedfont[Sans at 40pt]test\\test}
%D \stoptyping

% \def\syst_boxes_determine_noflines % can be mkiv'd
%   {\beginofshapebox
%      \unvbox\nextbox
%    \endofshapebox
%    \globalscratchcounter\zerocount
%    \reshapebox{\global\advanceby\globalscratchcounter\plusone}%
%    \expandafter\egroup\expandafter\noflines\the\globalscratchcounter\relax}

\def\syst_boxes_determine_noflines
  {\expandafter\egroup\expandafter\noflines\noflinesinbox\nextbox\relax}

\permanent\protected\def\determinenoflines
  {\bgroup
   \forgetall
   \enforced\let\crlf\endgraf
   \enforced\let\\\endgraf
   \dowithnextboxcs\syst_boxes_determine_noflines\vbox}

\def\determinednoflines#1%
  {\localcontrolled{\determinenoflines{#1}}\noflines}

%D \macros
%D   {doiftextelse, doiftext}
%D
%D When \type {\doifelse} cum suis hopelessly fail, for instance because we pass
%D data, we can fall back on the next macro:
%D
%D \starttyping
%D \doiftextelse {data} {then branch} {else branch}
%D \doiftext     {data} {then branch}
%D \stoptyping

% performance:
%
% \ifcondition\validtext {...}T\else F\fi   4.47
% \doifelsetext          {...}{T}{F}        4.91
% \iftext                {...}T\else F\fi   5.01
%
% \ifcondition\validtext {}T\else F\fi      0.22
% \doifelsetext          {}{T}{F}           1.02
% \iftext                {}T\else F\fi      0.39

\permanent\protected\def\doifelsetext#1%
  {\begingroup
   \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
     {\settrialtypesetting
      \ignorespaces#1\removeunwantedspaces}%
   \ifzeropt\wd\scratchbox
     \endgroup\expandafter\secondoftwoarguments
   \else
     \endgroup\expandafter\firstoftwoarguments
   \fi}

\permanent\protected\def\doiftext#1%
  {\begingroup
   \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
     {\settrialtypesetting
      \ignorespaces#1\removeunwantedspaces}%
   \ifzeropt\wd\scratchbox
     \endgroup\expandafter\gobbleoneargument
   \else
     \endgroup\expandafter\firstofoneargument
   \fi}

\permanent\protected\def\validtext#1%
  {\ifparameter#1\or
     \begingroup
     \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
       {\settrialtypesetting
        \ignorespaces#1\removeunwantedspaces}%
     \expanded{\endgroup\noexpand\expandafter\ifzeropt\wd\scratchbox\if_false\else\if_true\fi}%
   \else
     \expandafter\if_false
   \fi}

% \iftext{xx}     YES\else NOP\fi
% \iftext{}       YES\else NOP\fi
% \iftext{\strut} YES\else NOP\fi
% \iftext{ }      YES\else NOP\fi

% more efficient but maybe fragile: \nospacing#1

\aliased\let\doiftextelse\doifelsetext

%D \macros
%D   {dowithnextbox,nextbox}
%D
%D Sometimes we want a macro to grab a box and do something on the content. One
%D could pass an argument to a box, but this can violate the specific \CATCODES\ of
%D its content and leads to unexpected results. The next macro treats the following
%D braced text as the content of a box and manipulates it afterwards in a predefined
%D way.
%D
%D The first argument specifies what to do with the content. This content is
%D available in \type {\nextbox}. The second argument is one of \type {\hbox}, \type
%D {\vbox} or \type {\vtop}. The third argument must be grouped with \type {\bgroup}
%D and \type {\egroup}, \type {{...}} or can be a \type {\box} specification.
%D
%D In \CONTEXT\ this macro is used for picking up a box and treating it according to
%D earlier specifications. We use for instance something like:
%D
%D \starttyping
%D \def\getfloat%
%D   {\def\handlefloat{...\box\nextbox...}
%D    \dowithnextboxcs\handlefloat\vbox}
%D \stoptyping
%D
%D instead of:
%D
%D \starttyping
%D \def\getfloat#1%
%D   {...#1...}
%D \stoptyping
%D
%D In this implementation the \type {\aftergroup} construction is needed because
%D \type {\afterassignment} is executed inside the box.

\let\syst_boxes_with_next_box\relax

\permanent\protected\def\dowithnextbox#1%
  {\def\syst_boxes_with_next_box{#1}%
   \afterassignment\syst_boxes_with_next_box_indeed
   \setbox\nextbox}

\def\syst_boxes_with_next_box_indeed
  {\aftergroup\syst_boxes_with_next_box}

\permanent\protected\def\dowithnextboxcs#1%
  {\let\syst_boxes_with_next_box#1%
   \afterassignment\syst_boxes_with_next_box_indeed
   \setbox\nextbox}

%D So in fact we get:
%D
%D \starttyping
%D \setbox\nextbox { \aftergroup\syst_boxes_with_next_box ... }
%D \stoptyping
%D
%D or
%D
%D \starttyping
%D \setbox\nextbox { ... } \syst_boxes_with_next_box
%D \stoptyping
%D
%D A slower but more versatile implementation is:
%D
%D \starttyping
%D \protected\def\dowithnextbox#1#2%
%D   {\def\syst_boxes_with_next_box{#1}%
%D    \ifx#2\hbox
%D      \afterassignment\syst_boxes_with_next_box_indeed
%D    \orelse\ifx#2\vbox
%D      \afterassignment\syst_boxes_with_next_box_indeed
%D    \orelse\ifx#2\vtop
%D      \afterassignment\syst_boxes_with_next_box_indeed
%D    \orelse\ifx#2\normalvcenter
%D      \afterassignment\syst_boxes_with_next_box_indeed
%D    \else
%D      \afterassignment\syst_boxes_with_next_box
%D    \fi
%D    \setbox\nextbox#2}
%D \stoptyping
%D
%D This alternative also accepts \type {\box0} and alike, but we don't really need
%D this functionality now.

%D \macros
%D   {nextboxht,nextboxwd,nextboxdp,flushnextbox}
%D
%D The next couple of shortcuts saves us memory as well as \type {{}}'s in passing
%D parameters.

\permanent\def\nextboxht  {\ht\nextbox}
\permanent\def\nextboxwd  {\wd\nextbox}
\permanent\def\nextboxdp  {\dp\nextbox}
\permanent\def\nextboxhtdp{\htdp\nextbox}

\permanent\protected\def\flushnextbox{\box\nextbox}

%D \macros
%D   {dowithnextboxcontent}
%D
%D But, occasionally we do need to pass some local settings without wanting to use
%D additional grouping. Therefore we provide:
%D
%D \starttyping
%D \dowithnextboxcontent{inside}{after}{box content}
%D \stoptyping
%D
%D {\em todo: Search source for potential usage!}

% \protected\def\dowithnextboxcontent#1#2% inside, after
%   {\def\syst_boxes_with_next_box_one{#2}%
%    \def\syst_boxes_with_next_box_two{#1}%
%    \afterassignment\syst_boxes_with_next_box_content_indeed
%    \setbox\nextbox}
%
% \protected\def\dowithnextboxcontentcs#1#2% inside, after
%   {\let\syst_boxes_with_next_box_one#2%
%    \let\syst_boxes_with_next_box_two#1%
%    \afterassignment\syst_boxes_with_next_box_content_indeed
%    \setbox\nextbox}
%
% \def\syst_boxes_with_next_box_content_indeed
%   {\syst_boxes_with_next_box_two\aftergroup\syst_boxes_with_next_box_one}

\permanent\protected\def\dowithnextboxcontent#1#2% inside, after
  {\afterassigned{#1\aftergrouped{#2}}%
   \setbox\nextbox}

\permanent\protected\def\dowithnextboxcontentcs#1#2% inside, after
  {\afterassigned{#1\aftergroup#2}%
   \setbox\nextbox}

%D \macros
%D   {llap, rlap, tlap, blap, clap}
%D
%D Some well known friends, but we implement them our own way. We want the macros to
%D work in both math and text mode.

\def\syst_boxes_do_rlap{\hpack to \zeropoint{\box\nextbox\hss}\endgroup}
\def\syst_boxes_do_llap{\hpack to \zeropoint{\hss\box\nextbox}\endgroup}
\def\syst_boxes_do_clap{\hpack to \zeropoint{\hss\box\nextbox\hss}\endgroup}
\def\syst_boxes_do_tlap{\vpack to \zeropoint{\vss\box\nextbox}\endgroup}
\def\syst_boxes_do_blap{\vpack to \zeropoint{\box\nextbox\vss}\endgroup}

\protected\def\syst_boxes_rlap{\begingroup\dowithnextboxcs\syst_boxes_do_rlap\hbox}
\protected\def\syst_boxes_llap{\begingroup\dowithnextboxcs\syst_boxes_do_llap\hbox}
\protected\def\syst_boxes_clap{\begingroup\dowithnextboxcs\syst_boxes_do_clap\hbox}

% \def\syst_boxes_do_math_clap#1#2{\syst_boxes_clap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
% \def\syst_boxes_do_math_llap#1#2{\syst_boxes_llap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
% \def\syst_boxes_do_math_rlap#1#2{\syst_boxes_rlap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
%
% \def\syst_boxes_math_clap{\mathpalette\syst_boxes_do_math_clap}
% \def\syst_boxes_math_llap{\mathpalette\syst_boxes_do_math_llap}
% \def\syst_boxes_math_rlap{\mathpalette\syst_boxes_do_math_rlap}

\def\syst_boxes_math_xlap#1#2%
  {\expanded{#1\bgroup\normalstartimath\givenmathstyle\the\mathstyle}%
 %{\expandafter#1\expandafter\bgroup\expandafter\normalstartimath\expandafter\givenmathstyle\the\mathstyle
     \mathsurround\zeropoint#2%
   \normalstopimath\egroup}

\def\syst_boxes_math_clap{\syst_boxes_math_xlap\syst_boxes_clap}
\def\syst_boxes_math_llap{\syst_boxes_math_xlap\syst_boxes_llap}
\def\syst_boxes_math_rlap{\syst_boxes_math_xlap\syst_boxes_rlap}

\permanent\protected\def\rlap{\mathortext\syst_boxes_math_rlap\syst_boxes_rlap}
\permanent\protected\def\llap{\mathortext\syst_boxes_math_llap\syst_boxes_llap}
\permanent\protected\def\clap{\mathortext\syst_boxes_math_clap\syst_boxes_clap}

\permanent\protected\def\tlap{\begingroup\dowithnextboxcs\syst_boxes_do_tlap\vbox}
\permanent\protected\def\blap{\begingroup\dowithnextboxcs\syst_boxes_do_blap\vbox}

%D in \LMTX\ this mechanism is obsolete! Use boxlines instead!

%D \macros
%D   {beginofshapebox,
%D    reshapebox, doreshapebox,
%D    flushshapebox,
%D    innerflushshapebox,
%D    shapebox,
%D    ifreshapingbox}
%D
%D The next utility macro originates from some linenumbering mechanism. Due to
%D \TEX's advanced way of typesetting paragraphs, it's not easy to do things on a
%D line||by||line basis. This macro is able to reprocess a given box and can act
%D upon its vertical boxed components, such as lines. The unwinding sequence in this
%D macro is inspired by a \NTG\ workshop of David Salomon in June 1992.
%D
%D First we have to grab the piece of text we want to act upon. This is done by
%D means of the duo macros:
%D
%D \starttyping
%D \beginofshapebox
%D a piece of text
%D \endofshapebox
%D \stoptyping
%D
%D When all texts is collected, we can call \type {\reshapebox} and do something
%D with it's vertical components. We can make as much passes as needed. When we're
%D done, the box can be unloaded with \type {\flushshapebox}. The only condition in
%D this scheme is that \type {\reshapebox} must somehow unload the \BOX\ \type
%D {\shapebox}.
%D
%D An important aspect is that the content is unrolled bottom||up. The next example
%D illustrates this maybe unexpected characteristic.
%D
%D \startbuffer
%D \beginofshapebox
%D \em \input tufte
%D \endofshapebox
%D
%D \newcounter\LineNumber
%D
%D \reshapebox
%D   {\doglobal\increment\LineNumber
%D    \hbox{\llap{\LineNumber\hskip2em}\box\shapebox}}
%D
%D \flushshapebox
%D \stopbuffer
%D
%D \typebuffer
%D
%D \getbuffer
%D
%D As we can see, when some kind of numbering is done, we have to add a second pass.
%D
%D \startbuffer
%D \newcounter\LineNumber
%D \newcounter\NumberOfLines
%D
%D \reshapebox
%D   {\doglobal\increment\NumberOfLines
%D    \box\shapebox}
%D
%D \reshapebox
%D   {\doglobal\increment\LineNumber
%D    \hbox
%D      {\llap{\LineNumber\ (\NumberOfLines)\hskip2em}%
%D       \box\shapebox}%
%D    \doglobal\decrement\NumberOfLines}
%D
%D \flushshapebox
%D \stopbuffer
%D
%D \typebuffer
%D
%D \getbuffer
%D
%D This example shows that the content of the box is still available after flushing.
%D Another feature is that only the last reshaping counts. Multiple reshaping can be
%D done by:
%D
%D \startbuffer
%D \beginofshapebox
%D \flushshapebox
%D \endofshapebox
%D
%D \reshapebox
%D   {\doglobal\increment\LineNumber
%D    \hbox{\llap{$\star$\hskip1em}\box\shapebox}%
%D    \doglobal\decrement\NumberOfLines}
%D
%D \flushshapebox
%D \stopbuffer
%D
%D \typebuffer
%D
%D \getbuffer
%D
%D The macros are surprisingly easy to follow and in fact introduce no new concepts.
%D Nearly all books on \TEX\ show similar solutions for unwinding \BOXES.
%D
%D Some macros, like footnote ones, can be sensitive for reshaping, which can result
%D in an endless loop. We therefore offer:
%D
%D \starttyping
%D \ifreshapingbox
%D \stoptyping
%D
%D Some \CONTEXT\ commands are protected this way. Anyhow, reshaping is aborted
%D after 100 dead cycles.
%D
%D By the way, changing the height and depth of \BOX\ \type {\shapebox} results in
%D bad spacing. This means that for instance linenumbers etc. should be given zero
%D height and depth before being lapped into the margin. The previous examples
%D ignore this side effect, but beware!
%D
%D This is ancient stuff and proably not used any more but we keep it around or
%D maybe turn it into a module some day. It shows the kind of struggling that we
%D needed before \LUATEX\ came around.

\newif    \ifsomeshapeleft
\newif    \ifreshapingbox
\newif    \ifreshapingfailed % may save redundant runs

\newbox      \shapebox
\newinteger  \shapepenalty
\newdimension\shapekern
\newgluespec \shapeskip
\newbox      \newshapebox
\newbox      \oldshapebox
\newbox      \tmpshapebox
\newinteger  \shapecounter
\newevery    \everyshapebox \relax

\permanent\dimensiondef\shapesignal.12345678pt % or 12345sp

\permanent\protected\def\reshapebox#1%
  {\doreshapebox
     {#1}%
     {\penalty\shapepenalty}%
     {\kern   \shapekern   }%
     {\vskip  \shapeskip   }}

\permanent\protected\def\doreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
  {\global\reshapingfailedfalse
   \ifzeropt\ht\oldshapebox
     \setbox\newshapebox\emptyvbox
   \else
     \setbox\newshapebox\vbox % can be \vpack
       {\unvcopy\oldshapebox
        \setbox\newshapebox\emptybox
        \shapecounter\zerocount
        \doloop{\dodoreshapebox{#1}{#2}{#3}{#4}}}%
     \setbox\newshapebox\box\tmpshapebox
   \fi}

% We will turn this into a \MKIV\ variant (we can use \type {\vpack} too).

\permanent\protected\def\insertshapesignal
  {\hpack to \shapesignal{\strut\hss}% plus \strut
   \prevdepth\strutdp} % never \nointerlineskip

\permanent\protected\def\restoreshapebox % compensates for the signal
  {\global\setbox\tmpshapebox\vbox{\vskip-\lineheight\unvcopy\oldshapebox}}

\permanent\def\dodoreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
  {\ifnum\lastnodetype=\gluenodecode
     \shapeskip\lastskip
     \global\setbox\tmpshapebox\vbox{#4\unvbox\tmpshapebox}%
     \unskip
   \orelse\ifnum\lastnodetype=\kernnodecode
     \shapekern\lastkern
     \global\setbox\tmpshapebox\vbox{#3\unvbox\tmpshapebox}%
     \unkern
   \orelse\ifnum\lastnodetype=\penaltynodecode
     \shapepenalty\lastpenalty
     \global\setbox\tmpshapebox\vbox{#2\unvbox\tmpshapebox}%
     \unpenalty
   \orelse\ifnum\lastnodetype<\zeropoint
     \exitloop
   \else
     \setbox\shapebox\lastbox
     \ifvoid\shapebox
     \orelse\ifdim\wd\shapebox=\shapesignal\relax
       \exitloop
     \else
       \shapecounter\zerocount
       \global\setbox\tmpshapebox\vbox{#1\unvbox\tmpshapebox}%
     \fi
   \fi
   \ifnum\shapecounter>100 % can be less
     \global\reshapingfailedtrue
     \message{!!forced exit from shapebox \the\lastnodetype !!}%
     \restoreshapebox
     \exitloop
   \else
     \advanceby\shapecounter \plusone
   \fi}

\permanent\protected\def\beginofshapebox
  {\setbox\oldshapebox\vbox
     \bgroup
     \reshapingboxtrue
     \expand\everyshapebox
     \insertshapesignal}

\permanent\protected\def\endofshapebox
  {\endgraf
   \egroup}

\aliased\let\beginshapebox\beginofshapebox
\aliased\let\endshapebox  \endofshapebox

\permanent\protected\def\flushshapebox
  {\bgroup
   \ifzeropt\ht\newshapebox
   \else
     % make \prevdepth legal
     % \par before the next \vskip gives far worse results
     \ifdim\parskip>\zeropoint\vskip\parskip\else\par\fi
     % and take a look
     \ifdim\prevdepth=-\thousandpoint % or <=
       \prevdepth\zeropoint
     \fi
     \ifdim\prevdepth<\zeropoint\relax
       % something like a line or a signal or ...
       \donetrue
     \orelse\ifinner
       % not watertight and not ok
       \donefalse
     \orelse\ifdim\pagegoal=\maxdimen
       \donetrue
     \else
       % give the previous line a normal depth
       \donetrue
       {\forgeteverypar\verticalstrut}\nobreak
       \kern-\struttotal % geen \vskip
       \kern-\parskip
     % \vskip-\strutdp
     \fi
     \scratchdimen\dp\newshapebox
     \unvbox\newshapebox
     % \prevdepth=0pt and \dp\newshapebox depend on last line
     \kern-\scratchdimen % ??
     % now \prevdepth=0pt
     \ifdone
       \kern\strutdp
       \prevdepth\strutdp
     \fi
   \fi
   \egroup}

%D In real inner situations we can use:
%D
%D \starttyping
%D \flushinnershapebox
%D \stoptyping
%D
%D This one is used in \type{\framed}.

% The kern fails on for instance:
%
% \omlijnd[offset=0pt,hoogte=8mm,uitlijnen={rechts,laho}]{\bfa test}

\permanent\protected\def\innerflushshapebox
  {\ifzeropt\ht\newshapebox \else
     \unvcopy\newshapebox\relax % unvcopy ! else spacing problem
   % \kern-\dp\newshapebox\relax
   \fi}

%D For absolute control, one can use \type {\doreshapebox} directly. This macro
%D takes four arguments, that take care of:
%D
%D \startitemize[n,packed]
%D \item \type{\shapebox}
%D \item \type{\shapepenalty}
%D \item \type{\shapekern}
%D \item \type{\shapeskip}
%D \stopitemize

%D \macros
%D   {shapedhbox}
%D
%D When constructing a new box, using the content of \type {\shapebox}, one can best
%D use \type {\shapedhbox} instead of \type {\hbox}, since it manages the height and
%D depth of the line.

\permanent\protected\def\shapedhbox % lines with non strutted dimensions have
  {\expanded{\dowithnextbox         % interlineskip so if we want the original
     {\ht\nextbox\the\ht\shapebox   % spacing, we need to preserve the original
      \dp\nextbox\the\dp\shapebox   % height and depth which is definitely
      \box\nextbox}}                % needed if we apply struts to the 'new'
   \hbox}                           % box or do something that changed ist size

%D Till here obsolete.

%D \macros
%D   {hyphenatedword,
%D    hyphenatedpar,
%D    hyphenatedfile,
%D    dohyphenateword}
%D
%D We no longer use the pure \TEX\ variant. In due time we will report some more
%D advanced statistics.
%D
%D \starttyping
%D \showhyphens{dohyphenatedword}
%D \stoptyping

\permanent\protected\def\doshowhyphenatednextbox
  {\clf_showhyphenatedinlist\nextbox}

\permanent\protected\def\showhyphens % hpack: so no processing (we hyphenate in lua)
  {\dowithnextboxcs\doshowhyphenatednextbox\hpack}

%D The following macros are seldom used but handy for tracing.
%D
%D \starttyping
%D \hyphenatedword{dohyphenatedword}
%D \hyphenatedpar {\dorecurse{10}{dohyphenatedword }}
%D \hyphenatedfile{tufte}
%D \stoptyping

\def\syst_boxes_hyphenatednextbox     {\clf_hyphenatedlist\nextbox false\relax\unhbox\nextbox}
\def\syst_boxes_hyphenatednextboxcolor{\clf_hyphenatedlist\nextbox true \relax\unhbox\nextbox}

\permanent\protected\def\hyphenatedword       {\dowithnextboxcs\syst_boxes_hyphenatednextbox\hbox}
\permanent\protected\def\hyphenatedpar        {\dowithnextboxcs\syst_boxes_hyphenatednextbox\hbox}
\permanent\protected\def\hyphenatedfile     #1{\dowithnextboxcs\syst_boxes_hyphenatednextbox\hbox{\readfile{#1}\donothing\donothing}}
\permanent\protected\def\hyphenatedcoloredword{\dowithnextboxcs\syst_boxes_hyphenatednextboxcolor\hbox}

%D \macros
%D   {processtokens}
%D
%D We fully agree with (most) typographers that inter||letter spacing is only
%D permitted in fancy titles, we provide a macro that can be used to do so. Because
%D this is (definitely and fortunately) no feature of \TEX, we have to step through
%D the token list ourselves.
%D
%D \starttyping
%D \processtokens {before} {between} {after} {space} {tokens}
%D \stoptyping
%D
%D An example of a call is:
%D
%D \startbuffer
%D \processtokens {[} {+} {]} {\space} {hello world}
%D \stopbuffer
%D
%D \typebuffer
%D
%D This results in:
%D
%D \getbuffer
%D
%D The list of tokens may contain spaces, while \type {\\}, \type {{}} and \type {\
%D } are handled as space too.

%D This can be done in a more modern way but for nostalgic reasons we keep it.

\mutable\lettonothing\nextprocessedtoken

\mutable\let\before \relax % for now mutable
%mutable\let\between\relax % is a math character
\mutable\let\after  \relax % for now mutable
\mutable\let\white  \relax % for now mutable

\lettonothing\m_syst_boxes_before

\permanent\protected\def\processtokens#1#2#3#4#5%
  {\begingroup
   \enforced\permanent\def\space{ }%
   \enforced\let\\\space
   \enforced\def\before {#1}%
   \enforced\def\between{#2}%
   \enforced\def\after  {#3}%
   \enforced\def\white  {#4}%
   \enforced\let\m_syst_boxes_before\before
   \syst_boxes_processtokens#5\s!e_o_t_token
   \endgroup}

\def\syst_boxes_processtokens% the space after = is essential
  {\afterassignment\syst_boxes_do_processtokens\let\nextprocessedtoken= }

\def\syst_boxes_redo_processedtoken
  {\dowithnextbox
     {\before{\copy\nextbox}% \before can use nextbox several times
      \enforced\let\before\between
      \syst_boxes_processtokens}
      \hbox\bgroup}

\def\syst_boxes_do_processtokens
  {\ifx\nextprocessedtoken\s!e_o_t_token
     \after
   \orelse\ifx\nextprocessedtoken\bgroup
     \expandafter\syst_boxes_redo_processedtoken
   \else
     \expandafter\if\space\nextprocessedtoken
       \after\white
       \enforced\let\before\m_syst_boxes_before
     \else
       \before\nextprocessedtoken
       \enforced\let\before\between
     \fi
     \expandafter\syst_boxes_processtokens
   \fi}

%D \macros
%D   {doboundtext}
%D
%D Sometimes there is not enough room to show the complete (line of) text. In such a
%D situation we can strip of some characters by using \type {\doboundtext}. When the
%D text is wider than the given width, it's split and the third argument is
%D appended. When the text to be checked is packed in a command, we'll have to use
%D \type {\expandafter}.
%D
%D \starttyping
%D \doboundtext{a very, probably to long, text}{3cm}{...}
%D \stoptyping
%D
%D When calculating the room needed, we take the width of the third argument into
%D account, which leads to a bit more complex macro than needed at first sight.
%D
%D Sort of obsolete I guess:

\def\syst_boxes_boundtext#1%
  {\setbox\scratchboxone\hbox{#1}%
   \advanceby\scratchdimen -\wd\scratchboxone
   \ifdim\scratchdimen>\zeropoint\relax#1\fi}

\permanent\protected\def\doboundtext#1#2#3% still used?
  {\hbox
     {\setbox\scratchbox\hbox{#1}%
      \scratchdimen{#2}%
      \ifdim\wd\scratchbox>\scratchdimen
        \setbox\scratchbox\hbox{#3}%
        \advanceby\scratchdimen -\wd\scratchbox
        \handletokens#1\with\syst_boxes_boundtext
      \fi
      \box\scratchbox}}

%D \macros
%D   {limitatetext}
%D
%D A bit more beautiful alternative for the previous command is the next one. This
%D command is more robust because we let \TEX\ do most of the job. The previous
%D command works better on text that cannot be hyphenated.
%D
%D \starttyping
%D \limitatetext {text}  {width} {sentinel}
%D \limitatetext {text} {-width} {prelude}
%D \stoptyping
%D
%D When no width is given, the whole text comes available. The sentinel is optional.
%D This is about the third version.

\ifdefined\fakecompoundhyphen\else \let\fakecompoundhyphen\relax      \fi
\ifdefined\veryraggedright   \else \def\veryraggedright{\raggedright} \fi

%D See \MKIV\ file for the older implementation.

\lettonothing\m_syst_boxes_left
\lettonothing\m_syst_boxes_right

\permanent\protected\def\limitatetext#1#2#3%
  {% we could also split in \LUA
   \splitatcomma{#2}\m_syst_boxes_left\m_syst_boxes_right
   \limitated
  \ifchkdimension\m_syst_boxes_left\or
      left    \lastchkdimension
  \fi
  \ifchkdimension\m_syst_boxes_right\or
      right    \lastchkdimension
  \fi
      strip    true
      sentinel {#3}
      text     {#1}
   \relax}

%D Undocumented bonus (see wiki):
%D
%D \starttyping
%D \limitatefirstline{\input tufte\relax}{10cm}{\unknown}
%D \stoptyping

\permanent\protected\def\limitatefirstline#1#2#3%
  {\hbox\bgroup\strut % \hpack
   \setbox\scratchbox\hbox{\begstrut#1\endstrut}%
   \ifdim\wd\scratchbox>{#2}%
     \setbox\scratchbox\hbox{#3}%
     \hsize{#2}%
     \advanceby\hsize-\wd\scratchbox
     \setbox\scratchbox\vbox{\forgetall\veryraggedright#1}%
     \setbox\scratchbox\vsplit\scratchbox to \lineheight
     \vbox
       {\unvbox\scratchbox
        \global\setbox\plusone\lastbox
        \global\setbox\plusone\hbox{\strut\unhbox\plusone}%
        \hbox % to #2 % \hpack
          {\unless\ifdefined\clip
             \box\plusone
           \orelse\ifdim\wd\plusone>\hsize
             \lower\strutdepth\hpack{\clip[\c!width=\hsize,\c!height=\lineheight]{\hpack{\raise\strutdepth\box\plusone}}}%
           \else
             \box\plusone
           \fi
           \removeunwantedspaces#3}}% \removeunwantedspaces\hss#3}}%
   \else
     #1%
   \fi
   \egroup}

%D \macros
%D   {processisolatedwords,processisolatedchars}
%D
%D \startbuffer
%D \processisolatedchars{some more words}           \ruledhbox \par
%D \processisolatedchars{and some $x + y = z$ math} \ruledhbox \par
%D \processisolatedchars{and a \hbox{$x + y = z$}}  \ruledhbox \par
%D \processisolatedwords{some more words}           \ruledhbox \par
%D \processisolatedwords{and some $x + y = z$ math} \ruledhbox \par
%D \processisolatedwords{and a \hbox{$x + y = z$}}  \ruledhbox \par
%D \stopbuffer
%D
%D \typebuffer \blank \getbuffer \blank

% todo: provide variant with #1 picked up as box

\permanent\protected\def\processisolatedchars#1#2%
  {\dontleavehmode
   \begingroup
   \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
   \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
   \clf_applytobox
     method  {char}%
     box     \scratchbox
     command {\csstring#2}%
     nested  true%
   \relax
   \endgroup}

\permanent\protected\def\processisolatedwords#1#2%
  {\dontleavehmode
   \begingroup
   \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
   \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
   \clf_applytobox
     method  {word}%
     box     \scratchbox
     command {\csstring#2}%
     nested  true%
   \relax
   \endgroup}

%D A variant:

\permanent\protected\def\applytocharacters#1%
  {\dontleavehmode
   \dowithnextbox{\clf_applytobox
     method  {char}%
     box     \nextbox
     command {\csstring#1}%
     nested  true%
   \relax}%
   \hbox}

\permanent\protected\def\applytowords#1%
  {\dontleavehmode
   \dowithnextbox{\clf_applytobox
     method  {word}%
     box     \nextbox
     command {\csstring#1}%
     nested  true%
   \relax}%
   \hbox}

%D The old call:

\permanent\protected\def\processwords#1%
  {\processisolatedwords{#1}\processword}

\mutable\let\processword\relax

\permanent\protected\def\applytosplitstringchar#1#2%
  {\dontleavehmode\clf_processsplit
     data    {#2}%
     command {\csstring#1}%
     method  {char}%
   \relax}

\permanent\protected\def\applytosplitstringword#1#2%
  {\dontleavehmode\clf_processsplit
     data    {#2}%
     command {\csstring#1}%
     method  {word}%
   \relax}

\permanent\protected\def\applytosplitstringline#1#2%
  {\dontleavehmode\clf_processsplit
     data    {#2}%
     command {\csstring#1}%
     method  {line}%
   \relax}

\permanent\protected\def\applytosplitstringcharspaced#1#2%
  {\dontleavehmode\clf_processsplit
     data    {#2}%
     command {\csstring#1}%
     method  {char}%
     spaced  true%
   \relax}

\permanent\protected\def\applytosplitstringwordspaced#1#2%
  {\dontleavehmode\clf_processsplit
     data    {#2}%
     command {\csstring#1}%
     method  {word}%
     spaced  true%
   \relax}

\permanent\protected\def\applytosplitstringlinespaced#1#2%
  {\dontleavehmode\clf_processsplit
     data    {#2}%
     command {\csstring#1}%
     method  {line}%
     spaced  true%
   \relax}

%D \macros
%D   {sbox}
%D
%D This is a rather strange command. It grabs some box content and and limits the
%D size to the height and depth of a \type {\strut}. The resulting bottom||alligned
%D box can be used aside other ones, without disturbing the normal baseline
%D distance.
%D
%D \startbuffer
%D \ruledhbox to .5\hsize{\sbox{eerste\par tweede \par derde}}
%D \stopbuffer
%D
%D \typebuffer
%D
%D Shows up as:
%D
%D \startexample
%D \vskip3\baselineskip
%D \getbuffer
%D \stopexample
%D
%D Before displaying the result we added some skip, otherwise the first two lines
%D would have ended up in the text. This macro can be useful when building
%D complicated menus, headers and footers and|/|or margin material.

\permanent\protected\def\sbox
  {\vpack\bgroup
   \dowithnextboxcs\syst_boxes_sbox_finish\vbox}

\def\syst_boxes_sbox_finish
  {\boxyoffset\nextbox-\strutdp
   \dp\nextbox\strutdp
   \ht\nextbox\strutht
   \box\nextbox
   \egroup}

%D A variant on this:
%D
%D \starttyping
%D xx \ruledhbox{\inlinedbox{\tfd test}} xx
%D \stoptyping

\permanent\protected\def\inlinedbox
  {\bgroup
   \dowithnextboxcs\syst_boxes_inlined_finish\hbox}

\def\syst_boxes_inlined_finish
  {\boxyoffset\nextbox{-((\htdp\nextbox-\lineheight)/\plustwo+\strutdp)}%
   \ht\nextbox\strutht
   \dp\nextbox\strutdp
   \box\nextbox
   \egroup}

%D \macros
%D   {struttedbox}
%D
%D This boxing macro limits the height and depth to those of a strut.

\permanent\protected\def\struttedbox
  {\hpack\bgroup
   \dowithnextboxcs\syst_boxes_struttedbox_finish\hbox}

\def\syst_boxes_struttedbox_finish
  {\dp\nextbox\strutdepth
   \ht\nextbox\strutheight
   \box\nextbox
   \egroup}

%D \macros
%D   {topskippedbox}
%D
%D This macro compensates the difference between the topskip and strutheight. Watch
%D how we preserve the depth when it equals strutdepth.

\permanent\protected\def\topskippedbox
  {\hpack\bgroup\dowithnextboxcs\syst_boxes_topskippedbox_finish\hbox}

% \def\syst_boxes_topskippedbox_finish
%   {\edef\m_boxes_tmp{\ifdim\strutdepth=\dp\nextbox\dp\nextbox\the\dp\nextbox\fi}%
%    \lower\topskip\hpack{\raise\strutheight\box\nextbox}%
%    \m_boxes_tmp
%    \egroup}

\def\syst_boxes_topskippedbox_finish
  {\ifdim\dp\nextbox=\strutdp
     \donetrue
   \else
     \donefalse
   \fi
   \lower\topskip\hpack\bgroup
     \raise\strutht\box\nextbox
   \egroup
   \ifdone
     \dp\nextbox\strutdp
   \fi
   \egroup}

%D \macros
%D   {centeredbox, centerednextbox}
%D
%D Here is another strange one. This one offers a sort of overlay with positive or
%D negative offsets. This command can be used in well defined areas where no offset
%D options are available. We first used it when building a button inside the margin
%D footer, where the button should have a horizontal offset and should be centered
%D with respect to the surrounding box. The last of the three examples we show below
%D says:
%D
%D \starttyping
%D \vsize=3cm
%D \hsize=3cm
%D \ruledvbox to \vsize
%D   {\centeredbox height .5cm width -1cm
%D      {\vrule width \hsize height \vsize}}}
%D \stoptyping
%D
%D Here the \type {\ruledvbox} just shows the surrounding box and \type {\vrule} is
%D used to show the centered box.
%D
%D \def\AnExample#1#2%
%D   {\vsize=3cm
%D    \hsize=3cm
%D    \ruledvbox to \vsize
%D      {\centeredbox height #1 width #2
%D         {\color[green]{\vrule width \hsize height \vsize}}}}
%D
%D \startlinecorrection
%D \startcombination[3*1]
%D   {\AnExample {-1cm}  {.5cm}} {}
%D   {\AnExample {.5cm}  {-1cm}} {}
%D   {\AnExample {-1cm} {-.5cm}} {}
%D \stopcombination
%D \stoplinecorrection
%D
%D This command takes two optional arguments: \type {width} and \type {height}.
%D Observing readers can see that we use \TEX's own scanner for grabbing these
%D arguments: \type {#1#} reads everyting till the next brace and passes it to both
%D rules. The setting of the box dimensions at the end is needed for special cases.
%D The dimensions of the surrounding box are kept intact. This commands handles
%D positive and negative dimensions (which is why we need two boxes with rules).

\permanent\protected\def\centeredbox#1#%   height +/-dimen width +/-dimen
  {\bgroup
   \dontcomplain
   \forgetall
   \scangivendimensions#1\relax
   \advanceby\vsize\givenheight
   \advanceby\hsize\givenwidth
   \dowithnextboxcs\syst_boxes_centered_finish
   \hbox}

\def\syst_boxes_centered_finish
  {\boxxoffset\nextbox{(\hsize-\wd\nextbox-\givenwidth)/2}%
   \boxyoffset\nextbox{(\vsize-\ht\nextbox+\dp\nextbox-\givenheight)/2}%
   \wd\nextbox{\hsize-\givenwidth }%
   \ht\nextbox{\vsize-\givenheight}%
   \dp\nextbox\zeropoint
   \box\nextbox
   \egroup}

%D For those who don't want to deal with \type {\hsize} and \type {\vsize}, we have:
%D
%D \starttyping
%D \centerednextbox width 2bp height 2bp
%D   {\framed[width=100bp,height=100bp]{}}
%D \stoptyping
%D
%D Do you see why we call this one \type {next}?

\permanent\protected\def\centerednextbox#1#%
  {\bgroup
   \dowithnextbox
     {\hsize\wd\nextbox
      \vsize\ht\nextbox
      \centeredbox#1{\box\nextbox}%
      \egroup}
   \hbox}

%D \macros
%D   {centerbox}
%D
%D Centering on the available space is done by:
%D
%D \starttyping
%D \centerbox <optional specs> {content}
%D \stoptyping
%D
%D When omitted, the current \type {\hsize} and \type {\vsize} are used. Local
%D dimensions are supported.

\permanent\protected\def\centerbox#1#%   optional height +/-dimen width +/-dimen
  {\bgroup
   \dowithnextbox
     {\setlocalhsize
      \setbox\scratchbox\hpack{\vrule\s!width \zeropoint#1}%
      \ifzeropt\wd\scratchbox\else\hsize\wd\scratchbox\fi
      \setbox\scratchbox\vpack{\hrule\s!height\zeropoint#1}%
      \ifzeropt\ht\scratchbox\else\vsize\ht\scratchbox\fi
      \vpack to \vsize{\vss\hpack to \hsize{\hss\box\nextbox\hss}\vss}%
      \egroup}%
     \hbox}

%D \macros
%D   {setrigidcolumnhsize,rigidcolumnbalance,rigidcolumnlines}
%D
%D These macros are copied from the \TEX book, page~397, and extended by a macro
%D that sets the \type {\hsize}.
%D
%D \starttyping
%D \setrigidcolumnhsize {total width} {distance} {n}
%D \rigidcolumnbalance  {box}
%D \stoptyping
%D
%D Both these macros are for instance used in typesetting footnotes. The following
%D flags influence the process.

\newif\ifalignrigidcolumns
\newif\ifstretchrigidcolumns
\newif\iftightrigidcolumns    % if true: just a vbox, no depth/noflines/gridsnap corrrections

\mutable\let\rigidcolumnlines\!!zerocount

\newbox      \rigidcolumnbox
\newdimension\rigidhsize
\newinteger  \rigidcolumns

% \permanent\protected\def\setrigidcolumnhsize#1#2#3% todo: \dimexpr
%   {\global\rigidhsize\hsize
%    \global\rigidcolumns#3\relax
%    \hsize#1\relax
%    \scratchdimen -#2\relax
%    \multiplyby\scratchdimen #3\relax
%    \advanceby\scratchdimen  #2\relax
%    \advanceby\hsize \scratchdimen
%    \divideby\hsize #3\relax}

% ==

\def\setrigidcolumnhsize#1#2#3%
  {\global\rigidhsize\hsize
   \global\rigidcolumns{#3}%
   \hsize{(#1-\numexpr\rigidcolumns-1\relax\dimexpr#2\relax)/\rigidcolumns}}

\permanent\protected\def\rigidcolumnbalance#1%
  {\ifnum\rigidcolumns=1 % tzt ook h/d correctie
     \ifinner\ifhmode\box\else\unvbox\fi\else\unvbox\fi#1\relax
   \else
     \vbox % \vpack
       {\forgetall
        \nopenalties
        \dontcomplain
        \setbox\rigidcolumnbox\vbox
          {\line{}\goodbreak\unvbox#1\removebottomthings}%
        \splittopskip\openstrutheight
        \setbox\scratchbox\vsplit\rigidcolumnbox to \zeropoint
        \ifcase\rigidcolumnlines\relax
          % \iffalse
          %  % maybe some day an option
          %  \scratchskip\ht\rigidcolumnbox
          %  \advanceby\scratchskip\dp\rigidcolumnbox
          %  \getnoflines\scratchskip
          %  \ifodd\noflines
          %    \advanceby\noflines\plusone
          %  \fi
          %  \divideby\noflines\rigidcolumns
          %\else
            \scratchdimen\ht\rigidcolumnbox
            \divideby\scratchdimen \rigidcolumns
            \getnoflines\scratchdimen
          %\fi
        \else
          \noflines\rigidcolumnlines % to be sure
        \fi
        \scratchdimen\noflines\lineheight
        % new: we now loop so that we don't loose content
        % since in practice we also use this macro for
        % funny lineheights and border cases
        \setbox0=\box\rigidcolumnbox
        \ifvoid0\else
          \doloop
            {\setbox\rigidcolumnbox=\copy0
             \setbox\scratchbox\hpack to \rigidhsize
               {\dorecurse\rigidcolumns
                  {\setbox\scratchbox\vsplit\rigidcolumnbox to \scratchdimen
                     \dp\scratchbox\openstrutdepth
                     \setbox\scratchbox\vtop
                       \ifalignrigidcolumns to
                         \ifstretchrigidcolumns\vsize\else\scratchdimen\fi
                       \fi
                       {\unvbox\scratchbox}%
                   \wd\scratchbox\hsize
                   \box\scratchbox
                   \hfill}%
                \hfillneg}%
            \ifvoid\rigidcolumnbox\exitloop\else\advanceby\scratchdimen\lineheight\fi}%
         \iftightrigidcolumns
           \setbox\scratchbox\hpack{\raise\dp\scratchbox\box\scratchbox}%
         \else
           \advanceby\scratchdimen -\openstrutdepth
           \setbox\scratchbox\hpack{\raise\scratchdimen\box\scratchbox}%
           \dp\scratchbox\openstrutdepth
           \ht\scratchbox\scratchdimen
         \fi
         \box\scratchbox
       \fi}%
   \fi}

%D \macros
%D   {startvboxtohbox,stopvboxtohbox,convertvboxtohbox}
%D
%D Here is another of Knuth's dirty tricks, as presented on pages 398 and 399 of the
%D \TEX book. These macros can be used like:
%D
%D \starttyping
%D \vbox
%D   \bgroup
%D     \startvboxtohbox ... \stopvboxtohbox
%D     \startvboxtohbox ... \stopvboxtohbox
%D     \startvboxtohbox ... \stopvboxtohbox
%D   \egroup
%D
%D \vbox
%D   \bgroup
%D     \convertvboxtohbox
%D   \egroup
%D \stoptyping
%D
%D These macros are used in reformatting footnotes, so they do what they're meant
%D for.

\newdimension\vboxtohboxslack
\newdimension\hboxestohboxslack

%D Create line and fake height of paragraph by messing with heights: a nice hack by
%D DEK himself.

%\protected\def\setvboxtohbox
%  {\bgroup
%   \ifdim\baselineskip<16pt \relax
%     \scratchdimen\baselineskip
%     \multiplyby\scratchdimen 1024
%   \else
%     \message{cropping \baselineskip to 16pt}%
%     \scratchdimen\maxdimen
%   \fi
%   \divideby\scratchdimen \hsize
%   \multiplyby\scratchdimen 64
%   \xdef\vboxtohboxfactor{\toscaled\scratchdimen}%
%   \egroup}
%
% \protected\def\startvboxtohbox
%  {\bgroup
%   \setvboxtohbox
%   \setbox\scratchbox\hbox\bgroup}
%
% \protected\def\stopvboxtohbox
%   {\ifcase\vboxtohboxslack\else\hskip\zeropoint\s!minus\vboxtohboxslack\fi
%    \egroup
%    \dp\scratchbox\zeropoint
%    \ht\scratchbox\vboxtohboxfactor\wd\scratchbox
%    \box\scratchbox
%    \egroup}

% More modern:

% \definesystemattribute[vboxtohboxseparator][public]

%newbox\d_syst_boxes_vboxtohbox
\newbox\d_syst_boxes_separator

\permanent\protected\def\startvboxtohboxseparator
  {\setbox\d_syst_boxes_separator\hbox attr \vboxtohboxseparatorattribute\plusone\bgroup}

\permanent\protected\def\stopvboxtohboxseparator
  {\egroup}

\permanent\protected\def\startvboxtohbox
  {\begingroup
   \setbox\scratchbox\hbox\bgroup}

\permanent\protected\def\stopvboxtohbox
  {\ifvoid\d_syst_boxes_separator
     \hskip\zeropoint\ifcase\vboxtohboxslack\else\s!minus\vboxtohboxslack\fi % we really need a skip
   \else
     \box\d_syst_boxes_separator
   \fi
   \egroup
   \clf_hboxtovbox\scratchbox
   \box\scratchbox
   \endgroup}

% A possible reconstruction:

\permanent\protected\def\convertvboxtohbox
  {\makehboxofhboxes
   \setbox\scratchboxone\hpack{\unhbox\scratchboxone\removehboxes}% \hpack
   \noindent\unhbox\scratchboxone\par}

\permanent\protected\def\makehboxofhboxes
  {\setbox\scratchboxone\emptyhbox
   \loop % \doloop { .. \exitloop .. }
     \setbox\scratchboxtwo\lastbox
     \ifhbox\scratchboxtwo
       \setbox\scratchboxone\hpack{\box\scratchboxtwo\unhbox\scratchboxone}%
   \repeat}

\permanent\protected\def\removehboxes
  {\setbox\scratchboxone\lastbox
   \ifhbox\scratchboxone
     {\removehboxes}\unhbox\scratchboxone
   \fi}

% And one special for notes:

\permanent\protected\def\starthboxestohbox
  {\bgroup
   \setbox\scratchbox\vbox\bgroup}

\permanent\protected\def\stophboxestohbox
  {\egroup
   \clf_vboxlisttohbox\scratchbox\nextbox{\hboxestohboxslack}%
   \dontleavehmode
   \unhbox\nextbox
   \removeunwantedspaces
   \par
   \egroup}

%D \macros
%D   {unhhbox}
%D
%D The next macro is used in typesetting inline headings. Let's first look at the
%D macro and then show an example. As many other helpers here, it is no longer
%D used in the core and dates from \MKII\ times, but we keep it here just in case
%D some use style uses it. Eventually we might moev this to a load|-|on|-|demand
%D module.

\newbox      \unhhedbox
\newbox      \hhbox
\newdimension\lasthhboxwidth
\newgluespec \hhboxindent

\permanent\protected\def\unhhbox#1\with#2%
  {\bgroup
   \nopenalties
   \dontcomplain
   \forgetall
   \setbox\unhhedbox\vbox{\hskip\hhboxindent\strut\unhbox#1}% => \hsize
   \doloop
     {\setbox\hhbox\vsplit\unhhedbox to \lineheight
      \ifvoid\unhhedbox
        \setbox\hhbox\hbox{\strut\hboxofvbox\hhbox}% \hpack
      \fi
      \ht\hhbox\strutht
      \dp\hhbox\strutdp
      \ifzeropt\hhboxindent\else
        \setbox\hhbox\hpack{\kern-\hhboxindent\box\hhbox}%
        \hhboxindent\zeropoint
      \fi
      \global\lasthhboxwidth\wd\hhbox
      #2\relax
      \ifvoid\unhhedbox
        \exitloop
      \else
        \hskip\zeropoint \s!plus \zeropoint
      \fi}%
   \egroup}

\def\syst_boxes_hboxofvbox
  {\setbox0\vpack{\unvbox\scratchcounter\global\setbox1\lastbox}%
   \unhbox1
   \egroup}

\permanent\protected\def\hboxofvbox
  {\bgroup
   \afterassignment\syst_boxes_hboxofvbox
   \scratchcounter=}

%D This macro can be used to break a paragraph apart and treat each line seperately,
%D for instance, making it clickable. The main complication is that we want to be
%D able to continue the paragraph, something that's needed in the in line section
%D headers.
%D
%D \startbuffer
%D \setbox0=\hbox{\input tufte \relax}
%D \setbox2=\hbox{\input knuth \relax}
%D \unhhbox0\with{\ruledhbox{\box\hhbox}}
%D \hskip1em plus 1em minus 1em
%D \hhboxindent=\lasthhboxwidth
%D \advanceby\hhboxindent by \lastskip
%D \unhhbox2\with{\ruledhbox{\box\hhbox}}
%D \stopbuffer
%D
%D \getbuffer
%D
%D This piece of text was typeset by saying:
%D
%D \typebuffer
%D
%D Not that nice a definition, but effective. Note the stretch we've build in the
%D line that connects the two paragraphs.

%D \macros
%D   {doifcontent}
%D
%D When processing depends on the availability of content, one can give the next
%D macro a try.
%D
%D \starttyping
%D \doifcontent{pre content}{post content}{no content}\somebox
%D \stoptyping
%D
%D Where \type {\somebox} is either a \type {\hbox} or \type {\vbox}. If the
%D dimension of this box suggest some content, the resulting box is unboxed and
%D surrounded by the first two arguments, else the third arguments is executed.

\permanent\protected\def\doifcontent#1#2#3%
  {\dowithnextbox
     {\ifhbox\nextbox
        \ifdim\wd\nextbox>\zeropoint
          #1\unhbox\nextbox#2\relax
        \else
          #3\relax
        \fi
      \else
        \ifdim\ht\nextbox>\zeropoint
          #1\unvbox\nextbox#2\relax
        \else
          #3\relax
        \fi
      \fi}}

%D So when we say:
%D
%D \startbuffer
%D \doifcontent{[}{]}{}\hbox{content sensitive typesetting}
%D
%D \doifcontent{}{\page}{}\vbox{content sensitive typesetting}
%D
%D \doifcontent{}{}{\message{Didn't you forget something?}}\hbox{}
%D \stopbuffer
%D
%D \typebuffer
%D
%D We get:
%D
%D \getbuffer
%D
%D Where the last call of course does not show up in this document, but definitely
%D generates a confusing message.

%D \macros
%D   {processboxes}
%D
%D The next macro gobble boxes and is for instance used for overlays. First we show
%D the general handler.

\newbox\processbox % public : this is the one where \nextbox's end up in

\let\syst_boxes_process_indeed\relax

\permanent\protected\def\processboxes#1%
  {\bgroup
   \def\syst_boxes_process_indeed{#1}% #1 can be redefined halfway
   \setbox\processbox\emptybox
   \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}

\def\syst_boxes_process_yes
  {\dowithnextboxcs\syst_boxes_process_content\hbox}

\def\syst_boxes_process_content
  {\removeunwantedspaces
   \syst_boxes_process_indeed % takes \nextbox makes \processbox
   \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}

\protected\def\syst_boxes_process_nop
  {\removeunwantedspaces
   \box\processbox
   \egroup}

%D \macros
%D   {startoverlay}
%D
%D We can overlay boxes by saying:
%D
%D \startbuffer
%D \startoverlay
%D   {\framed{hans}}
%D   {\framed[width=3cm]{ton}}
%D   {\framed[height=2cm]{oeps}}
%D \stopoverlay
%D \stopbuffer
%D
%D \typebuffer
%D
%D shows up as:
%D
%D \leavevmode\getbuffer

\permanent\def\boxisempty#1%
  {\ifdim\wd#1=\zeropoint
     \ifdim\ht#1=\zeropoint
       \ifdim\dp#1=\zeropoint
         \zerocount
       \else
         \plusone
       \fi
     \else
       \plusone
     \fi
   \else
     \plusone
   \fi}

\def\syst_boxes_overlay_process
  {\ifcase\boxisempty\nextbox\else
     \syst_boxes_overlay_process_indeed
   \fi}

\def\syst_boxes_overlay_process_indeed
  {%\removeunwantedspaces % already done
   \scratchdepth\dp\ifdim\dp\nextbox>\dp\processbox\nextbox\else\processbox\fi
   \ifdim\ht\nextbox>\ht\processbox
     \setbox\processbox\vpack to \ht\nextbox   {\dp\processbox\zeropoint\vss\box\processbox\vss}%
   \else
     \setbox\nextbox   \vpack to \ht\processbox{\dp\nextbox   \zeropoint\vss\box\nextbox   \vss}%
   \fi
   \dp\nextbox   \scratchdepth
   \dp\processbox\scratchdepth
   \scratchwidth\wd\ifdim\wd\nextbox>\wd\processbox\nextbox\else\processbox\fi
   \setbox\processbox\hpack to \scratchwidth
     {\hpack to \scratchwidth{\hss\box\processbox\hss}%
      \kern-\scratchwidth
      \hpack to \scratchwidth{\hss\box\nextbox   \hss}}}

\permanent\protected\def\startoverlay
  {\vbox\bgroup % we remove unwanted spaces so we want to prevent the pre-overlay gobble
   \enforced\aliased\let\stopoverlay\egroup
   \processboxes\syst_boxes_overlay_process}

\permanent\protected\lettonothing\stopoverlay

%D \macros
%D   {fakebox}
%D
%D The next macro is a rather silly one, but saves space.
%D
%D \starttyping
%D \hbox{\fakebox0}
%D \stoptyping
%D
%D returns an empty box with the dimensions of the box specified, here being zero.

\permanent\protected\def\fakebox
  {\bgroup
   \afterassignment\syst_boxes_fakebox_finish\scratchcounter}

\def\syst_boxes_fakebox_finish
  {\setbox\scratchbox\ifhbox\scratchcounter\emptyhbox\else\emptyvbox\fi
   \wd\scratchbox\wd\scratchcounter
   \ht\scratchbox\ht\scratchcounter
   \dp\scratchbox\dp\scratchcounter
   \box\scratchbox
   \egroup}

%D \macros
%D   {lbox,rbox,cbox,tbox,bbox}
%D
%D Here are some convenient alternative box types:
%D
%D \starttyping
%D \lbox{text ...}
%D \cbox{text ...}
%D \rbox{text ...}
%D \stoptyping
%D
%D Are similar to \type {\vbox}, which means that they also accept something like
%D \type {to 3cm}, but align to the left, middle and right. These box types can be
%D used to typeset paragraphs.

\def\syst_boxes_lrc_process#1%
  {\bgroup
   \forgetall
   \enforced\let\\\endgraf
   #1%
   \let\nexttoken}

\permanent\protected\def\lbox#1#{\vbox#1\syst_boxes_lrc_process\raggedleft  }
\permanent\protected\def\cbox#1#{\vbox#1\syst_boxes_lrc_process\raggedcenter}
\permanent\protected\def\rbox#1#{\vbox#1\syst_boxes_lrc_process\raggedright }

\permanent\protected\def\ltop#1#{\vtop#1\syst_boxes_lrc_process\raggedleft  }
\permanent\protected\def\ctop#1#{\vtop#1\syst_boxes_lrc_process\raggedcenter}
\permanent\protected\def\rtop#1#{\vtop#1\syst_boxes_lrc_process\raggedright }

%D The alternatives \type {\tbox} and \type {\bbox} can be used to properly align
%D boxes, like in:
%D
%D \setupexternalfigures[directory={../sample}]
%D \startbuffer
%D \starttable[|||]
%D \HL
%D \VL \tbox{\externalfigure[cow][height=3cm,frame=on]} \VL top aligned    \VL\SR
%D \HL
%D \VL \bbox{\externalfigure[cow][height=3cm,frame=on]} \VL bottom aligned \VL\SR
%D \HL
%D \stoptable
%D \stopbuffer
%D
%D \typebuffer
%D
%D The positioning depends on the strut settings:
%D
%D \getbuffer

\permanent\protected\def\tbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_tbox_finish\hbox}
\permanent\protected\def\bbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_bbox_finish\hbox}

\def\syst_boxes_tbox_finish
  {\scratchheight\strutht
   \scratchdepth{\htdp\nextbox-\scratchheight}%
   \ht\nextbox\scratchheight
   \dp\nextbox\scratchdepth
   \boxyoffset\nextbox-\scratchdepth
   \box\nextbox
   \egroup}

\def\syst_boxes_bbox_finish
  {\scratchdepth\strutdp
   \scratchheight{\htdp\nextbox-\scratchdepth}%
   \dp\nextbox\scratchdepth
   \ht\nextbox\scratchheight
   \boxyoffset\nextbox-\scratchdepth
   \box\nextbox
   \egroup}

%D \macros
%D   {lhbox,mhbox,rhbox}
%D
%D A few more boxes.

\def\syst_boxes_lhbox{\hpack to \hsize{\box\nextbox\hss    }}
\def\syst_boxes_mhbox{\hpack to \hsize{\hss\box\nextbox\hss}}
\def\syst_boxes_rhbox{\hpack to \hsize{\hss\box\nextbox    }}

\permanent\protected\def\lhbox{\dowithnextboxcs\syst_boxes_lhbox\hbox}
\permanent\protected\def\mhbox{\dowithnextboxcs\syst_boxes_mhbox\hbox}
\permanent\protected\def\rhbox{\dowithnextboxcs\syst_boxes_rhbox\hbox}

\aliased\let\lefthbox \lhbox
\aliased\let\midhbox  \mhbox
\aliased\let\righthbox\rhbox

%D \macros
%D   {boxofsize}
%D
%D Sometimes we need to construct a box with a height or width made up of several
%D dimensions. Instead of cumbersome additions, we can use:
%D
%D \starttyping
%D \boxofsize \vbox 10cm 3cm -5cm {the text to be typeset}
%D \stoptyping
%D
%D This example demonstrates that one can use positive and negative values.
%D Dimension registers are also accepted.

\newdimension\sizeofbox

\permanent\protected\def\boxofsize#1%
  {\bgroup
   \sizeofbox\zeropoint
   \scratchdimen\zeropoint
   \def\docommand
     {\advanceby\sizeofbox\scratchdimen
      \futurelet\nexttoken\dodocommand}%
   \def\dodocommand
     {\ifx\nexttoken\bgroup
        \expanded{\egroup#1 to \the\sizeofbox}%
      \else
        \expandafter\afterassignment\expandafter\docommand\expandafter\scratchdimen
      \fi}%
   \docommand}

%D Some new, still undocumented features:

% limitatetext -> beter {text} als laatste !!
%
% \limitvbox
% \limithbox

\permanent\protected\def\limitatelines#1#2% size sentinel
  {\dowithnextbox
     {\scratchdimen#1\hsize
      \ifdim\wd\nextbox>\scratchdimen
        \setbox\nextbox\hbox
          {\advanceby\scratchdimen -.1\hsize
           \limitatetext{\unhbox\nextbox}{\scratchdimen}{\nobreak#2}}%
      \fi
      \unhbox\nextbox}
     \hbox}

\permanent\protected\def\fittoptobaselinegrid % weg hier
  {\dowithnextbox
     {\bgroup
      \par
      \scratchdimen\ht\nextbox
      \ht\nextbox\strutht
      \dp\nextbox\strutdp
      \hpack{\box\nextbox}
      \prevdepth\strutdp
      \doloop
        {\advanceby\scratchdimen -\lineheight
         \ifdim\scratchdimen<\zeropoint
           \exitloop
         \else
           \nobreak
           \hpack{\strut}
         \fi}
      \egroup}
     \vbox}

%D Some more undocumented macros (used in m-chart).

\newif\iftraceboxplacement % \traceboxplacementtrue

\newbox\fakedboxcursor

\setbox\fakedboxcursor\hpack
  {\vrule\s!width\zeropoint\s!height\zeropoint\s!depth\zeropoint}

\permanent\protected\def\boxcursor % overloaded in core-vis
  {\iftraceboxplacement
     \bgroup
     \scratchdimen2\onepoint
     \setbox\scratchbox\hpack to \zeropoint
       {\hss
        \vrule
          \s!width \scratchdimen
          \s!height\scratchdimen
          \s!depth \scratchdimen
        \hss}%
     \smashedbox\scratchbox
     \egroup
   \else
     \copy\fakedboxcursor
   \fi}

\permanent\protected\def\placedbox
  {\iftraceboxplacement\ruledhbox\else\hbox\fi}

\newdimension\boxoffset
\newdimension\boxhdisplacement
\newdimension\boxvdisplacement

\permanent\protected\def\rightbox      {\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbox_finish      \placedbox}
\permanent\protected\def\leftbox       {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbox_finish       \placedbox}
\permanent\protected\def\topbox        {\hpack\bgroup\dowithnextboxcs\syst_boxes_topbox_finish        \placedbox}
\permanent\protected\def\bottombox     {\hpack\bgroup\dowithnextboxcs\syst_boxes_bottombox_finish     \placedbox}
\permanent\protected\def\lefttopbox    {\hpack\bgroup\dowithnextboxcs\syst_boxes_lefttopbox_finish    \placedbox}
\permanent\protected\def\righttopbox   {\hpack\bgroup\dowithnextboxcs\syst_boxes_righttopbox_finish   \placedbox}
\permanent\protected\def\leftbottombox {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbottombox_finish \placedbox}
\permanent\protected\def\rightbottombox{\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbottombox_finish\placedbox}

\aliased\let\topleftbox    \lefttopbox
\aliased\let\toprightbox   \righttopbox
\aliased\let\bottomleftbox \leftbottombox
\aliased\let\bottomrightbox\rightbottombox

\def\syst_boxes_rightbox_finish
  {\global\boxhdisplacement\boxoffset
   \global\boxvdisplacement{(\ht\nextbox-\dp\nextbox)/2}%
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_leftbox_finish
  {\global\boxhdisplacement{-\wd\nextbox-\boxoffset}%
   \global\boxvdisplacement{(\ht\nextbox-\dp\nextbox)/2}%
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_topbox_finish
  {\global\boxhdisplacement-.5\wd\nextbox
   \global\boxvdisplacement{-\dp\nextbox-\boxoffset}%
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_bottombox_finish
  {\global\boxhdisplacement{-\wd\nextbox/2}%
   \global\boxvdisplacement{\ht\nextbox+\boxoffset}%
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_lefttopbox_finish
  {\global\boxhdisplacement{-\wd\nextbox-\boxoffset}%
   \global\boxvdisplacement{-\dp\nextbox-\boxoffset}%
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_righttopbox_finish
  {\global\boxhdisplacement\boxoffset
   \global\boxvdisplacement{-\dp\nextbox-\boxoffset}%
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_leftbottombox_finish
  {\global\boxhdisplacement{-\wd\nextbox-\boxoffset}%
   \global\boxvdisplacement{\ht\nextbox+\boxoffset}%
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_rightbottombox_finish
  {\global\boxhdisplacement\boxoffset
   \global\boxvdisplacement{\ht\nextbox+\boxoffset}%
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\permanent\protected\def\middlebox        {\hpack\bgroup\dowithnextboxcs\syst_boxes_middlebox_finish        \placedbox}
\permanent\protected\def\baselinemiddlebox{\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinemiddlebox_finish\placedbox}
\permanent\protected\def\baselineleftbox  {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselineleftbox_finish  \placedbox}
\permanent\protected\def\baselinerightbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinerightbox_finish \placedbox}

\def\syst_boxes_middlebox_finish
  {\global\boxhdisplacement{-\wd\nextbox/2}%
   \global\boxvdisplacement{(\ht\nextbox-\dp\nextbox)/2}%
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_baselinemiddlebox_finish
  {\global\boxhdisplacement{-.5\wd\nextbox-\boxoffset}%
   \global\boxvdisplacement-\boxoffset
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_baselineleftbox_finish
  {\global\boxhdisplacement{-\wd\nextbox-\boxoffset}%
   \global\boxvdisplacement-\boxoffset
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

\def\syst_boxes_baselinerightbox_finish
  {\global\boxhdisplacement\boxoffset
   \global\boxvdisplacement-\boxoffset
   \boxcursor
   \boxxmove\nextbox \boxhdisplacement
   \boxymove\nextbox-\boxvdisplacement
   \box\nextbox
   \egroup}

%D \macros
%D   {obox}
%D
%D Experimental, not yet frozen:

\permanent\protected\def\lrtbbox#1#2#3#4% l r t b
  {\bgroup
   \dowithnextboxcontent
     {\advanceby\hsize-#1\advanceby\hsize-#2\relax
      \advanceby\vsize-#3\advanceby\vsize-#4\relax}
     {\forgetall\vpack to \vsize{\vskip#3\hpack to \hsize{\hskip#1\box\nextbox\hss}\vss}\egroup}
     \vbox}

%D \macros
%D   {toplinebox}
%D
%D See core-tbl.tex for an example of its usage:

\permanent\protected\def\toplinebox
  {\dowithnextboxcs\syst_boxes_toplinebox_finish\tbox}

\def\syst_boxes_toplinebox_finish
  {\ifdim\dp\nextbox>\strutdepth
     \scratchdimen\dp\nextbox
     \advanceby\scratchdimen-\strutdepth
     \getnoflines\scratchdimen
     \struttedbox{\box\nextbox}%
     \dorecurse\noflines\verticalstrut
   \else
     \box\nextbox
   \fi}

%D \macros
%D   {initializeboxstack,savebox,foundbox}
%D
%D At the cost of some memory, but saving box registers, we have implemented a box
%D repository.
%D
%D \starttyping
%D \initializeboxstack{one}
%D
%D \savebox{one}{a}{test a}
%D \savebox{one}{p}{test p}
%D \savebox{one}{q}{test q}
%D
%D \hbox{a:\foundbox{one}{a}} \par
%D \hbox{q:\foundbox{one}{q}} \par
%D \hbox{p:\foundbox{one}{p}} \par
%D \hbox{x:\foundbox{one}{x}} \par
%D \hbox{y:\foundbox{two}{a}} \par
%D \stoptyping

%D Kind of obsolete:

\installcorenamespace {stackbox}
\installcorenamespace {stacklst}

\permanent\protected\def\setstackbox#1#2%
  {\ifcsname\??stackbox#1:#2\endcsname\else
     \expandafter\newbox\csname\??stackbox#1:#2\endcsname
   \fi
   \global\setbox\csname\??stackbox#1:#2\endcsname\vbox}

\permanent\protected\def\initializeboxstack#1%
  {\def\docommand##1{\setstackbox{#1}{##1}{}}%
   \ifcsname\??stacklst#1\endcsname
     \expandafter\processcommacommand\expandafter[\lastnamedcs]\docommand
   \fi
   \gletcsname\??stacklst#1\endcsname\empty}

\permanent\protected\def\savebox#1#2% stack name
  {% beware, \setxvalue defines the cs beforehand so we cannot use the test inside the { }
   \ifcsname\??stacklst#1\endcsname
     \xdefcsname\??stacklst#1\expandafter\endcsname\expandafter{\lastnamedcs,#2}%
   \else
     \xdefcsname\??stacklst#1\endcsname{#2}%
   \fi
   \setstackbox{#1}{#2}}

\permanent\protected\def\flushbox#1#2% unwrapped
  {\ifcsname\??stackbox#1:#2\endcsname
     \box\lastnamedcs
   \else
     \emptybox
   \fi}

\permanent\protected\def\restorebox#1#2% unwrapped
  {\ifcsname\??stackbox#1:#2\endcsname
     \copy\lastnamedcs
   \else
     \emptybox
   \fi}

\permanent\protected\def\foundbox#1#2% wrapped
  {\vpack
     {\ifcsname\??stackbox#1:#2\endcsname
        \copy\lastnamedcs
      \fi}}

\permanent\protected\def\doifelsebox#1#2%
  {\unless\ifcsname\??stackbox#1:#2\endcsname
     \expandafter\secondoftwoarguments
   \orelse\ifvoid\lastnamedcs
     \expandafter\secondoftwoarguments
   \else
     \expandafter\firstoftwoarguments
   \fi}

\aliased\let\doifboxelse\doifelsebox

%D This one is cheaper (the above is no longer used that much):

\installcorenamespace {boxstack}

\newinteger\c_syst_boxes_stack

\mutable\let\b_syst_boxes_stack\relax

\protected\def\syst_boxes_stack_allocate
  {\newbox\b_syst_boxes_stack
   \letcsname\??boxstack\the\c_syst_boxes_stack\endcsname\b_syst_boxes_stack}

\protected\def\syst_boxes_push#1#2%
  {\global\advanceby\c_syst_boxes_stack\plusone
   \expandafter\let\expandafter\b_syst_boxes_stack\csname\??boxstack\the\c_syst_boxes_stack\endcsname
   \ifrelax\b_syst_boxes_stack % cheaper then csname check as in most cases it's defined
      \syst_boxes_stack_allocate
   \fi
   #1\setbox\b_syst_boxes_stack\box#2\relax}

\protected\def\syst_boxes_pop#1#2%
  {#1\setbox#2\box\csname\??boxstack\the\c_syst_boxes_stack\endcsname
   \global\advanceby\c_syst_boxes_stack\minusone}

\permanent\protected\def\localpushbox {\syst_boxes_push\relax}
\permanent\protected\def\localpopbox  {\syst_boxes_pop \relax}

\permanent\protected\def\globalpushbox{\syst_boxes_push\global}
\permanent\protected\def\globalpopbox {\syst_boxes_pop \global}

%D And here is a more modern one (not yet in i-*):
%D
%D \starttyping
%D \dorecurse {100} {
%D     \setbox\zerocount\hbox{test \recurselevel}
%D     \putboxincache{foo}{\recurselevel}\zerocount
%D     \copyboxfromcache{foo}{\recurselevel}\zerocount
%D     \iftrue
%D         \setbox\zerocount\hbox{\directboxfromcache{foo}{\recurselevel}}%
%D     \else
%D         \getboxfromcache{foo}{\recurselevel}\zerocount
%D     \fi
%D }
%D % \startMPcode draw rawtexbox("category","name") ; \stopMPcode
%D \resetboxesincache{foo}
%D \stoptyping

% \putboxincache          % {category} {name} number
% \getboxfromcache        % {category} {name} number
% \doifelseboxincache     % {category} {name}
% \copyboxfromcache       % {category} {name} number
% \directboxfromcache     % {category} {name}
% \directcopyboxfromcache % {category} {name}
% \resetboxesincache      % {category}
% \putnextboxincache      % {category} {name} box
% \getboxwdfromcache      % {category} {name}
% \getboxhtfromcache      % {category} {name}
% \getboxdpfromcache      % {category} {name}
% \getboxhtdpfromcache    % {category} {name}

%D \macros
%D   {removedepth, obeydepth}
%D
%D While \type {\removedepth} removes the preceding depth, \type {\obeydepth} makes
%D sure we have depth. Both macros leave the \type {\prevdepth} untouched.

\permanent\protected\def\removedepth
  {\ifvmode
     \ifdim\prevdepth>\zeropoint
       \kern-\prevdepth
     \fi
   \fi}

\permanent\protected\def\obeydepth
  {\par % watch out for changes in math formulas
   \ifvmode\ifdim\prevdepth<\zeropoint\orelse\ifdim\prevdepth<\strutdp
     \kern{\strutdp-\prevdepth}%
     \prevdepth\strutdp
   \fi\fi}

\permanent\protected\def\undepthed
  {\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\hbox}

%D \macros
%D   {removebottomthings, removelastskip}
%D
%D A funny (but rather stupid) one, plus a redefinition.

% \permanent\protected\def\removebottomthings
%   {\dorecurse\plusfive{\unskip\unkern\unpenalty}}

\permanent\protected\def\removebottomthings
  {\localcontrolledloop\plusone\plusfive\plusone{\unskip\unkern\unpenalty}}

\permanent\protected\def\removelastskip % \ifvmode the plain tex one \fi, overloaded to \permanent in spac-ver
  {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi}

%D \macros
%D   {makestrutofbox}
%D
%D This macro sets the dimensions of a box to those of a strut. Sort of obsolete so
%D it will go away.

\permanent\protected\def\makestrutofbox % not used
  {\afterassignment\syst_boxes_makestrutofbox\c_boxes_register}

\def\syst_boxes_makestrutofbox
  {\ht\c_boxes_register\strutht
   \dp\c_boxes_register\strutdp
   \wd\c_boxes_register\zeropoint}

%D \macros
%D   {raisebox,lowerbox}
%D
%D Some more box stuff, related to positioning (under construction). Nice stuff for
%D a tips and tricks maps article.
%D
%D \starttyping
%D \raisebox{100pt}\hbox{test}
%D \hsmash{\raisebox{100pt}\hbox{test}}
%D \stoptyping

\permanent\protected\def\raisebox#1{\bgroup\afterassignment\syst_boxes_raise_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted
\permanent\protected\def\lowerbox#1{\bgroup\afterassignment\syst_boxes_lower_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted

\def\syst_boxes_raise_indeed{\dowithnextboxcs\syst_boxes_raise_finish}
\def\syst_boxes_lower_indeed{\dowithnextboxcs\syst_boxes_lower_finish}

\def\syst_boxes_raise_finish
  {\boxyoffset\nextbox\scratchdimen
   \ht\nextbox\strutht
   \dp\nextbox\strutdp
   \box\nextbox
   \egroup}

\def\syst_boxes_lower_finish
  {\boxyoffset\nextbox-\scratchdimen
   \ht\nextbox\strutht
   \dp\nextbox\strutdp
   \box\nextbox
   \egroup}

% vcenter in text, we kunnen vcenter overloaden

\permanent\protected\def\halfwaybox
  {\hpack\bgroup
   \dowithnextboxcs\syst_boxes_halfwaybox_finish\hbox}

\def\syst_boxes_halfwaybox_finish
  {\dp\nextbox\zeropoint
   \lower.5\ht\nextbox\box\nextbox
   \egroup}

\permanent\protected\def\depthonlybox
  {\tpack\bgroup
   \dowithnextboxcs\syst_boxes_depthonlybox_finish\vbox}

\def\syst_boxes_depthonlybox_finish
  {\hsize\wd\nextbox
   \kern\zeropoint\box\nextbox
   \egroup}

%D New:

\permanent\def\setdimentoatleast#1#2{\ifdim#1>\zeropoint\else#1=#2\fi}
\permanent\def\setdimentoatmost #1#2{\ifdim#1>#2\relax  \else#1=#2\fi}

%D And even rawer:

\aliased\let\naturalvcenter\normalvtop % will go away

% \appendtoks \let\vcenter\normalvcenter \to \everymathematics

%D \macros
%D   {frozenhbox}
%D
%D A not so well unhboxable box can be made with:

\permanent\protected\def\frozenhbox
  {\hpack\bgroup
   \dowithnextboxcs\syst_boxes_frozenhbox_finish\hbox}

\def\syst_boxes_frozenhbox_finish
  {\hpack{\hpack{\box\nextbox}}%
   \egroup}

%D \macros
%D   {setboxllx,setboxlly,gsetboxllx,gsetboxlly,getboxllx,getboxlly}
%D
%D A prelude to an extended \TEX\ feature:

\installcorenamespace {box_x}
\installcorenamespace {box_y}

\permanent\protected\def\setboxllx #1#2{\edefcsname\??box_x\number#1\endcsname{\todimension{#2}}}
\permanent\protected\def\setboxlly #1#2{\edefcsname\??box_y\number#1\endcsname{\todimension{#2}}}

\permanent\protected\def\gsetboxllx#1#2{\xdefcsname\??box_x\number#1\endcsname{\todimension{#2}}}
\permanent\protected\def\gsetboxlly#1#2{\xdefcsname\??box_y\number#1\endcsname{\todimension{#2}}}

\permanent\def\getboxllx#1{\ifcsname\??box_x\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
\permanent\def\getboxlly#1{\ifcsname\??box_y\number#1\endcsname\lastnamedcs\else\zeropoint\fi}

\permanent\def\directgetboxllx#1{\csname\??box_x\number#1\endcsname} % use when sure existence
\permanent\def\directgetboxlly#1{\csname\??box_y\number#1\endcsname} % use when sure existence

%D \macros
%D   {shownextbox}
%D
%D Handy for tracing
%D
%D \starttyping
%D \shownextbox\vbox{test}
%D \shownextbox\vbox{test\endgraf}
%D \shownextbox\vbox{test\endgraf\strut\endgraf}
%D \shownextbox\vbox{test\endgraf\thinrule}
%D \shownextbox\vbox{\setupwhitespace[big]test\endgraf\thinrule}
%D \stoptyping

\permanent\protected\def\shownextbox % seldom used
  {\dowithnextbox
     {\bgroup
      \showboxbreadth\maxcount
      \showboxdepth  \maxcount
      \scratchcounter\interactionmode
      \batchmode
      \showbox\nextbox
      \box\nextbox
      \interactionmode\scratchcounter
      \egroup}}

\permanent\protected\def\spreadhbox#1% rebuilds \hbox{<box><hss><box><hss><box>}
  {\bgroup
   \ifhbox#1\relax
     \setbox\scratchboxtwo\emptybox
     \unhbox#1%
     \doloop
       {\unpenalty\unskip\unpenalty\unskip\unpenalty\unskip
        \setbox\scratchboxone\lastbox
        \ifvoid\scratchboxone
          \exitloop
        \else
          \setbox\scratchboxtwo\hbox
            {\ifhbox\scratchboxone \spreadhbox\scratchboxone\else\box\scratchboxone\fi
             \ifvoid\scratchboxtwo \else\hss\unhbox\scratchboxtwo\fi}%
        \fi}%
     \ifvoid\scratchboxtwo\else\unhbox\scratchboxtwo\fi
   \else
     \box#1%
   \fi
   \egroup}

% \showboxbreadth\plusthousand
% \showboxdepth  \plusthousand

%D Moved from cont-new:
%D
%D \starttyping
%D \minimalhbox 100pt {test}
%D \stoptyping

\permanent\protected\def\minimalhbox#1#%
  {\dowithnextbox
     {\bgroup
      \setbox\scratchbox\hpack#1{\hss}%
      \ifdim\wd\nextbox<\wd\scratchbox\wd\nextbox\wd\scratchbox\fi
      \box\nextbox
      \egroup}
     \hbox}

%D A bit dirty:

% \permanent\protected\def\nodestostring#1#2% more tolerant for #2=\cs
%   {\begingroup
%    \setbox\nextbox\hbox{#2}%
%    \expanded{\endgroup\edef\noexpand#1{\boxtostring\nextbox}}}
%
% \permanent\def\tostring
%   {\beginlocalcontrol
%    \dowithnextbox{\endlocalcontrol\boxtostring\nextbox}\hbox}
%
% \permanent\def\tostring
%   {\beginlocalcontrol\begingroup
%    \dowithnextbox{\expanded{\endgroup\endlocalcontrol\boxtostring\nextbox}}\hbox}

\def\syst_boxes_contenttostring
  {\expanded{\endgroup\endlocalcontrol\boxtostring\nextbox}}

\permanent\def\contenttostring
  {\beginlocalcontrol\begingroup
   \dowithnextboxcs\syst_boxes_contenttostring\hbox}

\newtoks \everypreroll
\newif   \ifprerolling

\appendtoks
    \prerollingtrue
\to \everypreroll

\let\prerolltostring\firstofoneargument % we need to bypass initializations

% This fails on an empty document (probably some mode issue):

% \appendtoks
%     \permanent\def\prerolltostring
%       {\beginlocalcontrol\begingroup
%        \expand\everypreroll
%        \dowithnextboxcs\syst_boxes_contenttostring\hbox}
% \to \everydump
%
% So we do this instead:

\newbox\b_syst_boxes

\appendtoks
    \permanent\def\prerolltostring#1%
      {\beginlocalcontrol
       \setbox\b_syst_boxes\hbox{\expand\everypreroll#1}%
       \expanded
         {\setbox\b_syst_boxes\emptybox
          \endlocalcontrol
          \boxtostring\b_syst_boxes}}
\to \everydump

% depricated:

\permanent\protected\def\nodestostring#1#2% more tolerant for #2=\cs
  {\edef#2{\contenttostring{#1}}}

%D Even more dirty:

\aliased\let\hyphenatedhbox\hbox % was a macro in mkii

%D We can do this:
%D
%D \starttyping
%D \setbox0\hbox to 10cm{foo} \setbox2\hbox{\unhbox0} \the\wd2
%D \stoptyping
%D
%D But this saves a copy (and hpack pass):
%D
%D \starttyping
%D \setbox0\hbox to 10cm{foo} \the\naturalwd0
%D \stoptyping

% \newdimension\lastnaturalboxwd
% \newdimension\lastnaturalboxht
% \newdimension\lastnaturalboxdp

%D We can define these public in lua:

% \aliased\let\getnaturaldimensions\clf_getnaturaldimensions % sets three dimensions
% \aliased\let\naturalwd           \clf_naturalwd            % calculates and returns wd

% \aliased\let\getnaturalwd\clf_getnaturalwd % no intermediate
% \aliased\let\setnaturalwd\clf_setnaturalwd % no intermediate

\permanent\protected\def\doifelserighttoleftinbox{\clf_doifelserighttoleftinbox}

\aliased\let\doifrighttoleftinboxelse\doifelserighttoleftinbox

%D New, used in high/low:

\definesystemattribute [runningtext] [public]

\permanent\protected\def\runninghbox{\hbox attr \runningtextattribute \fontid\font} % not yet in i-*

%D To complement lua (yet undocumented):

\permanent\protected\def\beginhbox{\hbox\bgroup}  \aliased\let\endhbox\egroup
\permanent\protected\def\beginvbox{\vbox\bgroup}  \aliased\let\endvbox\egroup
\permanent\protected\def\beginvtop{\vtop\bgroup}  \aliased\let\endvtop\egroup

\permanent\protected\def\sethboxregister#1{\setbox#1\hbox}
\permanent\protected\def\setvboxregister#1{\setbox#1\vbox}
\permanent\protected\def\setvtopregister#1{\setbox#1\vtop}

\permanent\protected\def\flushboxregister#1{\box\numexpr#1\relax}

\permanent\protected\def\starthboxregister#1{\setbox#1\hbox\bgroup}  \aliased\let\stophboxregister\egroup
\permanent\protected\def\startvboxregister#1{\setbox#1\vbox\bgroup}  \aliased\let\stopvboxregister\egroup
\permanent\protected\def\startvtopregister#1{\setbox#1\vtop\bgroup}  \aliased\let\stopvtopregister\egroup

% %D For whatever third party package needs it:
% %D
% %D \starttyping
% %D \newlocalbox\BoxOne
% %D \newlocalbox\BoxTwo
% %D
% %D \setbox\BoxOne\hbox{Box One}
% %D \setbox\BoxTwo\hbox{Box Two}
% %D
% %D [\box\BoxTwo] [\box\BoxOne]
% %D \stoptyping
%
% \installcorenamespace{localbox}
%
% \permanent\protected\def\newlocalbox#1%
%   {\expandafter\let\expandafter#1\csname\??localbox\string#1\endcsname
%    \ifrelax#1%
%      \syst_aux_new_localbox#1%
%    \fi}
%
% \def\syst_aux_new_localbox#1%
%   {\expandafter\newbox\csname\??localbox\string#1\endcsname
%    \newlocalbox#1}

%D Who knows when this comes in handy:

%permanent\protected\def\lastlinewidth{\dimexpr\clf_lastlinewidth\scaledpoint\relax} % at lua end

%D Keep as reference:

% \protected\def\tightvbox{\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\vbox}
% \protected\def\tightvtop{\dowithnextbox{\ht\nextbox\zeropoint\box\nextbox}\vtop}

%D This one keeps dimensions and sets the shift field (and so it's more for testing
%D than for real usage):

%permanent\protected\def\shiftbox  {\clf_shiftbox}
            \aliased\let\shiftbox       \boxshift

\permanent\protected\def\vpackbox  {\clf_vpackbox}
\permanent\protected\def\hpackbox  {\clf_hpackbox}
\permanent\protected\def\vpackedbox{\clf_vpackedbox}
\permanent\protected\def\hpackedbox{\clf_hpackedbox}

%D This one has been moved from a 2 decade old file. It makes something boxed
%D sit on the baseline.

\permanent\protected\def\linebox
  {\hpack\bgroup\dowithnextbox
     {\scratchdimen{(\htdp\nextbox-\lineheight)/2+\strutdp}%
      \setbox\nextbox\hpack{\lower\scratchdimen\box\nextbox}%
      \ht\nextbox\strutht
      \dp\nextbox\strutdp
      \box\nextbox
      \egroup}
     \hbox}

%D \macros
%D   {widthuptohere}
%D
%D Implemented at the \LUA\ end:
%D
%D \startbuffer
%D widthuptohere:\the\widthuptohere\crlf
%D widthuptohere : \the\widthuptohere (space without stretch or shrink!)
%D \stopbuffer
%D
%D \typebuffer \blank \getbuffer \blank
%D
%D Implemented elsewhere:
%D
%D \starttyping
%D \boxlines    <box>
%D \boxline     <box> <line>
%D \copyboxline <box> <line>
%D \setboxline  <box> <line>
%D \boxlineht   <box> <line> [<dimen>]
%D \boxlinedp   <box> <line> [<dimen>]
%D \boxlinewd   <box> <line> [<dimen>]
%D \boxlinels   <box> <line>
%D \boxliners   <box> <line>
%D \boxlinelh   <box> <line>
%D \boxlinerh   <box> <line>
%D \boxlinelp   <box> <line>
%D \boxlinerp   <box> <line>
%D \boxlinein   <box> <line>
%D \boxrangeht  <box> <first line> <last line>
%D \boxrangedp  <box> <first line> <last line>
%D \boxrangewd  <box> <first line> <last line>
%D \stoptyping

% To be discussed with ws.
%
% \installcorenamespace{namedboxes}
%
% \protected\def\newnamedbox#1%
%   {\ifcsname\??namedboxes#1\endcsname\else
%      \expandafter\newbox\csname\??namedboxes#1\endcsname
%    \fi}
%
% \protected\def\namedbox#1{\csname\??namedboxes#1\endcsname}

%D Implemented elsewhere:
%D
%D \startbuffer
%D \setbox0\hbox{test \footnote{test}} (\prelistbox0) (\postlistbox0)
%D \setprelistbox0\hbox{BEFORE} \setpostlistbox0\hbox{AFTER}
%D \box0
%D \stopbuffer
%D
%D \typebuffer \blank \getbuffer \blank
%D
%D \starttyping
%D \prelistbox     <box>
%D \postlistbox    <box>
%D \prelistcopy    <box>
%D \postlistcopy   <box>
%D \setprelistbox  <box> <hbox|vbox|vtop|somebox>
%D \setpostlistbox <box> <hbox|vbox|vtop|somebox>
%D \stoptyping

%D Defined in lua:
%D
%D setsplitlisthtdp\scratchbox\struthp\strutdp

%D Handy but I'll probably forget it:
%D
%D \starttyping
%D \setbox0\hbox{!!!!!}
%D \showbox     0
%D \showboxhere 0 % always on console, less clutter
%D \stoptyping

\untraced\permanent\protected\def\showboxhere{\showbox nolevels content online all }

% % possible extra interface, currently disabled
%
% \permanent\tolerant\protected\def\registeranchorbox[#1]#*[#2]%
%   {\dowithnextbox
%      {\clf_registeranchorbox
%         \namedboxanchor{#1}%
%         \ifcstok{#2}\v!before\minusone\else\plusone\fi
%         \box\nextbox}}

%D \macros{doifelseindented}
%D
%D This test macro is defined at the \LUA\ end:
%D
%D \startbuffer
%D test \doifelseindented{yes}{nop} test\par
%D \setupindenting[3em] \indenting[yes]
%D test \doifelseindented{yes}{nop} test\par
%D \stopbuffer
%D
%D \typebuffer \blank \startpacked \getbuffer \stoppacked \blank

% \definedasluacommand\noflinesinbox

%D \macros{boxfixstretch}
%D
%D This is relative new one and a wrapper around \typ {\boxlimitate} but with a
%D criterium.
%D
%D \startbuffer
%D \setbox2\copy0 \boxfixstretch 20pt      2 \box2
%D \setbox2\copy0 \boxfixstretch 30pt      2 \box2
%D \setbox2\copy0 \boxfixstretch 40pt      2 \box2
%D \setbox2\copy0 \boxfixstretch  0pt      2 \box2 % \boxlimitate 2 0pt
%D \setbox2\copy0 \boxfixstretch \maxdimen 2 \box2
%D \stopbuffer
%D
%D \setbox0\ruledvbox to 2cm \bgroup
%D     test\vskip10pt plus 10pt minus 5pt\relax test%
%D \egroup
%D
%D \startlinecorrection
%D \getbuffer
%D \stoplinecorrection
%D
%D \setbox0\ruledhbox to 3cm \bgroup
%D     test\hskip10pt plus 10pt minus 5pt\relax test%
%D \egroup \getbuffer
%D
%D \startlinecorrection
%D \getbuffer
%D \stoplinecorrection

\newconditional\boxstretchfixed
\newdimension  \boxstretchdelta

\permanent\protected\def\boxfixstretch
  {\begingroup
   \afterassignment\syst_boxes_fixstretch_a\scratchdimen}

\permanent\protected\def\syst_boxes_fixstretch_a
  {\afterassignment\syst_boxes_fixstretch_b\scratchcounter}

\permanent\protected\def\syst_boxes_fixstretch_b
  {\scratchdimenone  \ifvbox\scratchcounter\ht\else\wd\fi\scratchcounter % current size
   \scratchdimentwo  \boxrepack\scratchcounter                           % natural
   \scratchdimenthree\boxstretch\scratchcounter                          % stretch
   \scratchdistance  {\scratchdimenone-\scratchdimentwo}%
   % if size - natural > stretch
   \unless\ifdim\scratchdistance>\scratchdimenthree
     % we don't stretch beyond what is acceptable
     \global\boxstretchfixed\conditionalfalse
     \global\boxstretchdelta\zeropoint
   \orelse\ifdim\scratchdistance>\scratchdimen
     % we are below the criterium
     \boxlimitate\scratchcounter\zerocount
     \global\boxstretchfixed\conditionaltrue
     \global\boxstretchdelta{\ifvbox\scratchcounter\ht\else\wd\fi\scratchcounter-\boxrepack\scratchcounter}%
   \else
     % we are above the criterium
     \global\boxstretchfixed\conditionalfalse
     \global\boxstretchdelta\zeropoint
   \fi
% \writestatus{PAGE}{stretch:#L
%   size \the\scratchdimenone,#L
%   natural \the\scratchdimentwo,#L
%   stretch \the\scratchdimenthree,#L
%   distance \the\scratchdistance,#L
%   criterium \the\scratchdimen,#L
%   fixed case
%    \unless\ifdim\scratchdistance>\scratchdimenthree
%      1:false,#L
%    \orelse\ifdim\scratchdistance<\scratchdimen
%      2:true,#L
%    \else
%      4:false,#L
%    \fi
%    delta \the\boxstretchdelta
% }%
   \endgroup}

%D Just in case:
%D
%D \starttyping
%D \vreflected{±}
%D \stoptyping

\permanent\protected\def\vreflected
  {\dontleavehmode
   \dowithnextbox{\hpack \s!orientation "712 \s!swap{\box\nextbox}}\hbox}

\protect \endinput

% alternative

% \newdimension\d_syst_boxes_target_size
% \newdimension\d_syst_boxes_natural_size
% \newdimension\d_syst_boxes_stretch
% \newdimension\d_syst_boxes_available
% \newdimension\d_syst_boxes_limit
%
% \permanent\protected\def\boxfixstretch
%   {\begingroup
%    \afterassignment\syst_boxes_fixstretch_a\d_syst_boxes_limit}
%
% \permanent\protected\def\syst_boxes_fixstretch_a
%   {\afterassignment\Xsyst_boxes_fixstretch_b\scratchcounter}
%
% \permanent\protected\def\syst_boxes_fixstretch_b
%   {\d_syst_boxes_target_size \ifvbox\scratchcounter\ht\else\wd\fi\scratchcounter % current size
%    \d_syst_boxes_natural_size\boxrepack\scratchcounter                           % natural
%    \d_syst_boxes_stretch     \boxstretch\scratchcounter                          % stretch
%    \d_syst_boxes_available   \dimexpr\d_syst_boxes_target_size-\d_syst_boxes_natural_size\relax
%    \ifdim\d_syst_boxes_available>\d_syst_boxes_stretch
%      % we don't stretch beyond what is acceptable
% %      \boxlimitate\scratchcounter\zerocount
%      \boxfinalize\scratchcounter-1000
% % \boxfreeze\scratchcounter1
%      \global\boxstretchfixed\conditionalfalse
%      \global\boxstretchdelta\zeropoint
%    \orelse\ifdim\d_syst_boxes_available>\d_syst_boxes_limit
%      % we are below the criterium
% %      \boxfinalize\scratchcounter1000
% \boxfreeze\scratchcounter\zerocount
% % \boxfreeze\scratchcounter1
% % \boxlimitate\scratchcounter\zerocount
%      \global\boxstretchfixed\conditionaltrue
%      \global\boxstretchdelta\dimexpr\ifvbox\scratchcounter\ht\else\wd\fi\scratchcounter-\boxrepack\scratchcounter\relax
%    \else
%      % we are above the criterium
%      \global\boxstretchfixed\conditionalfalse
%      \global\boxstretchdelta\zeropoint
%    \fi
% % \writestatus{PAGE}{%
% %   page      \the\realpageno,#L
% %   size      \the\d_syst_boxes_target_size,#L
% %   natural   \the\d_syst_boxes_natural_size,#L
% %   stretch   \the\d_syst_boxes_stretch,#L
% %   distance  \the\d_syst_boxes_available,#L
% %   criterium \the\d_syst_boxes_limit,#L
% %   fixed case
% %    \unless\ifdim\d_syst_boxes_available>\d_syst_boxes_stretch
% %             1:false,#L
% %    \orelse\ifdim\d_syst_boxes_available>\d_syst_boxes_limit
% %             2:true,#L
% %    \else
% %             4:false,#L
% %    \fi
% %    delta    \the\boxstretchdelta
% % }%
%    \endgroup}

% a bit of test code:

% \hbox \bgroup
%     \ruledvbox                {\hbox{\strut gans}}
%     \ruledvbox to \lineheight {\hbox{\strut gans}}
%     \ruledvbox to \lineheight {\hbox       {gans}}
%     \ruledvbox to \strutheight{\hbox       {gans}}
%     \ruledvbox to \strutheight{\hbox{\strut gans}}
%     \ruledvbox to \strutheight{\vss\hbox{gans}}
% \egroup

% to be considered

% \startluacode
%
%     local spacer = lpeg.patterns.spacer
%
%     function commands.withwords(command,str)
%         if str then
%             command = command or "ruledhbox"
%             local done = false
%             local function apply(s)
%                 if done then
%                     context.space()
%                     done = true
%                 else
%                     context.dontleavehmode()
%                 end
%                 context[command](s)
%             end
%             lpeg.match(lpeg.splitter(spacer,apply),str)
%         end
%
%     end
%
% \stopluacode
%
% \unprotect
%
% \protected\def\withwordsinstring#1#2% command str
%   {\ctxcommand{withwords(\!!bs#1\!!es,\!!bs#2\!!es)}}
%
% \protected\def\withwordsinfile#1#2% command name
%   {\ctxcommand{withwords(\!!bs#1\!!es,io.loaddata(resolvers.findfile("#2")))}}
%
% \protect
%
% \starttext
%
%     \defineframed[colored][foregroundcolor=red,foregroundstyle=\bfc\underbar,location=low]
%
%     \withwordsinstring{colored}{bla bla}
%     \withwordsinfile{colored}{ward.tex}
%
% \stoptext