Discussion:
hyperref and redefining label, ref, and pageref again
(too old to reply)
i***@gmail.com
2006-10-23 15:31:55 UTC
Permalink
I am trying to chain another set of macros to the end of the \label,
\ref, and \pageref macros. Basically, I want to do later referencing
analysis in perl (such as what labels are used most often, where I have
useless labels, where I have forward references, etc. I plan to post
this for public consumption once it works). Therefore I have written a
short style file to just write every encounter to an '.mrl' file, and
use whatever the macros were. Alas, as soon as I usepackage hyperref,
it no longer works. The file is created, but nothing is ever written
to it.I believe hyperref prevents the chaining.

I have in mrl.sty:

% [1] squirrel away whatever the original definition is
\let\labelmrl\label
\let\refmrl\ref
\let\pagerefmrl\pageref

% [2] use the original, but also write it out to the .mrl file
\renewcommand\label[1]{\labelmrl{#1}\mrlwrite{label*#1}}
\renewcommand\ref[1]{\refmrl{#1}\mrlwrite{ref*#1}}
\renewcommand\pageref[1]{\pagerefmrl{#1}\mrlwrite{pageref*#1}}

% [3] provide the backend to save all the information
\providecommand\curfilename{\jobname}

\newwrite\mymrlptr % we need a file pointer
\immediate\openout\mymrlptr=\jobname.mrl

\makeatletter
\def\mrlwrite#1{%
\typeout{WRITING OUT RIGHT NOW #1}%
\@bsphack%

{\immediate\write\mymrlptr{***#1*\thepage*\the\inputlineno*\curfilename***}}
\@esphack%
}
\makeatother

----------------
\documentclass{article}

\usepackage{mrl}

\usepackage{hyperref} % renders mrl.sty useless; it does not matter
whether mrl is before or after

\begin{document}

\section{Hello}

This is an example.

\label{a-useless-label}

This is an example.

\label{label-on-p1} This is a ref to \ref{label-on-p2} on page
\pageref{label-on-p2}.

\ref{a-bad-reference}

\clearpage

\label{label-on-p2} This is a ref to \ref{label-on-p1} on page
\pageref{label-on-p1}.

\label{a-useless-label}

\end{document}


How am I supposed to do this?

regards,

/ivo
Heiko Oberdiek
2006-10-23 17:00:50 UTC
Permalink
Post by i***@gmail.com
% [1] squirrel away whatever the original definition is
\let\labelmrl\label
\let\refmrl\ref
\let\pagerefmrl\pageref
Also nameref redefines them -- hyperref loads nameref
\AtBeginDocument.

Yours sincerely
Heiko <***@uni-freiburg.de>
Heiko Oberdiek
2006-10-23 17:00:50 UTC
Permalink
Post by i***@gmail.com
\renewcommand\label[1]{\labelmrl{#1}\mrlwrite{label*#1}}
\def\mrlwrite#1{%
\typeout{WRITING OUT RIGHT NOW #1}%
{\immediate\write\mymrlptr{***#1*\thepage*\the\inputlineno*\curfilename***}}
}
\makeatother
BTW, the original \label (\labelmrl) also uses \@bsphack...\@esphack.
Two following \@bsphack...\@esphack will not work as expected,
instead you have to surround all:

\renewcommand*{\label}[1]{%
\@bsphack
\labelmrl{#1}%
\mrlwrite{label*#1}%
\@esphack
}

Yours sincerely
Heiko <***@uni-freiburg.de>
i***@gmail.com
2006-10-23 18:18:41 UTC
Permalink
hi heiko: this at least fixes my incredulous staring at my code and
not understanding why this did not work. as author of nameref, how
would you suggest I hook into \label, \ref, and \pageref (preferably
with a package), so that I can produce the .mrl output file that I want
to produce? Should I simply wrap my code into a beginatdocument, too,
or is there a better hook method?

regards,

/ivo
Heiko Oberdiek
2006-10-23 19:46:09 UTC
Permalink
Post by i***@gmail.com
hi heiko: this at least fixes my incredulous staring at my code and
not understanding why this did not work. as author of nameref, how
would you suggest I hook into \label, \ref, and \pageref (preferably
with a package), so that I can produce the .mrl output file that I want
to produce? Should I simply wrap my code into a beginatdocument, too,
or is there a better hook method?
Just request, that nameref is loaded before your package.

Yours sincerely
Heiko <***@uni-freiburg.de>
Donald Arseneau
2006-10-23 18:11:20 UTC
Permalink
Post by i***@gmail.com
\ref, and \pageref macros. Basically, I want to do later referencing
analysis in perl .... Therefore I have written a
short style file to just write every encounter to an '.mrl' file,
Why? Perl is quite capable of pulling the information out of the .aux
file(s).
--
Donald Arseneau ***@triumf.ca
i***@gmail.com
2006-10-23 18:48:09 UTC
Permalink
Post by Donald Arseneau
Post by i***@gmail.com
\ref, and \pageref macros. Basically, I want to do later referencing
analysis in perl .... Therefore I have written a
short style file to just write every encounter to an '.mrl' file,
Why? Perl is quite capable of pulling the information out of the .aux
file(s).
--
hi don:

I believe \ref{} and \pageref{} are not logged to the .aux files.
(minor: labels seem to follow different formats, depending on whether
hyperref is used or not.)

I could write a style file that logs to the .aux files, but then I
still need to write a package, plus then my perl code needs to sort out
the tree of which tex file inputs which other tex file. at this point,
it becomes easier to just log everything that I want into one .mrl
file, even if it wastes a little space. this single file can then be
easily analyzed with minimal parsing complications.

please let me know if I am mistaken so that this is not a good
strategy.

regards,

/ivo
Ulrich Diez
2006-10-23 15:41:38 UTC
Permalink
Post by i***@gmail.com
I am trying to chain another set of macros to the end of the \label,
\ref, and \pageref macros. Basically, I want to do later referencing
analysis in perl
This issue seems to be closely related to another thread started
by you back in 2004:

| From: ***@anderson.ucla.edu (ivo welch)
| Newsgroups: comp.text.tex
| Subject: detect forward references?
| Date: 12 Jun 2004 09:34:40 -0700
| Message-ID: <***@posting.google.com>
|
| hi: how would I systematically detect forward references? that is,
| in my 600 page book, I would like to know which labels are referenced
| before they are created. There are of course includes and inputs in
| various places. I would like to have the ability to just check that
| they make sense.
|
| sincerely, /iaw
Post by i***@gmail.com
such as what labels are used most often, where I have
useless labels, where I have forward references, etc.
"useless" label or "unused label"?
There are situations where a label within your document might
get defined but never used for referencing within your document.
E.g., due to label-import via xr/xr-hyper-package while the
"unused" label in question is used by the other document...
Post by i***@gmail.com
I plan to post
this for public consumption once it works). Therefore I have written a
short style file to just write every encounter to an '.mrl' file, and
use whatever the macros were. Alas, as soon as I usepackage hyperref,
it no longer works. The file is created, but nothing is ever written
to it.I believe hyperref prevents the chaining.
I experienced similar problems when playing around with the
referencing-mechanism: Hyperref loads the nameref-package by
means of \AtBeginDocument. nameref redefines the referencing-
macros. This means there are great chances that your
redefinitions of the referencing-macros will get overridden by
the stuff that was placed into/launched by the
\AtBeginDocument-Hook.

You need to make sure that your changes take place after
loading nameref while nameref
- could be loaded in the preamble without hyperref,
- 's loading could be launched by hyperref via \AtBegindocument
- ...

The best strategy is possibly making the user read the fine
manual and follow the instruction of not loading the package
before other packages like hyperref/nameref etc.

Another strategy might be putting your changes/patches into the
\AtBeginDocument-hook while issuing a warning in case mrl.sty is
loaded _before_ the hyperref-package:

\@ifpackageloaded{hyperref}{%
\AtBeginDocument{%
<TAKE ACTION IN THE WAY WHICH IS NECESSARY WITH HYPERREF>
}%
}{%
\AtBeginDocument{%
\@ifpackageloaded{hyperref}%
{%
\PackageWarningNoLine
{mrl}%
{Load package `mrl' after package `hyperref'}%
\stop % push the panic-button
}{}%
}%
\AtBeginDocument{%
<TAKE ACTION IN THE WAY WHICH IS NECESSARY WITHOUT HYPERREF>
}%
}%
Post by i***@gmail.com
% [1] squirrel away whatever the original definition is
\let\labelmrl\label
\let\refmrl\ref
\let\pagerefmrl\pageref
% [2] use the original, but also write it out to the .mrl file
\renewcommand\label[1]{\labelmrl{#1}\mrlwrite{label*#1}}
\renewcommand\ref[1]{\refmrl{#1}\mrlwrite{ref*#1}}
\renewcommand\pageref[1]{\pagerefmrl{#1}\mrlwrite{pageref*#1}}
What about
- \nameref
- \titleref
- \autoref
- ams-package(s)
- babel-package(s)
- zref-package
- varioref-package (which afaik create \labels on the fly)
- refcount-package
- xr/xr-hyper-package
[ - labelcas-package
- elidpref-package ] ;-)
- "from-scratch" user-defined referencing-macros ... ?

With LaTeX kernel-macros and hyperref, referencing-workflow is:

\label{<label>} in main tex yields
\newlabel{<label>}{{}{}{}{}{}} in aux which yields defining
\r@<label> -> {<section-number>}
{<page-number>}
{<section-name>}
{<href-anchor>}
{<external URL>}

All referencing-macros "expand" \r@<label> and "grab" the
appropriate arguments...

About two years ago, when this 2004-thread took place, there was
this "PrvRefLg"-thing and I failed when thinking about replacing
it by a mechanism where you don't need to change each single
referencing-macro:

I thought about redefining \label and \newlabel:
1) Redefine \label so that any usage of \label would be noted
within an external file.
2) Redefine \newlabel so that \r@<label> gets defined to also
note its usage within the same external file.

On the second glimpse I could not see a feasible approach for
2) as \r@<label> is supposed to be usable in expandable contexts
also (->refcount, hyperref,...) while "\write" etc is not
expandable.

I think currently you cannot get away without modifying each
referencing-macro/each user-macro which is intended for calling
instances of \r@<label>-macros.

This is fun because there are already many packages which rede-
fine the LaTeX-kernel's referencing-macros. For doing the right
patching, you may need to track down all possible combinations
of how those packages might be loaded.
Also you never know if/how the user does introduce her own
referencing-macros from scratch and thus cannot prepare for this
case at all.

A (cumbersome) strategy for making sure that your package is
loaded as the last one, could be: Nest something like the
following where the actual changes/patches go into the innermost
nesting-branches, enclosed into "\AtBeginDocument".

\newcommand\@ifpackageloadedLaterloadedwarn[3]{%
\@ifpackageloaded{#1}{%
#2%
}{%
\AtBeginDocument{%
\@ifpackageloaded{#1}%
{%
\PackageWarningNoLine
{mrl}%
{Load package `mrl' after package `#1'}%
\stop % push the panic-button
}{}%
}%
#3%
}%
}%

Could be put together to something like:

\@ifpackageloadedLaterloadedwarn{hyperref}{%
\AtBeginDocument{%
% REDEFINE REFERENCING MACROS AS NECESSARY WITH
% HYPERREF AND NAMEREF
}%
}{%
\@ifpackageloadedLaterloadedwarn{nameref}{%
\AtBeginDocument{%
% REDEFINE REFERENCING MACROS AS NECESSARY WITHOUT
% HYPERREF BUT WITH NAMEREF
}%
}{%
\AtBeginDocument{%
% REDEFINE REFERENCING MACROS AS NECESSARY WITHOUT
% BOTH HYPERREF AND NAMEREF
}%
}%
}%

You could introduce more nesting-levels, taking into account that
some packages "provide support" for other packages.
E.g., hyperref provides support for varioref in case varioref is
loaded...

If you decide for patching "\label" and all referencing-macros
in favor of a mechanism where expanding an instance of the
\label-macro or expanding an instance of a referencing-macro
(e.g., \ref, \pageref, \autoref...) leads to writing to an
external-file, I suggest making the redefined/patched variants
of these macros robust (\DeclareRobustCommand) so that instances
of these macros won't get expanded within \***@edef or
\***@write where an expandable "\write" must not occur.

Perhaps you wish to make writing the external file which is
intended for later evaluation via Perl (or possibly via some
other script which is also written in (La)TeX ) optional.

In this case you could implement a mechanism similar to
\addcontents and \@starttoc (the latter is called internally by
\tableofcontents, \listoffĂ­gures, listoftables etc).

The workflow with \addcontents is:

- \addcontents does write to the ".aux"-file an entry of the
pattern: \@writefile{<extension>}{<stuff>}
( e.g. \@writefile{toc}{This is a sentence.} )

- \@writefile does write <stuff> to the \write-register
"\tf@<extension>" only in case the register is defined/
allocated. Otherwise it does nothing.

- The ".aux"-file/s is (are) read at the beginning and the end
of compilation.

- When the aux-file(s) is read at the beginning of compilation,
the register \tf@<table-extension> does not yet exist, so
nothing happens when those \@writefile-entries come to be
executed.

- Maybe the register gets allocated during compilation (due to
some instance of "\@starttoc").
In this case reading the aux-file at the end of compilation
yields that the stuff in the \@writefile-entries is written
to that register/to the file which is associated to that
register.
Otherwise still nothing happens.

So when patching your macros, you can use the "\addcontents"-
macro for (indirectly) writing to your external file.
For enabling creation of your external file, you can use
something similar to "\@starttoc" (used within \tableofcontents,
\listoftables, \listoffigures) which does also allocate a new
\write-register but which does not input the external file.
[Alternatively you could just "neutralize" \@starttoc's
inputting-process by making sure that your external file
starts with "\endinput".]

Assuming that the file containing the list of defined/used
labels is called \jobname.rft, you can redefine your
referencing-commands to also do something like

\addcontents{rft}
{\string\labeldefine{<name of label>}{whatever else you need}}

respectively

\addcontents{rft}
{\string\labeluse{<name of label>}{whatever else you need}}

For enabling creation of \jobname.rft, you can define something
similar to \@starttoc:

\newcommand*\createRefUsageFile{%
\@bsphack
\begingroup
\@ifdefinable\***@rft{%
\***@filesw
\newwrite\***@rft
\immediate\openout\***@rft\jobname.rft\relax
\fi
}%
\endgroup
\@esphack
}%

[
Alternatively:

\AtBeginDocument{%
\addcontents{rft}{\string\endinput}
}%

\newcommand*\createRefUsageFile{%
\@bsphack
\@starttoc{rft}
\@esphack
}%
]

If \createRefUsageFile appears somewhere in your documents,
\jobname.rft gets created and you can use it for further
evaluation e.g., by Perl or by some other TeX-script where
"\labeldefine" and "\labeluse" are defined control-sequences.
(You could even input it into the main-tex-file while defining
\labeldefine / \labeluse to write messages to the log-file...)

For reloading into TeX a file which starts with "\endinput", you
can locally redefine \endinput:

\begingroup
\let\endinput\endgroup
\input{<file with leading "\endinput">}

Seems to work sometimes.

Good luck.

Ulrich
i***@gmail.com
2006-10-25 00:36:23 UTC
Permalink
Post by Ulrich Diez
Post by i***@gmail.com
I am trying to chain another set of macros to the end of the \label,
\ref, and \pageref macros. Basically, I want to do later referencing
analysis in perl
This issue seems to be closely related to another thread started
hi ulrich---thank you for the very long post. this seems to be quite a
task, after all, and pretty much beyond my skills. I can play around
with perl, but even after 10 years, latex is still mostly a black box
to me. as for my earlier attempt last week, I have already learned
that something else in my more naive attempt seems to redefine my
labels inside equations, even after I take care of nameref. yuck!

in 2004, I wrote something called reflabel.pl, which I also posted,
which at least checks whether all refs have labels, where multiple
definitions of labels are, and where there are unused labels. equally
important, it follows standard compiler output format, so emacs can
page you nicely through the errors.

last week, I thought that this would be easier and cleaner (especially
on the forward references) if I would just write everything in sequence
to a file, and I could do more things. little did I know...I give up.
not important enough.

thanks everyone for helping on this one.

best regards,

/ivo

Loading...