3 # tex2pdf - script for translating latex docs to pdf
5 # Copyright (C) 2000-2002 by Steffen Evers and others
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License version 2 as
9 # published by the Free Software Foundation.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 # The GNU General Public License is also available online:
21 # http://www.gnu.org/licenses/gpl.html
23 # Thanks a lot to all the people that have already contributed to this project!
25 # The changelog including the credits has become too long. So, I have removed it
26 # from the script, but it is still available online (see below).
28 # Special thanks to the following people for their contribution
29 # (see the changelog for details):
30 # Matej Cepl, Herbert Voss, Nicolas Marsgui, Bruce Foster, Mark van Rossum,
31 # Matt Bandy, Garrick Chien Welsh, Stacy J. Prowell, Pavel Sedivy,
32 # Holger Daszler, Olaf Gabler, Ahmet Sekercioglui, Richard, Steffen Macke,
33 # Rainer Dorsch & friends, Jean-Pierre Chretien, Fernando Perez,
34 # Ha Duong Minh, Oscar Lopez
36 # Project Homepage: http://tex2pdf.berlios.de
37 # Developer Homepage: http://developer.berlios.de/projects/tex2pdf
38 # Mailing lists: http://developer.berlios.de/mail/?group_id=57
39 # Changelog: http://tex2pdf.berlios.de/changelog.html
41 # Anyone is invited to help to improve tex2pdf. Therefore any kind of feedback
42 # is welcome. Maybe you even would like to hack the code and send us your
43 # changes. This would help a lot and is highly appreciated. Think about it :-)
44 # Subscribing to the developer mailing list might be a first step (see above).
46 # Send feedback to: tex2pdf-devel@lists.berlios.de
58 ####### global variables
60 my $MYRELEASE="3.0.21";
61 my $MYHOSTNAME=hostname;
62 my $MYNAME=basename $0;
63 my $MYUSER=$ENV{'USER'};
64 my $USER_HOME=$ENV{'HOME'};
65 if (not $MYUSER) { $MYUSER = 'nobody'; }
66 if (not $USER_HOME) { $USER_HOME = '/tmp'; }
73 my $MTP_PREAMBLE_FILENAME="preamble.cfg";
74 my $MTP_TMP_BASESUFFIX="-mp";
75 my @EPS_SUFFIXES=('eps','ps','ps.gz','eps.gz' );
76 my $PDF_ORIG_SUFFIX='pdf.orig';
77 my @BITMAP_SUFFIXES=( 'jpg', 'png', 'tif' );
79 # (initial) log file of this script
80 # this log file will be moved to the specified log_dir after configuration
81 # and the variable will be updated to the new name
82 my $MYLOGFILE="$USER_HOME/tex2pdf-$$.log";
83 my $LOGFILE_VERBOSITY=9;
85 ### text token for no value
87 my $UNDEF="undefined";
89 ### token for boolean 'false', 'no'
93 ### token for boolean 'true', 'yes'
97 ### file to store private parameters
98 # If you only want to change your private parameters change them there
99 # default: $HOME/.tex2pdf3rc
100 my $RC_FILENAME="$USER_HOME/.tex2pdf3rc";
101 my $MYRCFILE_VERSION=7;
102 my $RCVERSION_STRING="rcfile_version";
104 ## set global variable configured to prevent access to configuration
105 # parameters before configuration process is finished
106 my $CONFIGURED=$FALSE;
107 my $PRE_CONFIG_VERBOSITY=4;
109 ########################## NEW PERL CONFIGURATON
111 my %CONFIGURATION = ();
112 my %PARAMETER_LIST = ();
113 my @PARAMETER_ORDER = ();
114 my %PARAMETER_TYPES = ();
116 ## Array index for the various information in each parameter specifcation
117 ## referenced by %PARAMETER_LIST
126 &add_param_type('paper',
127 [ ['a4paper' , 'a4 paper' ],
128 [ 'letterpaper', 'letter paper' ],
129 [ 'legalpaper', 'legal paper' ],
130 [ 'executivepaper', 'executive paper' ],
131 [ $NIL, 'do not set value - leave it to hyperref' ]
134 &add_param_type('color',
135 [ [ 'yellow', 'LaTeX color yellow' ],
136 [ 'red', 'LaTeX color red' ],
137 [ 'green', 'LaTeX color green' ],
138 [ 'cyan', 'LaTeX color cyan' ],
139 [ 'blue', 'LaTeX color blue' ],
140 [ 'magenta', 'LaTeX color magenta' ],
141 [ 'black', 'LaTeX color black' ],
142 [ $NIL , 'do not set this value - leave it to hyperref' ]
145 &add_param_type('destination',
146 [ [ 'source', 'directory of the LaTeX source document' ] ,
147 [ 'input', 'root directory of referenced material' ],
148 [ 'custom', 'custom directory as specified' ]
151 ### Option parameters: these parameters have no default value and can not
152 # be configured interactively, but only as a command line option
153 # an option parameter is not allowed to have a default value, question or
155 # and all parameter of type action are treated as option parameters
156 # $key, $type, $def_value, $opt_alias, $opt_spec, $description, $question, $explanation
158 &add_param('help', 'action', undef, '|h', '',
159 'print a short help text and exit');
161 &add_param('version', 'action', undef, '|v', '',
162 'print the version of this script and exit');
164 &add_param('print_config', 'action', undef, '|o', '',
165 'print the current configuration and exit');
167 &add_param('configure', 'action', undef, '|c', '',
168 'configure all parameters interactivly, store them and exit');
170 &add_param('title', 'text', undef, '|t', '=s',
171 'set PDF info title for specified document');
173 &add_param('author', 'text', undef, '|a', '=s',
174 'set PDF info author for specified document');
176 &add_param('input_path', 'directory', undef, '', '=s',
177 'set path for referenced material in main document');
180 # parameter type action is not allowed
181 # $key, $type, $def_value, $opt_alias, $opt_spec, $description, $question, $explanation
183 &add_param('logdir', 'directory',"$USER_HOME/tex2pdf-log/", '', '=s',
184 'set directory for saving log files',
185 'What log directory should be used?',
186 "The log directory is used to store information about the generation\n"
187 ."process for later review, e.g. for debugging.");
189 &add_param('lyxrc_path', 'directory', "$USER_HOME/.lyx/", '', '=s',
190 'set the configuration directory of LyX',
191 'What is the directory for your LyX configuration data?',
192 "If I have to generate a LateX file from a LyX file I need to clear two "
193 ."temporary\nfiles in your LyX configuration directory. They will "
194 ."be backuped and normally\ndo not contain any valuable data anyway. If "
195 ."you do not use LyX, simply leave\nthe default.");
197 &add_param('lyx_exec', 'text', "lyx", '', '=s',
198 'specify the LyX executable for converting lyx to latex',
199 'Which executable should I use for converting LyX docs to LaTeX?',
200 "I use LyX to generate a LateX file from a LyX file. As you might use\n"
201 ."several versions of LyX at the same time or do not have it in your path"
202 ."\nyou can give me the apropriate executable here (e.g. '/usr/bin/lyx')."
203 ."\nIn most cases the default 'lyx' should be fine.");
205 &add_param('debug', 'bool', $NO, '', '!',
206 'do not delete temporary files after execution and be as verbose as possible',
207 'Do you want to debug this script?',
208 "I will not remove any temporary files. This could cause problems on a "
209 ."second\nexecution as I might refuse to overwrite these files for security "
210 ."reasons.\nYou have to remove them manually in this case. Additionally, I "
211 ."will provide\nas much information during execution as possible.");
213 &add_param('delete_pdf_images', 'bool', $NO, '', '!',
214 'delete generated PDF image files after execution',
215 'Should generated PDF image files be deleted after execution?',
216 "Pdflatex cannot handle EPS images. Therefore all such images need to be\n"
217 ."translated to PDF in advance. After a successful generation of the final "
218 ."PDF \ndocument or after encountering an error I could leave this PDF "
219 ."images for\n later executions or simply delete them.");
221 &add_param('clean_on_abort', 'bool', $YES, '', '!',
222 'also delete temporary files after abort',
223 'Should temporary files be deleted when aborting?',
224 "When the generation of the PDF file fails for some reason you might still "
225 ."want\nto keep already generated temporary files for some reason, e.g. "
226 ."debugging.\nIf you do not want to keep them set this parameter to 'yes'.");
228 &add_param('tmp_base_suffix', 'text', '-pdf', '', '=s',
229 'specify the extension of the basename for temporary TeX files',
230 'What string should be used as basename suffix for temporary files?',
231 "I have to find names for my temporary files. Therefore I construct a new "
232 ."name\nfrom the original filename and this string. Me and various called "
233 ."applications\nwill then create several files with this constructed "
234 ."basename and different\nextensions. When cleaning up I will simple "
235 ."delete all files with the\nconstructed basenames I have used.");
237 &add_param('overwrite', 'bool', $NO, '', '!',
238 'ignore existence of files with same basename as temporary TeX files',
239 'Should I overwrite existing (temporary) files?',
240 "In spite of the precaution with the appended base suffix, there still "
241 ."might\nexist files with an identical basename. If you set this option I "
242 ."will consider\nsuch files as old temporary files and overwrite them "
243 ."during generation.\nHowever, I will not remove any files with this "
244 ."constructed basename on the\nclean up. You have to remove them manually.");
246 &add_param('clean_logs', 'bool', $YES, '|l', '!',
247 'delete all log files in log directory before execution',
248 'Should the old log files be removed before execution?',
249 "I can remove old log files prior to execution. However, you might "
250 ."experience\nproblems if you run the script on several documents at the "
251 ."same time. If you\nwant to be on the safe side, answer '$NO'. Than you "
252 ."have to remove the logs\nmanually from time to time.");
254 &add_param('check_commands', 'bool', $YES, '', '!',
255 'make sure that required shell commands does exist before start',
256 'Should I look for required executables?',
257 "As I use several different applications for PDF generation you might want "
258 ."to \nmake sure that they are available before the real work starts.");
260 &add_param('destination', 'destination', 'source', '', '=s',
261 'specifiy final location of generated PDF document',
262 'Where should I store the resulting PDF document?',
263 "Depending on the application that starts this script (or you if you call "
264 ."it\ndirectly) you might want to have the resulting PDF document located "
265 ."at\ndifferent places.");
267 &add_param('custom_path', 'directory', $USER_HOME.'/', '|d', '=s',
268 "specify custom path for 'destination' parameter",
269 'What custom directory should be used?',
270 "When ever you specifiy to store the generated PDF document (command line "
271 ."or\nconfiguration) in a custom directory I will put it here.");
273 &add_param('colorlinks', 'three', $YES, '', '!',
274 'activate colored links in PDF doc (hyperref)',
275 'Should colors be used for links?',
276 "I can use different colors for links inside the PDF document.\nYou can "
277 ."use '$UNDEF' to tell me that you would like to leave this up to\n"
278 ."independent hyperref configuration.");
280 &add_param('paper', 'paper', 'a4paper', '|p', '=s',
281 'specify papersize of the PDF doc (hyperref)',
282 'What papersize should be used?',
283 "I can set the papersize of the resulting PDF document");
285 &add_param('citecolor', 'color', 'blue', '', '=s',
286 'specify color of citations in PDF doc (hyperref)',
287 'What color should be used for citation?', "");
289 &add_param('urlcolor', 'color', 'blue', '', '=s',
290 'specify color of URLs in PDF doc (hyperref)',
291 'What color should be used for URLs?', "");
293 &add_param('linkcolor', 'color', 'blue', '', '=s',
294 'specify color of internal links in PDF doc (hyperref)',
295 'What color should be used for normal internal links?', "");
297 &add_param('pagecolor', 'color', 'blue', '', '=s',
298 'specify color of links to other pages in PDF doc (hyperref)',
299 'What color should be used for page links?', "");
301 &add_param('link_toc_page', 'bool', $YES, '', '!',
302 'link table of contents to pages instead of sections (hyperref)',
303 'Should TOC be linked to pages?',
304 "The table of contents of the resulting PDF document is normally linked to "
305 ."the\ncorresponding section. However, you can also link it to the "
306 ."corresponding page\ninstead.");
308 &add_param('default_title', 'text', $NIL, '', '=s',
309 'set default PDF info title',
310 'What is the default title?',
311 "A PDF document contains meta data about itself: the document info.\nOne "
312 ."of the info fields is the document title. You can set a default value\n"
313 ."which will be used in the case the script cannot determine a proper "
314 ."title from\nthe LaTeX document and you have not set one on the command "
315 ."line.\nYou can use '$NIL' to tell me that you would like to leave this "
316 ."up to\nindependent hyperref configuration.");
318 &add_param('default_author', 'text', $NIL, '', '=s',
319 'set default PDF info author',
320 'What is the default author?',
321 "A PDF document contains meta data about itself: the document info.\nOne "
322 ."of the info fields is the document author. You can set a default value\n"
323 ."which will be used in the case the script cannot determine a proper "
324 ."author\nfrom the LaTeX document and you have not set one on the command "
325 ."line.\nYou can use '$NIL' to tell me that you would like to leave this "
326 ."up to\nindependent hyperref configuration.");
328 &add_param('force_index', 'bool', $NO, '|i', '!',
329 'force explicit inclusion of (existing) index in PDF doc',
330 'Should the call of makeindex be forced?',
331 "Older versions of pdflatex have not included the index of a document\n"
332 ."automatically. If you are missing the index in your document you can "
333 ."force the\ncall of makeindex on the condition that an index file was "
336 &add_param('makeindex_opts', 'text', '', '', '=s',
337 'specify extra options for shell execution of makeindex',
338 'What additional options for makeindex should be used?',
339 "Sometimes, people would like to pass some extra options over to makeindex. "
340 ."This\nis the right place to do that. Everyone else can leave this empty.");
342 &add_param('bibtex', 'three', $NIL, '|b', '!',
343 'set bibtex behavior',
344 'How should bibtex be used?',
345 "The bibtex usage can be specified.\nPossible values are: '$YES' (always "
346 ."run bibtex), '$NO' (never run bibtex)\nand '$UNDEF' (scan tex file for "
347 ."a bibtex entry and run it if required).");
349 &add_param('gloss', 'three', $NIL, '', '!',
350 'set gloss behavior',
351 'How should gloss be used?',
352 "The gloss usage can be specified.\nPossible values are: '$YES' (always "
353 ."run bibtex on file.gls), '$NO' (never run bibtex on file.gls)\nand '$UNDEF' (scan tex file for "
354 ."a gloss entry and run it if required).");
356 &add_param('thumbpdf', 'bool', $NO, '|n', '!',
357 'generate thumbnails for PDF document',
358 'Should PNG thumbnails be created?',
359 "I can use thumbpdf to include thumbnails of the document pages in the PDF "
360 ."file.\nThis requires Ghostscript 5.50 or higher.");
362 &add_param('ppower', 'bool', $NO, '|w', '!',
363 'postprocess PDF document with ppower',
364 'Should ppower postprocess the PDF document?',
365 "I can use ppower to postprocess the PDF "
366 ."file.\nThis requires ppower 4.0 or higher.");
368 &add_param('authorindex', 'bool', $NO, '', '!',
369 'generate author index for PDF document',
370 'Should authorindex process the PDF document?',
371 "I can use authorindex to process to include an author index in the PDF "
372 ."file.\nThis requires authorindex.");
375 &add_param('mtp_preamble', 'bool', $NO, '|r', '!',
376 "add the file $MTP_PREAMBLE_FILENAME at the current dir to metapost files",
377 "Should the $MTP_PREAMBLE_FILENAME file be added to the metapost files?",
378 "I can add $MTP_PREAMBLE_FILENAME to metapost "
379 ."files.\nThis requires an existing $MTP_PREAMBLE_FILENAME file.");
381 &add_param('maxrun', 'integer', 6, '', '=i',
382 'specify maximal number of pdflatex runs if problems are detected',
383 'What should be the maximum number of runs for pdflatex (1-6)?', "");
385 &add_param('minrun', 'integer', 2, '', '=i',
386 'specify minimal number of pdflatex runs if no problems are detected',
387 'What should be the minimum number of runs for pdflatex (1-6)?', "");
389 &add_param('verbosity', 'integer', 5, '', '=i',
390 'set the level of verbosity',
391 'Which level of verbosity do you want (0-9)',
392 "Different people want different amounts of information about what the "
393 ."script\nactually does. Therefore you can adjust the verbosity to your "
394 ."personal needs\nby setting this parameter to a value from 0 to 9. 0 "
395 ."means no output at all\nand 9 means maximal output.");
397 &add_param('pdftex_opts', 'text', '', '', '=s',
398 'specify extra options for shell execution of pdflatex',
399 'What additional options for pdflatex should be used?',
400 "Sometimes, people would like to pass some extra options over to pdflatex. "
401 ."This\nis the right place to do that. Everyone else can leave this empty.");
403 &add_param('hyperref_args', 'text', '', '', '=s',
404 'specify extra arguments for the hyperref package',
405 'What additional arguments should be passed to the hyperref package?',
406 "Sometimes, people would like to pass some extra options over to hyperref. "
407 ."This\nis the right place to do that. Everyone else can leave this empty.");
409 # the following parameter types should be set now:
410 # 'color' => \@VALUES,
411 # 'destination' => \@VALUES,
412 # 'paper' => \@VALUES,
416 # 'integer' => undef,
418 # 'directory' => undef
420 ##### Functions ###########################################
422 ### handle a status report with a given priority level
423 # write it to the log file if log file if configuration is done
424 # write it to stdout if verbosity is set lower or equal
426 # The following priority levels exist:
427 # 1: minimal fatal error messages
428 # 2: additional information about fatal error
429 # 3: non-fatal error message
431 # 5: major step of the process
432 # 6: minor step of the process
433 # 7: progress report of minor step
434 # 8: long status report from called applications
437 # parameter 1: priority level
438 # parameter 2: list of output strings
448 @output = ( "Oppss! Report function got only 1 argument!" );
451 ($level, @output) = @_;
455 if( ¶m_value('debug') eq $NO ) {
456 $verbosity = ¶m_value('verbosity');
457 $log_verbosity = $LOGFILE_VERBOSITY;
463 $verbosity = $PRE_CONFIG_VERBOSITY;
464 $log_verbosity = $LOGFILE_VERBOSITY;
467 if ( $level <= $log_verbosity ) {
468 open LOGFILE, ">> $MYLOGFILE";
469 print LOGFILE @output,"\n";
473 if( $level <= $verbosity ) {
478 ### process system command and do the appropriate reports
479 # parameter 1: the system command to process
480 # parameter 2: flag - TRUE: abort on failure, FALSE: continue on failures
481 # parameter 3: priority level for output of system command
482 # parameter 4: specific failure message
483 # return value: TRUE - success, FALSE - failure
487 my $fatal_failure= $_[1];
488 my $output_priority = $_[2];
489 my $fail_message = $_[3];
492 $system_out = `$command 2>&1`;
495 if ($fatal_failure) {
496 &report(2, $system_out) if ($system_out);
497 &abort($fail_message.": $!");
499 &report($output_priority, $system_out) if ($system_out);
500 &report(3, $fail_message.": $!");
508 ### Index of the first occurence of a string in an array
511 # return value: index or -1 if not element of the array
514 my ($text, @list) = @_;
516 if(!defined($text)) {
517 &report(9, "Oppss! Cannot compare nothing.");
521 foreach (0..$#list) {
522 if ( $list[$_] eq $text ) { return $_; }
528 ### extract the last N lines of a text file
530 # parameter 1: file to read
531 # parameter 2: N - number of lines to print (undef/0: all lines)
532 # return value: last N lines
535 my $file_name = $_[0];
536 my $no_of_lines = defined($_[1]) ? $_[1] : 0;
539 &check_file($file_name);
540 open(TAIL_SOURCE, "<$file_name")
541 or &abort("Could not read file $file_name: $!");
543 if($no_of_lines == 0) {
545 while(<TAIL_SOURCE>) {
553 while(@cache < $no_of_lines and <TAIL_SOURCE>) {
558 # always cache the last N lines up to the end of the file
559 while(<TAIL_SOURCE>) {
571 ### return all lines of FILE which match match regexp EXPR
572 # parameter 1: FILE - file to read
573 # parameter 2: EXPR - regular expression to match
574 # parameter 3: true: exit on first occurence, otherwise get all (default: false)
575 # return value: array of matching lines
578 my $file_name = $_[0];
580 my $first_only = $_[2] ? $TRUE : $FALSE;
583 ### open file and abort if not possible
584 &check_file($file_name);
585 open(GREP_SOURCE, "<$file_name")
586 or &abort("Could not read file $file_name: $!");
588 while(<GREP_SOURCE>) {
591 if($first_only) { last; }
599 ### Removing all temporary files
602 &report(6, "Removing temporary files ...");
603 foreach (@TMPFILES) {
604 unlink($_) if(-f $_);
607 foreach (@TMP_TEX_FILES) {
608 # make sure that we have a good tex file name in order
609 # to avoid unintended removals
610 if( $_ ne "" and -f $_.'.tex' ) {
611 unlink glob($_.".???");
613 &report(3, "Bad file in temp tex files list: $_");
618 ### Output of all temp files
620 sub print_temp_files {
621 if (scalar @TMPFILES > 0) {
622 print "Stored the following explicit temporary files:\n";
623 foreach (@TMPFILES) {
627 print "> ".$_." (does not exist)\n";
633 if (scalar @TMP_TEX_FILES > 0) {
634 print "Stored the following temporary TeX base names:\n";
635 foreach (@TMP_TEX_FILES) {
636 if( $_ ne "" and -f $_.'.tex' ) {
638 foreach my $file (glob($_.".???")) {
639 print basename($file)." ";
643 print "> ".$_.": bad file for temp TeX file\n";
650 ### exit with an error message
654 if ( $CONFIGURED and ¶m_value('clean_on_abort') eq $YES
655 and ¶m_value('debug') eq $NO) {
660 &report(2, "Aborting ...");
664 ### Check for required command with 'which'; abort if not found
665 # parameter $1: command to check
666 # parameter $2: remark if specified command is not found
673 $which_output = `which $command 2>&1`;
676 s|^(.*/)?([^/]+)$|$2|;
678 if ( $_ ne $command ) {
679 &report(2, "\n$which_output");
680 &report(1, "\nRequired command '$command' seems not to be in your path.");
681 if ( defined($message) ) {
682 &report(2, "$message");
684 &report(2, "Aborting ...");
689 ###################### Generic configuration functions
691 ### interactively answer a question with yes or no
692 # parameter 1: question
693 # parameter 2: default value (not set means $NIL)
694 # parameter 3: yes: allow undefined as third value
695 # no : only yes/no allowed (default)
696 # return value: the given answer
700 my $question = $_[0];
701 my $default = defined($_[1]) ? $_[1] : $NIL;
702 my $undef_allowed = $_[2];
703 my $response = undef;
705 if (defined($undef_allowed) and $undef_allowed eq $YES) {
706 $undef_allowed = $TRUE;
708 $undef_allowed = $FALSE;
711 if( $default =~ /^y(es)?/i ) {
712 $question .= ' [y]: ';
714 } elsif ( $default eq $NIL and $undef_allowed ) {
715 $question .= ' [u]: ';
718 $question .= ' [n]: ';
721 while (! defined($response)) {
723 $user_input = <STDIN>;
726 if( $user_input =~ /^y(es)?/i ) {
728 } elsif ( $user_input =~ /^no?/i ) {
730 } elsif ( $user_input =~ /^u(ndef(ined)?)?/i and $undef_allowed ) {
732 } elsif ( $user_input eq "" ) {
735 print "Please respond with y(es)";
736 print ", u(ndefined)" if($undef_allowed);
743 ### interactively input a positive integer number
744 # parameter 1: question
745 # parameter 2: default value
746 # parameter 3: min value
747 # parameter 4: max value
748 # return value: the input number
751 my $question = $_[0];
753 my $min_limit = $_[2];
754 my $max_limit = $_[3];
757 while (! defined($response)) {
758 print "$question [$default]: ";
759 my $user_input = <STDIN>;
762 if ($user_input eq "") {
766 if (s/^([0-9]+)$/$1/ and $_ >= $min_limit and $_ <= $max_limit ) {
769 print "Invalid input. Please enter a positve integer from $min_limit to $max_limit.\n";
776 ### interactively choose between several given values
777 # parameter 1: question
778 # parameter 2: default value
779 # parameter 3: reference to an array of possible values arrays
780 # return value: the chosen value
783 my ($question, $default, $enum_array_ref)=@_;
786 my @possible_values = @$enum_array_ref;
792 foreach (0..$#possible_values) {
794 @value_array = @{$possible_values[$_]};
795 $value_key = $value_array[0];
796 $value_output = $value_array[1];
798 print "$no) " . $value_output . "\n";
799 if ( $default eq $value_key ) { $default_no=$no; }
802 $chosen_no=&input_number("Please enter the corresponding number", $default_no, 1, $#possible_values);
804 @value_array = @{$possible_values[$chosen_no - 1]};
805 $value_key = $value_array[0];
809 ### interactively answer a question
810 # parameter 1: question
811 # parameter 2: current value
812 # return value: the new value
819 print "Suggested value: $default\n";
820 if ( &question_ynu("Do you want to keep this value?", $YES) eq $YES ) {
824 my $user_input = <STDIN>;
827 $response = $user_input;
832 ##### Make sure that specified file exists and is readable; abort if missing
833 # parameter 1: file to check
834 # parameter 2: remark if check fails on specified file
838 my $message = defined($_[1]) ? $_[1] : "Required file cannot be accessed!";
841 &report(2, "\nSorry. I cannot find '$file'.");
843 } elsif ( ! -r $file ) {
844 &report(2, "\nSorry. File '$file' exists, but is not readable.");
849 ##### Make sure that specified directory exists and is writable
850 # parameter 1: directory to check
851 # parameter 2: remark if check fails on specified directory
852 # parameter 3: if yes, creation is allowed
853 # return value: $TRUE - ok; $FALSE - error
856 my $directory = $_[0];
857 my $message = defined($_[1]) ? $_[1] : "Not a valid path!";
858 my $allow_creation = defined($_[2]) ? $_[2] : $NO;
860 if ( index($directory, "/") != 0 ) {
861 &report(3, "\nSorry. '$directory' is not an absolute path.");
862 &report(3, $message);
864 } elsif ( ! -d $directory ) {
866 if ( $allow_creation eq $YES ) {
868 &report(4, "\nI cannot find '$directory'. Try to create it.");
869 if ( mkdir($directory, 0755) ) {
870 &report(7, "Creation of '$directory' was successful.");
873 &report(3, "Creation of '$directory' failed.");
874 &report(3, $message);
878 # creation not allowed
879 &report(3, "\nSorry. Directory '$directory' does not exist.");
880 &report(3, $message);
883 } elsif ( ! -w $directory ) {
885 &report(3, "\nSorry. Directory '$directory' exists, but is not writable.");
886 &report(3, $message);
892 ### interactively input a directory for data storage (absolute path)
893 # parameter 1: question
894 # parameter 2: default dir
895 # parameter 3: if 'yes' allow creation of directory
896 # return value: the specified directory
899 my $question = $_[0];
900 my $default_dir = $_[1];
901 my $allow_creation = defined($_[2]) ? $_[2] : $NO;
903 my $response = undef;
905 if ( defined($default_dir) and index($default_dir, "/") == 0
906 and ( (! -d $default_dir and $allow_creation eq $YES)
907 or (-d $default_dir and -w $default_dir) ) ) {
908 $question .= " [$default_dir]: ";
910 $default_dir = undef;
914 while (! defined($response)) {
916 $user_input = <STDIN>;
919 if( $user_input eq "" and defined($default_dir) ) {
920 # user has only pressed <ENTER> and thereby confirmed default value
921 if( ! &check_dir($default_dir,"Default value was not valid. Please, give different directory.", $allow_creation ) ) {
922 # default dir does not exist and cannot be created
923 $default_dir = undef;
924 $question = "$_[0]: ";
926 # valid default dir has already existed or has been created
927 $response = $default_dir;
930 # user has given a directory
931 if( &check_dir($user_input,"This is not a valid directory!", $allow_creation) ) {
932 $response = $user_input;
939 #### add a new parameter type with corresponding additional data argument
940 #### parameters types
941 # parameter 1: type key
942 # parameter 2: additonal data for the type
943 # e.g. for enum type: reference to list of arrays
948 my ($type, $scalar_argument) = @_;
950 $PARAMETER_TYPES{$type} = $scalar_argument;
953 #### add a new parameter to the adminstrated parameters
957 # parameter 3: default value
958 # parameter 4: alias for command line options
959 # parameter 5: specification for command line options
960 # parameter 6: short description for help
961 # parameter 7: question
962 # parameter 8: explanation
967 my ($key, $type, $def_value, $opt_alias, $opt_spec, $description, $question, $explanation) = @_;
969 $CONFIGURATION{$key} = $def_value;
971 $PARAMETER_LIST{$key} = [ $type, $opt_alias, $opt_spec, $def_value, $description, $question, $explanation ];
973 push(@PARAMETER_ORDER, $key);
975 if (! exists $PARAMETER_TYPES{$type}) {
976 $PARAMETER_TYPES{$type} = undef;
980 ### get the value of an existing parameter
981 # parameter 1: a parameter key
982 # return value: reference to the array of possible value entries
983 # (undef if not valid)
985 sub type_enum_array {
989 if(! exists($PARAMETER_TYPES{$key})) {
990 &abort("unknown type: $key");
993 $values_ref = $PARAMETER_TYPES{$key};
995 if(ref $values_ref ne 'ARRAY') {
1002 ### get the value of an existing parameter
1003 # parameter 1: a parameter key
1004 # return value: parameter value
1010 exists($CONFIGURATION{$key})
1011 or &abort("unknown parameter: $key");
1012 $current_value = $CONFIGURATION{$key};
1014 return $current_value;
1017 ### get the type of an existing parameter
1018 # parameter 1: a parameter key
1019 # return value: parameter value
1026 exists($PARAMETER_LIST{$key})
1027 or &abort("unknown parameter: $key");
1028 $def_ref = $PARAMETER_LIST{$key};
1029 $type = @{$def_ref}[$TYPE];
1031 exists($PARAMETER_TYPES{$type})
1032 or &abort("parameter has unknown type: $key (type: $type)");
1037 ### determine if the given parameter is a full one (instead of option only)
1038 # parameter 1: a parameter key
1039 # return value: $TRUE - full parameter; $FALSE otherwise
1045 exists($PARAMETER_LIST{$key})
1046 or &abort("unknown parameter: $key");
1047 @param_def = @{$PARAMETER_LIST{$key}};
1049 if ($param_def[$TYPE] ne 'action' and defined ($param_def[$QUESTION])) {
1056 ### get the output needed for configuration of this parameter
1057 # parameter 1: a parameter key
1058 # return value: array - (description, explanation, question)
1060 sub param_config_output {
1067 exists($PARAMETER_LIST{$key})
1068 or &abort("unknown parameter: $key");
1069 @param_def = @{$PARAMETER_LIST{$key}};
1070 $description = $param_def[$DESCRIPTION];
1071 $explanation = $param_def[$EXPLANATION];
1072 $question = $param_def[$QUESTION];
1074 return ($description, $explanation, $question);
1077 ### set the value of an existing parameter
1078 # parameter 1: a parameter key
1079 # parameter 2: the new value
1080 # return value: none
1082 sub set_param_value {
1084 my $new_value = $_[1];
1086 exists($CONFIGURATION{$key})
1087 or &abort("unknown parameter: $key");
1088 $CONFIGURATION{$key}=$new_value;
1091 ### get option specifier for getopts
1092 # parameter 1: option key
1093 # return value: string - option specifier
1095 sub option_specifier {
1100 exists($PARAMETER_LIST{$key})
1101 or &abort("unknown parameter: $key");
1102 $def_ref = $PARAMETER_LIST{$key};
1103 $spec = $key . ${$def_ref}[$OPT_ALIAS] . ${$def_ref}[$OPT_SPEC];
1108 ### handle an option
1109 # parameter 1: a parameter/option key
1110 # parameter 2: the option value
1111 # return value: none
1118 $type = ¶m_type($key);
1120 if ($type eq 'action') {
1121 &handle_action_opt($key, $value);
1122 } elsif ( $type eq 'bool' or $type eq 'three') {
1123 my $bool_value = $value ? $YES : $NO;
1124 &set_param_value($key, $bool_value);
1125 } elsif ( $type eq 'directory') {
1126 if (! &check_dir($value)) {
1127 &report(2, "$key requires an existing writable directory as an absolute path.");
1128 &abort("Illegal value: $value");
1130 &set_param_value($key, $value);
1131 } elsif (defined(&type_enum_array($type))){
1132 &set_enum_param($key, $value);
1134 &set_param_value($key, $value);
1138 ### handle all action options
1139 # parameter 1: a option key
1140 # parameter 2: the option value
1141 # return value: none
1143 sub handle_action_opt {
1147 if ($key eq 'help') {
1150 } elsif ($key eq 'version') {
1153 } elsif ($key eq 'configure') {
1154 if ( -f $RC_FILENAME ) {
1155 &read_configuration($RC_FILENAME);
1158 &write_configuration($RC_FILENAME);
1159 &print_configuration;
1161 } elsif ($key eq 'print_config') {
1162 if ( -f $RC_FILENAME ) {
1163 &read_configuration($RC_FILENAME);
1165 &print_configuration;
1174 ### set a variable by a command line option to a possible values; abort on error
1175 # parameter 1: parameter key
1176 # parameter 2: value
1178 sub set_enum_value {
1179 my ($key, $value) = @_;
1182 my @allowed_values=();
1184 $type = ¶m_type($key);
1185 $enum_array_ref = &type_enum_array($type);
1186 &abort("Internal error: No value array for parameter $key.")
1187 if(!defined($enum_array_ref));
1189 ### find out if the given value is allowed
1190 foreach my $value_array_ref (${$enum_array_ref}) {
1191 if(${$value_array_ref}[0] eq $value) {
1192 ### found it, so it is okay!
1193 &set_param_value($key, $value);
1198 ### value is not listed, so not allowed
1199 ### make a list of all allowed values
1200 foreach my $value_array_ref (${$enum_array_ref}) {
1201 push(@allowed_values, ${$value_array_ref}[0]);
1204 &report(2, "\n$key allows: " . @allowed_values . ".\n");
1205 &abort("Illegal value: $value");
1208 ### configure an existing parameter interactively
1209 # parameter 1: a parameter key
1210 # return value: none
1221 ### get required information about this parameter
1222 $type = ¶m_type($key);
1223 $current_value = ¶m_value($key);
1224 ($description, $explanation, $question) = ¶m_config_output($key);
1226 ### tell the user the facts
1227 print "\n\n--------------------------------------------\n";
1228 print "Parameter: ".$key."\n";
1229 print $description."\n\n";
1230 print $explanation."\n\n" if($explanation ne "");
1232 ### ask him what he wants
1233 if ($type eq 'bool') {
1234 $new_value=&question_ynu($question, $current_value, $NO);
1235 } elsif ($type eq 'three') {
1236 $new_value=&question_ynu($question, $current_value, $YES);
1237 } elsif ($type eq 'directory') {
1238 $new_value=&input_dir($question, $current_value, $YES);
1239 } elsif ($type eq 'text') {
1240 $new_value=&input_text($question, $current_value);
1241 } elsif ($type eq 'integer') {
1242 $new_value=&input_number($question, $current_value,
1243 $NUM_PARAM_MIN, $NUM_PARAM_MAX);
1247 $enum_array_ref=&type_enum_array($type);
1248 if (! defined($enum_array_ref)) {
1249 &abort("Do not know how to configure this parameter: $key (type: $type)");
1252 $new_value=&choose_value($question,$current_value,$enum_array_ref);
1255 ### store his choice
1256 &set_param_value($key, $new_value);
1259 ### save configuration in rc file
1260 # parameter 1: file name
1261 # return value: none
1263 sub write_configuration {
1264 my $file_name = $_[0];
1267 open(RCFILE, ">$file_name") or
1268 &abort("Could not open configuration file for writing ($file_name)");
1274 print "# Configuration file for $MYNAME V$MYRELEASE\n";
1275 print "# Generated $date by $MYUSER on $MYHOSTNAME\n";
1276 print "$RCVERSION_STRING=$MYRCFILE_VERSION\n";
1278 foreach my $key (@PARAMETER_ORDER) {
1279 my $value = $CONFIGURATION{$key};
1280 if(&full_param($key)) {
1281 print $key.'='.$value."\n";
1290 ### print the configuration parameters
1292 sub print_configuration {
1293 print "\nConfiguration for $MYNAME V$MYRELEASE\n";
1295 foreach my $key (@PARAMETER_ORDER) {
1296 my $value = $CONFIGURATION{$key};
1297 if(&full_param($key)) {
1298 print $key.'='.$value."\n";
1305 ### load parameters from rc file
1306 # parameter 1: file name
1307 # return value: version of read rc file or 0 if no version given
1309 sub read_configuration {
1310 my $file_name = $_[0];
1311 my $file_version= 0;
1313 &check_file($file_name, "Could not access configuration file");
1314 open(RCFILE, "<$file_name") or
1315 &abort("Could not open configuration file for reading ($file_name)");
1319 if( /^([^#=]+)=(.*)$/ ) {
1320 if( exists $CONFIGURATION{$1} ) {
1321 $CONFIGURATION{$1} = $2;
1322 } elsif ( $1 eq $RCVERSION_STRING ) {
1325 print "Ignoring unknown parameter in RC file: $1=$2\n";
1331 return $file_version;
1334 ### print script version
1337 print "\n$MYNAME Version $MYRELEASE\n";
1340 ###################### Specific functions (for use with this script only)
1342 ### print usage of command
1345 print "\nUsage: $MYNAME [OPTIONS] DOCUMENT.lyx\n";
1346 print " $MYNAME [OPTIONS] DOCUMENT[.tex]\n\n";
1347 print " $MYNAME -c | --configure modify/set up configuration\n";
1348 print " $MYNAME -h | --help give a short help\n";
1349 print " $MYNAME -o | --print_config print current configuration\n";
1350 print " $MYNAME -v | --version print my version\n\n";
1353 ### print command help
1359 foreach my $key (@PARAMETER_ORDER) {
1360 my @param_def = @{$PARAMETER_LIST{$key}};
1361 my $description = $param_def[$DESCRIPTION];
1362 my $takes_value = $param_def[$OPT_SPEC] =~ /[=:]/ ? $TRUE : $FALSE;
1363 my $negation = $param_def[$OPT_SPEC] eq '!' ? $TRUE : $FALSE;
1364 my $alias = $param_def[$OPT_ALIAS];
1366 $alias =~ s/\|(([a-zA-Z])(\||$))/ | -$1/g;
1367 $alias =~ s/\|(([a-zA-Z][a-zA-Z0-9_]+)(\||$))/ | --$1/g;
1370 print "[no]" if($negation);
1372 print " VALUE" if ($takes_value);
1373 print ":\n ".$description."\n\n";
1378 ### configure all tex2pdf parameters interactively
1380 # return value: none
1384 print "\n--------------------------------------------------------\n";
1385 print "\n***** Configuration for $MYNAME *****\n\n";
1386 print "The following answers are considered as defaults in later ";
1387 print "executions\n";
1388 print "of $MYNAME. You can change these values by using the option ";
1389 print "--configure \nagain.";
1390 print "Additionally, all command-line options override these settings.\n";
1391 print "Many parameters can be set to '$NIL' or '$UNDEF'. This means that NO";
1392 print "\nvalue at all (not even an empty value) is passed over to the ";
1393 print "called\napplication (e.g. latex package hyperref).\n";
1398 foreach my $key (@PARAMETER_ORDER) {
1399 if(&full_param($key)) {
1400 &config_param($key);
1404 print "\nConfiguration for $MYNAME finished.\n\n";
1407 ### check if the most important executables are installed on the system
1410 sub check_commands {
1412 ### check for which command
1413 &checkCommand("which","You can switch off all command checks to fix this.");
1415 ### pdftex executables
1416 # Homepage: http://tug.org/applications/pdftex
1417 &checkCommand("pdflatex","See pdftex homepage for details: http://tug.org/applications/pdftex");
1418 &checkCommand("epstopdf","See pdftex homepage for details: http://tug.org/applications/pdftex");
1419 $exec_epstopdf = `which epstopdf`;
1420 chomp $exec_epstopdf;
1421 my $compat = "-dCompatibilityLevel=1\\.1";
1422 if (defined($ENV{'GS_OPTIONS'}) && $ENV{'GS_OPTIONS'} =~ /$compat/o) {
1423 &report(9, "Good: ghostscript option '-dCompatibilityLevel=1.1' detected "
1424 ."in\n'\$GS_OPTIONS'.");
1425 } elsif (&grep_file($exec_epstopdf, $compat, $TRUE) > 0) {
1426 &report(9, "Good: ghostscript option '-dCompatibilityLevel=1.1' detected "
1427 ."in\n'$exec_epstopdf'.");
1429 &report(4, "\nWARNING: no ghostscript option '-dCompatibilityLevel=1.1' "
1430 ."in\n'$exec_epstopdf'.\n"
1431 ."You might run into trouble with the conversions of bitmaps.\n"
1432 ."Adjusting epstopdf or setting the environment variable GS_OPTIONS "
1433 ."to \n".'"$GS_OPTIONS -dCompatibilityLevel=1.1" before calling this '
1434 ."script\nmight help in this case.\n");
1437 if ( ¶m_value('thumbpdf') eq $YES ) {
1438 &checkCommand("thumbpdf","You can switch off thumbpdf support to fix this.");
1441 if ( ¶m_value('ppower') eq $YES ) {
1442 &checkCommand("ppower","You can switch off ppower support to fix this.");
1445 ### authorindex perl script
1446 if ( ¶m_value('authorindex') eq $YES ) {
1447 &checkCommand("authorindex","You can switch off authorindex support to fix this.");
1450 ### bibtex executable
1451 if ( ¶m_value('bibtex') ne $NO or ¶m_value('gloss') ne $NO) {
1452 &checkCommand("bibtex","You can switch off BibTeX support to fix this.");
1456 #### generate the tmp file name from the original tex filename
1457 #### and make sure that they are not the same
1458 # parameter 1: orignal filename (with or without a path or .tex)
1459 # parameter 2: path for the tmp file (default: doc path)
1460 # return value: tmp name
1462 sub reserve_tmp_texname {
1463 my $original_name = $_[0];
1464 my $tmp_path = $_[1];
1465 my $tmp_base_suffix = ¶m_value('tmp_base_suffix');
1466 my $overwrite = ¶m_value('overwrite');
1470 my $pathed_tmp_base;
1473 # separate path, base and suffix
1474 ($original_base,$original_path,$suffix) = fileparse($original_name, '\.tex');
1476 # set the path of the tmp file
1478 $tmp_path=$original_path;
1480 $tmp_path .= '/' if( $tmp_path ne "" and ! ($tmp_path =~ m#/$#) );
1483 # abort if no absolute path is given
1484 if( index($tmp_path, "/") != 0 ) {
1485 &abort("Internal error: Illegal argument for reserve_tmp_texname:".
1486 "Given file has no absolute path: $original_name");
1489 # make sure that tmp_base_suffix is set correctly
1490 if($tmp_base_suffix eq "") {
1491 &abort("Temporary filename base suffix is empty.");
1494 $pathed_tmp_base = $tmp_path.$original_base.$tmp_base_suffix;
1496 # make sure no file with this base exists in this directory
1497 @existing_files = glob "$pathed_tmp_base.*";
1498 if (@existing_files != 0) {
1499 &report(3, "Problems detected while reserving temporay file name!\n",
1500 "In this directory are already files with this basename.\n",
1501 "A list of the conflicting, existing files:\n",
1502 join("\n", @existing_files), "\n");
1503 if ($overwrite eq $YES) {
1504 &report(4, "As you have activated the parameter 'overwrite' I will "
1506 "However, in order to protect the existing files I will not\n",
1507 "delete any files with this basename at the final clean-up.");
1509 &report(2, "You could activate the parameter 'overwrite' or remove ",
1510 "the\n corresponding files in order to avoid these problems.");
1511 &abort("No temporary name found for $original_name.");
1514 push(@TMP_TEX_FILES, $pathed_tmp_base);
1517 return $pathed_tmp_base.$suffix;
1520 ### generate LaTeX file from LyX document with LyX itself
1521 # parameter ($1): Lyx document
1522 # parameter ($2): Latex document
1524 sub generate_tex_file {
1525 my $lyx_doc = $_[0];
1526 my $tex_doc = $_[1];
1529 my $lyx_exec=¶m_value('lyx_exec');
1531 $lyx_dir = ¶m_value('lyxrc_path');
1532 $lyx_dir .= '/' if( ! ($lyx_dir =~ m#/$#) );
1533 $lyx_dir .= '/' if( ! ($lyx_dir =~ m#/$#) );
1535 ### Check if LyX file can be accessed
1536 &check_file($lyx_doc,"Cannot read the specified LyX document!");
1538 ### Check if LaTeX file exists and is newer than the LyX file
1539 if ( -f $tex_doc and -M $tex_doc < -M $lyx_doc ) {
1540 &report(4, "\nLaTeX file is newer than LyX document ($lyx_doc).\n",
1541 "Using existing TeX file: $tex_doc\n",
1542 "Remove it to force its new generation.");
1544 ### export LaTeX file with LyX (needs a display!)
1545 &checkCommand($lyx_exec, "Cannot generate LaTeX document without LyX!");
1546 &report(6, "\nExporting LaTeX file");
1548 ### move some files out of the way that stop LyX from exporting
1549 foreach my $file ($lyx_dir."lyxpipe.out",$lyx_dir."lyxpipe.in",$tex_doc) {
1550 if ( -f $file ) { rename($file, $file.'~'); }
1553 $lyx_output = `$lyx_exec --export latex $lyx_doc 2>&1`;
1555 ### check if LaTeX file now really exists
1556 if ( ! -f $tex_doc ) {
1557 &report(2, "Lyx Output:\n$lyx_output");
1558 &report(2, "\nSorry. I cannot find '$tex_doc'.");
1559 &abort("The LaTeX document was not generated by LyX!");
1561 &report(8, "Lyx Output:\n$lyx_output");
1566 #### search TeX document for a certain text tag (e.g. author, title)
1567 # parameter 1: file to parse
1568 # parameter 2: full TeX tag name
1569 # return value: list of the contents strings of all matching tags
1571 sub extract_tag_contents {
1576 my $error_message="Could not read TeX document to extract $tag_name";
1578 &check_file($source, $error_message.'.');
1579 open(EXTRACT_SOURCE, "<$source") or
1580 &abort($error_message." ($source).");
1583 while(<EXTRACT_SOURCE>) {
1587 s/\\thanks\{.*?\}//g;
1588 # change \and to and
1594 close EXTRACT_SOURCE;
1598 # add contents of all occurences of this tag in a line to result list
1599 while ( /\\($tag_name)(\[[^]]*?\])*?{+([^{}]*?)}/s ) {
1604 $text="" if (!defined($text));
1605 push(@results, $text);
1611 #### search for filenames in given TeX Tag in entire document
1612 ### skip all comments and duplicates while parsing
1613 # parameter 1: file to parse
1614 # parameter 2: full TeX tag name
1615 # parameter 3: reference to a list of possible filename suffixes (without '.')
1616 # parameter 4: regexp for suffix to ignore when specified in TeX file
1617 # (undef if not used)
1618 # return value: list of identified files
1620 sub identify_files {
1623 my @suffixes=@{$_[2]};
1624 my $ignore_suffix=$_[3];
1627 my $regexp_suffixes;
1629 # create one large regexp from given suffixes and escape dots in them
1630 $regexp_suffixes= '.('.join('|', @suffixes).')';
1631 $regexp_suffixes =~ s/\./\\./g;
1633 @matched_tags = &extract_tag_contents($source, $tag_name);
1635 foreach my $tag_contents (@matched_tags) {
1640 my $working_dir = cwd."/";
1642 ($base,$path,$suffix) = fileparse($tag_contents, $regexp_suffixes);
1644 # if a suffix is specified in the tag_contents handle it as requested
1646 # 1. $suffix: TRUE if $suffix is defined and not of zero length
1647 # means: a valid suffix has been found in the filename
1648 # 2. defined($ignore_suffix): TRUE if $ignore_suffix is defined
1649 # means: a regexp for suffixes to be ignored has been specified as
1651 # 3. $suffix =~ /$ignore_suffix/: TRUE if $suffix matches the regexp
1652 # means: the suffix in the filename is wanted to be ignored
1654 # The IF statement will be executed when:
1655 # a valid suffix has been found in the filename (1)
1656 # AND regexp for suffixes to be ignored has NOT been specified (not 2)
1658 # a valid suffix has been found in the filename (1)
1659 # AND regexp for suffixes to be ignored has been specified (2)
1660 # AND the suffix in the filename is NOT wanted to be ignored (not 3)
1662 # The stuff that is executed if the entire IF statement is TRUE does the
1663 # following: accept the found suffix and consider it as the only possible
1665 if($suffix and not (defined($ignore_suffix) and $suffix =~ /$ignore_suffix/)){
1666 $kpse_result=`kpsewhich $tag_contents`;
1667 # print warning and skip this tag if kpsewhich could not find it
1668 if (!$kpse_result) {
1669 &report(4, "WARNING - Could not identify referenced file:\n",
1670 " Ignoring '$tag_contents'.");
1674 # if there is a '.' in the basename assume that this is a reference
1675 # to a file of another type and skip it
1676 if( $base =~ /\./ ) {
1677 &report(9, "Found an unknown extension. Ignoring '$tag_contents'.");
1681 # search for all possible files with allowed suffixes
1682 foreach my $allowed_suffix (@suffixes) {
1683 if (not $allowed_suffix =~ /[\]\)\(\|\[\\]/ ) {
1684 # suffix is not a regexp, but a real extension
1685 my $possible_file= $path.$base.'.'.$allowed_suffix;
1686 $kpse_result=`kpsewhich $possible_file`;
1694 # if kpsewhich could not find any file with an allowed suffix
1695 # assume that this reference is of a different type and skip it
1697 if (!$kpse_result) {
1698 &report(9, "No suitable file found. Ignoring '$tag_contents'.");
1702 # expand '.' in kpsewhich output to the current path
1703 $kpse_result =~ s#^\./#$working_dir#;
1705 # remove trailing newline
1706 chomp($kpse_result);
1708 # add file to the found file list if it is not already on it
1709 if( &array_index($kpse_result, @found_files) < 0 ) {
1710 push(@found_files, $kpse_result);
1714 return @found_files;
1717 ### Build a list of all files which are included from the root file.
1718 # This function recurses, and is maybe smart enough to detect cycles.
1719 # Be sure to set REF_DOCS to the empty string prior to calling this.
1720 # parameter 1: tex file to start with
1722 # result is appended to global variable @REF_DOCS
1728 # This is the cycle avoidance logic.
1729 if ( &array_index($source, @REF_DOCS) < 0 ) {
1730 # Make sure the file can be accessed
1731 &check_file($source, "Included TeX file seems not to be available. Path problem?");
1733 # Save the argument in the list of files.
1734 push(@REF_DOCS, $source);
1736 # Get the list of files included by the argument.
1737 @imports=&identify_files($source, 'include|input', ['tex']);
1740 foreach my $file (@imports) {
1741 if( ! ($file =~ /\.tex$/) ) { $file .= '.tex'; }
1742 &get_file_list($file);
1747 ### do the required modifications in the LaTeX preamble
1748 # parameter 1: original preamble from the source file
1749 # lines before \begin{document} tag (without this tag)
1750 # parameter 2: reference to hyperref parameter list
1751 # return value: adjusted preamble
1753 sub adjust_preamble {
1754 my $preamble = $_[0];
1755 my $hyperref_params_ref = $_[1];
1761 # protect pdflatex execution mode
1762 s/^(\\batchmode)$/% $1/m;
1764 # insert a4paper in the documentclass when a4wide is used
1765 # fixes problem that hyperref defaults to letter otherwise
1766 if ( /^[^%]*\\usepackage(\[widemargins\])?\{(a4|a4wide)\}/m ) {
1767 # check if package parameters with [] brackets are present
1768 if ( not s/^(\\documentclass\[.*?)\]/$1,a4paper]/m ) {
1769 s/^\\documentclass/$&\[a4paper\]/m;
1773 ### collect additional LaTeX code
1775 $extra_code = "\n" . '\usepackage{pslatex}' . "\n";
1777 if ( ¶m_value('thumbpdf') eq $YES ) {
1778 $extra_code .= '\usepackage{thumbpdf}' . "\n";
1780 $extra_code .= "% no thumbpdf support\n";
1783 # if ( ¶m_value('ppower') eq $YES ) {
1784 # $extra_code .= '\usepackage{mpmulti}' . "\n";
1786 # $extra_code .= "% no ppower support\n";
1789 if ( ¶m_value('authorindex') eq $YES ) {
1790 $extra_code .= '\usepackage[pages]{authorindex}' . "\n";
1791 $extra_code .= '\let\cite=\aicite' . "\n";
1793 $extra_code .= "% no authorindex support\n";
1796 $extra_code .= '\makeatletter' . "\n";
1797 $extra_code .= '\usepackage[' . join(',', @$hyperref_params_ref)
1798 . ']{hyperref}' . "\n";
1799 $extra_code .= '\makeatother' . "\n";
1801 ### insert the extra LaTeX code directly after documentclass
1802 m/^(\\documentclass)(\[[^]]*\])?(\{.*\})/m;
1803 return $` . $& . $extra_code . $';
1806 ### adjust all filenames in the LaTeX code to the tmp files
1807 # parameter 1: original LaTeX code from the source file
1808 # return value: adjusted code
1810 sub adjust_filenames {
1812 my $tmp_suffix = ¶m_value('tmp_base_suffix');
1817 # cut off the suffix of eps, ps, *.gz and pstex graphics
1818 s/((\\includegraphics)(\[[^]]*?\])?(\{[^}]+?))\.(e?ps|pstex|e?ps\.gz)\n?\}/$1}/sg;
1820 # replace the suffix 'pstex_t' with 'pdf_t'
1821 s/(\\input\{[^}]+?\.)pstex_t\n?\}/$1pdf_t}/sg;
1823 if ( ¶m_value('mtp_preamble') eq $NO ) {
1824 # cut off the suffix of mmp graphics
1825 s/(\\multiinclude(\[[^]]*?\])?\{[^}]+?)\.mmp\n?\}/$1}/sg;
1827 # replace the suffix '.#' with '-mp.#'
1828 s/(\\includegraphics(\[[^]]*?\])?\{[^}]+?)\.(\d+?)\n?\}/$1$MTP_TMP_BASESUFFIX\.$3}/sg;
1830 # replace the suffix '.#' with '-mp.#'
1831 s/(\\convertMPtoPDF(\[[^]]*?\])?\{[^}]+?)\.(\d+?)\n?\}/$1$MTP_TMP_BASESUFFIX\.$3}/sg;
1833 # cut off optional suffix '.mmp' and append '-mp' in any case
1834 s/(\\multiinclude(\[[^]]*?\])?\{[^}]+?)(\.mmp)?\n?\}/$1$MTP_TMP_BASESUFFIX}/sg;
1837 # insert the tmp_suffix in tex filenames
1838 # I assume that files with no extension are TeX files as well; correct?
1839 s#(\\(input|include)\{([^}]*?/)?[^}/.]+?)((\.tex)?\n?\})#$1$tmp_suffix$4#sg;
1844 ### Convert given tex file to the temp tex file we need for pdftex
1845 ### major task is to change the reference in the tex files to the
1846 ### corresponding tmp files
1847 # parameter 1: tex source file
1848 # parameter 2: tex tmp file
1849 # parameter 3: reference to hyperref parameter list or
1850 # 'undef' if preamble should not be changed
1852 sub convert_tex2tmp {
1855 my $hyperref_params_ref = $_[2];
1859 my $adjust_preamble = defined($hyperref_params_ref) ? $YES : $NO;
1860 my $read_err_msg = "Could not read original TeX document to generate temporary document";
1862 ### open source and target file
1863 &check_file($source, $read_err_msg . '.');
1864 open(SOURCE_FILE, "<$source") or
1865 &abort($read_err_msg . " ($source).");
1867 ### read in the LaTeX source file
1869 while(<SOURCE_FILE>) {
1875 ### prepare the LaTeX code for PDF generation
1876 if ( $adjust_preamble eq $YES ) {
1877 $contents =~ m/^ *\\begin\{document\} *$/m;
1880 $preamble = &adjust_preamble($preamble, $hyperref_params_ref);
1881 $preamble = &adjust_filenames($preamble);
1887 $body = &adjust_filenames($body);
1889 ### write the new LaTeX target file
1890 open(TARGET_FILE, ">$target") or
1891 &abort("Could not open file to write temporary TeX document ($target).");
1893 print TARGET_FILE $preamble.$body;
1898 ### Convert the given EPS image to PDF
1899 # parameters $1: EPS image filename with absolute path
1900 # return value: none
1902 sub convert_eps2pdf {
1912 ($image_base,$image_path,$suffix) = fileparse($image, '\.eps', '\.ps', '\.pstex', '\.gz');
1913 if ($suffix eq "\.gz") {
1915 ($image_base,$dummy,$suffix) = fileparse($image_base, '\.eps', '\.ps', '\.pstex');
1917 $image_name = $image_base . $suffix;
1918 $image_target = $image_path . $image_base . '.pdf';
1920 #### check if image file really exists
1921 #&check_file($image, "Could not convert referenced image.");
1923 ### return if image directory is not writeable
1924 if (! -w $image_path) {
1925 &report(4, "WARNING - Image directory not writable: $image_path\n",
1926 " Skipping '$image_name', assume you have converted it manually.");
1930 if ( ! -f $image_target or -M $image_target > -M $image ) {
1931 &report(7, "Converting image $image_name to $image_target ...\n");
1933 &system_command("gunzip -c $image | epstopdf -f -outfile=$image_target",
1934 $TRUE, 8, "epstopdf failed on $image_name");
1936 &system_command("epstopdf -outfile=$image_target $image",
1937 $TRUE, 8, "epstopdf failed on $image_name");
1939 if (¶m_value('delete_pdf_images') eq $YES) {
1940 push(@TMPFILES, $image_target);
1943 &report(7, "$image_base.pdf newer than $image_name, conversion skipped...");
1947 ### Convert the given PSTEX_T file to PDF_T
1948 # parameters 1: PSTEX_T filename with absolute path
1949 # return value: none
1951 sub convert_pstex2pdf {
1952 my $pstex_file = $_[0];
1960 ($pstex_base,$pstex_path,$suffix) = fileparse($pstex_file, ('\.pstex_t'));
1961 $pstex_name = $pstex_base . $suffix;
1962 $pstex_target = $pstex_path . $pstex_base . '.pdf_t';
1964 #### check if image file really exists
1965 #&check_file($pstex_file, "Could not convert referenced file.");
1967 ### return if directory is not writeable
1968 if (! -w $pstex_path) {
1969 &report(4, "WARNING - Directory not writable: $pstex_path\n",
1970 " Skipping '$pstex_name', assume you have converted it manually.");
1975 &report(7, "Converting file $pstex_name ...\n");
1977 # find included EPS image(s)
1978 @eps_images=&identify_files($pstex_file, 'includegraphics',
1979 ['pstex', 'pstex\.gz']);
1981 # create .pdf_t file
1982 &convert_tex2tmp($pstex_file, $pstex_target, undef);
1984 # put tmp file in the tmp file list
1985 push(@TMPFILES, $pstex_target);
1987 # convert image(s) to pdf
1988 foreach my $image (@eps_images) {
1989 &convert_eps2pdf($image);
1993 ### Convert the given MP image to PDF
1994 # parameters $1: MP image filename with absolute path
1995 # return value: none
1997 sub convert_mp2pdf {
2008 ($image_base,$image_path,$suffix) = fileparse($image, '\.mp|\.mmp');
2009 $image_name = $image_base . $suffix;
2010 $image_src=$image_path . $image_base . $suffix;
2012 @mps_fig= &grep_file($image_path.$image_name,'beginfig',$TRUE);
2016 if (¶m_value('mtp_preamble') eq $YES) {
2017 $image_target = $image_path . $image_base . $MTP_TMP_BASESUFFIX . '.' . $mp_fig;
2018 $image_name=$image_base.$MTP_TMP_BASESUFFIX.$suffix;
2020 $image_target = $image_path . $image_base . '.' . $mp_fig;
2023 #### check if image file really exists
2024 #&check_file($image, "Could not convert referenced image.");
2026 ### return if image directory is not writeable
2027 if (! -w $image_path) {
2028 &report(4, "$MYNAME: WARNING - Image directory not writable: $image_path\n",
2029 " Skipping '$image_name', assume you have converted it manually.");
2033 if ( ! -f $image_target
2034 or (-M $image_target > -M $image_src)
2035 or ( ( ¶m_value('mtp_preamble') eq $YES)
2036 and (-M $image_target > -M $image_path.$MTP_PREAMBLE_FILENAME) ) ) {
2037 &report(7, "Converting image $image_name ...\n");
2038 my $working_dir = cwd."/";
2039 chdir("$image_path") or &abort("cannot cd to $image_path($!)");
2040 if ( ¶m_value('mtp_preamble') eq $YES ) {
2041 &modify_mp_file($image_base,$suffix);
2043 &system_command("mpost $image_name",
2044 $TRUE, 8, "mpost failed on $image_name");
2045 chdir("$working_dir") or &abort("cannot cd to $working_dir($!)");
2046 if (¶m_value('delete_pdf_images') eq $YES) {
2047 push(@TMPFILES, $image_target);
2050 if ( ¶m_value('mtp_preamble') eq $YES ) {
2051 &report(7, "$image_base$MTP_TMP_BASESUFFIX.$mp_fig newer than $image_base$suffix, conversion skipped...");
2053 &report(7, "$image_base.$mp_fig newer than $image_base$suffix, conversion skipped...");
2058 ### Convert the given MP image to PDF
2059 # parameters $1: MP image filename with absolute path
2060 # return value: none
2062 sub modify_mp_file {
2065 my $preamble_file=$MTP_PREAMBLE_FILENAME;
2067 my $mp_source=$base.$suffix;
2068 my $mp_target=$base.$MTP_TMP_BASESUFFIX.$suffix;
2070 ### open source and target file
2071 open(SOURCE_FILE, "<$mp_source") or
2072 &abort("Could not open $mp_source to add $preamble_file ($mp_source).");
2074 open(TARGET_FILE, ">$mp_target") or
2075 &abort("Could not open $mp_target to add $preamble_file ($mp_source).");
2077 open(PREAMBLE_FILE, "<$preamble_file") or
2078 &abort("Could not open $preamble_file to be added to metapost files ($mp_source).");
2080 ### set target file as stdout
2082 print 'verbatimtex' . "\n";
2083 print '%&latex' . "\n"; # This forces metapost to use latex in the compilation
2084 print '\documentclass[english]{article}' . "\n"; # we have to decide if this sentence goes in preamble.cfg or here
2085 # english must be added
2086 # to preamble in order to
2087 # make work mpost, why ???
2088 while(<PREAMBLE_FILE>) {
2091 print '\begin{document}' . "\n"; # we have to decide if this sentence goes in preamble.cfg or here
2092 print 'etex' . "\n";
2093 while(<SOURCE_FILE>) {
2096 print 'verbatimtex' . "\n";
2097 print '\end{document}' . "\n";
2098 print 'etex' . "\n";
2100 ### set STDOUT as stdout again
2106 close PREAMBLE_FILE;
2111 ### Convert included images to pdf
2112 # parameter 1: tex source file
2115 sub convert_images {
2116 my $tex_source=$_[0];
2117 my @pstex_file_list;
2124 &report(6, "\nConverting images referenced in $tex_source.");
2126 ##### Get images of major type from the source file
2127 @major_suffixes = (@BITMAP_SUFFIXES, $PDF_ORIG_SUFFIX, @EPS_SUFFIXES);
2128 $ignore_regexp = '.('.join('|',@EPS_SUFFIXES).')';
2129 $ignore_regexp =~ s/\./\\./g;
2131 &report(6, "\nScanning for major image types (".join(', ',@major_suffixes)."):");
2132 @image_list = &identify_files($tex_source,'includegraphics',
2133 \@major_suffixes, $ignore_regexp );
2135 if ( @image_list > 0 ) {
2136 &report(7, join("\n", @image_list));
2138 &report(7, "None.");
2141 ##### Get PSTEX_T files from the source file
2142 &report(6, "\nScanning for PSTEX_T files (.pstex_t):");
2143 @pstex_file_list=&identify_files($tex_source, 'input', ['pstex_t']);
2144 if ( @pstex_file_list > 0 ) {
2145 &report(7, join("\n", @pstex_file_list));
2147 &report(7, "None.");
2150 ##### Get MP images from the source file
2151 &report(6, "\nScanning for MP images (.mp):");
2152 @mp_image_list=&identify_files($tex_source,
2153 'convertMPtoPDF|includegraphics',['mp','(\d+)'],'\.(\d+)');
2155 # fixed for now by ignoring strange extension in identify_files
2157 # the above could cause problems as identify_files is expecting a list of
2158 # real extensions and not of regexps
2159 # maybe the only way to fix this is to adjust identify_files to ignore
2160 # invalid extension when testing them with kpsewhich
2161 # ALTERNATIVE: design identify_files to use preffered_suffixes instead
2162 # of ignore_suffixes
2164 if ( @mp_image_list > 0 ) {
2165 &report(7, join("\n", @mp_image_list));
2167 &report(7, "None.");
2170 ##### Get MMP images from the source file
2171 &report(6, "\nScanning for MMP images (.mmp):");
2172 @mmp_image_list=&identify_files($tex_source,'multiinclude',['mmp']);
2173 if ( @mmp_image_list > 0 ) {
2174 &report(7, join("\n", @mmp_image_list));
2176 &report(7, "None.");
2179 ### Convert EPS images to PDF, copy pdf.orig image files to pdf,
2180 ### and simply ignore all other
2181 if ( @image_list > 0) {
2182 my $handled_suffixes;
2184 &report(6, "\nProcessing images of major types:");
2186 # create one large regexp from suffixes and escape dots in them
2187 $handled_suffixes = '.('.join('|',(@EPS_SUFFIXES, $PDF_ORIG_SUFFIX)).')';
2188 $handled_suffixes =~ s/\./\\./g;
2190 foreach my $image (@image_list) {
2194 ($base,$path,$suffix) = fileparse($image, $handled_suffixes);
2196 &report(7, "No special handling required for image: $base$suffix");
2197 } elsif ($suffix eq ('.'.$PDF_ORIG_SUFFIX) ) {
2198 my $image_target = $path.$base.'.pdf';
2200 if ( ! -f $image_target or -M $image_target > -M $image ) {
2201 &report(7, "Create temporary PDF file from original: $base$suffix");
2202 copy($image, $image_target)
2203 or &abort("Could not create tmp file: $!");
2204 if (¶m_value('delete_pdf_images') eq $YES) {
2205 push(@TMPFILES, $image_target);
2208 &report(7, "$base.pdf newer than $base$suffix, copy skipped ...");
2211 &convert_eps2pdf($image);
2216 ### Convert all PSTEX_T files to PDF_T
2217 if ( @pstex_file_list > 0 ) {
2218 &report(6, "\nConverting pstex_t docs to pdf_t docs");
2219 foreach my $image (@pstex_file_list) {
2220 &convert_pstex2pdf($image);
2224 ### Convert all MP images to PDF
2225 if ( @mp_image_list > 0) {
2226 &report(6, "\nConverting MP images to PDF");
2227 foreach my $image (@mp_image_list) {
2228 &convert_mp2pdf($image);
2232 ### Convert all MMP images to PDF
2233 if ( @mmp_image_list > 0) {
2234 &report(6, "\nConverting MMP images to PDF");
2235 foreach my $image (@mmp_image_list) {
2236 &convert_mp2pdf($image);
2240 &report(6, "\nFinished converting for ${tex_source}.");
2244 # parameter 1: LaTeX file without extension
2245 # parameter 2: log-file where the full out put is stored
2246 # return value: 0 - no errors (no rerun); 1 - errors (rerun required)
2253 my $extra_options=¶m_value('pdftex_opts');
2255 if( !defined($extra_options) or $extra_options eq $NIL ) {
2256 $extra_options = "";
2259 &report(7, "Running pdflatex. This may take a while.\n");
2260 system("pdflatex --interaction nonstopmode $extra_options $texfile > $logfile 2>&1");
2262 &report(7, "Pdflatex finished. Errors:");
2264 ### extract all errors and warnings from the log file
2265 @errors = &grep_file($logfile, '(Emergency stop|Error|Warning).*:');
2267 ### make sure thumbpdf package does not spoil rerun detection
2268 ### as it will be processed very last
2269 if(grep(/Package thumbpdf/, @errors) == @errors) { @errors=(); }
2271 if ( @errors != 0 or $exit_status != 0 ) {
2272 if ( grep(/Emergency stop/, @errors) != 0 ) {
2273 &report(2, &file_tail($logfile,10));
2274 &report(2, "\nSee $logfile for details.");
2275 &abort("Fatal error occured. I am lost.");
2277 if( @errors != 0 ) {
2278 &report(8, @errors);
2280 &report(8, &file_tail($logfile,10));
2282 &report(7, "\nSee $logfile for details.");
2285 &report(7, "None detected (log file: $logfile).");
2290 #### run bibtex if BIBTEX=$YES or a bibliography tag is found
2291 # included tex files are not parsed for a bibliography
2292 # parameter 1: filename of the aux file without .aux suffix
2293 # parameter 2: log-file where the full out put is stored
2298 my $run_bibtex=$FALSE;
2299 my $bibtex_param=¶m_value('bibtex');
2301 if ( $bibtex_param eq $YES ) {
2303 &report(7, "BibTeX parameter set to '$YES':");
2305 &report(7, "Checking for BibTeX bibliography in main document: ");
2306 if( &grep_file($auxfile.'.tex', '^[^%]*\\\\bibliography{') != 0) {
2308 &report(7, "Bibliography detected.");
2310 if ( @REF_DOCS > 0 ) {
2311 &report(7, "Checking for BibTeX bibliography in included documents:");
2312 foreach my $file (@REF_DOCS) {
2313 if( &grep_file($file, '^[^%]*\\\\bibliography{') != 0) {
2315 &report(7, "Bibliography detected.");
2317 &report(7, "No bibliography detected in $file.");
2321 &report(7, "No bibliography detected.");
2326 if ( $run_bibtex ) {
2330 &report(7, "Running bibtex. This may take a while.\n");
2331 system "bibtex $auxfile > $logfile";
2333 &report(7, "Bibtex finished. Errors:");
2335 ### extract all errors and warnings from the log file
2336 @errors=&grep_file($logfile, 'error message');
2338 if ( @errors != 0 or $exit_status != 0 ) {
2339 &report(4, &file_tail($logfile));
2340 &report(4, "\nYou can switch off BibTeX support by setting the bibtex parameter accordingly.");
2342 &report(7, "None detected (log file: $logfile).");
2347 #### run bibtex on file.gls if BIBTEX=$YES or a bibliography tag is found
2348 # included tex files are not parsed for a bibliography
2349 # parameter 1: filename of the aux file without .aux suffix
2350 # parameter 2: log-file where the full out put is stored
2355 my $run_gloss=$FALSE;
2356 my $gloss_param=¶m_value('gloss');
2357 my $glsfile=$auxfile.'.gls';
2359 if ( $gloss_param eq $YES ) {
2361 &report(7, "Gloss parameter set to '$YES':");
2363 &report(7, "Checking for Gloss bibliography in main document: ");
2364 if( &grep_file($auxfile.'.tex', '^[^%]*\\\\printgloss{') != 0) {
2366 &report(7, "Gloss bibliography detected.");
2368 if ( @REF_DOCS > 0 ) {
2369 &report(7, "Checking for Gloss bibliography in included documents:");
2370 foreach my $file (@REF_DOCS) {
2371 if( &grep_file($file, '^[^%]*\\\\printgloss') != 0) {
2373 &report(7, "Gloss bibliography detected.");
2375 &report(7, "No gloss database detected in $file.");
2379 &report(7, "No gloss database detected.");
2387 &report(7, "Running bibtex on $glsfile. This may take a while.\n");
2388 system "bibtex $glsfile > $logfile 2>&1";
2390 &report(7, "Bibtex finished. Errors:");
2392 ### extract all errors and warnings from the log file
2393 @errors=&grep_file($logfile, 'error message');
2395 if ( @errors != 0 or $exit_status != 0 ) {
2396 &report(4, &file_tail($logfile));
2397 &report(4, "\nYou can switch off Gloss support by setting the gloss parameter accordingly.");
2399 &report(7, "None detected (log file: $logfile).");
2404 #### run thumbpdf command to make thumbnails
2405 # more informations: /usr/share/texmf/doc/pdftex/thumbpdf/readme.txt
2406 # parameter 1: LaTeX file without extension
2407 # parameter 2: log-file where the full out put is stored
2414 &report(7, "\nCreating thumbnails with 'thumbpdf'\n");
2415 &system_command("thumbpdf $texfile", $FALSE, 8,
2416 "thumbpdf failed.\n"
2417 ."I will continue, but maybe there will not be thumbs in the PDF doc.");
2419 if ( -f 'thumbpdf.log' ) {
2420 move('thumbpdf.log', $logfile);
2421 &report(7, "\nSee $logfile for details.");
2424 ### store possible tmp files
2425 push(@TMPFILES, glob 'thumb???.png');
2426 push(@TMPFILES, 'thumbpdf.pdf');
2427 push(@TMPFILES, 'thumbdta.tex');
2428 push(@TMPFILES, $texfile.'.tpt');
2432 #### run ppower command to make presentations
2433 # more informations:
2434 # parameter 1: LaTeX file without extension
2435 # parameter 2: log-file where the full out put is stored
2447 ##### Getting document name, suffix and path
2448 ($texfile_base,$texfile_path,$texfile_suffix) = fileparse($texfile,¶m_value('tmp_base_suffix'));
2450 $infile=$texfile_base.'.pdf';
2451 $outfile=$texfile_base.'_p4.pdf';
2453 &report(7, "\nPostprocessing PDF file with 'ppower'\n");
2454 if(&system_command("ppower $infile $outfile", $FALSE, 8,
2455 "ppower failed.\nI will continue, "
2456 ."but maybe there will not be pause effects in the PDF doc.")) {
2457 &report(7, "\nThe postprocessed pdf file is: $outfile\n");
2460 if ( -f 'ppower.log' ) {
2461 move('ppower.log', $logfile);
2462 &report(7, "See $logfile for details.");
2466 #### run authorindex command to obtain an author index
2467 # more informations:
2468 # parameter 1: LaTeX file without extension
2469 # parameter 2: log-file where the full out put is stored
2471 sub run_authorindex {
2476 &report(7, "\nProcessing file with 'authorindex'\n");
2477 &system_command("authorindex $texfile", $FALSE, 8,
2478 "authorindex failed.\nI will continue, "
2479 ."but maybe there will not be an author index in the PDF doc.");
2481 if ( -f 'authorindex.log' ) {
2482 move('authorindex.log', $logfile);
2483 &report(7, "\nSee $logfile for details.");
2489 ##### read and analyse configuration and options and adjust basic variables
2491 #### The following sources are considered (last value overrides previous)
2492 ## 1. general configuration (global variables in the script)
2493 ## 2. private configuration (in user's RC file)
2494 ## 3. command line options
2496 # return value: given document argument
2498 sub adjust_configuration {
2499 my $valid_rcfile = $FALSE;
2502 ### Check number of arguments
2504 &report(1, "\nI need at least one argument!");
2509 ##### command line options and private configuration files handling
2511 ### set parameters from rc file
2512 if ( -f $RC_FILENAME ) {
2514 $rcfile_version = &read_configuration($RC_FILENAME);
2515 if( $rcfile_version == $MYRCFILE_VERSION ) {
2516 $valid_rcfile = $TRUE;
2517 } elsif ( $rcfile_version == 0 ) {
2518 &report(4, "Could not determine version of read RC file.");
2520 &report(4, "Version of read RC file ($rcfile_version) and ",
2521 "this script ($MYRCFILE_VERSION) differs.");
2526 foreach (keys %PARAMETER_LIST) {
2527 $opt_specs{&option_specifier($_)} = \&handle_option;
2529 if(! GetOptions(%opt_specs)) {
2531 &abort("An error occured while processing command line options");
2534 if( ! $valid_rcfile ) {
2535 &report(3,"No valid configuration file found. Please run '$MYNAME "
2536 ."--configure'.\nUsing default values for missing parameters in this "
2540 ### As the configuration process is done now, it is time to set the
2541 # global configuration flag
2542 $CONFIGURED = $TRUE;
2544 #### do some test in order to secure as good as possible that we will
2545 #### succeed before to much work was done and maybe some data as damaged
2547 ### make sure that tmp_base_suffix is not empty
2548 if ( ¶m_value('tmp_base_suffix') eq "" ) {
2549 &report(2, "\nCAUTION: Empty tmp_base_suffix would destroy the original files!");
2550 &abort("Parameter tmp_base_suffix is not set.");
2553 ##### check for required commands
2554 if (¶m_value('check_commands') ne $NO ) {
2558 ### Check number of arguments
2560 &report(1, "\nWrong number of arguments. I need exactly one file.");
2568 #### prepare the logdir for the log files of the various called appplications
2570 sub prepare_logdir {
2571 my $log_dir= ¶m_value('logdir');
2574 ##### Preparing the LOGDIR
2575 if (! &check_dir($log_dir, "Could not create log directory", $YES)) {
2576 &abort("Please, set a different path and restart");
2579 # make sure there is a slash at the end of the path
2580 $log_dir .= '/' if( ! ($log_dir =~ m#/$#) );
2582 if( <$log_dir/*.log> and ¶m_value('clean_logs') eq $YES ) {
2583 &report(6, "\nRemoving old log files ($log_dir).");
2584 unlink (<$log_dir/pdflatex-*.log>, <$log_dir/bibtex-*.log>,
2585 <$log_dir/gloss-*.log>, <$log_dir/thumbpdf-*.log>,
2586 <$log_dir/ppower-*.log>, <$log_dir/authorindex-*.log>,
2587 <$log_dir/tex2pdf-*.log>);
2589 &report(6, "\nAll log files will be stored in ($log_dir).");
2592 ### move my pre-configuration log file to specified log directory
2593 $my_new_log = "$log_dir/tex2pdf-$$.log";
2594 if ( move($MYLOGFILE, $my_new_log) ) {
2595 $MYLOGFILE = $my_new_log;
2597 &report(3, "Could not move '$MYLOGFILE' to logdir: $!");
2601 ##### analyse document argument
2602 #### process the one and only argument (besides the options) which specifies
2603 #### which LaTeX document the user wants to translate to PDF
2604 #### a lyx file will be translated to LaTeX first
2605 # parameter 1: argument
2607 sub process_doc_argument {
2608 my $argument = $_[0];
2613 ##### Getting document name, suffix and path
2614 ($doc_base,$doc_path,$arg_suffix) = fileparse($argument, ('\.tex', '\.lyx'));
2616 if (! defined($arg_suffix) or $arg_suffix eq "") {
2617 $arg_suffix = '.tex';
2620 ###### change working directory to document directory
2621 if ( $doc_path ne "" ) {
2625 ###### make DOCPATH an absolute path
2626 $doc_path = cwd.'/';
2628 ###### Cut off suffix and do lyx or tex specific stuff
2629 if ( $arg_suffix eq '.lyx' ) {
2630 # Lyx document argument: generate Latex document if required
2631 &generate_tex_file($doc_base.'.lyx', $doc_base.'.tex');
2633 # LaTeX document argument: check access to given LaTeX document
2634 &check_file($doc_base.'.tex', "Cannot read the specified LaTeX document!");
2637 return $doc_path.$doc_base.'.tex';
2640 #### handle the dir of the input path if the document has one and
2641 # parameter 1: main tex doc
2642 # return value: absolute input path
2644 sub process_inputpath {
2652 ### Maybe the user has given us a different inputpath
2653 $input_path = ¶m_value('input_path');
2654 if(defined($input_path) and $input_path ne "") {
2655 &report(6, "Setting input path to specified directory: $input_path");
2657 &report(7, "Change working directory to input path.");
2663 ##### Getting document name, suffix and path
2664 ($doc_base,$doc_path,$doc_suffix) = fileparse($texdoc, ('\.tex'));
2666 ###### change working directory to input_path if set
2667 # When the files' path (images, included documents, etc.) in your document is
2668 # relative to another directory than the PASSED document's directory.
2669 # This is useful when the calling application (e.g. LyX) generates a
2671 # TeX file and calls the tex2pdf with it instead of the original file.
2673 @matches=&extract_tag_contents($texdoc, 'def\\\\input@path');
2674 $input_path=$matches[0];
2676 ## check if input_path is ok
2678 &report(7, "Found an input path in the latex document: $input_path");
2679 if( &check_dir($input_path, 'The retrieved input@path seems not to be valid.', $NO)) {
2680 &set_param_value('input_path', $input_path);
2681 &report(7, "Change working directory to input path.");
2684 &abort ('I am lost.');
2687 &report(4, "No input path in the latex document found.");
2688 &report(7, "Resources are expected to be relative to document's location: $doc_path");
2689 $input_path=$doc_path;
2695 #### set the working dir to the input path if the document has one and
2696 #### and determine the path for the result
2697 # parameter 1: main tex doc
2698 # parameter 2: absolute input path
2699 # return value: absolute path were the resulting pdf doc should be stored
2701 sub get_target_name {
2703 my $input_path=$_[1];
2711 ##### Getting document name, suffix and path
2712 ($doc_base,$doc_path,$doc_suffix) = fileparse($texdoc, ('\.tex'));
2714 ##### set the directory where the final pdf will be stored
2715 $destination=¶m_value('destination');
2718 if ($destination eq 'custom' ) {
2719 $pdf_path=¶m_value('custom_path');
2720 } elsif ($destination eq 'input') {
2721 $pdf_path=$input_path;
2723 $pdf_path=$doc_path;
2726 if( ! defined($pdf_path) or $pdf_path eq "" or ! &check_dir($pdf_path,
2727 'The specified destination directory for the final PDF documents is not valid.', $NO)) {
2728 &report(7, "Using document's instead of destination path: $doc_path");
2729 $pdf_path=$doc_path;
2732 # make sure there is a slash at the end of the path
2733 $pdf_path .= '/' if( ! ($pdf_path =~ m#/$#) );
2735 return $pdf_path.$doc_base.'.pdf';
2738 ### generate hyperref parameters from given settings
2739 # parameter 1: main tex doc
2740 # return_value: result
2742 sub generate_hyperref_params {
2745 my @params = ('pdftex');
2747 ##### Set title and author from main LaTeX document or parameters
2748 foreach my $info (('title', 'author')) {
2751 $value=¶m_value("$info");
2752 if (! defined($value) ) {
2753 my @matches=&extract_tag_contents($texdoc, $info);
2754 $value= $matches[0];
2755 if (! defined($value) ) {
2756 &report(4, "\nWARNING: Could not identify document's $info correctly.");
2757 &report(7, "Maybe you have used a LaTeX tag inside the $info which confuses me.\n",
2758 "Adjust the $info of the LaTeX file in order to avoid the problem or\n",
2759 "you could set the $info parameter manually.");
2760 $value= ¶m_value("default_$info");
2761 &report(7, "Using default-$info: $value");
2764 if (! defined($value) or $value eq $NIL ) {
2765 &report(7, "$info field set to $NIL - no value will be passed.");
2767 &report(7, "Document's $info: $value");
2768 push(@params, "pdf$info={$value}");
2772 $para=¶m_value('paper');
2773 if ( $para ne $NIL ) { push(@params, $para); }
2775 $para=¶m_value('link_toc_page');
2776 if ( $para eq $YES ) { push(@params, 'linktocpage'); }
2778 $para=¶m_value('colorlinks');
2779 if ( $para ne $NIL ) {
2780 $para= $para eq $YES ? 'true' : 'false';
2781 push(@params, "colorlinks=$para");
2784 if ( $para ne 'false' ) {
2785 foreach (('linkcolor', 'pagecolor', 'urlcolor', 'citecolor')) {
2786 $para=¶m_value($_);
2787 if ( $para ne $NIL ) { push(@params, "$_={$para}"); }
2791 $para=¶m_value('hyperref_args');
2792 if(defined($para) and $para ne "" and $para ne $NIL) {
2793 push(@params, $para);
2799 #### Prepare the main document and all referenced ones for the generation
2800 #### of the PDF document (including referenced images)
2801 # parameter 1: top level tex document
2802 # parameter 2: parameter list of hyperref parameters
2804 sub prepare_documents {
2805 my ($main_tex_doc, $input_path, @hyperref_params) = @_;
2808 ## get a name for the tmp tex file
2809 my $main_tmp_doc = &reserve_tmp_texname($main_tex_doc, $input_path);
2811 ## Get the list of imported files from the tex file
2812 &get_file_list($main_tex_doc);
2814 ## remove main file from list (first element; needs special handling)
2817 ## tell user about the identified refereneced docs
2818 if ( @REF_DOCS > 0 ) {
2819 &report(7, "\nFound the following referenced TeX files:");
2820 foreach my $file (@REF_DOCS) {
2821 &report(7, ">>>>> $file");
2824 &report(7, "\nFound no referenced TeX files.");
2827 ##### Generate adjusted temp tex files and convert all their images
2829 &report(6, "\nGenerating main temporary LaTeX document: $main_tmp_doc");
2830 &convert_tex2tmp($main_tex_doc, $main_tmp_doc, \@hyperref_params);
2831 &convert_images($main_tex_doc);
2834 foreach my $file (@REF_DOCS) {
2835 my $tmp_file = &reserve_tmp_texname($file);
2837 ### Insert pdf conversation tags in tex file and write it to tmp_file
2838 &report(7, "\nGenerating temporary LaTeX document: $tmp_file");
2839 &convert_tex2tmp($file, $tmp_file, undef);
2840 &convert_images($file);
2843 return $main_tmp_doc;
2846 ##### Generate the final PDF document
2847 # parameter 1: filename of the source LaTeX document (with extension)
2849 sub generate_pdf_doc {
2859 my $max_run_no= ¶m_value('maxrun');
2860 my $min_run_no= ¶m_value('minrun');
2861 my $log_dir= ¶m_value('logdir');
2862 $log_dir .= '/' if( ! ($log_dir =~ m#/$#) );
2863 my $makeindex_options=¶m_value('makeindex_opts');
2865 # setting the log files for the output of pdflatex, bibtex, gloss,
2866 # thumbpdf, ppower and authorindex
2867 my $pdflog_base = $log_dir."pdflatex-$$-";
2868 my $bibtex_log = $log_dir."bibtex-$$.log";
2869 my $gloss_log = $log_dir."gloss-$$.log";
2870 my $thumbpdf_log = $log_dir."thumbpdf-$$.log";
2871 my $ppower_log = $log_dir."ppower-$$.log";
2872 my $authorindex_log = $log_dir."authorindex-$$.log";
2874 ##### Getting document name, suffix and path
2875 ($base,$path,$suffix) = fileparse($source, ('\.tex'));
2877 $pdf_doc = $base.'.pdf';
2879 ### run pdflatex until no more errors are reported (max MAXRUNNO)
2880 while ( $rerun and $runno <= $max_run_no )
2882 &report(6, "\n************ Pdflatex run no. $runno *************");
2883 if ( &run_pdflatex($doc, $pdflog_base.$runno.'.log') == $TRUE
2884 and ( $min_run_no <= $runno )) {
2885 # no errors detected and min. no. of runs are done
2888 # errors appeared or max run no. has not been reached
2892 ### Execute BibTeX after first run if set (and required)
2893 if ( $runno == 1 and ¶m_value('bibtex') ne $NO ) {
2894 &report(6, "\n****************** BibTeX handling ***********************");
2895 &handle_bibtex($doc, $bibtex_log);
2898 ### Execute BibTeX on file.gls after first run if set (and required)
2899 if ( $runno == 1 and ¶m_value('gloss') ne $NO ) {
2900 &report(6, "\n****************** Gloss handling ***********************");
2901 &handle_gloss($doc, $gloss_log);
2904 ### generated index file exists
2905 if ( $runno == 1 and -f $doc.'.idx' and ¶m_value('force_index') ne $NO ) {
2906 if( !defined($makeindex_options) or $makeindex_options eq $NIL ) {
2907 $makeindex_options = "";
2909 &report(6, "\n****************** Extra index generation ***************");
2910 &report(7, "Document seems to have an index. Generating ...\n");
2911 &system_command("makeindex $makeindex_options $doc.idx", $FALSE, 8,
2912 "makeindex failed.\nI will continue, "
2913 ."but maybe there will not be an index in the PDF doc.");
2921 ### if the authorindex option is switched on then run authorindex
2922 if ( ¶m_value('authorindex') eq $YES ) {
2923 &report(6, "\n****************** authorindex generation *****************");
2924 &run_authorindex($doc, $authorindex_log);
2927 ### generated index file exists
2928 if ( -f $doc.'.idx' and ¶m_value('force_index') ne $NO ) {
2929 if( !defined($makeindex_options) or $makeindex_options eq $NIL ) {
2930 $makeindex_options = "";
2932 &report(6, "\n****************** Extra index generation ***************");
2933 &report(7, "Document seems to have an index. Generating ...\n");
2934 &system_command("makeindex $makeindex_options $doc.idx", $FALSE, 8,
2935 "makeindex failed.\nI will continue, "
2936 ."but maybe there will not be an index in the PDF doc.");
2940 ### if the thumbpdf option is switched on then make thumbnails
2941 if ( ¶m_value('thumbpdf') eq $YES ) {
2942 &report(6, "\n****************** Thumbnail generation *****************");
2943 &run_thumbpdf($doc, $thumbpdf_log);
2947 ### One final pdflatex run if requested
2949 &report(6, "\n************ One final pdflatex run no. $runno *************");
2950 &run_pdflatex($doc, $pdflog_base.$runno.'.log');
2953 ### if the ppower option is switched on then run ppower
2954 if ( ¶m_value('ppower') eq $YES ) {
2955 &report(6, "\n****************** ppower postprocess *****************");
2956 &run_ppower($doc, $ppower_log);
2959 if ( ! -f $pdf_doc ) {
2960 &abort("\nThe new PDF file could not be generated: ".$pdf_doc);
2966 ################## Lift off !!!! (main part) ##################
2972 my @hyperref_params;
2976 &report(5, "\nScript starts ($MYRELEASE)");
2978 ##### read and analyse configuration and options and adjust basic variables
2980 ##### write RC file on config request
2981 #### use the finished configuration to get all further settings before we
2982 #### actually start doing something
2984 &report(5, "\nProcessing given parameters and arguments.");
2985 $doc_argument = &adjust_configuration;
2987 #### prepare the script to write some information to specified log files
2989 &report(5, "\nPreparing directory for log files.");
2992 #### process the one and only argument (besides the options) which specifies
2993 #### which LaTeX document the user wants to translate to PDF
2994 #### a lyx file will be translated to LaTeX first
2996 &report(5, "\nAnalysing your document argument.");
2997 $texdoc = &process_doc_argument($doc_argument);
2999 #### we would like to get some more information from the actual
3000 #### main LaTeX document before we really start
3001 #### parse the document and try to get the info
3003 ## translate hyperref settings to the actual package parameters
3005 &report(5, "\nSetting up parameters for hyperref.");
3006 @hyperref_params = &generate_hyperref_params($texdoc);
3008 ## set the working dir to the input path if the document has one and
3010 &report(5, "\nProcessing input path for main tex document.");
3011 $input_path = &process_inputpath($texdoc);
3013 ## determine the name for the result
3015 &report(5, "\nSetting the correct name for the result.");
3016 $target_name = &get_target_name($texdoc, $input_path);
3018 ## as much as possible is prepared in advance at this point
3019 ## so hopefully we will succeed in generating the PDF document
3021 ##### real work starts NOW
3023 ##### Generate adjusted temp tex files and convert all their images
3025 &report(5, "\nPreparing all documents and images.");
3026 $tmp_tex_doc = &prepare_documents($texdoc, $input_path, @hyperref_params);
3028 ##### Generate the final PDF document
3030 &report(5, "\nProcessing the actual generation of the PDF document.");
3031 $new_pdf_doc = &generate_pdf_doc($tmp_tex_doc);
3034 move($new_pdf_doc, $target_name) or &abort("Could not move PDF file to final destination: $!");
3036 if ( ¶m_value('debug') eq $NO ) {
3042 &report(5, "\nThe new pdf file is: $target_name\n");