#!/usr/bin/perl -w ###################################################################### # Given a .tex file and an optional .aux file, the references in the # .tex file are sorted according to occurence. # Author: Joakim Edsjo, edsjo@physto.se # Date: November 8, 1999 ###################################################################### use Getopt::Std; ######### SETUP and INPUT ########## $ver="1.2, November 8, 1999"; ### Parse input arguments getopts('a:o:s:wh',\%opts); if ($#ARGV < 0 || $opts{"h"}) { # No arguments print< to determine the order of occurance of citations instead of using the tex-file directly. -o file write output to . Default: Input file with '-new' inserted before '.tex'. -s method Use to sort the references. can be 1 : sort by order of occurance (default) 2 : sort alphabetically as given by the optional argument to \\bibitem. -w Do not overwrite the output file if it exists. Instead issue a warning about it. All files can be given without the trailing '.tex' and '.aux' respectively. If only a texfile is given, the information in that single file is used to check either the order of occurence or alphabetic order. This is sufficient for simple tex files without any \\include or \\input lines or if an alphabetic sort is requested. For more complex multi-file tex documents, the information about occurance can be retrieved from the aux file instead. In this case supply the name of the aux file as '-a auxfile' and use the file with the bibliographic information as the input texfile. For example, if you have a big tex document with the main document called Main.tex and the bibliography information in Refs.tex you would call bibsort.pl like 'bibsort.pl -a Main.aux Refs.tex'. Joakim Edsjo, edsjo\@physto.se END } die "-- bibsort.pl version $ver --\n"; } $texfile=$ARGV[0]; $texfile .= ".tex" unless $texfile =~ /.tex$/; if ($opts{"a"}) { $auxfile=$opts{"a"}; $auxfile .= ".aux" unless $auxfile =~ /.aux$/; } if ($opts{"o"}) { $outfile=$opts{"o"}; $outfile .= ".tex" unless $outfile =~ /.tex$/; } else { ($outfile = $texfile) =~ s/.tex$/-new.tex/; } if (! $opts{"s"} || $opts{"s"} == 1) { $sortstyle=1; } elsif ($opts{"s"} == 2) { $sortstyle=2; } else { die "Unknown option: -s $opts{'s'}\n"; } print "Welcome to bibsort.pl version $ver\n"; -e $texfile || die "$texfile doesn't exist. Stopping.\n"; if ($sortstyle==1 and $auxfile and ! -e $auxfile) { print "$auxfile doesn't exist, but you have requested to use it.\n"; print "Should I run latex on $texfile? [y]"; unless ( =~ /^[nN]/) { unless (system("latex $texfile") == 0) { print "Couldn't run latex on $texfile without errors: $!\n"; die "Please run latex on $texfile manually to produce the aux-file.\n"; } } else { die "OK. Please run latex on $texfile manually to produce the aux-file.\n"; } } if (-e $outfile && $opts{"w"}) { print "WARNING: The output file $outfile exists, overwrite? [n] "; unless ( =~ /^[yY]/) { print "Give me a new output file:\n"; chomp($outfile=); } } if ($sortstyle==1) { print "I will use the following files:\n"; print " .tex file: $texfile\n"; print " .aux file: $auxfile\n" if $auxfile; } else { print "I will use the following file:\n"; print " .tex file: $texfile\n"; } print " output file: $outfile\n"; print "Sorting is in order of occurance.\n" if $sortstyle==1; print "Sorting is alphabetically.\n" if $sortstyle==2; ########## SCAN THE INPUT FILE(S) ########## if ($sortstyle==1) { ########## In order of appearance ########## $nrcite=0; if ($auxfile) { ##### Go through aux file for citations ##### print "Going through ${auxfile} for citations...\n"; open(AUXFILE,$auxfile) || die "Can't open $auxfile: $!"; while () { if (/^\\citation{(\S+)}/) { @cites=split(/,/,$1); foreach $cite (@cites) { unless ($citations{$cite}) { $citations{$cite}=++$nrcite; } } } } close(AUXFILE) || die "Can't close $auxfile: $!"; } else { ##### Go through tex file for citations ##### print "Going through ${texfile} for citations...\n"; open(TEXFILE,$texfile) || die "Can't open $texfile: $!"; $all = join("",); $all =~ s/(^.*?)[^\\]%$/$1/g; $all =~ s/\s+//g; while ($all =~ /^.*?\\cite{(.*?)}/) { @cites=split(/,/,$1); foreach $cite (@cites) { unless ($citations{$cite}) { $citations{$cite}=++$nrcite; } } $all=$'; # remaining part of string } close(TEXFILE) || die "Can't close $texfile: $!\n"; } %citations = reverse %citations; # Swap citations and number ##### Go through texfile ##### print "Going through $texfile and sorting references...\n"; open(TEXFILE,$texfile) || die "Can't open $texfile: $!"; open(OUTFILE,">".$outfile) || die "Can't open $outfile: $!"; while () { print OUTFILE $_; last if /^[^%]*\\begin{thebibliography}/; } ### OK, we have now printed upto \begin{thebib... to $outfile $type="first"; while(){ if (/^[^%]*\\end{thebibliography}/) { $type="after"; } # if (/^[^%]*\\bibitem[^\{]*{(\S+)}/ && $type ne "after") { if (/^[^%]*\\bibitem(?:\[.*\])?.*?{(\S+)}/ && $type ne "after") { $cite=$1; # citation label while ($entry{$cite}) { $cite .= "2"; } $type="entries"; } if ($type eq "first") { $linesbefore .= $_; } elsif ($type eq "entries") { $entry{$cite} .= $_; } else { # else $type eq "after" $linesafter .= $_; } } # end while close(TEXFILE) || die "Can't close $texfile: $!"; ### Print out the lines before the first entry print OUTFILE $linesbefore; ### Print out the entries in order of occurance for ($i=1; $i<=$nrcite; $i++) { if ($entry{$citations{$i}}) { print OUTFILE $entry{$citations{$i}}; delete $entry{$citations{$i}}; } else { print OUTFILE "\\bibitem{$citations{$i}}" . " {\\bfseries MISSING REFERENCE!!!}\n\n"; } } ### Print out remaining entries if (keys(%entry)>0) { # if %citations is non-empty print OUTFILE "\\bibitem{???} {\\bfseries THE REMAINING CITATIONS" . " ARE NEVER REFERED TO.}\n\n"; foreach $entry (values %entry) { print OUTFILE $entry; } } ### Print out the remaining lines print OUTFILE $linesafter; close(OUTFILE) || die "Can't close $outfile: $!"; print "The new tex file is $outfile\n"; } else { # $sortstyle==2 ########## In alphabetic order ########## ##### Go through texfile ##### print "Going through $texfile and sorting references...\n"; open(TEXFILE,$texfile) || die "Can't open $texfile: $!"; open(OUTFILE,">".$outfile) || die "Can't open $outfile: $!"; while () { print OUTFILE $_; last if /^[^%]*\\begin{thebibliography}/; } ### OK, we have now printed upto \begin{thebib... to $outfile $type="first"; $i=0; while(){ if (/^[^%]*\\end{thebibliography}/) { $type="after"; } # if (/^[^%]*\\bibitem[^\{]*{(\S+)}/ && $type ne "after") { if (/^[^%]*\\bibitem(?:\[(.*)\])?.*?{(\S+)}/ && $type ne "after") { if ($1) { $cite=$1; # optional text - now clean it $cite =~ s/(\\[.&]*)\s//g; $cite =~ s/\W+//g; } else { $cite="ZZZextra".++$i; } $cite="\L$cite"; while ($entry{$cite}) { $cite .= "2"; } $type="entries"; } if ($type eq "first") { $linesbefore .= $_; } elsif ($type eq "entries") { $entry{$cite} .= $_; } else { # else $type eq "after" $linesafter .= $_; } } # end while close(TEXFILE) || die "Can't close $texfile: $!"; ### Print out the lines before the first entry print OUTFILE $linesbefore; ### Print out the entries in order of occurance foreach $opt (sort keys %entry) { print OUTFILE $entry{$opt}; } ### Print out the remaining lines print OUTFILE $linesafter; close(OUTFILE) || die "Can't close $outfile: $!"; print "The new tex file is $outfile\n"; }