5

I am using \write to output table of contents information. While the correct heading counter information apears in the headings itself, the TOC headings have the number of the last heading of a page. So the \write command seems to be delayd until a page eject. How can I flush a \write at the time a heading macro is processed?

My current section macro begins with:

\edef\SecWr#1{\write0{\line{\hskip2em\hbox to2em{\the\ChaptNo.\the\SecNo\hfil}
    #1\leaderfill\noexpand\folio}}}
\def\Sec#1{\advance\SecNo by1
    \SecWr{#1}

The page number is displayed correctly but e.g. \the\ChaptNo is displayed as 0?

6
  • 1
    It looks like you have to expand the heading number before it is passed to \write. By adding \immediate before \write, the write is not delayed, but you need the delayed writing for the page number, which is known at page shipout time and usually not before. Aug 13 '15 at 16:11
  • How can I do this expansion? Lets assume I want to use \write{\the\ChapNo} (this is not a useful example but a minimum one). Aug 13 '15 at 18:42
  • \expandafter can help: \expandafter\write\expandafter\handle\expandafter{\the\ChapNo}. Or the whole \write expression can be put inside an \edef with protecting the page number from expansion, e.g. \noexpand\folio. Aug 13 '15 at 19:26
  • My example had been too simple. The actual is now \expandafter\write0\expandafter\handle\expandafter{\line{\hskip2em\hbox to2em{\the\ChapNo.\the\SecNo\hfil}#1\leaderfill\the\pageno}} which doesn't compile. Aug 13 '15 at 19:44
  • Using \edef\Test#1{\write0{\line{\hskip2em\hbox to2em{\the\ChapNo.\the\SecNo\hfil}#1\leaderfill\the\noexpand\pageno}}} and then \Test{#1} inside my \section macros does also not work. Aug 13 '15 at 19:52
6

The chapter and section number need to be expanded at the time, the \write is issued, but the expansion of the page number \folio needs to be delayed to the page shipout time, when the page number is definitely known.

Example:

\def\tocentry#1#2{%
  \line{%
    \hskip2em\relax
    \hbox to 2em{#1\hfil}%
    #2\leaderfill
    \folio
  }%
}
\def\SecWr#1{%
  \begingroup
    \let\folio\relax % prevent expansion of `\folio` during `\edef`
    \edef\next{%
      \write0{\noexpand\tocentry{\the\ChaptNo.\the\SecNo}{#1}}%
    }%
    \next
  \endgroup
}
2

Whether a macro is defined with \def or \edef is only important at definition time, not at usage time.

Thus, you don't want to \edef\SecWr, which would fix forever the value of \ChaptNo and \SecNo to the value at definition time (which is zero).

If you want a macro that expands its argument at usage time you can exploit expl3, that also works with Plain TeX, provided you run an e-TeX engine like pdftex (not with Knuth TeX).

\input expl3-generic
\ExplSyntaxOn
\cs_new_protected:Nn \test_sec_wr:nn
 {
  \tocsection{#1}{#2}
 }
\cs_generate_variant:Nn \test_sec_wr:nn { x }
\cs_set_eq:NN \SecWr \test_sec_wr:xn
\ExplSyntaxOff

\def\tocsection#1#2{%
  \write0{%
    \line{\hskip2em\hbox to2em{#1\hfil}#2\leaderfill\folio}%
  }%
}

\def\Sec#1{\advance\SecNo by1 \SecWr{\the\ChaptNo.\the\SecNo}{#1}}

Here's a full example (with \leaderfill defined as \relax just for testing, as I don't know what's your definition).

\input expl3-generic
\ExplSyntaxOn
\cs_new_protected:Nn \test_sec_wr:nn
 {
  \tocsection{#1}{#2}
 }
\cs_generate_variant:Nn \test_sec_wr:nn { x }
\cs_set_eq:NN \SecWr \test_sec_wr:xn
\ExplSyntaxOff

\def\tocsection#1#2{%
  \write0{%
    \line{\hskip2em\hbox to2em{#1\hfil}#2\leaderfill\folio}%
  }%
}

\def\Sec#1{\advance\SecNo by1 \SecWr{\the\ChaptNo.\the\SecNo}{#1}}

\newcount\ChaptNo
\newcount\SecNo
\let\leaderfill\relax % just for testing

\ChaptNo=3 % just for testing

\Sec{Section Title}
\Sec{Section Title}
\Sec{Section Title}

\bye

The macro \test_sec_wr:nn is defined as a normal macro, but then we define a variant that fully expands its first argument and use it as \SecWr. Here's the output on the terminal:

\hbox to\hsize {\hskip 2em\hbox to2em{3.1\hfil }Section Title\leaderfill 1}
\hbox to\hsize {\hskip 2em\hbox to2em{3.2\hfil }Section Title\leaderfill 1}
\hbox to\hsize {\hskip 2em\hbox to2em{3.3\hfil }Section Title\leaderfill 1}
1
  • Thank you for this solution! I nethertheless did use Heiko's solution since that it works with "old" tex too is a more general approach. Finally I may indeed use pdftex but there the general solution may also work. I come back to your example when I run into problems with the other solution. Aug 14 '15 at 9:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.