5

DVI file obtained from the following TeX file is good:

\font\eightrm=cmr8
\let\mainfont=\tenrm

\newtoks\gtitle % title of current major group

\newif\iftitle \newif\ifpagesaved

\newif\ifheader
\def\lheader{\headertrue\mainfont\the\pageno\eightrm\qquad\grouptitle
  \hfill\title\qquad\mainfont\topsecno} % top line on left-hand pages
\def\rheader{\headertrue\mainfont\topsecno\eightrm\qquad\title\hfill
  \grouptitle\qquad\mainfont\the\pageno} % top line on right-hand pages
\def\grouptitle{\let\i=I\let\j=J\uppercase\expandafter{\expandafter
                        \takethree\topmark}}
\def\topsecno{\expandafter\takeone\topmark}
\def\takeone#1#2#3{#1}
\def\takethree#1#2#3{#3}
\def\nullsec{\eightrm\kern-2em} % the \kern-2em cancels \qquad in headers

\let\page=\pagebody \raggedbottom
% \def\page{\box255 }\normalbottom % faster, but loses plain TeX footnotes
\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi
 \shipout\vbox{
  \vbox to\fullpageheight{
  \iftitle\global\titlefalse
  \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi
  \vfill#1}} % parameter #1 is the page itself
  \global\advance\pageno by1}

\gtitle={\.{CWEB} output} % this running head is reset by starred sections
\mark{\noexpand\nullsec0{\the\gtitle}}
\def\title{\expandafter\uppercase\expandafter{\jobname}}

\newdimen\pagewidth \pagewidth=6.5in % the width of each page
\newdimen\pageheight \pageheight=8.7in % the height of each page
\newdimen\fullpageheight \fullpageheight=9in % page height including headlines
\newdimen\pageshift \pageshift=\hoffset % shift righthand pages wrt lefthand ones
\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size
\def\contentsfile{\jobname.toc} % file that gets table of contents info

\newwrite\cont
\output{\setbox0=\page % the first page is garbage
  \openout\cont=\contentsfile
  \global\output{\normaloutput\page\lheader\rheader}}
\setpage
\vbox to \vsize{} % the first \topmark won't be null

\newbox\sbox % saved box preceding the index
\newbox\lbox % lefthand column in the index

% it seems that if there is only one line at the top, the output routine above is
% not executed:
%abc
abc\par ok

\par\vskip6pt plus 1fil % we are beginning the index
\def\page{\box255 } \normalbottom
\write\cont{If you see this on stdout, the output routine above was not executed}
\output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi
  \global\setbox\sbox=\page \global\pagesavedtrue}
\pagesavedfalse \eject % eject the page-so-far and predecessors
\setbox\sbox\vbox{\unvbox\sbox} % take it out of its box
\vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height
\hsize=.5\pagewidth \advance\hsize by -10pt
  % column width for the index (20pt between cols)
\parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
\def\lr{L} % this tells whether the left or right column is next
\output{\if L\lr\global\setbox\lbox=\page \gdef\lr{R}
  \else\normaloutput{\vbox to\pageheight{\box\sbox\vss
      \hbox to\pagewidth{\box\lbox\hfil\page}}}\lheader\rheader
  \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi}
\parskip 0pt plus .5pt
\rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar
\hyphenpenalty 10000 \parindent0pt
hello.

\par\vfill\eject % this is done when we are ending the index
\ifpagesaved\null\vfill\eject\fi % output a null index column
\if L\lr\else\null\vfill\eject\fi % finish the current page
\end

But if we uncomment the first "abc" line and comment the second, the output becomes "bad", because it is output on two pages instead of one.

Why such a small modification of TeX file for some reason breaks things?

2 Answers 2

3

The difference comes from the time when the output routine is invoked. It is exercised when TeX moves material from the list of recent contributions to the current page.

In the case that only abc is entered the current page consists of a mark, the topskip and an empty vbox; the paragraph with abc is the recent contribution. The output routine is called when TeX sees the \eject a few lines later and the current page, which has enough material, is output as the output routine that is active at that point is no longer the one which states that the first page is garbage. At the end of the file the second page is output by the then active output routine.

In the second case the start of the paragraph which contains ok invokes the output routine and the recent contribution, i.e., the paragraph with abc, becomes the current page. The empty vbox is thrown away by the output routine. Later the two paragraphs are saved by the new output routine and output by the third output routine.

You can see the current page and the recent contributions with the command \showlists. For example, change your code:

% it seems that if there is only one line at the top, the output routine above is
% not executed:
\showlists
abc
%abc\showlists\par ok
\showlists

and play with the two lines. To see which output routine is called add a \tracingall at the start of your file and search for \output->. You will see that in the %-lines sometimes the total is larger than the goal but that is normal as TeX collects often more material than necessary to find a good page break.

2
  • I have found significant discrepancies in log file in your TUGboat article "Tracing paragraphs". Please write to my email - it is in my profile (I need your email address to inform you about what I found). Commented Jun 9, 2019 at 13:25
  • If you have the article you have my email address too. I saw that you have asked a question so I assume that the problem is solved. Commented Jun 10, 2019 at 8:18
4

You are processing the following items in main vertical list when abc\par OK is used:

- set first special output routine (line 42)
- put \vbox to\vsize (line 46), this makes the page full, but cost is zero
- put one-line paragraph "abc", this makes the page overfull, cost is infinity
- put second paragraph "OK": 
    when the \parskip of this paragraph is processed, then pageberak is found
    after \vbox to\vsize, then first special output is invoked which throws away
    this \vbox because \shipout (or saving \box255) is missing here
- the main vertical list keeps "abc" and "OK" lines.
- set second special \output (line 61 of your obscure code)
- put another vertical material following by \end
     this invokes second special output, page [1].

And you are processing following items in main vertical list when only abc is used:

- set first special output routine (line 42)
- put \vbox to\vsize (line 46), this makes the page full, but cost is zero
- put one-line paragraph "abc", this makes the page overfull, cost is infinity
- set second special \output (line 61 of your obscure code)
- put another material, when the next \parskip is put then:
   - the page breaking point is set after \vbox to\vsize
   - the second special output prints this empty \vbox, page [1]
   - the line "abc" is kept in main vertical list
- put another vertical material following by \end
   this invokes secondly the second special output, page [2]

So, this is my explanation how your obscure code works and where is the reason of this strange behavior. I strongly recommend to remove all such code and write something more elegant from scratch.

3
  • In this case, the obscure and not-elegant code was written by D. E. Knuth, not the OP. :-) (Try kpsewhich cwebmac.tex or Appendix B in texdoc cwebman.) Commented Jan 31, 2018 at 13:23
  • 1
    Maybe. But this does not matter that we can write something more transparent code from scratch. Setting new \output values inside \output or inside another macros, putting \vbox to\vsize etc. is not so ideal IMHO.
    – wipet
    Commented Jan 31, 2018 at 13:32
  • I guess TeX itself shows that DEK's idea of elegance is different from that of most others. :-) Could you say how you'd write a better version, to replace the \input cwebmac line in files generated by cweave? I think it would be informative…. (Also Knuth is still maintaining CWEB (latest version of cwebmac.tex is 3.70 from July 2017) so he may even change it if there's something better.) Commented Jan 31, 2018 at 18:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .