Hypertext marks in L^{A}TEX^{∗}

Sebastian Rahtz and Yannis Haralambous

1994/10/02

Contents

1 Introduction 1

2 Usage 2

3 Original, history and acknowledgements 2

4 The macros 3 4.1 Package options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 4.2 Basic hypertext macros . . . . . . . . . . . . . . . . . . . . . . . . 6 4.3 User hypertext macros . . . . . . . . . . . . . . . . . . . . . . . . . 8 4.4 Compatibility with the L^{A}TEX2html package . . . . . . . . . . . . . 10 4.5 Direct Acrobat ‘pdfmark’ insertion . . . . . . . . . . . . . . . . . . 10 4.6 Automated L^{A}TEX hypertext cross-references . . . . . . . . . . . . . 13 4.7 Equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 4.8 Footnotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 4.9 Float captions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 4.10 Bibliographic references . . . . . . . . . . . . . . . . . . . . . . . . 17 4.11 Page numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 4.12 Table of contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 4.13 New counters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 4.14 AMS L^{A}TEX compatibility . . . . . . . . . . . . . . . . . . . . . . . 18 4.15 Included figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 4.16 Index entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 4.17 Bookmarks in PDF file . . . . . . . . . . . . . . . . . . . . . . . . . 20 4.18 Low-level utility macros . . . . . . . . . . . . . . . . . . . . . . . . 21

∗This file has version number v1.5i, last revised 1994/10/02.

1 Introduction

This package derives from and builds on the work of the HyperTEX project; see http://xxx.lanl.gov/hypertex/. It aims to extend the functionality of all the L^{A}TEX cross-referencing commands (including the table of contents) to produce \special commands which are parsed by dvi processors conforming to the HyperTEX guidelines (i.e. xhdvi and dvihps); it provides general hypertext links, including those to external documents.

The package also provides a generalized interface to Acrobat pdfmark commands.

The HyperTEX specification (this is borrowed from an article by Arthur Smith) says that conformant viewers/translators must recognize the following set of \special commands:

href: html:<a href = "href_string">
name: html:<a name = "name_string">
end: html:</a>
image: html:<img src = "href_string">
base_name: html:<base href = "href_string">

The href, name and end commands are used to do the basic hypertext operations of establishing links between sections of documents. The image command is intended (as with current html viewers) to place an image of arbitrary graphical format on the page in the current location. The base_name command is be used to communicate to the dvi viewer the full (URL) location of the current document so that files specified by relative URL’s may be retrieved correctly.

The href and name commands must be paired with an end command later in the TEX file — the TEX commands between the two ends of a pair form an anchor in the document. In the case of an href command, the anchor is to be highlighted in the dvi viewer, and when clicked on will cause the scene to shift to the destination specified by href_string. The anchor associated with a name command represents a possible location to which other hypertext links may refer, either as local references (of the form href="#name_string" with the name_string identical to the one in the name command) or as part of a URL (of the form URL#name_string). Here href_string is a valid URL or local identifier, while name_string could be any string at all: the only caveat is that ‘"’ characters should be escaped with a backslash (\), and if it looks like a URL name it may cause problems.

2 Usage

Use this package with any more or less normal L^{A}TEX document with \usepackage{hyperref}. Make sure it comes last of your loaded packages, to give it a fighting chance of not being over-written. The resulting dvi file can be processed with xhdvi or dvihps and hopefully you will find that all cross-references work correctly as hypertext.

3 Original, history and acknowledgements

The original authors of hyperbasics.tex and hypertex.sty, from which this package descends, are:

Tanmoy Bhattacharya

     tanmoy@qcd.lanl.gov

Los Alamos National Laboratory

New Mexico, 87544-0285

USA and Thorsten Ohl

     Thorsten.Ohl@Physik.TH-Darmstadt.de

Technische Hochschule Darmstadt

Schloßgartenstr. 9 D-64289 Darmstadt Germany

Eventually I (SPQR) think I have rewritten most of the stuff, because I didn’t understand a lot of the original, and was only interested in getting it to work with L^{A}TEX 2ε; it still has problems, but the majority of L^{A}TEX documents go through, with good PDF functionality.

Tanmoy Bhattacharya found a great many of the bugs, and (even better) often provided fixes, which has made the package more robust.

I am grateful to Michael Mehlich, whose hyper package (developed in parallel with hyperref) solved some problems for me. Hopefully the two packages will combine one of these days!

Thanks to Arthur Smith, Paul Ginsparg, David Carlisle and Leslie Lamport for comments, thoughts and code.

4 The macros

1 ⟨∗package⟩

4.1 Package options

It does need the June 95 L^{A}TEX, because it uses \protected@write, and it defines commands in options.

 2 \newif\if@NeedsBackref
 3 \newif\ifHyper@nativepdf
 4 \newif\ifHyper@Figures
 5 \newif\ifHyper@Nesting

 6 \newif\ifHyper@Index
 7 \newif\ifPlain@Pages
 8 \newif\if@ActiveAnchor
 9 \newif\ifHyper@raiselinks
10 \Hyper@raiselinksfalse
11 \newdimen\@linkdim
12 \Hyper@Indextrue
13 \Hyper@Figuresfalse
14 \Hyper@Nestingfalse
15 \@NeedsBackreffalse
16 \NeedsTeXFormat{LaTeX2e}[1995/06/01]
17 \ProvidesPackage{hyperref}[\filedate\space HyperTeX links for LaTeX]
18 \RequirePackage{color}
19 \RequirePackage{keyval}
20 \RequirePackage{nameref}

The ‘draft’ option makes the low-level macros no-ops.

21 \DeclareOption{draft}{\AtBeginDocument{%
22  \gdef\hyper@anchor#1#2{#2}%
23  \gdef\hyper@link#1#2#3{#3}%
24  \def\literalps@out#1{}%
25  \typeout{* Hyperref: Draft mode *}
26 }%

27 }

The driver dependent part of PDF support, as we need to pass pdfmark commands straight through to the PS file; the ps: convention is quite common, but you’ll have to worry about it for other drivers. Life is too short to go around working on it for others, and providing a full set of options. The small header file defines the necessary escape for pdfmark on normal PS printers.

28 \DeclareOption{pdfmark}{%
29 \def\literalps@out#1{\special{ps:#1}}%
30 \special{header=pdfmark.pro}
31 \typeout{* Hyperref:  pdfmark generation ON *}%

32 }

33 \DeclareOption{nopdfmark}{%
34 \def\literalps@out#1{}%
35 \typeout{* Hyperref:  pdfmark generation OFF*}%

36 }

37 \DeclareOption{nativepdf}{%
38 \Hyper@nativepdftrue

39 }

40 \DeclareOption{nonativepdf}{%
41  \typeout{* Hyperref: native pdf mode *}%
42 \Hyper@nativepdffalse

43 }

Colouring links at the L^{A}TEX level is useful for debugging, perhaps.

44 \DeclareOption{colorlinks}{%
45 \def\colorlink#1{\color{#1}}%
46  \typeout{* Hyperref: link coloring mode *}

48 \DeclareOption{nocolorlinks}{%
49 \def\colorlink#1{}%
50  \typeout{* Hyperref: no link coloring *}%

51 }

If we are going to PDF, the dvips processor does not know the height of a link, as it works solely on the position of the closing \special. If we use this option, the \special is raised up by the right amount, to fool the dvi processor.

52 \DeclareOption{raiselinks}{%
53 \Hyper@raiselinkstrue

54 }

55 \DeclareOption{noraiselinks}{%
56 \Hyper@raiselinksfalse

57 }

Set up back-referencing to be hyper links, by page, section number, or section title.

58 \DeclareOption{backref}{%
59 \PassOptionsToPackage{hyperref}{backref}
60 \@NeedsBackreftrue
61 \typeout{* Hyperref: backref mode *}

62 }

63 \DeclareOption{pagebackref}{%
64 \PassOptionsToPackage{hyperpageref}{backref}
65 \@NeedsBackreftrue
66 \typeout{* Hyperref: backref by page mode *}

67 }

Make index entries be links back to the relevant pages. By default this is turned on, but may be stopped.

68 \DeclareOption{hyperindex}{%
69 \Hyper@Indextrue
70 \typeout{* Hyperref: hyperindex mode *}

71 }

72 \DeclareOption{nohyperindex}{%
73 \Hyper@Indexfalse
74 \typeout{* Hyperref: no hyperindex mode *}

75 }

Are the page links done as plain arabic numbers, or do they follow the formatting of the package? The latter loses if you put in typesetting like \textbf or the like.

76 \DeclareOption{plainpages}{%
77 \Plain@Pagestrue
78 \typeout{* Hyperref: plainpages mode *}

79 }

80 \DeclareOption{noplainpages}{%
81 \Plain@Pagesfalse
82 \typeout{* Hyperref: no plainpages mode *}

83 }

Make included figures (assuming they use the standard graphics package) be HTML links. Off by default.

 84 \DeclareOption{hyperfigures}{\Hyper@Figurestrue}
 85 \DeclareOption{nohyperfigures}{\Hyper@Figuresfalse}

Currently, dvihps doesn’t allow anchors nested within targets, so this option tries to stop that happening. Other processors may be able to cope.

 86 \DeclareOption{nonesting}{%
 87 \Hyper@Nestingfalse
 88 \typeout{* Hyperref: no nesting *}

89 }

 90 \DeclareOption{nesting}{%
 91 \Hyper@Nestingtrue
 92 \typeout{* Hyperref: nesting allowed *}

93 }

 94 \def\@nil{}
 95 \ExecuteOptions{raiselinks,nocolorlinks,noplainpages,%
 96 nonesting,hyperindex,nohyperfigures,pdfmark,nonativepdf}
 97 \ProcessOptions
 98 \if@NeedsBackref
 99 \RequirePackage{backref}
100 \fi
101 \def\LinkColor{red}
102 \def\AnchorColor{blue}
103 \@ActiveAnchorfalse

4.2 Basic hypertext macros

Links have a filename (possibly a URL), an internal name, and some marked text. Anchors have a name, and marked text.

104 \long\def\hyper@link#1#2#3{%
105 \ifHyper@nativepdf
106 \def\hyper@hash{}%
107 \ifx\\#1\\
108  \pdfmark[#3]{pdfmark=/LNK,Dest=#2}%
109 \else
110  \pdfmark[#3]{pdfmark=/LNK,Action=/GoToR,File=#1,Dest=#2}%
111 \fi
112 \else

If we want to raise up the final link \special, we need to get its height; ask me why L^{A}TEX constructs make this totally foul up, and make us revert to basic TEX. I do not know.

113 \ifHyper@raiselinks
114 \setbox\@tempboxa=\hbox{#3}%
115 \@linkdim\dp\@tempboxa
116 \lower\@linkdim\hbox{\special{html:<A href=\hyper@quote#1#2\hyper@quote>}}%
117 {\colorlink{\LinkColor}#3}%
118 \@linkdim\ht\@tempboxa

Because of the interaction with the dvihps processor, we have to subtract a little from the height. This is not clean, or checked. Check with Mark Doyle about what gives here.

119 \advance\@linkdim by -6.5\p@
120 \raise\@linkdim\hbox{\special{html:</A>}}%
121 \else
122 \special{html:<A href=\hyper@quote#1#2\hyper@quote>}%
123 {\colorlink{\LinkColor}#3}%
124 \special{html:</A>}%
125 \fi
126 \fi

127 }

We have to be careful with the marked text, as if we break off part of something to put a \special around it, all hell breaks loose. Therefore, we check the category code of the first token, and only proceed if its safe. Tanmoy sorted this out.

128 \long\def\hyper@anchor#1#2{%
129 \ifHyper@nativepdf
130 \pdfmark[#2]{pdfmark=/DEST,Dest=#1}%
131 \else
132 \hyper@@anchor{#1}{#2}%
133 \fi

134 }

135 \long\def\hyper@@anchor#1#2{%
136 \ifx\\#1\\
137 \typeout{empty link? #1: #2}#2
138 \else
139 \def\anchor@spot{#2}%
140 \def\put@me@back{}%
141 \ifx\relax#2\relax
142 \else
143  \ifHyper@Nesting
144  \else
145  \ifcat a\noexpand#2 \relax
146  \else
147  \ifcat 0\noexpand#2 \relax
148  \else
149  \typeout{Anchor start is not alphanumeric on input line
150  \the\inputlineno}%
151  \def\anchor@spot{}%
152  \def\put@me@back{#2}%
153  \fi
154  \fi
155  \fi
156 \fi
157 \if@ActiveAnchor
158  \anchor@spot
159 \else
160  \special{html:<A name=\hyper@quote #1\hyper@quote>}%
161  \@ActiveAnchortrue

162  \bgroup\colorlink{\AnchorColor}\anchor@spot\egroup
163  \special{html:</A>}%
164  \@ActiveAnchorfalse
165 \fi
166 \expandafter\put@me@back
167 \fi

168 }

169 \long\def\hyper@pointanchor#1{\special{html:<A #1></A>}}

We may need to keep the beginning and end of the anchor separate, when a whole section is the link. Set this up.

170 \def\hyper@anchorstart#1{%
171  \ifHyper@nativepdf
172  \literalps@out{currentpoint /pdf@lly exch def /pdf@llx exch def}%
173  \gdef\hyper@currentanchor{#1}%
174  \else
175  \special{html:<A name=\hyper@quote#1\hyper@quote>}%
176  \colorlink{\AnchorColor}%
177  \fi
178  \@ActiveAnchortrue

179 }

180 \def\hyper@anchorend{%
181  \ifHyper@nativepdf
182  \leavevmode\raise\baselineskip\hbox{%
183  \literalps@out{currentpoint /pdf@ury exch def /pdf@urx exch def}}%
184  \pdfmark{pdfmark=/DEST,Dest=\hyper@currentanchor,
185  Rect=pdf@llx pdf@lly pdf@urx pdf@ury}%
186  \else
187  \special{html:</A>}%
188  \fi
189  \@ActiveAnchorfalse

190 }

191 \def\hyper@linkstart#1{%
192  \ifHyper@nativepdf
193  \def\hyper@hash{}%
194  \literalps@out{currentpoint /pdf@lly exch def /pdf@llx exch def}
195  \gdef\hyper@currentanchor{#1}%
196  \else
197  \special{html:<A href=\hyper@quote#1\hyper@quote>}%
198  \colorlink{\LinkColor}%
199  \fi

200 }

201 \def\hyper@linkend{%
202  \ifHyper@nativepdf
203  \raise\baselineskip\hbox{%
204  \literalps@out{currentpoint /pdf@ury exch def /pdf@urx exch def}}%
205  \pdfmark{pdfmark=/LNK,Dest=\hyper@currentanchor,
206  Rect=pdf@llx pdf@lly pdf@urx pdf@ury}%
207  \else
208  \special{html:</A>}%

209  \fi

210 }

4.3 User hypertext macros

\hyperlink has two arguments, the name of a hypertext object defined somewhere by \hypertarget, and the anchor text. \href also has two arguments, but the first is in this case a full URL. The difference is that \hyperlink puts in the # sign for you, for use in internal cross-referencing. You have to escape the #, ~ and % characters in the URL.

\hyperimage points to a graphic.

A simple link is created with \hypertarget, with two parameters of an anchor name, and anchor text.

211 \def\hyperlink#1#2{%
212 \hyper@link{}{\hyper@hash#1}{#2}%

213 }%

214 \def\href#1#2{%
215 \bgroup
216 \let\%\@percentchar
217 \let\#\hyper@hash
218 \let\~\hyper@tilde
219 \hyper@link{#1}{}{#2}%
220 \egroup

221 }

222 \def\hyperimage#1{%
223 \bgroup
224 \let\%\@percentchar
225 \let\#\hyper@hash
226 \let\~\hyper@tilde
227 \special{html: <img src=\hyper@quote#1\hyper@quote>}
228 \egroup

229 }

230 \def\hypertarget#1#2{%
231 \ifHyper@Nesting
232 \hyper@anchor{#1}{#2}%
233 \else
234 \hyper@anchor{#1}#2
235 \fi

236 }

\hyperref is more complicated, as it includes the concept of a category of link, used to make the name. This is not really used in this package. \hyperdef sets up an anchor in the same way. They each have four parameters: URL, name, category and link name.

If there is an optional first parameter, it is the name of a L^{A}TEX label which can be used in a short form of \hyperref later, to avoid remembering the name and category.

237 \def\hyperref{\@ifnextchar[{\label@hyperref}{\@hyperref}}

238 \def\@hyperref#1#2#3#4{% URL, category, name, text
239 \bgroup
240 \let\%\@percentchar
241 \let\#\hyper@hash
242 \let\~\hyper@tilde
243 \ifx\\#2\\
244  \ifx\\#3\\
245  \hyper@link{#1}{}{#4}%
246  \else
247  \hyper@link{#1}{\hyper@hash#3}{#4}%
248  \fi
249 \else
250  \hyper@link{#1}{\hyper@hash#2.#3}{#4}%
251 \fi
252 \egroup

253 }

254 \def\hyperdef{\@ifnextchar[{\label@hyperdef}{\@hyperdef}}
255 \def\@hyperdef#1#2#3#4{% URL, category, name, text
256 \ifHyper@Nesting
257 \hyper@anchor{#1#2.#3}{#4}%
258 \else
259 \hyper@anchor{#1#2.#3}#4
260 \fi

261 }

We also have a need to give a L^{A}TEX label to a hyper reference, to ease the pain of referring to it later

262 \def\label@hyperref[#1]#2{%
263 \expandafter\label@@hyperref{\csname r@#1\endcsname}{#1}{#2}%

264 }

265 \def\label@@hyperref#1#2#3{%
266 \ifx#1\relax
267 \protect\G@refundefinedtrue
268  \@latex@warning{Hyper reference `#2' on page \thepage \space
269  undefined}%
270 \hyper@link{}{??}{#3}%
271 \else
272 \hyper@link{}{#1}{#3}%
273 \fi

274 }

275 \def\label@hyperdef[#1]#2#3#4#5{% label name, url, category, name,
276  % anchor text
277 \@bsphack
278 \protected@write\@auxout{}%
279  {\string\newlabel{#1}{#2\protect\hyper@hash#3.#4}}%
280 \@esphack
281 \ifHyper@Nesting
282 \hyper@anchor{#2#3.#4}{#5}%
283 \else
284 \hyper@anchor{#2#3.#4}#5

4.4 Compatibility with the L^{A}TEX2html package

Map our macro names on to Nikos’, so that documents prepared for that system will work without change.

287 \let\htmladdimg\hyperimage
288 \def\htmladdnormallink#1#2{\href{#2}{#2}}

4.5 Direct Acrobat ‘pdfmark’ insertion

We define a single macro, pdfmark, which uses the ‘keyval’ system to define the various allowable keys; these are exactly as listed in the pdfmark Reference for Acrobat 2.0. The only addition is pdfmark which specifies the type of pdfmark to create (like ANN, LINK etc). The surrounding round and square brackets in the pdfmark commands are supplied, but you have to put in / characters as needed for the values.

289 \def\pdfmark{\@ifnextchar[{\@pdfmark}{\@pdfmark[]}}
290 \def\@pdfmark[#1]#2{%
291  \edef\goforit{\noexpand\pdf@toks={ \the\pdf@defaulttoks}}%
292  \goforit
293  \ifx\\#1\\\relax\else\pdf@rect{#1}\fi
294  \let\pdf@type\relax
295  \setkeys{PDF}{#2}%
296  \ifx\pdf@type\relax
297  \typeout{ERROR: no pdfmark type specified in #2!!}%
298  \else
299  \literalps@out{[\the\pdf@toks\space \pdf@type\space pdfmark}%
300  \fi

301 }

The complicated bit is working out the right enclosing rectangle of some piece of TEX text, needed by the /Rect key. This solution is due to Toby Thain

 (tobyt@netspace.net.au).
302 \def\pdf@rect#1{%
303 \leavevmode
304 \setbox0=\hbox{#1}%
305  \lower\dp0\hbox{\literalps@out{currentpoint
306  /pdf@lly exch def /pdf@llx exch def}}%
307 \copy0
308 \raise\ht0\hbox{\literalps@out{currentpoint
309  /pdf@ury exch def /pdf@urx exch def}}%
310 \setbox0=\hbox{}%
311 \pdf@addtoks{[pdf@llx pdf@lly pdf@urx pdf@ury]}{Rect}%

312 }

All the supplied material is stored in a token list; since I do not feel sure I quite understand these, things may not work as expected with expansion. We’ll have to experiment.

313 \newtoks\pdf@toks
314 \newtoks\pdf@defaulttoks
315 \pdf@defaulttoks={ }%
316 \def\pdf@addtoks#1#2{%
317 \toks0={/#2 #1 }%
318 \edef\goforit{\noexpand\pdf@toks={\the\pdf@toks\space /#2 #1}}%
319 \goforit

320 }

321 \def\PDFdefaults#1{%
322 \pdf@defaulttoks={#1}%

323 }

324 \PDFdefaults{/View [ /FitB ]}

This is the list of allowed keys. See the Acrobat manual for an explanation.

325 % what is the type of pdfmark?
326 \define@key{PDF}{pdfmark}{\def\pdf@type{#1}}
327 % parameter is a name
328 \define@key{PDF}{Action}{\pdf@addtoks{#1}{Action}}
329 % parameter is a array
330 \define@key{PDF}{Border}{\pdf@addtoks{[#1]}{Border}}
331 % parameter is a array
332 \define@key{PDF}{Color}{\pdf@addtoks{[#1]}{Color}}
333 % parameter is a string
334 \define@key{PDF}{Contents}{\pdf@addtoks{(#1)}{Contents}}
335 % parameter is a integer
336 \define@key{PDF}{Count}{\pdf@addtoks{#1}{Count}}
337 % parameter is a array
338 \define@key{PDF}{CropBox}{\pdf@addtoks{[#1]}{CropBox}}
339 % parameter is a string
340 \define@key{PDF}{DOSFile}{\pdf@addtoks{(#1)}{DOSFile}}
341 % parameter is a string or file
342 \define@key{PDF}{DataSource}{\pdf@addtoks{(#1)}{DataSource}}
343 % parameter is a destination
344 \define@key{PDF}{Dest}{%
345 \ifx\\#1\\\else\pdf@addtoks{/#1}{Dest}\fi}
346 % parameter is a string
347 \define@key{PDF}{Dir}{\pdf@addtoks{(#1)}{Dir}}
348 % parameter is a string
349 \define@key{PDF}{File}{\pdf@addtoks{(#1)}{File}}
350 % parameter is a int
351 \define@key{PDF}{Flags}{\pdf@addtoks{#1}{Flags}}
352 % parameter is a array
353 \define@key{PDF}{ID}{\pdf@addtoks{[#1]}{ID}}
354 % parameter is a string
355 \define@key{PDF}{MacFile}{\pdf@addtoks{(#1)}{MacFile}}
356 % parameter is a string
357 \define@key{PDF}{ModDate}{\pdf@addtoks{(#1)}{ModDate}}

358 % parameter is a string
359 \define@key{PDF}{Op}{\pdf@addtoks{(#1)}{Op}}
360 % parameter is a Boolean
361 \define@key{PDF}{Open}{\pdf@addtoks{#1}{Open}}
362 % parameter is a integer or name
363 \define@key{PDF}{Page}{\pdf@addtoks{#1}{Page}}
364 % parameter is a name
365 \define@key{PDF}{PageMode}{\pdf@addtoks{#1}{PageMode}}
366 % parameter is a string
367 \define@key{PDF}{Params}{\pdf@addtoks{(#1)}{Params}}
368 % parameter is a array
369 \define@key{PDF}{Rect}{\pdf@addtoks{[#1]}{Rect}}
370 % parameter is a integer
371 \define@key{PDF}{SrcPg}{\pdf@addtoks{#1}{SrcPg}}
372 % parameter is a string
373 \define@key{PDF}{Title}{\pdf@addtoks{(#1)}{Title}}
374 % parameter is a string
375 \define@key{PDF}{Unix}{\pdf@addtoks{(#1)}{Unix}}
376 % parameter is a string
377 \define@key{PDF}{UnixFile}{\pdf@addtoks{(#1)}{UnixFile}}
378 % parameter is a array
379 \define@key{PDF}{View}{\pdf@addtoks{[#1]}{View}}
380 % parameter is a string
381 \define@key{PDF}{WinFile}{\pdf@addtoks{(#1)}{WinFile}}

And now for some useful examples:

382 \def\PDFNextPage{\@ifnextchar[{\@PDFNextPage}%
383 {\@PDFNextPage[]}}
384 \def\@PDFNextPage[#1]#2{\pdfmark[#2]{#1,pdfmark=/LNK,Page=/Next}}
385 \def\PDFPreviousPage{\@ifnextchar[{\@PDFPreviousPage}%
386 {\@PDFPreviousPage[]}}
387 \def\@PDFPreviousPage[#1]#2{\pdfmark[#2]{#1,pdfmark=/LNK,Page=/Prev}}
388 \def\PDFOpen#1{%
389 \pdfmark{#1,pdfmark=/DOCVIEW}%

390 }

This is not as simple as it looks; if we make the argument of this macro eg \pageref{foo} and expect it to expand to ‘3’, we need a special version of \pageref which does not produce ‘3 ’…. David Carlisle looked at this bit and provided the solution, as ever!

391 \DeclareRobustCommand\PDFPage[3][]{%
392 {\let\pageref\simple@pageref
393 \pdfmark[#3]{#1,Page=#2,pdfmark=/LNK}}}
394 \def\simple@pageref#1{%
395 \expandafter\ifx\csname r@#1\endcsname\relax

396 0%

397 \else
398  \expandafter\expandafter\expandafter
399  \@secondoffour\csname r@#1\endcsname
400 \fi}

4.6 Automated L^{A}TEX hypertext cross-references

401 \def\realpageref#1{\expandafter\real@setref
402 \csname r@#1\endcsname\@secondoffour{#1}}

Emend \@setref to put out a hypertext link as well as its normal text (which is used as an anchor). This means that arbitrary \pageref commands won’t work right. \realpageref is available for people who know about these things, which uses a copy of \@setref.

403 \let\real@setref\@setref
404 \def\@setref#1#2#3{% csname, extract macro, ref
405 \ifx#1\relax
406 \protect\G@refundefinedtrue
407 \nfss@text{\reset@font\bfseries ??}%
408 \@latex@warning{Reference `#3' on page \thepage \space
409  undefined}%
410 \else
411 \hyper@link{}{\hyper@hash\expandafter\@fourthoffour#1}%
412  {\expandafter#2#1\null}%
413 \fi}

Anything which can be referenced advances some counter; we overload this to put in a hypertext starting point (with no visible anchor), and make a note of that for later use in \label. This will fail badly if \theH<name> does not expand to a sensible reference. This means that classes or package which introduce new elements need to define an equivalent \theH<name> for every \the<name>

This shenanigans is to make sure section numbers etc are always arabic, separated by dots. Who knows how people will set up \@currentlabel? If they put spaces in (quite legal) then the hypertext processors will get upset.

But all this is very flaky, and open to abuse. Styles like subeqn will mess it up, for starters. Appendices are an issue, too. We just hope to cover most situations. We can at least cope with the standard sectioning structure, allowing for \part

 and \chapter.
414 \@ifundefined{thepart}{}{\newcommand\theHpart{\arabic{part}}}
415 \@ifundefined{thechapter}{%
416  \newcommand\theHsection        {\arabic{section}}
417  \newcommand\theHfigure         {\arabic{figure}}
418  \newcommand\theHtable         {\arabic{table}}
419 }{%
420 \@ifundefined{thepart}%
421  {\newcommand\theHchapter       {\arabic{part}.\arabic{chapter}}}
422  {\newcommand\theHchapter       {\arabic{chapter}}}
423 \newcommand\theHfigure        {\theHchapter.\arabic{figure}}
424 \newcommand\theHtable        {\theHchapter.\arabic{table}}
425 \newcommand\theHsection       {\theHchapter.\arabic{section}}

426 }

427 \newcommand\theHsubsection    {\theHsection.\arabic{subsection}}
428 \newcommand\theHsubsubsection {\theHsubsection .\arabic{subsubsection}}
429 \newcommand\theHparagraph     {\theHsubsubsection.\arabic{paragraph}}
430 \newcommand\theHsubparagraph  {\theHparagraph.\arabic{subparagraph}}

431 \newcommand\theHequation       {\theHsection.\arabic{equation}}
432 \newcommand\theHtheorem       {\theHsection.\arabic{theorem}}
433 \newcommand\theHthm       {\theHsection.\arabic{thm}}
434 \newcommand\theHenumi  {\theHsection.\arabic{enumi}}
435 \newcommand\theHenumii  {\theHenumi.\arabic{enumii}}
436 \newcommand\theHenumiii  {\theHenumii.\arabic{enumiii}}
437 \newcommand\theHenumiv  {\theHenumiii.\arabic{enumiv}}
438 \newcommand\theHHfootnote  {\arabic{Hfootnote}}
439 \newcommand\theHmpfootnote  {\arabic{mpfootnote}}
440 \let\theHHmpfootnote\theHHfootnote
441 \newcommand\theHslide  {\arabic{slide}}
442 \let\H@refstepcounter\refstepcounter
443 \def\refstepcounter#1{%
444 \H@refstepcounter{#1}%
445 \hyper@makecurrent{#1}%
446 \hyper@anchorstart{\@currentHref}%
447 \hyper@anchorend

448 }

449 \def\hyper@makecurrent#1{%
450 \edef\@currentHlabel{\csname theH#1\endcsname}%
451 \global\edef\@currentHref{#1.\expandafter\strip@prefix\meaning\@currentHlabel}%

452 }

4.7 Equations

We want to make the whole equation a target anchor. Very dangerous to go in and change L^{A}TEX internals like this, but we need to avoid the changed \refstepcounter from being activated.

453 \def\equation{%

454 $$

455 \H@refstepcounter{equation}%
456 \hyper@makecurrent{equation}%
457 \hyper@anchorstart{\@currentHref}%

458 }

459 \def\endequation{%
460 \eqno \hbox{\@eqnnum}%
461 \hyper@anchorend
462 $$\global\@ignoretrue

463 }

My goodness, why can’t L^{A}TEX be consistent? Why is \eqnarray set up differently from other objects?

464 \let\H@eqnarray\eqnarray
465 \let\H@endeqnarray\endeqnarray
466 \def\eqnarray{%
467 \H@eqnarray
468 \hyper@makecurrent{equation}%
469 \hyper@anchorstart{\@currentHref}%

470 }

471 \def\endeqnarray{%
472 \hyper@anchorend
473 \H@endeqnarray

474 }

4.8 Footnotes

The footnote mark is a hypertext link, and the text is a target. We separately number the footnotes sequentially through the text, separately from whatever labels the text assigns. Too hard to keep track of markers otherwise.

475 \newcounter{Hfootnote}
476 \let\H@@footnotemark\@footnotemark
477 \let\H@@footnotetext\@footnotetext
478 \let\H@@mpfootnotetext\@mpfootnotetext
479 \long\def\@mpfootnotetext#1{%
480 \H@@mpfootnotetext{%

If we cannot have nesting, just the first character.

481 \ifHyper@Nesting
482 \hyper@anchor{\@currentHref}{#1}%
483 \else
484 \hyper@anchor{\@currentHref}#1
485 \fi

486 }% 487 }

488 \long\def\@footnotetext#1{%
489 \H@@footnotetext{%

If we cannot have nesting, just the first character.

490 \ifHyper@Nesting
491 \hyper@anchor{\@currentHref}{#1}%
492 \else
493 \hyper@anchor{\@currentHref}#1
494 \fi

495 }% 496 }

497 \def\@footnotemark{%
498 \H@refstepcounter{Hfootnote}%
499 \hyper@makecurrent{Hfootnote}%
500 \hyper@linkstart{\hyper@hash\@currentHref}%
501 \H@@footnotemark
502 \hyper@linkend

503 }

504 \def\realfootnote{\@ifnextchar[\@xfootnote{\stepcounter{\@mpfn}%
505  \protected@xdef\@thefnmark{\thempfn}%
506  \H@@footnotemark\H@@footnotetext}}

But the special footnotes in \maketitle are much too hard to deal with properly. Let them revert to plain behaviour.

507 \let\orig@maketitle\maketitle

508 \def\maketitle{%
509 \let\H@@origfootnotemark\@footnotemark
510 \let\H@@origfootnotetext\@footnotetext
511 \let\@footnotemark\H@@footnotemark
512 \let\@footnotetext\H@@footnotetext
513 \orig@maketitle
514 \ifx\@footnotemark\H@@footnotemark
515 \let\@footnotemark\H@@origfootnotemark
516 \fi
517 \ifx\@footnotetext\H@@footnotetext
518 \let\@footnotetext\H@@origfootnotetext
519 \fi

520 }

4.9 Float captions

Make the float caption the hypertext anchor; curiously enough, we can’t just copy the definition of \@caption. Its all to do with expansion. It screws up. Sigh.

521 \def\caption{\H@refstepcounter\@captype \@dblarg{\@caption\@captype}}
522 \long\def\@caption#1[#2]#3{%
523 \hyper@makecurrent{\@captype}%
524 \par\addcontentsline{\csname
525 ext@#1\endcsname}{#1}{\protect\numberline{\csname
526 the#1\endcsname}{\ignorespaces #2}}\begingroup
527  \@parboxrestore
528  \normalsize
529  \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces

If we cannot have nesting, just the first character of the caption is the anchor.

530 \ifHyper@Nesting
531 \hyper@anchorstart{\@currentHref}#3\hyper@anchorend
532 \else
533 \hyper@anchor{\@currentHref}#3
534 \fi
535 }\par
536 \endgroup}

4.10 Bibliographic references

This is not at all robust, since many styles redefine these things.

537 \def\@lbibitem[#1]#2{%
538 \item[\hyper@anchorstart{#2}\@biblabel{#1}\hyper@anchorend\hfill]%
539  \if@filesw{\let\protect\noexpand
540  \immediate\write\@auxout{\string\bibcite{#2}{#1}}}%
541  \fi
542  \ignorespaces

543 }

544 \def\@bibitem#1{\item
545  \hyper@anchor{#1}{\relax}%

546  \if@filesw \immediate\write\@auxout
547  {\string\bibcite{#1}{\the\value{\@listctr}}}\fi\ignorespaces}
548 \def\@citex[#1]#2{%
549 \let\@citea\@empty
550 \@cite{\@for\@citeb:=#2\do
551  {\@citea\def\@citea{,\penalty\@m\ }%
552  \edef\@citeb{\expandafter\@iden\@citeb}%
553  \if@filesw\immediate\write\@auxout{\string\citation{\@citeb}}\fi
554  \@ifundefined{b@\@citeb}{{\reset@font\bfseries ?}%
555  \G@refundefinedtrue\@latex@warning
556  {Citation `\@citeb' on page \thepage \space undefined}}%
557  {\hyperlink{\@citeb}{\hbox{\csname b@\@citeb\endcsname}}%

558 }% 559 }% 560 }%

561 {#1}%

562 }

4.11 Page numbers

Give every page an automatic number anchor. This involves, sigh, overloading L^{A}TEX’s output bits and pieces, which must be dangerous.

563 \let\H@old@shipoutsetup\@shipoutsetup
564 \def\@shipoutsetup{%
565 \H@old@shipoutsetup
566 \let\H@old@thehead\@thehead
567 \ifPlain@Pages
568  \def\@foo{\hyper@anchor{page.\arabic{page}}}%
569 \else
570  \def\@foo{\hyper@anchor{page.\thepage}}%
571 \fi
572 \ifx\expandafter\@empty\H@old@thehead\def\H@old@thehead{\hfil}\fi
573 \def\@thehead{\@foo\relax\H@old@thehead}%

574 }

4.12 Table of contents

575 \def\addcontentsline#1#2#3{%
576 \addtocontents{#1}{\protect\contentsline{#2}{#3}{\thepage}{\@currentHref}}%

577 }

578 \def\contentsline#1#2#3#4{%
579 \csname l@#1\endcsname{%
580 \hyper@linkstart{\hyper@hash#4}{#2}\hyper@linkend}
581 {#3}%

582 }

4.13 New counters

The whole theorem business makes up new counters on the fly; we are going to intercept this. Sigh. Do it at the level where new counters are defined.

583 \let\H@definecounter\@definecounter
584 \def\@definecounter#1{%
585 \H@definecounter{#1}%
586 \expandafter\def\csname theH#1\endcsname       {\arabic{#1}}%

587 }

But what if they have used the optional argument to e.g. \newtheorem to determine when the numbering is reset? OK, we’ll trap that too.

588 \let\H@newctr\@newctr
589 \def\@newctr#1[#2]{%
590 \H@newctr#1[#2]%
591 \expandafter\def\csname theH#1\endcsname
592  {\csname the#2\endcsname.\arabic{#1}}%

593 }

4.14 AMS L^{A}TEX compatibility

Oh, no, they don’t use anything as simple as \refstepcounter in the AMS! We need to intercept some low-level operations of theirs. Damned if we are going to try and work out what the hell they get up to. Just stick a label of ‘AMS’ on the front, and use the label they worked out. If that produces something invalid, I give up. They’ll change all the code again anyway, I expect.

594 \let\Hmake@df@tag@@\make@df@tag@@
595 \def\make@df@tag@@#1{%
596 \Hmake@df@tag@@{#1}%
597 \global\edef\@currentHref{AMS.\theequation}%

598 }

599 \let\H@seteqlabel\@seteqlabel
600 \def\@seteqlabel#1{%
601 \H@seteqlabel{#1}%
602 \global\edef\@currentHref{AMS.\theequation}%

603 }

604 \let\H@tagform@\tagform@
605 \def\tagform@#1{%
606 \maketag@@@{\hyper@anchor{\@currentHref}%
607 {(\ignorespaces#1\unskip)}}%

608 }

609 \def\eqref#1{\textup{\H@tagform@{\ref{#1}}}}

4.15 Included figures

Simply intercept the low level graphics package macro.

610 \ifHyper@Figures
611 \def\Gin@setfile#1#2#3{%
612 \hyperimage{#3}%

614 \fi

4.16 Index entries

Hyper-indexing works crudely, by forcing code onto the end of the index entry with the | feature; this puts a hyperlink around the printed page numbers. It will not proceed if the author has already used the | specifier for something like emboldening entries. That would make Makeindex fail (cannot have two | specifiers). The solution is for the author to use generic coding, and put in the requisite \hyperPage in his/her own macros along with the boldness.

This section is poor stuff; it’s open to all sorts of abuse. Sensible large projects will design their own indexing macros any bypass this.

615 \ifHyper@Index
616 \def\@wrindex#1{\@@wrindex#1||\\}
617 \def\@@wrindex#1|#2|#3\\{%
618 \ifx\\#2\\
619 \protected@write\@indexfile{}%
620  {\string\indexentry{#1|hyperpage}{\thepage}}%
621 \else
622 \protected@write\@indexfile{}%
623  {\string\indexentry{#1|#2}{\thepage}}%
624 \fi
625 \endgroup
626 \@esphack

627 }

628 \fi

This again is quite flaky, but allow for the common situation of a page range separated by en-rule. We split this into two different hyperlinked pages.

629 \def\hyperpage#1{\@hyperpage#1----\\}
630 \def\@hyperpage#1--#2--#3\\{%
631 \ifx\\#2\\
632  \@commahyperpage{#1}%
633 \else
634 \hyperlink{page.#1}{#1}--\hyperlink{page.#2}{#2}%
635 \fi

636 }

637 \def\@commahyperpage#1{\@@commahyperpage#1, ,\\}
638 \def\@@commahyperpage#1, #2,#3\\{%
639 \ifx\\#2\\
640 \hyperlink{page.#1}{#1}%
641 \else
642 \hyperlink{page.#1}{#1}, \hyperlink{page.#2}{#2}%
643 \fi

644 }

4.17 Bookmarks in PDF file

This was developed by YH (it was the separate repere.sty); it needs the repere post-processor to work properly. See the script dvi2pdf for how to use repere.

645 \newwrite\@reperefile
646 \immediate\openout\@reperefile=\jobname.rep
647 \def\@writetorep#1#2{%
648  \protected@write\@reperefile
649  {\def\TeX{TeX}\def\LaTeX{LaTeX}\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}%
650  {(#2) <#1>}%

651 }

To write out the current section title, and its rationalized number, we have to intercept the \@sect command, which is rather dangerous. But how else to see the information we need?

652 \let\H@old@sect\@sect
653 \def\@sect#1#2#3#4#5#6[#7]#8{%
654 \H@old@sect{#1}{#2}{#3}{#4}{#5}{#6}[{#7}]{#8}%

If the sectioning internal commands are abused and beaten, what are we to do? Answer, nothing if the first parameter is empty.

655 \ifx\\#1\\\else
656 \ifnum#2<\c@secnumdepth
657 \edef\@thishlabel{\csname theH#1\endcsname}%
658 \@writetorep{#7}{#1.\@thishlabel}%
659 \fi
660 \fi

661 }

Unfortunately, that only works if the section headings use the standard \@startsection macros. Chapters and parts typically don’t. This makes it almost impossible to get 100% right, so we just intercept the code in the standard styles.

662 \let\H@old@part\@part
663 \def\@part[#1]#2{%
664 \H@old@part[{#1}]{#2}%
665 \@writetorep{#1}{part.\theHpart}%

666 }

667 \let\H@old@chapter\@chapter
668 \def\@chapter[#1]#2{%
669 \H@old@chapter[{#1}]{#2}%
670 \@writetorep{#1}{chapter.\theHchapter}%

671 }

4.18 Low-level utility macros

We need unrestricted access to the #, ~ and " characters, so make them nice macros.

672 \edef\hyper@hash{\string#}
673 \edef\hyper@tilde{\string~}
674 \edef\hyper@quote{\string"}

675 \def\@currentHref{}

676 ⟨/package⟩