#!/bin/sh -u
# Authors: Marc Boyer
#          Esa Hyytia (header option)
# Date  : 10/6/2008

# Version : 0.5

# sh options
# -u       Treat unset variables as an error when  substituting. 
# -v       Print shell input lines as they are read.
# -x       Print commands and their arguments as they are executed.


# Erase de LANG environment variable, because it can create bugs with 
# sed. With my "fr_FR@euro" value, some regular expression in ps2epsi
# fail.
LANG=

# Tools
PS2EPS=ps2epsi
PS2EPS_CMDNAME=ps2epsi


# Default options

METHOD=2
PS2PS_OPT=no
EPS2EPS_OPT=no
CLEAN_OPT="yes"
FORCE_EPSI_OPT="no"
OWN_HEADER_OPT=""
MASTER_FILE_OPT=""
AUTO="no"

TMPD=/tmp


# usage method
usage() {
cat <<EOF
Usage: $0 [-h][-p][-e][-a][-m method][-H header_file.tex][-M master_file.tex] file.tex
    -h: help
    -m: method: integer in 0..3 (default is 2)
       the number of the method used to convert dvi to pdf
       if one method fails, try another, and add -p and/or -e options :-)
    -p: filter each postscript file with ps2ps
    -e: filter each encapsulated postscript file with eps2eps
    -a: auto/all, translate all figures included with \includegraphics (avoid 
	the use of \pdfrackincludegraphics)
    -i: force use of ps2epsi instead of ps2eps
    -k: keep (all tempory files are keeped, usefull for debug)
    -H: own header file (default is to extract from .tex file)
    -M: master file (to handle sub files)

Authors: Marc Boyer <Marc.Boyer@enseeiht.fr>
Contributors:  Esa Hyytia (header option)
Version: 1.0
EOF
}


detect_ps2eps_filter() {
    ps2eps -V > /dev/null
    if [ $? -ne 0 ]
    then
cat<<EOF
Warning: ps2eps not found. Using ps2epsi instead
	   this should produce incorrect bounding boxes
You can disable this warning with option -i
You can find ps2eps at:
  http://www.ipv6.tm.uka.de/~bless/ps2eps
  ps2eps: (C)opyright 1998-2004 Roland Bless
EOF
	PS2EPS=ps2epsi
	PS2EPS_CMDNAME=ps2epsi
    else
	PS2EPS=ps2eps_with_output
	PS2EPS_CMDNAME=ps2eps
    fi	
}



cleantexfiles(){
    if [ $CLEAN_OPT = "yes" ]
    then
	\rm -f ${FIGNAME}.tex ${FIGNAME}.dvi  ${FIGNAME}.aux  ${FIGNAME}.log ${FIGNAME}.thm
    fi
}

cleanfiles(){
    if  [ $CLEAN_OPT = "yes" ]
    then
        echo "Removing temporary files"
        cleantexfiles;
        \rm -f $*
    fi
}


detect_mktemp(){
    mktemp /tmp/testMktemp-XXXXXX > /dev/null    
    if [ $? = "1" ]
    then
	echo "Warning: no mktemp foumd"
	MKTEMP=echo
    else
	MKTEMP=mktemp
    fi
    \rm -f /tmp/testMktemp-*
}


# This function is "like" ps2eps except that his second argument is
#    the name of the output file

ps2eps_with_output() {
    mv $1 $1.ps
    ps2eps -q $1.ps
    mv $1.eps $2
}


# This function just runs ps2ps on its first argument, and uses
# the second argument to store the old file, if the PS2PS_OPT is set
# to yes  
# Classical uses are 
#   ps2psFilter file.ps file.ps.bak
#   ps2psFilter file.ps file-raw.ps
ps2psFilter(){    
    if [ ${PS2PS_OPT} = "yes" ]
    then
	echo "     Cleaning ps with ps2ps filter"
	mv $1 $2
	ps2ps $2 $1
    fi
}

# Same as ps2ps with eps
eps2epsFilter(){
    if [ ${EPS2EPS_OPT} = "yes" ]
    then
	echo "     Cleaning eps with eps2eps filter"
	mv $1 $2
	eps2eps $2 $1
    fi
}

# This simple version relies on dvips + ps2pdf.
# It outputs a too wide bounding box
dvi2pdfV0() {
    echo "Method 0: Trying conversion with dvips -|-> ps2pdf"
    echo "Converting dvi -> ps (dvips)" 
    FIG_DVIPS=`${MKTEMP} ${TMPD}/${FIGNAME}-dvi2ps.ps.XXXXXX`
    FIG_DVIPS_RAW=`${MKTEMP} ${TMPD}/${FIGNAME}-dvi2ps-raw.ps.XXXXXX`
    dvips -f -q ${FIGNAME}.dvi > ${FIG_DVIPS}
    ps2psFilter ${FIG_DVIPS} ${FIG_DVIPS_RAW}
    echo "Converting ps -> pdf (ps2pdf)"
    ps2pdf ${FIG_DVIPS} ${FIGNAME}.pdf
    cleanfiles ${FIG_DVIPS} {FIG_DVIPS_RAW};
}



# This version relies on dvips + PS2EPS + eps2pdf.
# It often works
dvi2pdfV1() {
    echo "Method 1: Trying conversion with dvips -|-> "${PS2EPS_CMDNAME}" -|-> epstopdf"
    dvi2pdfV1_noPrompt;
}

dvi2pdfV1_noPrompt() {
    FIG_DVIPS=`${MKTEMP} ${TMPD}/${FIGNAME}-dvi2ps.ps.XXXXXX`
    FIG_DVIPS_RAW=`${MKTEMP} ${TMPD}/${FIGNAME}-dvi2ps-raw.ps.XXXXXX`
    FIG_DVIPS_EPS=`${MKTEMP} ${TMPD}/${FIGNAME}-dvi2ps-ps2eps.eps.XXXXXX`
    FIG_DVIPS_EPS_RAW=`${MKTEMP} ${TMPD}/${FIGNAME}-dvi2ps-ps2eps-raw.eps.XXXXXX`
    echo "Converting dvi -> ps (dvips)"
    dvips -f -q ${FIGNAME}.dvi | egrep -v "^%%BoundingBox:"  > ${FIG_DVIPS};
    ps2psFilter ${FIG_DVIPS} ${FIG_DVIPS_RAW}
    echo "Converting ps -> eps ("${PS2EPS_CMDNAME}")"
    ${PS2EPS} ${FIG_DVIPS} ${FIG_DVIPS_EPS}
    eps2epsFilter ${FIG_DVIPS_EPS} ${FIG_DVIPS_EPS_RAW}
    echo "Converting eps -> pdf (epstopdf)"
    epstopdf ${FIG_DVIPS_EPS} --outfile=${FIGNAME}.pdf
    cleanfiles $FIG_DVIPS $FIG_DVIPS_RAW $FIG_DVIPS_EPS $FIG_DVIPS_EPS_RAW;
}

# This  version relies on dvips + PS2EPS + eps2eps + eps2pdf.
dvi2pdfV2() {
    echo "Method 2: Trying conversion with dvips -|-> " ${PS2EPS_CMDNAME}  "-|-> eps2eps -|-> epstopdf"
    if [ $EPS2EPS_OPT = "yes" ]
    then
	dvi2pdfV1_noPrompt;
    else
	EPS2EPS_OPT="yes";
	dvi2pdfV1_noPrompt;
	EPS2EPS_OPT="no";
    fi
}


# This  version relies on dvips -E + eps2eps + eps2pdf.  
dvi2pdfV3(){
    echo "Trying conversion with dvips -E -|-> eps2eps -|-> eps2pdf"
    FIG_DVIEPS=`${MKTEMP} ${TMPD}/${FIGNAME}-dvi2eps.eps.XXXXXX`
    FIG_DVIEPS_RAW=`${MKTEMP} ${TMPD}/${FIGNAME}-dvi2eps-raw.eps.XXXXXX`
    FIG_DVIEPS_EPS=`${MKTEMP} ${TMPD}/${FIGNAME}-dvi2eps-eps2eps.eps.XXXXXX`
    echo "Converting dvi -> eps (dvips -E)" 
    dvips -f -q -E ${FIGNAME}.dvi > ${FIG_DVIEPS}
    echo "Tightening the bounding box (eps2eps)"
    mv ${FIG_DVIEPS} ${FIG_DVIEPS_RAW}
    eps2eps ${FIG_DVIEPS_RAW} ${FIG_DVIEPS_EPS}
    echo "Converting eps -> pdf (epstopdf)"
    epstopdf ${FIG_DVIEPS_EPS} --outfile=${FIGNAME}.pdf
    cleanfiles $FIG_DVIEPS $FIG_DVIEPS_RAW $FIG_DVIEPS_EPS;
}


# Compiling one figure
# Input: File  ${MAIN}.header
#        File  ${MAIN}.figure
#        ${FIGNAME}.tex
#        ${METHOD}
compileOneFigure() {
    echo "Using LaTeX: producting dvi"
    cat ${MAIN}.header > ${FIGNAME}.tex 
    echo ":pagestyle{empty}:renewcommand{:caption}[1]{}" | \
	    sed 's/:/\\/g' >>  ${FIGNAME}.tex
    # There could be several pdfrackincludegraphics in the same figure
    # environment... Then, the script should there just keep one.
    #set -x
    # Simple expression:
    # grep -n "^.*\\pdfrackincludegraphics.*{${FIGNAME}}" ${MAIN}.figure 
    # More precise expression
    KEEPED_LINE=`grep -n "^.*\\pdfrackincludegraphics\(\[[^]]*\]\)*{${FIGNAME}}" ${MAIN}.figure | cut -f1 -d:`
    sed  ${KEEPED_LINE}!s/pdfrackincludegraphics/pdfracknullcommand/ ${MAIN}.figure \
    >> ${FIGNAME}.tex
    echo ':end{document}' | sed 's/:/\\/g' >> ${FIGNAME}.tex   
    if [ ! -r ${FIGNAME}.tex ] ; then
	echo "Fail: no readable file "${FIGNAME}.tex   
	return
    fi
    latex -interaction=batchmode ${FIGNAME}.tex
# The main pb is: how to convert from dvi to pdf, with the right size ?
#    The option "-E" of dvips "only works [...] at marks made by
#  characters and rules, not by any included graphics".
#    So I have tried some versions, and the 2d seems to be the more
#  efficient, but, sometimes, another is better...
    if [ -r  ${FIGNAME}.dvi ]
    then
	case ${METHOD} in
	    0)  echo "Warning: Method 0 should produce bad size";
		dvi2pdfV0;;
	    1)  dvi2pdfV1;;
	    2)  dvi2pdfV2;;
	    3)  dvi2pdfV3;;
	    *)  echo "Unknown method "${METHOD};
		cleantexfiles;;
	esac
    else
	echo "Fail: no readable file "${FIGNAME}.dvi
    fi
}



######################################################################
##  Main 


# Check paremetes and set options

set - - `getopt ahm:H:M:peki $*`
if  [ $? != 0 ];
then
    usage;
    exit;
fi
#echo "Options are:"$*
for i in $*
do
    case $i in
    -m) METHOD=$3; shift 2;;
    -p) PS2PS_OPT="yes"; shift 1;;
    -e) EPS2EPS_OPT="yes"; shift 1;;
    -a) AUTO="yes"; shift 1;;
    -k) CLEAN_OPT=no; shift 1;;
    -i) FORCE_EPSI_OPT="yes"; shift 1;;
    -H) OWN_HEADER_OPT=$3; shift 2;;
    -M) MASTER_FILE_OPT=$3; shift 2;;
    -h)
	usage; 
	exit;;
    --) shift
	break;;
    esac
 # echo "Remaining options are:"$*
 done
 shift 1;    # To drop the  -- added by command set - - `getopt cho: $*`

#echo "After all Remaining options are:"$*


if [ $# -lt 1 ]
then
    echo "Error: No input parameter file";
    usage;
    exit;
fi
#echo "toto"
if [ ! -f $1 -o ! -r $1 ] ; then
    echo "Error: File $1 unreadable"
    exit 1
fi

if [ $FORCE_EPSI_OPT = no ] ;
then    
    detect_ps2eps_filter;
fi

if [ x$MASTER_FILE_OPT != "x" -a x$OWN_HEADER_OPT != "x" ]; then
    echo "Error: options -M and -H are incompatible"
    exit 1
fi
if [ x$MASTER_FILE_OPT != "x" ] ; then
  if [ ! -f $MASTER_FILE_OPT -o ! -r $MASTER_FILE_OPT ]; then
    echo "Error: file $MASTER_FILE_OPT unreadable"
    exit 1
  fi
fi
if [ x$OWN_HEADER_OPT != "x" ]; then
  if [ ! -f $OWN_HEADER_OPT -o ! -r $OWN_HEADER_OPT ]; then
    echo "Error: file $OWN_HEADER_OPT unreadable"
    exit 1
  fi
fi


MAIN=`basename $1 "\..*"`

# Check for Dos files
if [ `wc -l < $1` -eq 1 ] ; then
cat <<EOF
 Suspicious file: your file is only one line long !"
 If your file comes from Dos/Windows world, you should"
 try command
   tr "\r" "\n" < MAIN > unix-MAIN
 and then run the script on unix-MAIN
EOF
 echo " (with MAIN="$MAIN")"
 exit 1
fi

# Check for bash noclober option
if [ `basename $SHELL` = bash ] ; then
   set +o noclobber
fi

detect_mktemp;

if [ x$OWN_HEADER_OPT != "x" ]; then
 cat $OWN_HEADER_OPT > ${MAIN}.header
else if [ x$MASTER_FILE_OPT != "x" ]; then
 # Extract the header of the file, is, all from first line to 
 # the "\]begin{document}"
 HEADERSIZE=`grep -n "^[\]begin{document}" ${MASTER_FILE_OPT} | head -1 | cut -f1 -d:`
 if [ x${HEADERSIZE} = "x" ]; then
   echo "Error: no \\\\begin{document} found in file "${MASTER_FILE_OPT}
   exit 1
 fi
 head -${HEADERSIZE}  ${MASTER_FILE_OPT} > ${MAIN}.header
else
 HEADERSIZE=`grep -n "^[\]begin{document}" $1 | head -1 | cut -f1 -d:`
 if [ x${HEADERSIZE} = "x" ]; then
   echo "Error: no \\\\begin{document} found in file "$1
   exit 1
 fi
 head -${HEADERSIZE}  $1 > ${MAIN}.header
fi
fi

# Create a file with the line number of the figures
{ grep -n "^[ ]*[\]begin{figure}" $1 ; \
  grep -n "^[ ]*[\]end{figure}" $1; } | cut -f1 -d: \
  | sort -n  > ${MAIN}.figlines

# Proceedes the files
cat ${MAIN}.figlines | while read BEGIN 
do {
    read END
    # Creates a file
    DIFF=`expr ${END} - ${BEGIN} + 1`
    head -${END} $1 | tail -${DIFF} | sed 's/^%.*$//' | \
    sed 's/\([^\]\)%.*$/\1/'>  ${MAIN}.figure
    # Debug: grep "\pdfrackincludegraphics\[.*\]{.*}" ${MAIN}.figure 
    # Comment on the regular expression used
    #   The (extended) regular expr for egrep has 4 parts:
    #    - ^[^%] : excludes any '%' in the beginning of the line (to
    #              avoid to match a pdfrackincludegraphics in comments
    #    - \pdfrackincludegraphics  : just matches the macro name
    #    - (\[[^]]*\])? : the optionnal options
    #                     the (...)? means that this subpart is repeated 0 or 1 time (need egrep)
    #                     the \[...\]  are juste the delimiters of LaTeX option
    #                     the [^]]*  matches any sequence without any ']'
    #    - {[^}]*} :   the name of the figure
    #  The regular expersions used by sed is quite the same, except that,
    #    - because de (...)? is not allowed, two expressions are used
    #    - there are pair of \( \) is used to capture the name of the figure
    #    - there is a .*$ used to capture the end of the line
    if [ $AUTO = "no" ]; then
    egrep "^[^%]*\pdfrackincludegraphics(\[[^]]*\])?{[^}]*}" ${MAIN}.figure | \
	sed -e 's/^[^%]*\\pdfrackincludegraphics\[.*\]{\([^}]*\)}.*$/\1/' \
	    -e 's/^[^%]*\\pdfrackincludegraphics{\([^}]*\)}.*$/\1/'  \
        > ${MAIN}.fignames
    else
    egrep "^[^%]*\includegraphics(\[[^]]*\])?{[^}]*}" ${MAIN}.figure | \
	sed -e 's/^[^%]*\\includegraphics\[.*\]{\([^}]*\)}.*$/\1/' \
	    -e 's/^[^%]*\\includegraphics{\([^}]*\)}.*$/\1/'  \
        > ${MAIN}.fignames
    fi
    for FIGNAME in `cat ${MAIN}.fignames`
    do
       echo "----------------------------------------------"
       echo "  ---> Converting figure $FIGNAME"
       compileOneFigure;
    done
} done 

\rm  ${MAIN}.figlines  ${MAIN}.header ${MAIN}.figure ${MAIN}.fignames
