#! /usr/bin/perl
$TMPDIR="/tmp";
$CONTEXT_DIFF="diff -C 1";
#
# The perl script requires bindings for the following
# variables to be prepended:
#     TMPDIR
#     CONTEXTDIFF
#

$Pgm = $0; $Pgm =~ s/.*\/([^\/]+)$/\1/;
#
# set up signal handler
sub quit_upon_signal { &rm_temp_files_and_exit(); }
$SIG{'INT'}  = 'quit_upon_signal';
$SIG{'QUIT'} = 'quit_upon_signal';
#
$Verbose = 0;
if ($ARGV[0] eq '-v') {
    $Verbose = 1;
    shift(@ARGV);
}
#
die "$Pgm: must have exactly one argument\n" if $#ARGV != 0;
# figure out input file and its filename root
if (-f $ARGV[0]) {
    $TeX_input = $ARGV[0];
    if ($TeX_input =~ /(.+)\.[^\.\/\n]+$/) {
	$TeX_root  = $1;
    } else {
	$TeX_root  = $TeX_input;
    }
} elsif (-f $ARGV[0].'.tex') {
    $TeX_input = $ARGV[0].'.tex';
    $TeX_root  = $ARGV[0];
} else {
    die "$Pgm: input file $ARGV[0] doesn't exist\n";
}

if ( $ENV{'TMPDIR'} ) { # where to make tmp file names
    $Tmp_prefix = $ENV{'TMPDIR'} ;
} else {
    $Tmp_prefix ="$TMPDIR";
    $ENV{'TMPDIR'} = "$TMPDIR"; # set the env var as well
}

sub rm_temp_files {
    system("rm -f $Tmp_prefix/ltx-*.$$");
}
sub rm_temp_files_and_exit {
    system("rm -f $Tmp_prefix/ltx-*.$$");
    exit(1);
}
$SIG{'INT'}  = 'rm_temp_files_and_exit';
$SIG{'QUIT'} = 'rm_temp_files_and_exit';

sub die_gracefully {
    local($msg) = @_;
    
    print STDERR $msg;
    &rm_temp_files_and_exit();
}

# must read through root file to see if a \bibliography
# is there...
$Bibliography_requested = 0;
open(TEXIF, "<$TeX_input") 
    || &die_gracefully("$Pgm: Can't read $TeX_input\n");
while (<TEXIF>) {
    $Bibliography_requested = 1 if /^\\bibliography/;
}
close(TEXIF);
&die_gracefully("$Pgm: reading $TeX_input had errors\n") if $? >> 8;

# run latex first time (?)
&run_latex(); # sets $Says_labels_changed
$Times_run = 1;

while (&something_more_needed()) {

    print STDERR "labels_changed=$Says_label_changed;bibtex_needed=$BibTeX_run_needed;makeindex_needed=$MakeIndex_run_needed\n" if $Verbose;

    if ($BibTeX_run_needed) {
	&run_bibtex();
    }
    if ($MakeIndex_run_needed) {
	unlink "$TeX_root.ind";
	(system("makeindex $TeX_root.idx") >> 8) 
	    && &die_gracefully("$Pgm: makeindex $TeX_root.idx had errors\n");
    }

    # save (copy) .aux file as .aux-prev file for future ref
    # ditto for .idx file
    unlink "$TeX_root.aux-prev";
    (system("cp $TeX_root.aux $TeX_root.aux-prev") >> 8)
	&& &die_gracefully("$Pgm: cp $TeX_root.aux $TeX_root.aux-prev failed\n");
    if (-f "$TeX_root.idx") {
	unlink "$TeX_root.idx-prev";
	(system("cp $TeX_root.idx $TeX_root.idx-prev") >> 8)
	    && &die_gracefully("$Pgm: cp $TeX_root.idx $TeX_root.idx-prev failed\n");
    }

    # run latex again
    &run_latex(); # sets $Says_labels_changed
    $Times_run++;

    if ($Times_run >= 4) {
	print STDERR "*** I don't run LaTeX more than four times;\n";
	print STDERR "*** Something is probably wrong...\n";
	&rm_temp_files_and_exit();
    }
}
&rm_temp_files();
exit(0);

sub run_latex {
    $Says_labels_changed = 0;
    $Multiply_defined_labels = 0;

    select(STDERR); $| = 1; select(STDOUT); # no buffering on STDERR
    print STDERR "$Pgm: *** running LaTeX...\n" if $Verbose;
    unlink "$TeX_root.dvi";

    open(LTXPIPE, "latex $TeX_input 2>&1 |") 
    	|| &die_gracefully("$Pgm: Can't run latex pipe\n");
    while (<LTXPIPE>) {
	$Multiply_defined_labels = 1 if /^LaTeX Warning: Label .* multiply defined/;
	$Says_labels_changed = 1 if /^LaTeX Warning: Label\(s\) may have changed/
					&& ! $Multiply_defined_labels;
	print STDERR $_;
    }
    close(LTXPIPE);
    &die_gracefully("$Pgm: LaTeX run had errors\n") if $? >> 8;

    # sort .idx file, because this helps makeindex
    # (can you say `bug'?)
    if (-f "$TeX_root.idx") {
	print STDERR "$Pgm: *** sorting $TeX_root.idx...\n" if $Verbose;
	(system("sort $TeX_root.idx -o $TeX_root.idx") >> 8)
	&& &die_gracefully("$Pgm: sorting $TeX_root.idx failed\n");
    }

}

sub run_bibtex { # ugly because bibtex doesn't return a correct error status
    local($bibtex_had_errors) = 0;

    print STDERR "$Pgm: *** running BibTeX...\n" if $Verbose;
    unlink "$TeX_root.bbl";

    $| = 1; # no buffering
    open(BIBTXPIPE, "bibtex $TeX_root 2>&1 |") 
    	|| &die_gracefully("$Pgm: Can't run bibtex pipe\n");
    while (<BIBTXPIPE>) {
	$bibtex_had_errors = 1 if /^\(There.*error message(s)?\)$/;
	print STDERR $_;
    }
    close(BIBTXPIPE);
    &die_gracefully("$Pgm: BibTeX run had errors\n")
    	if $? >> 8 || $bibtex_had_errors;
}

sub something_more_needed {
    # returns 1 or 0 if we need to run LaTeX
    # possibly preceded by bibtex and/or makeindex run

    # $Says_labels_changed was set by previous &run_latex...
    $BibTeX_run_needed    = 0;
    $MakeIndex_run_needed = 0;

    if ( ! -f ($TeX_root . '.aux-prev')) { # this was the first run

	print STDERR "$Pgm: *** 'twas first run of LaTeX on $TeX_input\n" if $Verbose;

	# we need makeindex to run if a non-zero-sized .idx file exists
	#
	$MakeIndex_run_needed = 1
	    if -f "$TeX_root.idx" && -s "$TeX_root.idx";

	# we need bibtex to run if there are \citations in the .aux file
	#
        &slurp_aux_file('aux');
	$BibTeX_run_needed = 1
	    if $Bibliography_requested &&
	      -f "$Tmp_prefix/ltx-aux-cite.$$" &&
	      -s "$Tmp_prefix/ltx-aux-cite.$$";


    } else { # ltx had been run before (.aux-prev/.idx-prev files exist)

	# slurp both .aux and .aux-prev files
        &slurp_aux_file('aux');
        &slurp_aux_file('aux-prev');

	local($tmp_pre) = "$Tmp_prefix/ltx";

	if ((-s "$tmp_pre-.aux-cite.$$") # there are still \cite's in there
	 && (system("cmp -s $tmp_pre-.aux-cite.$$ $tmp_pre-.aux-prev-cite.$$") >> 8)) {
	    $BibTeX_run_needed = 1 if $Bibliography_requested;
	    if ($Verbose) {
		system("$CONTEXT_DIFF $tmp_pre-.aux-prev-cite.$$ $tmp_pre-.aux-cite.$$");
	    }
	}

	if (-f "$TeX_root.idx") {
	    $MakeIndex_run_needed =
		(system("cmp -s $TeX_root.idx $TeX_root.idx-prev") >> 8) ? 1 : 0;
	    if ($MakeIndex_run_needed && $Verbose) {
		system("$CONTEXT_DIFF $TeX_root.idx-prev $TeX_root.idx");
	    }
	}
    }

    $Says_labels_changed || $BibTeX_run_needed || $MakeIndex_run_needed;
}

sub slurp_aux_file {
    local($ext) = @_;

    # copy all citations from slurpfile into $Tmp_prefix/ltx-$ext-cite.$$

    open(SLURPF,"< $TeX_root.$ext")
	|| &die_gracefully("$Pgm: Can't open $TeX_root.$ext for reading\n");
    open(CITEF,"> $Tmp_prefix/ltx-$ext-cite.$$")
	|| &die_gracefully("$Pgm: Can't open $Tmp_prefix/ltx-$ext-cite.$$ for writing\n");

    while (<SLURPF>) {
	print CITEF $_  if /\\citation/;
    }
    close(CITEF);
    close(SLURPF);
}
