syst-con.mkii / last modification: 2020-01-30 14:15
%D \module
%D   [       file=syst-con,
%D        version=2000.12.10, % actually very old -)
%D          title=\CONTEXT\ System Macros,
%D       subtitle=Conversions,
%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 System Macros / Conversions}

\unprotect

%D When the number of conversions grew, it did no longer make
%D sense to spread them over multiple files. So, instead of
%D defining these in \type {font-ini}, we now have a dedicated
%D module.

\catcode127=12 % other, just to be sure

%D \macros
%D   {lchexnumber,uchexnumber,lchexnumbers,uchexnumbers}
%D
%D In addition to the uppercase hex conversion, as needed in
%D math families, we occasionally need a lowercase one, for
%D instance when we want to compose gbsong fontnames.
%D
%D The ugly indirectness is needed to get rid of \TEX\
%D induced spaces and \type {\relax}'s.
%D
%D \starttyping
%D [\uchexnumber{0}]
%D [\uchexnumber\scratchcounter]
%D [\uchexnumber\zerocount]
%D [\uchexnumber{\number0}]
%D [\uchexnumber{\number\scratchcounter}]
%D [\uchexnumber{\number\zerocount}]
%D [\uchexnumber{\the\scratchcounter}]
%D [\uchexnumber{\the\zerocount}]
%D [\expandafter\uchexnumber\expandafter{\number0}]
%D [\expandafter\uchexnumber\expandafter{\number\scratchcounter}]
%D [\expandafter\uchexnumber\expandafter{\number\zerocount}]
%D [\expandafter\uchexnumber\expandafter{\the\scratchcounter}]
%D [\expandafter\uchexnumber\expandafter{\the\zerocount}]
%D \stoptyping
%D
%D These macros may look slow but are actually rather fast due to
%D the fact that \TEX\ handles conditional pretty fast. We need
%D a two step approach in order to stay relax clean in fully
%D expandable macros.

\def\dolchexnumber#1\relax
  {\ifcase#1 0\or 1\or 2\or 3\or 4\or 5\or 6\or 7\or
             8\or 9\or a\or b\or c\or d\or e\or f\else 0\fi}

\def\douchexnumber#1\relax
  {\ifcase#1 0\or 1\or 2\or 3\or 4\or 5\or 6\or 7\or
             8\or 9\or A\or B\or C\or D\or E\or F\else 0\fi}

\def\dolchexnumbers#1\relax
  {\ifcase#1
     00\or 01\or 02\or 03\or 04\or 05\or 06\or 07\or 08\or 09\or 0a\or 0b\or 0c\or 0d\or 0e\or 0f\or
     10\or 11\or 12\or 13\or 14\or 15\or 16\or 17\or 18\or 19\or 1a\or 1b\or 1c\or 1d\or 1e\or 1f\or
     20\or 21\or 22\or 23\or 24\or 25\or 26\or 27\or 28\or 29\or 2a\or 2b\or 2c\or 2d\or 2e\or 2f\or
     30\or 31\or 32\or 33\or 34\or 35\or 36\or 37\or 38\or 39\or 3a\or 3b\or 3c\or 3d\or 3e\or 3f\or
     40\or 41\or 42\or 43\or 44\or 45\or 46\or 47\or 48\or 49\or 4a\or 4b\or 4c\or 4d\or 4e\or 4f\or
     50\or 51\or 52\or 53\or 54\or 55\or 56\or 57\or 58\or 59\or 5a\or 5b\or 5c\or 5d\or 5e\or 5f\or
     60\or 61\or 62\or 63\or 64\or 65\or 66\or 67\or 68\or 69\or 6a\or 6b\or 6c\or 6d\or 6e\or 6f\or
     70\or 71\or 72\or 73\or 74\or 75\or 76\or 77\or 78\or 79\or 7a\or 7b\or 7c\or 7d\or 7e\or 7f\or
     80\or 81\or 82\or 83\or 84\or 85\or 86\or 87\or 88\or 89\or 8a\or 8b\or 8c\or 8d\or 8e\or 8f\or
     90\or 91\or 92\or 93\or 94\or 95\or 96\or 97\or 98\or 99\or 9a\or 9b\or 9c\or 9d\or 9e\or 9f\or
     a0\or a1\or a2\or a3\or a4\or a5\or a6\or a7\or a8\or a9\or aa\or ab\or ac\or ad\or ae\or af\or
     b0\or b1\or b2\or b3\or b4\or b5\or b6\or b7\or b8\or b9\or ba\or bb\or bc\or bd\or be\or bf\or
     c0\or c1\or c2\or c3\or c4\or c5\or c6\or c7\or c8\or c9\or ca\or cb\or cc\or cd\or ce\or cf\or
     d0\or d1\or d2\or d3\or d4\or d5\or d6\or d7\or d8\or d9\or da\or db\or dc\or dd\or de\or df\or
     e0\or e1\or e2\or e3\or e4\or e5\or e6\or e7\or e8\or e9\or ea\or eb\or ec\or ed\or ee\or ef\or
     f0\or f1\or f2\or f3\or f4\or f5\or f6\or f7\or f8\or f9\or fa\or fb\or fc\or fd\or fe\or ff\fi}

\def\douchexnumbers#1\relax
  {\ifcase#1
     00\or 01\or 02\or 03\or 04\or 05\or 06\or 07\or 08\or 09\or 0A\or 0B\or 0C\or 0D\or 0E\or 0F\or
     10\or 11\or 12\or 13\or 14\or 15\or 16\or 17\or 18\or 19\or 1A\or 1B\or 1C\or 1D\or 1E\or 1F\or
     20\or 21\or 22\or 23\or 24\or 25\or 26\or 27\or 28\or 29\or 2A\or 2B\or 2C\or 2D\or 2E\or 2F\or
     30\or 31\or 32\or 33\or 34\or 35\or 36\or 37\or 38\or 39\or 3A\or 3B\or 3C\or 3D\or 3E\or 3F\or
     40\or 41\or 42\or 43\or 44\or 45\or 46\or 47\or 48\or 49\or 4A\or 4B\or 4C\or 4D\or 4E\or 4F\or
     50\or 51\or 52\or 53\or 54\or 55\or 56\or 57\or 58\or 59\or 5A\or 5B\or 5C\or 5D\or 5E\or 5F\or
     60\or 61\or 62\or 63\or 64\or 65\or 66\or 67\or 68\or 69\or 6A\or 6B\or 6C\or 6D\or 6E\or 6F\or
     70\or 71\or 72\or 73\or 74\or 75\or 76\or 77\or 78\or 79\or 7A\or 7B\or 7C\or 7D\or 7E\or 7F\or
     80\or 81\or 82\or 83\or 84\or 85\or 86\or 87\or 88\or 89\or 8A\or 8B\or 8C\or 8D\or 8E\or 8F\or
     90\or 91\or 92\or 93\or 94\or 95\or 96\or 97\or 98\or 99\or 9A\or 9B\or 9C\or 9D\or 9E\or 9F\or
     A0\or A1\or A2\or A3\or A4\or A5\or A6\or A7\or A8\or A9\or AA\or AB\or AC\or AD\or AE\or AF\or
     B0\or B1\or B2\or B3\or B4\or B5\or B6\or B7\or B8\or B9\or BA\or BB\or BC\or BD\or BE\or BF\or
     C0\or C1\or C2\or C3\or C4\or C5\or C6\or C7\or C8\or C9\or CA\or CB\or CC\or CD\or CE\or CF\or
     D0\or D1\or D2\or D3\or D4\or D5\or D6\or D7\or D8\or D9\or DA\or DB\or DC\or DD\or DE\or DF\or
     E0\or E1\or E2\or E3\or E4\or E5\or E6\or E7\or E8\or E9\or EA\or EB\or EC\or ED\or EE\or EF\or
     F0\or F1\or F2\or F3\or F4\or F5\or F6\or F7\or F8\or F9\or FA\or FB\or FC\or FD\or FE\or FF\fi}

\def\lchexnumber #1{\@EA\dolchexnumber \number#1\relax}
\def\uchexnumber #1{\@EA\douchexnumber \number#1\relax}
\def\lchexnumbers#1{\@EA\dolchexnumbers\number#1\relax}
\def\uchexnumbers#1{\@EA\douchexnumbers\number#1\relax}

\let\hexnumber\uchexnumber

%D \macros
%D   {octnumber}
%D
%D For unicode remapping purposes, we need octal numbers.

\def\dooctnumber#1\relax
  {\ifcase#1
     000\or 001\or 002\or 003\or 004\or 005\or 006\or 007\or
     010\or 011\or 012\or 013\or 014\or 015\or 016\or 017\or
     020\or 021\or 022\or 023\or 024\or 025\or 026\or 027\or
     030\or 031\or 032\or 033\or 034\or 035\or 036\or 037\or
     040\or 041\or 042\or 043\or 044\or 045\or 046\or 047\or
     050\or 051\or 052\or 053\or 054\or 055\or 056\or 057\or
     060\or 061\or 062\or 063\or 064\or 065\or 066\or 067\or
     070\or 071\or 072\or 073\or 074\or 075\or 076\or 077\or
     100\or 101\or 102\or 103\or 104\or 105\or 106\or 107\or
     110\or 111\or 112\or 113\or 114\or 115\or 116\or 117\or
     120\or 121\or 122\or 123\or 124\or 125\or 126\or 127\or
     130\or 131\or 132\or 133\or 134\or 135\or 136\or 137\or
     140\or 141\or 142\or 143\or 144\or 145\or 146\or 147\or
     150\or 151\or 152\or 153\or 154\or 155\or 156\or 157\or
     160\or 161\or 162\or 163\or 164\or 165\or 166\or 167\or
     170\or 171\or 172\or 173\or 174\or 175\or 176\or 177\or
     200\or 201\or 202\or 203\or 204\or 205\or 206\or 207\or
     210\or 211\or 212\or 213\or 214\or 215\or 216\or 217\or
     220\or 221\or 222\or 223\or 224\or 225\or 226\or 227\or
     230\or 231\or 232\or 233\or 234\or 235\or 236\or 237\or
     240\or 241\or 242\or 243\or 244\or 245\or 246\or 247\or
     250\or 251\or 252\or 253\or 254\or 255\or 256\or 257\or
     260\or 261\or 262\or 263\or 264\or 265\or 266\or 267\or
     270\or 271\or 272\or 273\or 274\or 275\or 276\or 277\or
     300\or 301\or 302\or 303\or 304\or 305\or 306\or 307\or
     310\or 311\or 312\or 313\or 314\or 315\or 316\or 317\or
     320\or 321\or 322\or 323\or 324\or 325\or 326\or 327\or
     330\or 331\or 332\or 333\or 334\or 335\or 336\or 337\or
     340\or 341\or 342\or 343\or 344\or 345\or 346\or 347\or
     350\or 351\or 352\or 353\or 354\or 355\or 356\or 357\or
     360\or 361\or 362\or 363\or 364\or 365\or 366\or 367\or
     370\or 371\or 372\or 373\or 374\or 375\or 376\or 377\fi}

\def\octnumber#1{\@EA\dooctnumber\number#1\relax}

%D \macros
%D   {twodigits, threedigits}
%D
%D These macros provides two or three digits always:

\def\twodigits  #1{\ifnum             #1<10     0\fi\number#1}
\def\threedigits#1{\ifnum#1<100 \ifnum#1<10 0\fi0\fi\number#1}

%D \macros{modulonumber}
%D
%D In the conversion macros described in \type {core-con} we
%D need a wrap||around method. The following solution is
%D provided by Taco.
%D
%D The \type {modulonumber} macro expands to the mathematical
%D modulo of a positive integer. It is crucial for it's
%D application that this macro is fully exandable.
%D
%D The expression inside the \type {\numexpr} itself is
%D somewhat bizarre because \ETEX\ uses a rounding
%D division instead of truncation. If \ETEX's division
%D would have behaved like \TEX's normal\type{\divide}, then
%D the expression could have been somewhat simpler, like
%D \type {#2-(#2/#1)*#1}. This works just as well, but a bit
%D more complex.

\def\modulonumber#1#2%
  {\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax}

%D \macros{modulatednumber}
%D
%D Modulo numbers run from zero to one less than the limit,
%D but for conversion sets, we need a value between 1 and the
%D limit. The \type{\modulatednumber} arranges that. This
%D macro also needs to be fully expandable, resulting in
%D two \type{\numexpr}s.

\def\modulatednumber#1#2%
  {\ifnum\the\numexpr\modulonumber{#1}{#2}\relax=0 #1%
   \else \the\numexpr\modulonumber{#1}{#2}\relax  \fi}

%D \macros
%D   {hexstringtonumber}
%D
%D This macro converts a two character hexadecimal number into
%D a decimal number, thereby taking care of lowercase characters
%D as well.

\dostepwiserecurse{0}{9}{1}{\setevalue{@@uc@@\recurselevel}{\recurselevel}}

\setvalue{@@uc@@a}{A} \setvalue{@@uc@@A}{A}
\setvalue{@@uc@@b}{B} \setvalue{@@uc@@B}{B}
\setvalue{@@uc@@c}{C} \setvalue{@@uc@@C}{C}
\setvalue{@@uc@@d}{D} \setvalue{@@uc@@D}{D}
\setvalue{@@uc@@e}{E} \setvalue{@@uc@@E}{E}
\setvalue{@@uc@@f}{F} \setvalue{@@uc@@F}{F}

\def\hexstringtonumber#1% {FF}
  {\dohexstringtonumber#1}

\def\dohexstringtonumber#1#2% FF
  {"\csname @@uc@@#1\endcsname\csname @@uc@@#2\endcsname}

%D \macros
%D   {rawcharacter}
%D
%D The next conversion macro produces raw characters. We have to
%D construct the macro in a special way to avoid problems with
%D characters with special meanings. So, we revert to the
%D lowercase conversion trick to bypass \TEX's input parser.
%D
%D This macro can be used to produce proper 8 bit characters
%D that we sometimes need in backends and round||trips.

\bgroup

\catcode`\^^@=12 % ascii null   == ignored in plain
\catcode`\^^?=12 % ascii delete == invalid in plain

\let\or\relax

\xdef\rawcharacter{ ^^00\or}

\dorecurse{255}
  {\lccode`a=\recurselevel
   \lowercase{\xdef\rawcharacter{\rawcharacter \string a\or}}} % string is needed for XeTeX

\@EA\gdef\@EA\rawcharacter\@EA#\@EA1\@EA
  {\@EA\ifcase\@EA#\@EA1\rawcharacter\fi}

\egroup

\protect \endinput