%  F W L W . S T Y  ( First Word, Last Word )
%
%  Donald Arseneau  (1993, 1995)
%
%  The fwlw package provides a mechanism to determine the first and
%  last words on the current page, plus the first word on the *next*
%  page.  These can be used in head-lines or foot-lines.  The `words'
%  you see may not be real words, but any unbreakable object.
%
%  Two pagestyles are defined to print these words: \pagestyle{NextWordFoot}
%  which helps you read ahead to the word on the next page; and \pagestyle
%  {fwlwhead} which is like the headers in a lexicon.  Or you can use the
%  words in your own page-style. The words are made available in the box
%  registers:
%       \FirstWordBox   -  first word on this page
%       \NextWordBox    -  first word on next page
%       \LastWordBox    -  last word on this page
%  Use them in your header lines like: \usebox\LastWordBox.
%
%  Such labelling does not make much sense when \chapter generates a page
%  break, so the last page before a \chapter (or any \clearpage) gets 
%  a blank "next word", and the first page of the chapter gets a blank
%  "first word". 
%
%  Note that `words' may unfortunately be things like:
%    - two~words
%    - [ ]Word  ( [ ] represents a parindent box)
%    - a whole displayed equation
%    - the first column of an aligned equation
%    - anomalously blank, if there are \writes or split footnotes etc.
%    - partial words like  par-  or  -tial due to hyphenation.
%
%  (Major digression...)
%  An entirely different approach is possible using \mark and \obeyspaces,
%  and would have different problems.  The problems with catcode changes
%  may be more or less serious for your particular application.  (You are
%  invited to write a package using that method!)  The best solution would 
%  involve \mark and an input filter program to 
%  `\w{tag} \w{each} \w{word}, \w{in} \w{some} \w{way}.'
%  TeX has no \everyword hook to insert such tagging.
%
%     Copyright (C) 1993,1995 by Donald Arseneau
%     Vancouver, Canada, email asnd@triumf.ca
%     This software package may be freely used, transmitted, reproduced,
%     or modified provided that this notice is left intact.
%
% Declare a "unique" penalty value as flag
\mathchardef\LW@pen 12345

% allocate box registers
\newbox\FirstWordBox     \global\setbox\FirstWordBox\hbox{}
\newbox\NextWordBox      \global\setbox\NextWordBox\hbox{}
\newbox\LastWordBox      \global\setbox\LastWordBox\hbox{}
\newbox\LW@box           \global\setbox\LW@box\hbox{}
\newbox\LW@saved

% pagestyle fwlwhead: header line hsa first word and last word
\def\ps@fwlwhead{\let\@mkboth\@gobbletwo
 \def\@oddhead{\if@fcolmade\else % no word-heads on float pages.
   \usebox\FirstWordBox\hfil\usebox\LastWordBox\fi}%
 \let\@evenhead\@oddhead 
 \let\@oddfoot\@empty\let\@evenfoot\@oddfoot
 \let\chaptermark\@gobble\let\sectionmark\@gobble\let\subsectionmark\@gobble
 }

% pagestyle NextWordFoot: foot line has page number and next-page first word,
% but only on odd pages
\def\ps@NextWordFoot{\let\@mkboth\@gobbletwo
 \let\@oddhead\@empty\let\@evenhead\@oddhead
 \def\@oddfoot{\hfil\thepage\hfil\llap{\usebox\NextWordBox}}%
 \let\@evenfoot\@empty
 \let\chaptermark\@gobble\let\sectionmark\@gobble\let\subsectionmark\@gobble
 }

%  Shell around old output routine.  Gets first word from next page by
%  letting TeX continue with \vsize=0 to get a look at the next line.
%  Values of \outputpenalty for \specialoutput ( -10001 to -19999 ) are
%  simply run through the output routine.
%  \supereject and \clearpage give a blank "next word".
%  When called after making a stub-page the stub is returned to the
%  vertical list, the previous page is restored and shipped out normally,
%  but knowing what the next word will be.

\edef\FWLWnorm@L@output{\the\output}

\output{\@tempswafalse
\ifnum \outputpenalty>-\@MM \ifnum\outputpenalty<-\@M \@tempswatrue\fi\fi
\if@tempswa % special (float) output
%  \message{Float handler: penalty=\the\outputpenalty}%
   \FWLWnorm@L@output
\else
  \ifvoid\LW@saved % end of real page
%    \message{End of real page}%
     \global\setbox\LW@saved\copy\@cclv % save page
     \setbox\@tempboxa\vbox{\unvbox\@cclv \unskip\unkern\unpenalty
       \unskip\unkern\unpenalty \unskip\unkern\unpenalty
       \setbox\@tempboxa\lastbox
       \LW@getlast@word\@tempboxa\LastWordBox
     }\ifnum\outputpenalty>-\@MM % not \supereject
       \xdef\LW@vsize{\global\vsize\the\vsize 
          \global\holdinginserts\the\holdinginserts}%
       \global\vsize\z@ \global\holdinginserts\@ne 
     \else % \supereject, just output, don't look for word on next page
%      \message{caused by super-eject.}
       \global\setbox\@cclv\box\LW@saved
       \global\setbox\NextWordBox\hbox{}%
       \FWLWnorm@L@output
       \global\setbox\FirstWordBox\box\NextWordBox
     \fi
  \else % saved page => just did tiny page to get next word
%    \message{Just got next line:}{\tracingall\showboxdepth2 \showbox\@cclv}%
     \setbox\@tempboxa\vbox{\penalty\LW@pen\unvcopy\@cclv \LW@getall@boxes
       \ifvbox\LW@box \penalty\LW@pen\unvbox\LW@box \LW@getall@boxes\fi
       \ifvbox\LW@box \global\setbox\NextWordBox\hbox{}\else
         \LW@getfirst@word\LW@box\NextWordBox
       \fi}%  Return tiny page to page list:
     \unvbox\@cclv \ifnum\outputpenalty<\@M \penalty\outputpenalty\fi
     \LW@vsize\relax
     \global\setbox\@cclv\box\LW@saved
     \FWLWnorm@L@output
     \global\setbox\FirstWordBox\box\NextWordBox
\fi\fi}

% globally get last "word" from a box (#1) into another box (#2)
\def\LW@getlast@word#1#2{\setbox\@tempboxa\vbox{\hsize\maxdimen \@parboxrestore
  \hyphenpenalty\@M \exhyphenpenalty\@M 
  \rightskip\fill \looseness\@M \linepenalty\z@
  \noindent\unhbox#1\endgraf
  \unskip\unkern\unpenalty \global\setbox\LW@box\lastbox
  }\LW@repack{#2}}

% globally get first "word" from a box (#1) into another box (#2)
\def\LW@getfirst@word#1#2{\setbox\@tempboxa\vbox{\@parboxrestore
  \parshape\thr@@ \z@\z@ \z@\z@ \z@\maxdimen \parfillskip\fill
  \hyphenpenalty\@M \exhyphenpenalty\@M 
  \hbadness\@MM \overfullrule\z@ \hfuzz\maxdimen
  \ifhbox#1\noindent
   \vadjust{\penalty\LW@pen}\penalty-\@M\unhbox#1% eliminate previous \leftskip
  \else\ifvbox#1\penalty\LW@pen\unvbox#1\fi\fi
  \endgraf
  \@tempcnta\z@  \LW@getall@boxes}\LW@repack{#2}}

% Go through a vertical list that starts with special penalty
\def\LW@getall@boxes{\global\setbox\LW@box\lastbox \unskip\unkern \unskip\unkern
  \let\@tempa\relax
  \ifvoid \LW@box \advance\@tempcnta\@ne \else \@tempcnta\z@ \fi
  \ifnum\lastpenalty=\LW@pen \else \unpenalty\fi
  \ifnum\lastpenalty=\LW@pen \else \unpenalty\fi
  \ifnum\lastpenalty=\LW@pen \else \ifnum\@tempcnta<5
    \let\@tempa\LW@getall@boxes \fi \fi \unpenalty \@tempa}

% Put contents of \LW@box into hbox #1
\def\LW@repack#1{\global\setbox#1\hbox{\ifhbox\LW@box
   \unhbox\LW@box\unskip\unskip\unpenalty\unskip
  \else\ifvbox\LW@box\box\LW@box\fi\fi}}