From 88f7d1ac35385d57d17eb60fb2d77f6704eadde5 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 15 Apr 2009 18:21:17 +0000 Subject: latexmk 4.05 (13apr09) git-svn-id: svn://tug.org/texlive/trunk@12722 c570f23f-e606-0410-a88d-b1316a301751 --- .../texk/texlive/linked_scripts/latexmk/latexmk.pl | 673 +++++++++++++++------ 1 file changed, 474 insertions(+), 199 deletions(-) (limited to 'Build') diff --git a/Build/source/texk/texlive/linked_scripts/latexmk/latexmk.pl b/Build/source/texk/texlive/linked_scripts/latexmk/latexmk.pl index 4d124a67893..1b122c7e975 100755 --- a/Build/source/texk/texlive/linked_scripts/latexmk/latexmk.pl +++ b/Build/source/texk/texlive/linked_scripts/latexmk/latexmk.pl @@ -1,22 +1,16 @@ -eval '(exit $?0)' && eval 'exec perl -x -S "$0" ${1+"$@"}' && -eval 'exec perl -x -S "$0" $argv:q' -if 0; +#!/usr/bin/env perl +# On a UNIX-like system, the above enables latexmk to run independently +# of the location of the perl executable. This line relies on the +# existence of the program /usr/bin/env +# If there is a problem for any reason, you can replace the first line of +# this file by: + #!/usr/bin/perl -w -#!/opt/local/bin/perl -w -#!/usr/local/bin/perl -w -# The above code allows this script to be run under UNIX/LINUX without -# the need to adjust the path to the perl program in a "shebang" line. -# (The location of perl changes between different installations, and -# may even be different when several computers running different -# flavors of UNIX/LINUX share a copy of latex or other scripts.) The -# script is started under the default command interpreter sh, and the -# evals in the first two lines restart the script under perl, and work -# under various flavors of sh. The -x switch tells perl to start the -# script at the first #! line containing "perl". The "if 0;" on the -# 3rd line converts the first two lines into a valid perl statement -# that does nothing. -# -# Source of the above: manpage for perlrun + +# with the path of the perl executable adjusted for your system. + + +use warnings; # Delete #??!! when working @@ -34,17 +28,21 @@ if 0; # primary run. Ensure fdb and c. is updated enough etc. # I may have it correct now: fdb_write in makeB # See also routine rdb_update_files_for_rule, and who calls it +# It appears to be unused. What is rationale? # Apparently excess runs of latex after change in .tex file that entails # change in bibliography. -# Now I am missing diagnostics - - ## ???!!!!!!!!!!!!! Should I remove bibtex rule? NO ## ?? Need to set dependence of extra bibtex rules on .bib file ## ?? Put $pass as variable in rule. +## ?? Issues with clean-up +## List of aux files deleted is those read, not those generated. +## Other files are generated by (pdf)latex; should they be deleted? +## (I have hooks for this). + + #======================================= @@ -142,8 +140,8 @@ if 0; $my_name = 'latexmk'; $My_name = 'Latexmk'; -$version_num = '4.01'; -$version_details = "$My_name, John Collins, 24 September 2008"; +$version_num = '4.05b'; +$version_details = "$My_name, John Collins, 11 April 2009"; use Config; @@ -210,8 +208,88 @@ else { ## 5. Parsing of log file instead of source file is used to ## obtain dependencies, by default. ## -## Modification log for 28 Mar 2007 onwards in detail +## Modification log for 24 Sep 2008 onwards in detail ## +## 11 Apr 2009, John Collins Capture ctrl/C and ctrl/break during wait +## loop in preview_continuous. Then +## control stays within latexmk on break +## from loop. It allows user to do +## postprocessing, like +## "latexmk -pvc file; cleanup;" +## 10 Apr 2009, John Collins Safer use of % in placeholders in commands +## 10 Apr 2009, John Collins V. 4.05 +## 3 Apr 2009, John Collins Change to a nicer #! line +## 26 Mar 2009, John Collins Case independence for one item in +## @file_not_found +## 6 Mar 2009, John Collins Single %input_extensions variable +## Correct bug in making cusdep for missing +## extensionless file +## 5 Mar 2009, John Collins Get rid of warning about variables used +## only once. +## 25 Feb 2009, John Collins Ensure viewed file type is made. +## Configurable extensions for finding +## cusdep. +## 24 Feb 2009, John Collins V. 4.04 +## Fix problems when using both latex and pdflatex +## 1. In fdb, keep primary rules that have been +## run, even if they are not in use in +## current invocation of latexmk. +## 2. But don't write primary rules if they have +## not been run (i.e., $run_time==0). +## 3. If $run_time==0 for an in-use primary +## rule, i.e., if the rule has not +## been run, then run it +## unconditionally. +## 4. But don't let this apply to other +## rules, since the time-stamp rule +## will normally have been adequate. +## Improved diagnostics on reason for rerun. +## Corrected classify_rules call in pvc. +## In rdb_set_from_logB: when setting +## subsidiary rules after parsing log +## file, this is now done only for the +## currently-being-applied primary rule, +## not for all primary rules. +## 22 Dec 2008, John Collins V. 4.03 +## 22 Dec 2008, John Collins Fix possibility that unwrapping of lines +## in log_file is done incorrectly +## 5 Dec 2008, John Collins Correct treatment of -e option +## 2 Dec 2008, John Collins For home directory (where user's .latexmkrc +## is located, when $ENV{'HOME'} does +## not exist, use $ENV{USERPROFILE} +## (suitable for MS-Win). +## Clean up code in rdb_set_rules +## 1 Dec 2008, John Collins -c and -C now also delete fdb_latex file +## 26 Nov 2008, John Collins Correct problem with invocation of MSWin +## with cygwin +## 25 Nov 2008, John Collins Correct problem with invocation of MSWin +## start command +## 15 Nov 2008, John Collins Make version # 4.02, for release +## 12 Nov 2008, John Collins Deal with quoted filenames in log file +## (as with MikTeX) +## 10 Nov 2008, John Collins Start fixing bug about -ps -pdfps +## running ps2pdf before dvips +## 30 Sep 2008, John Collins V. 4.01a +## Correct problem that aux files not of +## same basename are not deleted on clean-up +## Primary problem: fdb file was deleted before +## being read +## ?? Remaining issues on this: +## List of aux files deleted is those read, +## not those generated +## Other files are generated by (pdf)latex +## should they be deleted? +## Solution of problem that if a source file +## for (pdf)latex disappears, that is treated +## as a change requiring a rerun. This gives +## an infinite loop of unnecessary runs in +## -pvc mode +## Cleanup can also apply to all files +## generated during (pdf)latex run, +## as diagnosed by \openout lines, +## and also to files generated from +## these. Controlling variable +## $cleanup_includes_generated. ## 24 Sep 2008, John Collins Release version 4.01. ## ## 1998-2008, John Collins. Many improvements and fixes. @@ -328,7 +406,7 @@ $log_wrap = 79; '^\\! LaTeX Error: File `([^\\\']*)\\\' not found\\.', '.*?:\\d*: LaTeX Error: File `([^\\\']*)\\\' not found\\.', '^LaTeX Warning: File `([^\\\']*)\\\' not found', - '^Package .* file `([^\\\']*)\\\' not found', + '^Package .* [fF]ile `([^\\\']*)\\\' not found', ); ## Hash mapping file extension (w/o period, e.g., 'eps') to a single regexp, @@ -360,6 +438,17 @@ $pdflatex = 'pdflatex %O %S'; $latex_silent_switch = '-interaction=batchmode'; $pdflatex_silent_switch = '-interaction=batchmode'; +# %input_extensions maps primary_rule_name to pointer to hash of file extensions +# used for extensionless files specified in the source file by constructs +# like \input{file} \includegraphics{file} +# Could write +#%input_extensions = ( 'latex' => { 'tex' => 1, 'eps' => 1 };, +# 'pdflatex' => { 'tex' => 1, 'pdf' => 1, 'jpg' => 1, 'png' => 1 }; ); +# Instead we'll exercise the user-friendly access routines: +add_input_ext( 'latex', 'tex', 'eps' ); +add_input_ext( 'pdflatex', 'tex', 'jpg', 'pdf' ); +#show_input_ext( 'latex' ); show_input_ext( 'pdflatex' ); + ## Command to invoke bibtex $bibtex = 'bibtex %O %B'; # Switch(es) to make bibtex silent: @@ -584,7 +673,7 @@ elsif ( $^O eq "cygwin" ) { # NT-native start command of a cmd.exe is used. # For a pdf-file, "start x.pdf" starts the pdf viewer associated with # pdf files, so no program name is needed: - $start_NT = "cmd /c start"; + $start_NT = "cmd /c start \"\""; $pdf_previewer = "$start_NT %O %S"; $ps_previewer = "$start_NT %O %S"; $ps_previewer_landscape = $ps_previewer; @@ -840,6 +929,9 @@ $cleanup_mode = 0; # No cleanup of nonessential LaTex-related files. # dviF, pdf, ps, & psF $cleanup_fdb = 0; # No removal of file for latexmk's file-database $cleanup_only = 0; # When doing cleanup, do not go-on to making files +$cleanup_includes_generated = 0; + # Determines whether cleanup deletes files generated by + # (pdf)latex (found from \openout lines in log file). $diagnostics = 0; $dvi_filter = ''; # DVI filter command $ps_filter = ''; # Postscript filter command @@ -1003,8 +1095,7 @@ if (!$TEXINPUTS) { $TEXINPUTS = '.'; } # List of known rules. Rule types: primary, # external (calls program), internal (calls routine), cusdep. -%known_rules = ( 'latex' => 'primary', 'pdflatex' => 'primary', - ); +%possible_primaries = ( 'latex' => 'primary', 'pdflatex' => 'primary' ); %primaries = (); # Hash of rules for primary part of make. Keys are # currently 'latex', 'pdflatex' or both. Value is # currently irrelevant. Use hash for ease of lookup @@ -1023,7 +1114,7 @@ if (!$TEXINPUTS) { $TEXINPUTS = '.'; } %rule_db = (); # Database of all rules: # Hash: rulename -> [array of rule data] # Rule data: - # 0: [ cmd_type, ext_cmd, int_cmd, out_of_date-crit, + # 0: [ cmd_type, ext_cmd, int_cmd, test_kind, # source, dest, base, out_of_date, # out_of_date_user, time_of_last_run ] # where @@ -1043,7 +1134,7 @@ if (!$TEXINPUTS) { $TEXINPUTS = '.'; } # This variable intcmd is a reference to an array, # $$intcmd[0] = internal routine # $$intcmd[1...] = its arguments (if any) - # out_of_date_crit specifies method of determining + # test_kind specifies method of determining # whether a file is out-of-date: # 0 for never # 1 for usual: whether there is a source @@ -1100,6 +1191,17 @@ if (!$TEXINPUTS) { $TEXINPUTS = '.'; } #================================================== ## Read rc files: +# User's home directory +$HOME = ''; +if (exists $ENV{'HOME'} ) { + $HOME = $ENV{'HOME'}; +} +elsif (exists $ENV{'USERPROFILE'} ) { + $HOME = $ENV{'USERPROFILE'}; +} + + + sub read_first_rc_file_in_list { foreach my $rc_file ( @_ ) { #print "===Testing for rc file \"$rc_file\" ...\n"; @@ -1114,7 +1216,7 @@ sub read_first_rc_file_in_list { # Read system rc file: read_first_rc_file_in_list( @rc_system_files ); # Read user rc file. -read_first_rc_file_in_list( "$ENV{'HOME'}/.latexmkrc" ); +read_first_rc_file_in_list( "$HOME/.latexmkrc" ); # Read rc file in current directory. read_first_rc_file_in_list( "latexmkrc", ".latexmkrc" ); @@ -1133,9 +1235,8 @@ while ($_ = $ARGV[0]) # Make -- and - equivalent at beginning of option: s/^--/-/; shift; - if (/^-c$/) { $cleanup_mode = 2; $cleanup_only = 1; } - elsif (/^-C$/) { $cleanup_mode = 1; $cleanup_only = 1; } - elsif (/^-CA$/) { $cleanup_mode = 1; $cleanup_fdb = 1; $cleanup_only = 1;} + if (/^-c$/) { $cleanup_mode = 2; $cleanup_fdb = 1; $cleanup_only = 1; } + elsif (/^-C$/ || /^-CA$/ ) { $cleanup_mode = 1; $cleanup_fdb = 1; $cleanup_only = 1; } elsif (/^-CF$/) { $cleanup_fdb = 1; } elsif (/^-cd$/) { $do_cd = 1; } elsif (/^-cd-$/) { $do_cd = 0; } @@ -1211,12 +1312,10 @@ while ($_ = $ARGV[0]) elsif (/^-view=ps$/) { $view = "ps";} elsif (/^-view=pdf$/) { $view = "pdf"; } elsif (/^-e$/) { - if ( $ARGV[0] eq '' ) { + if ( $#ARGV < 0 ) { &exit_help( "No code to execute specified after -e switch"); } - else { - execute_code_string( $ARGV[0] ); - } + execute_code_string( $ARGV[0] ); shift; } elsif (/^-r$/) { @@ -1438,6 +1537,14 @@ if ( $view eq "default" ) { if ( $pdf_mode ) { $view = "pdf"; } } +# Make sure we make the kind of file we want to view: +if ($view eq 'dvi') { $dvi_mode = 1; } +if ($view eq 'ps') { $postscript_mode = 1; } +if ( ($view eq 'pdf') && ($pdf_mode == 0) ) { + $pdf_mode = 1; +} + +# Make sure that we make something if all requests are turned off if ( ! ( $dvi_mode || $pdf_mode || $postscript_mode || $printout_mode) ) { print "No specific requests made, so default to dvi by latex\n"; $dvi_mode = 1; @@ -1446,9 +1553,19 @@ if ( ! ( $dvi_mode || $pdf_mode || $postscript_mode || $printout_mode) ) { # Set new-style requested rules: if ( $dvi_mode ) { $requested_filerules{'latex'} = 1; } if ( $pdf_mode == 1 ) { $requested_filerules{'pdflatex'} = 1; } -elsif ( $pdf_mode == 2 ) { $requested_filerules{'ps2pdf'} = 1; } -elsif ( $pdf_mode == 3 ) { $requested_filerules{'dvipdf'} = 1; } -if ( $postscript_mode ) { $requested_filerules{'dvips'} = 1; } +elsif ( $pdf_mode == 2 ) { + $requested_filerules{'latex'} = 1; + $requested_filerules{'dvips'} = 1; + $requested_filerules{'ps2pdf'} = 1; +} +elsif ( $pdf_mode == 3 ) { + $requested_filerules{'latex'} = 1; + $requested_filerules{'dvipdf'} = 1; +} +if ( $postscript_mode ) { + $requested_filerules{'latex'} = 1; + $requested_filerules{'dvips'} = 1; +} if ( $printout_mode ) { $one_time{'print'} = 1; } if ( $preview_continuous_mode || $preview_mode ) { $one_time{'view'} = 1; } if ( length($dvi_filter) != 0 ) { $requested_filerules{'dvi_filter'} = 1; } @@ -1456,16 +1573,6 @@ if ( length($ps_filter) != 0 ) { $requested_filerules{'ps_filter'} = 1; } if ( $banner ) { $requested_filerules{'dvips'} = 1; } -%possible_primaries = (); -foreach (&rdb_possible_primaries) { - $possible_primaries{$_} = 1; -} - -#print "POSSIBLE PRIMARIES: "; -#foreach (keys %possible_primaries ) {print "$_, ";} -#print "\n"; - - if ( $pdf_mode == 2 ) { # We generate pdf from ps. Make sure we have the correct kind of ps. add_option( \$dvips, " $dvips_pdf_switch" ); @@ -1504,7 +1611,6 @@ foreach $filename ( @file_list ) $failure = 0; # Set nonzero to indicate failure at some point of # a make. Use value as exit code if I exit. $failure_msg = ''; # Indicate reason for failure -#?? Unneeded now: $bibtex_mode = $save_bibtex_mode; if ( $do_cd ) { ($filename, $path) = fileparse( $filename ); @@ -1539,31 +1645,55 @@ foreach $filename ( @file_list ) $fdb_file = "$root_filename.$fdb_ext"; - if ($cleanup_fdb) { unlink $fdb_file; } if ( $cleanup_mode > 0 ) { - my @extra_generated = (); + # Use parse_logB to get names of generated files. + # It returns its results in the following variables: + local %dependents = (); # Maps files to status + local @bbl_files = (); + local %idx_files = (); # Maps idx_file to (ind_file, base) + local %generated_log = (); # Lists generated files + print "$My_name: Examining log file for generated files...\n"; + &parse_logB; + + my @index_bibtex_generated = (); my @aux_files = (); - rdb_read_generatedB( $fdb_file, \@extra_generated, \@aux_files ); + my %other_generated = %generated_log; + + rdb_read_generatedB( $fdb_file, \@index_bibtex_generated, \@aux_files, + \%other_generated ); if ( ($go_mode == 2) && !$silent ) { warn "$My_name: Removing all generated files\n" unless $silent; } + foreach (@index_bibtex_generated, @aux_files) { + delete( $other_generated{$_} ); + } if ($diagnostics) { - show_array( "For deletion:\n Extra_generated:", @extra_generated ); + show_array( "For deletion:\n" + ." Generated (from makeindex and bibtex):", + @index_bibtex_generated ); show_array( " Aux files:", @aux_files ); + show_array( "Other generated files:\n" + ." (only deleted if \$cleanup_includes_generated is set): ", + keys %other_generated ); } + # Add to the generated files, some log file and some backup # files used in previous versions of latexmk - &cleanup1( 'blg', 'ilg', 'log', 'aux.bak', 'idx.bak', + &cleanup1( $fdb_ext, 'blg', 'ilg', 'log', 'aux.bak', 'idx.bak', split(' ',$clean_ext), @generated_exts ); - unlink( 'texput.log', @extra_generated, "texput.aux", @aux_files ); + unlink( 'texput.log', @index_bibtex_generated, "texput.aux", @aux_files ); + if ($cleanup_includes_generated) { + unlink( keys %other_generated ); + } if ( $cleanup_mode == 1 ) { &cleanup1( 'dvi', 'dviF', 'ps', 'psF', 'pdf', split(' ', $clean_full_ext) ); } } + if ($cleanup_fdb) { unlink $fdb_file; } if ($cleanup_only) { next FILE; } # Initialize file and rule databases. @@ -1832,11 +1962,10 @@ sub rdb_set_rules { # Set up rule database from definitions # Map of files to rules that MAKE them: - local %from_rules = (); %rule_db = (); foreach my $Prule_list (@_) { - foreach my $rule ( sort keys %$Prule_list) { + foreach my $rule ( keys %$Prule_list) { my ( $cmd_type, $ext_cmd, $int_cmd, $source, $dest, $base, $test_kind ) = @{$$Prule_list{$rule}}; my $needs_making = 0; # Substitute in the filename variables, since we will use @@ -1854,21 +1983,7 @@ sub rdb_set_rules { rdb_create_rule( $rule, $cmd_type, $ext_cmd, $int_cmd, $test_kind, $source, $dest, $base, $needs_making ); - if ($dest) { $from_rules{$dest} = $rule ; } } - rdb_for_all( - 0, - sub{ - # my ($base, $path, $ext) = fileparse( $file, '\.[^\.]*' ); - # if ( exists $from_rules{$file} && ! exists $generated_exts_all{$ext} ) { - # # Show how to make this file. But don't worry about generated - # # files. - if ( exists $from_rules{$file} ) { - $$Pfrom_rule = $from_rules{$file}; - } - #?? print "$rule: $file, $$Pfrom_rule\n"; - } - ); } # End arguments of subroutine &rdb_make_links; } # END rdb_set_rules @@ -2158,7 +2273,9 @@ sub make_preview_continuousB { local @changed = (); local @disappeared = (); local @no_dest = (); # Non-existent destination files + local @rules_never_run = (); local @rules_to_apply = (); + local $failure = 0; local $runs = 0; local %rules_applied = (); @@ -2282,15 +2399,18 @@ CHANGE: print "\n=== Watching for updated files. Use ctrl/C to stop ...\n"; } $waiting = 1; if ($diagnostics) { warn "WAITING\n"; } + &catch_break; + $have_break = 0; WAIT: while (1) { sleep($sleep_time); + if ($have_break) { last WAIT; } &rdb_clear_change_record; rdb_recurseA( [@targets], \&rdb_flag_changes_here ); - if ( &rdb_count_changes > 0) { - &rdb_diagnose_changes - unless $silent; -#??? - warn "$My_name: File(s) changed or not used in previous run(s). Remake files.\n"; + if ( &rdb_need_run ) { + if (!$silent) { + warn "$My_name: Need to remake files.\n"; + &rdb_diagnose_changes( ' ' ); + } last WAIT; } # Does this do this job???? @@ -2300,8 +2420,14 @@ CHANGE: warn "$My_name: New file(s) found.\n"; last WAIT; } + if ($have_break) { last WAIT; } } # end WAIT: - $waiting = 0; if ($diagnostics) { warn "NOT WAITING\n"; } + &default_break; + if ($have_break) { + print "$Latexmk: User typed ctrl/C or ctrl/break. I'll stop.\n"; + exit; + } + $waiting = 0; if ($diagnostics) { warn "NOT WAITING\n"; } } #end infinite_loop CHANGE: } #END sub make_preview_continuousB @@ -2483,10 +2609,9 @@ sub print_help " This and the other clean-ups are instead of a regular make.\n", " -C - clean up (remove) all nonessential files\n", " including aux, dep, dvi, postscript and pdf files\n", - " But exclude file of database of file information\n", - " -CA - clean up (remove) absolutely ALL nonessential files\n", - " including aux, dep, dvi, postscript and pdf files,\n", " and file of database of file information\n", + " -CA - clean up (remove) absolutely ALL nonessential files.\n", + " Now equivalent to -C option.\n", " -CF - Remove file of database of file information before doing \n", " other actions\n", " -cd - Change to directory of source file when processing it\n", @@ -2666,6 +2791,8 @@ sub parse_logB { # Treat the following specially, since they have special rules # @bbl_files to list of .bbl files. # %idx_files to map from .idx files to .ind files. +# %generated_log: keys give set of files written by (pdf)latex (e.g., aux, idx) +# as determined by \openout = ... lines in log file. # Also set # $reference_changed, $bad_reference, $bad_citation # Trivial or default values if log file does not exist/cannot be opened @@ -2686,6 +2813,7 @@ sub parse_logB { foreach (@default_includes) { $dependents{$_} = 4; } @bbl_files = (); %idx_files = (); # Maps idx_file to (ind_file, base) + %generated_log = (); $reference_changed = 0; $bad_reference = 0; @@ -2697,21 +2825,30 @@ sub parse_logB { return 0; } -LINE: +# Collect lines of log file + my @lines = (); while(<$log_file>) { # Could use chomp here, but that fails if there is a mismatch # between the end-of-line sequence used by latex and that # used by perl. (Notably a problem with MSWin latex and # cygwin perl!) s/[\n\r]*$//; - if ( $. == 1 ){ + push @lines, $_; + } + close $log_file; + + my $line = 0; +LINE: + while( $line <= $#lines ) { + $_ = $lines[$line]; + $line ++; + if ( $line == 1 ){ if ( /^This is / ) { # First line OK next LINE; } else { warn "$My_name: Error on first line of '$log_name'. ". "This is apparently not a TeX log file.\n"; - close $log_file; $failure = 1; $failure_msg = "Log file '$log_name' appears to have wrong format."; return 0; @@ -2720,10 +2857,16 @@ LINE: # Handle wrapped lines: # They are lines brutally broken at exactly $log_wrap chars # excluding line-end. + # But a line can be of the length where the wrapping occurs, but + # there can be no wrapping. So for a long line, try parsing it + # as if it is wrapped, but leave the index variable $line as is, + # so that on the next loop over LINE, we also try parsing the + # succeeding line as if there was no wrapping: my $len = length($_); - while ($len == $log_wrap) { - my $extra = <$log_file>; - $extra =~ s/[\n\r]*$//; + my $next = $line; + while ( ($len == $log_wrap) && ($next <= $#lines) ) { + my $extra = $lines[$next]; + $next++; $len = length($extra); $_ .= $extra; } @@ -2760,6 +2903,10 @@ LINE: # Latex error/warning, etc. next LINE; } + if ( /^\\openout\d+\s*=\s*\`([^\']+)\'\.$/ ) { + $generated_log{$1} = 1; + next LINE; + } # Test for writing of index file. The precise format of the message # depends on which package (makeidx.sty , multind.sty or index.sty) and # which version writes the message. @@ -2895,19 +3042,22 @@ LINE: # First step: replace $_ by whole of line after the '(' # Thus $_ is putative filename followed by other stuff. $_ = $1; - if ( /^([^\(^\)^\{]*?)\s\[/ ) { + if ( /^\"([^\(^\)^\"]+)\"/ ) { + # Quoted file name, as from MikTeX + } + elsif ( /^([^\(^\)]*?)\s\[/ ) { # Terminator: space then '[' # Use *? in condition: to pick up first ' [' as terminator # 'file [' should give good filename. } - elsif ( /^([^\(^\)^\{]*)\s(?=\()/ ) { + elsif ( /^([^\(^\)]*)\s(?=\()/ ) { # Terminator is ' (', but '(' isn't in matched string, # so we keep the '(' ready for the next match } - elsif ( /^([^\(^\)^\{]*)(\))/ ) { + elsif ( /^([^\(^\)]*)(\))/ ) { # Terminator is ')' } - elsif ( /^([^\(^\)^\{]*?)\s*\{/ ) { + elsif ( /^([^\(^\)]*?)\s*\{/ ) { # Terminator: arbitrary space then '{' # Use *? in condition: to pick up first ' [' as terminator # 'file [' should give good filename. @@ -2926,6 +3076,10 @@ LINE: # Part of font message next INCLUDE_CANDIDATE; } + # Remove quotes around filename, as for MikTeX. I've already + # treated this as a special case. For safety check here: + $include_candidate =~ s/^\"(.*)\"$/$1/; + # Make list of new include files; sometimes more than one. my @new_includes = ($include_candidate); if ( $include_candidate =~ /^(.+)\[([^\]]+)\]$/ ) { @@ -2961,7 +3115,6 @@ LINE: } # INCLUDE_NAME } # INCLUDE_CANDIDATE } # LINE - close($log_file); # Default includes are always definitive: foreach (@default_includes) { $dependents{$_} = 4; } @@ -3050,9 +3203,14 @@ CANDIDATE: if ( $misparse > 0 ) { print "$misparse\n"; - print "Apparent input files appearently from misunderstood lines in .log file:\n"; + print "Apparent input files apparently from misunderstood lines in .log file:\n"; foreach ( @misparse ) { print " $_\n"; } } + print "Log file shows the following generated files: "; + foreach (keys %generated_log) { + print "'$_' "; + } + print "\n"; } return 1; @@ -3364,13 +3522,20 @@ LINE: #************************************************************ sub rdb_read_generatedB { - # Call: rdb_read_generatedB( $in_name, \@extra_generated, \@aux_files ) + # Call: rdb_read_generatedB( $in_name, \@generated1, \@aux_files. + # \%other_generated ) # From rule database in saved file, in format written by rdb_write, - # finds the non-basic generated files that are to be deleted by a cleanup. - # Returns an array of these files, or an empty array if the file - # does not exist or cannot be opened. - my ($in_name, $Pgenerated, $Paux_files) = @_; - @$Pgenerated = (); + # finds the non-trivial generated files that are to be deleted by a cleanup. + # On entry: + # Keys of %other_generated: any detected generated files, from \openout + # lines log file, usually. + # At exit: + # Array @generated1: files associated with makeindex and bibtex + # Array @aux_files: aux files + # Added to keys of %other_generated: any files that are destinations of rules + # whose source is in %other_generated. (One stage only.) + my ($in_name, $Pgenerated1, $Paux_files, $Pother_generated) = @_; + @$Pgenerated1 = (); @$Paux_files = (); my $in_handle = new FileHandle; @@ -3384,6 +3549,7 @@ sub rdb_read_generatedB { my $ext = ''; my $path = ''; my $state = 0; # Outside a section + my @other_additions = (); LINE: while ( <$in_handle> ) { # Remove leading and trailing white space. @@ -3405,12 +3571,15 @@ LINE: } else { next LINE; } if ( $rule =~ /^makeindex/ ) { - push @$Pgenerated, $source, $dest, "$base.ilg"; + push @$Pgenerated1, $source, $dest, "$base.ilg"; } elsif ( $rule =~ /^bibtex/ ) { - push @$Pgenerated, $dest, "$base.blg"; + push @$Pgenerated1, $dest, "$base.blg"; push @$Paux_files, $source; } + elsif ( exists ${$Pother_generated}{$source} ) { + push @other_additions, $dest; + } $state = 1; #Reading a section } elsif ( /^\"([^\"]*)\"\s+(\S+)\s+(\S+)\s+(\S+)\s+\"([^\"]*)\"/ ) { @@ -3433,7 +3602,9 @@ LINE: } } # LINE undef $in_handle; - + foreach (@other_additions) { + ${$Pother_generated}{$_} = 1; + } } # END rdb_read_generatedB #************************************************************ @@ -3463,13 +3634,25 @@ sub rdb_write { &rdb_classify_rules( \%possible_primaries, keys %requested_filerules ); print $out_handle "# Fdb version $fdb_ver\n"; - my @rules = sort( - rdb_accessible( - uniq1( keys %known_rules, keys %current_primaries ))); + my @rules = rdb_accessible( uniq1( keys %possible_primaries ) ) ; + # Separate call to sort. Otherwise rdb_accessible seems to get wrong argument. + @rules = sort( @rules ); rdb_for_some( \@rules, - sub { print $out_handle "[\"$rule\"] $$Prun_time \"$$Psource\" \"$$Pdest\" \"$$Pbase\" \n"; }, - sub { print $out_handle " \"$file\" $$Ptime $$Psize $$Pmd5 \"$$Pfrom_rule\"\n"; }, + sub { + # Omit data on a unused and never-run primary rule: + if ( ($$Prun_time == 0) + && exists( $possible_primaries{$rule} ) + && ! exists( $current_primaries{$rule} ) + ) + { + return; + } + print $out_handle "[\"$rule\"] $$Prun_time \"$$Psource\" \"$$Pdest\" \"$$Pbase\" \n"; + rdb_do_files( + sub { print $out_handle " \"$file\" $$Ptime $$Psize $$Pmd5 \"$$Pfrom_rule\"\n"; } + ); + } ); undef $out_handle; return 1; @@ -3496,9 +3679,10 @@ sub rdb_set_from_logB { # Parse log file to find relevant filenames # Result in the following variables: - local %dependents = (); # Maps files to status + local %dependents = (); # Maps files to status local @bbl_files = (); - local %idx_files = (); # Maps idx_file to (ind_file, base) + local %idx_files = (); # Maps idx_file to (ind_file, base) + local %generated_log = (); # Lists generated files found in log file # The following are also returned, but are global, to be used by caller # $reference_changed, $bad_reference $bad_citation @@ -3514,11 +3698,9 @@ sub rdb_set_from_logB { if ($diagnostics); rdb_create_rule( $from_rule, 'external', $makeindex, '', 1, $idx_file, $ind_file, $ind_base, 1, 0); - foreach my $primary ( keys %primaries ) { - print " ===Source file '$ind_file' for '$primary'\n" + print " ===Source file '$ind_file' for '$rule'\n" if ($diagnostics > -1); - rdb_ensure_file( $primary, $ind_file, $from_rule ); - } + rdb_ensure_file( $rule, $ind_file, $from_rule ); } if ( ! -e $ind_file ) { # Failure was non-existence of makable file @@ -3545,24 +3727,22 @@ sub rdb_set_from_logB { if ($diagnostics); rdb_ensure_file( $from_rule, $source ); } - foreach my $primary ( keys %primaries ) { - print " ===Source file '$bbl_file' for '$primary'\n" + print " ===Source file '$bbl_file' for '$rule'\n" if ($diagnostics); - rdb_ensure_file( $primary, $bbl_file, $from_rule ); - if ( ! -e $bbl_file ) { - # Failure was non-existence of makable file - # Leave failure issue to other rules. - $failure = 0; - } + rdb_ensure_file( $rule, $bbl_file, $from_rule ); + if ( ! -e $bbl_file ) { + # Failure was non-existence of makable file + # Leave failure issue to other rules. + $failure = 0; } } } NEW_SOURCE: foreach my $new_source (keys %dependents) { - foreach my $primary ( keys %primaries ) { - rdb_ensure_file( $primary, $new_source ); - } + print " ===Source file for rule '$rule': '$new_source'\n" + if ($diagnostics); + rdb_ensure_file( $rule, $new_source ); } my @more_sources = &rdb_set_dependentsA( $rule ); @@ -3750,7 +3930,12 @@ sub rdb_set_dependentsA { # Call rdb_set_dependentsA( rules ...) # Returns array (sorted), of new source files. local @new_sources = (); + local @deletions = (); rdb_recurseA( [@_], 0, \&rdb_one_depA ); + foreach (@deletions) { + my ($rule, $file) = @$_; + rdb_remove_files( $rule, $file ); + } &rdb_make_links; return uniqs( @new_sources ); } #END rdb_set_dependentsA @@ -3764,6 +3949,7 @@ sub rdb_one_depA { my ($base_name, $path, $toext) = fileparseA( $new_dest ); $base_name = $path.$base_name; $toext =~ s/^\.//; + my $Pinput_extensions = $input_extensions{$rule}; DEP: foreach my $dep ( @cus_dep_list ) { my ($fromext,$proptoext,$must,$func_name) = split(' ',$dep); @@ -3781,6 +3967,7 @@ DEP: push @new_sources, $new_dest; } if (! rdb_rule_exists( $$Pfrom_rule ) ) { + print "=== Creating rule for '$$Pfrom_rule'\n"; rdb_create_rule( $$Pfrom_rule, 'cusdep', '', \@PAnew_cmd, 3, $source, $new_dest, $base_name, 0 ); } @@ -3810,7 +3997,11 @@ DEP: } } } - elsif ( ($toext eq '') && (! -e $file ) ) { + elsif ( ($toext eq '') + && (! -e $file ) + && (! -e "$base_name.$proptoext" ) + && exists $$Pinput_extensions{$proptoext} + ) { # Empty extension and non-existent destination # This normally results from \includegraphics{A} # without graphics extension for file, when file does @@ -3818,7 +4009,7 @@ DEP: my $source = "$base_name.$fromext"; if ( -e $source ) { $new_dest = "$base_name.$proptoext"; - my $from_rule = "cusdep $fromext $toext $base_name"; + my $from_rule = "cusdep $fromext $proptoext $base_name"; push @new_sources, $new_dest; print "Ensuring rule for '$from_rule', to make '$new_dest'\n" if $diagnostics > -1; @@ -3834,6 +4025,9 @@ DEP: ); } rdb_ensure_file( $rule, $new_dest, $from_rule ); + # We've now got a spurious file in our rule. But don't mess + # with deleting an item we are in the middle of! + push @deletions, [$rule, $file]; return; } } # End of Rule found @@ -3893,30 +4087,8 @@ sub rdb_accessible { return @accessible; } #END rdb_accessible -#************************************************************ - -sub rdb_possible_primaries { - # Returns array of possible primaries - my @rules = (); - foreach my $rule ( keys %known_rules ) { - if ( $known_rules{$rule} eq 'primary') { - push @rules, $rule; - } - } - return @rules; -} #END rdb_possible_primaries - -#************************************************************ #************************************************************ #************************************************************ - -# Routines for makes. NEW VERSIONS ?? - -#????????Debugging routines: -sub R1 {print "===START $rule\n"} -sub R2 {print "===END $rule\n"} -sub F1 {print " ---START $file\n"} -sub F2 {print " ---END $file\n"} #************************************************************ sub rdb_makeB { @@ -4071,6 +4243,7 @@ sub rdb_makeB { local @changed = (); local @disappeared = (); local @no_dest = (); # Non-existent destination files + local @rules_never_run = (); local @rules_to_apply = (); &rdb_classify_rules( \%possible_primaries, @requested_targets ); @@ -4100,6 +4273,7 @@ sub rdb_makeB { print "MakeB: doing pre_primary and primary...\n"; } rdb_for_some( [@pre_primary, $primary], \&rdb_makeB1 ); + if ( ($runs > 0) && ! $too_many_runs ) { $retry_msg = 0; if ( $failure && $newrule_nofile ) { @@ -4132,7 +4306,10 @@ sub rdb_makeB { continue { # Re-evaluate rule classification and accessibility, # but do not change primaries. - &rdb_classify_rules( \%current_primaries, @requested_targets ); + # Problem is that %current_primaries gets altered + my %old_curr_prim = %current_primaries; + &rdb_classify_rules( \%possible_primaries, @requested_targets ); + %current_primaries = %old_curr_prim; &rdb_make_links; } } @@ -4174,11 +4351,14 @@ sub rdb_makeB1 { if ($diagnostics) { print " MakeB1 $rule\n"; } if ($failure & ! $force_mode) {return;} &rdb_clear_change_record; - &rdb_flag_changes_here; -# if ($diagnostics>-1) { print " MakeB1.1 $rule $$Pout_of_date\n"; } + if ( ($$Prun_time == 0) && exists($possible_primaries{$rule}) ) { + push @rules_never_run, $rule; + $$Pout_of_date = 1; + } + else { + &rdb_flag_changes_here; + } - my $return = 0; # Return code from called routine -#?? print "makeB1: Trying '$rule' for '$$Pdest': "; if (!$$Pout_of_date) { #?? if ( ($$Pcmd_type eq 'primary') && (! $silent) ) { # print "Rule '$rule' up to date\n"; @@ -4188,19 +4368,17 @@ sub rdb_makeB1 { if ($diagnostics) { print " remake\n"; } if (!$silent) { print "$My_name: applying rule '$rule'...\n"; - &rdb_diagnose_changes( "Rule $rule: "); + &rdb_diagnose_changes( "Rule '$rule': "); } -##????????????????????????????????????: variable rules_applied not used $rules_applied{$rule} = 1; $runs++; -#?? print "$rule: $$Pcmd_type\n"; # We are applying the rule, so its source file state for when it # was last made is as of now: # ??IS IT CORRECT TO DO NOTHING IN CURRENT VERSION? # The actual run - $return = 0; + my $return = 0; # Return code from called routine # Rule may have been created since last run: if ( ! defined $pass{$rule} ) {$pass{$rule} = 0; } if ( $pass{$rule} ge $max_repeat ) { @@ -4330,6 +4508,7 @@ sub rdb_classify_rules { foreach ( @one_time ) { print " $_\n"; } } } #end diagnostics + } #END rdb_classify_rules #------------------- @@ -4338,7 +4517,7 @@ sub rdb_classify1 { # Helper routine for rdb_classify_rules # Applied as rule_act1 in recursion over rules # Assumes rule context, and local variables from rdb_classify_rules -# print "=========== '$rule' $depth ========== \n"; + #print "??======= '$rule' $depth $state ========== \n"; push @classify_stack, [$state]; if ( exists $possible_one_time{$rule} ) { # Normally, we will have already extracted the one_time rules, @@ -4462,14 +4641,23 @@ sub rdb_ext_cmd1 { #Set character to surround filenames: my $q = $quote_filenames ? '"' : ''; - foreach ($ext_cmd) { - s/%O/$options/g; - s/%R/$q$root_filename$q/g; - s/%B/$q$base$q/g; - s/%T/$q$texfile_name$q/g; - s/%S/$q$source$q/g; - s/%D/$q$dest$q/g; + + %subst = ( + '%O' => $options, + '%R' => $q.$root_filename.$q, + '%B' => $q.$base.$q, + '%T' => $q.$texfile_name.$q, + '%S' => $q.$source.$q, + '%D' => $q.$dest.$q, + '%%' => '%' # To allow literal %B, %R, etc, by %%B. + ); + + my @tokens = split /(%.)/, $ext_cmd; + foreach (@tokens) { + if (exists($subst{$_})) { $_ = $subst{$_}; } } + $ext_cmd = join '', @tokens; + # print "quote is '$q'; ext_cmd = '$ext_cmd'\n"; my ($pid, $return) = &Run_msg($ext_cmd); return $return; @@ -4553,13 +4741,14 @@ sub rdb_primary_run { #************************************************************ sub rdb_clear_change_record { + # Initialize diagnostics for reasons for running rule. @changed = (); @disappeared = (); @no_dest = (); - @rules_to_apply = (); -#??????????????? $failure = 0; -##????????????????????????????????????: variable rules_applied not used - $rules_applied = 0; + @rules_never_run = (); + @rules_to_apply = (); # This is used in recursive application + # of rdb_flag_changes_here, to list + # rules that were out-of-date for some reason. } #END rdb_clear_change_record #************************************************************ @@ -4607,12 +4796,19 @@ sub rdb_file_change1 { #?? " New $new_time, $new_size, $new_md5\n"; my $ext = ext( $file ); if ( ($new_size < 0) && ($$Psize >= 0) ) { - print "Disappeared '$file' in '$rule'\n"; + # print "Disappeared '$file' in '$rule'\n"; push @disappeared, $file; # No reaction is good. #$$Pout_of_date = 1; # ??? 1 Sep. 2008: I do NOT think so, for cusdep no-file-exists issue - $$Pout_of_date = 1; + # ??? 30 Sep 2008: I think I have this fixed. There were other changes + # needed. No-change-flagged is correct. The array @disappeared flags + # files that have disappeared, if I need to know. But having a source + # file disappear is not a reason for a remake unless I know how to + # make the file. If the file is a destination of a rule, that rule + # will be rerun. It may be that the user is changing another source + # in such a way that the disappeared file won't be needed. Before the + # change is applied we get a superfluous infinite loop. return; } if ( ($new_size < 0) && ($$Psize < 0) ) { @@ -4638,9 +4834,9 @@ sub rdb_file_change1 { #************************************************************ -sub rdb_count_changes { - return $#changed + $#disappeared + $#no_dest + $#rules_to_apply + 4; -} #END rdb_count_changes +sub rdb_need_run { + return ($#changed >= 0) || ($#no_dest >= 0) || ($#rules_to_apply >= 0); +} #END rdb_need_run #************************************************************ @@ -4650,26 +4846,31 @@ sub rdb_diagnose_changes { # Precede the message by the optional heading, else by "$My_name: " my $heading = defined($_[0]) ? $_[0] : "$My_name: "; - if ( &rdb_count_changes == 0 ) { - warn "${heading}No changes\n"; - return; - } - warn "${heading}Changes:\n"; - if ( $#changed >= 0 ) { - warn " Changed files, or newly in use since previous run(s):\n"; - foreach (uniqs(@changed)) { warn " '$_'\n"; } + if ($#rules_never_run >= 0) { + warn "${heading}Rules & subrules not known to be previously run:\n"; + foreach (@rules_never_run) { warn " $_\n"; } } - if ( $#disappeared >= 0 ) { - warn " No-longer-existing files:\n"; - foreach (uniqs(@disappeared)) { warn " '$_'\n"; } + if ( ($#changed >= 0) || ($#disappeared >= 0) || ($#no_dest >= 0) ) { + warn "${heading}File changes, etc:\n"; + if ( $#changed >= 0 ) { + warn " Changed files, or newly in use since previous run(s):\n"; + foreach (uniqs(@changed)) { warn " '$_'\n"; } + } + if ( $#disappeared >= 0 ) { + warn " No-longer-existing files:\n"; + foreach (uniqs(@disappeared)) { warn " '$_'\n"; } + } + if ( $#no_dest >= 0 ) { + warn " Non-existent destination files:\n"; + foreach (uniqs(@no_dest)) { warn " '$_'\n"; } + } } - if ( $#no_dest >= 0 ) { - warn " Non-existent destination files:\n"; - foreach (uniqs(@no_dest)) { warn " '$_'\n"; } + elsif ($#rules_to_apply >=0) { + warn "${heading}The following rules & subrules became out-of-date:\n"; + foreach (@rules_to_apply) { warn " '$_'\n"; } } - if ( $#rules_to_apply >= 0 ) { - warn " Rules to apply:\n"; - foreach (uniqs(@rules_to_apply)) { warn " '$_'\n"; } + else { + warn "${heading}No file changes\n"; } } #END rdb_diagnose_changes @@ -4773,6 +4974,7 @@ sub rdb_recurseA { # This routine sets a context for anything recursive, with @heads, # %visited and $depth being set as local variables. + local @heads = (); my $rules = shift; @@ -5180,7 +5382,8 @@ sub show_array { # Then print rest of @_, one item per line preceeded by some space warn "$_[0]\n"; shift; - foreach (@_){ warn " $_\n";} + if ($#_ >= 0) { foreach (@_){ warn " '$_'\n";} } + else { warn " NONE\n"; } } #************************************************************ @@ -5630,6 +5833,47 @@ sub show_cus_dep { #################################################### +sub add_input_ext { + # Usage: add_input_ext( rule, ext, ... ) + # Add extension(s) (specified without a leading period) to the + # list of input extensions for the given rule. The rule should be + # 'latex' or 'pdflatex'. These extensions are used when an input + # file without an extension is found by (pdf)latex, as in + # \input{file} or \includegraphics{figure}. When latexmk searches + # custom dependencies to make the missing file, it will assume that + # the file has one of the specified extensions. + my $rule = shift; + if ( ! exists $input_extensions{$rule} ) { + $input_extensions{$rule} = {}; + } + my $Prule = $input_extensions{$rule}; + foreach (@_) { $$Prule{$_} = 1; } +} + +#################################################### + +sub remove_input_ext { + # Usage: remove_input_ext( rule, ext, ... ) + # Remove extension(s) (specified without a leading period) to the + # list of input extensions for the given rule. The rule should be + # 'latex' or 'pdflatex'. See sub add_input_ext for the use. + my $rule = shift; + if ( ! exists $input_extensions{$rule} ) { return; } + my $Prule = $input_extensions{$rule}; + foreach (@_) { delete $$Prule{$_}; } +} + +#################################################### + +sub show_input_ext { + # Usage: show_input_ext( rule ) + my $rule = shift; + show_array ("Input extensions for rule '$rule': ", + keys %{$input_extensions{$rule}} ); +} + +#################################################### + sub find_dirs1 { # Same as find_dirs, but argument is single string with directories # separated by $search_path_separator @@ -5909,7 +6153,9 @@ sub Run_Detached { if ( "$^O" eq "MSWin32" ){ # Win95, WinNT, etc: Use MS's start command: - return( 0, system( "start $cmd_line" ) ); + # Need extra double quotes to deal with quoted filenames: + # MSWin start takes first quoted argument to be a Window title. + return( 0, system( "start \"\" $cmd_line" ) ); } else { # Assume anything else is UNIX or clone # For this purpose cygwin behaves like UNIX. @@ -6023,9 +6269,38 @@ sub finish_dir_stack { #************************************************************ #************************************************************ -#************************************************************ -#************************************************************ -#************************************************************ -#************************************************************ +# Break handling routines (for wait-loop in preview continuous) + +sub end_wait { + # Handler for break: Set global variable $have_break to 1. + $signal = shift; + # Some systems (e.g., MSWin reset) appear to reset the handler. + # So I'll re-enable it + &catch_break; + $have_break = 1; +} + +#======================== + +sub catch_break { +# Capture ctrl/C and ctrl/break. +# $SIG{INT} corresponds to ctrl/C on LINUX/?UNIX and MSWin +# $SIG{BREAK} corresponds to ctrl/break on MSWin, doesn't exist on LINUX + $SIG{INT} = \&end_wait; + if ( exists $SIG{BREAK} ) { + $SIG{BREAK} = \&end_wait; + } +} + +#======================== + +sub default_break { +# Arrange for ctrl/C and ctrl/break to give default behavior + $SIG{INT} = 'DEFAULT'; + if ( exists $SIG{BREAK} ) { + $SIG{BREAK} = 'DEFAULT'; + } +} + #************************************************************ #************************************************************ -- cgit v1.2.3