From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- support/go/go | 683 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 683 insertions(+) create mode 100644 support/go/go (limited to 'support/go/go') diff --git a/support/go/go b/support/go/go new file mode 100644 index 0000000000..68d550f72f --- /dev/null +++ b/support/go/go @@ -0,0 +1,683 @@ +#!/bin/perl +## go - D. Musliner - RCS $Revision: 3.6 $ +## - 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). +## - reads in user's default info from .gorc in local or home directory. +## - see sub print_help for info. +## - -i option is coolest: note it will turn on slide mode automatically if +## detects a \blackandwhite{} or \colorslides{} command. +## - also automatically puts root_filename into .gorc, so you can run +## 'go -i root_filename' once and only type 'go' forevermore. +## +## - NOTE portions of this code are designed to interface to the BiBDb +## bibliographic database system, which has not yet been released +## outside of UM. +##----------------------------------------------------------------------- +##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. +##----------------------------------------------------------------------- +## The -pvc option is derived from ideas by +## Bernd Nordhausen (bernd@iss.nus.sg) of National University of +## Singapore and Alex Lopez-Ortiz of University of Waterloo +##----------------------------------------------------------------------- + + ## default document processing programs. +$latex = 'latex'; +$bibtex = 'bibtex'; +$slitex = 'slitex'; +$dviselect = 'dviselect'; +$dvips = 'ndvips'; +$lpr = 'lpr'; +$ps_previewer = 'gs'; # gs or ghostview +$dvi_previewer = 'xtex'; # xtex +$makeindex = 'makeindex'; + + ## default flag settings. +$bibtex_mode = 0; # is there a bibliography needing bibtexing? +$index_mode = 0; # is there an index needing makeindex run? +$bibdb_mode = 0; # is the bibliography created by bibdb database manager? +$ran_bibextract = 0; # T if have run bibextract already. + +$root_filename = 'main'; # name of root LaTeX file + +$sleep_time = 2; # time to sleep b/w checks for file changes in -pvc mode + + ## read in .gorc, either in current directory or user's home directory + ## - .gorc simply contains perl code, which can override defaults. +$rcfile = '.gorc'; +if (!(-e $rcfile)) { $rcfile = "$ENV{HOME}/$rcfile"; } +if (-e $rcfile) + { + open(rcfile) || die "Couldn't open rc file [$rcfile]\n"; + while () { eval; } + close(rcfile); + } + +while ($_ = shift) ## process command line args. + { + if (/^-c/) { $cleanup_mode = 1; } + elsif (/^-f/) { $force_mode = 1; } + elsif (/^-g/) { $go_mode = 1; } + elsif (/^-h/) { &print_help; } + elsif (/^-i/) { $auto_include_mode = 1; } + elsif (/^-ps/) { $postscript_mode = 1; } + elsif (/^-pvc/) { $preview_continuous_mode = 1; } + elsif (/^-pv/) { $preview_mode = 1; $postscript_mode = 1;} + elsif (/^-p/) { $print_mode = 1; $preview_mode = 0; } + elsif (/^-s/) { $slide_mode = 1; } + elsif (/^-/) { $lpr_options .= "$_ "; } + elsif (/^[\d:\.\*]/) { $page_options .= "$_ "; } + else { $root_filename = $_; } + } + + ## remove .tex from filename if was given. +if ($root_filename =~ /(\S+)\.tex$/) { $root_filename = $1; } + +if ($auto_include_mode) + { + # get search paths. + $psfigsearchpath = '.'; + $TEXINPUTS = $ENV{'TEXINPUTS'}; + if (!$TEXINPUTS) { $TEXINPUTS = '.'; } + $BIBINPUTS = $ENV{'BIBINPUTS'}; + if (!$BIBINPUTS) { $BIBINPUTS = $TEXINPUTS; } + + # reset all saved flags that old .gorc might have set + # and that we can automatically detect should/not be set. + # Note we dont reset bibdb_mode b/c have no way to detect if it + # is correct or not: preserve that over repeated -i invocations. + $slide_mode =0; + $postscript_mode =0; + $landscape_mode =0; + $bibtex_mode =0; + $index_mode =0; + + $includes = ''; + &scan_for_includes("$root_filename.tex"); + &update_gorc; + } + +if ($cleanup_mode) { &cleanup; } + +if ($cleanup_mode || $auto_include_mode) { exit; } + + ## put root tex file into list of includes. +$includes .= " $root_filename.tex"; + +warn "Go: Processing document in [$root_filename.tex]\n"; + + ## 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"); + +#************************************************************ +# note for page options with slitex, we will create a duplicate root +# file and insert the appropriate \onlyslides command, rather than +# using dviselect to choose pages, since that way we will get headers +# properly used even if dont print first slide. + +if ($slide_mode) + { + if ($page_options) + { + $page_options =~ tr/:/-/; + warn "Go: Selected pages will appear in $root_filename"."_partial.*\n"; + @split_page_options = split(' ',$page_options); + @sorted_page_options = sort increasing @split_page_options; + $page_options = join(',',@sorted_page_options); + print "$page_options\n"; + # now set root filename to new partial one and + # reset page options to null, so process it entirely. + $partial_rootname = "$root_filename"."_partial"; + if (!open(rootfile,"$root_filename.tex")) + { + die "Go: could not open input file [$root_filename.tex]\n"; + } + if (!open(partial_rootfile,">$partial_rootname.tex")) + { + die "Go: could not open output file [$partial_rootname.tex]\n"; + } + while() + { + if (/begin\{document\}/) + { + print partial_rootfile; + print partial_rootfile " \\onlyslides{$page_options}\n"; + } + else { print partial_rootfile; } + } + close partial_rootfile; + close rootfile; + $root_filename = $partial_rootname; + $includes .= " $partial_rootname.tex"; + $page_options = ''; + } + &make_slitex_dvi; + &make_final_dvi; + &make_postscript; + if ($preview_mode) { &make_preview; } + if ($preview_continuous_mode) { &make_preview_continuous; } + &make_printout; + exit; + } +else + { + if ($page_options) # fix up page options, b/c dviselect uses : for + { # ranges, I always use - by mistake, so... + $page_options =~ tr/-/:/; + warn "Go: Selected pages will appear in $root_filename"."_partial.*\n"; + } + &make_latex_dvi; + &make_final_dvi; + &make_postscript; + if ($preview_mode) { &make_preview; } + if ($preview_continuous_mode) { &make_preview_continuous; } + &make_printout; + exit; + } + +#************************************************************ +#### 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"); + + ## - 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) || !(-e "$root_filename.aux")) + { + warn "------------\nRunning first $latex\n------------\n"; + $return = system("$latex $root_filename"); + $changed_dvi = 1; + + if (!$force_mode && $return) + { &exit_msg('Latex encountered an error',1); } + + if ($index_mode) + { + warn "------------\nRunning $makeindex\n------------\n"; + $return = system("$makeindex $root_filename"); + + if (!$force_mode && $return) + { &exit_msg('Makeindex encountered an error'); } + } + } + + $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\n------------\n"; + $return = system("$bibtex $root_filename"); + $bbl_mtime = &get_mtime("$root_filename.bbl"); + } + + if ($bibtex_mode && &check_for_bibtex_errors) + { + if ($bibdb_mode) + { + warn "------------\nRunning bibextract\n------------\n"; + $return = system("bibextract $root_filename"); + $bib_mtime = &get_latest_mtime($bib_files); + warn "------------\nRunning $bibtex\n------------\n"; + $return = system("$bibtex $root_filename"); + $bbl_mtime = &get_mtime("$root_filename.bbl"); + $ran_bibextract = 1; + } + elsif (!$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'); + } + } + + if ($ran_bibextract && &check_for_bibtex_errors && !$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 ) + { + warn "------------\nRunning second $latex\n------------\n"; + $return = system("$latex $root_filename"); + $changed_dvi = 1; + } + + if (!$force_mode && $return) + { &exit_msg('Latex encountered an error',1); } + + if (&check_for_reference_change) + { + warn "------------\nRunning third $latex\n------------\n"; + $return = system("$latex $root_filename"); + $changed_dvi = 1; + } + + 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\n------------\n"; + $return = system("$slitex $root_filename"); + } + if (!$force_mode && $return) + { &exit_msg('Slitex encountered an error'); } +} + +#************************************************************ +# arg1 = name + +sub find_process_id +{ + @ps_output = `ps -x`; + 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[0] eq $_[0]) + { + warn "Go: Reattached to existing previewer, pid=$pid\n"; + return($pid); + } + } + return(0); +} + +#************************************************************ +# run a one-shot postscript previewer. +sub make_preview +{ + if ($page_options) + { exec("$ps_previewer $root_filename"."_partial.ps"); } + else + { exec("$ps_previewer $root_filename.ps"); } +} + +#************************************************************ +# - launch a previewer, then run main guts of go (make_latex_dvi) every few +# seconds and send SIGUSR1 to the previewer if a change is made to dvi. + +sub make_preview_continuous +{ + # get the value of SIGUSR1, defaults to SPARC value. + if (!(do 'signal.ph')) { eval 'sub SIGUSR1 {30;}'; } + # note we only launch a previewer if one isnt already running... + # otherwise we'll send reopen signals to the existing previewer. + unless (($previewer_pid = &find_process_id($dvi_previewer)) || + ($previewer_pid = fork)) + { # in forked child, close off from parent so previewer runs + # on after parent 'go' dies. + setpgrp($$,0); + exec("$dvi_previewer $root_filename.dvi"); + } + + while (1) # loop forever, rebuilding .dvi as necessary. + { + sleep($sleep_time); + &make_latex_dvi; + if ($changed_dvi) { kill &SIGUSR1,$previewer_pid; } + } +} + +#************************************************************ +sub make_printout +{ + return if (!$print_mode); + warn "------------\nPrinting with [$lpr]\n------------\n"; + if ($page_options) + { system("$lpr $lpr_options $root_filename"."_partial.ps"); } + else + { system("$lpr $lpr_options $root_filename.ps"); } +} + +#************************************************************ +sub make_final_dvi +{ + if (!$page_options) + { + warn "\n------------\n"; + warn "[$root_filename.dvi] for [$root_filename.tex] is up to date\n"; + return; + } + warn "------------\nRunning $dviselect\n------------\n"; + system("$dviselect -i $root_filename.dvi -o $root_filename"."_partial.dvi $page_options"); +} + +#************************************************************ +sub make_postscript +{ + return if (!$postscript_mode && !$print_mode); + $ps_mtime = &get_mtime("$root_filename.ps"); + $dvi_mtime = &get_mtime("$root_filename.dvi"); + if ( ($ps_mtime < $dvi_mtime) || $page_options ) + { + warn "------------\nRunning $dvips\n------------\n"; + if ($page_options) + { system("$dvips $root_filename"."_partial.dvi"); } + else { system("$dvips $root_filename"); } + } + else + { + warn "\n------------\n"; + warn "[$root_filename.ps] for [$root_filename.tex] is up to date\n"; + } +} + +#************************************************************ +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 "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 "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 "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 "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.bbe"); ## bibdb imprecise citation translations. + unlink("$root_filename.dvi"); + unlink("$root_filename.ps"); + unlink("$root_filename.ind"); + unlink("$root_filename.idx"); + unlink("$root_filename.ilg"); + unlink("$root_filename.toc"); + unlink("$root_filename"."_partial.dvi"); + unlink("$root_filename"."_partial.ps"); + # .aux files are also made for \include'd files + foreach $include (split(' ',$includes)) + { + $include =~ s/\.[^\.]*$/.aux/; + unlink($include); + } +} + +#************************************************************ +sub print_help +{ + warn "Go: Automatic LaTeX document generation routine\n\n"; + warn "Usage: go [go_options] [lpr_options] [dviselect_options] [filename]\n\n"; + warn " Go_options:\n"; + warn " -c - clean up (remove) all nonessential files\n"; + warn " -f - force continued processing past errors\n"; + warn " -g - process regardless of file timestamps\n"; + warn " -h - print help\n"; + warn " -i - scan for includes & put defaults in .gorc\n"; + warn " -p - print document after generating postscript\n"; + warn " -ps - generate postscript\n"; + warn " -pv - preview document\n"; + warn " -pvc - preview document and continuously update\n\n"; + warn " filename = the root filename of LaTeX document\n\n"; + warn " Other options starting with - are passed to lpr (if using -p).\n"; + warn " Space-separated page lists & colon-separated ranges are passed to dviselect.\n"; + warn " Set default root filename in .gorc with \$root_filename=\'filename\'; or use -i.\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 GO?? + +sub scan_for_includes +{ + local(*FILE); + if (!open(FILE,$_[0])) + { warn "Go: could not open input file [$_[0]]\n"; return; } + while() + { + ($_,$junk) = split('%',$_); # primitive comment removal. + if (/\\include[{\s]+([^\001}]*)[\s}]/) + { + $full_filename = $1; + if ($1 =~ m/\./) + { $full_filename = &find_file($full_filename,$TEXINPUTS); } + else + { $full_filename = &find_file("$full_filename.tex",$TEXINPUTS); } + $includes .= "$full_filename "; + warn " Found include for file [$full_filename]\n"; + &scan_for_includes($full_filename); + } + elsif (/\\input[{\s]+([^\001}]*)[\s}]/) + { + $full_filename = $1; + if ($1 =~ m/\./) + { $full_filename = &find_file($full_filename,$TEXINPUTS); } + else + { $full_filename = &find_file("$full_filename.tex",$TEXINPUTS); } + $includes .= "$full_filename "; + warn " Found input for file [$full_filename]\n"; + &scan_for_includes($full_filename); + } + elsif (/\\blackandwhite{([^\001}]*)}/ || /\\colorslides{([^\001}]*)}/) + { + $slide_mode = 1; + $postscript_mode = 1; + $full_filename = $1; + if ($1 =~ m/\./) + { $full_filename = &find_file($full_filename,$TEXINPUTS); } + else + { $full_filename = &find_file("$full_filename.tex",$TEXINPUTS); } + $includes .= "$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); + $includes .= "$full_filename "; + warn " Found psfig for file [$full_filename]\n"; + } + elsif ( /\\epsfbox{([^}]+)}/ || /\\epsfbox\[[^\]]*\]{([^}]+)}/ || + /\\epsffile{([^}]+)}/ || /\\epsffile\[[^\]]*\]{([^}]+)}/ ) + { + $full_filename = &find_file($1,$TEXINPUTS); + $includes .= "$full_filename "; + warn " Found epsf for file [$full_filename]\n"; + } + elsif (/\\documentstyle[^\000]+landscape/) + { + $landscape_mode = 1; + warn " Detected landscape mode\n"; + } + 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"; + } + } +} + +#************************************************************ +# - puts root name and includes into local .gorc automatically + +sub update_gorc +{ + $rcfile = '>.gorc'; + open(rcfile) || die "Go: Unable to open .gorc for updating\n"; + print rcfile '$root_filename = \'' . "$root_filename';\n"; + print rcfile '$includes = \'' . "$includes';\n"; + print rcfile '$bib_files = \'' . "$bib_files';\n"; + if ($slide_mode) { print rcfile '$slide_mode = 1;' . "\n"; } + if ($postscript_mode) { print rcfile '$postscript_mode = 1;' . "\n"; } + if ($bibtex_mode) { print rcfile '$bibtex_mode = 1;' . "\n"; } + if ($bibdb_mode) { print rcfile '$bibdb_mode = 1;' . "\n"; } + if ($landscape_mode) { print rcfile '$landscape_mode = 1;' . "\n"; } + if ($preview_mode) { print rcfile '$preview_mode = 1;' . "\n"; } + if ($index_mode) { print rcfile '$index_mode = 1;' . "\n"; } + + print rcfile "\$latex = \'$latex\';\n"; + print rcfile "\$bibtex = \'$bibtex\';\n"; + print rcfile "\$slitex = \'$slitex\';\n"; + print rcfile "\$dviselect = \'$dviselect\';\n"; + print rcfile "\$dvips = \'$dvips\';\n"; + print rcfile "\$lpr = \'$lpr\';\n"; + print rcfile "\$ps_previewer = \'$ps_previewer\';\n"; + print rcfile "\$dvi_previewer = \'$dvi_previewer\';\n"; + print rcfile "\$makeindex = \'$makeindex\';\n"; + + close rcfile; + warn " Updated .gorc\n"; +} + +#************************************************************ +# given filename and path, return full name of file, or die if none found. + +sub find_file +{ + foreach $dir (split(':',$_[1])) + { if (-e "$dir/$_[0]") { return("$dir/$_[0]"); } } + die "GO ERROR: 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. + +sub find_file_list +{ + local($return_list) = ''; + foreach $file (split(' ',$_[0])) + { $return_list .= &find_file("$file$_[1]",$_[2]) . " "; } + $return_list; +} + +#************************************************************ +sub increasing { $a - $b; } + +#************************************************************ +sub exit_msg + { + warn "\n------------\n"; + warn "Go: $_[0].\n"; + warn "-- Use the -f option to force complete processing.\n"; + if ($_[1]) + { + warn "Go: restoring last $root_filename.aux file\n"; + system("cp -p $root_filename.aux.bak $root_filename.aux > /dev/null 2>&1"); + } + exit; + } -- cgit v1.2.3