supp-num.mkii / last modification: 2020-01-30 14:15
%D \module
%D   [       file=supp-num,
%D        version=1998.05.15,
%D          title=\CONTEXT\ Support Macros,
%D       subtitle=Numbers,
%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 / Numbers}

\unprotect

%D \macros
%D   {digits, setdigitmode, setdigitsign}
%D
%D Depending on the digit mode the command \type {\digits}
%D normalizes number patterns depending on the language set.
%D
%D \starttyping
%D This will never be a \digits{1.000.000} seller.
%D \stoptyping
%D
%D or
%D
%D \starttyping
%D I will never grow longer than \digits 1.86 \Meter.
%D \stoptyping
%D
%D The different modes are shown in:
%D
%D \startbuffer
%D \setdigitmode 1 \digits 12.345,90 \digits 12.345.000 \digits 1,23
%D \setdigitmode 2 \digits 12.345,90 \digits 12.345.000 \digits 1,23
%D \setdigitmode 3 \digits 12.345,90 \digits 12.345.000 \digits 1,23
%D \setdigitmode 4 \digits 12.345,90 \digits 12.345.000 \digits 1,23
%D \setdigitmode 5 \digits 12.345,90 \digits 12.345.000 \digits 1,23
%D \setdigitmode 6 \digits 12.345,90 \digits 12.345.000 \digits 1,23
%D \stopbuffer
%D
%D \typebuffer
%D
%D This is typset as:
%D
%D \startlines
%D \getbuffer
%D \stoplines
%D
%D The sign can be typeset as is or within the space of a
%D digit.
%D
%D \startbuffer
%D \setdigitsign 0 \digits +12.345,90
%D \setdigitmode 1 \digits +12.345,90
%D \setdigitmode 2 \digits +12.345,90
%D \setdigitmode 3 \digits +12.345,90
%D \stopbuffer
%D
%D \typebuffer
%D
%D This is typset as:
%D
%D \startlines
%D \getbuffer
%D \stoplines

\chardef\digitoutputmode=1 % 0..6
\chardef\digitsignmode  =0 % 0..3

\def\setdigitmode{\chardef\digitoutputmode}
\def\setdigitsign{\chardef\digitsignmode}

%D The digit modes are:
%D
%D \startitemize[packed]
%D \item periods      \& comma
%D \item commas       \& period
%D \item thinmuskips  \& comma
%D \item thinmuskips  \& period
%D \item thickmuskips \& comma
%D \item thickmuskips \& period
%D \stopitemize

\let\collecteddigits \empty \chardef\digitinputmode =1
\let\saveddigits     \empty \chardef\skipdigit      =0
\let\savedpowerdigits\empty \chardef\powerdigits    =0

%D The first stage of the \type {\digit} macro takes care of
%D the grouped call, the other branch handles the fuzzy
%D delimited calls.

\ifx\mbox\undefined \let\mbox\normalhbox \fi

% \unexpanded\def\digits
%   {\bgroup\let~@\doifnextbgroupelse\dodigits\grabdigit}

\unexpanded\def\digits
  {\bgroup
   \let~@%
   \doifnextbgroupelse\dodigits{\doifnextcharelse\normalmathshift\domathdigits\grabdigit}}

\def\dodigits#1%
  {\grabdigit#1\relax}

\def\domathdigits$#1$%
  {\mbox{\grabdigit#1\relax}} % adding $ $ goes wrong in tabulate

\def\grabdigit
  {\futurelet\next\scandigit}

%D Watch the test for \type {\nextobeyedline}, because the
%D endofline token can be \type {\def'd}, not \type {\let}'d,
%D we need to do an indirect test (see \type {verb-ini.tex})
%D for details.
%D
%D \starttyping
%D \def           ^^M{\obeyedline}
%D \def\nextbeyedline{\obeyedline}
%D \stoptyping

\ifx\normalmathshift\undefined \let\normalmathshift=$ \fi

\def\scandigit
  {\ifx\next\blankspace
     \let\next\handledigits
   \else\ifx\next\nextobeyedline % the indirect one
     \let\next\handledigits
   \else\ifx\next\bgroup
     \let\next\handledigits
   \else\ifx\next\egroup
     \let\next\handledigits
   \else\ifx\next\normalmathshift
     \let\next\handledigits
   \else
     \let\next\collectdigit
   \fi\fi\fi\fi\fi
   \next}

%D We store the power||of||ten (to be signaled by \type {^},
%D \type {e} or~\type {E}) in a seperate macro so that we can
%D typeset it in superscript. The space placeholders are
%D replaced by a \type {@}.

\def\savedigit#1#2%
  {\edef#1{#1\saveddigits#2}\let\saveddigits\empty}

\long\def\collectdigit#1%
  {\ifx#1~%
     \savedigit\collecteddigits @%
   \else\if#1_%
     \savedigit\collecteddigits @%
   \else\if\noexpand#1\relax
     \let\grabdigit\handledigits
   \else\ifcase\powerdigits
     \if#1E%
       \chardef\powerdigits\plusone
     \else\if#1e%
       \chardef\powerdigits\plusone
     \else\if#1^%
       \chardef\powerdigits\plusone
     \else
       \savedigit\collecteddigits#1%
       %\doifnumberelse{#1}
       %  {\savedigit\collecteddigits#1}
       %  {\def\saveddigits{#1}}%
     \fi\fi\fi
   \else
     \savedigit\savedpowerdigits#1%
     %\doifnumberelse{#1}
     %  {\savedigit\savedpowerdigits#1}
     %  {\def\saveddigits{#1}}%
   \fi\fi\fi\fi
   \grabdigit}

\let\handlemathdigits\firstofoneargument
\let\handletextdigits\mathematics

\def\handledigits
  {%\ifcase\powerdigits
   %  \edef\collecteddigits{\collecteddigits\saveddigits}%
   %\else
   %  \edef\savedpowerdigits{\savedpowerdigits\saveddigits}%
   %\fi
   \ifmmode
     \handlemathdigits{\dohandledigits}%
   \else
     \dontleavehmode\hbox{\handletextdigits{\dohandledigits}}%
   \fi
   \egroup}

%D Although we could do with one pass, a second pass for
%D handling the stored sequence is more readable.

\ifnum\texengine=\luatexengine

    \def\dohandledigits
      {\mathcode`\,="002C \mathcode`\.="002E % pretty hard coded
       \expandafter\handletokens\collecteddigits\with\scandigits
       \ifcase\powerdigits\else\digitpowerseparator^{\savedpowerdigits}\fi}

    \chardef\mathaxisfontid\zerocount

\else

    \def\dohandledigits
      {\mathcode`\,="013B \mathcode`\.="013A % pretty hard coded
       \expandafter\handletokens\collecteddigits\with\scandigits
       \ifcase\powerdigits\else\digitpowerseparator^{\savedpowerdigits}\fi}

    \chardef\mathaxisfontid\plustwo

\fi

\def\doscandigit#1%
  {\ifcase\skipdigit\@EA\hbox\else\@EA\hphantom\fi\bgroup
     \mathematics % brr, needed because of stored punctuation
       {\ifnum\digitinputmode=#1\relax
        \ifcase\digitoutputmode
        \or .%
        \or ,%
        \or \mskip\thinmuskip
        \or \mskip\thinmuskip
        \or \mskip\thickmuskip
        \or \mskip\thickmuskip
        \fi
      \else
        \ifodd\digitoutputmode,\else.\fi
      \fi}%
   \egroup}

%D The signs can be made smaller and sqeezed into the width
%D of a digit. Watch the \type {\mathaxisheight} trickery (this
%D font related register stored the math axis).

% 0,=
% 0,==  second = results in delta(00,=)
% 0,-   is invalid, should be =
% 0,--  is invalid, should be ==

\def\digitzeroamount
  {\digitsgn\zeroamount
   \def\digitzeroamount
     {\hphantom
        {00\setbox\scratchbox\hbox{$\zeroamount$}%
         \hskip-\wd\scratchbox}%
      \let\digitzeroamount\empty}}

\def\scandigits#1%
  {\if#1.\digitsep1\else
   \if#1,\digitsep2\else
   \if#1@\digitnop \else
   \if#1_\digitnop \else
   \if#1/\digitsgn{\hphantom{+}}\chardef\skipdigit0\else
   \if#1-\ifcase\skipdigit\digitsgn-\else
           \box\digitsepbox\digitzeroamount \fi\chardef\skipdigit0\else
   \if#1+\digitsgn+\chardef\skipdigit0\else
   \if#1=\box\digitsepbox\digitzeroamount \chardef\skipdigit0\else
   \if#1s\digitsgn{\hphantom{\positive}}\chardef\skipdigit0\else
   \if#1p\digitsgn\positive\chardef\skipdigit0\else
   \if#1m\digitsgn\negative\chardef\skipdigit0\else
   \if#1n\digitsgn\negative\chardef\skipdigit0\else
         \box\digitsepbox #1\chardef\skipdigit0\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}

\newbox\digitsepbox \chardef\autodigitmode=1

\def\digitsep#1%
  {\ifcase\autodigitmode
     \doscandigit#1%
   \else
     \setbox\digitsepbox\hbox{\doscandigit#1}%
   \fi
   \chardef\skipdigit0\relax}

% strange, does not work
%
% \def\digitnop
%   {\hphantom{\box\digitsepbox}%
%    \hphantom{0}\chardef\skipdigit1\relax}
%
% while this works

\def\digitnop
  {\hbox{\hphantom{\box\digitsepbox}}%
   \hphantom{0}\chardef\skipdigit1\relax}

% but this doesn't
%
% \def\digitnop
%   {\hphantom{\box\digitsepbox0}%
%    \chardef\skipdigit1\relax}

\def\digitsgn#1%
  {\ifcase\digitsignmode#1\else
     \hbox
       {\setbox\scratchbox\hbox{0}%
        \scratchdimen\mathaxisheight\textfont\mathaxisfontid
        \def\digitsgn##1##2%
          {\advance\scratchdimen-\mathaxisheight##1\mathaxisfontid
           \raise\scratchdimen
           \hbox to \wd\scratchbox{\hss$##2#1$\hss}}%
        \ifcase\digitsignmode\or
          \digitsgn\textfont        \textstyle        \or
          \digitsgn\scriptfont      \scriptstyle      \or
          \digitsgn\scriptscriptfont\scriptscriptstyle\fi}%
   \fi}

\ifx\undefined\zeroamount \def\zeroamount{-} \fi
\ifx\undefined\positive   \def\positive  {+} \fi
\ifx\undefined\negative   \def\negative  {-} \fi

%D The digit parser handles a bunch of special characters as
%D well as different formats. We strongly suggest you to use
%D the grouped call.
%D
%D \starttabulate[|l|l|l|]
%D \NC \type{.} \NC , . \NC comma or period \NC \NR
%D \NC \type{,} \NC , . \NC comma or period \NC \NR
%D \NC \type{@} \NC \NC invisible space \NC \NR
%D \NC \type{_} \NC \NC invisible space \NC \NR
%D \NC \type{/} \NC \NC invisible sign \NC \NR
%D \NC \type{-} \NC $-$ \NC minus sign \NC \NR
%D \NC \type{+} \NC $+$ \NC plus sign \NC \NR
%D \NC \type{s} \NC \NC invisible high sign \NC \NR
%D \NC \type{p} \NC $\positive$ \NC high plus sign \NC \NR
%D \NC \type{m} \NC $\negative$ \NC high minus sign \NC \NR
%D \NC \type{n} \NC $\negative$ \NC high minus (negative) sign \NC \NR
%D \NC \type{=} \NC $\zeroamount$ \NC zero padding \NC \NR
%D \stoptabulate
%D
%D These triggers are used in the following examples.
%D
%D \startbuffer
%D \digits 12
%D \digits{~~~.~~~.~~~.68.712,34}
%D \digits ~~~.~~~.~~~.68.712,34
%D \digits ___.___.111.68.712,34
%D \digits 111.111.111.68.712,34
%D \digits 12.345,90
%D \digits 12.345.000
%D \digits 12,34
%D \digits{392.857.230.68.712,34}
%D {\digits1234}
%D \digits{1234}
%D \digits 1234\relax
%D $\digits 123.222,00$
%D \digits 123.222,00
%D \digits 123.222,==
%D \digits 123.222,00^10
%D \digits 123.222,00e10
%D \digits /123.222,00e-12
%D \digits -123.222,00e-12
%D \digits +123.222,00e-12
%D \digits n123.222,00e-12
%D \digits s123.222,00e-12
%D \digits p123.222,00e-12
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlines
%D \getbuffer
%D \stoplines

%D \macros
%D   {Digits}
%D
%D We also permit:

\let\Digits\digits

%D These macros are complicated by the fact that we also
%D have to support cases like:
%D
%D \starttyping
%D {\digits1234}
%D \digits{1234}
%D \digits 1234\whatever
%D $\digits 123.222,00$
%D \digits 123.222,00.
%D \stoptyping
%D
%D The latter case shows us that trailing non digits are to
%D be passed untreated.
%D
%D Another interesting case is:
%D
%D \starttyping
%D \digits 123.222,00^10
%D \stoptyping
%D
%D The separator is defined as:

% \def\digitpowerseparator%
%   {\cdot10} % {\times10}

\def\digitpowerseparator
  {\ifx\collecteddigits\empty\else\cdot\fi10}

%D \macros
%D   {digittemplate}
%D
%D Users can specify the way they enter those digits by saying
%D something like:
%D
%D \starttyping
%D \digittemplate 12.000.000,00 % \digittemplate .,
%D \stoptyping

\def\digittemplate #1 %
  {\chardef\digitinputmode\zerocount
   \handletokens#1\with\scandigittemplate}

\def\scandigittemplate#1%
  {\if     #1.\ifcase\digitinputmode\chardef\digitinputmode\plusone \fi% period
   \else\if#1,\ifcase\digitinputmode\chardef\digitinputmode\plustwo \fi% comma
   \fi\fi}

\protect \endinput