7

I need to write a script in elisp that warns me when a float appears before the page where that float is first referred. From the .aux file I can extract the label, the number, and the page number of the float. But I need to get the exact page in where each \ref command is placed. I tried:

\AtBeginDocument{\hypersetup{pageanchor=false}
\let\oldref\ref
\renewcommand{\ref}[1]{{\oldref{#1}\typeout{RefsPagesInLog --> {#1} \thepage}}}

so e.g., \ref{fig:2} in the .tex files prints:

RefsPagesInLog --> {fig:2} 29

in the log file. It almost works but sometimes fails. In very few cases it prints a wrong page number in the log file so my script fails.

Is there a trick to achieve the same goal?

The data I need are the label \ref refers to, and the "exact" page where the refs appear.

Gabriele
  • 1,815
  • 1
    Welcome to TeX.SE. A working/compilable document would be really nice, not just fragments –  Apr 21 '17 at 15:21
  • You're right. Because I'm professional typesetter the documents on which I work are copyrighted. I'll need some time to prepare a simplified example. Thanks. – Gabriele Apr 21 '17 at 15:34
  • Just a comment to explain where the problem (probably) comes from: \thepage is not completely reliable in the document main text, see e.g. https://tex.stackexchange.com/q/239452/82917 or https://tex.stackexchange.com/q/338084/82917. – campa Apr 21 '17 at 15:35
  • @campa Thanks! I already realized that the problem comes from the page and the examples you gave me really clarified me the reason. So I'd need to use \label to get the exact page number in the .aux. But I'm not able to imagine how to label a \ref command. – Gabriele Apr 21 '17 at 15:46
  • there's such a thing as a \hyperanchor that could be used (with a \label) to identify the location of a \ref. but each one has to be unique, so you'd still have the problem of identifying the \refs because you'd have to know the label name for each one. – barbara beeton Apr 21 '17 at 15:51

2 Answers2

6

This will write

\ref@page{<key>}{<page>}

in the .aux file for each \ref{<key>} command found in the document.

In the example case, you get

\ref@page{somefigure}{4}

which can be read by your external script.

\documentclass{article}

\usepackage{blindtext}

\usepackage{etoolbox}    
\usepackage{hyperref}

\makeatletter
\AtBeginDocument{%
  \renewcommand{\NR@setref}[1]{%
    \ref@page@write{#1}%
    \begingroup\@safe@activestrue\expandafter\endgroup
    \expandafter\NR@@setref\csname r@#1\endcsname
  }%
}
\newcommand{\ref@page@write}[1]{%
  \protected@write\@auxout{}{\string\ref@page{#1}{\thepage}}%
}
\newcommand{\ref@page}[2]{}
\makeatother

\begin{document}

\blindtext[10]

\clearpage

\ref{somefigure}

\section{First section}\label{firstsec}

\blindtext[50]


\begin{figure}
  \caption{Some figure}\label{somefigure}
\end{figure}

\blindtext[50]

\section{Second section}\label{secondsec}

\end{document}
egreg
  • 1,121,712
  • It works fine. I'll write an alternative version of my script using this hack then I'll test them for a while. Thank you! – Gabriele Apr 21 '17 at 22:10
  • Finally I adopted this solution because it works also with \ref commands within the caption environment. Thank you. – Gabriele Apr 24 '17 at 13:25
4

This labels (!) the usage of \ref with the label refusage:\therefusage and extracts the page where this occurs with \getpagerefnumber (contained in refcount package, but loaded by hyperref anyway!)

  • Remember to compile twice to get the cross-references correct!
  • Do not manipulate the refusage counter!

\documentclass{article}

\usepackage{etoolbox}    
\usepackage{hyperref}

\newcounter{refusage}

\AtBeginDocument{\hypersetup{pageanchor=false}
\let\oldref\ref
\renewcommand{\ref}[1]{{\refstepcounter{refusage}\label{refusage:\therefusage}\oldref{#1}\typeout{RefsPagesInLog --> {#1} \getpagerefnumber{refusage:\therefusage}}}}
\robustify\ref
}

\usepackage{blindtext}

\begin{document}

\blindtext[10]

\clearpage

\ref{somefigure}

\section{First section}\label{firstsec}

\blindtext[50]


\begin{figure}
  \caption{Some figure}\label{somefigure}
\end{figure}

\blindtext[50]


\section{Second section}\label{secondsec}




\end{document}
  • Almost works... but it fails (compiler fails and stop) when there's a \ref command inside a \caption{} :-( . I get the same failure with other tricks. – Gabriele Apr 21 '17 at 16:31
  • 1
    @GabrieleNicolardi: Try \protect\ref inside of a caption –  Apr 21 '17 at 16:38
  • Woooooooow! This fixes my problem and my script now works fine! Thank you! – Gabriele Apr 21 '17 at 16:48
  • @GabrieleNicolardi: I'll add a fix such that you don't need to specify \protect\ref all the time any longer –  Apr 21 '17 at 16:49
  • That would be even better! But I get: ! Undefined control sequence. \@begindocumenthook ...herefusage }}}} \robustify – Gabriele Apr 21 '17 at 16:57
  • 1
    @GabrieleNicolardi: Have you added \usepackage{etoolbox}? –  Apr 21 '17 at 16:58
  • Oh sorry. I missed it! That's great! Thank you very very much! – Gabriele Apr 21 '17 at 16:59