core-con.mkii / last modification: 2006-09-17 13:21
%D \module
%D   [       file=core-con,
%D        version=1997.26.08,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Conversion Macros,
%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.

\unprotect

%D When upcasing the result, we just follow the text book rules
%D of expansion. Later on we'll see some more uppercase tricks.

\def\romannumerals#1%
  {\romannumeral#1}

%D For some years we had \unknown
%D
%D \starttyping
%D \def\Romannumerals#1%
%D   {\uppercase\expandafter{\romannumeral#1}}
%D \stoptyping
%D
%D \unknown but we need to be fully expandable in order to get
%D the utility output file right, so now we have the following
%D solution. It was Patrick Gundlach who first noticed this
%D ommision.

\def\Romannumerals#1%
  {\expandafter\doRomannumerals\number#1\relax}

\def\doRomannumerals#1#2\relax % spaces after ifcase prevent \relax
  {\ifnum#1#2<10
     \ifcase0#1#2 \or I\or II\or III\or IV\or V\or VI\or VII\or VIII\or IX\fi
   \else\ifnum#1#2<100
     \ifcase0#1   \or X\or XX\or XXX\or XL\or L\or LX\or LXX\or LXXX\or XC\fi
     \doRomannumerals#2\relax
   \else\ifnum#1#2<1000
     \ifcase0#1   \or C\or CC\or CCC\or CD\or D\or DC\or DCC\or DCCC\or CM\fi
     \doRomannumerals#2\relax
   \else\ifnum#1#2<4000
     \ifcase0#1   \or M\or MM\or MMM\fi
     \doRomannumerals#2\relax
   \else
     \uppercase\expandafter{\romannumeral#1#2}%
   \fi\fi\fi\fi}

%D Big case statements but pretty fast:

\def\character#1%
  {\ifcase#1\unknowncharacter
     \or a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or k\or l\or m%
     \or n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or x\or y\or z%
   \else
     \unknowncharacter
   \fi}

\def\Character#1%
  {\ifcase#1\unknowncharacter
     \or A\or B\or C\or D\or E\or F\or G\or H\or I\or J\or K\or L\or M%
     \or N\or O\or P\or Q\or R\or S\or T\or U\or V\or W\or X\or Y\or Z%
   \else
     \unknowncharacter
   \fi}

\def\greeknumerals#1%
  {% no longer needed: \mathematics
     {\ifcase#1\unknowncharacter\or
        \alpha      \or \beta  \or \gamma   \or \delta   \or
        \varepsilon \or \zeta  \or \eta     \or \theta   \or
        \iota       \or \kappa \or \lambda  \or \mu      \or
        \nu         \or \xi    \or \omicron \or \pi      \or
        \varrho     \or \sigma \or \tau     \or \upsilon \or
        \phi        \or \chi   \or \psi     \or \omega
      \else
        \unknowncharacter
      \fi}}

\def\Greeknumerals#1%
  {% no longer needed: \mathematics
     {\ifcase#1\unknowncharacter \or
        \Alpha   \or \Beta  \or \Gamma   \or \Delta   \or
        \Epsilon \or \Zeta  \or \Eta     \or \Theta   \or
        \Iota    \or \Kappa \or \Lambda  \or \Mu      \or
        \Nu      \or \Xi    \or \Omicron \or \Pi      \or
        \Rho     \or \Sigma \or \Tau     \or \Upsilon \or
        \Phi     \or \Xi    \or \Psi     \or \Omega
      \else
        \unknowncharacter
      \fi}}

\beginTEX

\def\dodoconvertcharacters#1#2#3%
  {\ifnum#3>#1
     \bgroup
     \!!counta#3\relax
     \ifnum\!!counta>\zerocount
       \advance\!!counta \minusone
       \!!countb\!!counta
       \divide\!!counta #1%
       \!!countc\!!counta
       \multiply\!!countc #1%
       \advance\!!countb -\!!countc
       \doconvertcharacters#3{\!!counta}%
       \advance\!!countb \plusone
       #3{\the\!!countb}%
     \fi
     \egroup
   \else
     #2{#3}% pure expansion, used in references
   \fi}

\endTEX

%D A fully expandable alternative:

\beginETEX \numexpr

\def\dodoconvertcharacters#1#2#3%
  {\ifcase#3\else
     \ifnum#3>#1
       \expandafter\doconvertcharacters\expandafter#2\expandafter{\the\numexpr(#3+12)/#1-1\relax}%
       \expandafter#2\expandafter{\the\numexpr#3-((#3+12)/#1-1)*#1\relax}%
     \else
       \expandafter#2\expandafter{\number#3}%
     \fi
   \fi}

\endETEX

\def\doconvertcharacters{\dodoconvertcharacters{26}}

\def\characters{\doconvertcharacters\character}
\def\Characters{\doconvertcharacters\Character}

\def\getdayoftheweek#1#2#3%
  {\bgroup
   \!!counta#3\relax
   \advance\!!counta \minusone
   \!!countb\!!counta
   \multiply\!!countb 365
   \advance\!!countb \ifcase#2\relax
     0 \or  0 \or 31 \or 59 \or 90 \or120 \or151 \or
   181 \or212 \or243 \or273 \or304 \or334 \or365 \fi
   \advance\!!countb #1\relax
   \ifnum#2>2
     \doifleapyearelse{#3}{\advance\!!countb 1}{}\relax
   \fi
   \!!countc\!!counta
   \dosetdivision\!!countc4\!!countc
   \advance\!!countb \!!countc
   \!!countc\!!counta
   \dosetdivision\!!countc{100}\!!countc
   \advance\!!countb -\!!countc
   \!!countc\!!counta
   \dosetdivision\!!countc{400}\!!countc
   \advance\!!countb \!!countc
   \dosetmodulo\!!countb7\!!countb
   \advance\!!countb \plusone
   \@EA\egroup\@EA\normalweekday\the\!!countb\relax}

\def\dayoftheweek#1#2#3%
  {\getdayoftheweek{#1}{#2}{#3}\doconvertday{\normalweekday}}

\def\doifleapyearelse#1% #2#3%
  {\bgroup
   \!!doneafalse
   \!!counta#1%
   \dosetmodulo\!!counta4\!!countb
   \ifcase\!!countb
     \dosetmodulo\!!counta{100}\!!countb
     \ifcase\!!countb \else \!!doneatrue \fi
     \dosetmodulo\!!counta{400}\!!countb
     \ifcase\!!countb \!!doneatrue \fi
   \fi
   \if!!donea
     \egroup\@EA\firstoftwoarguments  % \def\next{#2}%
   \else
     \egroup\@EA\secondoftwoarguments % \def\next{#3}%
   \fi}                               % \next}

% untested but cleaner:
%
% \def\doifleapyearelse#1% #2#3%
%   {\bgroup
%    \dosetmodulo{#1}{400}\scratchcounter
%    \ifcase\scratchcounter
%    \else
%      \dosetmodulo{#1}{100}\scratchcounter
%      \ifcase\scratchcounter
%        \scratchcounter\plusone
%      \else
%        \dosetmodulo{#1}4\scratchcounter
%      \fi
%    \fi
%    \ifcase\scratchcounter
%      \egroup\@EA\firstoftwoarguments
%    \else
%      \egroup\@EA\secondoftwoarguments
%    \fi}

\def\getdayspermonth#1#2%
  {\doifleapyearelse{#1}
     {\def\numberofdays{29}}
     {\def\numberofdays{28}}%
   \edef\numberofdays
     {\ifcase#2 \or31\or\numberofdays\or31\or30\or
        31\or30\or31\or31\or30\or31\or30\or31\fi}}

\def\calculatecurrenttime
  {\dosetdivision\time{60}\scratchcounter
   \edef\currenthour  {\ifnum\scratchcounter<10 0\fi \the\scratchcounter}%
   \dosetmodulo  \time{60}\scratchcounter
   \edef\currentminute{\ifnum\scratchcounter<10 0\fi \the\scratchcounter}}


%D \macros
%D   {defineconversionvector,conversionnumber} % bad names so no danger for clash
%D
%D For Adam and friends \unknown
%D
%D \startitemize[persiannummerals]
%D \item test \item test \item test \item test
%D \stopitemize

\def\defineconversionvector#1#2% name base
  {\bgroup
   % dirty trick
   \uccode`\*=`\1
   % plain:
   % \uccode`\0=\numexpr#2+0\relax \uccode`\1=\numexpr#2+1\relax
   % \uccode`\2=\numexpr#2+2\relax \uccode`\3=\numexpr#2+3\relax
   % \uccode`\4=\numexpr#2+4\relax \uccode`\5=\numexpr#2+5\relax
   % \uccode`\6=\numexpr#2+6\relax \uccode`\7=\numexpr#2+7\relax
   % \uccode`\8=\numexpr#2+8\relax \uccode`\9=\numexpr#2+9\relax
   % context:
   \dostepwiserecurse091{\expandafter\uccode\expandafter`\recurselevel=\numexpr#2+\recurselevel}%
   % prepared macro
   \uppercase\expandafter{\expandafter\gdef\csname::cvn::#1::\endcsname##*%
     {\ifcase##* 0\or1\or2\or3\or4\or5\or6\or7\or8\or9\fi}}%
   \egroup}

\def\conversionnumber#1#2%
  {\ifcsname::cvn::#1::\endcsname
     \expandafter\doconversionnumber\csname::cvn::#1::\expandafter\endcsname\number#2\relax
   \else
      \number#2%
   \fi}

\def\doconversionnumber#1#2%
  {\ifx#2\relax
     \expandafter\gobbleoneargument
   \else
     #1{#2}%
     \expandafter\doconversionnumber
   \fi#1}

% actually mkiii code

\beginXETEX

\defineconversionvector{arabicnumerals}    {"0660}
\defineconversionvector{persiannumerals}   {"06F0}
\defineconversionvector{thainumerals}      {"0E50}
\defineconversionvector{devanagarinumerals}{"0966}
\defineconversionvector{gurmurkhinumerals} {"0A66}
\defineconversionvector{gujaratinumerals}  {"0AE6}
\defineconversionvector{tibetannumerals}   {"0F20}  % also "half numerals?"

\defineconversion[arabicnumerals]    [\conversionnumber{arabicnumerals}]
\defineconversion[persiannumerals]   [\conversionnumber{persiannumerals}]
\defineconversion[thainumerals]      [\conversionnumber{thainumerals}]
\defineconversion[devanagarinumerals][\conversionnumber{devanagarinumerals}]
\defineconversion[gurmurkhinumerals] [\conversionnumber{gurmurkhinumerals}]
\defineconversion[gujaratinumerals]  [\conversionnumber{gujaratinumerals}]
\defineconversion[tibetannumerals]   [\conversionnumber{tibetannumerals}]

\endXETEX

\protect \endinput