#!/bin/bash
#
# Copyright (c) 2006 Mael Hillereau
#
# This file is part of alphabib.
#
# alphabib is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# alphabib is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with alphabib; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# cxBib -- Addition of alphabetical headers into BibTeX '.bbl' files.
# Author:        Mael Hillereau <mael.hillereau@free.fr>
# Created:       12.apr.2006
# Last modified: 18.apr.2006
version="0.6";
author="Mael Hillereau <mael.hillereau@free.fr>";
name=`basename $0`;

# default definitions for LaTeX macros
defaultpenalty="\penalty-200";
defaultskip="\bigskip";
defaultlabel="\Large\bfseries#1\hfill";
defaultcontent="\ \\\\[-1ex]\hrule\medskip";
pdfbookmarks="";
pdfbookmarkscodewithoutlevel="\expandafter\ifx\csname firstpdfbookmark\endcsname\relax\
\subpdfbookmark{#1}{alphabib.#1}\
\def\firstpdfbookmark{}\
\else\
\currentpdfbookmark{#1}{alphabib.#1}\
\fi";
pdfbookmarkslevel="";
pdfbookmarkscodewithlevelB="\pdfbookmark[";
pdfbookmarkscodewithlevelE="]{#1}{alphabib.#1}";

# display errors
function error()
{
  echo -ne "Error:\t$1\n\tTry '$name -h' for some help.\n";
}

# display usage
function usage()
{
  echo "";
  echo "SYNTAX";
  echo "  $name [-hv] [-b [-l level]] <input-file.bbl> [<output-file.bbl>]";
  echo "";
  echo "DESCRIPTION";
  echo "  Addition of alphabetical headers into BibTeX '.bbl' files. Input and output";
  echo "  files may be identical, which is equivalent to no output file given. Input";
  echo "  file must be a '.bbl' file generated by BibTeX (so you have to run bibtex";
  echo "  before running $name).";
  echo "";
  echo "OTIONS";
  echo "  -b";
  echo "    This option will cause insertion of bookmarks into PDF files. Of course, it";
  echo "    requires using 'hyperref' package. Bookmarks level is set automatically if";
  echo "    option -l is not given.";
  echo "  -h";
  echo "    Displays this help.";
  echo "  -l";
  echo "    This option allows specifying level of bookmarks into PDF files. It must be";
  echo "    used with -b option.";
  echo "  -v";
  echo "    Displays version information.";
  echo "";
  echo "See the manual for more detailed information.";
  echo "";
}

# deletion of temporary files
function clean()
{
  rm -f "$inputfile.working";
}

echo "This is cxBib version $version.";
echo "Bash script written by $author.";

# other arguments
while getopts "bhl:v" arg
do
  case $arg in
  b)
    echo "PDF bookmarks option selected.";
    pdfbookmarks=$pdfbookmarkscodewithoutlevel;;
  h)
    usage;
    exit 0;;
  l)
    echo "Bookmarks level $OPTARG selected.";
    pdfbookmarkslevel=$OPTARG;;
  v)
    exit 0;;
  ?)
    error "Problem while processing options.";
    exit 1;;
  esac
done
shift $(($OPTIND - 1));

# input and output files
if [ $# -eq 1 ]
then
  outputfile=$1;
elif [ $# -eq 2 ]
then
  outputfile=$2;
else
  error "Invalid number of arguments!";
  exit 1;
fi
if [ ! -f "$1" ]
then
  error "'$1' is not a valid file!";
  exit 2;
fi
inputfile=$1;

# test dependence between -b and -l and adjust bookmarks code
if [ ! -z "$pdfbookmarkslevel" ]
then
  if [ -z "$pdfbookmarks" ]
  then
    error "-l option used without -b option!";
    exit 1;
  fi
  pdfbookmarks=$pdfbookmarkscodewithlevelB$pdfbookmarkslevel$pdfbookmarkscodewithlevelE;
fi

# make a working copy of input file
cp -i $inputfile $inputfile.working;
if [ $? -ne 0 ]
then
  error "Unable to create a temporary file. You must have write permission into\n\tthe current directory!";
  exit 3;
fi

# test wether input file contains a bibliography environment
grep -n -e "\\\\begin{thebibliography}" "$inputfile.working" > /dev/null 2>&1
bbibenv=$?;
grep -n -e "\\\\end{thebibliography}" "$inputfile.working" > /dev/null 2>&1
ebibenv=$?;
if [ $bbibenv -ne 0 -o $ebibenv -ne 0 ]
then
  error "'$inputfile' is not a valid '.bbl' file !";
  clean;
  exit 4;
fi

# scanning input file
endpreamb=`grep -m 1 -n -e "^$" $inputfile.working | tr -d ":"`;
if [ "$endpreamb" == "" ]
then
  error "Couldn't find end of bibliography preamble in '$inputfile'!";
  clean;
  exit 4;
fi
preamb=`head -n$endpreamb $inputfile.working`;
nblines=`wc -l $inputfile.working | cut -f 1 -d " "`
rawentries=`grep -n -e "^.bibitem" $inputfile.working | tr " " "@" | tr "\n" " "`;
echo "$nblines lines; end of preamble on line $endpreamb.";

nbentries=0;
for rawentry in $rawentries
do
  line[$nbentries]=`echo $rawentry | cut -f 1 -d ":"`;
  if [ $nbentries -ne 0 ]
  then
    next[`expr $nbentries - 1`]=${line[$nbentries]};
  fi
  letter[$nbentries]=`expr match "$rawentry" '.*bibitem.\(.\).*'`;
  nbentries=`expr $nbentries + 1`;
done

next[`expr $nbentries - 1`]=$nblines;

echo "$nbentries bib entries found in input file '$inputfile'."

# read again and write output file
echo "$preamb" > $outputfile;

# write '\alphabibitem' macro definition
echo "\def\alphabibitem#1{\
\expandafter\ifx\csname firstalphabibitem\endcsname\relax\
\def\firstalphabibitem{}\
\else\
\expandafter\ifx\csname alphabibitemskip\endcsname\relax\
$defaultskip\
\else\
\alphabibitemskip\
\fi\
\fi\
\expandafter\ifx\csname alphabibitempenalty\endcsname\relax\
\alphabibitempenalty\
\else\
$defaultpenalty\
\fi\
$pdfbookmarks\
\expandafter\ifx\csname alphabibitemlabel\endcsname\relax\
\expandafter\ifx\csname alphabibitemcontent\endcsname\relax\
\item[$defaultlabel]$defaultcontent\
\else\
\item[$defaultlabel]\alphabibitemcontent{#1}\
\fi\
\else\
\expandafter\ifx\csname alphabibitemcontent\endcsname\relax\
\item[\alphabibitemlabel{#1}]$defaultcontent\
\else\
\item[\alphabibitemlabel{#1}]\alphabibitemcontent{#1}\
\fi\
\fi}" >> $outputfile;

n=0;
precletter="_"
for rawentry in $rawentries
do
  currentletter=${letter[$n]};
  currentline=${line[$n]};
  nextline=${next[$n]};
  last=`expr $nblines - $currentline + 1`;
  first=`expr $nextline - $currentline`;
  bibentry=`tail -n$last $inputfile.working | head -n$first`
  if [ ! $currentletter == $precletter ]
  then
    echo -ne "$currentletter ";
    echo -ne "\n\\\\alphabibitem{$currentletter}\n" >> $outputfile;
    precletter=$currentletter;
  fi
  echo -ne "\n" >> $outputfile;
  echo "$bibentry" >> $outputfile;
  n=`expr $n + 1`;
done

echo -ne "\n\\\\end{thebibliography}\n" >> $outputfile;

# delete temp files
clean;

echo -ne "\nOutput written in '$outputfile'.\n";
exit 0;
