0

I have a command that creates some canned text at the top of a file that requires information about the location of an environment I've created. I've got the code for this all put together, and it works just fine at the end of the document, but I'm required to put it at the head of the document.

Specifically, I've got a command

\newcommand\Pages{\expandafter\@printWatermarkedPage\@watermarkedPages,@}
\makeatother

\newcommand{\makeparagraph}{
Pages \Pages of this document has watermarks
}

where a bunch of logic populates the watermarkedPages list (see here for more Iterate over pages and set variable) and I need to print the resulting phrase up at the top. If I simply move the current implementation to the head of the document, I get a "Missing \endcsname inserted." error, which I assume is because the list hasn't been populated yet.

How does one create a command that knows it needs multiple passes to get the information it needs?

  • 1
    You write the stuff you need to an external file and then read it back on the next run. If you post a complete, small example, it will be possible to demonstrate this. But the idea is just the same as creating a .toc or writing to the .aux file or whatever. – cfr Sep 16 '15 at 20:39
  • I figured it was something like that, but I've not had to read from a .aux file before. – webb Sep 17 '15 at 17:22
3

I've taken the accepted answer from Iterate over pages and set variable and added the necessary components to allow for using a \label-\ref approach to extracting the watermarked pages.

I've added

\usepackage{atveryend}
\newcommand\printWatermarkedPages{%
  \@ifundefined{r@watermark-pages}{??}{%
    \edef\@thewatermarkedPages{\expandafter\expandafter\expandafter\@firstoffive\csname r@watermark-pages\endcsname}%
    \expandafter\@printWatermarkedPage\@thewatermarkedPages,@%
  }%
}
\AfterLastShipout{
  \immediate\write\@auxout{\string\newlabel{watermark-pages}{{\@watermarkedPages}{}{}{watermark.end}{}}}
}

which does two things:

  1. Writes the "watermark labels" to the .aux in the form of the reference/\label at the end of the document with the aid of atveryend's \AfterLastShipout. You might get away without this and just using \AtEndDocument).

  2. Creates \printWatermarkedPages which inserts the hyperlinked sequence of watermarked pages (similar to \WatermarkedPages) obtained from the above-mentioned reference.

Here's a complete minimal example:

enter image description here

\documentclass{article}
\usepackage[contents={Watermarked!},pages=some]{background}
\usepackage[colorlinks]{hyperref}
\pagenumbering{arabic}

\newcounter{watermark}

\makeatletter
\newif\ifWatermarkPage\WatermarkPagefalse% true if page should be watermarked
\newif\ifStillWatermarking\StillWatermarkingfalse% true if we want a watermark on the next page
\AddEverypageHook{%
  \ifWatermarkPage%
    \bg@material%
  \else%
    \ifStillWatermarking%
      \global\WatermarkPagefalse%
      \AddWatermarkLabels\bg@material%
    \fi%
  \fi%
  \global\WatermarkPagefalse%
}
% will hold a comma separated list of labels for the watermarked pages
\def\@watermarkedPages{\@gobble}  % gobble will eat an initial comma
% add a watermark and create a label - unless we've already done this for this page
\newcommand\AddWatermarkLabels{%
  \ifWatermarkPage%  already have label, so do nothing
  \else%
    \global\WatermarkPagetrue
    \refstepcounter{watermark}% increment number of watermarked pages
    % NB. Using \label{watermark:\thepage} doesn't write to the aux file 
    % when this is called via \AddEverypageHook, so we do it ourselves:
    \immediate\write\@auxout{\string\newlabel{watermark:\thepage}{{\thewatermark}{\thepage}{}{watermark.\thewatermark}{}}}
    \global\edef\@watermarkedPages{\@watermarkedPages,watermark:\thepage}% add label
  \fi
}
\newenvironment{watermarked}%
    {\global\StillWatermarkingtrue\AddWatermarkLabels}
    {\global\StillWatermarkingfalse\AddWatermarkLabels} % this page still needs a watermark

% The next macros pass the labels in \@watermarkedPages to \pageref taking
% care to add commas between references and an "and" between the last two.
\def\@printWatermarkedPage#1,#2{\pageref{#1}%
  \ifx#2@\let\@nextWatermark\@gobble%
  \else\let\@nextWatermark\@printWatermarkedPages%
  \fi%
  \@nextWatermark#2%
  }
\def\@printWatermarkedPages#1,#2{%
  \ifx#2@ and \let\@nextWatermark\@gobble\else ,\fi%
  \pageref{#1}%
  \@nextWatermark#2%
}
\newcommand\WatermarkedPages{\expandafter\@printWatermarkedPage\@watermarkedPages,@}

\usepackage{atveryend}
\newcommand\printWatermarkedPages{%
  \@ifundefined{r@watermark-pages}{??}{%
    \edef\@thewatermarkedPages{\expandafter\expandafter\expandafter\@firstoffive\csname r@watermark-pages\endcsname}%
    \expandafter\@printWatermarkedPage\@thewatermarkedPages,@%
  }%
}
\AfterLastShipout{
  \immediate\write\@auxout{\string\newlabel{watermark-pages}{{\@watermarkedPages}{}{}{watermark.end}{}}}
}
\makeatother

\begin{document}
Watermarks on pages \printWatermarkedPages.% 2,4,5,6,7


Some text here on page  1.
\newpage

\begin{watermarked}
some text
\end{watermarked}

\begin{watermarked}
more text
\end{watermarked}

More text here.

\newpage
Page with no watermarked stuff.
\newpage

\begin{watermarked}
more text,
\newpage
on several pages
\newpage
\end{watermarked}

More text here. Start a new page.
\newpage

\begin{watermarked}
more text
\end{watermarked}

\newpage
Loop to find pages containing the watermarked environment. Hard coded
here.

The \arabic{watermark} watermarked environments appear on the following
pages \printWatermarkedPages.

\end{document}

You can use \printWatermarkedPages anywhere in the document in the same way you would normally use \ref.

  • There appears to be a bug if there is only one watermarked page, which causes the thing to say "pagenumberref@" instead of just "pagenumberref". I'm trying to track that down. – webb Sep 17 '15 at 17:53
  • 1
    @webb: What seems to work is \let\@nextWatermark\@gobble instead of \let\@nextWatermark\relax in \@printWatermarkedPage. – Werner Sep 17 '15 at 18:07
  • That did work, and everything works great, unless I don't define any watermarked pages. It's weird that this comes up even if I don't invoke the \printWatermarkedPages command, but right now the easiest solution is to just take this part out and have a separate class for now. – webb Sep 17 '15 at 20:33

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.