#!/usr/local/bin/perl ## latexmk - version 2.0 ## ## Modified by Evan McLean (emm@rdt.monash.edu.au) ## Original script (RCS version 2.3) called "go" written by David J. Musliner ## ## - fully automated LaTeX document generation routine. ## - checks to see if .bib or .tex source files (or included other files) ## have been changed since last run (which made .aux). ## - see sub print_help for info. ## ## LatexMk is no longer supported by the author. With changes in work ## situation, the author no longer uses latex, and hence does not use ## LatexMk. Having no access to latex also makes it difficult to test fixes. ## ##----------------------------------------------------------------------- ## Here's the copyright notice that Mr. Musliner required to be ## kept here. ##----------------------------------------------------------------------- ##Copyright 1992 by David J. Musliner and The University of Michigan. ## ## All Rights Reserved ## ##Permission to use, copy, modify, and distribute this software and its ##documentation for any purpose and without fee is hereby granted, ##provided that the above copyright notice and this permission notice appear in ##all copies and modified versions. ## ##THE COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ##INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT ##SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR ##CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, ##DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ##TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ##PERFORMANCE OF THIS SOFTWARE. ##----------------------------------------------------------------------- ##While I am not copyrighting my modifications (I don't even know if I ##can) I do include my own disclaimer: ## ##THE AUTHOR/MODIFIER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ##INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT ##SHALL THE AUTHOR/MODIFIER(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR ##CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, ##DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ##TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ##PERFORMANCE OF THIS SOFTWARE. ##----------------------------------------------------------------------- $version_num = '2.0'; ##Modification History: ## 2.0 - Final release, no enhancements. LatexMk is no longer supported ## by the author. ## 1.9 - Fixed bug that was introduced in 1.8 with path name fix. ## - Fixed buglet in man page. ## 1.8 - Add not about announcement mailling list above. ## - Added texput.dvi and texput.aux to files deleted with -c and/or ## the -C options. ## - Added landscape mode (-l option and a bunch of RC variables). ## - Added sensing of "\epsfig{file=...}" forms in dependency generation. ## - Fixed path names when specified tex file is not in the current ## directory. ## - Fixed combined use of -pvc and -s options. ## - Fixed a bunch of speling errors in the source. :-) ## - Fixed bugs in xdvi patches in contrib directory. ## 1.7 - Fixed -pvc continuous viewing to reattach to pre-existing ## process correctly. ## - Added $pscmd to allow changing process grepping for different ## systems. ## 1.6 - Fixed buglet in help message ## - Fixed bugs in detection of input and include files. ## 1.5 - Removed test message I accidentally left in version 1.4 ## - Made dvips use -o option instead of stdout redirection as some ## people had problems with dvips not going to stdout by default. ## - Fixed bug in input and include file detection ## - Fixed dependency resolution process so it detects new .toc file ## and makeindex files properly. ## - Added dvi and postscript filtering options -dF and -pF. ## - Added -v version commmand. ## 1.4 - Fixed bug in -pvc option. ## - Made "-F" option include non-existant file in the dependency list. ## (RC variable: $force_include_mode) ## - Added .lot and .lof files to clean up list of extentions. ## - Added file "texput.log" to list of files to clean for -c. ## - LatexMk now handles file names in a similar fashion to latex. ## The ".tex" extention is no longer enforced. ## - Added $texfile_search RC variable to look for default files. ## - Fixed \input and \include so they add ".tex" extention if necessary. ## - Allow intermixing of file names and options. ## - Added "-d" and banner options (-bm, -bs, and -bi). ## (RC variables: $banner, $banner_message, $banner_scale, ## $banner_intensity, $tmpdir) ## - Fixed "-r" option to detect an command line syntax errors better. ## 1.3 - Added "-F" option, patch supplied by Patrick van der Smagt. ## 1.2 - Added "-C" option. ## - Added $clean_ext and $clean_full_ext variables for RC files. ## - Added custom dependency generation capabilities. ## - Added command line and variable to specify custom RC file. ## - Added reading of rc file in current directly. ## 1.1 - Fixed bug where Dependency file generation header is printed ## rependatively. ## - Fixed bug where TEXINPUTS path is searched for file that was ## specified with absolute an pathname. ## 1.0 - Ripped from script by David J. Musliner (RCS version 2.3) called "go" ## - Fixed a couple of file naming bugs ## e.g. when calling latex, left the ".tex" extention off the end ## of the file name which could do some interesting things ## with some file names. ## - Redirected output of dvips. My version of dvips was a filter. ## - Cleaned up the rc file mumbo jumbo and created a dependency file ## instead. Include dependencies are always searched for if a ## dependency file doesn't exist. The -i option regenerates the ## dependency file. ## Getting rid of the rc file stuff also gave the advantage of ## not being restricted to one tex file per directory. ## - Can specify multiple files on the command line or no files ## on the command line. ## - Removed lpr options stuff. I would guess that generally, ## you always use the same options in which case they can ## be set up from an rc file with the $lpr variable. ## - Removed the dviselect stuff. If I ever get time (or money :-) ) ## I might put it back in if I find myself needing it or people ## express interest in it. ## - Made it possible to view dvi or postscript file automatically ## depending on if -ps option selected. ## - Made specification of dvi file viewer seperate for -pv and -pvc ## options. ##----------------------------------------------------------------------- ## default document processing programs. $latex = 'latex'; $bibtex = 'bibtex'; $slitex = 'slitex'; $makeindex = 'makeindex'; $dvips = 'dvips'; $dvips_landscape = 'dvips -tlandscape'; $dviselect = 'dviselect'; $ps_previewer = 'gv'; $ps_previewer_landscape = 'gv -swap'; $dvi_previewer = 'xdvi -s 4'; $dvi_previewer_landscape = 'xdvi -s 4 -paper a4r'; $dvi_cont_previewer = 'xtex'; $dvi_cont_previewer_landscape = 'xtex'; $lpr = 'lpr'; $tmpdir = '/usr/tmp'; $pscmd = 'ps -x'; # This works for SunOs. Solaris should just be 'ps' ## default flag settings. $bibtex_mode = 0; # is there a bibliography needing bibtexing? $index_mode = 0; # is there an index needing makeindex run? $landscape_mode = 0; # default to portrait mode $sleep_time = 2; # time to sleep b/w checks for file changes in -pvc mode $banner = 0; # Non-zero if we have a banner to insert $banner_scale = 220; # Original default scale $banner_intensity = 0.95; # Darkness of the banner message $banner_message = 'DRAFT'; # Original default message $dvi_filter = ''; # DVI filter command $ps_filter = ''; # Postscript filter command ## Read rc files. # Read system rc file. $rcfile = '/usr/local/lib/latexmk/LatexMk'; if ( -e $rcfile ) { # Read the system rc file do "$rcfile"; } # Read user rc file. $rcfile = "$ENV{'HOME'}/.latexmkrc"; if ( -e $rcfile ) { # Read the user rc file do "$rcfile"; } # Read rc file in current directory. $rcfile = "latexmkrc"; if ( -e $rcfile ) { # Read the user rc file do "$rcfile"; } ## Process command line args. @the_file_list = ( ); while ($_ = $ARGV[0]) { shift; if (/^-c$/) { $cleanup_mode = 1; } elsif (/^-C$/) { $cleanup_mode = 1; $cleanup_full_mode = 1; } elsif (/^-d$/) { $banner = 1; } elsif (/^-f$/) { $force_mode = 1; } elsif (/^-F$/) { $force_include_mode = 1; } elsif (/^-g$/) { $go_mode = 1; } elsif (/^-h$/) { &print_help; } elsif (/^-i$/) { $generate_and_save_includes = 1; } elsif (/^-I$/) { $force_generate_and_save_includes = 1; } elsif (/^-l$/) { $landscape_mode = 1; } elsif (/^-pvc$/) { $preview_continuous_mode = 1; } elsif (/^-pv$/) { $preview_mode = 1; } elsif (/^-ps$/) { $postscript_mode = 1; } elsif (/^-p$/) { $printout_mode = 1; } elsif (/^-s$/) { $slide_mode = 1; } elsif (/^-v$/) { warn "\nLatexMk $version_num\n"; exit; } elsif (/^-r$/) { if ( $ARGV[0] eq '' ) { warn "LatexMk: No RC file specified\n"; &print_help; } if ( -e $ARGV[0] ) { do "$ARGV[0]"; } else { die "LatexMk: RC file [$ARGV[0]] does not exist\n"; } shift; } elsif (/^-bm$/) { if ( $ARGV[0] eq '' ) { warn "LatexMk: No message specified\n"; &print_help; } $banner = 1; $banner_message = $ARGV[0]; shift; } elsif (/^-bi$/) { if ( $ARGV[0] eq '' ) { warn "LatexMk: No intensity specified\n"; &print_help; } $banner_intensity = $ARGV[0]; shift; } elsif (/^-bs$/) { if ( $ARGV[0] eq '' ) { warn "LatexMk: No scale specified\n"; &print_help; } $banner_scale = $ARGV[0]; shift; } elsif (/^-dF$/) { if ( $ARGV[0] eq '' ) { warn "LatexMk: No dvi filter specified\n"; &print_help; } $dvi_filter = $ARGV[0]; shift; } elsif (/^-pF$/) { if ( $ARGV[0] eq '' ) { warn "LatexMk: No ps filter specified\n"; &print_help; } $ps_filter = $ARGV[0]; shift; } elsif (/^-/) { warn "LatexMk: $_ bad option\n"; } else { @the_file_list = ( @the_file_list, $_ ); } } @ARGV = @the_file_list; # Check we haven't selected mutually exclusive modes. # Note that -c overides all other options, but doesn't cause # an error if they are selected. if (($printout_mode && ( $preview_mode || $preview_continuous_mode )) || ( $preview_mode && $preview_continuous_mode )) { warn "LatexMk: Conflicting options (-p, -pv, -pvc) selected\n"; &print_help; } # If seleced a previewer mode, make sure one and only one filename was specified if ($preview_mode || $preview_continuous_mode) { if (($ARGV[0] eq '') || ($ARGV[1] ne '')) { warn"LatexMk: Need to specify one and only one filename for previewer mode\n"; &print_help; } } # If no files specified, try and find some if ($ARGV[0] eq '') { @ARGV=<*.tex $texfile_search>; } # If still no files, exit. if ($ARGV[0] eq '') { warn "LatexMk: No file name specified\n"; &print_help; ## print_help function exits. } # If landscape mode, change modes if ( $landscape_mode ) { $dvips = $dvips_landscape; $dvi_previewer = $dvi_previewer_landscape; $dvi_cont_previewer = $dvi_cont_previewer_landscape; $ps_previewer = $ps_previewer_landscape; } # Process for each file. foreach $filename ( @ARGV ) { ## remove extention from filename if was given. if ( &find_basename($filename, $root_filename, $texfile_name) ) { die "LatexMk: Could not find file [$texfile_name]\n"; } if ($cleanup_mode) { ## Do clean if necessary &cleanup; if ($cleanup_full_mode) { &cleanup_full; } } 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 ( ! $force_generate_and_save_includes ) { if ( $generate_and_save_includes ) { if ( -e $depfile ) { # Compare timestamp of dependency file and root tex file. $dep_mtime = &get_mtime("$depfile"); $tex_mtime = &get_mtime("$texfile_name"); if ( $tex_mtime < $dep_mtime ) { $read_depend = 1; } } } elsif ( -e $depfile ) # If dependency file already exists. { $read_depend = 1; } } if ( $read_depend ) { # Read the dependency file open(depfile) || die "LatexMk: Couldn't open dependency file [$root_filename.dep]\n"; while() { eval; } close(depfile); } else { # Generate dependency file. # get search paths for includes. $psfigsearchpath = '.'; $TEXINPUTS = $ENV{'TEXINPUTS'}; if (!$TEXINPUTS) { $TEXINPUTS = '.'; } $BIBINPUTS = $ENV{'BIBINPUTS'}; if (!$BIBINPUTS) { $BIBINPUTS = $TEXINPUTS; } &scan_for_includes("$texfile_name"); &update_depend_file; } ## put root tex file into list of includes. $includes .= " $texfile_name"; ## before munging, save existing .aux file. ## - if latex bombs, kill .aux, restore this backup to get back most ## useful bib/ref info. system("cp -p $root_filename.aux $root_filename.aux.bak > /dev/null 2>&1"); #************************************************************ &make_dependents("$includes"); if ($slide_mode) { &make_slitex_dvi; } else { &make_latex_dvi; } &make_dvi_filtered; &make_preview_continous; &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_mode || !(-e "$root_filename.dvi") || ($aux_mtime < $tex_mtime) || ($aux_mtime < $bbl_mtime) || ($aux_mtime < $ilg_mtime) || ($aux_mtime < $ind_mtime) || !(-e "$root_filename.aux")) { warn "------------\nRunning first $latex [$texfile_name]\n------------\n"; &backup_toc; $return = system("$latex $texfile_name"); $changed_dvi = 1; if (!$force_mode && $return) { &exit_msg('Latex encountered an error',1); } if ($index_mode) { warn "------------\nRunning $makeindex [$root_filename]\n------------\n"; $return = system("$makeindex $root_filename"); if (!$force_mode && $return) { &exit_msg('Makeindex encountered 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))) { warn "------------\nRunning $bibtex [$root_filename]\n------------\n"; $return = system("$bibtex $root_filename"); $bbl_mtime = &get_mtime("$root_filename.bbl"); } if ($bibtex_mode && &check_for_bibtex_errors) { if (!$force_mode) { # touch a .bib file so that will rerun bibtex to fix errors. @split_bib_files = split(' ',$bib_files); system("touch $split_bib_files[0]"); &exit_msg('Bibtex reported an error'); } } ## 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)) { warn "------------\nRunning second $latex [$texfile_name]\n------------\n"; &backup_toc; $return = system("$latex $texfile_name"); $changed_dvi = 1; } if (!$force_mode && $return) { &exit_msg('Latex encountered an error',1); } if (&check_for_reference_change || &check_toc) { warn "------------\nRunning third $latex [$texfile_name]\n------------\n"; &backup_toc; $return = system("$latex $texfile_name"); $changed_dvi = 1; } if (!$force_mode && &check_for_bad_reference) { &exit_msg('Latex could not resolve all references'); } if (!$force_mode && &check_for_bad_citation) { &exit_msg('Latex could not resolve all citations or labels'); } return(1); } #************************************************************ sub make_slitex_dvi { $tex_mtime = &get_latest_mtime($includes); $dvi_mtime = &get_mtime("$root_filename.dvi"); if ( $go_mode || !(-e "$root_filename.dvi") || ($dvi_mtime < $tex_mtime) ) { warn "------------\nRunning $slitex [$texfile_name]\n------------\n"; $return = system("$slitex $texfile_name"); } if (!$force_mode && $return) { &exit_msg('Slitex encountered an error'); } } #************************************************************ sub make_dvi_filtered { return if ( length($dvi_filter) == 0 ); warn "------------\nRunning $dvi_filter [$root_filename]\n------------\n"; system("$dvi_filter < $root_filename.dvi > $root_filename.dviF"); } #************************************************************ # Finds the basename of the root file # Arguments: # 1 - Filename to breakdown # 2 - Where to place base file # 3 - Where to place tex file # Returns non-zero if tex file exists sub find_basename { local($base_name,$ch,$ext,$base_path); $ch = ''; $ext = ''; $base_path = $_[0]; while (( $ch ne '.' ) && ( $ch ne '/' ) && ( $base_path ne '' )) { $ext = $ch . $ext; $ch = chop $base_path; } if (( $ch eq '.' ) && ( $base_path ne '' )) { ## Found extention stuff $_[2] = $base_path . '.' . $ext; } else { ## No extention $base_path = $_[0]; $_[2] = $_[0]; } $ch = ''; $base_name = ''; while (( $ch ne '/' ) && ( $base_path ne '' )) { $ch = chop $base_path; if ( $ch ne '/' ) { $base_name = $ch . $base_name; } } $_[1] = $base_name; if ( ! -e $_[2] ) { ## File does not exist, try adding a ".tex" extention if ( -e "$_[2].tex" ) { # Adding the extention works, so put the extention back on the # basename $_[1] = $_[2]; $_[2] .= '.tex'; return(0); } return(1); } return(0); } #************************************************************ sub make_dependents { local($file,$dep,$base_name,$ch,$toext,$fromext,$proptoext,$must,$func_name,$return); foreach $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 extention. foreach $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") )) { warn "------------\nRunning $func_name [$base_name]\n------------\n"; $return = &$func_name($base_name); if ( !$force_mode && $return ) { &exit_msg("$func_name encountered an error"); } } } else { if ( !$force_mode && ( $must != 0 )) { &exit_msg("File '$base_name.$fromext' does not exist to build '$base_name.$toext'\n"); } } } } } } } #************************************************************ sub make_printout { return if (!$printout_mode); local ($ext); if ( length($ps_filter) == 0 ) { $ext = '.ps'; } else { $ext = '.psF'; } warn "------------\nPrinting using $lpr [$root_filename]\n------------\n"; system("$lpr $root_filename$ext"); } #************************************************************ sub make_postscript { if ( ! $banner ) { return if (!$postscript_mode && !$printout_mode); } 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.dviF"; } # Do banner stuff if ( $banner ) { ## Make temp banner file local(*INFILE,*OUTFILE,$count); $tmpfile = "$tmpdir/latexmk.$$"; $count = 0; while ( -e $tmpfile ) { $count = $count + 1; $tmpfile = "$tmpdir/latexmk.$$.$count"; } if ( ! open(OUTFILE, ">$tmpfile") ) { die "LatexMk: 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 $banner_scale scalefont setfont\n"; print OUTFILE "0 0 moveto $banner_intensity setgray ($banner_message) 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 ) || $banner ) { warn "------------\nRunning $dvips [$root_filename]\n------------\n"; system("$dvips $header $dvi_file -o $root_filename.ps"); } if ( $banner ) { unlink("$tmpfile"); } ## Do we have postscript filtering? if ( length($ps_filter) != 0 ) { warn "------------\nRunning $ps_filter [$root_filename]\n------------\n"; system("$ps_filter < $root_filename.ps > $root_filename.psF"); } } #************************************************************ # run appropriate previewer. sub make_preview { return if (!$preview_mode); $viewer = $dvi_previewer; $ext = '.dvi'; if ($postscript_mode) { $viewer = $ps_previewer; $ext = '.ps'; if ( length($ps_filter) != 0 ) { $ext = '.psF'; } } else { if ( length($dvi_filter) != 0 ) { $ext = '.dviF'; } } warn "------------\nStarting previewer: $viewer $root_filename$ext\n------------\n"; exec("$viewer $root_filename$ext"); warn "LatexMk: Could not start previewer [$viewer $root_filename$ext]"; exit; } sub backup_toc { if ( -e "$root_filename.toc" ) { system( "cp -p $root_filename.toc $root_filename.toc.bak > /dev/null 2>&1"); } } #************************************************************ # 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.toc.bak" ) { $return = system( "diff $root_filename.toc.bak $root_filename.toc > /dev/null 2>&1"); } else { $return = 1; } } else { $return = 0; } return($return); } #************************************************************ # arg1 = name sub find_process_id { local(@command, $lookingfor); @ps_output = `$pscmd`; shift(@ps_output); # Discard the header line from ps foreach (@ps_output) { # s/\s+/ /g; #Compress multiple spaces. ($pid,$tt,$stat,$time,@command) = split(' ',$_); if ("@command" eq "$_[0]") { return($pid); } } return(0); } #************************************************************ sub make_preview_continous { return if (!$preview_continuous_mode); # local ($dvi_file); # get the value of SIGUSR1, defaults to SPARC value. if (!(do 'signal.ph')) { eval 'sub SIGUSR1 {30;}'; } # Figure out the dvi file name if ( length($dvi_filter) == 0 ) { $dvi_file = "$root_filename.dvi"; } else { $dvi_file = "$root_filename.dviF"; } # note, we only launch a previewer if one isnt already running... # otherwise we'll send reopen signals to the existing previewer. if ($previewer_pid = &find_process_id("$dvi_cont_previewer $dvi_file")) { warn "------------\nReattached to existing previewer, pid=$pid\n------------\n"; kill &SIGUSR1,$previewer_pid; } else { if (!($previewer_pid = fork)) { # in forked child, close off from parent so previewer runs on # after parent 'latexmk' dies. setpgrp($$,0); warn "------------\n$dvi_cont_previewer $dvi_file\n------------\n"; exec("$dvi_cont_previewer $dvi_file"); warn "LatexMk: Failed to exec file viewer\n"; exit; } } # Loop forever, rebuilding .dvi as necessary. while ( 1 ) { sleep($sleep_time); if ($slide_mode) { &make_slitex_dvi; } else { &make_latex_dvi; } if ($changed_dvi) { kill &SIGUSR1,$previewer_pid; } } } #************************************************************ sub get_mtime { local ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime, $ctime,$blksize,$blocks) = stat($_[0]); $mtime; } #************************************************************ sub check_for_reference_change { local($logfile) = "$root_filename.log"; open(logfile) || die "LatexMk: Could not open log file to check for reference check\n"; while() { if (/Rerun to get/) { return 1; } } 0; } #************************************************************ sub check_for_bad_reference { local($logfile) = "$root_filename.log"; open(logfile) || die "LatexMk: Could not open log file to check for bad reference\n"; while () { 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) || die "LatexMk: Could not open log file to check for bad citation\n"; while () { 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) || die "LatexMk: Could not open bibtex log file error check\n"; while () { 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.aux.bak"); 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.toc.bak"); 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 foreach $include (split(' ',$includes)) { $include =~ s/\.[^\.]*$/.aux/; unlink($include); } # Do any other file extentions specified foreach $ext (split(' ',$clean_ext)) { unlink("$root_filename.$ext"); } } #************************************************************ sub cleanup_full { unlink("$root_filename.dvi"); unlink("$root_filename.ps"); unlink("$root_filename.dviF"); unlink("$root_filename.psF"); unlink("texput.dvi"); # Do any other file extentions specified foreach $ext (split(' ',$clean_full_ext)) { unlink("$root_filename.$ext"); } } #************************************************************ sub print_help { warn "LatexMk $version_num: Automatic LaTeX document generation routine\n\n"; warn "Usage: latexmk [latexmk_options] [filename ...]\n\n"; warn " LatexMk_options:\n"; warn " -bm - Print message across the page when converting to postscript\n"; warn " -bi - Set contrast or intensity of banner\n"; warn " -bs - Set scale for banner\n"; warn " -c - clean up (remove) all nonessential files\n"; warn " -C - clean up (remove) all nonessential files\n"; warn " including dvi and postscript files\n"; warn " -d - Print `DRAFT' across the page when converting to postscript\n"; warn " -dF - Filter to apply to dvi file\n"; warn " -f - force continued processing past errors\n"; warn " -F - Ignore non-existent files when making dependencies\n"; warn " -g - process regardless of file timestamps\n"; warn " -h - print help\n"; warn " -i - rescan for includes if depenancy file older than tex file\n"; warn " -I - force rescan for includes\n"; warn " -l - force landscape mode\n"; warn " -ps - generate postscript\n"; warn " -pF - Filter to apply to postscript file\n"; warn " -p - print document after generating postscript\n"; warn " -pv - preview document\n"; warn " -pvc - preview document and continuously update\n"; warn " -r - Read custom RC file\n"; warn " -s - set slide mode\n"; warn " -v - display program version\n"; warn " filename = the root filename of LaTeX document\n"; warn "\n -p, -pv and -pvc are mutually exclusive\n"; warn " -h, -c and -C overides all other options.\n"; warn " -pv and -pvc require one and only one filename specified\n"; warn " Contents of RC file specified by -r overrides options specified\n"; warn " before the -r option on the command line\n"; exit; } #************************************************************ # - stats all files listed in first arg, returns most recent modify time of all. sub get_latest_mtime { local($return_mtime) = 0; foreach $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 psfig'd 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 LatexMk?? sub scan_for_includes { warn "------------\nGenerating Dependency File [$root_filename]\n------------\n"; &scan_for_includes_($_[0]); } sub scan_for_includes_ { local(*FILE,$orig_filename,$full_filename1,$full_filename2); if (!open(FILE,$_[0])) { warn "LatexMk: could not open input file [$_[0]]\n"; return; } while() { ($_,$junk) = split('%',$_); # primitive comment removal. if (/\\include[{\s]+([^\001\040\011}]*)[\s}]/) { $full_filename = $1; $orig_filename = $full_filename; $full_filename1 = &find_file($full_filename,$TEXINPUTS,'1'); if (( $full_filename1 eq '' ) || ( ! -e $full_filename1 )) { $full_filename2 = &find_file("$full_filename.tex",$TEXINPUTS,'1'); if (( $full_filename2 ne '' ) && ( -e $full_filename2 )) { $full_filename = $full_filename2; } else { $full_filename = $full_filename1; } } else { $full_filename = $full_filename1; } if ($full_filename) { $includes .= "$full_filename "; if ( -e $full_filename ) { warn " Found include for file [$full_filename]\n"; &scan_for_includes_($full_filename); } else { if ( $orig_filename =~ /^\// ) { warn "LatexMk: Could not find file [$orig_filename]\n"; } else { warn "LatexMk: Could not find file [$orig_filename] in path [$TEXINPUTS]\n"; warn " assuming in current directory ($full_filename)\n"; } } } else { if ( ! $force_include_mode ) { if ( $orig_filename =~ /^\// ) { die "LatexMk: Could not find file [$orig_filename]\n"; } else { die "LatexMk: Could not find file [$orig_filename] in path [$TEXINPUTS]\n"; } } } } elsif (/\\input[{\s]+([^\001\040\011}]*)[\s}]/) { $full_filename = $1; $orig_filename = $full_filename; $full_filename1 = &find_file($full_filename,$TEXINPUTS,'1'); if (( $full_filename1 eq '' ) || ( ! -e $full_filename1 )) { $full_filename2 = &find_file("$full_filename.tex",$TEXINPUTS,'1'); if (( $full_filename2 ne '' ) && ( -e $full_filename2 )) { $full_filename = $full_filename2; } else { $full_filename = $full_filename1; } } else { $full_filename = $full_filename1; } if ($full_filename) { $includes .= "$full_filename "; warn "added '$full_filename'\n"; if ( -e $full_filename ) { warn " Found input for file [$full_filename]\n"; &scan_for_includes_($full_filename); } else { if ( $orig_filename =~ /^\// ) { warn "LatexMk: Could not find file [$orig_filename]\n"; } else { warn "LatexMk: Could not find file [$orig_filename] in path [$TEXINPUTS]\n"; warn " assuming in current directory ($full_filename)\n"; } } } else { if ( ! $force_include_mode ) { if ( $orig_filename =~ /^\// ) { die "LatexMk: Could not find file [$orig_filename]\n"; } else { die "LatexMk: Could not find file [$orig_filename] in path [$TEXINPUTS]\n"; } } } } elsif (/\\blackandwhite{([^\001\040\011}]*)}/ || /\\colorslides{([^\001}]*)}/) { $slide_mode = 1; $full_filename = $1; if ($1 =~ m/\./) { $full_filename = &find_file($full_filename,$TEXINPUTS); } else { $full_filename = &find_file("$full_filename.tex",$TEXINPUTS); } if ($full_filename) { $includes .= "$full_filename "; if ( -e $full_filename ) { warn " Found slide input for file [$full_filename]\n"; &scan_for_includes_($full_filename); } } } elsif (/\\psfig{file=([^,}]+)/ || /\\psfig{figure=([^,}]+)/) { $full_filename = &find_file($1,$psfigsearchpath); if ($full_filename) { $includes .= "$full_filename "; if ( -e $full_filename ) { warn " Found psfig for file [$full_filename]\n"; } } } elsif ( /\\epsfbox{([^}]+)}/ || /\\epsfbox\[[^\]]*\]{([^}]+)}/ || /\\epsffile{([^}]+)}/ || /\\epsffile\[[^\]]*\]{([^}]+)}/ || /\\epsfig{file=([^,}]+)/ || /\\epsfig{figure=([^,}]+)/ ) { $full_filename = &find_file($1,$TEXINPUTS); if ($full_filename) { $includes .= "$full_filename "; if ( -e $full_filename ) { warn " Found epsf for file [$full_filename]\n"; } } } elsif (/\\documentstyle[^\000]+landscape/) { warn " Detected landscape mode\n"; $landscape_mode = 1; } elsif (/\\bibliography{([^}]+)}/) { $bib_files = $1; $bib_files =~ tr/,/ /; $bib_files = &find_file_list($bib_files,'.bib',$BIBINPUTS); warn " Found bibliography files [$bib_files]\n"; $bibtex_mode = 1; } elsif (/\\psfigsearchpath{([^}]+)}/) { $psfigsearchpath = $1; } elsif (/\\makeindex/) { $index_mode = 1; warn " Detected index mode\n"; } } } #************************************************************ # given filename and path, return full name of file, or die if none found. # when force_include_mode=1, only warn if an include file was not # found, and return 0 (PvdS). sub find_file { if ( $_[0] =~ /^\// ) { if ($force_include_mode) { if ( $_[2] eq '' ) { warn "LatexMk: Could not find file [$_[0]]\n"; } return("$_[0]"); } else { if (-e $_[0]) { return("$_[0]"); } die "LatexMk: Could not find file [$_[0]]\n"; } } foreach $dir (split(':',$_[1])) { if (-e "$dir/$_[0]") { return("$dir/$_[0]"); } } if ($force_include_mode) { if ( $_[2] eq '' ) { warn "LatexMk: Could not find file [$_[0]] in path [$_[1]]\n"; warn " assuming in current directory (./$_[0])\n"; } return("./$_[0]"); } else { if ( $_[2] ne '' ) { return(''); } die "LatexMk: Could not find file [$_[0]] in path [$_[1]]\n"; } } #************************************************************ # given space sep list of filenames, a file suffix, and a path, return list of # full names of files, or die w/ warning if not found. # When $force_include_mode=1, don't die and don't append the file names (PvdS). sub find_file_list { local($tmp_file,$return_list) = ''; foreach $file (split(' ',$_[0])) { $tmp_file = &find_file("$file$_[1]",$_[2]); if ($tmp_file) { $return_list .= $tmp_file . " "; } } $return_list; } #************************************************************ sub exit_msg { warn "\n------------\n"; warn "LatexMk: $_[0].\n"; warn "-- Use the -f option to force complete processing.\n"; if ($_[1]) { warn "LatexMk: restoring last $root_filename.aux file\n"; system("cp -p $root_filename.aux.bak $root_filename.aux > /dev/null 2>&1"); } exit; } #************************************************************ sub update_depend_file { warn "Writing dependency file [$root_filename.dep]\n"; $rcfile = ">$root_filename.dep"; open(rcfile) || die "LatexMk: Unable to open dependency file [$rcfile] for updating\n"; print rcfile '$includes = \'' . "$includes';\n"; print rcfile '$bib_files = \'' . "$bib_files';\n"; if ($slide_mode) { print rcfile '$slide_mode = 1;' . "\n"; } if ($bibtex_mode) { print rcfile '$bibtex_mode = 1;' . "\n"; } if ($index_mode) { print rcfile '$index_mode = 1;' . "\n"; } close rcfile; }