#!/usr/bin/perl -w
# prv - compile, preview, and print LaTeX document
$version_num = '0.7'; # version history at the end

=head1 NAME

        prv - compile, preview, and print LaTeX document

=head1 SYNOPSIS

Options are shown in logically identical pairs, with the full version 
in the second column and the minimum shorthand (without any parameters)
in the first:

        prv [-b]     [-batch <selection>]           
            [-cl]    [-clean]                       
            [-co]    [-continue]                    
            [-dr]    [-draft]                       
            [-dv]    [-dvi_filter <filter>]         
            [-f]     [-full_clean]                  
            [-g]     [-go]                          
            [-h]     [-help]                        
            [-ig]    [-ignore_missing_includes]     
            [-in]    [-intensity_draft <intensity>] 
            [-l]     [-landscape]                   
            [-m]     [-message_draft <message>]     
            [-pr]    [-printout]                    
            [-ps]    [-ps]                          
            [-ps_]   [-ps_filter <filter>]          
            [-pv]    [-pv]                          
            [-pvc]   [-pvc]                         
            [-q]     [-quiet]                       
            [-r]     [-rcfile <rcfile]              
            [-scal]  [-scale_draft <scale>]         
            [-scan]  [-scan]                        
            [-scan_] [-scan_force]                  
            [file ...]

Boolean options can be negated by a no-prefix. So -noquiet makes a 
previous -quiet undone. Useful in combination with rcfiles.

=cut

# more pod at the end

use Getopt::Long;
use Carp;
use Cwd;
use Env;
use File::Basename;
use Config;
use Term::ReadKey qw(ReadLine);

# following initialized because of -w noise
use vars qw ( $quiet $help $version
              $message_draft $scan_force $scan $go
              $name
            );
$msdos = $Config{'osname'} =~ /ms/i;
$texfile_search=$clean_ext=$full_clean_ext="";
@cus_dep_list=();
$comline=join(' ',@ARGV);

if ($msdos) {
  $TEMP= "\\tmp\\";
  $tonull                       = "> ${TEMP}tonull";
  $fromnull                     = "< ${TEMP}fromnull";
  system("echo > ${TEMP}fromnull");
  $systemrcfile                 = "\\lib\\prv\\prv";
  $userrcfile                   = "$HOME\\prv.rc";
  $rc_file                      = "prv.rc";
  $copy                         = "copy";
  $lpr                          = 'print';
  $ps_previewer                 = 'gv';
  $ps_previewer_landscape       = 'gv';
  $dvi_previewer                = 'windvi';
  $dvi_previewer_landscape      = 'windvi';
  $dvi_cont_previewer           = 'dviwin2 -1 -c';
  $dvi_cont_previewer_landscape = 'dviwin2 -1 -c';
} else {
  $TEMP= "/tmp/";
  $tonull                       = "> /dev/null";
  $fromnull                     = "< /dev/null";
  $systemrcfile                 = '/etc/prvrc';
  $userrcfile                   = "$HOME/.prvrc";
  $rc_file                      = ".prvrc";
  $copy                         = "cp -p"; 
  $lpr                          = 'lpr';
  $ps_previewer                 = 'gv';
  $ps_previewer_landscape       = 'gv -swap';
  $dvi_previewer                = 'xdvi';
  $dvi_previewer_landscape      = 'xdvi -paper a4r';
  $dvi_cont_previewer           = 'xdvi';
  $dvi_cont_previewer_landscape = 'xdvi -paper a4r';
}
-d $TEMP or die "Missing directory $TEMP\n";
-w $TEMP or die "Unwritable directory $TEMP\n";

## default document processing programs.
$latex          = 'latex';
$bibtex         = 'bibtex -terse';
$makeindex      = 'makeindex';
$dvips          = 'dvips -s';
$dvips_landscape= 'dvips -tlandscape';
$pscmd          = 'ps x';  # This works for SunOs.  Solaris should just be 'ps'
$touch          = 'touch';
$psselect       = 'psselect';
$pstops         = 'pstops';
$diff           = 'diff';
$dvi_filter = "";
$ps_filter  = "";
$leader=$trailer= "";

# default flag settings.
$bibtex_mode = 0;  # is there a bibliography needing bibtexing?
$index_mode = 0;   # is there an index needing makeindex run?
$sleep_time = 2;   # time to sleep b/w checks for file changes in -pvc mode

# Read rc files.
for ($systemrcfile,$userrcfile,$rc_file) {
  -e $_ and do $_;
}

print_help() unless @ARGV;

# Process command line args.
$batch='';
GetOptions(
  "die"                 => \$die,
  "intensity_draft=f"	=> \$intensity_draft,
  "message_draft=s"	=> \$message_draft,
  "scale_draft=i"	=> \$scale_draft,
  "batch=s"		=> \$batch,
  "clean!"		=> \$clean,
  "full_clean!"		=> \$full_clean,
  "draft!"		=> \$draft,
  "dvi_filter=s"	=> \$dvi_filter,
  "continue!"		=> \$continue,
  "ignore_missing_includes!"	=> \$ignore_missing_includes,
  "go!"			=> \$go,
  "help"		=> \$help,
  "scan!"		=> \$scan,
  "scan_force!"		=> \$scan_force,
  "landscape!"		=> \$landscape,
  "printout!"		=> \$printout,
  "ps!"			=> \$ps,
  "ps_filter=s"		=> \$ps_filter,
  "pv!"			=> \$pv,
  "pvc!"		=> \$pvc,
  "quiet!"		=> \$quiet,
  "rcfile=s"		=> \$rcfile,
  "version"		=> \$version,
) or print_help("Option problem in `".$comline."'");

# $batch must contain valid printing commands:
if ($batch) {
  for (split(/\s+/,$batch)) {
    CASE: {
      /^q$/        and last CASE; # drop on n of q
      /^x[0-9]+$/  and last CASE; # x3 -> lpr -#3
      /^b$/        and last CASE; # print a5 booklet
      /^t$/        and last CASE; # print twosided
      /^a$/        and last CASE; # print all
      /^(([0-9]+-?[0-9]*|[0-9]*-?[0-9]+),?)+$/    # n-m or n- or -m
        and last CASE;
      die "Illegal argument for -batch option: $batch\nUse q if you want no printout\n";
    }
  }
}

$version                   and warn "\nprv $version_num\n";
$help                      and print_help("");
$pvc                       and $quiet=1;
$draft=1                   if $message_draft;
$scale_draft = 220         unless $scale_draft;
$intensity_draft = 0.95    unless $intensity_draft;
$message_draft = 'DRAFT'   unless $message_draft;
do $rcfile                 if $rcfile;
$clean=1                   if $full_clean;
$pv=0                      if $batch or $pvc;
($intensity_draft <0 || $intensity_draft > 1) and
    die "Banner intensity must be 0 - 1\n";
($scale_draft <10 || $scale_draft > 10000) and
    die "Banner scale must be 10 - 10000\n";

# If no files specified, try and find some
@ARGV=glob($texfile_search) unless @ARGV;

# If still no files, exit.
print_help("prv: No filename specified\n") if (!@ARGV);

# If landscape mode, change modes
if ( $landscape ) {
  $dvips = $dvips_landscape;
  $dvi_previewer = $dvi_previewer_landscape;
  $dvi_cont_previewer = $dvi_cont_previewer_landscape;
  $ps_previewer = $ps_previewer_landscape;
}

if ($quiet) {
  $dvips.=" -q";
  $dvips_landscape.=" -q";
}

=pod

This is how it works: 

=head2 do some initializations.

=head2 read the rc-files for customization:

	/etc/prvrc, $HOME/.prvrc, and ./.prvrc, in that order under Unix, or
        \\lib\\prv\\prv", $HOME\\prv.rc", and prv.rc" under MD-DOS

These files may contain Perl-statements that set some variables
	
=head2 handle the command line options and get the filename(s) to be compiled

prv looks for filenames on the command line and, if there are none, in the 
variable $texfile_search that may have been set in an rc-file.

=head2 save current working directory

=head2 for each source to be compiled:

return to the starting directory, get the source's path and
chdir to the source's directory.
If the file is'nt found there, 

=cut


# save current working directory, we'll want to get back here:
$startdir=cwd;

RESTART:
# Process for each file.
for $filename ( @ARGV ) {
  chdir $startdir; # look from here, for relative paths

  # add a .tex extension if it lacks.
  # if a path is given, move to it
  ($root_filename,$path,$ext)=fileparse($filename,'\.tex');
  $tex_filename="$root_filename.tex";
  $linenum=1; # editing sessions start at this line
  @filestack=($tex_filename); # file to be edited
  chdir $path;
  if ( (! -f $tex_filename) &&	# if the file is not found here
       ($path eq "./") &&      	# and no path was specified
       ($leader || $trailer)) { # then try adding leader and trailers
                                # to the original name:
    $filename=$leader.$filename.$trailer;
    redo;
  }
  -f $tex_filename or die "No file $path$tex_filename found\n";
  
  if ($clean) {
    warn "Cleaning for $root_filename\n" unless $quiet;
    # Do clean if necessary
    cleanup();
    cleanup_full() if ($full_clean);
  } else {
    # Make file
    # Find includes
    $includes = '';
    $read_depend = 0;  # True to read depend file, false to generate it.
    $depfile = "$root_filename.dep";

    # Figure out if we read the dependency file or generate a new one.
    if ( ! $scan_force ) {
      if ( $scan ) {
        if ( -e $depfile ) {
          # Compare timestamp of dependency file and root tex file.
          $dep_mtime = &get_mtime("$depfile");
          $tex_mtime = &get_mtime("$tex_filename");
          $read_depend = 1 if ( $tex_mtime < $dep_mtime );
        }
      } elsif ( -e $depfile ) {  # If dependency file already exists.
        $read_depend = 1;
      }
    }

    if ( $read_depend ) {
      # Read the dependency file
      open(DEPFILE,$depfile) ||
        die "prv: Couldn't open dependency file [$root_filename.dep]\n";
      while(<DEPFILE>) { eval; }
      close(DEPFILE);
    } else {
      # Generate dependency file.
      # get search paths for includes.
      if (!$TEXINPUTS) { $TEXINPUTS = '.'; }
      if (!$BIBINPUTS) { $BIBINPUTS = $TEXINPUTS; }

      &scan_for_includes("$tex_filename");
      &update_depend_file;
    }

    ## put root tex file into list of includes.
    $includes .= " $tex_filename";

    ## before munging, save existing .aux file.
    ## - if latex bombs, kill .aux, restore this backup to get back most
    ## useful bib/ref info.
    sys("$copy $root_filename.aux $root_filename.auk $tonull")
      if -f "$root_filename.aux";

    #************************************************************

    &make_dependents("$includes");
    &make_latex_dvi;
    &make_dvi_filtered;
    &make_preview_continuous;
    &make_postscript;
    &make_preview;
    &make_printout;
  }
}

#************************************************************
#### Subroutines
#************************************************************

sub make_latex_dvi {
  $changed_dvi = 0 ;            # flag if anything changed.
  ## get initial last modified times.
  $tex_mtime = &get_latest_mtime($includes);
  $aux_mtime = &get_mtime("$root_filename.aux");
  $bbl_mtime = &get_mtime("$root_filename.bbl");
  $ilg_mtime = &get_mtime("$root_filename.ilg");
  $ind_mtime = &get_mtime("$root_filename.ind");

  ## - if no dvi file, or .aux older than tex file or bib file, run latex.
  if ( $go || !(-e "$root_filename.dvi")
    || ($aux_mtime < $tex_mtime)
    || ($aux_mtime < $bbl_mtime)
    || ($aux_mtime < $ilg_mtime)
    || ($aux_mtime < $ind_mtime)
    || !(-e "$root_filename.aux")) {
    message("Running first $latex [$tex_filename]");
    &backup_toc;
    unlink "$root_filename.dvi"; # just in case latex produces no output...
    $return = run_latex();
    unless (-f "$root_filename.dvi") {
      warn "Latex produced no output!\n" unless $return;
      $return=1;
    }
    die "Giving up...\n" if $return && $die;
    $changed_dvi = 1;

    if (!$continue && $return) {
      message("$latex found an error in\n$startdir/$root_filename.tex");
      unlink "$startdir/$root_filename.dvi";
      edit(1);
    }

    if  ($index_mode) {
      message("Running $makeindex [$root_filename]");
      $return = sys("$makeindex $root_filename");

      if (!$continue && $return) {
        &exit_msg('Makeindex found an error');
      }
      $ilg_mtime = &get_mtime("$root_filename.ilg");
      $ind_mtime = &get_mtime("$root_filename.ind");
    }
  }

  $bib_mtime = &get_latest_mtime($bib_files);
  ## if no .bbl or .bib changed since last bibtex run, run bibtex.
  if ($bibtex_mode && (&check_for_bad_citation || !(-e "$root_filename.bbl")
     || ($bbl_mtime < $bib_mtime))) {
    message("Running $bibtex [$root_filename]");
    $return = sys("$bibtex $root_filename");
    $bbl_mtime = &get_mtime("$root_filename.bbl");
  }

  if ($bibtex_mode && &check_for_bibtex_errors) {
    if (!$continue) {
      # touch a .bib file so that will rerun bibtex to fix errors.
      @split_bib_files = split(' ',$bib_files);
      sys("$touch $split_bib_files[0]");
      &exit_msg('Bibtex reported an error',0);
    }
  }

  ## now, if need to, rerun latex up to twice to generate valid .dvi
  ## w/ citations resolved.

  $dvi_mtime = &get_mtime("$root_filename.dvi");
  if ( ($dvi_mtime <= $bbl_mtime) || &check_for_reference_change
     || ($dvi_mtime <= $ilg_mtime)
     || ($dvi_mtime <= $ind_mtime)
     || (&check_toc)) {
    message("Running second $latex [$tex_filename]");
    &backup_toc;
    $return = run_latex();
    $changed_dvi = 1;
  }

  if (!$continue && $return) {
    &exit_msg('$latex found an error',1);
  }

  if (&check_for_reference_change || &check_toc) {
    message("Running third $latex [$tex_filename]");
    &backup_toc;
    $return = run_latex();
    $changed_dvi = 1;
  }

  if (!$continue && &check_for_bad_reference) {
    &exit_msg('$latex could not resolve all references');
  }

  if (!$continue && &check_for_bad_citation) {
    &exit_msg('$latex could not resolve all citations or labels');
  } 
  return(1);
}

#************************************************************

sub make_dvi_filtered {
  return if ( length($dvi_filter) == 0 );
  message("Running $dvi_filter [$root_filename]");
  sys("$dvi_filter < $root_filename.dvi > $root_filename.dvf");
}

#************************************************************

sub make_dependents {
  local($file,$dep,$base_name,$ch,$toext,$fromext,
        $proptoext,$must,$func_name,$return);

  for $file (split(' ',$_[0])) { $ch = '';
    $toext = '';
    $base_name = $file;
    while (( $ch ne '.' ) && ( $ch ne '/' ) && ( $base_name ne '' )) {
      $toext = $ch . $toext;
      $ch = chop $base_name;
    }
    if (( $ch eq '.' ) && ( $base_name ne '' )) {
      #Extracted proper extension.
      for $dep ( @cus_dep_list ) { 
        ($fromext,$proptoext,$must,$func_name) = split(' ',$dep);
        if ( $toext eq $proptoext ) {
          # Found match
          if ( -e "$base_name.$fromext" ) {
            # From file exists, now check if it is newer
            if (( ! (-e "$base_name.$toext" ))
                || ( &get_mtime("$base_name.$toext")
                < &get_mtime("$base_name.$fromext") )) {
              message("Running $func_name [$base_name]");
              $return = &$func_name($base_name);
              if ( !$continue && $return ) {
                &exit_msg("$func_name found an error");
              }
            }
          } else {
            if ( !$continue && ( $must != 0 )) {
              &exit_msg("File '$base_name.$fromext' does not exist".
                        "to build '$base_name.$toext'\n");
            }
          }
        }
      }
    }
  }
}

#************************************************************

sub make_printout {
  $printout or return;
  $batch=~/^q$/ and return;
  
  local ($ext);
  $ext = $ps_filter ? '.psF' : '.ps';
  my $tmp = "${TEMP}$$";
  my $sel="${tmp}sel";
  my $print_prompt="printer ready? then turn pack and type return ";
  my $front_spec='"4:-3L@.707(210mm,0)+0L@.707(210mm,148.5mm)"';
  my $back_spec='"4:1L@.707(210mm,0)+-2L@.707(210mm,148.5mm)"';

  while (1) {
    my ($selection,$booklet,$twosided,$lpropt)=ask_selection($batch);
    defined($selection) or return;
    if ($selection) {   # if anything was set
      print STDERR "\n";
      make_postscript();
      $selection =~ /[1-9]/ or $selection.=" -e -o ";
      sys("$psselect -q $selection $root_filename.ps $sel");
      if ($booklet) {
          sys("$pstops -q $front_spec $sel >$tmp"); # no piping: non-Unix OS 
          sys("$lpr $lpropt $tmp");                # can get problems
          print STDERR $print_prompt; ReadLine 0;
          sys("$pstops -q $back_spec $sel >$tmp");
          sys("$lpr $lpropt $tmp");
          unlink $tmp;
      } elsif ($twosided) {
          sys("$pstops 2:0 $sel >$tmp");
          sys("$lpr $lpropt $tmp");
          print STDERR $print_prompt; ReadLine 0;
          sys("$pstops 2:1 $sel >$tmp");
          sys("$lpr $lpropt $tmp");
      } else {
          sys("$lpr $lpropt $sel");
      }
    }
    unlink $sel;
    last if $batch;
  }
}

sub ask_selection {
  my $prompt='Pages ([range[,range...]|a] [b|t] [x<n>])? ';
  my $com=shift || ask($prompt);
  chomp($com);
  my ($booklet,$twosided,$selection,$lpropt)=('','','','');
  for (split(/\s+/,$com)) {
    CASE: {
      /^q$/                    # drop on q
          and return undef;
      /^e$/                    # edit $root_filename.tex, then exit
          and edit(0);
      /^x[0-9]+$/              # x3 -> lpr -#3
          and do {
	    s/x//;
            $batch or print STDERR " $_ copies";
            $lpropt = '-#'.$_;
            $selection.=" -q";
          },
          last CASE;
      /^b$/                    # print a5 booklet
          and do {
	    $selection.=" -q ";
            $batch or print STDERR " booklet";
            $booklet=1;
          },
          last CASE;
      /^t$/                    # print twosided
          and do {
	    $selection.=" -q";
            $twosided=1;
            $batch or print STDERR " twosided";
          },
          last CASE;
      /^a$/                    # print all
          and do {
	    $selection="-e -o";
            $batch or print STDERR " all pages";
          },
          last CASE;
      /^(([0-9]+-?[0-9]*|[0-9]*-?[0-9]+),?)+$/    # n-m or n- or -m
          and do {
	    s/^-/1-/;
            ($selection=$_) =~ s/,$//;
            $batch or print STDERR " pages: $selection";
          },
          last CASE;

       warn
       "Illegal specification(s)\n".
       "Examples of page specifications:\n".
       "5       to print page 5\n".
       "5-      to print pages 5 through the end\n".
       "5-7     to print pages 5, 6 and 7\n".
       "-7      to print the first 7 pages\n".
       "5-7,19- to print pages 5, 6, 7 and 19 through the end\n".
       "a       to print the whole document\n".
       "a x3    to print 3 copies of the document\n".
       "x3      the same\n".
       "5 x3    to print 3 copies of page 5\n".
       "t       print the whole document twosided\n".
       "t 2-    print twosided starting at page 2\n".
       "b       to print the whole document as an a5 size booklet\n".
       "b -12   to print the first 12 pages as an a5 size booklet\n".
       "e       edit the tex source and rerun prv\n".
       "q       quit\n".
       "";

     }
  }
  ($selection,$booklet,$twosided,$lpropt)
}
sub ask {
  print $_[0];
  my $x=ReadLine 0;
  chomp($x);
  $x;
}

#************************************************************
sub edit {
  $EDITOR or die "EDITOR environment variable undefined\n";
  my $x;
  if ($_[0]) {
    while(($x=ask("=====> e(dit) q(uit) "))!~/^(q|e)$/) { warn "you must type e or q\n" }
    $x eq 'q' and exit;
  }
  die unless $linenum;
  system("$EDITOR +$linenum ".(pop(@filestack)));
  goto RESTART;
}

sub make_postscript {
  if ( ! $draft ) {
    return if (!$ps && !$printout);
  }
  local ($tmpfile,$header,$dvi_file);

  # Figure out the dvi file name
  if ( length($dvi_filter) == 0 ) {
    $dvi_file = "$root_filename.dvi";
  } else {
    $dvi_file = "$root_filename.dvf";
  }

  # Do banner stuff
  if ( $draft ) {
    ## Make temp banner file
    local(*OUTFILE,$count);

    $tmpfile = "${TEMP}prv.$$";
    $count = 0;
    while ( -e $tmpfile ) {
      $count = $count + 1;
      $tmpfile = "${TEMP}prv.$$.$count";
    }
    if ( ! open(OUTFILE, ">$tmpfile") ) {
      die "prv: Could not open temporary file [$tmpfile]\n"; }
    print OUTFILE "userdict begin /bop-hook{gsave 200 30 translate\n";
    print OUTFILE "65 rotate /Times-Roman findfont $scale_draft".
                  "scalefont setfont\n";
    print OUTFILE "0 0 moveto $intensity_draft setgrays".
                  "($message_draft) show grestore}def end\n";
    close(OUTFILE);
    $header = "-h $tmpfile";
  } else {
    $header = ''
  }

  $ps_mtime = &get_mtime("$root_filename.ps");
  $dvi_mtime = &get_mtime("$dvi_file");
  if (( $ps_mtime < $dvi_mtime ) || $draft ) {
    message("Running $dvips [$root_filename]");
    sys("$dvips $header $dvi_file -o $root_filename.ps");
  }
  unlink("$tmpfile") if $draft;

  ## Do we have postscript filtering?
  if ( length($ps_filter) != 0 ) {
    message("Running $ps_filter [$root_filename]");
    sys("$ps_filter < $root_filename.ps > $root_filename.psF");
  }
}

#************************************************************
# run appropriate previewer.

sub make_preview {
  return if (!$pv);
  $viewer = $dvi_previewer;
  $ext = '.dvi';
  if ($ps) {
    $viewer = $ps_previewer;
    $ext = '.ps';
    if ( length($ps_filter) != 0 ) {
      $ext = '.psF';
    }
  } else {
    if ( length($dvi_filter) != 0 ) {
      $ext = '.dvf';
    }
  }
  message("Starting previewer: $viewer $root_filename$ext");
  sys("$viewer $root_filename$ext");
}

sub backup_toc {
  if ( -e "$root_filename.toc" ) {
    sys("$copy $root_filename.toc $root_filename.tok $tonull");
  }
}

#************************************************************
# Compare the toc file with the backup.  If they differ then
# return non-zero.
sub check_toc {
  local($return);

  if ( -e "$root_filename.toc" ) {
    if ( -e "$root_filename.tok" ) {
      $return = sys("$diff $root_filename.tok $root_filename.toc $tonull");
    } else {
      $return = 1
    }
  } else {
    $return = 0;
  }
  return($return);
}

#************************************************************
# arg1 = name

sub find_process_id {
  local(@command);
  @ps_output = `$pscmd`;
  shift(@ps_output);  # Discard the header line from ps
  for (@ps_output) {
    ($pid,$tt,$tt,$tt,@command) = split(' ',$_);
    return($pid) if "@command" eq "$_[0]";
  }
  return(0);
}

#************************************************************

sub make_preview_continuous {
  return if (!$pvc);
  #
  local ($dvi_file);
  # get the value of SIGUSR1, defaults to Linux value.
  # try kill -l to figure your value out
  if (!(do 'signal.ph'))
  {
    eval 'sub SIGUSR1 {10;}';
  }
  # Figure out the dvi file name
  if ( length($dvi_filter) == 0 )
  {
    $dvi_file = "$root_filename.dvi";
  }
  else
  {
    $dvi_file = "$root_filename.dvf";
  }
  # note, we only launch a previewer if one isnt already running...
  # otherwise we'll send reopen signals to the existing previewer.
  if ($msdos) {
    warn "$dvi_cont_previewer $dvi_file\n";
    sys("$dvi_cont_previewer $dvi_file");
  } else {
    if ($previewer_pid = &find_process_id("$dvi_cont_previewer $dvi_file")) {
      message("Reattached to existing previewer, pid=$pid");
      kill &SIGUSR1,$previewer_pid;
    } else {
      if (!($previewer_pid = fork)) {
        # in forked child, close off from parent so previewer runs on
        # after parent 'prv' dies.
        setpgrp($$,0);
        message("$dvi_cont_previewer $dvi_file");
        exec("$dvi_cont_previewer $dvi_file");
      }
    }
  }
  # Loop forever, rebuilding .dvi as necessary.
  while ( 1 )
  {
    sleep($sleep_time);
    &make_latex_dvi;
    if ($changed_dvi)
    {
      kill &SIGUSR1,$previewer_pid;
    }
  }
}

#************************************************************

sub get_mtime { 
  my $m=(stat($_[0]))[9];
  $m ? $m : 0;
}

#************************************************************

sub check_for_reference_change {
  local($logfile) = "$root_filename.log";
  open(LOGFILE,$logfile) ||
    die "prv: Could not open log file to check for reference check\n";
  while(<LOGFILE>) {
    return(1) if (/Rerun/);
  }
  0;
}

#************************************************************

sub check_for_bad_reference {
  local($logfile) = "$root_filename.log";
  open(LOGFILE,$logfile) ||
    die "prv: Could not open log file to check for bad reference\n";
  while (<LOGFILE>)
  { 
    if (/LaTeX Warning: Reference[^\001]*undefined./) { return 1; }
  }
  0;
}

#************************************************************
# check for citation which latex couldnt resolve.

sub check_for_bad_citation {
  local($logfile) = "$root_filename.log";
  open(LOGFILE,$logfile) ||
    die "prv: Could not open log file to check for bad citation\n";
  while (<LOGFILE>)
  { chomp;
    warn WHITE,ON_RED,BOLD,substr($_,2),RESET,"\n" if /^--/;
    if (/LaTeX Warning: Citation[^\001]*undefined./) { return 1; }
  }
  0;
}

#************************************************************
# check for citation which bibtex didnt find.

sub check_for_bibtex_errors {
  local($logfile) = "$root_filename.blg";
  open(LOGFILE,$logfile) ||
    die "prv: Could not open bibtex log file error check\n";
  while (<LOGFILE>)
  {
#    if (/Warning--/) { return 1; }
    if (/error message/) { return 1; }
  }
  0;
}

#************************************************************
# cleanup
# - erases all generated files, exits w/ no other processing.

sub cleanup {
  unlink("$root_filename.aux");
  unlink("$root_filename.auk");
  unlink("$root_filename.bbl");
  unlink("$root_filename.blg");
  unlink("$root_filename.log");
  unlink("$root_filename.ind");
  unlink("$root_filename.idx");
  unlink("$root_filename.ilg");
  unlink("$root_filename.toc");
  unlink("$root_filename.tok");
  unlink("$root_filename.lof");
  unlink("$root_filename.lot");
  unlink("$root_filename.dep");
  unlink("texput.log");
  unlink("texput.aux");

  # .aux files are also made for \include'd files
  if ($includes) {
    for $include (split(' ',$includes)) {
      $include =~ s/\.[^\.]*$/.aux/;
      unlink($include);
    }
  }
  # Do any other file extensions specified
  for $ext (split(' ',$clean_ext))
  {
    unlink("$root_filename.$ext");
  }
}

#************************************************************
sub cleanup_full {
  unlink("$root_filename.dvi");
  unlink("$root_filename.ps");
  unlink("$root_filename.dvf");
  unlink("$root_filename.psF");
  unlink("texput.dvi");
  # Do any other file extensions specified
  for $ext (split(' ',$full_clean_ext)) {
    unlink("$root_filename.$ext");
  }
}

#************************************************************
sub print_help {
  exit(1) if $full_clean;
  while (<DATA>) { print STDERR }
  $_=$_[0] and die "\nError in prv version $version_num: $_[0]\n";
  exit(1);
}

#************************************************************
# - stats all files listed in first arg, returns most recent modify time of all.

sub get_latest_mtime { 
  return 0 unless $_[0];
  local($return_mtime) = 0;
  for $include (split(' ',$_[0])) {
    $include_mtime = &get_mtime($include);
    if ($include_mtime >  $return_mtime)
    {
      $return_mtime = $include_mtime;
    }
  }
  $return_mtime;
}

#************************************************************
# - looks recursively for included & inputted and graphics files and puts
#   them into $includes.
# - note only primitive comment removal: cannot deal with escaped %s, but then,
#       when would they occur in any line important to prv??

sub scan_for_includes {
  message("Generating Dependency File [$root_filename]");
  $bib_files=$includes=$graphicspath='';
  &scan_for_includes_($_[0]);
}

sub scan_for_includes_ {
  local(*FILE,$orgfile); # because this sub calls itself
  my %commands=('include'        =>'.tex',
                'input'          =>'.tex',
	        'includegraphics'=>'.ps',
	        'verbatimfile'   =>'.tex',
	        'verbatiminput'  =>'.tex',
		'bibliography'   =>'',
		'graphicspath'   =>'',
	       );
  if (!open(FILE,$_[0])) {
    warn "prv: could not open input file [$_[0]]\n";
    return;
  }
  while(<FILE>) {
    chomp;
    s/^%\\input/\input/; # a line beginning with %\input can be used to
                         # indicate dependency files that would not be
			 # recognised otherwise
    s/%.*//;
    /^\\documentclass.*landscape/ and do {
      warn "    Detected landscape mode\n" unless $quiet;
      $landscape = 1;
    };
    /\\makeindex/ and do {
      warn "    Detected index mode\n" unless $quiet;
      $index_mode = 1;
    };
    s/\\\\//g;                          # remove newlines
    s/\[.*?\]//g;                       # remove optional parameters
    s/([^\\])%.*/$1/;                   # remove comment
    /\\verb(.)/ and s/\\verb$1.*?$1//g; # remove \verb!...!
    next unless /\\/;			# skip if no commands
    s/.*?\\/\\/;                        # remove upto first \backslash
    for ((split(/\\/))) {
      s/{{(.*)}}/{$1}/;			# graphicspath{{p1}{p2}} -> ...path{p1}{p2}
      s/}{/:/g;				#                        -> ...path{p1,p2}
      s/(.*}).*/$1/;                    # remove all after last }
      s/\s*([{}])\s*/$1/g;              # remove space around { and }
      s/}.*//;            		# remove all after }
      $keys=join('|',(keys %commands));	# input|include|...

      next unless /^($keys)(\[.*?\])?{(.*)/;
      $orgfile=$file=$3;
      $command=$1;
      if ($command eq 'bibliography') {
	$file=~s/\.bib\b//g; # remove .bib extensions
        my $com="kpsewhich ".join(".bib ",split(/,/,$file)).".bib";
        $bib_files=join(' ',(split(/\n/,`$com`)));
        warn "    Found bibliography files [$bib_files]\n" unless $quiet;
        $bibtex_mode = 1;
      } elsif ($command eq 'graphicspath') {
        ($graphicspath = $file) =~ s/{(.*?)}/:$1/g;
      } else {
        next if $file=~/#/;		# skip if it is a parameter in a command
	my $opt=$command eq 'includegraphics' && $graphicspath ? "--path=$graphicspath" : '';
	my $ext=$commands{$command};
        $file=~/$ext$/ or $file.=$ext; 			# append default extension if its lacks
        chomp($file = `kpsewhich $opt $file`);		# lookup in the tex-tree
	$file||chomp($file=`kpsewhich $opt $orgfile`); 	# on fail, try without default extension
  
        if ($file) {
          $includes.="$file ";
          warn "    Added '$file'\n" unless $quiet;
          $file=~/\.tex$/ and scan_for_includes_($file);
        } else {
	  warn "Missing file $orgfile for \\$command command\n";
	  die "Quitting....\n" unless $ignore_missing_includes;
        }
      }
    }
  }
}

#************************************************************
sub exit_msg
{ my ($message,$fatal)=@_;
  warn "\n------------\n";
  carp "prv: $message.\n";
  warn "-- Use the -continue option to force complete processing.\n";
  sys("grep 'LaTeX Warning' $root_filename.log");
  if ($fatal) {
    warn "prv: restoring last $root_filename.aux file\n";
    sys("$copy $root_filename.auk $root_filename.aux $tonull");
    exit(1);
  }
}

#************************************************************

sub update_depend_file
{
  message("Writing dependency file [$root_filename.dep]\n");
  $rc_file = ">$root_filename.dep";
  open(RCFILE,$rc_file) ||
    die "prv: Unable to open dependency file [$rc_file] for updating\n";
  print RCFILE '$includes = \'' . "$includes';\n";
  print RCFILE '$bib_files = \'' . "$bib_files';\n";
  print RCFILE '$bibtex_mode = 1;' . "\n" if $bibtex_mode;
  print RCFILE '$index_mode = 1;' . "\n" if $index_mode;
  close RCFILE;
}

#************************************************************

sub message {
  return 0 if $quiet;
  my $mess=shift;
  carp "----------\n$mess\n----------\n";
}

#************************************************************

sub run_latex {
  my $myquiet=$quiet;
  my $err=$myquiet ? sys("$latex $tex_filename $tonull $fromnull")
                 : sys("$latex $tex_filename");
  if ($err) {
    @filestack=($filestack[0]); # empty @filestack except for the first entry (the main document)
    warn "found error $err\n";
    open(IN,"$root_filename.log");
    while(<IN>) {
      my $line=$_;
      $line=~s/\(.*?\)//g; # remove (...)
      while ($line=~/\)/g) { pop(@filestack) } # each ) closes a previous file
      $line=~/\(([^(]*)/ and push(@filestack,$1);  # push new filename
      /^l\.(\d+)/ and $linenum=$1;	 # error's linenumber
      if ($quiet) {   # just report the error
        last if /^(\?|Type X)/ && !$myquiet;
        $myquiet=0 if /^\!/ || /^Runaway/; 
        print STDERR unless $myquiet;
      } else {            # report everything
        print STDERR;
      }
    }
    close(IN);
    return $err;
  } else { # check log file to see if a rerun is needed:
    open(LOG,"$root_filename.log");
    while (<LOG>) {
      /LaTeX Warning.*Rerun/ and run_latex(),last;
    }
    close LOG;
  }
  return 0;
}

sub sys {
  my $command=shift;
  print STDERR "system call: $command\n" unless $quiet;
  system($command);
}

=pod

=head1 DESCRIPTION

B<prv> completely automates the process of generating a LaTeX
document. Essentially, it is a highly specialized relative of the
general make utility.  Given the source files for a document,
B<prv> issues the appropriate sequence of commands to generate a
.dvi, .ps or hardcopy version of the document.

B<prv> will scan source files for all included files, placing the
resulting dependency information into a dependency file with the same
name as the root file with the extension .dep. This option allows the
user to essentially leave all the work to B<prv>.  The program will
find all LaTeX \include, \input, and \includegraphics commands which
input other source files. As a special case, B<prv> will interpret lines
beginning with exactly "%\input" as if they were lines beginning with
"\input". You can use such lines to force recognition of file
dependencies that would not otherwise be recognized. For example, the moreverb.sty 
package has a command \listinginput that includes a file, but would not be found 
by B<prv>.

When B<prv> is run, it will examine the
timestamps on those files and run the various LaTeX processing
programs as necessary, if any of the source files have been changed
since the last document generation.  If the dependencies of the
document are changed (e.g., by adding or removing a \include command),
an additional pass of B<prv> -scan or prv -scan_force will update the
dependency file.

By default, if no dependency exists, the source files are scanned and
the dependency file generated.  If the dependency file exists, it is
read instead (even if the root file is newer than the dependency file
(see -scan option))

B<prv> has two different previewing options.  In the simple -pv
option, a postscript or dvi previewer is automatically run after
generating the postscript or dvi version of the document.  The type of
viewer is selected automatically depending on the -ps option.  When a
document is reaching the final stages of editing, the user frequently
wants to make small changes to the source files and examine the
effects in a previewer; for this phase, B<prv> provides the
powerful -pvc option (mnemonic: "preview continuously").  With this
option, B<prv> forks a child process to run an xdvi (or other
specified) previewer on the document, and then B<prv> repeatedly
monitors the source files of the document to see if any changes have
been made since the last .dvi file was produced.  When changes are
detected, B<prv> runs the appropriate LaTeX commands to regenerate
the .dvi file, and then sends a signal to xdvi job, indicating that
the previewer should update its display.  Thus the user can simply
edit a file and, when the changes are written to disk, B<prv>
completely automates the cycle of updating the .dvi and refreshing the
previewer's display.  It's not quite WYSIWYG, but LaTeX has never been
closer.

B<prv> has the ability to print a banner in gray diagonally across
each page when making the postscript file.

This script is derived from LatexMk version 2.0, which has undergone a
major revision by wybo@servalys.nl. In particular, the options
have been renamed to long names using the Getops::Long module. And
page and print-format selection has been built in.

=head1 OPTIONS

Before evaluating any options, B<prv> will try to read a system rc-file,
a user rc-file, and, finally an rc-file in the current directory.
The system rc-file, if it exists, is /etc/prvrc (\prv.rc for 
MSDOS users), the user rc-file is $HOME/.prvrc ($HOME\prv.rc for MSDOS users) and the 
local one is .prvrc (prv.rc for MSDOS).
Options can be set in the rc-files with statements like:

        $quiet=1;
        $message_draft="ENTWURF";

So if you usually like B<prv> to work quietly, you can indicate so in your rc-file
and change your mind in some cases by using the -noquiet (or perhaps -noq) option.
See also the section on RC FILES.

=over 4

=item file

One or more files can be specified.  If no files are specified,
B<prv> will run on any files that match any file masks specified
in the $texfile_search variable.

B<prv> requires source files to have a .tex extension. If the filename 
is specified without it, it is automatically appended.
So if you specify:

        prv foo

then B<prv> will try to operate on the file "foo.tex".

=item -batch <printing command string>

Prevents the -printout option the interrogate the user about pages to be
printed. Instead the document is printed according to the mandatory <print command string>. 
Also sets previewing off.
Thus the command 
        
        prv -batch '2-3 x3' test

print 3 copies of pages 2 and 3 of test.tex, without previewing.

=item -clean

Clean up (remove) all unnecessary files generated by latex and bibtex
except dvi and postscript.

=item -continue

Force B<prv> to continue document processing despite errors.
Normally, when B<prv> detects that latex has found an error which
will not be resolved by further processing, the program terminates.

=item -draft

Set draft mode.  This prints the banner message "DRAFT" across your
page when converting the dvi file to postscript.  Size and intensity
can be modified with the -scale_draft and -intensity_draft options.
The -message_draft option will override this option as this is really
just a short way of specifying:

B<prv> -message_draft DRAFT

Note that if the -draft option is specified, the -ps option is assumed
and the postscript file is always generated, even if it is newer than
the dvi file.

=item -dvi_filter

Dvi file filtering.  The argument to this option is a filter which
will generate a filtered dvi file with the extension ".dvf".  All
extra processing (e.g. conversion to postscript, preview, printing)
will then be performed on this filtered dvi file.

Exampe usage: Use dviselect to select only the even pages of the dvi
file:

B<prv> -dvi_filter 'dviselect even' foo.tex

=item -full_clean

Clean up (remove) all unnecessary files generated by latex and bibtex
including dvi and postscript.

=item -go

Force B<prv> to process document, disregarding the timestamps of
the source files.  This option is particularly useful when updating
style files, which are not included in the file dependency
information.

=item -help

Print help information.

=item -ignore_missing_includes

Force B<prv> to include files that don't exist when generating
dependency files.  A warning is produced instead of an error message
and the program terminating.  If the file name is not an absolute
path, it is assumed to be relative to the current working directory.

=item -intensity_draft <intensity>

How dark to print the banner message. A decimal number between 0 and
1. 0 is black and 1 is white, default is 0.95 which is ok unless your
toner cartridge is getting low.

=item -landscape

Run in landscape mode, using the landscape mode previewers and dvi to
postscript converters.

=item -message_draft <message>

A banner message to print diagonally accross each page when converting
the dvi file to postscript.  The message must be a single argument on
the command line so be careful with quoting spaces and such.

Note that if the -message_draft option is specified, the -ps option
is assumed and the postscript file is always generated, even if it is
newer than the dvi file.

=item -printout

Print out the file using lpr after generating the postscript version.
Unless the -batch option was given, the user is given the opportunity
to select pages and double-sided or booklet printing formats (see
section on PAGE SELECTION.  With the -batch option the complete
document will be printed.  

=item -ps

Generate postscript version of document.

=item -ps_filter

Postscript file filtering.  The argument to this option is a filter
which will generate a filtered postscript file with the extension
".psF". All extra processing (e.g. preview, printing) will then be
performed on this filtered postscript file.

Exampe usage: Use psnup to print two pages on the one page:

B<prv> -ps -ps_filter 'psnup -2' foo.tex

=item -pv

Run file previewer; if -ps is specified, will run postscript previewer,
otherwise runs dvi previewer.

=item -pvc

Run a dvi-previewer and continually update the .dvi file whenever
changes are made to source files (see the Description above).  Note
that if B<prv> dies because it encounters an error, the forked
previewer will continue to run.  Successive invocations with the -pvc
option will not fork new previewers, but will find the existing
previewer and send it the signals indicating the .dvi has been
updated. This option implies the -quiet option.

For xdvi you need at least version 21.27k to have this
option work properly.

You normally use this option by typing:

	prv -pvc file.tex&
	vi file.tex         # or another editor

=item -quiet

Suppresses messages about the progress B<prv> is making.
However, Latex log-file messages starting with -- will be printed in red to 
STDERR, even in quiet mode. You can use this to run quietly and nevertheless 
tell yourself urgent messages, like: 
  
  \typeout{-- please use colored paper for this job}

or

  \typeout{-- print frontpages separately on glossy paper}

=item -rcfile <rcfile>

Read specified RC file before processing.  The contents of the RC file
may override options specified before the -rcfile option, therefore it
is a good idea have the habit of specifying the -rcfile option first.

=item -scale_draft <scale>

A decimal number that specifies how large the banner message will be
printed. Experimentation is necessary to get the right scale for your
message, as a rule of thumb the scale should be about equal to 1100
divided by the number of characters in the message.  Default is 220.0
which is just right for 5 character messages.

=item -scan

Scan source files and generate new dependency file if root file is
newer than dependency file or dependency file does not exist.

=item -scan_force

Always scan source files and generate new dependency file, even if
newer dependency file exists.  This forces a scan.

=item -version

Print version number of B<prv>.


=back

If -ps is specified when the dependency file is created or
updated, then these options are stored in the dependency file.  This
means that these options will automatically be activated without
having to be explicitly specified on the command line in future runs.
Of coarse, if the dependency file is updated or deleted, these
automatic settings will be lost.

Options -pv and -pvc require one and only one filename specified on
the command line.

Options -pv and -pvc are mutually exclusive.

=head1 PAGE SELECTION

When you select the -printout option, and you did not also
use the -batch option, B<prv> interrogates you about the pages you
want to print. To that end the following prompt appears:

Pages ([range[,range...]|a] [b|t] [x<n>])?

You can react to this as in the following examples:

    5       # to print page 5
    5-      # to print pages 5 through the end
    5-7     # to print pages 5, 6 and 7
    -7      # to print the first 7 pages
    5-7,19- # to print pages 5, 6, 7 and 19 through the end
    a       # to print the whole document
    a x3    # to print 3 copies of the document
    x3      # the same
    5 x3    # to print 3 copies of page 5
    t       # print the whole document twosided
    t 2-    # print twosided starting at page 2
    b       # to print the whole document as an a5 size booklet
    b -12   # to print the first 12 pages as an a5 size booklet
    e       # edit the tex sourcefile and rerun prv
    q       # quit

If you use b to print a booklet, or t to print twosided, then you will
have to arrange your printer such that, with the printed sides up, the
first page printed will be at the bottom of the stack, and the last
page printed will be on top. Normally you will then have your output
come out the back of your printer.

B<prv> will first print one side of the
paper and prompt you for a return when the printer is ready and you
have turned the stack and put it back in the paper feed.

Finally, if you used the b option to print a booklet, you will have to
reshuffle your pages manually as follows:
- take the bottom page from the stack and put it aside without
  changing its position
- take the top page from the stack and put it upside down on the 
  bottom page
- repeat these two actions until the stack is empty
- if you find out how to prevent this manual action, please tell me how 
  you did it!! (wybo@servalys.nl)

When you use B<e> to edit the tex sourcefile, the environment variable EDITOR 
must point to your editor. Or you car set this variable in your startup file:
$EDITOR='my_favorite_editor';

=head1 EXAMPLES

 % prv thesis             # scan for includes, setup thesis.dep
                          # if thesis.tex is does not exist

 % prv -include thesis    # scan for includes, setup thesis.dep
                          # if thesis.tex is newer

 % prv -scan_force thesis # scan for includes, setup thesis.dep

 % prv -clean             # remove .aux, .log, .bbl, .blg, .dep,
                          # .dvi, .ps & .bbe files

=head1 EMACS

You can use prv for previewing and printing under emacs by creating functions
for it in your .emacs file like this:

	(defun prv ()
	  "preview latex document in the current buffer
	   after saving the buffer if necessary"
	  (interactive)
	  (save-buffer)
	  (message "Running prv.....")
	  (shell-command (concat "prv -noprintout " buffer-file-name))
	  (message "")
	)
	
	(defun prvpr (selection)
	  "print (a selection of pages from) the latex document
	   in the current buffer after saving it if necessary and
	   asking the user for a selection"
  	  (interactive "sPages ([range[,range...]|a] [b|t] [x<n>]) [a] ")
	  (if (equal selection "")(setq selection "a"))
	  (save-buffer)
	  (message "Running prv.....")
	  (shell-command (concat "prv -b " selection " " buffer-file-name))
	  (message "")
	)

and binding those to function keys:

	(global-set-key [f3] 'prv)
	(global-set-key [\C-f3] 'prvpr)

=HEAD1 VI

You can use prv for previewing and printing under vi by adding this line to your .vimrc file:

	map <F3> :w^M:!prv %^M

Pressing F3 then shows an xdvi preview (or error messages...) and after quitting this you can 
print (part of) your document and return to vi.

=head1 RC FILE

There are four RC files that B<prv> can read at startup:

The system RC file: UNIX: /etc/prvrc    MSDOS: C:\lib\prv\prv

The user's RC file: UNIX: $HOME/.prvrc  MSDOS: $HOME\prv.rc

The local RC file:  UNIX: .prvrc        MSDOS: prv.rc

The command-line RC files specified on the command line with the -rcfile option.

=head1 RC VARIABLES

The available variables that can be set are shown below.  Syntax is of
the form:

 $bibtex='bibtex';

Default values are indicated in brackets.

=over 4

=item $leader and $trailer ['']

If non-empty and a filename is a non-existing file, it will be given another try 
after packing it between $leader and $trailer. So if you like to have you latex files
in ~/mydata/<some_number>/main.tex you can preview from any directory with:

        prv 2134

which will give you ~/mydata/2134/main.tex.

=item $draft [0]

The equivalent of the -draft option.

=item $intensity_draft [0.95]

The equivalent of the -intensity_draft option.

=item $message_draft ['DRAFT']

The equivalent to the -message_draft option.

=item $scale_draft [220.0]

The equivalent of the -scale_draft option.

=item $bibtex ['bibtex']

The BibTeX processing program.

=item $bibtex_mode [0]

If nonzero, the document has a bibtex bibliography.  Set by the
-scan and -scan_force options and saved in the dependency
file. Should not need to set this in an RC file.

=item $clean [0]

The equivalent of the -clean option. Recommend that this is not
set from an RC file.

=item $clean_ext ['']

Extra extensions of files for B<prv> to remove when the -clean
option is selected.

=item $full_clean_ext ['']

Extra extensions of files for B<prv> to remove when the
-full_clean option is selected.

=item $cus_dep_list [empty]

Custom dependency list (see below).

=item $dvi_cont_previewer ['xdvi']

The dvi-previewer to run with the -pvc option.

=item $dvi_cont_previewer_landscape ['xdvi']

The dvi-previewer to run with the -pvc option in landscape mode.

=item $dvi_filter [empty]

The equivalent of the -dvi_filter option.

=item $dvi_previewer ['xdvi']

The dvi-previewer to run with the -pv option.

=item $dvi_previewer_landscape ['xdvi -paper a4r']

The dvi-previewer to run with the -pv option in landscape mode.

=item $dvips ['dvips']

The program to used as a filter to convert a .dvi file to a .ps file.

=item $dvips_landscape ['dvips -tlandscape']

The program to used as a filter to convert a .dvi file to a .ps file
in landscape mode.

=item $scan_force [0]

The equivalent of the -scan_force option.

=item $continue [0]

The equivalent of the -continue option.

=item $ignore_missing_includes [0]

The equivalent of the -ignore_missing_includes option.

=item $scan [0]

The equivalent of the -scan option.

=item $go [0]

The equivalent of the -go option.

=item $index_mode [0]

If nonzero, run makeindex to produce index of document. Set by the
-scan and -scan_force options and saved in the dependency file.
Should not need to set this in an RC file.


=item $landscape [0]

The equivalent of the -landscape option.

=item $latex ['latex']

The LaTeX processing program.

=item $lpr ['lpr']

The printing program.

=item $makeindex ['makeindex']

The index processing program.

=item $ps [0]

Equivalent to the -ps option.

=item $pvc [0]

The equivalent of the -pvc option.

=item $preview [0]

The equivalent of the -pv option.

=item $printout [0]

The equivalent of the -printout
option.  Recommend that this is not set from an RC file or you could
waste lots of paper.

=item $pscmd ['ps B<-x>']

Command used to get all the processes currently run by the user.  This
is used by the -pvc option to try and reattach itself to the already
existing previewer from a previous run with -pvc on the same file. The
default works for SunOS (BSD UNIX?).  For Solaris (System V?) try 'ps'
in the B<prv> RC file.

=item $ps_filter [empty]

The equivalent of the -ps_filter option.

=item $ps_previewer ['gs']

The postscript  previewer  to  run  with the -pv option.  

=item $ps_previewer_landscape ['gs -swap']

The postscript previewer to run with the -pv option in landscape mode.

=item $sleep_time [2]

The time to sleep (in seconds) between checking for source file
changes when running the -pvc option.

=item $texfile_search ['']

If no files were specified on the command line, then B<prv> will
search for files that  match the file mask specifed in this variable.

e.g.: $texfile_search = "$texfile_search *.ftex *.c.tex";

=item $tmpdir [$TMP]

Directory to store very small temporary files that B<prv>
generates while running.

=back

=head1 CUSTOM DEPENDENCIES

In any RC file a set of custom dependencies can be set up to convert a
file with one extension to a file with another.  An example use of
this would be to allow B<prv> to convert a .fig file to
dependencies are set up by using the @cus_dep_list array.  Each string
in the array has four arguments, separated by a space:

=over 4

=item from extension:

The extension of the file we are converting from (e.g. "fig").

=item to extension:

The extension of the file we are converting to (e.g. "eps").

=item must:

If non-zero, the file we are converting from must exist, if it doesn't
exist B<prv> will give an error message and exit unless the -continue
option is specified. If must is zero and the file we are converting
from doesn't exist, then no action is taken.


=item function:

The name of the subroutine that B<prv> should call to perform the
file conversion.  The first argument to the subroutine is the base
name of the file to be converted without any extension.  The
subroutines are declared in the syntax of perl.  

=back

Example in an RC file to convert a .fig file to a .eps file:

@cus_dep_list = (@cus_dep_list, "fig eps 0 fig2eps");

sub fig2eps {
system("fig2dev -Lps $_[0].fig $_[0].eps"); }

The subroutine fig2eps will only be called if the .fig file was
modified more recently then the .eps file, or the .eps file does not
exist.

If the return value of the subroutine is non-zero, then B<prv>
will assume an error occurred during the execution of the subroutine.

=head1 ENVIRONMENT

B<prv> needs several external programs; the following tabulates
their function, default Unix name and default MS-Dos name:

=over 4

=item 

Function:			Unix:		MS-Dos:

latex				latex		latex	

bibtex				bibtex		bibtex	

makeindex			makeindex	makeindex	

dvips				dvips -s	dvips -s	

dvips_landscape			dvips -tlandscape	dvips -tlandscape

pscmd				ps -x		ps -x	

touch				touch		touch	

psselect			psselect	psselect	

pstops				pstops		pstops	

diff				diff		diff	

copy				cp -p		copy

lpr				lpr		print

ps_previewer			gv		gv	

ps_previewer_landscape		gv -swap	gv

dvi_previewer			xdvi		windvi

dvi_previewer_landscape		xdvi -paper	a4r windvi

dvi_cont_previewer		xdvi		dviwin2 -1 -c

dvi_cont_previewer_landscape	xdvi -paper a4r	dviwin2 -1 -c

=back

B<prv> needs the following environment variables:

 HOME        user's home directory, for rc files
 TEXINPUTS   user's directory for style files etc.
 EDITOR      editor to be used, is needed

=head1 SEE ALSO

latex(1), bibtex(1).

=head1 BUGS

If you use macros for generating input file names in your document,
B<prv> will not be able to figure out what the name should be when
trying to generate a dependency file.  Using the -ignore_missing_includes option
will make B<prv> ignore these, but B<prv> will also obviously
not have a complete dependency list.

\includegraphics[...]{ is unseen
\includegraphics{file} is treated as \includegraphics{file.tex}

=head1 IDENTIFICATION

Modifications and enhancements by Wybo Dekker
(wybo@servalys.nl), based on LatexMk by Evan McLean (Version
2.0), original script called "go" by David J. Musliner (RCS Version
3.2)

=cut

# This script is derived from LatexMk version 2.0, which has undergone a
# major revision by wybo@servalys.nl. In particular:
# - The options have been renamed to long names using the Getops::Long module.
# - Page and print-format selection has been built in.
# - The manpage has been converted to pod
# - Works now also under MSDOS/Windows-95/NT
# - Allows for interactive pages selection in the printing phase
# - Facilities for printing reduced size booklets have been built in
# - the -quiet option was added for silencing both prv and latex

# version history
# 0.2
#   - previous version did not work under MSDOS because of open(IN,"latex|") 
#     construction.
#   - if a filename contains a path specification it  is now detected and latex
#     is run in the directory where the .tex file is. Previously, it was run in
#     the starting directory, causing .aux, etcetera files to be created there
#   - source files are now required to have a .tex extension. The extension is
#     added if it is lacking.
#   - replaced .dviF with dvf for sake of MSDOS
#   - moved system rc file to /etc
#   - negation of boolean options built in (-noq besides -q)
#   - for path-less filenames another try is now given by packing it
#     between $leader and $trailer (which can be defined in an rc-file
#   - added -s option to dvips. Prevents bop-hooks to be copied documents 
#     printed later
#   - changed the -batch option: now needs a string for format/page selection
#   - system calls now reported unless $quiet
#   - \typeout messages starting with -- now are printed in red to STDERR,
#     even in quiet mode
# 0.3
#   - moved some variable from the `use vars' statement to an ="" statement,
#     because of uninitialized messages.
# 0.4
#   - latex now runs in batchmode (-interaction=batchmode);
#     with the quiet option, if latex finds an error, only the error and
#     its explanation is reported.
# 0.5
#   - revised testing of included files, removing tests on
#     \blackandwhite, \colorslides, \psfig, \epsfig, \epsfbox, \epsffile, but
#     adding \includegraphics
#   - if TEXINPUTS path ends in ::, the last dir is now searched with find
#   - Environment variable TMP *must* have been set now and must not end
#     in a / (MSDOS: \) any more
#   - new option e introduced in print menu: can be used to edit the source file
#     and rerun prv.
#   - lines beginning with exactly %\input can now be used to make prv recognise 
#     dependency files that it would not find otherwise. For example, the moreverb
#     package has a command \listinginput{file}, or a user can create his own
#     commands for file inclusion.
#   - bibtex warnings are not seen as an error anymore
# 0.6
#   - replaced Term::ReadLine interface with Term::Query
#   - for unix, replaced /tmp/{to,from}null with /dev/null
#   - sub latex_run now checks log file for Rerun request. 
#   - removed slitex
#   - if no sourcefiles are given on the command line prv does not try to compile
#     *.tex anymore, since this would also imply compilation of input and include files.
#     Prv still looks in the variable $texfile_search though
#   - prv now offers the included file for editing if it contains the error
#   - the editor starts on the erroneous line
#   - temporary files are removed
#   - added comment about previewing under vi
#   - choosing -pvc now automatically cancels -pv instead of dying
#   - "Runaway argument" error messages now also displayed in quiet mode
# 0.7
#   - removed requirement of environment variable TMP. 
#     prv now supposes /tmp (\tmp for msdos) to be present and writable.
#   - search for included files now performed with kpsewhich
#   - $opt_variables renamed to the same without $opt_
#   - included files now are searched with their default extension appended,
#     but if that fails, the search is tried without it.
#   - Latex correctly producing no output is now seen as an error
__DATA__
Usage: prv [prv_options] [filename ...]

prv_options:

-b      -batch <selection>       run in batchmode, printing the selection
-cl     -clean                   clean up (remove) all nonessential files
-co     -continue                force continued processing past errors
-dr     -draft                   Print `DRAFT' across the page (in PostScript)
-dv     -dvi_filter <filter>     Filter to apply to dvi file
-f      -full_clean              remove nonessential files including .dvi + .ps
-g      -go                      process regardless of file timestamps
-h      -help                    print help
-ig     -ignore_missing_includes Ignore missing files when making dependencies
-in     -intensity_draft <intensity> Set contrast or intensity of banner
-l      -landscape               force landscape mode
-m      -message_draft <message> Print message across the page (in PostScript)
-pr     -printout                print document after generating postscript
-ps     -ps                      generate postscript
-ps_    -ps_filter <filter>      Filter to apply to postscript file
-pv     -pv                      preview document
-pvc    -pvc                     preview document and continuously update
-q      -quiet                   Operate silently
-r      -rcfile <file>           Read custom RC file
-scal   -scale_draft <scale>     Set scale for draft-string
-scan   -scan                    rescan for includes if .dep older than .tex
-scan_  -scan_force              force rescan for includes
-v      -version                 display program version

filename: the root filename of LaTeX document

Remarks:
-printout, -pv and -pvc are mutually exclusive
-help, -clean and -full_clean overide all other options: they just help/clean.
-pv and -pvc require exactly one filename specified
-rcfile's file contents override earlier options on the command line
