# How can I test if a label has been marked?

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?

• You might want to look at varioref which gives different texts depending on the relative position (same page, previous page, next page, befpre after,...) – David Carlisle Nov 20 '12 at 13:16
• @DavidCarlisle: Thanks for the pointer. I need to look at varioref for another question anyway. – Matthew Leingang Nov 20 '12 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 '12 at 13:32
• 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 '12 at 13:41
• (Testing for existance also is easy: test if \r@<labelname> is defined: \newcommand*\iflabelexists[1]{\ifcsdef{r@#1}}) – cgnieder Nov 20 '12 at 13:48

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}