#!/usr/bin/env perl
#
# Script to sort a bibtex .bib file in lexicographic order of citation key.
# The sort is case insensitive, so Abel2002 comes after abel2001.
#
# If any duplicate keys are encountered during the scan a warning is printed to
# stderr - the last mention of the key in the original file will be the one
# that ends up in the sorted file, but you should probably go back and fix the
# original file to remove duplicates.
#
# Usage:
#
#   ./sort-bib.pl file.bib > sorted-file.bib
#
# Ian Roberts, 2013-05-22

use warnings;
use strict;

my %bib = ();

my $curKey = '';
my $curEntry = '';

while(<>) {
  # starting a new entry
  if(/^\%*\@[A-Za-z0-9]+\s*\{\s*(.+)$/s) {
    my $lastKey = $curKey;
    $curKey = $1;

    # add a blank line separating one entry from the next, if there is not one
    # there already
    unless($curEntry =~ /\n\s*\n\s*$/) {
      $curEntry .= "\n";
    }

    if(exists $bib{$lastKey}) {
      print STDERR "Duplicate key found: $lastKey\n";
      print STDERR "Previous value:\n$bib{$lastKey}";
      print STDERR "New value:\n$curEntry";
    }
    $bib{$lastKey} = $curEntry;
    $curEntry = '';
  }
  $curEntry .= $_;
}

# Handle the last entry
$bib{$curKey} = $curEntry;

foreach my $key (sort { lc $a cmp lc $b } keys %bib) {
  print $bib{$key};
}
