catc-ini.mkii / last modification: 2020-01-30 14:15
%D \module
%D   [       file=catc-ini,
%D        version=2006.09.18,
%D          title=\CONTEXT\ System Macros,
%D       subtitle=Catcode Handling,
%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.

%D We've split the functionality of syst-cat.* over more files
%D now so that we can load more selectively.

%D A long standing wish has been the availability of catcode
%D arrays. Because traditional \TEX\ does ot provide this we
%D implement a fake method in the Mark II file.

\ifx\zerocount\undefined \chardef           \zerocount= 0 \fi
\ifx\plusone  \undefined \chardef           \plusone  = 1 \fi
\ifx\minusone \undefined \newcount\minusone \minusone =-1 \fi

\chardef\escapecatcode       =   0
\chardef\begingroupcatcode   =   1
\chardef\endgroupcatcode     =   2
\chardef\mathshiftcatcode    =   3
\chardef\alignmentcatcode    =   4
\chardef\endoflinecatcode    =   5
\chardef\parametercatcode    =   6
\chardef\superscriptcatcode  =   7
\chardef\subscriptcatcode    =   8
\chardef\ignorecatcode       =   9
\chardef\spacecatcode        =  10
\chardef\lettercatcode       =  11
\chardef\othercatcode        =  12   \chardef\other  = 12
\chardef\activecatcode       =  13   \chardef\active = 13
\chardef\commentcatcode      =  14
\chardef\invalidcatcode      =  15

\chardef\tabasciicode        =   9  % ^^I
\chardef\newlineasciicode    =  10  % ^^J don't confuse this one with \endoflineasciicode
\chardef\formfeedasciicode   =  12  % ^^L
\chardef\endoflineasciicode  =  13  % ^^M somewhat messy but this can be the active \par
\chardef\endoffileasciicode  =  26  % ^^Z
\chardef\spaceasciicode      =  32
\chardef\hashasciicode       =  35
\chardef\dollarasciicode     =  36
\chardef\commentasciicode    =  37
\chardef\ampersandasciicode  =  38
\chardef\backslashasciicode  =  92 % `\\
\chardef\circumflexasciicode =  94
\chardef\underscoreasciicode =  95
\chardef\leftbraceasciicode  = 123 % `\{
\chardef\barasciicode        = 124 % `\|
\chardef\rightbraceasciicode = 125 % `\}
\chardef\tildeasciicode      = 126 % `\~
\chardef\delasciicode        = 127

\newif \ifrecatcodeuppercharacters % only used in good old tex

% \newcount\cctdefcounter \cctdefcounter\plusone % 0 = signal
\newcount\cctdefcounter \cctdefcounter\zerocount % 0 = signal, so advance before allocate

\newcount\cctcountera
\newcount\cctcounterb
\newcount\cctcounterc

\def\newcatcodetable#1%
  {\global\advance\cctdefcounter\plusone
   \global\mathchardef#1\cctdefcounter
   \expandafter\xdef\csname @@ccn:\number\cctdefcounter\endcsname{\string#1}% logging
   \expandafter\newtoks\csname @@cct:\number\cctdefcounter\endcsname}

\mathchardef\currentcatcodetable\zerocount

\newtoks \setdefaultlowercatcodes
\newtoks \setdefaultuppercatcodes

\def\next#1% we don't have a proper loop defined yet
  {\edef\nextnext{#1{\the#1\catcode\the\cctcountera\space
     \ifnum\catcode\cctcountera=\lettercatcode \lettercatcode\else\othercatcode\fi}}%
   \nextnext\ifnum\cctcountera<\cctcounterb \advance\cctcountera\plusone \expandafter\next\expandafter#1\fi}

\cctcountera   0  \cctcounterb 127  \next\setdefaultlowercatcodes
\cctcountera 128  \cctcounterb 255  \next\setdefaultuppercatcodes

\recatcodeuppercharactersfalse

\def\catcodetable#1%
  {\mathchardef\currentcatcodetable#1%
   \the\setdefaultlowercatcodes
   \ifrecatcodeuppercharacters\the\setdefaultuppercatcodes\fi
   \the\csname @@cct:\number#1\endcsname}

\long\def\startcatcodetable#1#2\stopcatcodetable
  {\global\csname @@cct:\number#1\endcsname{#2}}

\long\def\startextendcatcodetable#1#2\stopextendcatcodetable
  {\global\csname @@cct:\number#1\endcsname\expandafter{\the\csname @@cct:\number#1\endcsname#2}}

%D The next command can be defined in a cleaner way in the
%D Mk IV file but we want to have a fast one with a minimal
%D chance for interference.

\chardef\activehackcode=`\~

%D Once a catcode is assigned, the next assignments will happen faster.

% (expandable) let

\def\letcatcodecommand {\afterassignment\letcatcodecommanda\cctcountera}
\def\letcatcodecommanda{\afterassignment\letcatcodecommandb\cctcounterb}

\def\letcatcodecommandb % each time
  {\ifcsname CCL:\number\cctcountera:\number\cctcounterb\endcsname
     \csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
   \else
     \expandafter\letcatcodecommandc
   \fi}

\def\letcatcodecommandc % only first time
  {\expandafter\gdef\csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname\expandafter
     {\expandafter\let\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname}%
   \reinstatecatcodecommanda
   \csname CCL:\number\cctcountera:\number\cctcounterb\endcsname}

% expandable def

\def\defcatcodecommand {\afterassignment\defcatcodecommanda\cctcountera}
\def\defcatcodecommanda{\afterassignment\defcatcodecommandb\cctcounterb}

\def\defcatcodecommandb % each time
  {\ifcsname CCD:\number\cctcountera:\number\cctcounterb\endcsname
     \csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
   \else
     \expandafter\defcatcodecommandc
   \fi}

\def\defcatcodecommandc % only first time
  {\expandafter\gdef\csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
     \expandafter##\expandafter1\expandafter
       {\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
   \reinstatecatcodecommanda
   \csname CCD:\number\cctcountera:\number\cctcounterb\endcsname}

% un expandable def (e.g. used for discretionaries)

\def\uedcatcodecommand {\afterassignment\uedcatcodecommanda\cctcountera}
\def\uedcatcodecommanda{\afterassignment\uedcatcodecommandb\cctcounterb}

\def\uedcatcodecommandb % each time
  {\ifcsname CCU:\number\cctcountera:\number\cctcounterb\endcsname
     \csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
   \else
     \expandafter\uedcatcodecommandc
   \fi}

\def\uedcatcodecommandc % only first time
  {\expandafter\gdef\csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
     \expandafter##\expandafter1\expandafter
       {\expandafter\unexpanded\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
   \reinstatecatcodecommanda
   \csname CCU:\number\cctcountera:\number\cctcounterb\endcsname}

\def\reinstatecatcodecommand{\afterassignment\reinstatecatcodecommanda\cctcounterb}

\def\reinstatecatcodecommanda % can be used when a direct definition has been done
  {\bgroup                    % and the selector has been lost
   \uccode\activehackcode\cctcounterb
   \catcode\uccode\activehackcode\activecatcode
   \uppercase{\xdef~{\noexpand\catcodecommand{\number\cctcounterb}}}%
   \egroup}

\chardef\defaultcatcodetable\zerocount

\def\catcodecommand#1%
  {\csname CCC:\number
     \ifcsname CCC:\number\currentcatcodetable:\number#1\endcsname
       \currentcatcodetable \else \defaultcatcodetable
     \fi
   :\number#1\endcsname}

%D \macros
%D   {restorecatcodes,
%D    beginrestorecatcodes,endrestorecatcodes}
%D
%D We're not finished dealing \CATCODES\ yet. In \CONTEXT\ we
%D use only one auxiliary file, which deals with tables of
%D contents, registers, two pass tracking, references etc. This
%D file, as well as files concerning graphics, is processed when
%D needed, which can be in the mid of typesetting verbatim.
%D However, when reading in data in verbatim mode, we should
%D temporary restore the normal \CATCODES, and that's exactly
%D what the next macros do. Saving the catcodes can be
%D disabled by saying \type{\localcatcodestrue}.

\let\savedcatcodetable\relax

\newcount\catcoderestorelevel

\def\pushcatcodetable
  {\advance\catcoderestorelevel\plusone
   \tracepushcatcodetable
   \expandafter\mathchardef\csname scct:\number\catcoderestorelevel\endcsname\currentcatcodetable}

\def\popcatcodetable
  {\ifcase\catcoderestorelevel
     \showcatcodenestingerror
   \else
     \expandafter\catcodetable\csname scct:\number\catcoderestorelevel\endcsname
     \tracepopcatcodetable
     \advance\catcoderestorelevel\minusone
   \fi}

\def\showcatcodenestingerror % can be overloaded
  {\immediate\write16{}%
   \immediate\write16{Fatal error: catcode push/pop mismatch. Fix this!}\wait\end
   \immediate\write16{}}

\def\restorecatcodes % takes previous level
  {\ifnum\catcoderestorelevel>\plusone
     \expandafter\catcodetable\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname
   \fi}

\newtoks\everycatcodetable

\def\setcatcodetable#1%
   {\catcodetable#1%
    \the\everycatcodetable
    \tracesetcatcodetable}

\def\dotracecatcodetable#1{\immediate\write16{[#1]}}

\def\tracecatcodetables
  {\def\tracesetcatcodetable {\dotracecatcodetable{set  \catcodetablename\space                              at \number\catcoderestorelevel}}%
   \def\tracepushcatcodetable{\dotracecatcodetable{push \catcodetablename\space from \catcodetableprev\space at \number\catcoderestorelevel}}%
   \def\tracepopcatcodetable {\dotracecatcodetable{pop  \catcodetablename\space to   \catcodetableprev\space at \number\catcoderestorelevel}}}

\def\catcodetableprev
  {\ifnum\numexpr\catcoderestorelevel-1\relax>\zerocount
     \csname @@ccn:\number\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname\endcsname
   \else
     -%
   \fi}

\def\catcodetablename
  {\ifnum\currentcatcodetable>\zerocount
     \csname @@ccn:\number\currentcatcodetable\endcsname
   \else
     -%
   \fi}

\ifx\empty\undefined \def\empty{} \fi

\let\tracesetcatcodetable \empty
\let\tracepushcatcodetable\empty
\let\tracepopcatcodetable \empty

\def\beginrestorecatcodes{\pushcatcodetable}
\def\endrestorecatcodes  {\popcatcodetable}

%D Handy for debugging:

% \tracecatcodetables

\endinput