6

I have a macro that stores some text. I'd like to print the text of that macro as it was at the start of the page in the header, and as it is at the end of the page in the footer. I can do this for counters like so:

\documentclass{article}
\usepackage{scrpage2,lipsum}
\pagestyle{scrheadings}
\makeatletter
\newcounter{ctr}
\newcounter{@ctr}
\chead{\arabic{@ctr}\setcounter{@ctr}{\value{ctr}}}
\cfoot{\arabic{ctr}}
\setcounter{ctr}{1}
\setcounter{@ctr}{1}
\makeatother

When the header is set, (at the end of the page) it outputs the value of the internal counter @ctr and then sets that counter to be the value of the counter used by the user ctr. It sets it to the value at the end of the page (which will be the value at the beginning of the new page (which is what I want)).

When I try the "analogous" process for a macro that contains text rather than for a counter, I don't get what I want: the header is set with the value of the macro as it is at the end of the page. How can I fix this?

The following MWE shows the problem. The counter and the text should always refer to the same number, but they don't.

\documentclass{article}
\usepackage{scrpage2,lipsum}
\pagestyle{scrheadings}
\ohead{}

\makeatletter

\newcounter{ctr}
\newcounter{@ctr}
\chead{\arabic{@ctr}\setcounter{@ctr}{\value{ctr}}}
\cfoot{\arabic{ctr}}
\setcounter{ctr}{1}
\setcounter{@ctr}{1}

\def\thetext{First text}
\def\@thetext{\thetext}
\ihead{\@thetext\def\@thetext{\thetext}}
\ifoot{\thetext}

\makeatother

\begin{document}
\lipsum[1-4]

{\Large Becoming Second text}\stepcounter{ctr}
\def\thetext{Second text}

\lipsum[5-7]

{\Large Becoming Third text}\stepcounter{ctr}
\def\thetext{Third text}

\lipsum[8-11]

{\Large Becoming Fourth text}\stepcounter{ctr}
\def\thetext{Fourth text}

\lipsum[12]
\end{document}

This looks to me like it's probably some sort of expansion problem. I tried playing with \edef instead of \def but if I couldn't get the desired result. What am I doing wrong?

2
  • I am trying to solve a similar problem tex.stackexchange.com/questions/20512/…. Jul 19, 2011 at 17:24
  • 1
    Your system will not work in reliable way for counters either. Due to the asynchronous page breaking there is the danger that you get values from following pages. If you want to put variable text depending on the content of the current page in the headers always use \mark-command. Jul 20, 2011 at 9:43

3 Answers 3

7

You need to use \edef (expanding \def) or better \xdef (global expand) instead of \def, otherwise you simply define \@thetext to expand to \thetext which then expands to its then current definition. So constantly saying \def\@thetext{\thetext} doesn't change its definition at all. What you want to do is to assign the current value of \thetext to \@thetext not "reference" it.

LaTeX provides an extended version called \protected@xdef which takes care that the \protect will work properly in its argument. (There is also a \protected@edef.)

\def\thetext{First text}
\def\@thetext{\thetext}
\ihead{\@thetext\protected@xdef\@thetext{\thetext}}
\ifoot{\thetext}
7
  • \xdef being a mix of \edef and \gdef, or a \global\edef
    – raphink
    Jul 19, 2011 at 15:29
  • 2
    This can have adverse effects if \thetext is not completely expandable; \protected@xdef would be safer.
    – egreg
    Jul 19, 2011 at 15:30
  • @egreg: Very good point! I will edit this in. Jul 19, 2011 at 15:31
  • @Raphink: \xdef is the same as \global\edef. Also, \gdef is simply a short version of \global\def. Jul 19, 2011 at 15:36
  • 1
    The first definition of \@thetext needs to be \xdef or \edef as well. Otherwise, the first couple of pages get it wrong... And just using \edef isn't enough inside the \ifoot you need it to be global...
    – Seamus
    Jul 19, 2011 at 15:40
2

Here's a first approximation using \marks:

\documentclass{article}
\usepackage{lipsum,etex}
\usepackage{scrpage2}
\pagestyle{scrheadings}
\ohead{}

\makeatletter

\newmarks\grillmark

\newcounter{ctr}
\newcounter{@ctr}
\chead{\arabic{@ctr}\setcounter{@ctr}{\value{ctr}}}
\cfoot{\arabic{ctr}}
\setcounter{ctr}{1}
\setcounter{@ctr}{1}

\ihead{%
  \ifnum\value{page}=1 
    \expandafter\firstmarks
  \else
    \expandafter\topmarks
  \fi\grillmark}% changed per Martin's suggestion
\ifoot{\botmarks\grillmark}

\makeatother

\begin{document}
\marks\grillmark{First text}
\lipsum[1-4]

{\Large Becoming Second text}\stepcounter{ctr}
\marks\grillmark{Second text}

\lipsum[5-7]

{\Large Becoming Third text}\stepcounter{ctr}
\marks\grillmark{Third text}

\lipsum[8-11]

{\Large Becoming Fourth text}\stepcounter{ctr}
\marks\grillmark{Fourth text}

\lipsum[12]

{\Large Becoming Fifth text}\stepcounter{ctr}
\marks\grillmark{Fifth text}
\lipsum[13-15]
\vspace{0.75in}% Enough to get to end of page

{\Large Becoming Sixth text}\stepcounter{ctr}
\marks\grillmark{Sixth text}
\lipsum[16]
\end{document}

The explanation is in the TeXbook or TeX by Topic: generalized marks work the same as the standard marks in TeX, with the difference that the commands have a final "s" and need a number after them. Here the number is allocated through \newmarks provided by etex. The standard marks are available also as \marks0 for setting a mark and \firstmarks0, \topmarks0 and \botmarks0 for retrieving the marks. There are 32767 mark classes: more than enough, I believe.

6
  • 1
    The \grillmarks work pretty good (nice name BTW). But with the example above there are a few minor issues: Bottom of Page 3 has the number 6, but should be 5. Top of Page 4 should have "Sixth text" instead of "Fifth text". Jul 20, 2011 at 2:27
  • Actually you should use two marks, one for the top and one for the bottom. The problem of a section starting at the top of the page should be solvable with Javier's trick.
    – egreg
    Jul 20, 2011 at 7:48
  • Sorry, don't know what Javier's trick refers to? Jul 20, 2011 at 8:12
  • 1
    @Peter Oh, sorry! I worked thinking it was your question! The marks should be called \seamusmark, instead. There's a trick of Javier Bezos in his titlesec package just for this.
    – egreg
    Jul 20, 2011 at 8:21
  • Yeah, my problem which I linked to in the comment to this question is pretty much identical so can see how they can be confused. Jul 20, 2011 at 8:25
0

This is not an answer, but a comment. I need to add code, hence posting it here.

It appears that there is an issue with this solution if the value of the macro changes at the top of a page. The following MWE includes the fixes suggested by Martin and Seamus, and has additional Fifth and Sixth test to illustrate the problem:

\documentclass{article}
\usepackage{lipsum}
\usepackage{scrpage2}
\pagestyle{scrheadings}
\ohead{}

\makeatletter

\newcounter{ctr}
\newcounter{@ctr}
\chead{\arabic{@ctr}\setcounter{@ctr}{\value{ctr}}}
\cfoot{\arabic{ctr}}
\setcounter{ctr}{1}
\setcounter{@ctr}{1}

\def\thetext{First text}
\xdef\@thetext{\thetext}% changed \def to \xdef per Seamus's comment
\ihead{\@thetext\protected@xdef\@thetext{\thetext}}% changed per Martin's suggestion
\ifoot{\thetext}

\makeatother

\begin{document}
\lipsum[1-4]

{\Large Becoming Second text}\stepcounter{ctr}
\def\thetext{Second text}

\lipsum[5-7]

{\Large Becoming Third text}\stepcounter{ctr}
\def\thetext{Third text}

\lipsum[8-11]

{\Large Becoming Fourth text}\stepcounter{ctr}
\def\thetext{Fourth text}

\lipsum[12]

{\Large Becoming Fifth text}\stepcounter{ctr}
\def\thetext{Fifth text}
\lipsum[13-15]
\vspace{0.75in}% Enough to get to end of page

{\Large Becoming Sixth text}\stepcounter{ctr}
\def\thetext{Sixth text}
\lipsum[16]
\end{document}

Note that bottom of Page 3 should have referred to 5, and not 6.

4
  • It's due to the asynchronous behavior of the page splitting procedure: TeX always typesets an entire paragraph before deciding where to split a page. The only safe way is to use the \label-\ref mechanism, probably with the refcount package to be sure of using actual numbers and not typesetting instructions.
    – egreg
    Jul 19, 2011 at 21:14
  • Of course there is also the "mark" mechanism; with e-TeX one has plenty of marks to play with.
    – egreg
    Jul 19, 2011 at 21:28
  • That sounds interesting. Where can I find example usage of that? The documentation I found via Google does not have much info on this. Jul 19, 2011 at 21:33
  • See my answer. :)
    – egreg
    Jul 19, 2011 at 21:48

You must log in to answer this question.

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