%D \module
%D   [       file=supp-new,
%D        version=1997.01.03,
%D          title=\CONTEXT\ Support Macros,
%D       subtitle=New Ones,
%D         author=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 Code from this module will move. For instance to
%D syst-dat.tex (datastructures).

\unprotect

% moved from core-ntb

\def\v!oddeven#1{\ifodd#1\v!odd\else\v!even\fi}

% For myself

\newcount\nofprofiled

\def\profilemacro#1%
  {\nofprofiled\zerocount
   \letvalue{\string#1\string#1}#1%
   \appendtoks
     \normalwritestatus\m!systems{profile \string#1: \number\nofprofiled}%
   \to \everystoptext
   \unexpanded\def#1%
     {\global\advance\nofprofiled\plusone
      \csname\string#1\string#1\endcsname}}

% pretty ugly but fast

% \copycsname xxx\endcsname\csname ..\endcsname

\def\copycsname{\@EA\@EA\@EA\let\@EA\@EA\csname}

% \letcscsname    \crap               \csname ..\endcsname
% \letcsnamecs    \csname ..\endcsname\crap
% \letcsnamecsname\csname ..\endcsname\csname ..\endcsname

\def\letcscsname    {\@EA\let\@EA}
\def\letcsnamecs    {\@EA\let}
\def\letcsnamecsname{\@EA\@EA\@EA\let\@EA\@EA}

% another one, add an item to a commalist

\def\addvalue#1#2% cs item
  {\ifundefined{#1}\@EA\let\csname#1\endcsname\empty\fi
   \expanded{\addtocommalist{#2}\@EA\noexpand\csname#1\endcsname}}

% faster, and looks okay

\dostepwiserecurse{0}{255}{1}
  {\@EA\chardef\csname-\recurselevel\endcsname\recurselevel}

\newtoks\withminorcharacters
\newtoks\withlowercharacters
\newtoks\withuppercharacters

% \thewithcharacter#1 % self

\dostepwiserecurse{0}{31}{1}
  {\expanded
     {\appendtoks\noexpand\withcharacter\csname-\recurselevel\endcsname
        \noexpand\to\withminorcharacters}}

\dostepwiserecurse{32}{127}{1}
  {\expanded
     {\appendtoks\noexpand\withcharacter\csname-\recurselevel\endcsname
        \noexpand\to\withlowercharacters}}

\dostepwiserecurse{128}{255}{1}
  {\expanded
     {\appendtoks\noexpand\withcharacter\csname-\recurselevel\endcsname
        \noexpand\to\withuppercharacters}}

\def\doassigncatcodes#1%
  {\def\withcharacter##1{\catcode##1#1}%
   \the\withminorcharacters
   \the\withlowercharacters
   \ifeightbitcharacters\the\withuppercharacters\fi}

\def\makeallother
  {\doassigncatcodes\@@other}

\chardef\obeyedlccode=`. % so <32 and >127 chars become .

% \def\obeylccodes
%   {\def\withcharacter##1{\lccode##1##1}%
%    \the\withlowercharacters
%    \def\withcharacter##1{\lccode##1\obeyedlccode}%
%    \the\withminorcharacters
%    \ifeightbitcharacters\the\withuppercharacters\fi}

\def\setownlccode   #1{\lccode#1#1}
\def\setobeyedlccode#1{\lccode#1\obeyedlccode}

\def\obeylccodes % also eightbitcharacters
  {\let\withcharacter\setownlccode
   \the\withlowercharacters
   \let\withcharacter\setobeyedlccode
   \the\withminorcharacters
   \the\withuppercharacters
   \relax}

\def\retainlccodes % also eightbitcharacters
  {\let\withcharacter\setownlccode
   \the\withlowercharacters
   \the\withminorcharacters
   \the\withuppercharacters
   \relax}

% not faster
%
% \newtoks \retainedlccodes
% \dostepwiserecurse{0}{255}{1}
%   {\appendetoks\lccode\recurselevel=\recurselevel\to\retainedlccodes}
% \appendetoks\relax\to\retainedlccodes

%D This one is much faster in \ETEX. Hm, I misinterpreted
%D the specs; it does not work.
%
% \ifx\normallanguage\undefined \let\normallanguage\language \fi
% \let\doobeylccodes\obeylccodes
%
% \beginETEX \lccode
%   \begingroup
%     \normallanguage\zerocount
%     \doobeylccodes
%     \patterns{dummy}
%   \endgroup
%   \def\obeylccodes{\normallanguage\zerocount}
% \endETEX

\def\unspaced#1%
  {\dounspaced#1\end}

\def\dounspaced#1%
  {\ifx#1\end
     \@EA\gobbleoneargument
   \else
     \ifx#1\blankspace\else#1\fi
   \fi
   \dounspaced}

\def\unspaceargument#1\to#2%
  {\convertargument#1\to#2%
   \@EA\edef\@EA#2\@EA{\@EA\unspaced\@EA{#2}}}

\def\unspaceafter#1#2%
  {\edef\ascii{\dounspaced#2\end}\@EA#1\@EA{\ascii}}

% etex, much faster
%
% \def\unspaceargument#1\to#2%
%   {\scratchcounter\catcode'32\catcode32=\@@ignore
%    \scantokens{\edef#2{#1}}%
%    \catcode32=\scratchcounter}

\def\unspaceafter#1#2%
  {\edef\ascii{\dounspaced#2\end}\@EA#1\@EA{\ascii}}

% this will replace loadfile once and alike !!! todo

\def\@flg@{@flg@}

\def\setflag#1%
  {\@EA\dodoglobal\@EA\chardef\csname\@flg@#1\endcsname\zerocount}

\def\resetflag#1%
  {\@EA\dodoglobal\@EA\chardef\csname\@flg@#1\endcsname\plusone}

\let\ifflagged\ifcase

\def\flag#1{\csname\@flg@#1\endcsname}

\def\doifelseflagged#1%
  {\@EA\ifx\csname\@flg@#1\endcsname\relax
     \@EA\secondoftwoarguments
   \else\ifcase\csname\@flg@#1\endcsname
     \@EAEAEA\firstoftwoarguments
   \else
     \@EAEAEA\secondoftwoarguments
   \fi\fi}

\def\doifnotflagged#1%
  {\@EA\ifx\csname\@flg@#1\endcsname\relax
     \@EA\firstofoneargument
   \else\ifcase\csname\@flg@#1\endcsname
     \@EAEAEA\gobbleoneargument
   \else
     \@EAEAEA\firstofoneargument
   \fi\fi}

\def\inheritparameter[#1]#2[#3]#4[#5]% tag tokey fromkey % [bypasses k!prefix]
  {\@EAEAEA\def\@EA\csname\@EA#1\@EA#3\@EA\endcsname\@EA
     {\csname#1#5\endcsname}}

% \buildarray[test][aa,bb,cc,dd,ee,ff]
% \setarrayelement{test}{1}{qq}
% \arrayelement{test}{1}
% \arraylength{test}
%
% \def\buildarray[#1][#2]%
%   {\scratchcounter=0
%    \def\docommando##1%
%      {\advance\scratchcounter by 1
%       \setvalue{@@aa#1\the\scratchcounter}{##1}}%
%    \processcommalist[#2]\docommando
%    \setevalue{@@aa#1}{\the\scratchcounter}}%
%
% \def\setarrayelement#1#2{\setvalue{@@aa#1#2}}
% \def\arrayelement   #1#2{\getvalue{@@aa#1#2}}
% \def\arraylength      #1{\getvalue{@@aa#1}}

% \newsignal\junksignal
%
% \def\setjunksignal%
%   {\ifhmode
%      \hskip\junksignal
%      \let\removejunkspaces\doremovejunkspaces
%    \else
%      \let\removejunkspaces\relax
%    \fi}
%
% \def\doremovejunkspaces%
%   {\doloop{\ifdim\lastskip=\junksignal\unskip\else\exitloop\fi}}

% \def\doifnonzeropositiveelse#1#2#3%
%   {\bgroup
%    \setbox\scratchbox=\hbox{\scratchcounter=0#1}%
%    \ifdim\wd\scratchbox=\!!zeropoint\egroup#2\else\egroup#3\fi}
%
% \def\dodoifnonzeropositiveelse#1#2\end#3#4%
%   {\egroup
%    \ifx#1\relax#3\else#4\fi}
%
% \def\doifnonzeropositiveelse#1%
%   {\bgroup
%    \afterassignment\dodoifnonzeropositiveelse\scratchcounter=0#1\relax\empty\end}

\def\dodoifnonzeropositiveelse#1#2\end#3#4%
  {\ifx#1\relax
     \ifcase\scratchcounter\endgroup#4\else\endgroup#3\fi\else\endgroup#4%
   \fi}

\def\doifnonzeropositiveelse#1%
  {\begingroup\afterassignment\dodoifnonzeropositiveelse\scratchcounter=0#1\relax\empty\end}

% here ?

\def\dosetrawvalue #1#2#3{\@EA \def\csname#1#2\endcsname{#3}}
\def\dosetrawevalue#1#2#3{\@EA\edef\csname#1#2\endcsname{#3}}
\def\dosetrawgvalue#1#2#3{\@EA\gdef\csname#1#2\endcsname{#3}}
\def\dosetrawxvalue#1#2#3{\@EA\xdef\csname#1#2\endcsname{#3}}

\def\getrawparameters      {\dogetparameters\dosetrawvalue }
\def\getraweparameters     {\dogetparameters\dosetrawevalue}
\def\getrawgparameters     {\dogetparameters\dosetrawgvalue}
\def\getrawxparameters     {\dogetparameters\dosetrawxvalue}

\def\globalgetrawparameters{\dogetparameters\dosetrawgvalue} % obsolete

\def\splitskip#1%
  {\scratchskip\zeropoint \!!plus \onepoint \!!minus \onepoint
   \advance\scratchskip#1\relax % \relax is realy needed here
   \expandafter\SPLITSKIP\the\scratchskip}

{\catcode`\.=\@@other
 \catcode`\p=\@@other
 \catcode`\l=\@@other
 \catcode`\u=\@@other
 \catcode`\s=\@@other
 \catcode`\m=\@@other
 \catcode`\i=\@@other
 \catcode`\n=\@@other
 \catcode`\t=\@@other
 \gdef\SPLITSKIP#1pt plus #2pt minus #3pt%
   {\DOSPLITSKIP#1 #2 #3 }}

\def\DOSPLITSKIP#1 #2 #3
  {\dimen0=#1pt\dimen2=#2pt\dimen4=#3pt
   \advance\dimen2 -\onepoint
   \advance\dimen4 -\onepoint}

% \def\minimaxskip#1#2%
%   {\splitskip#2\relax
%    \scratchdimen=#2\relax
%    #2=\scratchdimen
%    \advance#2 by #1\relax}
%
% \def\maximizeskip%
%   {\minimaxskip{-\dimen4}}
%
% \def\maximizeskip%
%   {\minimaxskip{\dimen2}}
%
% \def\maximizespacing%
%   {\maximizeskip\blankskipamount
%    \maximizeskip\parskip
%    \maximizeskip\ctxparskip
%    \maximizeskip\baselineskip
%    \maximizeskip\bigskipamount
%    \maximizeskip\medskipamount
%    \maximizeskip\smallskipamount}

\newcount\modcounter

%\def\DoMod #1by#2to#3%
%  {\modcounter#1\divide\modcounter#2\multiply\modcounter#2%
%   #3#1\advance#3 -\modcounter}
%
%\def\DoDiv #1by#2to#3%
%  {#3#1\divide#3 #2\relax}

\def\dosetmodulo#1#2#3%
  {\modcounter#1\divide\modcounter#2\multiply\modcounter#2%
   #3#1\advance#3-\modcounter}

\def\dosetdivision#1#2#3%
  {#3#1\divide#3 #2\relax}

\def\DoMod#1by#2to#3{\dosetmodulo  {#1}{#2}{#3}}
\def\DoDiv#1by#2to#3{\dosetdivision{#1}{#2}{#3}}

\def\dounprotected#1\par
  {#1\protect}

\def\unprotected
  {\unprotect\dounprotected}

%D Standaard kan een spatie (zoals ~) uitrekken. Dit is in
%D overzichten niet altijd de bedoeling, vandaar:

%\def\fixedspace%
%  {\hskip\fontdimen2\font\relax}

%\def\ExpandSecondAfter#1#2#3%
%  {\!!toksa={#2}%
%   \edef\!!stringa{#3}%
%   \edef\expanded%
%     {\noexpand#1{\the\!!toksa}{\!!stringa}}%
%   \expanded}
%
%\def\ExpandThirdAfter#1#2#3#4%
%  {\!!toksa={#2}%
%   \!!toksb={#3}%
%   \edef\!!stringa{#4}%
%   \edef\expanded%
%     {\noexpand#1{\the\!!toksa}{\the\!!toksb}{\!!stringa}}%
%   \expanded}

%\def\indirect#1#2#3%
%  {\@EA#1\@EA#2\@EA{\@EA#3\csname\s!do\string#2\endcsname}%
%   \@EA#1\csname\s!do\string#2\endcsname}
%
%\def\doubleemptied#1#2#3%
%  {\indirect#1#2\dodoublempty}
%
%\indirect\def\stelietsin\dodoubleempty[#1][#2]%
%  {...}
%
%\doubleemptied\def\stelietsin[#1][#2]%
%  {...}

% in mult-set
%
%\def\defaultsetup{def}
%
%\def\selectdefaultsetup#1#2%
%  {\writestatus{setup}{choose #1 setupfile}%
%   \bgroup
%   \endlinechar=-1
%   \global\read16 to \usersetup
%   \egroup
%   \ifx\usersetup\empty
%     \let\usersetup=\defaultsetup
%   \fi
%   \readfile{#2\usersetup}{}{}%
%   \writestatus{setup}{loading #1 setupfile #2\usersetup}}

% awaiting the definitive implementation

\ifx\resettimer\undefined
  \let\resettimer \relax
  \newcount\elapsedtime
\fi

\newcount\featuretest

\def\testfeature#1#2%
  {\def\dotestfeature
     {\advance\featuretest \plusone
      \ifnum\featuretest>#1\else#2\expandafter\dotestfeature\fi}%
   \retestfeature}

\def\retestfeature % timer support is new per 10/5/2005
  {\bgroup
   \ifcase\interactionmode\let\wait\relax\fi
   \writestatus\m!systems{starting feature test}\wait
   \resettimer
   \featuretest\zerocount \dotestfeature
   \scratchdimen\elapsedtime\s!sp
   \writestatus\m!systems{feature test done (\expandafter\withoutpt\the\scratchdimen s)}%
   \wait
   \egroup}

%  \edef\elapsedtime{\expandafter\withoutpt\the\dimexpr\elapsedtime\relax s}%
%  \writestatus\m!systems{feature test done (\elapsedtime)}%

\def\testfeatureonce#1#2%
  {\let\wait\relax\testfeature{#1}{#2}\end}

%D \macros
%D   {adddimenregister,adddimenmacro}
%D
%D Instead of using numerous \type {\advance}'s, one can use
%D the next macros to add|/|subtract a series of dimensions
%D to a register or macro.
%D
%D \starttyping
%D \adddimenregister 10pt 5pt \paperwidth \to \somedimen
%D \adddimenmacro    10pt 5pt \paperwidth \to \bagger
%D \stoptyping

\newdimen\dimentoaddto

\def\adddimenregister#1\to#2% will be obsolete once full etex
  {\begingroup
   #2=\zeropoint
   \dimentoaddto\zeropoint
   \def\docommando%
     {\advance#2 \dimentoaddto
      \futurelet\next\dodocommando}%
   \def\dodocommando%
     {\ifx\next\relax
        \expanded{\endgroup#2=\the#2}%
      \else
        \@EA\afterassignment\@EA\docommando\@EA\dimentoaddto
      \fi}%
   \docommando#1\relax}

\def\adddimenmacro#1\to#2%
  {\adddimenregister#1\to\scratchdimen
   \edef#2{\the\scratchdimen}}

%D \macros
%D   {freezedimenmacro}
%D
%D This macro is use as:
%D
%D \starttyping
%D \freezedimenmacro\leftmargindistance
%D \stoptyping

\def\freezedimenmacro#1%
  {\scratchdimen#1\edef#1{\the\scratchdimen}}

%D The next one is slower:
%D
%D \starttyping
%D \def\freezedimenmacro#1{\edef#1{\the\dimexpr(#1)}}
%D \stoptyping

% \newcount\rawrecursecounter
%
% \def\rawrecurselevel{\the\rawrecursecounter}%
%
% \def\dorawrecurse#1#2%
%   {\rawrecursecounter\plusone
%    \let\oldrecurselevel\recurselevel
%    \let\recurselevel\rawrecurselevel
%    \def\dodorawrecurse
%      {\ifnum\rawrecursecounter>#1\relax
%         \let\recurselevel\oldrecurselevel
%       \else
%         #2\advance\rawrecursecounter \plusone
%         \expandafter\dodorawrecurse
%       \fi}%
%    \dodorawrecurse}

%D The next macro negates a macro (dimension or number, or actually, whatever.
%D It's a typical example of \type {\if} usage:
%D
%D \starttyping
%D \if-\whatever \else-\whatever\fi => else => -whatever
%D \if--\whatever\else-\whatever\fi => then =>  whatever
%D \stoptyping

\def\negated#1{\if-#1\else-#1\fi} % does only work in macros or text

% This permits things like ^\index{hans}^, where hans is
% duplicated in the text.

\newif\ifduplicate

\bgroup

\gdef\checkduplication % in line with Knuth
  {\ifmmode\expandafter^\else\expandafter\startduplication\fi}

\gdef\insideduplication
  {\ifmmode\expandafter^\else\expandafter\egroup\fi}

\catcode`\^=\@@active

\gdef\enableduplication
  {\catcode`\^=\@@active \let^\checkduplication}

\gdef\disableduplication
  {\catcode`\^=\@@superscript}

\gdef\startduplication
  {\bgroup \duplicatetrue \let^\insideduplication}

\egroup

\def\gobbleassigndimen#1\\{}

\def\assigndimen#1#2%
  {\afterassignment\gobbleassigndimen#1=#2\!!zeropoint\\}

\def\setusage#1%
  {\@EA\let\csname#1\endcsname\iftrue}

\def\resetusage#1%
  {\@EA\let\csname#1\endcsname\iffalse}

\beginTEX

\def\ifusage#1%
  {\@EA\ifx\csname#1\endcsname\relax
     \resetusage{#1}%
   \fi
   \csname#1\endcsname}

\endTEX

\beginETEX \ifcsname

\def\ifusage#1%
  {\ifcsname#1\endcsname\else
     \resetusage{#1}%
   \fi
   \csname#1\endcsname}

\endETEX

%D Very handy, more efficient than \type{{}}, and more readable
%D than \type {\empty}.

\let\donothing\empty

% The following macros are used in XML handling.

% \long\def\dowithstringed#1#2#3#4% " ' space
%   {\if#4"\@EA#1\else\if#4'\@EAEAEA#2\else\@EAEAEA#3\fi\fi#4}
%
% \def\unstringed
%   {\dowithstringed\unstringdouble\unstringsingle\unstringspaced}
%
% \long\def\unstringdouble"#1"{#1}
% \long\def\unstringsingle'#1'{#1}
% \long\def\unstringspaced #1 {#1}
%
% \def\grabstring
%   {\dowithstringed\grabstringdouble\grabstringsingle\grabstringspaced}
%
% \def\dowithgrabbedstring#1%
%   {\def\@@dowithgrabbedstring{#1}%
%    \afterassignment\@@dowithgrabbedstring\grabstring}
%
% \long\def\grabstringdouble"#1"{\scratchtoks{#1}}
% \long\def\grabstringsingle'#1'{\scratchtoks{#1}}
% \long\def\grabstringspaced #1 {\scratchtoks{#1}}

\long\setvalue{@u@s@"}#1#2"{#2} \long\setvalue{@g@s@"}#1#2"{\scratchtoks{#2}}
\long\setvalue{@u@s@'}#1#2'{#2} \long\setvalue{@g@s@'}#1#2'{\scratchtoks{#2}}
\long\setvalue{@u@s@ }#1#2 {#2} \long\setvalue{@g@s@ }#1#2 {\scratchtoks{#2}}

\long\def\unstringed#1{\csname\ifcsname @u@s@#1\endcsname @u@s@#1\else\s!empty\fi\endcsname#1}
\long\def\grabstring#1{\csname\ifcsname @g@s@#1\endcsname @g@s@#1\else\s!empty\fi\endcsname#1}

\def\dowithgrabbedstring#1%
  {\def\@@dowithgrabbedstring{#1}%
   \afterassignment\@@dowithgrabbedstring\grabstring}

\def\expifequalelse#1#2%
  {\@@ifequal#1\relax\relax\@@and#2\relax\relax\@@then}

\def\@@ifequal#1#2\@@and#3%
  {\ifx#1\relax
     \ifx#3\relax
       \@EAEAEA\@@if@@equal@@true
     \else
       \@EAEAEA\@@if@@equal@@false
     \fi
   \else
     \ifx#3\relax
       \@EAEAEAEAEAEA\@@if@@equal@@false
     \else\ifx#1#3%
       % go on
     \else
       \@EAEAEAEAEAEA\@@if@@equal@@false
     \fi\fi
   \fi
   \@@ifequal#2\@@and}

\long\def\@@if@@equal@@true #1\@@then#2#3{#2}
\long\def\@@if@@equal@@false#1\@@then#2#3{#3}

%D new stuff :

\def\partialexpanded#1%
   {\let\notexpanded\noexpand
    \long\xdef\@@expanded{\noexpand#1}%
    \let\notexpanded\empty
    \@@expanded}

% for Simon ; watch how we make them fully expandable (i.e.
% no \type {\relax}es) popping up

\def\@@dothenumber#1\relax#2\end{#1}

\def\@@thenumber#1{\@EA\@@dothenumber\number#1\relax\end}

\def\doifnum#1#2%
  {\ifnum#1=\@@thenumber{#2} % space needed
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\def\doifnotnum#1#2%
  {\ifnum#1=\@@thenumber{#2} % space needed
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\def\doifelsenum#1#2%
  {\ifnum#1=\@@thenumber{#2} % space needed
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

% \edef\xxxx{\doifnum{1}{2}{no}} \show \xxxx
% \edef\xxxx{\doifnum{2}{2}{yes}} \show \xxxx
% \scratchcounter0 \edef\xxxx{\doifnum{1}{\scratchcounter}{no}} \show \xxxx
% \scratchcounter1 \edef\xxxx{\doifnum{1}{\scratchcounter}{yes}} \show \xxxx

\def\appended#1#2#3{\@EA#1\@EA#2\@EA{#2#3}}
\def\appendvalue #1{\@EA\appended\@EA \def\csname#1\endcsname}
\def\appendgvalue#1{\@EA\appended\@EA\gdef\csname#1\endcsname}

\def\prepended#1#2#3{\scratchtoks{#3}\@EA\@EA\@EA#1\@EA\@EA\@EA#2\@EA\@EA\@EA{\@EA\the\@EA\scratchtoks#2}}
\def\prependvalue #1{\@EA\prepended\@EA \def\csname#1\endcsname}
\def\prependgvalue#1{\@EA\prepended\@EA\gdef\csname#1\endcsname}

%D \macros
%D   {compresscommacommandnrs,compresscommalistnrs,compressedcommalistnrs,
%D    compresscommacommand,compresscommalist,compressedcommalist,
%D    reversecommacommand,reversecommalist,reversedcommalist}
%D
%D The following two list processing macros are needed by Taco's
%D bibliography module. The numbers compressor converts the
%D list in a list of ranges. The normal compressor remove duplicate
%D and empty entries.

\def\compresscommalistnrs[#1]%
  {\let\compressedlist\empty
   \!!counta\maxdimen
   \!!countb\maxdimen
   \processcommalist[#1]\docompresslistnrs
   \ifnum\!!counta=\maxdimen\else\dodocompresslistnrs\fi}

\def\compresscommacommandnrs[#1]%
  {\expanded{\compresscommalistnrs[#1]}}

\def\docompresslistnrs#1%
  {\edef\commalistelement{#1}%
   \ifx\commalistelement\empty\else
     \ifnum\!!counta=\maxdimen
       \!!counta\commalistelement\relax
       \!!countb\!!counta
     \else
       \advance\!!countb\plusone
       \ifnum\commalistelement>\!!countb
         \advance\!!countb\minusone
         \dodocompresslistnrs
         \!!counta\commalistelement\relax
         \!!countb\!!counta
       \fi
     \fi
   \fi}

\def\dodocompresslistnrs
  {\edef\compressedlist
     {\ifx\compressedlist\empty\else\compressedlist,\fi
      {\the\!!counta}{\ifnum\!!countb>\!!counta\the\!!countb\fi}}}

%D \def\test#1{{\tttf#1->\compresscommalistnrs[#1]\convertcommand\compressedlist\to\ascii\ascii}}
%D \startlines
%D \test{}
%D \test{1}
%D \test{1,3}
%D \test{1,3,4}
%D \test{1,3,3,4,5}
%D \test{1,3,3,4,5,8}
%D \test{1,3,3,4,5,5,8,10}
%D \test{1,3,4,5,8,10,11}
%D \test{1,,3,,4,,5,,8,,10,,11,}
%D \stoplines

\def\compresscommalist[#1]%
  {\let\compressedlist\empty
   \let\!!stringa\empty
   \processcommalist[#1]\docompresslist}

\def\compresscommacommand[#1]%
  {\expanded{\compresscommalist[#1]}}

\def\docompresslist#1%
  {\edef\commalistelement{#1}%
   \ifx\commalistelement\empty \else
     \ifx\!!stringa\commalistelement \else
       \ifx\compressedlist\empty
         \def\compressedlist{#1}%
       \else
         \appended\def\compressedlist{,#1}%
       \fi
       \let\!!stringa\commalistelement
     \fi
   \fi}

%D \def\test#1{{\tttf#1->\compresscommalist[#1]\convertcommand\compressedlist\to\ascii\ascii}}
%D \startlines
%D \test{}
%D \test{1}
%D \test{1,3}
%D \test{1,3,4}
%D \test{1,3,3,4,5}
%D \test{1,3,3,4,5,8}
%D \test{1,3,3,4,5,5,8,10}
%D \test{1,3,4,5,8,10,11}
%D \test{1,,3,,4,,5,,8,,10,,11,}
%D \stoplines

\def\reversecommalist[#1]%
  {\let\reversedlist\empty
   \processcommalist[#1]\doreverselist}

\def\doreverselist#1%
  {\ifx\reversedlist\empty
     \def\reversedlist{#1}%
   \else
     \prepended\def\reversedlist{#1,}%
   \fi}

\def\reversecommacommand[#1]%
  {\expanded{\reversecommalist[#1]}}

%D \def\test#1{{\tttf#1->\reversecommalist[#1]\convertcommand\reversedlist\to\ascii\ascii}}
%D \startlines
%D \test{}
%D \test{1}
%D \test{1,3}
%D \test{1,3,4}
%D \test{1,3,3,4,5}
%D \test{1,3,3,4,5,8}
%D \test{1,3,3,4,5,5,8,10}
%D \test{1,3,4,5,8,10,11}
%D \test{1,,3,,4,,5,,8,,10,,11,}
%D \stoplines

%D \macros
%D   {stripstring}
%D
%D Needed in bookmarks:
%D
%D \starttyping
%D {\sanitizePDFdocencoding test \CONTEXT\  test \to\oeps\stripstring\oeps\tttf[\oeps]}
%D \stoptyping

\def\stripstring#1% #1 is \cs
  {\bgroup
   \convertcommand#1\to\ascii
   \global\let\globalascii\empty
   \donefalse
   \expandafter\handletokens\ascii\with\dostripstring
   \egroup
   \let#1\globalascii}

\def\dostripstring#1%
  {\ifx#1\blankspace
     \donetrue
   \else
     \ifdone\ifx\globalascii\empty\else
       \xdef\globalascii{\globalascii\space}%
       \donefalse
     \fi\fi
     \xdef\globalascii{\globalascii#1}%
   \fi}

%D \macros
%D   {dowithrange}
%D
%D This one is for Mojca Miklavec, who made me aware of the fact that
%D \type {page-imp.tex} was not the best place to hide it.

\def\dowithrange#1#2% #2 takes number
  {\splitstring#1\at:\to\fromrange\and\torange
   \ifx\torange\empty\let\torange\fromrange\fi
   \dostepwiserecurse\fromrange\torange1{#2{\recurselevel}}}

\protect \endinput
