#!/usr/bin/perl use strict; use warnings; sub help { my $cmdname = $0; $cmdname =~ s:.*/::; print "$cmdname - list bib keys cited in LaTeX files and not defined in bib files.\n"; print "Input is read from stdin or from named files.\n"; print "The keys are those found in \\cite commands.\n"; print "Each \\cite command can contain several keys, and can span lines.\n"; print "The keys are presented sorted lexicographically, with each key listed once\n"; print "even if it appears more than once.\n"; print "If any .bib files are named on the command line, these are scanned for\n"; print "definitions of keys. Then only cited keys that are not defined are listed.\n"; print " -help Show this help.\n"; print " -1 Display keys one per line.\n"; print " -, Display keys in a comma-separated list.\n"; print " -v Verbose.\n"; print "\n"; print "Here is an example use of $cmdname with bibfile to collect all the bib\n"; print "entries needed for a group of .tex files:\n"; print "bibfile -keep=`$cmdname *.tex` -expandCrossrefs"; print " -keepStandardFields -showEntry ~/alspaugh.bib >cited.bib\n"; } my $arg; my $numFiles = 0; my $sep = ","; my $v = ""; my $k = ""; my %keys = (); my %keysDefined = (); my $count = 0; foreach $arg (@ARGV) { if ($arg =~ /^-/) { if ($arg =~ /^-+help$/) { &help; exit 0; } elsif ($arg =~ /^-+1$/) { $sep = "\n"; } elsif ($arg =~ /^-+,$/) { $sep = ","; } elsif ($arg =~ /^-+v$/) { $v = "y"; } else { print "Unexpected argument \"$arg\".\n"; exit 0; } } else { if (open(HIN, $arg)) { if ($arg =~ /\.bib$/) { &bibFile(\*HIN, $arg); } else { &perFile(\*HIN, $arg); } close HIN; ++$numFiles; } else { print STDERR "Can't open input file \"$arg\".\n"; exit -1; } } } if (0 == $numFiles) { &perFile(\*STDIN); } if (scalar %keys) { foreach $k (sort keys %keys) { if (defined $keysDefined{$k}) { # do nothing } else { if ($count++) { print "$sep"; } print "$k"; } } print "\n"; } sub bibFile { my $IN = $_[0]; my $fname = $_[1]; my $lineno = 0; while (<$IN>) { ++$lineno; chomp; if (/^@[a-zA-Z]+[({]([-0-9a-zA-Z+]+),$/) { s/^@[a-zA-Z]+[({]([-0-9a-zA-Z+]+),$/$1/; #print "$_\n"; my $key = $_; if (defined $keysDefined{$key}) { print STDERR "($fname:$lineno) '$key' multiply defined ($keys{$key}).\n"; } $keysDefined{$_} = "$fname:$lineno"; } } } sub perFile { my $IN = $_[0]; my $fname = $_[1]; my $inCite = ""; my $line = ""; my $lineno = 0; while (<$IN>) { ++$lineno; chomp; s/^%.*$//; s/([^\\])%.*/$1/g; if ($inCite) { s/^[ \t]+//; $line = "${inCite}$_"; $inCite = ""; if ($v) { print STDERR "Joining lines: `$line'\n"; } } else { $line = $_; } while ($line =~ /^.*?(\\cite{) *([^,}]+),?([^}]*}.*)/) { $k = $line; $k =~ s/^.*?(\\cite{) *([^,}]+),?([^}]*}.*)/$2/; $line =~ s/^.*?(\\cite{) *([^,}]+),?([^}]*}.*)/$1$3/; $keys{$k} = "$fname:$lineno"; if ($v) { print STDERR "Cited `$k'\n"; } } if ($line =~ /.*(\\cite{[^}]*$)/) { $inCite = $line; $inCite =~ s/.*(\\cite{[^}]*$)/$1/; } } }