From 2fb8da60f16f82e518a6b86d172c840627e083cc Mon Sep 17 00:00:00 2001 From: gord-fig Date: Wed, 4 Sep 2002 15:05:52 +0000 Subject: [PATCH] Use tex2pdf. --- lustre/doc/Makefile.am | 8 +- lustre/doc/tex2pdf | 3039 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3045 insertions(+), 2 deletions(-) create mode 100755 lustre/doc/tex2pdf diff --git a/lustre/doc/Makefile.am b/lustre/doc/Makefile.am index 1c4f237..a836430 100644 --- a/lustre/doc/Makefile.am +++ b/lustre/doc/Makefile.am @@ -2,7 +2,8 @@ # # This code is issued under the GNU General Public License. # See the file COPYING in this distribution -LYX2PDF = tex2pdf -overwrite +LYX2PDF = $(srcdir)/tex2pdf -overwrite +TEX2PDF = $(srcdir)/tex2pdf -overwrite LYX2PS = lyx --export ps LYX2TEX = lyx --export latex LYX2TXT = lyx --export text @@ -24,7 +25,7 @@ CLEANFILES = *.aux *.tex doc.old/*.aux doc.old/*.tex *.eps VERSIONED = lustre-HOWTO.lyx lustre.lyx doc.old/lustre-HOWTO.lyx doc.old/lustre.lyx GENERATED = $(VERSIONED) lustre-full.tex lustre-chbar.tex -EXTRA_DIST = chbar.sh postbar $(DOCS) $(IMAGES) $(LYXFILES) lustre.bib +EXTRA_DIST = chbar.sh postbar tex2pdf $(DOCS) $(IMAGES) $(LYXFILES) lustre.bib all: $(DOCS) @@ -58,6 +59,9 @@ $(VERSIONED) : %.lyx: %.lin Makefile .lyx.html: @echo $(LYX2HTML) $< && $(LYX2HTML) $< || printf "\n*** Warning: not creating HTML docs; install lyx to rectify this\n" +.tex.pdf: + $(TEX2PDF) $< + .tex.dvi: $(LATEX) $< $(LATEX) $< diff --git a/lustre/doc/tex2pdf b/lustre/doc/tex2pdf new file mode 100755 index 0000000..d2c5738 --- /dev/null +++ b/lustre/doc/tex2pdf @@ -0,0 +1,3039 @@ +#!/usr/bin/perl -w + +# tex2pdf - script for translating latex docs to pdf +# +# Copyright (C) 2000-2002 by Steffen Evers and others +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# The GNU General Public License is also available online: +# http://www.gnu.org/licenses/gpl.html +# +# Thanks a lot to all the people that have already contributed to this project! +# +# The changelog including the credits has become too long. So, I have removed it +# from the script, but it is still available online (see below). +# +# Special thanks to the following people for their contribution +# (see the changelog for details): +# Matej Cepl, Herbert Voss, Nicolas Marsgui, Bruce Foster, Mark van Rossum, +# Matt Bandy, Garrick Chien Welsh, Stacy J. Prowell, Pavel Sedivy, +# Holger Daszler, Olaf Gabler, Ahmet Sekercioglui, Richard, Steffen Macke, +# Rainer Dorsch & friends, Jean-Pierre Chretien, Fernando Perez, +# Ha Duong Minh, Oscar Lopez +# +# Project Homepage: http://tex2pdf.berlios.de +# Developer Homepage: http://developer.berlios.de/projects/tex2pdf +# Mailing lists: http://developer.berlios.de/mail/?group_id=57 +# Changelog: http://tex2pdf.berlios.de/changelog.html +# +# Anyone is invited to help to improve tex2pdf. Therefore any kind of feedback +# is welcome. Maybe you even would like to hack the code and send us your +# changes. This would help a lot and is highly appreciated. Think about it :-) +# Subscribing to the developer mailing list might be a first step (see above). +# +# Send feedback to: tex2pdf-devel@lists.berlios.de +# + +######## Imports + +use File::Basename; +use File::Copy; +use Getopt::Long; +use Sys::Hostname; +use Cwd; +use strict; + +####### global variables + +my $MYRELEASE="3.0.21"; +my $MYHOSTNAME=hostname; +my $MYNAME=basename $0; +my $MYUSER=$ENV{'USER'}; +my $USER_HOME=$ENV{'HOME'}; +if (not $MYUSER) { $MYUSER = 'nobody'; } +if (not $USER_HOME) { $USER_HOME = '/tmp'; } + +my @TMPFILES=(); +my @TMP_TEX_FILES=(); +my $NUM_PARAM_MIN=0; +my $NUM_PARAM_MAX=9; +my @REF_DOCS; +my $MTP_PREAMBLE_FILENAME="preamble.cfg"; +my $MTP_TMP_BASESUFFIX="-mp"; +my @EPS_SUFFIXES=('eps','ps','ps.gz','eps.gz' ); +my $PDF_ORIG_SUFFIX='pdf.orig'; +my @BITMAP_SUFFIXES=( 'jpg', 'png', 'tif' ); + +# (initial) log file of this script +# this log file will be moved to the specified log_dir after configuration +# and the variable will be updated to the new name +my $MYLOGFILE="$USER_HOME/tex2pdf-$$.log"; +my $LOGFILE_VERBOSITY=9; + +### text token for no value +my $NIL="NOVALUE"; +my $UNDEF="undefined"; + +### token for boolean 'false', 'no' +my $NO="no"; +my $FALSE=0; + +### token for boolean 'true', 'yes' +my $YES="yes"; +my $TRUE=1; + +### file to store private parameters +# If you only want to change your private parameters change them there +# default: $HOME/.tex2pdf3rc +my $RC_FILENAME="$USER_HOME/.tex2pdf3rc"; +my $MYRCFILE_VERSION=7; +my $RCVERSION_STRING="rcfile_version"; + +## set global variable configured to prevent access to configuration +# parameters before configuration process is finished +my $CONFIGURED=$FALSE; +my $PRE_CONFIG_VERBOSITY=4; + +########################## NEW PERL CONFIGURATON + +my %CONFIGURATION = (); +my %PARAMETER_LIST = (); +my @PARAMETER_ORDER = (); +my %PARAMETER_TYPES = (); + +## Array index for the various information in each parameter specifcation +## referenced by %PARAMETER_LIST +my $TYPE=0; +my $OPT_ALIAS=1; +my $OPT_SPEC=2; +my $DEF_VALUE=3; +my $DESCRIPTION=4; +my $QUESTION=5; +my $EXPLANATION=6; + +&add_param_type('paper', + [ ['a4paper' , 'a4 paper' ], + [ 'letterpaper', 'letter paper' ], + [ 'legalpaper', 'legal paper' ], + [ 'executivepaper', 'executive paper' ], + [ $NIL, 'do not set value - leave it to hyperref' ] + ] ); + +&add_param_type('color', + [ [ 'yellow', 'LaTeX color yellow' ], + [ 'red', 'LaTeX color red' ], + [ 'green', 'LaTeX color green' ], + [ 'cyan', 'LaTeX color cyan' ], + [ 'blue', 'LaTeX color blue' ], + [ 'magenta', 'LaTeX color magenta' ], + [ 'black', 'LaTeX color black' ], + [ $NIL , 'do not set this value - leave it to hyperref' ] + ] ); + +&add_param_type('destination', + [ [ 'source', 'directory of the LaTeX source document' ] , + [ 'input', 'root directory of referenced material' ], + [ 'custom', 'custom directory as specified' ] + ] ); + +### Option parameters: these parameters have no default value and can not +# be configured interactively, but only as a command line option +# an option parameter is not allowed to have a default value, question or +# explanation +# and all parameter of type action are treated as option parameters +# $key, $type, $def_value, $opt_alias, $opt_spec, $description, $question, $explanation + +&add_param('help', 'action', undef, '|h', '', + 'print a short help text and exit'); + +&add_param('version', 'action', undef, '|v', '', + 'print the version of this script and exit'); + +&add_param('print_config', 'action', undef, '|o', '', + 'print the current configuration and exit'); + +&add_param('configure', 'action', undef, '|c', '', + 'configure all parameters interactivly, store them and exit'); + +&add_param('title', 'text', undef, '|t', '=s', + 'set PDF info title for specified document'); + +&add_param('author', 'text', undef, '|a', '=s', + 'set PDF info author for specified document'); + +&add_param('input_path', 'directory', undef, '', '=s', + 'set path for referenced material in main document'); + +### Full parameters +# parameter type action is not allowed +# $key, $type, $def_value, $opt_alias, $opt_spec, $description, $question, $explanation + +&add_param('logdir', 'directory',"$USER_HOME/tex2pdf-log/", '', '=s', + 'set directory for saving log files', + 'What log directory should be used?', + "The log directory is used to store information about the generation\n" + ."process for later review, e.g. for debugging."); + +&add_param('lyxrc_path', 'directory', "$USER_HOME/.lyx/", '', '=s', + 'set the configuration directory of LyX', + 'What is the directory for your LyX configuration data?', + "If I have to generate a LateX file from a LyX file I need to clear two " + ."temporary\nfiles in your LyX configuration directory. They will " + ."be backuped and normally\ndo not contain any valuable data anyway. If " + ."you do not use LyX, simply leave\nthe default."); + +&add_param('lyx_exec', 'text', "lyx", '', '=s', + 'specify the LyX executable for converting lyx to latex', + 'Which executable should I use for converting LyX docs to LaTeX?', + "I use LyX to generate a LateX file from a LyX file. As you might use\n" + ."several versions of LyX at the same time or do not have it in your path" + ."\nyou can give me the apropriate executable here (e.g. '/usr/bin/lyx')." + ."\nIn most cases the default 'lyx' should be fine."); + +&add_param('debug', 'bool', $NO, '', '!', +'do not delete temporary files after execution and be as verbose as possible', + 'Do you want to debug this script?', + "I will not remove any temporary files. This could cause problems on a " + ."second\nexecution as I might refuse to overwrite these files for security " + ."reasons.\nYou have to remove them manually in this case. Additionally, I " + ."will provide\nas much information during execution as possible."); + +&add_param('delete_pdf_images', 'bool', $NO, '', '!', + 'delete generated PDF image files after execution', + 'Should generated PDF image files be deleted after execution?', + "Pdflatex cannot handle EPS images. Therefore all such images need to be\n" + ."translated to PDF in advance. After a successful generation of the final " + ."PDF \ndocument or after encountering an error I could leave this PDF " + ."images for\n later executions or simply delete them."); + +&add_param('clean_on_abort', 'bool', $YES, '', '!', + 'also delete temporary files after abort', + 'Should temporary files be deleted when aborting?', + "When the generation of the PDF file fails for some reason you might still " + ."want\nto keep already generated temporary files for some reason, e.g. " + ."debugging.\nIf you do not want to keep them set this parameter to 'yes'."); + +&add_param('tmp_base_suffix', 'text', '-pdf', '', '=s', + 'specify the extension of the basename for temporary TeX files', + 'What string should be used as basename suffix for temporary files?', + "I have to find names for my temporary files. Therefore I construct a new " + ."name\nfrom the original filename and this string. Me and various called " + ."applications\nwill then create several files with this constructed " + ."basename and different\nextensions. When cleaning up I will simple " + ."delete all files with the\nconstructed basenames I have used."); + +&add_param('overwrite', 'bool', $NO, '', '!', + 'ignore existence of files with same basename as temporary TeX files', + 'Should I overwrite existing (temporary) files?', + "In spite of the precaution with the appended base suffix, there still " + ."might\nexist files with an identical basename. If you set this option I " + ."will consider\nsuch files as old temporary files and overwrite them " + ."during generation.\nHowever, I will not remove any files with this " + ."constructed basename on the\nclean up. You have to remove them manually."); + +&add_param('clean_logs', 'bool', $YES, '|l', '!', + 'delete all log files in log directory before execution', + 'Should the old log files be removed before execution?', + "I can remove old log files prior to execution. However, you might " + ."experience\nproblems if you run the script on several documents at the " + ."same time. If you\nwant to be on the safe side, answer '$NO'. Than you " + ."have to remove the logs\nmanually from time to time."); + +&add_param('check_commands', 'bool', $YES, '', '!', + 'make sure that required shell commands does exist before start', + 'Should I look for required executables?', + "As I use several different applications for PDF generation you might want " + ."to \nmake sure that they are available before the real work starts."); + +&add_param('destination', 'destination', 'source', '', '=s', + 'specifiy final location of generated PDF document', + 'Where should I store the resulting PDF document?', + "Depending on the application that starts this script (or you if you call " + ."it\ndirectly) you might want to have the resulting PDF document located " + ."at\ndifferent places."); + +&add_param('custom_path', 'directory', $USER_HOME.'/', '|d', '=s', + "specify custom path for 'destination' parameter", + 'What custom directory should be used?', + "When ever you specifiy to store the generated PDF document (command line " + ."or\nconfiguration) in a custom directory I will put it here."); + +&add_param('colorlinks', 'three', $YES, '', '!', + 'activate colored links in PDF doc (hyperref)', + 'Should colors be used for links?', + "I can use different colors for links inside the PDF document.\nYou can " + ."use '$UNDEF' to tell me that you would like to leave this up to\n" + ."independent hyperref configuration."); + +&add_param('paper', 'paper', 'a4paper', '|p', '=s', + 'specify papersize of the PDF doc (hyperref)', + 'What papersize should be used?', + "I can set the papersize of the resulting PDF document"); + +&add_param('citecolor', 'color', 'blue', '', '=s', + 'specify color of citations in PDF doc (hyperref)', + 'What color should be used for citation?', ""); + +&add_param('urlcolor', 'color', 'blue', '', '=s', + 'specify color of URLs in PDF doc (hyperref)', + 'What color should be used for URLs?', ""); + +&add_param('linkcolor', 'color', 'blue', '', '=s', + 'specify color of internal links in PDF doc (hyperref)', + 'What color should be used for normal internal links?', ""); + +&add_param('pagecolor', 'color', 'blue', '', '=s', + 'specify color of links to other pages in PDF doc (hyperref)', + 'What color should be used for page links?', ""); + +&add_param('link_toc_page', 'bool', $YES, '', '!', + 'link table of contents to pages instead of sections (hyperref)', + 'Should TOC be linked to pages?', + "The table of contents of the resulting PDF document is normally linked to " + ."the\ncorresponding section. However, you can also link it to the " + ."corresponding page\ninstead."); + +&add_param('default_title', 'text', $NIL, '', '=s', + 'set default PDF info title', + 'What is the default title?', + "A PDF document contains meta data about itself: the document info.\nOne " + ."of the info fields is the document title. You can set a default value\n" + ."which will be used in the case the script cannot determine a proper " + ."title from\nthe LaTeX document and you have not set one on the command " + ."line.\nYou can use '$NIL' to tell me that you would like to leave this " + ."up to\nindependent hyperref configuration."); + +&add_param('default_author', 'text', $NIL, '', '=s', + 'set default PDF info author', + 'What is the default author?', + "A PDF document contains meta data about itself: the document info.\nOne " + ."of the info fields is the document author. You can set a default value\n" + ."which will be used in the case the script cannot determine a proper " + ."author\nfrom the LaTeX document and you have not set one on the command " + ."line.\nYou can use '$NIL' to tell me that you would like to leave this " + ."up to\nindependent hyperref configuration."); + +&add_param('force_index', 'bool', $NO, '|i', '!', + 'force explicit inclusion of (existing) index in PDF doc', + 'Should the call of makeindex be forced?', + "Older versions of pdflatex have not included the index of a document\n" + ."automatically. If you are missing the index in your document you can " + ."force the\ncall of makeindex on the condition that an index file was " + ."generated."); + +&add_param('makeindex_opts', 'text', '', '', '=s', + 'specify extra options for shell execution of makeindex', + 'What additional options for makeindex should be used?', + "Sometimes, people would like to pass some extra options over to makeindex. " + ."This\nis the right place to do that. Everyone else can leave this empty."); + +&add_param('bibtex', 'three', $NIL, '|b', '!', + 'set bibtex behavior', + 'How should bibtex be used?', + "The bibtex usage can be specified.\nPossible values are: '$YES' (always " + ."run bibtex), '$NO' (never run bibtex)\nand '$UNDEF' (scan tex file for " + ."a bibtex entry and run it if required)."); + +&add_param('gloss', 'three', $NIL, '', '!', + 'set gloss behavior', + 'How should gloss be used?', + "The gloss usage can be specified.\nPossible values are: '$YES' (always " + ."run bibtex on file.gls), '$NO' (never run bibtex on file.gls)\nand '$UNDEF' (scan tex file for " + ."a gloss entry and run it if required)."); + +&add_param('thumbpdf', 'bool', $NO, '|n', '!', + 'generate thumbnails for PDF document', + 'Should PNG thumbnails be created?', + "I can use thumbpdf to include thumbnails of the document pages in the PDF " + ."file.\nThis requires Ghostscript 5.50 or higher."); + +&add_param('ppower', 'bool', $NO, '|w', '!', + 'postprocess PDF document with ppower', + 'Should ppower postprocess the PDF document?', + "I can use ppower to postprocess the PDF " + ."file.\nThis requires ppower 4.0 or higher."); + +&add_param('authorindex', 'bool', $NO, '', '!', + 'generate author index for PDF document', + 'Should authorindex process the PDF document?', + "I can use authorindex to process to include an author index in the PDF " + ."file.\nThis requires authorindex."); + + +&add_param('mtp_preamble', 'bool', $NO, '|r', '!', + "add the file $MTP_PREAMBLE_FILENAME at the current dir to metapost files", + "Should the $MTP_PREAMBLE_FILENAME file be added to the metapost files?", + "I can add $MTP_PREAMBLE_FILENAME to metapost " + ."files.\nThis requires an existing $MTP_PREAMBLE_FILENAME file."); + +&add_param('maxrun', 'integer', 6, '', '=i', + 'specify maximal number of pdflatex runs if problems are detected', + 'What should be the maximum number of runs for pdflatex (1-6)?', ""); + +&add_param('minrun', 'integer', 2, '', '=i', + 'specify minimal number of pdflatex runs if no problems are detected', + 'What should be the minimum number of runs for pdflatex (1-6)?', ""); + +&add_param('verbosity', 'integer', 5, '', '=i', + 'set the level of verbosity', + 'Which level of verbosity do you want (0-9)', + "Different people want different amounts of information about what the " + ."script\nactually does. Therefore you can adjust the verbosity to your " + ."personal needs\nby setting this parameter to a value from 0 to 9. 0 " + ."means no output at all\nand 9 means maximal output."); + +&add_param('pdftex_opts', 'text', '', '', '=s', + 'specify extra options for shell execution of pdflatex', + 'What additional options for pdflatex should be used?', + "Sometimes, people would like to pass some extra options over to pdflatex. " + ."This\nis the right place to do that. Everyone else can leave this empty."); + +&add_param('hyperref_args', 'text', '', '', '=s', + 'specify extra arguments for the hyperref package', + 'What additional arguments should be passed to the hyperref package?', + "Sometimes, people would like to pass some extra options over to hyperref. " + ."This\nis the right place to do that. Everyone else can leave this empty."); + +# the following parameter types should be set now: +# 'color' => \@VALUES, +# 'destination' => \@VALUES, +# 'paper' => \@VALUES, +# 'action' => undef, +# 'three' => undef, +# 'bool' => undef, +# 'integer' => undef, +# 'text' => undef, +# 'directory' => undef + +##### Functions ########################################### + +### handle a status report with a given priority level +# write it to the log file if log file if configuration is done +# write it to stdout if verbosity is set lower or equal +# +# The following priority levels exist: +# 1: minimal fatal error messages +# 2: additional information about fatal error +# 3: non-fatal error message +# 4: warning +# 5: major step of the process +# 6: minor step of the process +# 7: progress report of minor step +# 8: long status report from called applications +# 9: debug info +# +# parameter 1: priority level +# parameter 2: list of output strings +# return value: none + +sub report { + my $level; + my $verbosity; + my $log_verbosity; + my @output; + + if (@_ < 2 ) { + @output = ( "Oppss! Report function got only 1 argument!" ); + $level = 9; + } else { + ($level, @output) = @_; + } + + if($CONFIGURED) { + if( ¶m_value('debug') eq $NO ) { + $verbosity = ¶m_value('verbosity'); + $log_verbosity = $LOGFILE_VERBOSITY; + } else { + $verbosity = 9; + $log_verbosity = 9; + } + } else { + $verbosity = $PRE_CONFIG_VERBOSITY; + $log_verbosity = $LOGFILE_VERBOSITY; + } + + if ( $level <= $log_verbosity ) { + open LOGFILE, ">> $MYLOGFILE"; + print LOGFILE @output,"\n"; + close LOGFILE; + } + + if( $level <= $verbosity ) { + print @output,"\n"; + } +} + +### process system command and do the appropriate reports +# parameter 1: the system command to process +# parameter 2: flag - TRUE: abort on failure, FALSE: continue on failures +# parameter 3: priority level for output of system command +# parameter 4: specific failure message +# return value: TRUE - success, FALSE - failure + +sub system_command { + my $command = $_[0]; + my $fatal_failure= $_[1]; + my $output_priority = $_[2]; + my $fail_message = $_[3]; + my $system_out; + + $system_out = `$command 2>&1`; + + if ($?) { + if ($fatal_failure) { + &report(2, $system_out) if ($system_out); + &abort($fail_message.": $!"); + } else { + &report($output_priority, $system_out) if ($system_out); + &report(3, $fail_message.": $!"); + } + return $FALSE; + } + + return $TRUE; +} + +### Index of the first occurence of a string in an array +# parameter 1: text +# parameter 2: list +# return value: index or -1 if not element of the array + +sub array_index { + my ($text, @list) = @_; + + if(!defined($text)) { + &report(9, "Oppss! Cannot compare nothing."); + return -1; + } + + foreach (0..$#list) { + if ( $list[$_] eq $text ) { return $_; } + } + + return -1; +} + +### extract the last N lines of a text file +# abort on failures +# parameter 1: file to read +# parameter 2: N - number of lines to print (undef/0: all lines) +# return value: last N lines + +sub file_tail { + my $file_name = $_[0]; + my $no_of_lines = defined($_[1]) ? $_[1] : 0; + my @cache=(); + + &check_file($file_name); + open(TAIL_SOURCE, "<$file_name") + or &abort("Could not read file $file_name: $!"); + + if($no_of_lines == 0) { + # use entire file + while() { + if(!$_) { $_="\n"; } + push(@cache, $_); + } + } else { + # only last N lines + + # fill up cache + while(@cache < $no_of_lines and ) { + if(!$_) { $_="\n"; } + push(@cache, $_); + } + + # always cache the last N lines up to the end of the file + while() { + if(!$_) { $_="\n"; } + shift(@cache); + push(@cache, $_); + } + } + + close TAIL_SOURCE; + + return @cache; +} + +### return all lines of FILE which match match regexp EXPR +# parameter 1: FILE - file to read +# parameter 2: EXPR - regular expression to match +# parameter 3: true: exit on first occurence, otherwise get all (default: false) +# return value: array of matching lines + +sub grep_file { + my $file_name = $_[0]; + my $regexp = $_[1]; + my $first_only = $_[2] ? $TRUE : $FALSE; + my @result=(); + + ### open file and abort if not possible + &check_file($file_name); + open(GREP_SOURCE, "<$file_name") + or &abort("Could not read file $file_name: $!"); + + while() { + if(m#$regexp#) { + push(@result, $_); + if($first_only) { last; } + } + } + + close GREP_SOURCE; + return @result; +} + +### Removing all temporary files + +sub clean_up { + &report(6, "Removing temporary files ..."); + foreach (@TMPFILES) { + unlink($_) if(-f $_); + } + + foreach (@TMP_TEX_FILES) { + # make sure that we have a good tex file name in order + # to avoid unintended removals + if( $_ ne "" and -f $_.'.tex' ) { + unlink glob($_.".???"); + } else { + &report(3, "Bad file in temp tex files list: $_"); + } + } +} + +### Output of all temp files + +sub print_temp_files { + if (scalar @TMPFILES > 0) { + print "Stored the following explicit temporary files:\n"; + foreach (@TMPFILES) { + if (-f $_) { + print "> ".$_."\n"; + } else { + print "> ".$_." (does not exist)\n"; + } + } + print "\n"; + } + + if (scalar @TMP_TEX_FILES > 0) { + print "Stored the following temporary TeX base names:\n"; + foreach (@TMP_TEX_FILES) { + if( $_ ne "" and -f $_.'.tex' ) { + print "> ".$_.": "; + foreach my $file (glob($_.".???")) { + print basename($file)." "; + } + print "\n"; + } else { + print "> ".$_.": bad file for temp TeX file\n"; + } + } + print "\n"; + } +} + +### exit with an error message + +sub abort { + &report(1, @_); + if ( $CONFIGURED and ¶m_value('clean_on_abort') eq $YES + and ¶m_value('debug') eq $NO) { + &clean_up; + } else { + &print_temp_files; + } + &report(2, "Aborting ..."); + exit 1; +} + +### Check for required command with 'which'; abort if not found +# parameter $1: command to check +# parameter $2: remark if specified command is not found + +sub checkCommand { + my $command = $_[0]; + my $message = $_[1]; + my $which_output; + + $which_output = `which $command 2>&1`; + chomp $which_output; + $_ = $which_output; + s|^(.*/)?([^/]+)$|$2|; + + if ( $_ ne $command ) { + &report(2, "\n$which_output"); + &report(1, "\nRequired command '$command' seems not to be in your path."); + if ( defined($message) ) { + &report(2, "$message"); + } + &report(2, "Aborting ..."); + exit 1; + } +} + +###################### Generic configuration functions + +### interactively answer a question with yes or no +# parameter 1: question +# parameter 2: default value (not set means $NIL) +# parameter 3: yes: allow undefined as third value +# no : only yes/no allowed (default) +# return value: the given answer + +sub question_ynu { + my $user_input; + my $question = $_[0]; + my $default = defined($_[1]) ? $_[1] : $NIL; + my $undef_allowed = $_[2]; + my $response = undef; + + if (defined($undef_allowed) and $undef_allowed eq $YES) { + $undef_allowed = $TRUE; + } else { + $undef_allowed = $FALSE; + } + + if( $default =~ /^y(es)?/i ) { + $question .= ' [y]: '; + $default = $YES; + } elsif ( $default eq $NIL and $undef_allowed ) { + $question .= ' [u]: '; + $default = $NIL; + } else { + $question .= ' [n]: '; + $default = $NO; + } + while (! defined($response)) { + print $question; + $user_input = ; + chomp($user_input); + + if( $user_input =~ /^y(es)?/i ) { + $response=$YES; + } elsif ( $user_input =~ /^no?/i ) { + $response=$NO; + } elsif ( $user_input =~ /^u(ndef(ined)?)?/i and $undef_allowed ) { + $response=$NIL; + } elsif ( $user_input eq "" ) { + $response=$default; + } else { + print "Please respond with y(es)"; + print ", u(ndefined)" if($undef_allowed); + print " or n(o).\n"; + } + } + return $response; +} + +### interactively input a positive integer number +# parameter 1: question +# parameter 2: default value +# parameter 3: min value +# parameter 4: max value +# return value: the input number + +sub input_number { + my $question = $_[0]; + my $default = $_[1]; + my $min_limit = $_[2]; + my $max_limit = $_[3]; + my $response= undef; + + while (! defined($response)) { + print "$question [$default]: "; + my $user_input = ; + chomp($user_input); + + if ($user_input eq "") { + $response=$default; + } else { + $_ = $user_input; + if (s/^([0-9]+)$/$1/ and $_ >= $min_limit and $_ <= $max_limit ) { + $response = $_; + } else { + print "Invalid input. Please enter a positve integer from $min_limit to $max_limit.\n"; + } + } + } + return $response; +} + +### interactively choose between several given values +# parameter 1: question +# parameter 2: default value +# parameter 3: reference to an array of possible values arrays +# return value: the chosen value + +sub choose_value { + my ($question, $default, $enum_array_ref)=@_; + my $default_no=1; + my $chosen_no; + my @possible_values = @$enum_array_ref; + my @value_array; + my $value_key; + my $value_output; + + print "$question\n"; + foreach (0..$#possible_values) { + my $no = $_ + 1; + @value_array = @{$possible_values[$_]}; + $value_key = $value_array[0]; + $value_output = $value_array[1]; + + print "$no) " . $value_output . "\n"; + if ( $default eq $value_key ) { $default_no=$no; } + } + + $chosen_no=&input_number("Please enter the corresponding number", $default_no, 1, $#possible_values); + + @value_array = @{$possible_values[$chosen_no - 1]}; + $value_key = $value_array[0]; + return $value_key; +} + +### interactively answer a question +# parameter 1: question +# parameter 2: current value +# return value: the new value + +sub input_text { + my $question=$_[0]; + my $default=$_[1]; + my $response= undef; + + print "Suggested value: $default\n"; + if ( &question_ynu("Do you want to keep this value?", $YES) eq $YES ) { + $response= $default; + } else { + print "$question "; + my $user_input = ; + chomp($user_input); + + $response = $user_input; + } + return $response; +} + +##### Make sure that specified file exists and is readable; abort if missing +# parameter 1: file to check +# parameter 2: remark if check fails on specified file + +sub check_file { + my $file = $_[0]; + my $message = defined($_[1]) ? $_[1] : "Required file cannot be accessed!"; + + if ( ! -f $file ) { + &report(2, "\nSorry. I cannot find '$file'."); + &abort($message); + } elsif ( ! -r $file ) { + &report(2, "\nSorry. File '$file' exists, but is not readable."); + &abort($message); + } +} + +##### Make sure that specified directory exists and is writable +# parameter 1: directory to check +# parameter 2: remark if check fails on specified directory +# parameter 3: if yes, creation is allowed +# return value: $TRUE - ok; $FALSE - error + +sub check_dir { + my $directory = $_[0]; + my $message = defined($_[1]) ? $_[1] : "Not a valid path!"; + my $allow_creation = defined($_[2]) ? $_[2] : $NO; + + if ( index($directory, "/") != 0 ) { + &report(3, "\nSorry. '$directory' is not an absolute path."); + &report(3, $message); + return $FALSE; + } elsif ( ! -d $directory ) { + # dir does not exist + if ( $allow_creation eq $YES ) { + # creation allowed + &report(4, "\nI cannot find '$directory'. Try to create it."); + if ( mkdir($directory, 0755) ) { + &report(7, "Creation of '$directory' was successful."); + return $TRUE; + } else { + &report(3, "Creation of '$directory' failed."); + &report(3, $message); + return $FALSE; + } + } else { + # creation not allowed + &report(3, "\nSorry. Directory '$directory' does not exist."); + &report(3, $message); + return $FALSE; + } + } elsif ( ! -w $directory ) { + # dir not writable + &report(3, "\nSorry. Directory '$directory' exists, but is not writable."); + &report(3, $message); + return $FALSE; + } + return $TRUE; +} + +### interactively input a directory for data storage (absolute path) +# parameter 1: question +# parameter 2: default dir +# parameter 3: if 'yes' allow creation of directory +# return value: the specified directory + +sub input_dir { + my $question = $_[0]; + my $default_dir = $_[1]; + my $allow_creation = defined($_[2]) ? $_[2] : $NO; + my $user_input; + my $response = undef; + + if ( defined($default_dir) and index($default_dir, "/") == 0 + and ( (! -d $default_dir and $allow_creation eq $YES) + or (-d $default_dir and -w $default_dir) ) ) { + $question .= " [$default_dir]: "; + } else { + $default_dir = undef; + $question .= ": "; + } + + while (! defined($response)) { + print "$question"; + $user_input = ; + chomp($user_input); + + if( $user_input eq "" and defined($default_dir) ) { + # user has only pressed and thereby confirmed default value + if( ! &check_dir($default_dir,"Default value was not valid. Please, give different directory.", $allow_creation ) ) { + # default dir does not exist and cannot be created + $default_dir = undef; + $question = "$_[0]: "; + } else { + # valid default dir has already existed or has been created + $response = $default_dir; + } + } else { + # user has given a directory + if( &check_dir($user_input,"This is not a valid directory!", $allow_creation) ) { + $response = $user_input; + } + } + } + return $response; +} + +#### add a new parameter type with corresponding additional data argument +#### parameters types +# parameter 1: type key +# parameter 2: additonal data for the type +# e.g. for enum type: reference to list of arrays +# return value: none + +sub add_param_type { + + my ($type, $scalar_argument) = @_; + + $PARAMETER_TYPES{$type} = $scalar_argument; +} + +#### add a new parameter to the adminstrated parameters +#### +# parameter 1: key +# parameter 2: type +# parameter 3: default value +# parameter 4: alias for command line options +# parameter 5: specification for command line options +# parameter 6: short description for help +# parameter 7: question +# parameter 8: explanation +# return value: none + +sub add_param { + + my ($key, $type, $def_value, $opt_alias, $opt_spec, $description, $question, $explanation) = @_; + + $CONFIGURATION{$key} = $def_value; + + $PARAMETER_LIST{$key} = [ $type, $opt_alias, $opt_spec, $def_value, $description, $question, $explanation ]; + + push(@PARAMETER_ORDER, $key); + + if (! exists $PARAMETER_TYPES{$type}) { + $PARAMETER_TYPES{$type} = undef; + } +} + +### get the value of an existing parameter +# parameter 1: a parameter key +# return value: reference to the array of possible value entries +# (undef if not valid) + +sub type_enum_array { + my $key = $_[0]; + my $values_ref; + + if(! exists($PARAMETER_TYPES{$key})) { + &abort("unknown type: $key"); + } + + $values_ref = $PARAMETER_TYPES{$key}; + + if(ref $values_ref ne 'ARRAY') { + $values_ref = undef; + } + + return $values_ref; +} + +### get the value of an existing parameter +# parameter 1: a parameter key +# return value: parameter value + +sub param_value { + my $key = $_[0]; + my $current_value; + + exists($CONFIGURATION{$key}) + or &abort("unknown parameter: $key"); + $current_value = $CONFIGURATION{$key}; + + return $current_value; +} + +### get the type of an existing parameter +# parameter 1: a parameter key +# return value: parameter value + +sub param_type { + my $key = $_[0]; + my $def_ref; + my $type; + + exists($PARAMETER_LIST{$key}) + or &abort("unknown parameter: $key"); + $def_ref = $PARAMETER_LIST{$key}; + $type = @{$def_ref}[$TYPE]; + + exists($PARAMETER_TYPES{$type}) + or &abort("parameter has unknown type: $key (type: $type)"); + + return $type; +} + +### determine if the given parameter is a full one (instead of option only) +# parameter 1: a parameter key +# return value: $TRUE - full parameter; $FALSE otherwise + +sub full_param { + my $key = $_[0]; + my @param_def; + + exists($PARAMETER_LIST{$key}) + or &abort("unknown parameter: $key"); + @param_def = @{$PARAMETER_LIST{$key}}; + + if ($param_def[$TYPE] ne 'action' and defined ($param_def[$QUESTION])) { + return $TRUE; + } else { + return $FALSE; + } +} + +### get the output needed for configuration of this parameter +# parameter 1: a parameter key +# return value: array - (description, explanation, question) + +sub param_config_output { + my $key = $_[0]; + my @param_def; + my $description; + my $explanation; + my $question; + + exists($PARAMETER_LIST{$key}) + or &abort("unknown parameter: $key"); + @param_def = @{$PARAMETER_LIST{$key}}; + $description = $param_def[$DESCRIPTION]; + $explanation = $param_def[$EXPLANATION]; + $question = $param_def[$QUESTION]; + + return ($description, $explanation, $question); +} + +### set the value of an existing parameter +# parameter 1: a parameter key +# parameter 2: the new value +# return value: none + +sub set_param_value { + my $key = $_[0]; + my $new_value = $_[1]; + + exists($CONFIGURATION{$key}) + or &abort("unknown parameter: $key"); + $CONFIGURATION{$key}=$new_value; +} + +### get option specifier for getopts +# parameter 1: option key +# return value: string - option specifier + +sub option_specifier { + my $key = $_[0]; + my $spec; + my $def_ref; + + exists($PARAMETER_LIST{$key}) + or &abort("unknown parameter: $key"); + $def_ref = $PARAMETER_LIST{$key}; + $spec = $key . ${$def_ref}[$OPT_ALIAS] . ${$def_ref}[$OPT_SPEC]; + + return $spec; +} + +### handle an option +# parameter 1: a parameter/option key +# parameter 2: the option value +# return value: none + +sub handle_option { + my $key = $_[0]; + my $value = $_[1]; + my $type; + + $type = ¶m_type($key); + + if ($type eq 'action') { + &handle_action_opt($key, $value); + } elsif ( $type eq 'bool' or $type eq 'three') { + my $bool_value = $value ? $YES : $NO; + &set_param_value($key, $bool_value); + } elsif ( $type eq 'directory') { + if (! &check_dir($value)) { + &report(2, "$key requires an existing writable directory as an absolute path."); + &abort("Illegal value: $value"); + } + &set_param_value($key, $value); + } elsif (defined(&type_enum_array($type))){ + &set_enum_param($key, $value); + } else { + &set_param_value($key, $value); + } +} + +### handle all action options +# parameter 1: a option key +# parameter 2: the option value +# return value: none + +sub handle_action_opt { + my $key = $_[0]; + my $value = $_[1]; + + if ($key eq 'help') { + &print_help; + + } elsif ($key eq 'version') { + &print_version; + + } elsif ($key eq 'configure') { + if ( -f $RC_FILENAME ) { + &read_configuration($RC_FILENAME); + } + &configure; + &write_configuration($RC_FILENAME); + &print_configuration; + + } elsif ($key eq 'print_config') { + if ( -f $RC_FILENAME ) { + &read_configuration($RC_FILENAME); + } + &print_configuration; + + } else { + &print_usage; + exit 1; + } + exit 0; +} + +### set a variable by a command line option to a possible values; abort on error +# parameter 1: parameter key +# parameter 2: value + +sub set_enum_value { + my ($key, $value) = @_; + my $type; + my $enum_array_ref; + my @allowed_values=(); + + $type = ¶m_type($key); + $enum_array_ref = &type_enum_array($type); + &abort("Internal error: No value array for parameter $key.") + if(!defined($enum_array_ref)); + + ### find out if the given value is allowed + foreach my $value_array_ref (${$enum_array_ref}) { + if(${$value_array_ref}[0] eq $value) { + ### found it, so it is okay! + &set_param_value($key, $value); + return; + } + } + + ### value is not listed, so not allowed + ### make a list of all allowed values + foreach my $value_array_ref (${$enum_array_ref}) { + push(@allowed_values, ${$value_array_ref}[0]); + } + + &report(2, "\n$key allows: " . @allowed_values . ".\n"); + &abort("Illegal value: $value"); +} + +### configure an existing parameter interactively +# parameter 1: a parameter key +# return value: none + +sub config_param { + my $key = $_[0]; + my $type; + my $new_value; + my $current_value; + my $description; + my $explanation; + my $question; + + ### get required information about this parameter + $type = ¶m_type($key); + $current_value = ¶m_value($key); + ($description, $explanation, $question) = ¶m_config_output($key); + + ### tell the user the facts + print "\n\n--------------------------------------------\n"; + print "Parameter: ".$key."\n"; + print $description."\n\n"; + print $explanation."\n\n" if($explanation ne ""); + + ### ask him what he wants + if ($type eq 'bool') { + $new_value=&question_ynu($question, $current_value, $NO); + } elsif ($type eq 'three') { + $new_value=&question_ynu($question, $current_value, $YES); + } elsif ($type eq 'directory') { + $new_value=&input_dir($question, $current_value, $YES); + } elsif ($type eq 'text') { + $new_value=&input_text($question, $current_value); + } elsif ($type eq 'integer') { + $new_value=&input_number($question, $current_value, + $NUM_PARAM_MIN, $NUM_PARAM_MAX); + } else { + my $enum_array_ref; + + $enum_array_ref=&type_enum_array($type); + if (! defined($enum_array_ref)) { + &abort("Do not know how to configure this parameter: $key (type: $type)"); + } + + $new_value=&choose_value($question,$current_value,$enum_array_ref); + } + + ### store his choice + &set_param_value($key, $new_value); +} + +### save configuration in rc file +# parameter 1: file name +# return value: none + +sub write_configuration { + my $file_name = $_[0]; + my $date; + + open(RCFILE, ">$file_name") or + &abort("Could not open configuration file for writing ($file_name)"); + select RCFILE; + + $date = `date`; + chomp($date); + + print "# Configuration file for $MYNAME V$MYRELEASE\n"; + print "# Generated $date by $MYUSER on $MYHOSTNAME\n"; + print "$RCVERSION_STRING=$MYRCFILE_VERSION\n"; + + foreach my $key (@PARAMETER_ORDER) { + my $value = $CONFIGURATION{$key}; + if(&full_param($key)) { + print $key.'='.$value."\n"; + } + } + + print "# EOF\n"; + select STDOUT; + close RCFILE; +} + +### print the configuration parameters + +sub print_configuration { + print "\nConfiguration for $MYNAME V$MYRELEASE\n"; + + foreach my $key (@PARAMETER_ORDER) { + my $value = $CONFIGURATION{$key}; + if(&full_param($key)) { + print $key.'='.$value."\n"; + } + } + + print "\n"; +} + +### load parameters from rc file +# parameter 1: file name +# return value: version of read rc file or 0 if no version given + +sub read_configuration { + my $file_name = $_[0]; + my $file_version= 0; + + &check_file($file_name, "Could not access configuration file"); + open(RCFILE, "<$file_name") or + &abort("Could not open configuration file for reading ($file_name)"); + + while () { + chomp; + if( /^([^#=]+)=(.*)$/ ) { + if( exists $CONFIGURATION{$1} ) { + $CONFIGURATION{$1} = $2; + } elsif ( $1 eq $RCVERSION_STRING ) { + $file_version = $2; + } else { + print "Ignoring unknown parameter in RC file: $1=$2\n"; + } + } + } + close RCFILE; + + return $file_version; +} + +### print script version + +sub print_version { + print "\n$MYNAME Version $MYRELEASE\n"; +} + +###################### Specific functions (for use with this script only) + +### print usage of command + +sub print_usage { + print "\nUsage: $MYNAME [OPTIONS] DOCUMENT.lyx\n"; + print " $MYNAME [OPTIONS] DOCUMENT[.tex]\n\n"; + print " $MYNAME -c | --configure modify/set up configuration\n"; + print " $MYNAME -h | --help give a short help\n"; + print " $MYNAME -o | --print_config print current configuration\n"; + print " $MYNAME -v | --version print my version\n\n"; +} + +### print command help + +sub print_help { + &print_version; + &print_usage; + + foreach my $key (@PARAMETER_ORDER) { + my @param_def = @{$PARAMETER_LIST{$key}}; + my $description = $param_def[$DESCRIPTION]; + my $takes_value = $param_def[$OPT_SPEC] =~ /[=:]/ ? $TRUE : $FALSE; + my $negation = $param_def[$OPT_SPEC] eq '!' ? $TRUE : $FALSE; + my $alias = $param_def[$OPT_ALIAS]; + + $alias =~ s/\|(([a-zA-Z])(\||$))/ | -$1/g; + $alias =~ s/\|(([a-zA-Z][a-zA-Z0-9_]+)(\||$))/ | --$1/g; + + print "--"; + print "[no]" if($negation); + print $key.$alias; + print " VALUE" if ($takes_value); + print ":\n ".$description."\n\n"; + } + print "\n"; +} + +### configure all tex2pdf parameters interactively +# parameters: none +# return value: none + +sub configure { + + print "\n--------------------------------------------------------\n"; + print "\n***** Configuration for $MYNAME *****\n\n"; + print "The following answers are considered as defaults in later "; + print "executions\n"; + print "of $MYNAME. You can change these values by using the option "; + print "--configure \nagain."; + print "Additionally, all command-line options override these settings.\n"; + print "Many parameters can be set to '$NIL' or '$UNDEF'. This means that NO"; + print "\nvalue at all (not even an empty value) is passed over to the "; + print "called\napplication (e.g. latex package hyperref).\n"; + + $NUM_PARAM_MIN=1; + $NUM_PARAM_MAX=9; + + foreach my $key (@PARAMETER_ORDER) { + if(&full_param($key)) { + &config_param($key); + } + } + + print "\nConfiguration for $MYNAME finished.\n\n"; +} + +### check if the most important executables are installed on the system +# parameters: none + +sub check_commands { + my $exec_epstopdf; + ### check for which command + &checkCommand("which","You can switch off all command checks to fix this."); + + ### pdftex executables + # Homepage: http://tug.org/applications/pdftex + &checkCommand("pdflatex","See pdftex homepage for details: http://tug.org/applications/pdftex"); + &checkCommand("epstopdf","See pdftex homepage for details: http://tug.org/applications/pdftex"); + $exec_epstopdf = `which epstopdf`; + chomp $exec_epstopdf; + if (&grep_file($exec_epstopdf, "-dCompatibilityLevel=1\\.1", $TRUE) > 0) { + &report(9, "Good: ghostscript option '-dCompatibilityLevel=1.1' detected " + ."in\n'$exec_epstopdf'."); + } else { + &report(4, "\nWARNING: no ghostscript option '-dCompatibilityLevel=1.1' " + ."in\n'$exec_epstopdf'.\n" + ."You might run into trouble with the conversions of bitmaps.\n" + ."Adjusting epstopdf or setting the environment variable GS_OPTIONS " + ."to \n".'"$GS_OPTIONS -dCompatibilityLevel=1.1" before calling this ' + ."script\nmight help in this case.\n"); + } + + if ( ¶m_value('thumbpdf') eq $YES ) { + &checkCommand("thumbpdf","You can switch off thumbpdf support to fix this."); + } + + if ( ¶m_value('ppower') eq $YES ) { + &checkCommand("ppower","You can switch off ppower support to fix this."); + } + + ### authorindex perl script + if ( ¶m_value('authorindex') eq $YES ) { + &checkCommand("authorindex","You can switch off authorindex support to fix this."); + } + + ### bibtex executable + if ( ¶m_value('bibtex') ne $NO or ¶m_value('gloss') ne $NO) { + &checkCommand("bibtex","You can switch off BibTeX support to fix this."); + } +} + +#### generate the tmp file name from the original tex filename +#### and make sure that they are not the same +# parameter 1: orignal filename (with or without a path or .tex) +# parameter 2: path for the tmp file (default: doc path) +# return value: tmp name + +sub reserve_tmp_texname { + my $original_name = $_[0]; + my $tmp_path = $_[1]; + my $tmp_base_suffix = ¶m_value('tmp_base_suffix'); + my $overwrite = ¶m_value('overwrite'); + my $original_path; + my $original_base; + my $suffix; + my $pathed_tmp_base; + my @existing_files; + + # separate path, base and suffix + ($original_base,$original_path,$suffix) = fileparse($original_name, '\.tex'); + + # set the path of the tmp file + if(!$tmp_path) { + $tmp_path=$original_path; + } else { + $tmp_path .= '/' if( $tmp_path ne "" and ! ($tmp_path =~ m#/$#) ); + } + + # abort if no absolute path is given + if( index($tmp_path, "/") != 0 ) { + &abort("Internal error: Illegal argument for reserve_tmp_texname:". + "Given file has no absolute path: $original_name"); + } + + # make sure that tmp_base_suffix is set correctly + if($tmp_base_suffix eq "") { + &abort("Temporary filename base suffix is empty."); + } + + $pathed_tmp_base = $tmp_path.$original_base.$tmp_base_suffix; + + # make sure no file with this base exists in this directory + @existing_files = glob "$pathed_tmp_base.*"; + if (@existing_files != 0) { + &report(3, "Problems detected while reserving temporay file name!\n", + "In this directory are already files with this basename.\n", + "A list of the conflicting, existing files:\n", + join("\n", @existing_files), "\n"); + if ($overwrite eq $YES) { + &report(4, "As you have activated the parameter 'overwrite' I will " + ."continue.\n", + "However, in order to protect the existing files I will not\n", + "delete any files with this basename at the final clean-up."); + } else { + &report(2, "You could activate the parameter 'overwrite' or remove ", + "the\n corresponding files in order to avoid these problems."); + &abort("No temporary name found for $original_name."); + } + } else { + push(@TMP_TEX_FILES, $pathed_tmp_base); + } + + return $pathed_tmp_base.$suffix; +} + +### generate LaTeX file from LyX document with LyX itself +# parameter ($1): Lyx document +# parameter ($2): Latex document + +sub generate_tex_file { + my $lyx_doc = $_[0]; + my $tex_doc = $_[1]; + my $lyx_dir; + my $lyx_output; + my $lyx_exec=¶m_value('lyx_exec'); + + $lyx_dir = ¶m_value('lyxrc_path'); + $lyx_dir .= '/' if( ! ($lyx_dir =~ m#/$#) ); + $lyx_dir .= '/' if( ! ($lyx_dir =~ m#/$#) ); + + ### Check if LyX file can be accessed + &check_file($lyx_doc,"Cannot read the specified LyX document!"); + + ### Check if LaTeX file exists and is newer than the LyX file + if ( -f $tex_doc and -M $tex_doc < -M $lyx_doc ) { + &report(4, "\nLaTeX file is newer than LyX document ($lyx_doc).\n", + "Using existing TeX file: $tex_doc\n", + "Remove it to force its new generation."); + } else { + ### export LaTeX file with LyX (needs a display!) + &checkCommand($lyx_exec, "Cannot generate LaTeX document without LyX!"); + &report(6, "\nExporting LaTeX file"); + + ### move some files out of the way that stop LyX from exporting + foreach my $file ($lyx_dir."lyxpipe.out",$lyx_dir."lyxpipe.in",$tex_doc) { + if ( -f $file ) { rename($file, $file.'~'); } + } + + $lyx_output = `$lyx_exec --export latex $lyx_doc 2>&1`; + + ### check if LaTeX file now really exists + if ( ! -f $tex_doc ) { + &report(2, "Lyx Output:\n$lyx_output"); + &report(2, "\nSorry. I cannot find '$tex_doc'."); + &abort("The LaTeX document was not generated by LyX!"); + } else { + &report(8, "Lyx Output:\n$lyx_output"); + } + } +} + +#### search TeX document for a certain text tag (e.g. author, title) +# parameter 1: file to parse +# parameter 2: full TeX tag name +# return value: list of the contents strings of all matching tags + +sub extract_tag_contents { + my $source=$_[0]; + my $tag_name=$_[1]; + my $contents; + my @results=(); + my $error_message="Could not read TeX document to extract $tag_name"; + + &check_file($source, $error_message.'.'); + open(EXTRACT_SOURCE, "<$source") or + &abort($error_message." ($source)."); + + + while() { + ### ignore comments + s/(^|[^\\])%.*/$1/; + # ignore \thanks{} + s/\\thanks\{.*?\}//g; + # change \and to and + s/\\and/ and/g; + + $contents .= $_; + } + + close EXTRACT_SOURCE; + + $_ = $contents; + + # add contents of all occurences of this tag in a line to result list + while ( /\\($tag_name)(\[[^]]*?\])*?{+([^{}]*?)}/s ) { + my $text = $3; + $_ = $'; + # remove newlines + $text =~ s/\n//g; + $text="" if (!defined($text)); + push(@results, $text); + } + + return @results; +} + +#### search for filenames in given TeX Tag in entire document +### skip all comments and duplicates while parsing +# parameter 1: file to parse +# parameter 2: full TeX tag name +# parameter 3: reference to a list of possible filename suffixes (without '.') +# parameter 4: regexp for suffix to ignore when specified in TeX file +# (undef if not used) +# return value: list of identified files + +sub identify_files { + my $source=$_[0]; + my $tag_name=$_[1]; + my @suffixes=@{$_[2]}; + my $ignore_suffix=$_[3]; + my @matched_tags; + my @found_files=(); + my $regexp_suffixes; + + # create one large regexp from given suffixes and escape dots in them + $regexp_suffixes= '.('.join('|', @suffixes).')'; + $regexp_suffixes =~ s/\./\\./g; + + @matched_tags = &extract_tag_contents($source, $tag_name); + + foreach my $tag_contents (@matched_tags) { + my $path; + my $base; + my $suffix; + my $kpse_result; + my $working_dir = cwd."/"; + + ($base,$path,$suffix) = fileparse($tag_contents, $regexp_suffixes); + + # if a suffix is specified in the tag_contents handle it as requested + # + # 1. $suffix: TRUE if $suffix is defined and not of zero length + # means: a valid suffix has been found in the filename + # 2. defined($ignore_suffix): TRUE if $ignore_suffix is defined + # means: a regexp for suffixes to be ignored has been specified as + # parameter4 + # 3. $suffix =~ /$ignore_suffix/: TRUE if $suffix matches the regexp + # means: the suffix in the filename is wanted to be ignored + # + # The IF statement will be executed when: + # a valid suffix has been found in the filename (1) + # AND regexp for suffixes to be ignored has NOT been specified (not 2) + # OR + # a valid suffix has been found in the filename (1) + # AND regexp for suffixes to be ignored has been specified (2) + # AND the suffix in the filename is NOT wanted to be ignored (not 3) + # + # The stuff that is executed if the entire IF statement is TRUE does the + # following: accept the found suffix and consider it as the only possible + # file name. + if($suffix and not (defined($ignore_suffix) and $suffix =~ /$ignore_suffix/)){ + $kpse_result=`kpsewhich $tag_contents`; + # print warning and skip this tag if kpsewhich could not find it + if (!$kpse_result) { + &report(4, "WARNING - Could not identify referenced file:\n", + " Ignoring '$tag_contents'."); + next; + } + } else { + # if there is a '.' in the basename assume that this is a reference + # to a file of another type and skip it + if( $base =~ /\./ ) { + &report(9, "Found an unknown extension. Ignoring '$tag_contents'."); + next; + } + + # search for all possible files with allowed suffixes + foreach my $allowed_suffix (@suffixes) { + if (not $allowed_suffix =~ /[\]\)\(\|\[\\]/ ) { + # suffix is not a regexp, but a real extension + my $possible_file= $path.$base.'.'.$allowed_suffix; + $kpse_result=`kpsewhich $possible_file`; + if ($kpse_result) { + last; + } + } + } + } + + # if kpsewhich could not find any file with an allowed suffix + # assume that this reference is of a different type and skip it + # quietly + if (!$kpse_result) { + &report(9, "No suitable file found. Ignoring '$tag_contents'."); + next; + } + + # expand '.' in kpsewhich output to the current path + $kpse_result =~ s#^\./#$working_dir#; + + # remove trailing newline + chomp($kpse_result); + + # add file to the found file list if it is not already on it + if( &array_index($kpse_result, @found_files) < 0 ) { + push(@found_files, $kpse_result); + } + } + + return @found_files; +} + +### Build a list of all files which are included from the root file. +# This function recurses, and is maybe smart enough to detect cycles. +# Be sure to set REF_DOCS to the empty string prior to calling this. +# parameter 1: tex file to start with +# no return value +# result is appended to global variable @REF_DOCS + +sub get_file_list { + my $source = $_[0]; + my @imports = (); + + # This is the cycle avoidance logic. + if ( &array_index($source, @REF_DOCS) < 0 ) { + # Make sure the file can be accessed + &check_file($source, "Included TeX file seems not to be available. Path problem?"); + + # Save the argument in the list of files. + push(@REF_DOCS, $source); + + # Get the list of files included by the argument. + @imports=&identify_files($source, 'include|input', ['tex']); + + # Recurse. + foreach my $file (@imports) { + if( ! ($file =~ /\.tex$/) ) { $file .= '.tex'; } + &get_file_list($file); + } + } +} + +### do the required modifications in the LaTeX preamble +# parameter 1: original preamble from the source file +# lines before \begin{document} tag (without this tag) +# parameter 2: reference to hyperref parameter list +# return value: adjusted preamble + +sub adjust_preamble { + my $preamble = $_[0]; + my $hyperref_params_ref = $_[1]; + my $extra_code; + my $result; + + $_ = $preamble; + + # protect pdflatex execution mode + s/^(\\batchmode)$/% $1/m; + + # insert a4paper in the documentclass when a4wide is used + # fixes problem that hyperref defaults to letter otherwise + if ( /^[^%]*\\usepackage(\[widemargins\])?\{(a4|a4wide)\}/m ) { + # check if package parameters with [] brackets are present + if ( not s/^(\\documentclass\[.*?)\]/$1,a4paper]/m ) { + s/^\\documentclass/$&\[a4paper\]/m; + } + } + + ### collect additional LaTeX code + + $extra_code = "\n" . '\usepackage{pslatex}' . "\n"; + + if ( ¶m_value('thumbpdf') eq $YES ) { + $extra_code .= '\usepackage{thumbpdf}' . "\n"; + } else { + $extra_code .= "% no thumbpdf support\n"; + } + +# if ( ¶m_value('ppower') eq $YES ) { +# $extra_code .= '\usepackage{mpmulti}' . "\n"; +# } else { +# $extra_code .= "% no ppower support\n"; +# } + + if ( ¶m_value('authorindex') eq $YES ) { + $extra_code .= '\usepackage[pages]{authorindex}' . "\n"; + $extra_code .= '\let\cite=\aicite' . "\n"; + } else { + $extra_code .= "% no authorindex support\n"; + } + + $extra_code .= '\makeatletter' . "\n"; + $extra_code .= '\usepackage[' . join(',', @$hyperref_params_ref) + . ']{hyperref}' . "\n"; + $extra_code .= '\makeatother' . "\n"; + + ### insert the extra LaTeX code directly after documentclass + m/^(\\documentclass)(\[[^]]*\])?(\{.*\})/m; + return $` . $& . $extra_code . $'; +} + +### adjust all filenames in the LaTeX code to the tmp files +# parameter 1: original LaTeX code from the source file +# return value: adjusted code + +sub adjust_filenames { + my $code = $_[0]; + my $tmp_suffix = ¶m_value('tmp_base_suffix'); + my $result; + + $_ = $code; + + # cut off the suffix of eps, ps, *.gz and pstex graphics + s/((\\includegraphics)(\[[^]]*?\])?(\{[^}]+?))\.(e?ps|pstex|e?ps\.gz)\n?\}/$1}/sg; + + # replace the suffix 'pstex_t' with 'pdf_t' + s/(\\input\{[^}]+?\.)pstex_t\n?\}/$1pdf_t}/sg; + + if ( ¶m_value('mtp_preamble') eq $NO ) { + # cut off the suffix of mmp graphics + s/(\\multiinclude(\[[^]]*?\])?\{[^}]+?)\.mmp\n?\}/$1}/sg; + } else { + # replace the suffix '.#' with '-mp.#' + s/(\\includegraphics(\[[^]]*?\])?\{[^}]+?)\.(\d+?)\n?\}/$1$MTP_TMP_BASESUFFIX\.$3}/sg; + + # replace the suffix '.#' with '-mp.#' + s/(\\convertMPtoPDF(\[[^]]*?\])?\{[^}]+?)\.(\d+?)\n?\}/$1$MTP_TMP_BASESUFFIX\.$3}/sg; + + # cut off optional suffix '.mmp' and append '-mp' in any case + s/(\\multiinclude(\[[^]]*?\])?\{[^}]+?)(\.mmp)?\n?\}/$1$MTP_TMP_BASESUFFIX}/sg; + } + + # insert the tmp_suffix in tex filenames + # I assume that files with no extension are TeX files as well; correct? + s#(\\(input|include)\{([^}]*?/)?[^}/.]+?)((\.tex)?\n?\})#$1$tmp_suffix$4#sg; + + return $_; +} + +### Convert given tex file to the temp tex file we need for pdftex +### major task is to change the reference in the tex files to the +### corresponding tmp files +# parameter 1: tex source file +# parameter 2: tex tmp file +# parameter 3: reference to hyperref parameter list or +# 'undef' if preamble should not be changed + +sub convert_tex2tmp { + my $source = $_[0]; + my $target = $_[1]; + my $hyperref_params_ref = $_[2]; + my $contents; + my $preamble; + my $body; + my $adjust_preamble = defined($hyperref_params_ref) ? $YES : $NO; + my $read_err_msg = "Could not read original TeX document to generate temporary document"; + + ### open source and target file + &check_file($source, $read_err_msg . '.'); + open(SOURCE_FILE, "<$source") or + &abort($read_err_msg . " ($source)."); + + ### read in the LaTeX source file + $contents = ""; + while() { + $contents .= $_; + } + + close SOURCE_FILE; + + ### prepare the LaTeX code for PDF generation + if ( $adjust_preamble eq $YES ) { + $contents =~ m/^ *\\begin\{document\} *$/m; + $preamble = $`; + $body = $&.$'; + $preamble = &adjust_preamble($preamble, $hyperref_params_ref); + $preamble = &adjust_filenames($preamble); + } else { + $preamble = ""; + $body = $contents; + } + + $body = &adjust_filenames($body); + + ### write the new LaTeX target file + open(TARGET_FILE, ">$target") or + &abort("Could not open file to write temporary TeX document ($target)."); + + print TARGET_FILE $preamble.$body; + + close TARGET_FILE; +} + +### Convert the given EPS image to PDF +# parameters $1: EPS image filename with absolute path +# return value: none + +sub convert_eps2pdf { + my $image = $_[0]; + my $image_path; + my $image_base; + my $image_name; + my $suffix; + my $image_target; + my $zipped = 0; + my $dummy; + + ($image_base,$image_path,$suffix) = fileparse($image, '\.eps', '\.ps', '\.pstex', '\.gz'); + if ($suffix eq "\.gz") { + $zipped = 1; + ($image_base,$dummy,$suffix) = fileparse($image_base, '\.eps', '\.ps', '\.pstex'); + } + $image_name = $image_base . $suffix; + $image_target = $image_path . $image_base . '.pdf'; + + #### check if image file really exists + #&check_file($image, "Could not convert referenced image."); + + ### return if image directory is not writeable + if (! -w $image_path) { + &report(4, "WARNING - Image directory not writable: $image_path\n", + " Skipping '$image_name', assume you have converted it manually."); + return; + } + + if ( ! -f $image_target or -M $image_target > -M $image ) { + &report(7, "Converting image $image_name to $image_target ...\n"); + if ($zipped > 0) { + &system_command("gunzip -c $image | epstopdf -f -outfile=$image_target", + $TRUE, 8, "epstopdf failed on $image_name"); + } else { + &system_command("epstopdf -outfile=$image_target $image", + $TRUE, 8, "epstopdf failed on $image_name"); + } + if (¶m_value('delete_pdf_images') eq $YES) { + push(@TMPFILES, $image_target); + } + } else { + &report(7, "$image_base.pdf newer than $image_name, conversion skipped..."); + } +} + +### Convert the given PSTEX_T file to PDF_T +# parameters 1: PSTEX_T filename with absolute path +# return value: none + +sub convert_pstex2pdf { + my $pstex_file = $_[0]; + my $pstex_path; + my $pstex_base; + my $pstex_name; + my $suffix; + my $pstex_target; + my @eps_images; + + ($pstex_base,$pstex_path,$suffix) = fileparse($pstex_file, ('\.pstex_t')); + $pstex_name = $pstex_base . $suffix; + $pstex_target = $pstex_path . $pstex_base . '.pdf_t'; + + #### check if image file really exists + #&check_file($pstex_file, "Could not convert referenced file."); + + ### return if directory is not writeable + if (! -w $pstex_path) { + &report(4, "WARNING - Directory not writable: $pstex_path\n", + " Skipping '$pstex_name', assume you have converted it manually."); + return; + } + + # descend into file + &report(7, "Converting file $pstex_name ...\n"); + + # find included EPS image(s) + @eps_images=&identify_files($pstex_file, 'includegraphics', + ['pstex', 'pstex\.gz']); + + # create .pdf_t file + &convert_tex2tmp($pstex_file, $pstex_target, undef); + + # put tmp file in the tmp file list + push(@TMPFILES, $pstex_target); + + # convert image(s) to pdf + foreach my $image (@eps_images) { + &convert_eps2pdf($image); + } +} + +### Convert the given MP image to PDF +# parameters $1: MP image filename with absolute path +# return value: none + +sub convert_mp2pdf { + my $image = $_[0]; + my $image_path; + my $image_base; + my $image_name; + my $suffix; + my $image_target; + my $image_src; + my @mps_fig=(); + my $mp_fig; + + ($image_base,$image_path,$suffix) = fileparse($image, '\.mp|\.mmp'); + $image_name = $image_base . $suffix; + $image_src=$image_path . $image_base . $suffix; + + @mps_fig= &grep_file($image_path.$image_name,'beginfig',$TRUE); + $_=$mps_fig[0]; + /(\d)/; + $mp_fig=$1; + if (¶m_value('mtp_preamble') eq $YES) { + $image_target = $image_path . $image_base . $MTP_TMP_BASESUFFIX . '.' . $mp_fig; + $image_name=$image_base.$MTP_TMP_BASESUFFIX.$suffix; + } else { + $image_target = $image_path . $image_base . '.' . $mp_fig; + } + + #### check if image file really exists + #&check_file($image, "Could not convert referenced image."); + + ### return if image directory is not writeable + if (! -w $image_path) { + &report(4, "$MYNAME: WARNING - Image directory not writable: $image_path\n", + " Skipping '$image_name', assume you have converted it manually."); + return; + } + + if ( ! -f $image_target + or (-M $image_target > -M $image_src) + or ( ( ¶m_value('mtp_preamble') eq $YES) + and (-M $image_target > -M $image_path.$MTP_PREAMBLE_FILENAME) ) ) { + &report(7, "Converting image $image_name ...\n"); + my $working_dir = cwd."/"; + chdir("$image_path") or &abort("cannot cd to $image_path($!)"); + if ( ¶m_value('mtp_preamble') eq $YES ) { + &modify_mp_file($image_base,$suffix); + } + &system_command("mpost $image_name", + $TRUE, 8, "mpost failed on $image_name"); + chdir("$working_dir") or &abort("cannot cd to $working_dir($!)"); + if (¶m_value('delete_pdf_images') eq $YES) { + push(@TMPFILES, $image_target); + } + } else { + if ( ¶m_value('mtp_preamble') eq $YES ) { + &report(7, "$image_base$MTP_TMP_BASESUFFIX.$mp_fig newer than $image_base$suffix, conversion skipped..."); + } else { + &report(7, "$image_base.$mp_fig newer than $image_base$suffix, conversion skipped..."); + } + } +} + +### Convert the given MP image to PDF +# parameters $1: MP image filename with absolute path +# return value: none + +sub modify_mp_file { + my $base=$_[0]; + my $suffix=$_[1]; + my $preamble_file=$MTP_PREAMBLE_FILENAME; + + my $mp_source=$base.$suffix; + my $mp_target=$base.$MTP_TMP_BASESUFFIX.$suffix; + + ### open source and target file + open(SOURCE_FILE, "<$mp_source") or + &abort("Could not open $mp_source to add $preamble_file ($mp_source)."); + + open(TARGET_FILE, ">$mp_target") or + &abort("Could not open $mp_target to add $preamble_file ($mp_source)."); + + open(PREAMBLE_FILE, "<$preamble_file") or + &abort("Could not open $preamble_file to be added to metapost files ($mp_source)."); + + ### set target file as stdout + select TARGET_FILE; + print 'verbatimtex' . "\n"; + print '%&latex' . "\n"; # This forces metapost to use latex in the compilation + print '\documentclass[english]{article}' . "\n"; # we have to decide if this sentence goes in preamble.cfg or here + # english must be added + # to preamble in order to + # make work mpost, why ??? + while() { + print $_ + } + print '\begin{document}' . "\n"; # we have to decide if this sentence goes in preamble.cfg or here + print 'etex' . "\n"; + while() { + print $_ + } + print 'verbatimtex' . "\n"; + print '\end{document}' . "\n"; + print 'etex' . "\n"; + + ### set STDOUT as stdout again + select STDOUT; + + ### close files + close SOURCE_FILE; + close TARGET_FILE; + close PREAMBLE_FILE; + +} + + +### Convert included images to pdf +# parameter 1: tex source file +# no return value + +sub convert_images { + my $tex_source=$_[0]; + my @pstex_file_list; + my @image_list; + my @mp_image_list; + my @mmp_image_list; + my @major_suffixes; + my $ignore_regexp; + + &report(6, "\nConverting images referenced in $tex_source."); + + ##### Get images of major type from the source file + @major_suffixes = (@BITMAP_SUFFIXES, $PDF_ORIG_SUFFIX, @EPS_SUFFIXES); + $ignore_regexp = '.('.join('|',@EPS_SUFFIXES).')'; + $ignore_regexp =~ s/\./\\./g; + + &report(6, "\nScanning for major image types (".join(', ',@major_suffixes)."):"); + @image_list = &identify_files($tex_source,'includegraphics', + \@major_suffixes, $ignore_regexp ); + + if ( @image_list > 0 ) { + &report(7, join("\n", @image_list)); + } else { + &report(7, "None."); + } + + ##### Get PSTEX_T files from the source file + &report(6, "\nScanning for PSTEX_T files (.pstex_t):"); + @pstex_file_list=&identify_files($tex_source, 'input', ['pstex_t']); + if ( @pstex_file_list > 0 ) { + &report(7, join("\n", @pstex_file_list)); + } else { + &report(7, "None."); + } + + ##### Get MP images from the source file + &report(6, "\nScanning for MP images (.mp):"); + @mp_image_list=&identify_files($tex_source, + 'convertMPtoPDF|includegraphics',['mp','(\d+)'],'\.(\d+)'); + # FIXME + # fixed for now by ignoring strange extension in identify_files + # + # the above could cause problems as identify_files is expecting a list of + # real extensions and not of regexps + # maybe the only way to fix this is to adjust identify_files to ignore + # invalid extension when testing them with kpsewhich + # ALTERNATIVE: design identify_files to use preffered_suffixes instead + # of ignore_suffixes + + if ( @mp_image_list > 0 ) { + &report(7, join("\n", @mp_image_list)); + } else { + &report(7, "None."); + } + + ##### Get MMP images from the source file + &report(6, "\nScanning for MMP images (.mmp):"); + @mmp_image_list=&identify_files($tex_source,'multiinclude',['mmp']); + if ( @mmp_image_list > 0 ) { + &report(7, join("\n", @mmp_image_list)); + } else { + &report(7, "None."); + } + + ### Convert EPS images to PDF, copy pdf.orig image files to pdf, + ### and simply ignore all other + if ( @image_list > 0) { + my $handled_suffixes; + + &report(6, "\nProcessing images of major types:"); + + # create one large regexp from suffixes and escape dots in them + $handled_suffixes = '.('.join('|',(@EPS_SUFFIXES, $PDF_ORIG_SUFFIX)).')'; + $handled_suffixes =~ s/\./\\./g; + + foreach my $image (@image_list) { + my $path; + my $base; + my $suffix; + ($base,$path,$suffix) = fileparse($image, $handled_suffixes); + if (not $suffix) { + &report(7, "No special handling required for image: $base$suffix"); + } elsif ($suffix eq ('.'.$PDF_ORIG_SUFFIX) ) { + my $image_target = $path.$base.'.pdf'; + + if ( ! -f $image_target or -M $image_target > -M $image ) { + &report(7, "Create temporary PDF file from original: $base$suffix"); + copy($image, $image_target) + or &abort("Could not create tmp file: $!"); + if (¶m_value('delete_pdf_images') eq $YES) { + push(@TMPFILES, $image_target); + } + } else { + &report(7, "$base.pdf newer than $base$suffix, copy skipped ..."); + } + } else { + &convert_eps2pdf($image); + } + } + } + + ### Convert all PSTEX_T files to PDF_T + if ( @pstex_file_list > 0 ) { + &report(6, "\nConverting pstex_t docs to pdf_t docs"); + foreach my $image (@pstex_file_list) { + &convert_pstex2pdf($image); + } + } + + ### Convert all MP images to PDF + if ( @mp_image_list > 0) { + &report(6, "\nConverting MP images to PDF"); + foreach my $image (@mp_image_list) { + &convert_mp2pdf($image); + } + } + + ### Convert all MMP images to PDF + if ( @mmp_image_list > 0) { + &report(6, "\nConverting MMP images to PDF"); + foreach my $image (@mmp_image_list) { + &convert_mp2pdf($image); + } + } + + &report(6, "\nFinished converting for ${tex_source}."); +} + +### run pdflatex +# parameter 1: LaTeX file without extension +# parameter 2: log-file where the full out put is stored +# return value: 0 - no errors (no rerun); 1 - errors (rerun required) + +sub run_pdflatex { + my $texfile=$_[0]; + my $logfile=$_[1]; + my @errors=(); + my $exit_status=0; + my $extra_options=¶m_value('pdftex_opts'); + + if( !defined($extra_options) or $extra_options eq $NIL ) { + $extra_options = ""; + } + + &report(7, "Running pdflatex. This may take a while.\n"); + system("pdflatex --interaction nonstopmode $extra_options $texfile > $logfile 2>&1"); + $exit_status=$?; + &report(7, "Pdflatex finished. Errors:"); + + ### extract all errors and warnings from the log file + @errors = &grep_file($logfile, '(Emergency stop|Error|Warning).*:'); + + ### make sure thumbpdf package does not spoil rerun detection + ### as it will be processed very last + if(grep(/Package thumbpdf/, @errors) == @errors) { @errors=(); } + + if ( @errors != 0 or $exit_status != 0 ) { + if ( grep(/Emergency stop/, @errors) != 0 ) { + &report(2, &file_tail($logfile,10)); + &report(2, "\nSee $logfile for details."); + &abort("Fatal error occured. I am lost."); + } + if( @errors != 0 ) { + &report(8, @errors); + } else { + &report(8, &file_tail($logfile,10)); + } + &report(7, "\nSee $logfile for details."); + return $FALSE; + } else { + &report(7, "None detected (log file: $logfile)."); + return $TRUE; + } +} + +#### run bibtex if BIBTEX=$YES or a bibliography tag is found +# included tex files are not parsed for a bibliography +# parameter 1: filename of the aux file without .aux suffix +# parameter 2: log-file where the full out put is stored + +sub handle_bibtex { + my $auxfile=$_[0]; + my $logfile=$_[1]; + my $run_bibtex=$FALSE; + my $bibtex_param=¶m_value('bibtex'); + + if ( $bibtex_param eq $YES ) { + $run_bibtex=$TRUE; + &report(7, "BibTeX parameter set to '$YES':"); + } else { + &report(7, "Checking for BibTeX bibliography in main document: "); + if( &grep_file($auxfile.'.tex', '^[^%]*\\\\bibliography{') != 0) { + $run_bibtex=$TRUE; + &report(7, "Bibliography detected."); + } else { + if ( @REF_DOCS > 0 ) { + &report(7, "Checking for BibTeX bibliography in included documents:"); + foreach my $file (@REF_DOCS) { + if( &grep_file($file, '^[^%]*\\\\bibliography{') != 0) { + $run_bibtex=$TRUE; + &report(7, "Bibliography detected."); + } else { + &report(7, "No bibliography detected in $file."); + } + } + } else { + &report(7, "No bibliography detected."); + } + } + } + + if ( $run_bibtex ) { + my @errors=(); + my $exit_status=0; + + &report(7, "Running bibtex. This may take a while.\n"); + system "bibtex $auxfile > $logfile"; + $exit_status=$?; + &report(7, "Bibtex finished. Errors:"); + + ### extract all errors and warnings from the log file + @errors=&grep_file($logfile, 'error message'); + + if ( @errors != 0 or $exit_status != 0 ) { + &report(4, &file_tail($logfile)); + &report(4, "\nYou can switch off BibTeX support by setting the bibtex parameter accordingly."); + } else { + &report(7, "None detected (log file: $logfile)."); + } + } +} + +#### run bibtex on file.gls if BIBTEX=$YES or a bibliography tag is found +# included tex files are not parsed for a bibliography +# parameter 1: filename of the aux file without .aux suffix +# parameter 2: log-file where the full out put is stored + +sub handle_gloss { + my $auxfile=$_[0]; + my $logfile=$_[1]; + my $run_gloss=$FALSE; + my $gloss_param=¶m_value('gloss'); + my $glsfile=$auxfile.'.gls'; + + if ( $gloss_param eq $YES ) { + $run_gloss=$TRUE; + &report(7, "Gloss parameter set to '$YES':"); + } else { + &report(7, "Checking for Gloss bibliography in main document: "); + if( &grep_file($auxfile.'.tex', '^[^%]*\\\\printgloss{') != 0) { + $run_gloss=$TRUE; + &report(7, "Gloss bibliography detected."); + } else { + if ( @REF_DOCS > 0 ) { + &report(7, "Checking for Gloss bibliography in included documents:"); + foreach my $file (@REF_DOCS) { + if( &grep_file($file, '^[^%]*\\\\printgloss') != 0) { + $run_gloss=$TRUE; + &report(7, "Gloss bibliography detected."); + } else { + &report(7, "No gloss database detected in $file."); + } + } + } else { + &report(7, "No gloss database detected."); + } + } + } + if ( $run_gloss ) { + my @errors=(); + my $exit_status=0; + + &report(7, "Running bibtex on $glsfile. This may take a while.\n"); + system "bibtex $glsfile > $logfile 2>&1"; + $exit_status=$?; + &report(7, "Bibtex finished. Errors:"); + + ### extract all errors and warnings from the log file + @errors=&grep_file($logfile, 'error message'); + + if ( @errors != 0 or $exit_status != 0 ) { + &report(4, &file_tail($logfile)); + &report(4, "\nYou can switch off Gloss support by setting the gloss parameter accordingly."); + } else { + &report(7, "None detected (log file: $logfile)."); + } + } +} + +#### run thumbpdf command to make thumbnails +# more informations: /usr/share/texmf/doc/pdftex/thumbpdf/readme.txt +# parameter 1: LaTeX file without extension +# parameter 2: log-file where the full out put is stored + +sub run_thumbpdf { + my $texfile=$_[0]; + my $logfile=$_[1]; + my $exit_status=0; + + &report(7, "\nCreating thumbnails with 'thumbpdf'\n"); + &system_command("thumbpdf $texfile", $FALSE, 8, + "thumbpdf failed.\n" + ."I will continue, but maybe there will not be thumbs in the PDF doc."); + + if ( -f 'thumbpdf.log' ) { + move('thumbpdf.log', $logfile); + &report(7, "\nSee $logfile for details."); + } + + ### store possible tmp files + push(@TMPFILES, glob 'thumb???.png'); + push(@TMPFILES, 'thumbpdf.pdf'); + push(@TMPFILES, 'thumbdta.tex'); + push(@TMPFILES, $texfile.'.tpt'); +} + + +#### run ppower command to make presentations +# more informations: +# parameter 1: LaTeX file without extension +# parameter 2: log-file where the full out put is stored + +sub run_ppower { + my $texfile=$_[0]; + my $logfile=$_[1]; + my $exit_status=0; + my $infile; + my $outfile; + my $texfile_base; + my $texfile_path; + my $texfile_suffix; + + ##### Getting document name, suffix and path + ($texfile_base,$texfile_path,$texfile_suffix) = fileparse($texfile,¶m_value('tmp_base_suffix')); + + $infile=$texfile_base.'.pdf'; + $outfile=$texfile_base.'_p4.pdf'; + + &report(7, "\nPostprocessing PDF file with 'ppower'\n"); + if(&system_command("ppower $infile $outfile", $FALSE, 8, + "ppower failed.\nI will continue, " + ."but maybe there will not be pause effects in the PDF doc.")) { + &report(7, "\nThe postprocessed pdf file is: $outfile\n"); + } + + if ( -f 'ppower.log' ) { + move('ppower.log', $logfile); + &report(7, "See $logfile for details."); + } +} + +#### run authorindex command to obtain an author index +# more informations: +# parameter 1: LaTeX file without extension +# parameter 2: log-file where the full out put is stored + +sub run_authorindex { + my $texfile=$_[0]; + my $logfile=$_[1]; + my $exit_status=0; + + &report(7, "\nProcessing file with 'authorindex'\n"); + &system_command("authorindex $texfile", $FALSE, 8, + "authorindex failed.\nI will continue, " + ."but maybe there will not be an author index in the PDF doc."); + + if ( -f 'authorindex.log' ) { + move('authorindex.log', $logfile); + &report(7, "\nSee $logfile for details."); + } + +} + + +##### read and analyse configuration and options and adjust basic variables +##### accordingly +#### The following sources are considered (last value overrides previous) +## 1. general configuration (global variables in the script) +## 2. private configuration (in user's RC file) +## 3. command line options +# parameters: none +# return value: given document argument + +sub adjust_configuration { + my $valid_rcfile = $FALSE; + my %opt_specs =(); + + ### Check number of arguments + if ( @ARGV == 0 ) { + &report(1, "\nI need at least one argument!"); + &print_usage; + exit 1; + } + + ##### command line options and private configuration files handling + + ### set parameters from rc file + if ( -f $RC_FILENAME ) { + my $rcfile_version; + $rcfile_version = &read_configuration($RC_FILENAME); + if( $rcfile_version == $MYRCFILE_VERSION ) { + $valid_rcfile = $TRUE; + } elsif ( $rcfile_version == 0 ) { + &report(4, "Could not determine version of read RC file."); + } else { + &report(4, "Version of read RC file ($rcfile_version) and ", + "this script ($MYRCFILE_VERSION) differs."); + } + } + + ### scan parameters + foreach (keys %PARAMETER_LIST) { + $opt_specs{&option_specifier($_)} = \&handle_option; + } + if(! GetOptions(%opt_specs)) { + &print_usage; + &abort("An error occured while processing command line options"); + } + + if( ! $valid_rcfile ) { + &report(3,"No valid configuration file found. Please run '$MYNAME " + ."--configure'.\nUsing default values for missing parameters in this " + ."session."); + } + + ### As the configuration process is done now, it is time to set the + # global configuration flag + $CONFIGURED = $TRUE; + + #### do some test in order to secure as good as possible that we will + #### succeed before to much work was done and maybe some data as damaged + + ### make sure that tmp_base_suffix is not empty + if ( ¶m_value('tmp_base_suffix') eq "" ) { + &report(2, "\nCAUTION: Empty tmp_base_suffix would destroy the original files!"); + &abort("Parameter tmp_base_suffix is not set."); + } + + ##### check for required commands + if (¶m_value('check_commands') ne $NO ) { + &check_commands; + } + + ### Check number of arguments + if ( @ARGV != 1 ) { + &report(1, "\nWrong number of arguments. I need exactly one file."); + &print_usage; + exit 1; + } + + return $ARGV[0]; +} + +#### prepare the logdir for the log files of the various called appplications + +sub prepare_logdir { + my $log_dir= ¶m_value('logdir'); + my $my_new_log; + + ##### Preparing the LOGDIR + if (! &check_dir($log_dir, "Could not create log directory", $YES)) { + &abort("Please, set a different path and restart"); + } + + # make sure there is a slash at the end of the path + $log_dir .= '/' if( ! ($log_dir =~ m#/$#) ); + + if( <$log_dir/*.log> and ¶m_value('clean_logs') eq $YES ) { + &report(6, "\nRemoving old log files ($log_dir)."); + unlink (<$log_dir/pdflatex-*.log>, <$log_dir/bibtex-*.log>, + <$log_dir/gloss-*.log>, <$log_dir/thumbpdf-*.log>, + <$log_dir/ppower-*.log>, <$log_dir/authorindex-*.log>, + <$log_dir/tex2pdf-*.log>); + } else { + &report(6, "\nAll log files will be stored in ($log_dir)."); + } + + ### move my pre-configuration log file to specified log directory + $my_new_log = "$log_dir/tex2pdf-$$.log"; + if ( move($MYLOGFILE, $my_new_log) ) { + $MYLOGFILE = $my_new_log; + } else { + &report(3, "Could not move '$MYLOGFILE' to logdir: $!"); + } +} + +##### analyse document argument +#### process the one and only argument (besides the options) which specifies +#### which LaTeX document the user wants to translate to PDF +#### a lyx file will be translated to LaTeX first +# parameter 1: argument + +sub process_doc_argument { + my $argument = $_[0]; + my $doc_base; + my $doc_path; + my $arg_suffix; + + ##### Getting document name, suffix and path + ($doc_base,$doc_path,$arg_suffix) = fileparse($argument, ('\.tex', '\.lyx')); + + if (! defined($arg_suffix) or $arg_suffix eq "") { + $arg_suffix = '.tex'; + } + + ###### change working directory to document directory + if ( $doc_path ne "" ) { + chdir $doc_path; + } + + ###### make DOCPATH an absolute path + $doc_path = cwd.'/'; + + ###### Cut off suffix and do lyx or tex specific stuff + if ( $arg_suffix eq '.lyx' ) { + # Lyx document argument: generate Latex document if required + &generate_tex_file($doc_base.'.lyx', $doc_base.'.tex'); + } else { + # LaTeX document argument: check access to given LaTeX document + &check_file($doc_base.'.tex', "Cannot read the specified LaTeX document!"); + } + + return $doc_path.$doc_base.'.tex'; +} + +#### handle the dir of the input path if the document has one and +# parameter 1: main tex doc +# return value: absolute input path + +sub process_inputpath { + my $texdoc = $_[0]; + my $doc_base; + my $doc_path; + my $doc_suffix; + my $input_path; + my @matches; + + ### Maybe the user has given us a different inputpath + $input_path = ¶m_value('input_path'); + if(defined($input_path) and $input_path ne "") { + &report(6, "Setting input path to specified directory: $input_path"); + + &report(7, "Change working directory to input path."); + chdir $input_path; + + return $input_path; + } + + ##### Getting document name, suffix and path + ($doc_base,$doc_path,$doc_suffix) = fileparse($texdoc, ('\.tex')); + + ###### change working directory to input_path if set + # When the files' path (images, included documents, etc.) in your document is + # relative to another directory than the PASSED document's directory. + # This is useful when the calling application (e.g. LyX) generates a + # temporary + # TeX file and calls the tex2pdf with it instead of the original file. + + @matches=&extract_tag_contents($texdoc, 'def\\\\input@path'); + $input_path=$matches[0]; + + ## check if input_path is ok + if ($input_path) { + &report(7, "Found an input path in the latex document: $input_path"); + if( &check_dir($input_path, 'The retrieved input@path seems not to be valid.', $NO)) { + &set_param_value('input_path', $input_path); + &report(7, "Change working directory to input path."); + chdir $input_path; + } else { + &abort ('I am lost.'); + } + } else { + &report(4, "No input path in the latex document found."); + &report(7, "Resources are expected to be relative to document's location: $doc_path"); + $input_path=$doc_path; + } + + return $input_path; +} + +#### set the working dir to the input path if the document has one and +#### and determine the path for the result +# parameter 1: main tex doc +# parameter 2: absolute input path +# return value: absolute path were the resulting pdf doc should be stored + +sub get_target_name { + my $texdoc = $_[0]; + my $input_path=$_[1]; + + my $doc_base; + my $doc_path; + my $doc_suffix; + my $destination; + my $pdf_path; + + ##### Getting document name, suffix and path + ($doc_base,$doc_path,$doc_suffix) = fileparse($texdoc, ('\.tex')); + + ##### set the directory where the final pdf will be stored + $destination=¶m_value('destination'); + $pdf_path=undef; + + if ($destination eq 'custom' ) { + $pdf_path=¶m_value('custom_path'); + } elsif ($destination eq 'input') { + $pdf_path=$input_path; + } else { + $pdf_path=$doc_path; + } + + if( ! defined($pdf_path) or $pdf_path eq "" or ! &check_dir($pdf_path, + 'The specified destination directory for the final PDF documents is not valid.', $NO)) { + &report(7, "Using document's instead of destination path: $doc_path"); + $pdf_path=$doc_path; + } + + # make sure there is a slash at the end of the path + $pdf_path .= '/' if( ! ($pdf_path =~ m#/$#) ); + + return $pdf_path.$doc_base.'.pdf'; +} + +### generate hyperref parameters from given settings +# parameter 1: main tex doc +# return_value: result + +sub generate_hyperref_params { + my $texdoc = $_[0]; + my $para; + my @params = ('pdftex'); + + ##### Set title and author from main LaTeX document or parameters + foreach my $info (('title', 'author')) { + my $value; + + $value=¶m_value("$info"); + if (! defined($value) ) { + my @matches=&extract_tag_contents($texdoc, $info); + $value= $matches[0]; + if (! defined($value) ) { + &report(4, "\nWARNING: Could not identify document's $info correctly."); + &report(7, "Maybe you have used a LaTeX tag inside the $info which confuses me.\n", + "Adjust the $info of the LaTeX file in order to avoid the problem or\n", + "you could set the $info parameter manually."); + $value= ¶m_value("default_$info"); + &report(7, "Using default-$info: $value"); + } + } + if (! defined($value) or $value eq $NIL ) { + &report(7, "$info field set to $NIL - no value will be passed."); + } else { + &report(7, "Document's $info: $value"); + push(@params, "pdf$info={$value}"); + } + } + + $para=¶m_value('paper'); + if ( $para ne $NIL ) { push(@params, $para); } + + $para=¶m_value('link_toc_page'); + if ( $para eq $YES ) { push(@params, 'linktocpage'); } + + $para=¶m_value('colorlinks'); + if ( $para ne $NIL ) { + $para= $para eq $YES ? 'true' : 'false'; + push(@params, "colorlinks=$para"); + } + + if ( $para ne 'false' ) { + foreach (('linkcolor', 'pagecolor', 'urlcolor', 'citecolor')) { + $para=¶m_value($_); + if ( $para ne $NIL ) { push(@params, "$_={$para}"); } + } + } + + $para=¶m_value('hyperref_args'); + if(defined($para) and $para ne "" and $para ne $NIL) { + push(@params, $para); + } + + return @params; +} + +#### Prepare the main document and all referenced ones for the generation +#### of the PDF document (including referenced images) +# parameter 1: top level tex document +# parameter 2: parameter list of hyperref parameters + +sub prepare_documents { + my ($main_tex_doc, $input_path, @hyperref_params) = @_; + @REF_DOCS=(); + + ## get a name for the tmp tex file + my $main_tmp_doc = &reserve_tmp_texname($main_tex_doc, $input_path); + + ## Get the list of imported files from the tex file + &get_file_list($main_tex_doc); + + ## remove main file from list (first element; needs special handling) + shift @REF_DOCS; + + ## tell user about the identified refereneced docs + if ( @REF_DOCS > 0 ) { + &report(7, "\nFound the following referenced TeX files:"); + foreach my $file (@REF_DOCS) { + &report(7, ">>>>> $file"); + } + } else { + &report(7, "\nFound no referenced TeX files."); + } + + ##### Generate adjusted temp tex files and convert all their images + ## main doc + &report(6, "\nGenerating main temporary LaTeX document: $main_tmp_doc"); + &convert_tex2tmp($main_tex_doc, $main_tmp_doc, \@hyperref_params); + &convert_images($main_tex_doc); + + ## referenced docs + foreach my $file (@REF_DOCS) { + my $tmp_file = &reserve_tmp_texname($file); + + ### Insert pdf conversation tags in tex file and write it to tmp_file + &report(7, "\nGenerating temporary LaTeX document: $tmp_file"); + &convert_tex2tmp($file, $tmp_file, undef); + &convert_images($file); + } + + return $main_tmp_doc; +} + +##### Generate the final PDF document +# parameter 1: filename of the source LaTeX document (with extension) + +sub generate_pdf_doc { + my $source = $_[0]; + my $runno=1; + my $rerun=$TRUE; + my $doc; + my $pdf_doc; + my $base; + my $path; + my $suffix; + + my $max_run_no= ¶m_value('maxrun'); + my $min_run_no= ¶m_value('minrun'); + my $log_dir= ¶m_value('logdir'); + $log_dir .= '/' if( ! ($log_dir =~ m#/$#) ); + my $makeindex_options=¶m_value('makeindex_opts'); + + # setting the log files for the output of pdflatex, bibtex, gloss, + # thumbpdf, ppower and authorindex + my $pdflog_base = $log_dir."pdflatex-$$-"; + my $bibtex_log = $log_dir."bibtex-$$.log"; + my $gloss_log = $log_dir."gloss-$$.log"; + my $thumbpdf_log = $log_dir."thumbpdf-$$.log"; + my $ppower_log = $log_dir."ppower-$$.log"; + my $authorindex_log = $log_dir."authorindex-$$.log"; + + ##### Getting document name, suffix and path + ($base,$path,$suffix) = fileparse($source, ('\.tex')); + $doc = $path.$base; + $pdf_doc = $base.'.pdf'; + + ### run pdflatex until no more errors are reported (max MAXRUNNO) + while ( $rerun and $runno <= $max_run_no ) + { + &report(6, "\n************ Pdflatex run no. $runno *************"); + if ( &run_pdflatex($doc, $pdflog_base.$runno.'.log') == $TRUE + and ( $min_run_no <= $runno )) { + # no errors detected and min. no. of runs are done + $rerun=$FALSE; + } else { + # errors appeared or max run no. has not been reached + $rerun=$TRUE; + } + + ### Execute BibTeX after first run if set (and required) + if ( $runno == 1 and ¶m_value('bibtex') ne $NO ) { + &report(6, "\n****************** BibTeX handling ***********************"); + &handle_bibtex($doc, $bibtex_log); + } + + ### Execute BibTeX on file.gls after first run if set (and required) + if ( $runno == 1 and ¶m_value('gloss') ne $NO ) { + &report(6, "\n****************** Gloss handling ***********************"); + &handle_gloss($doc, $gloss_log); + } + + ### generated index file exists + if ( $runno == 1 and -f $doc.'.idx' and ¶m_value('force_index') ne $NO ) { + if( !defined($makeindex_options) or $makeindex_options eq $NIL ) { + $makeindex_options = ""; + } + &report(6, "\n****************** Extra index generation ***************"); + &report(7, "Document seems to have an index. Generating ...\n"); + &system_command("makeindex $makeindex_options $doc.idx", $FALSE, 8, + "makeindex failed.\nI will continue, " + ."but maybe there will not be an index in the PDF doc."); + } + + $runno += 1; + } + + $rerun = $FALSE; + + ### if the authorindex option is switched on then run authorindex + if ( ¶m_value('authorindex') eq $YES ) { + &report(6, "\n****************** authorindex generation *****************"); + &run_authorindex($doc, $authorindex_log); + } + + ### generated index file exists + if ( -f $doc.'.idx' and ¶m_value('force_index') ne $NO ) { + if( !defined($makeindex_options) or $makeindex_options eq $NIL ) { + $makeindex_options = ""; + } + &report(6, "\n****************** Extra index generation ***************"); + &report(7, "Document seems to have an index. Generating ...\n"); + &system_command("makeindex $makeindex_options $doc.idx", $FALSE, 8, + "makeindex failed.\nI will continue, " + ."but maybe there will not be an index in the PDF doc."); + $rerun=$TRUE; + } + + ### if the thumbpdf option is switched on then make thumbnails + if ( ¶m_value('thumbpdf') eq $YES ) { + &report(6, "\n****************** Thumbnail generation *****************"); + &run_thumbpdf($doc, $thumbpdf_log); + $rerun=$TRUE; + } + + ### One final pdflatex run if requested + if ( $rerun ) { + &report(6, "\n************ One final pdflatex run no. $runno *************"); + &run_pdflatex($doc, $pdflog_base.$runno.'.log'); + } + + ### if the ppower option is switched on then run ppower + if ( ¶m_value('ppower') eq $YES ) { + &report(6, "\n****************** ppower postprocess *****************"); + &run_ppower($doc, $ppower_log); + } + + if ( ! -f $pdf_doc ) { + &abort("\nThe new PDF file could not be generated: ".$pdf_doc); + } + + return $pdf_doc; +} + +################## Lift off !!!! (main part) ################## + +my $texdoc; +my $doc_argument; +my $input_path; +my $target_name; +my @hyperref_params; +my $new_pdf_doc; +my $tmp_tex_doc; + +&report(5, "\nScript starts ($MYRELEASE)"); + +##### read and analyse configuration and options and adjust basic variables +##### accordingly +##### write RC file on config request +#### use the finished configuration to get all further settings before we +#### actually start doing something + +&report(5, "\nProcessing given parameters and arguments."); +$doc_argument = &adjust_configuration; + +#### prepare the script to write some information to specified log files + +&report(5, "\nPreparing directory for log files."); +&prepare_logdir; + +#### process the one and only argument (besides the options) which specifies +#### which LaTeX document the user wants to translate to PDF +#### a lyx file will be translated to LaTeX first + +&report(5, "\nAnalysing your document argument."); +$texdoc = &process_doc_argument($doc_argument); + +#### we would like to get some more information from the actual +#### main LaTeX document before we really start +#### parse the document and try to get the info + +## translate hyperref settings to the actual package parameters + +&report(5, "\nSetting up parameters for hyperref."); +@hyperref_params = &generate_hyperref_params($texdoc); + +## set the working dir to the input path if the document has one and + +&report(5, "\nProcessing input path for main tex document."); +$input_path = &process_inputpath($texdoc); + +## determine the name for the result + +&report(5, "\nSetting the correct name for the result."); +$target_name = &get_target_name($texdoc, $input_path); + +## as much as possible is prepared in advance at this point +## so hopefully we will succeed in generating the PDF document + +##### real work starts NOW + +##### Generate adjusted temp tex files and convert all their images + +&report(5, "\nPreparing all documents and images."); +$tmp_tex_doc = &prepare_documents($texdoc, $input_path, @hyperref_params); + +##### Generate the final PDF document + +&report(5, "\nProcessing the actual generation of the PDF document."); +$new_pdf_doc = &generate_pdf_doc($tmp_tex_doc); + +##### Finalize +move($new_pdf_doc, $target_name) or &abort("Could not move PDF file to final destination: $!"); + +if ( ¶m_value('debug') eq $NO ) { + &clean_up; +} else { + &print_temp_files; +} + +&report(5, "\nThe new pdf file is: $target_name\n"); + -- 1.8.3.1