Chapter 9
Tables of Contents

   9.1 Archiving the Table
   9.2 Invoked Tables of Contents
      Listing the Entries
      Loading the Entries
      Collecting the Entries
   9.3 Triggered Tables of Contents
      Process the Request
      Process the Request
      Interpretation for Included Entry
      End Points

9.1 Archiving the Table

For a source document that is stored in file named abc.xyz the table is assumed to be stored in a file that carries the name abc.4tc. It is archived into abc.4ct.

<..blocs for tocs..>
 \openin15=\jobname.4tc
 \ifeof15  \closein15
    \def\:TableOfContents[#1]{\immediate\write16{No file \jobname.4tc}}
    <.undef /TableOfContents.>
 \else
    \ifHtml  <.def html /TableOfContents.>
    \fi
    <.copy toc.>
 \fi
 -_-_-

<..copy toc..>
 \begingroup
   \catcode‘^=7
   <.define /:copytoc.>   \ifHtml \catcode‘\#=12\relax \fi
   \def\:next{\catcode\tmp:cnt=12
     \ifnum \tmp:cnt=0
        \def\:next{%
           \catcode‘\^^M=5
           \immediate\openout15=\jobname.4ct     \:copytoc
           \immediate\closeout15
           \endgroup \closein15
        }%
     \fi
     \advance\tmp:cnt by -1 \:next
   }
   \tmp:cnt=255   \:next
 -_-_-

<..define /:copytoc..>
 \def\:copytoc{%
    \ifeof15   \else
       \read15 to \:temp
       {\escapechar=‘\\\immediate\write15{\:temp}}%
       \expandafter\:copytoc
    \fi}
 -_-_-

9.2 Invoked Tables of Contents

Listing the Entries

The following pair of definitions are a degenerated case of the ‘sty’ option in which the parameters are required for a table to appear.

<..undef /TableOfContents..>
 \ifx \TableOfContents\:UnDef
    \def\TableOfContents{\futurelet\:temp\:TOC}
    \def\:TOC{\ifx [\:temp \expandafter\:TableOfContents\fi}
 \fi
 -_-_-

<..def html /TableOfContents..>
 <.undef /TableOfContents.>
 \def\:TableOfContents[#1]{\SaveEverypar{%
    \def\TocCount{0}%
    <.interpretation for entries.>%
    \def\InsertTitle##1##2##3{}%
    \hsize=4.5in  \rightskip = \z@ minus 1in  \linepenalty=1000
    \catcode‘\#=12  \catcode‘\@=11   \catcode‘\:=11
    <.Configure HtmlPar for TOC.>\everypar{\HtmlPar}%
    <.before toc.>\input \jobname.4ct
    {\ht:everypar{}\leavevmode}<.bottom toc.>%
    \par  }\RecallEverypar <.after toc.>}
 -_-_-

<..after toc..>
 \ifx \c:tableofcontents\:UnDef
    \csname c:TableOfContents\endcsname
 \else \c:tableofcontents \fi
 -_-_-

<..before toc..>
 \ifx \a:tableofcontents\:UnDef \csname a:TableOfContents\endcsname
 \else \a:tableofcontents \fi
 -_-_-

<..bottom toc..>
 \ifx \b:tableofcontents\:UnDef
       \csname b:TableOfContents\endcsname
 \else \b:tableofcontents \fi
 -_-_-

<..par toc..>
 \ifx \d:tableofcontents\:UnDef \csname d:TableOfContents\endcsname
 \else \d:tableofcontents \fi
 -_-_-

<..noindent toc par..>
 \ifx \e:tableofcontents\:UnDef
       \csname e:TableOfContents\endcsname
 \else \e:tableofcontents \fi
 -_-_-

The following might be a problem LaTeX, in particular with \IgnoreIndent/\ShowIndent cases. A partial solution to the problem used the code \if:latex \if:nopar \else \Configure{HtmlPar}{}{\Configure {HtmlPar}{|<noindent toc par|>}{|<par toc|>}{}{}}{}{}% \fi\fi, but then we got problems elsewhere.

<..Configure HtmlPar for TOC..>
 \Configure{HtmlPar}{<.noindent toc par.>}{<.par toc.>}{}{}%
 -_-_-

Loading the Entries

<..interpretation for entries..>
 \:tocPreamble#1,,%
 \let\doTocEntry=\:doTocEntry
 \def\contentsline##1##2##3{##2}%
 \no:lbl:idx
 -_-_-

<..blocs for tocs..>+
 \def\:doTocEntry#1#2#3#4{%
    \Advance:\TocCount by 1
    \expandafter\ifx \csname \string#1 \endcsname \relax \else
      #1{#2}{#3}{#4}\fi
 }
 -_-_-

<..shared config..>+
 \NewConfigure{TocLink}[1]{\def\a:TocLink##1##2##3##4{#1}}
 -_-_-

A field [\ifnum \FileNumber=#1 \else \RefFileNumber{#1}\fi] buys nothing as far as memory is concerned.

<..def Configure..>+
 \long\def\ConfigureToc#1#2#3#4#5{%
    \expandafter\def\csname toc#1\endcsname##1##2##3{#5}%
    <.cond toc config.>%
 }
 -_-_-

<..trace commands..>+
 \long\def\ConfigureToc#1#2#3#4#5{%
    \expandafter\def\csname toc#1\endcsname##1##2##3{#5}%
    \edit:p\def\:temp{#2#3#4#5}\ifx \:temp\empty
       \expandafter\pend:defIII\csname toc#1\endcsname{\hbox
         {\a:trc Toc(#1)1\b:trc}####1\hbox{\a:trc Toc(#1)2\b:trc}####2\hbox
         {\a:trc Toc(#1)3\b:trc}####3\hbox{\a:trc Toc(#1)4\b:trc}}%
    \else
      <.cond toc config.>%
    \fi
 }
 -_-_-

<..cond toc config..>
 \def\:temp{#4}\ifx \:temp\empty \else
    \expandafter\pend:defIII\csname toc#1\endcsname{#4####3}%
 \fi
 \def\:temp{#3}\ifx \:temp\empty \else
    \expandafter\pend:defIII\csname toc#1\endcsname{#3####2}%
 \fi
 \def\:temp{#2}\ifx \:temp\empty \else
    \expandafter\pend:defIII\csname toc#1\endcsname{#2####1}%
 \fi
 -_-_-

<..blocs for tocs..>+
 \def\:tocPreamble#1,{%
   \def\:temp{#1}\ifx \:temp\empty     \else
      \edef\:temp{\expandafter\string\csname toc#1 \endcsname}%
      \expandafter\expandafter\expandafter\let
         \expandafter\csname\:temp\endcsname=\empty
      \expandafter\:tocPreamble\fi}
 -_-_-

Collecting the Entries

After producing the table of contents from the previous compilation, a file is opened for collecting the entries of the table from the current compilation.

<..blocs for tocs..>+
 \ifx \:tocout\:UnDef
    \csname newwrite\endcsname\:tocout
 \fi
 \def\:temp{%
 <.if latex then latex/write sol.>\openout\:tocout=\jobname.4tc
    <.doTocEntry for dvi.>}
 \:temp
 -_-_-

In case we switch from html to dvi mode, without the presence of TeX4ht, we want to hide the \doTocEntry.. The \escapechar decides what is written out for escape character, no matter what the actual symbol is. texinfo changes that symbol to \escapechar=‘\@.

<..doTocEntry for dvi..>
 {\escapechar=‘\\<.if latex then latex/write sol.>\write
    \:tocout{\string\expandafter\string\ifx
    \noexpand\csname doTocEntry\string\endcsname\relax
       \string\expandafter\string\endinput
    \string\fi}%
 }%
 -_-_-

9.3 Triggered Tables of Contents

The \TocAt-{...} command asks for no TOC, the TocAt*{...} command asks for a TOC delayed until the next section, \TocAt{...} asks for TOC in place, and a list of size one asks for no more local TOC’s for the given logical unit.

<..blocs for tocs..>+
 \def\TocAt#1{%
    \def\:next##1{\:TocAt##1,//}%
    \def\:tempa{#1}\def\:temp{-}\ifx \:tempa\:temp  \let\:temp=-%
    \else \def\:temp{*}\ifx \:tempa\:temp           \let\:temp=*%
    \else    \def\:next{\:TocAt#1,//}%
    \fi \fi  \:next }
 -_-_-

<..Toc:At>..>
 \expandafter\edef\csname Toc:#1\endcsname{%
    \gdef\expandafter\noexpand\csname TocAt*\endcsname{%
       \noexpand \csname Toc#1\noexpand\endcsname }}%
 -_-_-

<..Toc:At..>
 \expandafter\edef\csname Toc:#1\endcsname{%
     \noexpand\csname Toc#1\noexpand\endcsname }%
 -_-_-

<..blocs for tocs..>+
 \def\:TocAt#1,#2//{%
    \ifx -\:temp \else \ifx *\:temp
            <.Toc:At>.>%
    \else   <.Toc:At.>\fi \fi
    \def\:temp{#2}\ifx  \:temp\empty
       \expandafter\let\csname Toc#1\endcsname=\:UnDef
    \else <.extract the entries.>\fi }
 -_-_-

Process the Request

For \TocAt{X,...,Y,...} we define a \TocX that includes the interpretations for the different \tocY w of Xithin commands of the form X::tocY.

<..extract the entries..>
 \let\:include=\empty
 \::TocAt#1,/#1,#2,,//%
 \edef\:include{\expandafter\:removecomma\:include}%
 \expandafter\edef\csname Toc#1\endcsname{{%
    \let\noexpand\TitleCount=\expandafter\noexpand
                                 \csname #1:Count\endcsname
    \noexpand\:assgtoc\:include,//{#1}%
    \:tocs[\:include]}}%
 -_-_-

Process the Request

<..blocs for tocs..>+
 \def\:tocs{\noexpand\TableOfContents}
 -_-_-

<..blocs for tocs..>+
 \def\:removecomma#1{}
 \def\:assgtoc#1,#2//#3{%
    \expand:after{\expandafter\let\csname toc#1\endcsname =}%
                                  \csname #3::toc#1\endcsname
    \if:notempty{#2}{\:assgtoc#2//{#3}}}
 -_-_-

<..blocs for tocs..>+
 \def\::TocAt#1,#2,#3//{\def\:temp{#2}%
    \ifx  \:temp\empty \else
       \if /\:firstch#2 //%
                <.stop toc for @1 at @2.>%
       \else    <.include @2 in toc for @1.>\fi
       \expand:after{\::TocAt#1,#3//}%
    \fi
 }
 -_-_-

Interpretation for Included Entry

Also for \TocAt{X,....,Y,...} the interpretation is defined in X::tocY.

<..include @2 in toc for @1..>
 \edef\:include{\:include,#2}%
 \expand:after{\expandafter\let\csname svtoc::#2\endcsname=}%
                                      \csname toc#2\endcsname
 \expandafter\edef\csname #1::toc#2\endcsname##1##2##3{%
    \noexpand\ifnum  \noexpand\TitleCount<\noexpand\TocCount
                                                         \noexpand\space
       \expandafter\noexpand \csname svtoc::#2\endcsname{##1}{##2}{##3}%
    \noexpand\fi}%
 -_-_-

Tex4ht relies on two counters \TitleCount and \TocCount to decide which entries of the global TOC should go to the local TOC. The first counter is increased when sectioning commands are encountered. The second counter is increased when the global TOC is traversed.

A discrepancy will occur when the contributions of the sectioning commands to the global TOC are not synchronized with the increments of the first counter. That will normally be the case when sectioning commands are introduced without tex4h being informed about their designation as sectioning commands.

End Points

Also for \TocAt{X,....,/Y,...} the termination point that we get is defined in X::tocY.

<..blocs for tocs..>+
 \def\:firstch#1#2 //{#1\def\:temp{#2}}
 -_-_-

<..stop toc for @1 at @2..>
 \edef\:include{\:include,\:temp}%
 \expandafter\def\csname #1::toc\:temp\endcsname##1##2##3{%
    \ifnum \TitleCount<\TocCount
        \Advance:\TocCount by -100000   \endinput
    \fi}%
 -_-_-

The \endinput is not required but it desired because it cuts off the reading of the toc file. The -100000 is needed forhierarchical toc’s due to parent-child relashions.