%D \module
%D   [       file=supp-mrk,
%D        version=1995.10.10,
%D          title=\CONTEXT\ Support Macros,
%D       subtitle=Marks,
%D         author=Jim Fox / Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for 
%C details. 

%D Remark: due to the lack of \type {\clearmark}, the \ETEX\ 
%D dedicated mechanism is not yet operational. 

% for testing etex, can be much faster than normal  
%
% \unprotect 
% 
% \newif\ifexpandmarks   \expandmarkstrue
% 
% \let\normalmark            = \mark
% \let\normaltopmark         = \topmark
% \let\normalbotmark         = \botmark
% \let\normalfirstmark       = \firstmark
% \let\normalsplitbotmark    = \splitbotmark
% \let\normalsplitfirstmark  = \splitfirstmark
% 
% \let\normalmarks           = \marks
% \let\normaltopmarks        = \topmarks
% \let\normalbotmarks        = \botmarks
% \let\normalfirstmarks      = \firstmarks
% \let\normalsplitbotmarks   = \splitbotmarks
% \let\normalsplitfirstmarks = \splitfirstmarks
% 
% \def\newmark         #1{\setgvalue{mrk\strippedcsname#1}{0}\newmarks#1}
% 
% \def\gettopmark        {\getmark\topmarks}
% \def\getbottommark     {\getmark\botmarks}
% \def\getfirstmark      {\getmark\firstmarks}
% \def\getsplitbottommark{\getmark\splitbotmarks}
% \def\getsplitfirstmark {\getmark\splitfirstmarks}
% 
% \def\getbotmark        {\getmark\botmarks}
% \def\getsplitbotmark   {\getmark\splitbotmarks}
% \def\getsplittopmark   {\getmark\splitfirstmarks}
% 
% \def\getmark#1#2%
%   {\ifcase\csname mrk\strippedcsname#2\endcsname\else
%      \expandafter#1\expandafter#2%
%    \fi}
% 
% \long\def\setmark#1#2%
%   {\setgvalue{mrk\strippedcsname#1}{0}%
%    \ifexpandmarks
%      \expanded{\normalmarks#1{#2}}%
%    \else
%      \normalmarks#1{#2}%
%    \fi}
% 
% \def\resetmark#1% 
%   {\setgvalue{mrk\strippedcsname#1}{1}\marks#1{}}
% 
% \def\noninterferingmarks%
%   {\let\savedsetmark\setmark
%    \let\noninterferingmarks\relax
%    \long\def\setmark##1##2%
%      {\ifhmode\prewordbreak\hbox\fi{\savedsetmark{##1}{##2}}}}
% 
% \let\getmarks        \gobbleoneargument
% \let\getallmarks     \relax
% \let\getsplitmarks   \gobbleoneargument
% \let\getallsplitmarks\relax
% 
% \let\newpersistentmark \newmark          % checken
% \newif\ifnofirstmarker                   % checken
% 
% \protect \endinput 

%D There are 256 \COUNTERS, \DIMENSIONS, \SKIPS, \MUSKIPS\ and
%D \BOXES, 16~in- and output buffers, but there is only one
%D \MARK. In TugBoat~8 (1987, no~1) Jim Fox presents a set of
%D macros that can be used to mimmick multiple marks. We
%D gladly adopt them here. I may rewrite this module from 
%D scratch some day, since some low level \CONTEXT\ commands
%D can be used.  
%D
%D This module was changed on behalf of \ETEX. The main
%D extension is that \type{\get..} and alike is used instead of
%D direct calls. The \TEX\ based multiple marks needs to store
%D the mark data but \ETEX\ uses a different approach.

\writestatus{loading}{Context Support Macros / Marks}

\unprotect

%% \beginTEX

%D This implementation is more or less compatible with the
%D other \type {\new} macros in \PLAIN\ \TEX. A mark is
%D defined by:
%D
%D \starttypen
%D \newmark\name
%D \stoptypen
%D
%D and can be called upon with:
%D
%D \starttypen
%D \gettopmark  \name  % or \topname
%D \getbotmark  \name  % or \botname
%D \getfirstmark\name  % or \firstname
%D \stoptypen
%D
%D The only drawback of his approach is that the marks must be
%D preloaded in the output routine. This is accomplished by
%D means of:
%D
%D \starttypen
%D \getmarks\name
%D \stoptypen
%D
%D The macros presented here are in most aspects copies of
%D those presented by Jim Fox. We've taken the freedom to
%D change a few things for more or less obvious reasons:
%D
%D \startopsomming
%D \som  Because the original macros look quite complicated,
%D       which is mainly due to extensive use of
%D       \type{\expandafter}'s and \type{\csname}'s, we changed
%D       those in favor of \type{\getvalue}.
%D \som  To be more in line with the rest of \CONTEXT, we've
%D       changed some of the names of macros.
%D \som  Because we are already short on \COUNTERS\ we use
%D       macros when possible.
%D \som  We maintain a list of defined marks and use one
%D       call for getting them all at once.
%D \som  We have extended the mechanism to splitmarks (not
%D       perfected yet).
%D \som  We've introduced optional expansion of the contents
%D       of marks.
%D \stopopsomming
%D
%D Whatever changes we've made, the credits still go to Jim,
%D whatever goes wrong is due to me. The method is described
%D in the TugBoat mentioned before, so we won't go into
%D details. All marks belonging to a group are packed in a
%D list. In this list they are preceded by a macro that can
%D be defined at will and a number concerning the position at
%D which it was defined.
%D
%D \starttypen
%D \def\somelist{... \domark5{this} ... \domark31{that} ...}
%D \stoptypen
%D
%D The original \type{\mark} keeps track of the number and
%D \type{\topmark} and \type{\botmark} are used to extract the
%D actual marks from the list. The counting is done by
%D
%D \starttypen
%D \currentmarker
%D \stoptypen
%D
%D In \CONTEXT\ we use the mark mechanism to keep track of
%D colors. In a complicated documents with many colors per
%D page, \type{\currentmarker} can therefore get pretty high.
%D (Well, this is not completely true, because we don't
%D always have to use marks.)

\newcount\currentmarker

%D The original implementation used a few more \COUNTERS. Two
%D have been substituted by macros, one has been replaced by
%D our scratch counter.
%D
%D \starttypen
%D % \newcount\topmarker
%D % \newcount\botmarker
%D % \newcount\foundmarker
%D \stoptypen
%D
%D We've also introduced some constants, one for the lists and
%D three for composing the mark commands.

\def\@@marklist@@  {marklist}
\def\@@marktop@@   {top}
\def\@@markbot@@   {bot}
\def\@@markfirst@@ {first}

%D The next one is new too. All defined marks are packed in a
%D comma seperated list. This could of course have been a token
%D list but \CONTEXT\ has some preference for comma lists.

\let\allmarks=\empty

%D \macros
%D   {expandmarks}
%D
%D There are two booleans. The first one handles the first
%D marks, the second concerns expansion. This second one is
%D new.

\newif\ifnofirstmarker
\newif\ifexpandmarks     \expandmarkstrue

%D We use an indirect call to the mark mechanism.

\let\normalmark           = \mark
\let\normaltopmark        = \topmark
\let\normalbotmark        = \botmark
\let\normalfirstmark      = \firstmark
\let\normalsplitbotmark   = \splitbotmark
\let\normalsplitfirstmark = \splitfirstmark

%D The next macro replaces the multiple step expansion and
%D command name constructors of Jim. This alternative leads to
%D a more readable source (we hope).

\def\makemarknames#1%
  {\bgroup
   \escapechar=-1
   \xdef\markname{\string#1}%
   \xdef\marklist{\@@marklist@@\string#1}%
   \egroup}

%D \macros
%D   {newmark,resetmark}
%D
%D A mark is defined by \type{\newmark}. At the same time,
%D the name of the mark is added to a commalist. The
%D three initializations were not in the original design, but
%D make calls from outside the output routine a bit more
%D robust.

\let\domark\relax % saves a restore on the stack 

\def\definenewmark#1#2%
  {\bgroup
   \makemarknames{#1}%
   #2%
   \global\letvalue{\@@marktop@@  \markname}\empty
   \global\letvalue{\@@markfirst@@\markname}\empty
   \global\letvalue{\@@markbot@@  \markname}\empty
   \setgvalue{\marklist}{\domark0{}}% beware of halfway definitions
   \long\gdef#1{\addmarker#1}%
   \egroup}

\def\newmark#1%
  {\definenewmark#1{\doglobal\addtocommalist\markname\allmarks}}

\let\setmark\empty
\let\resetmark\newmark

%D Some more natural interfacing macros:

\def\gettopmark        #1{\getvalue{\@@marktop@@  \strippedcsname#1}}
\def\getbottommark     #1{\getvalue{\@@markbot@@  \strippedcsname#1}}
\def\getfirstmark      #1{\getvalue{\@@markfirst@@\strippedcsname#1}}
\def\getsplitbottommark#1{\getvalue{\@@markbot@@  \strippedcsname#1}}
\def\getsplitfirstmark #1{\getvalue{\@@markfirst@@\strippedcsname#1}}

\let\getbotmark     \getbottommark
\let\getsplitbotmark\getsplitbottommark
\let\getsplittopmark\getsplitfirstmark

%D Don't ask me, but sometimes we need more control over
%D updating the marks, thereby we have:

\def\newpersistentmark#1% for an example see core-grd.tex
  {\definenewmark#1\relax}

%D \macros
%D   {setmark}
%D
%D Setting a new mark and adding a mark to the designated
%D list is done by \type{\addmarker}. This is an internal
%D command, the user set a marks bij calling it's name:
%D
%D \starttypen
%D \setmark\mymark{some text} % or \mymark{some text}
%D \stoptypen
%D
%D Where \type{\mymark} is previously defined by
%D \type{\newmark}.

\long\def\addmarker#1#2%
  {\bgroup
   \makemarknames{#1}%
   \global\advance\currentmarker by 1
   \normalmark{\the\currentmarker}%
   \@EA\!!toksa\@EA=\@EA\@EA\@EA{\csname\marklist\endcsname}%
   \ifexpandmarks
     \setxvalue{\marklist}%
       {\the\!!toksa
        \noexpand\domark
        \the\currentmarker{#2}}%
   \else
     \!!toksb=\@EA{#2}% one level
     \setxvalue{\marklist}%
       {\the\!!toksa
        \noexpand\domark
        \the\currentmarker{\the\!!toksb}}%
   \fi
   \egroup}

%D \macros
%D   {getmarks,getallmarks,
%D    getsplitmarks,getallsplitmarks}
%D
%D In fact, marks make only sense in the output routine. Marks
%D are derived from their list by means of \type{\getmarks}.
%D Only one call per mark is permitted in the output routine.
%D Therefore, it's far more easy to get them all at once, by
%D means of \type{\getallmarks}, which is not part of the
%D original design.
%D
%D This grabbing is done by processing the list using the
%D embedded \type{\domark} macros. When a relevant mark is
%D found, this macro is reassigned and from then on serves
%D in building the new list.

% Although the next couple of macros are already defined 
% in syst-gen.tex, we repeat them here. 

\let\normalfi   \fi    % replaces \@fi 
\let\normalelse \else  % replaces \@else
\let\normalor   \or    % replaces \@or 

\def\getmarks#1%
  {\bgroup
   \makemarknames{#1}%
   \edef\topmarker{0\normaltopmark}%
   \edef\botmarker{0\normalbotmark}%
   \!!toksb={}%
   \nofirstmarkertrue
   \let\fi=\relax
   \let\or=\relax
   \let\else=\relax
   \let\domark=\doscanmarks
   \getvalue{\marklist}\lastmark
   %\message{markstatus : [\the\!!toksa\the\!!toksb\the\!!toksc]}%
   \long\setxvalue{\marklist}{\the\!!toksa\the\!!toksb\the\!!toksc}%
   \egroup}

\def\getallmarks%
  {\processcommacommand[\allmarks]\getmarks}

\def\getsplitmarks#1%
  {\bgroup
   \makemarknames{#1}%
%   \@EA\let\@EA\savedmarklist\@EA=\csname\marklist\endcsname
   \edef\topmarker{0\normalsplitfirstmark}%
   \edef\botmarker{0\normalsplitbotmark}%
   \!!toksb={}%
   \nofirstmarkertrue
   \let\fi=\relax
   \let\or=\relax
   \let\else=\relax
   \let\domark=\doscanmarks
   \getvalue{\marklist}\lastmark
%   \@EA\global\@EA\let\csname\marklist\endcsname=\savedmarklist
   \egroup}

\def\getallsplitmarks%
  {\processcommacommand[\allmarks]\getsplitmarks}

\long\def\dodoscanmarks#1%
  {\ifnum\scratchcounter>\topmarker\relax
   \normalelse
     \long\setgvalue{\@@marktop@@\markname}{#1}%
   \normalfi
   \ifnum\scratchcounter>\botmarker\relax
     \let\domark=\dorecovermarks
     \!!toksb=\@EA{\@EA\domark\the\scratchcounter{#1}}%
   \normalelse
     \ifnofirstmarker
       \long\setgvalue{\@@markfirst@@\markname}{#1}%
       \ifnum\scratchcounter>\topmarker\relax
         \nofirstmarkerfalse
       \normalfi
     \normalfi
     \long\setgvalue{\@@markbot@@\markname}{#1}%
     \!!toksa=\@EA{\@EA\domark\the\scratchcounter{#1}}%
   \normalfi}

\def\doscanmarks%
  {\afterassignment\dodoscanmarks\scratchcounter=}

\long\def\dorecovermarks#1\lastmark%
  {\!!toksc={\domark#1}}

\def\lastmark%
  {\!!toksc={}}

%D \macros
%D   {noninterferingmarks}
%D
%D Marks can interfere badly with for instance postprocessing
%D paragraphs, for instance when we want to grab the last box
%D using \type {\lastbox}, when at the same time using colors.

\def\noninterferingmarks%
  {\let\savednormalmark\normalmark
   \let\noninterferingmarks\relax
   \def\normalmark##1%
     {\ifhmode\prewordbreak\hbox\fi{\savednormalmark{##1}}}}

%D This macro is for instance used in the inline headings
%D postprocessing, as needed when we want to make those
%D clickable.

%% \endTEX

\protect \endinput 

%D Right from the beginning, \CONTEXT\ supported more than one
%D mark, using an extended version of Jim Fox multiple mark
%D mechanism. In \ETEX\ we can however directly access more
%D marks than we will ever need.

\beginETEX \marks \topmarks \botmarks \firstmarks

\let\normalmark           = \mark
\let\normaltopmark        = \topmark
\let\normalbotmark        = \botmark
\let\normalfirstmark      = \firstmark
\let\normalsplitbotmark   = \splitbotmark
\let\normalsplitfirstmark = \splitfirstmark

\let\normalmarks\marks

%D The 100\% compatible solution is:
%D
%D \starttypen
%D \def\@@marktop@@        {top}
%D \def\@@markbot@@        {bot}
%D \def\@@markfirst@@      {first}
%D \def\@@marksplitbot@@   {splitbot}
%D \def\@@marksplitfirst@@ {splitfirst}
%D 
%D \def\newmark#1% temporary 5 \cs's, will be rewritten ; global needed
%D   {\newmarks#1%
%D    \setxvalue{\@@marktop@@       \strippedcsname#1}{\noexpand\topmarks  \the#1 }%
%D    \setxvalue{\@@markbot@@       \strippedcsname#1}{\noexpand\botmarks  \the#1 }%
%D    \setxvalue{\@@markfirst@@     \strippedcsname#1}{\noexpand\firstmarks\the#1 }%
%D    \setxvalue{\@@marksplitbot@@  \strippedcsname#1}{\noexpand\splitbotmarks  \the#1 }%
%D    \setxvalue{\@@marksplitfirst@@\strippedcsname#1}{\noexpand\splitfirstmarks\the#1 }%
%D    \xdef#1{\noexpand\donormalmarks{\the#1}}}
%D
%D \def\gettopmark        #1{\getvalue{\@@marktop@@       \strippedcsname#1}}
%D \def\getbottommark     #1{\getvalue{\@@markbot@@       \strippedcsname#1}}
%D \def\getfirstmark      #1{\getvalue{\@@markfirst@@     \strippedcsname#1}}
%D \def\getsplitbottommark#1{\getvalue{\@@marksplitbot@@  \strippedcsname#1}}
%D \def\getsplitfirstmark #1{\getvalue{\@@marksplitfirst@@\strippedcsname#1}}
%D
%D \def\getsplitmarks#1%
%D   {\setvalue{\@@markbot@@\strippedcsname#1}%
%D      {\getvalue{\@@marksplitbot@@\strippedcsname#1}}%
%D    \setvalue{\@@marktop@@\strippedcsname#1}%
%D      {\getvalue{\@@marksplitfirst@@\strippedcsname#1}}%
%D    \setvalue{\@@markfirst@@\strippedcsname#1}%
%D      {\getvalue{\@@marksplitfirst@@\strippedcsname#1}}}
%D
%D \def\noninterferingmarks%
%D   {\let\saveddonormalmarks\donormalmarks
%D    \let\noninterferingmarks\relax
%D    \long\def\donormalmarks##1##2%
%D      {\ifhmode\prewordbreak\hbox\fi{\saveddonormalmarks{##1}{##2}}}}
%D 
%D \long\def\donormalmarks#1#2%
%D   {\bgroup
%D    \scratchcounter=#1\relax
%D    \ifexpandmarks
%D      \expanded{\normalmarks\scratchcounter{#2}}%
%D    \else
%D      \normalmarks\scratchcounter{#2}%
%D    \fi
%D    \egroup}
%D
%D \let\setmark\empty
%D \def\resetmark#1{#1{}}
%D \stoptypen
%D
%D However, I prefer the less \type{\cs} hungry ones. Beware, 
%D these ones (and the next) do no longer support direct marks. 
%D 
%D \starttypen 
%D \newif\ifexpandmarks   \expandmarkstrue
%D 
%D \let\newmark           \newmarks
%D \let\gettopmark        \topmarks
%D \let\getbottommark     \botmarks
%D \let\getfirstmark      \firstmarks
%D \let\getsplitbottommark\splitbotmarks
%D \let\getsplitfirstmark \splitfirstmarks
%D 
%D \let\getbotmark        \botmarks
%D \let\getsplitbotmark   \splitbotmarks
%D \let\getsplittopmark   \splitfirstmarks
%D 
%D \long\def\setmark#1#2%
%D   {\ifexpandmarks
%D      \expanded{\normalmarks#1{#2}}%
%D    \else
%D      \normalmarks#1{#2}%
%D    \fi}
%D \stoptypen

%D Resetting marks in not compatible with the old method. 
%D Here a node is inserted, which can interfere badly. In 
%D fact, a real \type {\clearmarks\name} is needed. 
%D
%D \starttypen 
%D \def\resetmark#1% 
%D   {\marks#1{}}
%D \stoptypen

%D A possible macro solution is presented here. When discussing
%D \type {\clearmarks} on the \ETEX\ discussion list, Chris
%D Rowley suggested to use a reset flag. Although suitable, a
%D more natural low level solution would be better. So, for the
%D moment, we could end up with a solution similar to the macro 
%D based multiple marks as implemented before. Alas, this 
%D alternative is useless too, because it does not synchronize 
%D well with previous values. 

\def\@m@{@m@}

\def\newmark#1%
  {\newmarks#1%
   \expandafter\gdef\csname\@m@\number#1\endcsname{0}}

\long\def\setmark#1#2%
  {\expandafter\gdef\csname\@m@\number#1\endcsname{1}%
   \ifexpandmarks
     \expanded{\normalmarks#1{#2}}%
   \else
     \normalmarks#1{#2}%
   \fi}

\def\gettopmark        {\getsomemark\topmarks}
\def\getbottommark     {\getsomemark\botmarks}
\def\getfirstmark      {\getsomemark\firstmarks}
\def\getsplitbottommark{\getsomemark\splitbotmarks}
\def\getsplitfirstmark {\getsomemark\splitfirstmarks}

\def\getsomemark#1#2%
  {\ifnum\csname\@m@\number#2\endcsname=1 #1#2\fi}

\def\clearmarks#1%
  {\expandafter\gdef\csname\@m@\number#1\endcsname{0}}

\def\resetmark% 
  {\clearmarks}

\let\getbotmark      \getbottommark
\let\getsplitbotmark \getsplitbottommark
\let\getsplittopmark \getsplitfirstmark

%D Hm. 

\def\noninterferingmarks%
  {\let\savedsetmark\setmark
   \let\noninterferingmarks\relax
   \long\def\setmark##1##2%
     {\ifhmode\prewordbreak\hbox\fi{\savedsetmark{##1}{##2}}}}

\let\getmarks        \gobbleoneargument
\let\getallmarks     \relax
\let\getsplitmarks   \gobbleoneargument
\let\getallsplitmarks\relax

\let\newpersistentmark \newmark          % checken
\newif\ifnofirstmarker                   % checken

\endETEX

%D For those who want to know the story behind resetting 
%D marks, here are some examples of interference 
%D 
%D \startbuffer
%D \setbox0=\vbox{test}
%D \unvbox0\setbox0=\lastbox
%D \ruledhbox{\unhbox0}
%D \stopbuffer
%D
%D \typebuffer\blanko\haalbuffer\blanko
%D
%D \startbuffer
%D \setbox0=\vbox{test\normalmark{}}
%D \unvbox0\setbox0=\lastbox
%D \ruledhbox{\unhbox0}
%D \stopbuffer
%D
%D \typebuffer\blanko\haalbuffer\blanko
%D
%D \startbuffer
%D \setbox0=\vbox{test\hbox{\normalmark{}}}
%D \unvbox0\setbox0=\lastbox
%D \ruledhbox{\unhbox0}
%D \stopbuffer
%D
%D \typebuffer\blanko\haalbuffer\blanko
%D
%D \startbuffer
%D \setbox0=\vbox{test\vbox{\normalmark{}}}
%D \unvbox0\setbox0=\lastbox
%D \ruledhbox{\unhbox0}
%D \stopbuffer
%D
%D \typebuffer\blanko\haalbuffer\blanko

%D Because we used an indirect call to the mark mechanism 
%D we can redefine the original \type{\mark} command.

\beginTEX

\newmark\mark

\endTEX

%D One final advice. Use marks with care. When used in globally
%D assigned boxes, the list can grow quite big, and processing
%D can slow down considerably. This drawback is removed in 
%D \ETEX\ mode.  

\protect

\endinput
