I have now completed the patch to the Unix Text Professing book to add pdf 
bookmarks to it.

The results can be downloaded here:-

<http://chuzzlewit.co.uk/utp_book-1.1.pdf>

The attached patch can be applied to the existing UTP source by doing:-

patch -p1 <../patch-utp-1.0-v3.diff
rm -rf index #optional - no longer used
chmod +x mkindex.pl
make

There is a second make file which you can use to generate the same book but 
using pdfroff instead of gropdf. It can be used as "make -f Makefile.pdfroff".

Notes:-

Gropdf version.

Unless you use the latest CVS version of groff the pdf produced has two 
faults:-

A) The thick line on the front page will have square caps instead of round 
caps, and

B) The entries for "Preface" and "Chapter 4" will be open in the bookmarks 
pane of the pdf reader (should be closed).

PDFroff version.

A further patch is required to pdfmark.tmac changing it to use the \! to 
communicate with grops instead of \X. The reason is because in certain 
circumstances groff can insert a blank line when planting a bookmark. The 
newer \! escape does not do this. Without the patch you will see extra space 
in the book which should not be there. This patch is not "release quality 
since it only corrects the behaviour if the length of the pdfmark inserted 
into the postscript is greater than 255 characters (none of the UTP 
bookmarks). On further thought, it may be better to use the .ouput directive 
now it is available.

Cheers 

Deri
diff -uNBb a/ch03.t b/ch03.t
--- a/ch03.t	2003-07-28 01:59:46.000000000 +0100
+++ b/ch03.t	2013-01-22 17:39:00.035204544 +0000
@@ -2848,7 +2848,9 @@
 .Ps
 number  window=20  wrapmargin=10
 .Pe
-See Appendix A for a description of what these options mean.
+See
+.pdfhref L -D AppendixA -- Appendix A
+for a description of what these options mean.
 .ix [.exrc] file %key exrc file
 .Bh "The \f(CB.exrc\fP File
 .LP 0
diff -uNBb a/ch04.t b/ch04.t
--- a/ch04.t	2003-07-28 01:59:46.000000000 +0100
+++ b/ch04.t	2013-01-22 17:47:58.388044348 +0000
@@ -1791,7 +1791,9 @@
 depend on the resolution of the output device.
 For example, units for a 300 dot-per-inch (dpi) laser printer will be
 1/300 of an inch in either a vertical or a horizontal direction.
-See Appendix D for more information on
+See
+.pdfhref L -D AppendixD -- Appendix D
+for more information on
 .CW ditroff
 device units.
 .PP
@@ -3371,7 +3373,9 @@
 position 10.
 Which fonts are mounted, and in which positions, depends on the output
 device.
-See Appendix D for details.
+See
+.pdfhref L -D AppendixD -- Appendix D
+for details.
 The font that is mounted in position 1 will be used for the body type of
 the text\c
 \(em\c
@@ -3653,7 +3657,9 @@
 .CW DESC\.out
 in the device subdirectory of
 .CW /usr/lib/font .
-See Appendix D for details.
+See
+.pdfhref L -D AppendixD Appendix D
+for details.
 .ix %end fonts, changing
 .ix %end [troff] formatter, fonts %key troff formatter, fonts
 .Bh "Special Characters"
diff -uNBb a/ch05.t b/ch05.t
--- a/ch05.t	2003-07-28 01:59:46.000000000 +0100
+++ b/ch05.t	2013-01-22 17:31:10.054485575 +0000
@@ -1989,7 +1989,7 @@
 .CW troff
 feature called
 .I environments
-(see Chapter 14),
+.pdfhref L -D Chapter14 -P "(see " -A ), -- Chapter 14
 so that parameters like line length or font that are set
 inside a footnote are saved independently of the body text.
 So, for example, if you issued the requests:
diff -uNBb a/ch06.t b/ch06.t
--- a/ch06.t	2003-07-28 01:59:46.000000000 +0100
+++ b/ch06.t	2013-01-22 17:47:58.460045530 +0000
@@ -160,7 +160,8 @@
 device name using the
 .CW -T
 option.
-For a list of available devices, see Appendix B.
+For a list of available devices, see
+.pdfhref L -D AppendixB -P . -- Appendix B
 The
 .CW mm
 command also has a
diff -uNBb a/ch08.t b/ch08.t
--- a/ch08.t	2003-07-28 01:59:45.000000000 +0100
+++ b/ch08.t	2013-01-22 17:32:27.274753348 +0000
@@ -494,7 +494,8 @@
 T{
 delim (\f[I]xy\fP)
 T}	T{
-Set \f[I]x\fP and \f[I]y\fP as \f[CW]eqn\fP delimiters. See Chapter 9
+Set \f[I]x\fP and \f[I]y\fP as \f[CW]eqn\fP delimiters. See
+.pdfhref L -D Chapter9 -- Chapter 9
 for information on the equation preprocessor
 \f[CW]eqn\fP.
 T}
diff -uNBb a/ch09.t b/ch09.t
--- a/ch09.t	2013-01-10 01:50:40.000000000 +0000
+++ b/ch09.t	2013-01-22 18:26:01.615546441 +0000
@@ -753,9 +753,12 @@
 Note that special names don't exist for all uppercase Greek letters,
 such as ALPHA or ETA, because they are identical to the equivalent
 English letters.
-See Table 9-1 for a list of Greek letters.
+See
+.pdfhref L -D Tab9.1 -- Table 9-1
+for a list of Greek letters.
 .ix Greek characters
 .KS
+.pdfhref M -N Tab9.1 -E
 .Ts " Names for Greek Letters"
 .TS
 center,box;
diff -uNBb a/ch12.t b/ch12.t
--- a/ch12.t	2003-07-28 01:59:45.000000000 +0100
+++ b/ch12.t	2013-01-22 17:49:51.323899426 +0000
@@ -3712,7 +3712,9 @@
 *The preceding sections have not covered all
 .CW sed
 commands.
-See Appendix A for a complete list of
+See
+.pdfhref L -D AppendixA -- Appendix A
+for a complete list of
 .CW sed
 commands.
 .FE
diff -uNBb a/ch13.t b/ch13.t
--- a/ch13.t	2003-07-28 01:59:45.000000000 +0100
+++ b/ch13.t	2013-01-22 18:25:51.547381320 +0000
@@ -1962,7 +1962,9 @@
 (You have already seen how the
 .CW length
 function works).
-See Appendix A for the syntax of these functions.
+See
+.pdfhref L -D AppendixA -- Appendix A
+for the syntax of these functions.
 .PP
 Going back to our report generator, we need to split each field
 into subvalues.
diff -uNBb a/ch16.t b/ch16.t
--- a/ch16.t	2003-07-28 01:59:44.000000000 +0100
+++ b/ch16.t	2013-01-22 18:27:07.276623339 +0000
@@ -511,7 +511,9 @@
 footnotes, as well as counters for automatic numbering of
 figures, examples, equations, tables, and
 section headings.
-(See Appendix B for a complete listing).
+(See
+.pdfhref L -D AppendixB Appendix B
+for a complete listing).
 However, the registers used in
 .CW ms
 should give you a sufficient idea of the kinds of values
diff -uNBb a/front.t b/front.t
--- a/front.t	2004-06-15 03:54:30.000000000 +0100
+++ b/front.t	2013-01-12 19:31:30.384975268 +0000
@@ -6,8 +6,9 @@
 .so utp.mac
 .utp
 .page iii
-.ps 200
+\Z@\D't 8p'@
 .Hl
+\D't 0'
 .sp .6i
 .DS R
 .ps 52
Common subdirectories: a/index and b/index
diff -uNBb a/ix.macro b/ix.macro
--- a/ix.macro	2003-07-28 02:07:15.000000000 +0100
+++ b/ix.macro	1970-01-01 01:00:00.000000000 +0100
@@ -1,4 +0,0 @@
-.de ix
-.ie '\\n(.z'' .tm ix: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9	\\n%
-.el \\!.ix \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
-..
diff -uNBb a/Makefile b/Makefile
--- a/Makefile	2003-07-29 04:26:26.000000000 +0100
+++ b/Makefile	2013-01-22 18:46:51.989146666 +0000
@@ -15,15 +15,15 @@
 ch15.t ch16.t ch17.t ch18.t appa.t appb.t appc.t appd.t appe.t \
 appf.t appg.t
 
-utp_book.ps: toc.t utp_ix.t
-	$(GROFF) -step -ms -rRef=0 utp_book.t >[email protected]
+utp_book.pdf: toc.t utp_ix.t
+	$(GROFF) -Tpdf -P-e -P-pletter -step -ms -z -rpdf:bm.nr=1 -rRef=0 -dPDF.EXPORT=1 utp_book.t 2>&1 | grep '^.ds' | $(GROFF) -Tpdf -mpdfmark -P-pletter -P-e -step -ms -rRef=0 - utp_book.t >[email protected]
 	mv [email protected] $@
 
 clean::
-	rm -f utp_book.ps utp_book.ps.tmp
+	rm -f utp_book.pdf
 
 toc.t: $(CHAPTERS)
-	$(GROFF) -step -ms -rRef=1 ix.macro utp_book.t >/dev/null 2>utp.aux.tmp
+	$(GROFF) -Tpdf -P-e -P-pletter -z -step -rpdf:bm.nr=1 -ms -rRef=1 -wall utp_book.t >/dev/null 2>utp.aux.tmp
 	mv utp.aux.tmp utp.aux
 	$(AWK) -f toc.awk utp.aux >[email protected]
 	mv [email protected] $@
@@ -32,7 +32,7 @@
 	rm -f utp.aux.tmp utp.aux toc.t toc.t.tmp
 
 utp_ix.t: $(CHAPTERS)
-	cd index && ./make.index ../utp.aux >../[email protected]
+	./mkindex.pl utp.aux > [email protected]
 	mv [email protected] $@
 
 clean::
@@ -50,7 +49,6 @@
 	$(VIEW) x.ps
 
 %.pdf : %.t
-	groff -step -ms -rRef=0 $< > x.ps
-	ps2pdf x.ps
+	groff -step -ms -rRef=0 -Tpdf $< > x.pdf
 	mv x.pdf $@
-	$(VIEW) x.ps
+	$(VIEW) x.pdf
diff -uNBb a/Makefile.pdfroff b/Makefile.pdfroff
--- a/Makefile.pdfroff	1970-01-01 01:00:00.000000000 +0100
+++ b/Makefile.pdfroff	2013-01-22 19:33:56.811081246 +0000
@@ -0,0 +1,55 @@
+#
+# Makefile for _Unix Text Processing_
+#
+# 16 November 2002 - jcs
+#
+#
+# Set the next two lines for the paths for groff and awk on your system
+#
+GROFF = /usr/bin/groff
+AWK = /usr/bin/awk
+VIEW = gv
+
+CHAPTERS= front.t preface.t ch01.t ch02.t ch03.t ch04.t ch05.t \
+ch06.t ch07.t ch08.t ch09.t ch10.t ch11.t ch12.t ch13.t ch14.t \
+ch15.t ch16.t ch17.t ch18.t appa.t appb.t appc.t appd.t appe.t \
+appf.t appg.t
+
+utp_book-pdfroff.pdf: toc.t utp_ix.t
+	pdfroff -step -ms -mpdfmark -P-pletter --no-toc --emit-ps --no-kill-null-pages utp_book.t > @.tmp
+	perl -pe 's!\\f\(..|\\fP|\\f\[.+?\]!!g if m!OUT pdfmark!' @.tmp > utp_book-pdfroff.ps
+	ps2pdf -sPAPERSIZE=letter utp_book-pdfroff.ps && rm -f utp_book-pdfroff.ps @.tmp
+
+clean::
+	rm -f utp_book-pdfroff.pdf
+
+toc.t: $(CHAPTERS)
+	$(GROFF) -Tpdf -P-e -P-pletter -z -step -rpdf:bm.nr=1 -ms -rRef=1 -wall utp_book.t >/dev/null 2>utp.aux.tmp
+	mv utp.aux.tmp utp.aux
+	$(AWK) -f toc.awk utp.aux >[email protected]
+	mv [email protected] $@
+
+clean::
+	rm -f utp.aux.tmp utp.aux toc.t toc.t.tmp
+
+utp_ix.t: $(CHAPTERS)
+	./mkindex.pl utp.aux > [email protected]
+	mv [email protected] $@
+
+clean::
+	rm -f utp_ix.t utp_ix.t.tmp
+#########################################################################
+# helpers to maintain single chapters
+# make ch03
+#########################################################################
+
+.SUFFIXES: .t .html .pdf
+
+% : %.t
+	groff -step -ms -rRef=0 $< > x.ps 2>ix.raw
+	$(VIEW) x.ps
+
+%.pdf : %.t
+	groff -step -ms -rRef=0 -Tpdf $< > x.pdf
+	mv x.pdf $@
+	$(VIEW) x.pdf
diff -uNBb a/mkindex.pl b/mkindex.pl
--- a/mkindex.pl	1970-01-01 01:00:00.000000000 +0100
+++ b/mkindex.pl	2013-01-10 23:32:01.198153816 +0000
@@ -0,0 +1,412 @@
+#!/usr/bin/perl -w
+#
+#	mkindex.pl	: Make index for UTP project
+#	Deri James	: Monday 07 Jan 2013
+#
+# Input file produced by .ix macro
+#
+
+use strict;
+use constant {
+    TXT		=> 0,
+    PAGE		=> 1,
+    LABEL	=> 2,
+    TYPE		=> 3,
+};
+
+my (%idx,%bkm,%wds,%ltr);
+
+while (<>)
+{
+    chomp;
+
+    next if ! s/^ix: //;
+
+    my (@r)=split("\t");
+
+    # clean
+
+    foreach (@r)
+    {
+	s/^ +//;
+	s/ +$//;
+	s/  +/ /g;
+    }
+
+    # deroman
+
+#    $r[PAGE]=1000-from_roman($r[PAGE]) if $r[PAGE]=~m/^[ivxlc]+$/;
+
+    # range.prep
+
+    $r[TYPE]='a';
+    $r[TYPE]='b' if $r[TXT]=~s/\%begin //;
+    $r[TYPE]='e' if $r[TXT]=~s/\%end //;
+
+    # rotate
+
+    my (@tok,@keys);
+
+    if ($r[TXT]=~m/ %key /)
+    {
+	$tok[0]=$r[TXT];
+    }
+    else
+    {
+	(@tok)=split(' ',$r[TXT]);
+    }
+
+    foreach (@tok) {s/%~/QQ1QQ/g; tr/~/ /; s/QQ1QQ/%~/g;}
+
+    foreach my $j (0..$#tok)
+    {
+	my $key=join(' ',@tok[$j..$#tok]);
+	$key.=', '.join(' ',@tok[0..$j-1]) if $j>0;
+
+	if ($r[TYPE] eq 'a')
+	{
+	    push(@{$idx{$key}->{DATA}},[$r[LABEL],$r[PAGE]]);
+	}
+	elsif ($r[TYPE] eq 'b')
+	{
+	    $idx{$key}->{$r[TYPE]}=[$r[LABEL],$r[PAGE]];
+	}
+	else
+	{
+	    if (exists($idx{$key}->{b}))
+	    {
+		my $st=$idx{$key}->{b}->[1];
+		my $lab=$idx{$key}->{b}->[0];
+		$st.="\\[en]$r[PAGE]" if $r[PAGE] > $st;
+		push(@{$idx{$key}->{DATA}},[$lab,$st]);
+		delete($idx{$key}->{b});
+	    }
+	    else
+	    {
+		print STDERR "No matching %begin record for key '$key'\n";
+	    }
+	}
+    }
+}
+
+# see terms
+
+if (open(F,"<see.terms"))
+{
+    while (<F>)
+    {
+	chomp;
+
+	my (@r)=split("\t");
+
+	if ($r[2] and $r[2]=~m/\%also/)
+	{
+	    push(@{$idx{"$r[0], {see also} $r[1]"}->{DATA}},[]);
+	}
+	else
+	{
+	    push(@{$idx{"$r[0], {see} $r[1]"}->{DATA}},[]);
+	}
+    }
+
+    close(F);
+}
+
+# gen.key
+
+foreach my $key (keys %idx)
+{
+    my ($skey,$val);
+
+    if ($key=~m/^(.*) %key (.*)/)
+    {
+	$skey=$2;
+	$val=$1;
+	$skey=~tr'/''d;
+    }
+    else
+    {
+	$skey=Clean($key);
+	$val=$key;
+
+    }
+
+    $skey="!!$skey" if $skey=~m/^[^a-zA-Z]+$/;
+    $skey="!$skey" if $skey=~m/^[0-9]/;
+
+#    $skey=lc($skey);
+    if (exists($bkm{$skey}))
+    {
+	push(@{$bkm{$skey}->{DATA}},@{$idx{$key}->{DATA}});
+	$bkm{$skey}->{CT}+=$#{$idx{$key}->{DATA}}+1;
+	print STDERR "Duplicate key '$skey' merged\n";
+    }
+    else
+    {
+	$bkm{$skey}->{DATA}=$idx{$key}->{DATA};
+	$bkm{$skey}->{CT}=$#{$idx{$key}->{DATA}}+1;
+	$bkm{$skey}->{AKEY}=$val;
+    }
+}
+
+foreach my $key (sort {lc($a) cmp lc($b)} keys %bkm)
+{
+    my $skey=$key;
+    $skey=~tr[,][]d;
+    my ($wd1,$wd2)=split(' ',$skey);
+    $wd2='' if !defined($wd2);
+    my $flt=substr($wd1,0,1);
+    my $typ=2;
+    my $txt=$bkm{$key}->{AKEY};
+
+    # types: 1="{see...}",2=normal,4="^[...]", 3="...[...]..."
+
+    if ($txt=~m/{see/)
+    {
+	$typ=1;	
+    }
+    elsif ($txt=~m/^\[/)
+    {
+	$typ=4;
+    }
+    elsif ($txt=~m/\[.*\]/)
+    {
+	$typ=3;
+    }
+
+    my $nowds=split(' ',$txt);
+
+    $wd2=Clean($wd2);
+    
+    $wds{$wd1}->[$typ]->{WCT}++,$wds{$wd1}->[$typ]->{MINWDS}=$nowds if !exists($wds{$wd1}->[$typ]->{WORDS}->{$wd2});
+    push(@{$wds{$wd1}->[$typ]->{WORDS}->{$wd2}},$bkm{$key});
+    $wds{$wd1}->[$typ]->{CT}++;
+    $wds{$wd1}->[$typ]->{MINWDS}=$nowds if $wds{$wd1}->[$typ]->{MINWDS} > $nowds;
+}
+
+my $lastflt='';
+
+print <<'EOF';
+.ig
+Index formatting macros, lifted from CSTR #128
+with slight changes to fit the UTP manual
+..
+.so utp.mac
+.\" Precedes each index term
+.de XX
+.br
+.ti -.2i
+.ne 2
+..
+.de ZZ
+.br
+..
+.\" Header between letters
+.de YY
+.sp 1.5
+.ne 3
+.ce
+- \\$1 -
+.sp .5
+..
+.Se "" "Index" NONE
+.af PN 1
+.nr PS 8
+.nr VS 9
+.\" Just do one column for nroff...
+.if t .2C
+.na
+.in .2i
+.hy 0
+EOF
+
+foreach my $key (sort {lc($a) cmp lc($b)} keys %wds)
+{
+    my $flt=lc(substr($key,0,1));
+
+    $lastflt=$flt,print ".YY $flt ",uc($flt),"\n" if ($flt ne $lastflt and $flt ne '!');
+
+    foreach my $j (1..4)
+    {
+	next if !defined($wds{$key}->[$j]);
+
+	my $wd=$wds{$key}->[$j];
+
+	if ($wd->{WCT}==1)
+	{
+	    if ($wd->{CT}==1)
+	    {
+		# simple entry - one word, one entry
+
+		doref($wd->{WORDS},'XX',0,0,0,0);
+	    }
+	    else
+	    {
+		# multi...
+
+		if ($wd->{MINWDS} == 2)
+		{
+		    # The 2 words match the keys
+
+		    doref($wd->{WORDS},'XX',0,0,0,0);
+		    doref($wd->{WORDS},'ZZ',2,1,9999,0);
+		}
+		else
+		{
+		    # 2 words math, create a leader
+
+		    doref($wd->{WORDS},'XX',0,0,0,2);
+		    doref($wd->{WORDS},'ZZ',2,0,9999,0);
+		}
+	    }
+	}
+	else
+	{
+	    # Only 1 word match
+
+    		if ($wd->{MINWDS} == 1  or exists($wd->{WORDS}->{''}))
+		{
+		    # The words matches the keys
+
+		    doref($wd->{WORDS},'XX',0,0,0,0);
+		    doref($wd->{WORDS},'ZZ',1,1,9999,0);
+		}
+		else
+		{
+		    # create a leader
+
+		    doref($wd->{WORDS},'XX',0,0,0,1);
+		    doref($wd->{WORDS},'ZZ',1,0,9999,0);
+		}
+
+	}
+    }
+}
+
+sub doref
+{
+    my $w=shift;
+    my $typ=shift;
+    my $drop=shift;
+    my $from=shift;
+    my $to=shift;
+    my $leader=shift;
+    my $outbuf=".$typ\n";
+    my $j=-1;
+
+    foreach my $key (sort {lc($a) cmp lc($b)} keys %{$w})
+    {
+	foreach my $e (@{$w->{$key}})
+	{
+	    $j++;
+	    next if $j < $from;
+	    last if $j > $to;
+
+	    my $ent=$e->{AKEY};
+
+	    if ($drop or $leader)
+	    {
+		my (@l)=split(' ',$ent);
+		$ent=join(' ',@l[0..$leader-1]) if $leader;
+		$ent=join(' ',@l[$drop..$#l]) if $drop;
+	    }
+
+	    $ent=~s/\[(.*?)\]/\\f[CW]$1\\f[P]/g;
+	    $ent=~s/\{(.*?)\}/\\f[2]$1\\f[P]/g;
+
+	    $ent="  $ent" if $typ eq 'ZZ';
+	    $ent=~s/,+$//;
+
+	    my $ref=$e->{DATA};
+	    my $refct=0;
+	    my $reftot=$#{$ref};
+
+	    if (!$leader and $#{$ref->[0]} >= 0)
+	    {
+		$outbuf.="$ent,   \\c\n";
+		foreach my $r (@{$ref})
+		{
+		    my $prefix='';
+
+		    $prefix='-A ,' if $refct < $reftot;
+		    $outbuf.=".pdfhref L -D $r->[0] $prefix -E -- $r->[1]\n";
+		    $refct++;
+		}
+	    }
+	    else
+	    {
+		$outbuf.="$ent\n";
+	    }
+	}
+    }
+    print $outbuf;
+}
+
+sub Clean
+{
+    my $skey=shift;
+
+    $skey=~tr/_/0/;
+
+    my $quoted=0;
+
+    if ($skey=~m/%/)
+    {
+	$quoted=1;
+	$skey=~s/%%/QQ0QQ/g;
+	$skey=~s/%\[/QQ1QQ/g;
+	$skey=~s/%\]/QQ2QQ/g;
+	$skey=~s/%\{/QQ3QQ/g;
+	$skey=~s/%\}/QQ4QQ/g;
+	$skey=~s/%~/QQ5QQ/g;
+    }
+
+    $skey=~s/%e/\\/g;	# implement troff escape
+    $skey=~s/~/ /g;		# remove tildes
+    $skey=~tr'%()/[]{}''d;	# remove % and font-changing []{}
+
+    if ($quoted)
+    {  # restore literals but without escape charcter
+	$skey=~s/QQ0QQ/%/g;
+	$skey=~s/QQ1QQ/[/g;
+	$skey=~s/QQ2QQ/]/g;
+	$skey=~s/QQ3QQ/{/g;
+	$skey=~s/QQ4QQ/}/g;
+	$skey=~s/QQ5QQ/~/g;
+    }
+    
+    return($skey);
+}
+
+my $end=1;
+
+my @trans = (
+    [M  => 1000],     [CM => 900],
+    [D  => 500],      [CD => 400],
+    [C  => 100],      [XC => 90],
+    [L  => 50],       [XL => 40],
+    [X  => 10],       [IX => 9],
+    [V  => 5],        [IV => 4],
+    [I  => 1],
+);
+
+sub firstword
+{
+    my $wd=shift;
+
+    my ($ret)=split(' ',$wd,2);
+    $ret=~s/,//;
+    return $ret;
+}
+
+sub from_roman {
+    my $r = shift;
+    my $n = 0;
+    foreach my $pair (@trans) {
+	my ($k, $v) = @$pair;
+	$n += $v while $r =~ s/^$k//i;
+    }
+    return $n
+
+
+}
diff -uNBb a/see.terms b/see.terms
--- a/see.terms	1970-01-01 01:00:00.000000000 +0100
+++ b/see.terms	2013-01-10 17:39:56.513311965 +0000
@@ -0,0 +1,16 @@
+drawing	[pic] preprocessor	%also
+extensions to [ms] macros	 extended ms macros
+files, searching within	[grep]	%also
+formatting defaults, [mm]	[mm] macros	%also
+formatting defaults, [ms]	[ms] macros	%also
+graphics	[pic] preprocessor	%also
+integrals	[eqn]
+keep and release	displays	%also
+macros	[mm] and [ms]	%also
+[mS] macros	extended [ms] macros
+[nroff] formatter	[troff]	%also
+search	[grep]	%also
+subscripts	[eqn]	%also
+superscripts	[eqn]	%also
+[vi] editor, [ex] commands in	[ex]	%also
+[view] command	[vi] editor
diff -uNBb a/toc.awk b/toc.awk
--- a/toc.awk	2003-07-28 02:07:15.000000000 +0100
+++ b/toc.awk	2013-01-11 21:30:58.991727280 +0000
@@ -7,24 +7,27 @@
 			print ".Se \"\"  Contents NONE";
 			print ".af PN i";
 			print ".vs 12";
-			print ".ta \\n(.luR";
+			print ".nr llen \\n(.lu-.25i";
+			print ".ta \\n[llen]uR";
 			print ".nf";
 			print ".sp 2"
 		}
 /^Se:/	{
-			if ( $4 == "Contents" )
+			if ( $5 == "Contents" )
 				next;
-			gsub(/\\f\(CW/, "\\f\(CB" );
-			gsub(/\\f\[CW\]/, "\\f\[CB\]" );
-			gsub(/\\fC/, "\\f\[CB\]" );
+			gsub(/\\f\(CW/, "\\f[CB]" );
+			gsub(/\\f\(CB/, "\\f[CB]" );
+			gsub(/\\f\[CW\]/, "\\f[CB]" );
+			gsub(/\\fC/, "\\f[CB]" );
 			print ".ps 12\n.sp";
-			print $3"\\h'|.25i'\\fB"$4"\\fR	"$2;
+			print $4"\\h'|.25i'\\fB\\c";
+			print ".pdfhref L -D "$2" -E -- "$5"\t\\fR"$3;
 			print ".ps 10\n.sp";
 		}
 /^Ah:/	{
-			gsub(/\\f\(CB/, "\\f\(CW" );
-			gsub(/\\f\[CB\]/, "\\f\[CW\]" );
-			print "\\h'|.25i'"$3""$2;
+			gsub(/\\f\(CB/, "\\f[CW]" );
+			gsub(/\\f\[CB\]/, "\\f[CW]" );
+			print ".pdfhref L -D "$2" -P \\h'|.25i' -E -- "$4""$3;
 		}
 # default (skip index entries)
 	{ next; }
diff -uNBb a/utp_book.t b/utp_book.t
--- a/utp_book.t	2003-07-29 04:25:47.000000000 +0100
+++ b/utp_book.t	2013-01-12 00:49:42.180412230 +0000
@@ -8,6 +8,14 @@
 *	Still a couple of minor warnings under groff 1.18
 **************************************************************
 ..
+.nr ixno 0 1
+.ds PDFHREF.COLOUR 0.0 0.3 0.9
+.ds PDFHREF.TEXT.COLOUR pdf:href.colour
+.defcolor pdf:href.colour rgb \*[PDFHREF.COLOUR]
+.nr PDFOUTLINE.FOLDLEVEL 1
+.pdfinfo /Title Unix Text Processing
+.pdfinfo /Author Dale Dougherty and Tim O'Reilly
+.pdfview /PageMode /UseOutlines
 .nr chapter_page2 1
 .so front.t
 .nr chapter_page2 1
@@ -95,3 +103,5 @@
 .bp
 .nr chapter_page2 1
 .so utp_ix.t
+.pdfsync
+
diff -uNBb a/utp.mac b/utp.mac
--- a/utp.mac	2003-07-28 02:07:15.000000000 +0100
+++ b/utp.mac	2013-01-22 19:35:24.159533458 +0000
@@ -55,6 +55,7 @@
 .de utp_Ah
 .sp 26p
 .RT
+.pdfbookmark 2 \\$1
 .ne 6
 .ps 14
 .vs 16
@@ -65,7 +66,7 @@
 .lg
 .sp 18p
 .ns
-.if \\n[Ref] .tm Ah:	\\n(PN	\\$1
+.if \\n[Ref] .tm Ah:	\\*[PDFBOOKMARK.NAME]	\\n(PN	\\$1
 ..
 \#
 \#  The [ABCD]-head macros
@@ -95,6 +96,7 @@
 \#
 .de Bh                  \" B-head. $1: title
 .sp 23p
+.pdfbookmark 3 \\$1
 .RT
 .ne 6
 .ps 14
@@ -163,6 +165,7 @@
 .\}
 .ds chapter_name \\$2
 .ie !'\\$1'' \{.		\" If we have a section number
+.       utpbookmark -T "\\$3\\$1" 1 "\\$1. \\$2"
 .	ds chapter_head \\$1
 .	nr is_alpha 0
 .	if '\\$1'A' .set_section 1
@@ -198,6 +201,7 @@
 .\}
 .el \{.                 \" Illegal Chapter Appendix number
 .	nr section 0
+.       utpbookmark -T \\$2 1 \\$2
 .                       \" Might be Preface, etc. so no error diag.
 .\}
 .nr chapter_page2 1		\" Next page starts a chapter, so no header
@@ -215,10 +219,10 @@
 .nr table_num 0          \" Reset table number
 .format_section "\\$1" "\\$2" \\$3 \\$4
 .ie '\\$1'' \{\
-.ie '\\$2'' .if \\n[Ref] .tm	Se:	\\n(PN		\\$3
-.el .if \\n[Ref] .tm Se:	\\n(PN	\\$1	\\$2
+.ie '\\$2'' .if \\n[Ref] .tm	Se:	\\*[PDFBOOKMARK.NAME]	\\n(PN		\\$3
+.el .if \\n[Ref] .tm Se:	\\*[PDFBOOKMARK.NAME]	\\n(PN	\\$1	\\$2
 .\}
-.el .if \\n[Ref] .tm Se:	\\n(PN	\\$1	\\$2
+.el .if \\n[Ref] .tm Se:	\\*[PDFBOOKMARK.NAME]	\\n(PN	\\$1	\\$2
 ..
 \#
 \# Set section number for alphabet chapters (appendices)
@@ -695,6 +699,16 @@
 'po \\n[PO]u
 'sp |\\n[page-end]u
 ..
+.de ix
+.ie '\\n(.z'' \{\
+.   if !'\\$1'%end' \{\
+.      ds ixbk ix:bm\\n+[ixno]
+.      pdfhref M -N \\*[ixbk]
+.   \}
+.   if \\n[Ref] .tm ix: \\$*	\\n%	\\*[ixbk]
+.\}
+.el \\!.ix \\$*
+..
 \#
 \# Set defaults for UTP
 \#
@@ -717,5 +731,12 @@
 .vs \\n[VS]
 .ev
 ..
+.de utpbookmark
+.ie '\\*[.T]'ps' \{\
+.    pdfhref M -N \\$2 -- \\$4
+.    if !dpdf:href.map .tm gropdf-info:href \\$2 \\$4
+.    pdfbookmark \\$3 \\$4
+.\}
+.el .pdfbookmark \\$*
+..
 .em EM
-
--- a/contrib/pdfmark/pdfmark.tmac	2010-12-23 21:24:53.000000000 +0000
+++ b/contrib/pdfmark/pdfmark.tmac	2012-06-11 11:49:35.000000000 +0100
@@ -110,7 +110,7 @@
 .   \"
 .   \" This PDFMARK is suitable for single chunk output ...
 .   \"
-.      nop \X'ps:exec [\\$* pdfmark'\c
+.      nop \!x X ps:exec [\\$* pdfmark
 .      \}
 .   el \{\
 .   \" ... but, when the limit would be violated, then we must

Reply via email to