[comp.text.tex] bibfix - A Bibliographic Cross Reference Generator

collberg@dna.lth.se (Christian S. Collberg) (03/08/91)

Some time ago I asked for a bibliographic cross reference generator
to produce bibliographies along the line of what is found in 
"Concrete Mathematics". Someone pointed out the gkpmac.tex style file
used by Knuth et. al. in the production of the book, but it was not 
immediatedly obvious to me how to use gkpmac with bibtex. I finally 
decided to write my own generator from scratch. Please try it out, 
improve it, and send me the changes! I'd be especially greatful if 
someone with more knowledge of TeX than myself would come up with a 
better way of positioning the cross references than using marginpars. 

This is a gross hack. Use it at your own risk.

Christian S. Collberg
Christian.Collberg@dna.lth.se



#!/bin/sh
# This is a shell archive.  Remove anything before the "#!/bin/sh" line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have original permissions).
# This archive contains the following files:
#	./README
#	./bibfix
#	./cross.sty
#
echo "writing ./README"
sed 's/^X//' > ./README << '\End\of\File\'
X
X                                bibfix
X                                ======
X
X            Bibliographic cross reference generator for LaTeX
X
X
X      Copyright (c) 1991 by Christian S. Collberg
X      Permission to copy all or part of this work is granted, including
X      distribution for resale, provided that authorship is acknowledged 
X      and that the copyright notice and this notice are retained.
X
X      Bug reports, comments, and modifications may be sent to
X                      Christian.Collberg@dna.lth.se
X
X
XBibfix is a bibliographic cross reference generator to be used with 
XLaTeX and BibTeX. It modifies the .bbl file created by BibTeX by
Xincluding for each bibliographic entry the page numbers in the document
Xon which that entry was referenced. For an example see the bibliography
Xin Graham, Knuth, and Patashnik's "Concrete Mathematics".
X
XTo include cross referencing information in the document doc.tex 
Xinsert "cross" in the documentstyle header:
X
X    \documentstyle[...,cross,...]{...}
X    
Xand run the following commands:
X
X   > latex doc
X   > bibtex doc
X   > bibfix doc
X   > latex doc
X   
XFeatures:
X   + Page ranges (more than 2 consecutive pages containing 
X     references to the same article) are recognized. For 
X     example, if a certain bibliographic entry is referenced 
X     on pages 1,2,5,6, and 7 the cross referencing information
X     will come out as 1, 2, 5--7.
X   + Roman numbering is handled if it occurs at the beginning
X     of a document.
X   + The commands \crossbib, \crossnr, and \crossrange in
X     cross.sty can be modified to control the layout of 
X     the cross references.
X       
XBugs:
X   + Unix specific. Uses sort, awk, *and* nawk.
X   + Uses marginpar for positioning the cross references. 
X     According to the LaTeX book more than 5 marginpar's 
X     per page is dangerous. I have also run into marginpars
X     which come out in the wrong margin when they occur
X     at the top of a page. 
X   + If there are 10 initial roman numbered pages, followed
X     by pages using arabic numbering, and a certain article
X     is referenced on pages ix, x, 1, 2, 3 then the cross
X     references will be ix, x, 1--3, rather than ix--3. This
X     may be construed as a feature.
X   + I have not tested what happens in the presence of
X     include-files, includeonly, etc. 
X   + This being a gross hack, there are undoubtedly many more.
\End\of\File\
chmod 640 ./README
if [ `wc -c ./README | awk '{printf $1}'` -ne 2379 ]
then
echo `wc -c ./README | awk '{print "Got " $1 ", Expected " 2379}'`
fi
echo "writing ./bibfix"
sed 's/^X//' > ./bibfix << '\End\of\File\'
X#!/bin/csh
X#                                bibfix
X#                                ======
X#
X#            Bibliographic cross reference generator for LaTeX
X#
X#
X# Copyright (c) 1991 by Christian S. Collberg
X# Permission to copy all or part of this work is granted, including
X# distribution for resale, provided that authorship is acknowledged 
X# and that the copyright notice and this notice are retained.
X#
X# Bug reports, comments, and modifications may be sent to
X#                      Christian.Collberg@dna.lth.se
X
Xset first   = /tmp/$$.$1.1
Xset second  = /tmp/$$.$1.2
Xset third   = /tmp/$$.$1.3
Xset fourth  = /tmp/$$.$1.4
Xset fifth   = /tmp/$$.$1.5
Xset sixth   = /tmp/$$.$1.6
Xset seventh = /tmp/$$.$1.7
X
X# Extract \crosscite from .aux file. Subtract 10000 from roman numerals.
X# PRE:  \crosscite{Kieburtz78,Rudmik82,Barringer79}{5}{v}
X#       \crosscite{Fraser82}{1}{1}
X# POST: Kieburtz78,Rudmik82,Barringer79 -9995
X#       Fraser82 1
Xawk -F"{" \
X   '/\crosscite/ {x=substr($2,1,length($2)-1);\
X                  y=substr($3,1,length($3)-1);\
X                  z=substr($4,1,length($4)-1);\
X                  if (y==z) {print x,",",y} else {print x,",",y-10000}}'\
X         $1.aux >! $first
X
X# Separate multiple cites.
X# PRE:  Kieburtz78,Rudmik82,Barringer79 -9995
X# POST: Kieburtz78 -9995
X#       Rudmik82 -9995
X#       Barringer79 -9995
Xawk -F"," '{for(i=1;i<=(NF-1);i++){print $i,$NF}}' $first >! $second
X
X# Sort on label, then page number. Roman numerals are negative and  
X# come first. Duplicate entries (more than one \cite to the same article 
X# on the same page) are removed.
X# PRE:  Kieburtz78 10
X#       Kieburtz78 -9995
X#       Fraser82 11
X#       Fraser82 12
X#       Fraser82 10
X#       Fraser82 11
X# POST: Fraser82 10
X#       Fraser82 11
X#       Fraser82 12
X#       Kieburtz78 -9995
X#       Kieburtz78 10
Xsort +0 -1 +1n -u $second >! $third
X
X# Merge references.
X# PRE:  Fraser82 10
X#       Fraser82 11
X#       Fraser82 12
X#       Kieburtz78 -9995
X#       Kieburtz78 10
X# POST: Fraser82 10 11 12
X#       Kieburtz78 -9995 10
Xawk '{if (id==$1) \
X        {printf "%s", " " $2} \
X      else {\
X         if (id != "") print ""; \
X         printf "%s", $0}; \
X      id=$1}\
X      END {print ""}' $third >! $fourth
X
X# Merge sequences.
X# PRE:  Fraser82 10 11 12
X#       Kieburtz78 -9995 10
X#       Celentano80 8 9 11
X# POST: Fraser82 \crossrange{10}{12}
X#       Kieburtz78 \crossnr{\romannumeral 5}, \crossnr{10}
X#       Celentano80 \crossnr{8} \crossnr{9}, \crossnr{11}
Xawk '{printf "%s",$1 " "; i=2; \
X      while (i<=NF){\
X         if (i != 2) {printf "%s",", "}; \
X         j=i+1; k=i+2;\
X         if (($i==$j-1) && ($i==$k-2)) {\
X            x=$i; \
X            while ((i<=NF) && ($i == $j-1)) {i++; j=i+1}; \
X            y=$i; \
X            if (x<0) {x="\\\\romannumeral " x+10000}; \
X            if (y<0) {y="\\\\romannumeral " y+10000}; \
X            printf "%s","\\\\crossrange{" x "}{" y "}" } \
X         else {\
X            x=$i; \
X            if (x<0) {x="\\\\romannumeral " x+10000}; \
X            printf "%s", "\\\\crossnr{" x "}" }; \
X         i++};\
X         print ""}' $fourth >! $fifth
X
X# Create awk-script to insert cross references in the .bbl file.
X# PRE:  Fraser82 \crossrange{10}{12}
X# POST: /bibitem{Fraser82}/ {print $0; P="\crossbib{\crossrange{10}{12}}"; next}
X#       {print $0; if (P != "") {print P; P=""}}
Xawk '{printf "%s", "/bibitem{"$1"}/ {print $0; P=\"\\\\crossbib{"; \
X     for (i=2;i<=NF;i++){printf "%s", $i " "}; \
X     print "}\"; next}"} \
X     END {print "{print $0; if (P != \"\") {print P; P=\"\"}}"}' $fifth >! $sixth
X
X# Insert cross references in .bbl file. 'awk' can not be used here since it
X# allows only short literal strings.
X# PRE:  \bibitem{Fraser82}
X#       Christopher~W. Fraser and David~R. Hansson.
X#       \newblock A machine-independent linker.
X#       \newblock {\em Software---Practice and Experience}, 12:351--366, 1982.
X# POST: \bibitem{Fraser82}
X#       Christopher~W. Fraser and David~R. Hansson.
X#       \crossbib{\crossrange{10}{12}}
X#       \newblock A machine-independent linker.
X#       \newblock {\em Software---Practice and Experience}, 12:351--366, 1982.
Xnawk -f $sixth $1.bbl >! $seventh
X
X# Clean up
Xmv -f $seventh $1.bbl
X/bin/rm $first $second $third $fourth $fifth $sixth
X
X
\End\of\File\
chmod 750 ./bibfix
if [ `wc -c ./bibfix | awk '{printf $1}'` -ne 4261 ]
then
echo `wc -c ./bibfix | awk '{print "Got " $1 ", Expected " 4261}'`
fi
echo "writing ./cross.sty"
sed 's/^X//' > ./cross.sty << '\End\of\File\'
X% From latex.tex
X\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi
X  \if@filesw\immediate\write\@auxout{\string\crosscite{#2}{\the\c@page}{\thepage}}\fi
X  \def\@citea{}\@cite{\@for\@citeb:=#2\do
X    {\@citea\def\@citea{,\penalty\@m\ }\@ifundefined
X       {b@\@citeb}{{\bf ?}\@warning
X       {Citation `\@citeb' on page \thepage \space undefined}}%
X\hbox{\csname b@\@citeb\endcsname}}}{#1}}
X
X\newcommand{\crosscite}[3]{}
X\newcommand{\crossbib}[1]{\marginpar{\scriptsize #1}}
X\newcommand{\crossnr}[1]{#1}
X\newcommand{\crossrange}[2]{\crossnr{#1}--\crossnr{#2}}
\End\of\File\
chmod 640 ./cross.sty
if [ `wc -c ./cross.sty | awk '{printf $1}'` -ne 587 ]
then
echo `wc -c ./cross.sty | awk '{print "Got " $1 ", Expected " 587}'`
fi
echo "Finished archive 1 of 1"
# if you want to concatenate archives, remove anything after this line
exit
-- 

--------------------------------------------------------------------
Christian.Collberg@dna.lu.se