6

I have a long document which includes several files. In some cases I may want to include those files in different orders. In some cases, I may want to adapt the text depending on whether a specific \label has or has not been passed in the document.

The interface I was thinking of is a macro \iflabelexists{label}{foo}{bar}, which decides if \label{foo} has occurred already. If so, the macro expands foo; if not, bar.

The method I am currently trying is to patch \newlabel (a command written to the aux file when \label is expanded), to provide a toggle for each label. Then \label switches that toggle on.

\documentclass{article}
\usepackage{etoolbox}

\makeatletter
\patchcmd{\@newl@bel}{\global\@namedef{#1@#2}{#3}}{%
  \global\@namedef{#1@#2}{#3}%
  \global\providetoggle{l#1@#2}%
}
{\message{patching of \string\@newl@bel\space succeeded.}}
{\message{patching of \string\@newl@bel\space failed}}

\patchcmd{\label}{\@esphack}{%
  \pastlabel{#1}%
  \@esphack%
}
{\message{patching of \string\label\space succeeded}}
{\message{patching of \string\label\space failed}}

% each label ``foo'' results in a toggle ``lr@foo'' (label reference), 
% and \label{foo} sets \toggletrue{lr@foo}
\newcommand{\pastlabel}[1]{%
  \providetoggle{lr@#1}%
  \toggletrue{lr@#1}%
}

\newcommand{\iftoggleexists}[1]{%
    \ifcsdef{etb@tgl@#1}%
}
\newcommand{\gobble@two}[2]{\relax}

\newcommand{\ifpastlabel}[1]{%
  \iftoggleexists{lr@#1}{%
    \iftoggle{lr@#1}%
  }
  {% toggle does not exist so ambiguous
    \message{Warning: label reference toggle `#1' unknown.  Rerun to get toggles right.}%
    \textbf{??}%
    \gobble@two%
  }%
}
\makeatother

\begin{document}

\section{Bar}
\label{sec:bar}
Section \ref{sec:foo} \ifpastlabel{sec:foo}{has}{has NOT} been covered.

\section{Foo}
\label{sec:foo}
Section \ref{sec:bar} \ifpastlabel{sec:bar}{has}{has NOT} been covered.

\end{document}

If you rearrange the two document sections and compile (twice), the conditionals update correctly.

Before I adapt my whole document to this, I thought I'd ask the community: Is there a smarter way to do this, or a package I could use instead?

5
  • You might want to look at varioref which gives different texts depending on the relative position (same page, previous page, next page, befpre after,...) Nov 20, 2012 at 13:16
  • @DavidCarlisle: Thanks for the pointer. I need to look at varioref for another question anyway. Nov 20, 2012 at 13:18
  • I guess it all depends on what you are labelling. For example, if the end purpose is "label only the equations I refer to", the package mathtools and his option showonlyrefs is an out-of-the-box solution.
    – T. Verron
    Nov 20, 2012 at 13:32
  • 2
    If you don't want to distinguish between undefined labels and ones that haven't been set yet something like this should suffice: \patchcmd\label{\@bsphack}{\@bsphack\csdef{labelset@#1}{}}{}{} \newcommand*\ifpastlabel[1]{\ifcsdef{labelset@#1}} (still using etoolbox)
    – cgnieder
    Nov 20, 2012 at 13:41
  • 1
    (Testing for existance also is easy: test if \r@<labelname> is defined: \newcommand*\iflabelexists[1]{\ifcsdef{r@#1}})
    – cgnieder
    Nov 20, 2012 at 13:48

1 Answer 1

4

I do not see the point in hacking \newlabel to insert a "toggle". A macro marker defined by \label is all that is needed:

\documentclass{article}
\usepackage{etoolbox}

\makeatletter
\patchcmd{\label}{\@esphack}{%
  \pastlabel{#1}%
  \@esphack%
}
{\message{patching of \string\label\space succeeded}}
{\message{patching of \string\label\space failed}}

% each label ``foo'' results in a toggle ``lr@foo'' (label reference),
% and \label{foo} sets \toggletrue{lr@foo}
\newcommand{\pastlabel}[1]{%
  \global\expandafter\let\csname lr@#1\endcsname\@empty
}

\newcommand{\ifpastlabel}[1]{%
  \@ifundefined{lr@#1}{%
    \@ifundefined{r@#1}{%
      % toggle does not exist so ambiguous
      \message{Warning: label reference toggle `#1' unknown. %
        Rerun to get toggles right.}%
      \textbf{??}%
      \@gobbletwo
    }\@secondoftwo
  }\@firstoftwo
}
\makeatother

\begin{document}

\section{Bar}
\label{sec:bar}
Section \ref{sec:foo} \ifpastlabel{sec:foo}{has}{has NOT} been covered.

\section{Foo}
\label{sec:foo}
Section \ref{sec:bar} \ifpastlabel{sec:bar}{has}{has NOT} been covered.

\end{document}

You must log in to answer this question.

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