% Copyright 2012-2024, Alexander Shibakov
% This file is part of SPLinT
%
% SPLinT is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% SPLinT is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with SPLinT.  If not, see <http://www.gnu.org/licenses/>.

\def\yyuniontag{\auxunionctl}
\defp\xrefunionctl{}% sequence to activate/deactivate/take other action for
                    % xref set of macros

\defc\xrefunionctl{%
    \restorecslist{aux:global:xrefs}\xrefunion
}
\savecs{aux:global:activate}\xrefunionctl

\defc\xrefunionctl{%
    \restorecslist{aux:global:xrefs:neutral}\xrefunion
}
\savecs{aux:global:deactivate}\xrefunionctl

\defc\xrefunionctl{% this command should not make any page material contributions
    \message{xrefs...}%
}
\savecs{aux:global:preend}\xrefunionctl

\defc\xrefunionctl{% writing a header, etc.
    \message{xrefs...}%
    \toksa\expandafter{\xrefunion}%
    \immediate\write\auxstream{\harmlesscomment\the\toksa}%
}
\savecs{aux:global:prestart}\xrefunionctl

\yyuniondeclare\xrefunion{aux:global:xrefs}

\defp\MNM#1#2#3#4{}
\defp\XXX#1#2#3{}
\defp\BBB#1#2#3#4{}
\defp\SSS{}

\toyyunion{aux:global:xrefs:neutral}

% end global stream union macros for cross referencing

\def\stseclap{\rightskip=0pt % get out of C mode (cf. \B)
    \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50
    \noindent{\let\*=\empty\llap{\tentitle\setsafesecno{\secno}\quad}}% push it to the margins
    \putxref{\MNM}{}{}.% generate a location reference for noweb cross referencing style
    \ifpdftex\smash{\raise\baselineskip\hbox to0pt{%
        \let\*=\empty\ifmakepdf\pdfdest num \secstar fith\fi}}% this space is a bug in the original cwebmac.tex; AS
    \else
        \ifpdf
            \smash{\raise\baselineskip
                \hbox to0pt{%
                    \let\*=\empty\special{%
                    pdf: dest (\romannumeral\secstar) [ @thispage /FitH @ypos ]%
                    }%
                }%
            }%
        \fi
    \fi
}

\ifx\customchapterstyle\UNDEFINED
    \def\customchapterstyle{0}
\fi

\ifx\customsubchapterstyle\UNDEFINED
    \let\customsubchapterstyle\empty
\fi

\def\stsecchap#1#2{\rightskip=0pt % get out of C mode (cf. \B)
    \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50
%
    \ifnum#1>\z@ % the `level' if this section is below that of a chapter
        \noindent{\let\*=\empty\llap{\tentitle
            \setsafesecno{\secno}\quad}}{\stsecchapttl{#1}#2\stsecchapterminator{#1}}% push it to the margins
        \putxref{\MNM}{\customsubchapterstyle}{}.% generate a location reference for noweb cross referencing style
        \stsecchapseparator{#1}%
    \else
        \setchaptertitle{\secno}{#2}%
        \putxref{\MNM}{\customchapterstyle}{}.% generate a chapter location reference for noweb cross referencing style
    \fi
%
    \ifpdftex\smash{\raise\baselineskip\hbox to0pt{%
       \let\*=\empty\ifmakepdf\pdfdest num \secstar fith\fi}}% this space is a bug in the original cwebmac.tex; AS
    \else\ifpdf\smash{\raise\baselineskip\hbox to0pt{%
       \let\*=\empty\special{%
         pdf: dest (\romannumeral\secstar) [ @thispage /FitH @ypos ]}}}\fi\fi}

\def\stsecchapterminator#1{} % for deeply nested sections one may put a dot at the end
\def\stsecchapseparator#1{%
    \smallskip
    \noindent
}
\def\stsecchapttl#1{\ttl}

\def\setchaptertitle#1#2{%
    \global\chapterheadtrue
    \null
    {\ninepoint\tempda=\baselineskip
     \multiply\tempda by 17
     \vskip\tempda plus\baselineskip minus 2pt
    }%
    \vbox to 0pt{%
        \vss
        \tabskip=0pt plus 1 fil
        \halign to\hsize{%
            \hfil##\tabskip=0pt\cr
            \hugetitle\setsafechapno{#1}\cr
            \noalign{\vskip 1pc}%
            \midtitle#2\cr
        }%
    }%
    \prevdepth=0pt
    \bigskip
    \noindent%{\let\*=\empty\llap{\tentitle\setsafesecno{\secno}\quad}}%
}

\let\startsection\stseclap

\expandafter\def\expandafter\oldB\expandafter{\oldB\global\csectionstarttrue\putxref{\BBB}{}{}.}

% the command that writes references to the reference stream (file):
%     \<reference name>{page}{section}{param1}{param2}
%
\def\putxref#1#2.{% it is important that #2 contains at least two braced groups (as in {}{})
                  % otherwise the parameter scanning mechanism will strip the outside braces
    \ifxreflocal
        {\edef\next{\write\auxstream{\nx\nx\nx#1{\nx\the\nx\pageno}{\secno}#2\harmlesscomment}}\next}%
    \fi
}

\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi %$% section name
  \XX$\langle\,${\let\I=\ne#2\eightrm\kern.5em
    \ifacro{\pdfnote#1.}\else#1\fi}$\,\rangle$\putpathindex{\secno}{#1}\XX\putxrefx{#1}{#2}}

\def\putxrefx#1#2{%
    \ifxreflocal
        {\def\sname{#2}%
         \def\stripprefix##1>{ }%
         \let\*\empty
         \edef\next{\write\auxstream{\nx\nx\nx\XXX{\nx\the\nx\pageno}{\secno}{#1}\harmlesscomment
             \expandafter\stripprefix\meaning\sname}}\next}%
    \fi
}

\newif\ifcsectionstart % does this section name appear at the beginning of a \Cee\ section?

\def\putpathindex#1#2{%
    \ifcsectionstart
        \global\csectionstartfalse\strut
        \vadjust{%
            \setbox0=\hbox{\strut}%
            \kern-\dp0 
            \vbox to 0pt{
                \vss
                \hbox to\pagewidth{%
                    \hfil\rlap{%
                        \let\*\empty
                        \kern1em \setpathlinks{#1}{#2}%
                    }%
                }%
            }%
            \setbox0=\hbox{\strut}%
            \kern\dp0 
        }%
    \fi
}

\def\setpathlinks#1#2{%
    \expandafter\ifx\csname xchain[#1][#2]down\endcsname\relax
        \expandafter\ifx\csname xchain[#1][#2]up\endcsname\relax
        \else
            \setuplink{#1}{#2}{\hfil##\hfil}%
        \fi
    \else
        \expandafter\ifx\csname xchain[#1][#2]up\endcsname\relax
            \setdownlink{#1}{#2}{\hfil##\hfil}%
        \else
            \setuplink{#1}{#2}{##\hfil}
            \setdownlink{#1}{#2}{\hfil##}%
        \fi
    \fi
}

\def\setdownlink#1#2#3{%
    {\setbox0\vtop{
        \sevenpoint\halign{#3\cr
            \setsafesecorchapno{\csname xchain[#1][#2]down\endcsname}\cr
            \relax\ifacro
                \pdflink{\csname xchain[#1][#2]down\endcsname}{\raise3.5pt\hbox{$\scriptscriptstyle\bigtriangledown$}}%
            \else
                \raise3.5pt\hbox{$\scriptscriptstyle\bigtriangledown$}%
            \fi
            \cr
        }
    }%
    \dp0=0pt \box0}%
}

\def\setuplink#1#2#3{%
    {\setbox0\vbox{
        \sevenpoint\halign{#3\cr
            \relax\ifacro
                \pdflink{\csname xchain[#1][#2]up\endcsname}{\lower1.3pt\hbox{$\scriptscriptstyle\bigtriangleup$}}%
            \else
                \lower1.3pt\hbox{$\scriptscriptstyle\bigtriangleup$}%
            \fi
            \cr
            \setsafesecorchapno{\csname xchain[#1][#2]up\endcsname}\cr
        }
    }%
    \box0}%
}

% modify \makenote (used by \pdfnote) to use \noweb\ style references.

\def\makenote{%
    \addtokens\toksB{\noexpand\pdflink{\the\toksC}{\setsafesecorchapno{\the\toksC}}}%
    \toksC={}\global\countC=0
}

% redefine \pdflink; N.B.: the semantics of this command sequence have changed, since now
% #2 is not ignored (as it would have been if using pdftex); instead it becomes a typesetting
% template for the link

\ifpdftex
  \ifx\pdfannotlink\undefined\let\pdfannotlink\pdfstartlink\fi% for pdfTeX 0.14
  \def\pdflink#1#2{\hbox{\pdfannotlink height\ht\strutbox depth\dp\strutbox
    attr{/Border [0 0 0]} goto num #1 \BlueGreen #2\Black\pdfendlink}}
\else\def\pdflink#1#2{\setbox0=\hbox{\special{pdf: bc [ \pdflinkcolor ]}{#2}%
    \special{pdf: ec}}\special{pdf: ann width \thewidth height \theheight
      depth \thedepth << /Type /Annot /Subtype /Link
      /Border [0 0 0] /A << /S /GoTo /D (\romannumeral#1) >> >>}\box0\relax}\fi

% while typesetting the table of contents, show the actual section numbers
% TODO: introduce section accounting for book style typesetting.

\def\contentsline#1#2#3#4#5{\ifnum#2=0 \smallbreak\fi
    \line{\consetup{#2}#1
      \rm\leaders\hbox to .5em{.\hfil}\hfil
      \ \ifacro\pdflink{#3}{#3}\else#3\fi\hbox to3em{\hss#4}}}

\newif\ifxreflocal % are we generating references in noweb style (as page no., position pairs)?
\newif\ifcsecactive

\defc\BBB#1#2#3#4{% #1 is the page number
                 % #2 is the section number
                 % #3, #4 are reserved
    \csecactivetrue
}

\def\lxrcurrentpage{-1}

\newcount\lxrcurrentindex
\newcount\chaptercount

\lxrcurrentindex=\z@

% the command that processes the reference stream by setting
% chapter numbers, etc. based on the section number (which is 
% unique across all sections); see also \BBB\ above

\defc\MNM#1#2#3#4{% #1 is the page number
                  % #2 is the section number
                  % #3 is the chapter flag or empty
                  % #4 is a possible custom reference
    \ifnum#1=\lxrcurrentpage
    \else
        \lxrcurrentindex=\z@
        \def\lxrcurrentpage{#1}%
    \fi
    {%
        \tomodalpha\lxrcurrentindex\next
        \def\nnext{\expandafter\noexpand\csname lxref[#2]\endcsname}%
        \yystringempty{#3}{%
            \let\nnnext\empty
            \toksa{\advance\lxrcurrentindex\@ne}%
        }{%
            \ifnum#3=\z@
                \toksa{\advance\chaptercount\@ne}%
                \def\nnnext{\the\chaptercount}%
            \else
                \processcustomchapterref{#3}{#4}{\nnnext}%
            \fi
        }%
        \edef\next{\def\nnext{{#1}{\next}{\nnnext}{#3}}\the\toksa}%
        \expandafter
    }\next
}

\def\xref@nowebsection#1{% translate the \CWEB\ section number into a \noweb\ reference
    \expandafter\xr@f@nowebsection\romannumeral-1\csname lxref[#1]\endcsname.%
}

\def\xr@f@nowebsection#1#2#3#4.{%
    {#1}{#2}%
}

\def\xref@chapter#1{% translate the \CWEB\ section number into a chapter number
    \expandafter\xr@f@chapter\romannumeral-1\csname lxref[#1]\endcsname.%
}

\def\xr@f@chapter#1#2#3#4.{%
    \yystringempty{#3}{{000}}{%
        {#3}%
    }%
}

\def\xref@sectionorchapter#1{% translate the \CWEB\ section number into a chapter number
                             % if the section begins a chapter or a \noweb\ section reference otherwise
    \expandafter\xr@f@sectionorchapter\romannumeral-1\csname lxref[#1]\endcsname.%
}

\ifx\customchlabel\UNDEFINED
    \def\customchlabel#1#2#3#4{%
        ch#3%
    }
\fi

\def\xr@f@sectionorchapter#1#2#3#4.{%
    \yystringempty{#3}{{#1}{#1#2}}{%
        {#1}{\customchlabel{#1}{#2}{#3}{#4}}%
    }%
}

\def\setsafesecno#1{% extract the noweb style section reference from the \CWEB\ section index
                    % used to typeset marginal section references
    \expandafter\ifx\csname lxref[#1]\endcsname\relax
        #1%
    \else
        \expandafter\lmarginref\romannumeral-1\xref@nowebsection{#1}%
    \fi
}

\def\lmarginref#1#2{{\sscmd\rm#1}\rlap{\sscmd\rm#2}\ }

\def\setsafesecorchapno#1{% if the section begins a chapter, extract the chapter reference,
                          % otherwise, extract the \noweb\ style reference
    \expandafter\ifx\csname lxref[#1]\endcsname\relax
        #1%
    \else
        \expandafter\eatone\romannumeral-1\xref@sectionorchapter{#1}%
    \fi
}

\def\setsafechapno#1{% extract the chapter index
                     % used to typeset chapter headers
    \expandafter\ifx\csname lxref[#1]\endcsname\relax
        #1%
    \else
        \xref@chapter{#1}%
    \fi
}

\def\tomodalpha#1#2{%
    \tempca=#1
    \let#2\empty
    \bloop
        \tempcb=\tempca
        \divide\tempca by 26
        \tempcc=\tempca
        \multiply\tempcc by 26
        \advance\tempcb by -\tempcc
        \advance\tempcb by `\a
        \uccode`\.=\tempcb
        \uppercase{\edef#2{.#2}}%
        \advance\tempca\m@ne
    \ifnum\tempca<\z@
    \else
    \repeat
}

\defc\XXX#1#2#3{%
    \ifcsecactive % previous command was \BBB (produced by the \B macro)
%        \expandafter\def\csname lxref[][]\endcsname{}%
        \csecactivefalse
    \fi
}

% the next command takes advantage of the format for section references
% in the list of all sections: instead of a specific section number that
% points to the section where the given chunk of code started, the
% references contain ordered lists of all the section numbers that
% constitute the contents of the named section;
% this command should be placed in the main .w file before the list
% of all sections is included but after all the regular section references.

\def\lxrefseparator{%
    \write\auxstream{\nx\SSS}%
}

% forming chain references to be used for navigation through a given named section

\defc\SSS{\let\XXX\xxxchain} % reference separator

\def\xxxchain#1#2#3{%
    \xxxch@in{}{}#3, .%
}

\newif\iftracenowebchains

\def\xxxch@in#1#2#3, #4.{% #1 is the chain head
                         % #2 is the chain previous
                         % #3 is the chain next
                         % #4 is the remaining chain
    \yystringempty{#1}{% start the chain
        \yystringempty{#3}{%
            \errmessage{The reference chain (#3) is malformed.}%
        }{%
            \xxxch@in{#3}{}#4, .%
        }%
    }{%
        \yystringempty{#2}{% potentially the second link
            \yystringempty{#3}{% this is a one link chain
            }{% this is a second link
                \expandafter\def\csname xchain[#1][#1]down\endcsname{#3}%
                \expandafter\def\csname xchain[#3][#1]up\endcsname{#1}%
                \iftracenowebchains\message{s(#1.->#3 #3->#1.)}\fi
                \xxxch@in{#1}{#3}#4, .%
            }%
        }{% this is the middle or the end of the chain
            \yystringempty{#3}{% this is the end of the chain
            }{%
                \expandafter\def\csname xchain[#3][#1]up\endcsname{#2}%
                \expandafter\def\csname xchain[#2][#1]down\endcsname{#3}%
                \iftracenowebchains\message{m(#1)(#2->#3 #3->#2)}\fi
                \xxxch@in{#1}{#3}#4, .%
            }%
        }%
    }%
}

% replace the default reference setting macros in gindex.sty;
% typeset references so that, for example, \(77){8, 9} becomes 
% \(\compoundlink{77}{8c}), \(\pagelink{9}) provided section 77 
% is section 8c by noweb's reckoning.

\def\consumeonexref#1#2{% #1 is the accumulated references
                        % #2 is the section number
    \expandafter\ifx\csname lxref[#2]\endcsname\relax
        \errmessage{Section #2 does not have a local index.}%
    \else
        \yybreak{\expandafter\c@nsumeonexref\romannumeral-1\xref@sectionorchapter{#2}{#2}{#1}}%
    \yycontinue
}

\def\c@nsumeonexref#1#2#3#4#5{% #1 is the page number of the beginning of the section
                              % #2 is the (\noweb) section or chapter reference where the term appears
                              % #3 is the (\CWEB) section number there the term appears
                              % #4 is the accumulated references
                              % #5 is a list of pages where this term appears
    \c@nsume@nexref{#1}{#2}{#3}{#4}{}#5, \end
}

\def\c@nsume@nexref#1#2#3#4#5#6, {% #1 is the page number of the beginning of the section
                                  % #2 is the (\noweb) section or chapter reference where the term appears
                                  % #3 is the (\CWEB) section number where the term appears
                                  % #4 is a total list of processed references
                                  % #5 is a local list of processed references
                                  % #6 is a page number from the list
    \ifnum#1=#6 % the term appears on the same page where the section begins
        \yybreak{\c@nsume@nexr@f{#1}{#2}{#3}#4{#5}{\compoundlink{#3}{#2}}}%
    \else
        \yybreak{\c@nsume@nexr@f{#1}{#2}{#3}#4{#5}{\pagelink{#6}}}%
    \yycontinue
}

\def\c@nsume@nexr@f#1#2#3#4#5#6#7#8{%
    \c@nsume@n@xr@f{#1}{#2}{#3}{{#4}{#5}{#6}}{#7, #5#8#4}%
}

\def\c@nsume@n@xr@f#1#2#3#4#5#6\end{% no more page numbers
    \yystringempty{#6}{%
        \attachlocallist{#1}{#2}{#3}#4{#5}%
    }{%
        \c@nsume@nexref{#1}{#2}{#3}{#4}{#5}#6\end
    }%
}

\def\attachlocallist#1#2#3#4#5#6#7{%
    \grabfinexrefs{#6#7}%
}

\toyyunion{aux:global:xrefs}