Whamcloud - gitweb
d2c57382ac185f32d50e45f5792153ca7bf6598e
[fs/lustre-release.git] / lustre / doc / tex2pdf
1 #!/usr/bin/perl -w
2
3 #      tex2pdf - script for translating latex docs to pdf
4 #
5 #      Copyright (C) 2000-2002 by Steffen Evers and others
6 #
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.
10 #
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.
15 #
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.
19 #
20 #      The GNU General Public License is also available online:
21 #      http://www.gnu.org/licenses/gpl.html
22 #
23 # Thanks a lot to all the people that have already contributed to this project!
24 #
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). 
27 #
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
35 #
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
40 #
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).
45 #
46 # Send feedback to: tex2pdf-devel@lists.berlios.de
47 #
48
49 ######## Imports
50
51 use File::Basename;
52 use File::Copy;
53 use Getopt::Long;
54 use Sys::Hostname;
55 use Cwd;
56 use strict;
57
58 ####### global variables
59
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'; }
67
68 my @TMPFILES=();
69 my @TMP_TEX_FILES=(); 
70 my $NUM_PARAM_MIN=0;
71 my $NUM_PARAM_MAX=9;  
72 my @REF_DOCS;
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' );
78
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;
84
85 ### text token for no value
86 my $NIL="NOVALUE";
87 my $UNDEF="undefined";
88
89 ### token for boolean 'false', 'no' 
90 my $NO="no";
91 my $FALSE=0;
92
93 ### token for boolean 'true', 'yes' 
94 my $YES="yes";
95 my $TRUE=1;
96
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";
103
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;
108
109 ########################## NEW PERL CONFIGURATON
110
111 my %CONFIGURATION = ();
112 my %PARAMETER_LIST = ();
113 my @PARAMETER_ORDER = ();
114 my %PARAMETER_TYPES = ();
115  
116 ## Array index for the various information in each parameter specifcation
117 ## referenced by %PARAMETER_LIST
118 my $TYPE=0;
119 my $OPT_ALIAS=1;
120 my $OPT_SPEC=2;
121 my $DEF_VALUE=3;
122 my $DESCRIPTION=4;
123 my $QUESTION=5;
124 my $EXPLANATION=6;
125
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' ]
132    ] );
133                   
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' ]
143    ] );
144
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' ]
149    ] );
150
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
154 # explanation
155 # and all parameter of type action are treated as option parameters
156 # $key, $type, $def_value, $opt_alias, $opt_spec, $description, $question, $explanation
157
158 &add_param('help', 'action', undef, '|h', '',
159    'print a short help text and exit');
160
161 &add_param('version', 'action', undef, '|v', '',
162    'print the version of this script and exit');
163
164 &add_param('print_config', 'action', undef, '|o', '',
165    'print the current configuration and exit');
166
167 &add_param('configure', 'action', undef, '|c', '',
168    'configure all parameters interactivly, store them and exit');
169
170 &add_param('title', 'text', undef, '|t', '=s',
171    'set PDF info title for specified document');
172
173 &add_param('author', 'text', undef, '|a', '=s',
174    'set PDF info author for specified document');
175
176 &add_param('input_path', 'directory', undef, '', '=s',
177    'set path for referenced material in main document');
178
179 ### Full parameters
180 # parameter type action is not allowed
181 # $key, $type, $def_value, $opt_alias, $opt_spec, $description, $question, $explanation
182
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.");
188
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.");
196
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.");
204
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.");
212
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.");
220
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'.");
227
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.");
236
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.");
245
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.");
253
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.");
259
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.");
266
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.");
272
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.");
279
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");
284
285 &add_param('citecolor', 'color', 'blue', '', '=s',
286    'specify color of citations in PDF doc (hyperref)',
287    'What color should be used for citation?', "");
288
289 &add_param('urlcolor', 'color', 'blue', '', '=s',
290    'specify color of URLs in PDF doc (hyperref)',
291    'What color should be used for URLs?', "");
292
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?', "");
296
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?', "");
300
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.");
307
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.");
317
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.");
327
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 "
334    ."generated.");
335
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.");
341
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).");
348
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).");
355
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.");
361
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.");
367
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.");
373
374
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.");
380
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)?', "");
384
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)?', "");
388
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.");
396
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.");
402
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.");
408
409 # the following parameter types should be set now:
410 #  'color'       => \@VALUES,
411 #  'destination' => \@VALUES,
412 #  'paper'       => \@VALUES,
413 #  'action'      => undef,
414 #  'three'       => undef,
415 #  'bool'        => undef,
416 #  'integer'     => undef,
417 #  'text'        => undef,
418 #  'directory'   => undef
419
420 ##### Functions ###########################################
421
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
425 #
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 
430 # 4: warning
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
435 # 9: debug info
436 #
437 # parameter 1: priority level
438 # parameter 2: list of output strings
439 # return value: none
440
441 sub report {
442    my $level;
443    my $verbosity;
444    my $log_verbosity;
445    my @output;
446
447    if (@_ < 2 ) {
448       @output = ( "Oppss! Report function got only 1 argument!" );
449       $level  = 9;
450    } else {
451       ($level, @output) = @_;
452    }
453
454    if($CONFIGURED) {
455       if( &param_value('debug') eq $NO ) {
456          $verbosity = &param_value('verbosity');
457          $log_verbosity = $LOGFILE_VERBOSITY;
458       } else {
459          $verbosity = 9;
460          $log_verbosity = 9;
461       } 
462    } else {
463       $verbosity = $PRE_CONFIG_VERBOSITY;
464       $log_verbosity = $LOGFILE_VERBOSITY;
465    }
466
467    if ( $level <= $log_verbosity ) {
468       open LOGFILE, ">> $MYLOGFILE";
469       print LOGFILE @output,"\n";
470       close LOGFILE;
471    }
472
473    if( $level <= $verbosity ) {
474       print @output,"\n";
475    }
476 }
477
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 
484
485 sub system_command {
486    my $command = $_[0];
487    my $fatal_failure= $_[1];
488    my $output_priority = $_[2];
489    my $fail_message = $_[3];
490    my $system_out;
491
492    $system_out = `$command 2>&1`;
493
494    if ($?) {
495       if ($fatal_failure) {
496          &report(2, $system_out) if ($system_out);
497          &abort($fail_message.": $!");
498       } else {
499          &report($output_priority, $system_out) if ($system_out);
500          &report(3, $fail_message.": $!");
501       }
502       return $FALSE;
503    }
504
505    return $TRUE;
506 }
507
508 ### Index of the first occurence of a string in an array
509 # parameter 1: text
510 # parameter 2: list
511 # return value: index or -1 if not element of the array 
512
513 sub array_index {
514    my ($text, @list) = @_;
515
516    if(!defined($text)) {
517       &report(9, "Oppss! Cannot compare nothing.");
518       return -1;
519    }
520
521    foreach (0..$#list) {
522       if ( $list[$_] eq $text ) { return $_; }
523    }
524    
525    return -1;
526 }
527
528 ### extract the last N lines of a text file
529 # abort on failures
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 
533
534 sub file_tail {
535    my $file_name = $_[0];
536    my $no_of_lines = defined($_[1]) ? $_[1] : 0;
537    my @cache=();
538
539    &check_file($file_name);
540    open(TAIL_SOURCE, "<$file_name")
541       or &abort("Could not read file $file_name: $!");
542
543    if($no_of_lines == 0) {
544       # use entire file
545       while(<TAIL_SOURCE>) {
546          if(!$_) { $_="\n"; }
547          push(@cache, $_);
548       }
549    } else {
550       # only last N lines
551    
552       # fill up cache
553       while(@cache < $no_of_lines and <TAIL_SOURCE>) {
554          if(!$_) { $_="\n"; }
555          push(@cache, $_);
556       }
557    
558       # always cache the last N lines up to the end of the file
559       while(<TAIL_SOURCE>) {
560          if(!$_) { $_="\n"; }
561          shift(@cache);
562          push(@cache, $_);
563       }
564    }
565    
566    close TAIL_SOURCE;
567
568    return @cache;
569 }
570
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
576
577 sub grep_file {
578    my $file_name = $_[0];
579    my $regexp = $_[1];
580    my $first_only = $_[2] ? $TRUE : $FALSE;
581    my @result=();
582
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: $!");
587
588    while(<GREP_SOURCE>) {
589       if(m#$regexp#) {
590          push(@result, $_);
591          if($first_only) { last; }
592       }
593    }
594
595    close GREP_SOURCE;
596    return @result;
597 }
598    
599 ### Removing all temporary files
600
601 sub clean_up {
602    &report(6, "Removing temporary files ...");
603    foreach (@TMPFILES) {
604       unlink($_) if(-f $_); 
605    }
606
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($_.".???"); 
612       } else {
613          &report(3, "Bad file in temp tex files list: $_");
614       }
615    }
616 }
617
618 ### Output of all temp files
619
620 sub print_temp_files {
621    if (scalar @TMPFILES > 0) {
622       print "Stored the following explicit temporary files:\n";
623       foreach (@TMPFILES) {
624          if (-f $_) {
625             print "> ".$_."\n";
626          } else {
627             print "> ".$_." (does not exist)\n";
628          }
629       }
630       print "\n";
631    }
632    
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' ) {
637             print "> ".$_.": "; 
638             foreach my $file (glob($_.".???")) {
639                print basename($file)." ";
640             }
641             print "\n"; 
642          } else {
643             print "> ".$_.": bad file for temp TeX file\n";
644          }
645       }
646       print "\n";
647    }
648 }
649
650 ###  exit with an error message
651
652 sub abort {
653    &report(1, @_);
654    if ( $CONFIGURED and &param_value('clean_on_abort') eq $YES 
655        and &param_value('debug') eq $NO) {
656       &clean_up;
657    } else {
658       &print_temp_files;
659    }
660    &report(2, "Aborting ...");
661    exit 1;
662 }
663
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
667
668 sub checkCommand {
669    my $command = $_[0];
670    my $message = $_[1];
671    my $which_output;
672
673    $which_output = `which $command 2>&1`; 
674    chomp $which_output;
675    $_ = $which_output;
676    s|^(.*/)?([^/]+)$|$2|;
677
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");
683       }
684       &report(2, "Aborting ...");
685       exit 1;
686    }
687 }
688
689 ###################### Generic configuration functions
690
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
697
698 sub question_ynu {
699    my $user_input;
700    my $question = $_[0];
701    my $default = defined($_[1]) ? $_[1] : $NIL;
702    my $undef_allowed = $_[2];
703    my $response = undef;
704
705    if (defined($undef_allowed) and $undef_allowed eq $YES) {
706       $undef_allowed = $TRUE;
707    } else {
708       $undef_allowed = $FALSE;
709    }
710
711    if( $default =~ /^y(es)?/i ) {
712       $question .= ' [y]: ';
713       $default = $YES;
714    } elsif ( $default eq $NIL and $undef_allowed ) {
715       $question .= ' [u]: ';
716       $default = $NIL;
717    } else {
718       $question .= ' [n]: ';
719       $default = $NO;
720    }
721    while (! defined($response)) {
722       print $question;
723       $user_input = <STDIN>;
724       chomp($user_input);
725       
726       if( $user_input =~ /^y(es)?/i ) {
727          $response=$YES;
728       } elsif ( $user_input =~ /^no?/i ) {
729          $response=$NO;
730       } elsif ( $user_input =~ /^u(ndef(ined)?)?/i and $undef_allowed ) {
731          $response=$NIL;
732       } elsif ( $user_input eq "" ) {
733          $response=$default;
734       } else {
735          print "Please respond with y(es)";
736          print ", u(ndefined)" if($undef_allowed);
737          print " or n(o).\n";
738       }
739    }
740    return $response;
741 }
742
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
749
750 sub input_number {
751    my $question = $_[0];
752    my $default = $_[1];
753    my $min_limit = $_[2];
754    my $max_limit = $_[3];
755    my $response= undef;
756
757    while (! defined($response)) {
758       print "$question [$default]: ";
759       my $user_input = <STDIN>;
760       chomp($user_input);
761       
762       if ($user_input eq "") {
763          $response=$default;
764       } else {
765          $_ = $user_input;
766          if (s/^([0-9]+)$/$1/ and $_ >= $min_limit and $_ <= $max_limit ) {
767             $response = $_;
768          } else {
769             print "Invalid input. Please enter a positve integer from $min_limit to $max_limit.\n";
770          }
771       }
772    }
773    return $response;
774 }
775
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
781
782 sub choose_value {
783    my ($question, $default, $enum_array_ref)=@_;
784    my $default_no=1;
785    my $chosen_no;
786    my @possible_values = @$enum_array_ref;
787    my @value_array;
788    my $value_key;
789    my $value_output;
790
791    print "$question\n";
792    foreach (0..$#possible_values) {
793       my $no     = $_ + 1;
794       @value_array  = @{$possible_values[$_]};
795       $value_key    = $value_array[0];
796       $value_output = $value_array[1];
797
798       print "$no) " . $value_output . "\n";
799       if ( $default eq $value_key ) { $default_no=$no; }
800    }
801
802    $chosen_no=&input_number("Please enter the corresponding number", $default_no, 1, $#possible_values);
803
804    @value_array  = @{$possible_values[$chosen_no - 1]};
805    $value_key    = $value_array[0];
806    return $value_key;
807 }
808
809 ### interactively answer a question
810 # parameter 1: question
811 # parameter 2: current value
812 # return value: the new value
813
814 sub input_text {
815    my $question=$_[0];
816    my $default=$_[1];
817    my $response= undef;
818
819    print "Suggested value: $default\n";
820    if ( &question_ynu("Do you want to keep this value?", $YES) eq $YES ) {
821       $response= $default;
822    } else {
823       print "$question ";
824       my $user_input = <STDIN>;
825       chomp($user_input);
826       
827       $response = $user_input;
828    }
829    return $response;
830 }
831
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
835
836 sub check_file {
837    my $file = $_[0];
838    my $message = defined($_[1]) ? $_[1] : "Required file cannot be accessed!";
839
840    if ( ! -f $file ) {
841       &report(2, "\nSorry. I cannot find '$file'.");
842       &abort($message);
843    } elsif ( ! -r $file ) {
844       &report(2, "\nSorry. File '$file' exists, but is not readable.");
845       &abort($message);
846    }
847 }
848
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
854
855 sub check_dir {
856    my $directory = $_[0];
857    my $message = defined($_[1]) ? $_[1] : "Not a valid path!";
858    my $allow_creation = defined($_[2]) ? $_[2] : $NO;
859
860    if ( index($directory, "/") != 0 ) {
861       &report(3, "\nSorry. '$directory' is not an absolute path.");
862       &report(3, $message);
863       return $FALSE;
864    } elsif ( ! -d $directory ) {
865       # dir does not exist
866       if ( $allow_creation eq $YES ) {
867          # creation allowed
868          &report(4, "\nI cannot find '$directory'. Try to create it.");
869          if ( mkdir($directory, 0755) ) {
870             &report(7, "Creation of '$directory' was successful.");
871             return $TRUE;
872          } else {
873             &report(3, "Creation of '$directory' failed.");
874             &report(3, $message);
875             return $FALSE;
876               }
877       } else {
878          # creation not allowed
879          &report(3, "\nSorry. Directory '$directory' does not exist.");
880          &report(3, $message);
881          return $FALSE;
882       }
883    } elsif ( ! -w $directory ) {
884       # dir not writable
885       &report(3, "\nSorry. Directory '$directory' exists, but is not writable.");
886       &report(3, $message);
887       return $FALSE;
888    }
889    return $TRUE;
890 }
891
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
897
898 sub input_dir {
899    my $question = $_[0];
900    my $default_dir = $_[1];
901    my $allow_creation = defined($_[2]) ? $_[2] : $NO;
902    my $user_input;
903    my $response = undef;
904
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]: ";
909    } else {
910       $default_dir = undef;
911       $question .= ": ";
912    }
913
914    while (! defined($response)) {
915       print "$question";
916       $user_input = <STDIN>;
917       chomp($user_input);
918       
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]: ";
925          } else {
926             # valid default dir has already existed or has been created
927             $response = $default_dir;
928          }
929       } else {
930          # user has given a directory
931          if( &check_dir($user_input,"This is not a valid directory!", $allow_creation) ) {
932             $response = $user_input;
933          }
934       }
935    }
936    return $response;
937 }
938
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
944 # return value: none
945
946 sub add_param_type {
947  
948    my ($type, $scalar_argument) = @_;
949  
950    $PARAMETER_TYPES{$type} = $scalar_argument;
951 }
952
953 #### add a new parameter to the adminstrated parameters
954 ####
955 # parameter 1: key
956 # parameter 2: type
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
963 # return value: none
964
965 sub add_param {
966  
967    my ($key, $type, $def_value, $opt_alias, $opt_spec, $description, $question, $explanation) = @_;
968  
969    $CONFIGURATION{$key} = $def_value;
970
971    $PARAMETER_LIST{$key} = [ $type, $opt_alias, $opt_spec, $def_value, $description, $question, $explanation ];
972    
973    push(@PARAMETER_ORDER, $key);
974
975    if (! exists $PARAMETER_TYPES{$type}) {
976       $PARAMETER_TYPES{$type} = undef;
977    }
978 }
979
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)
984
985 sub type_enum_array {
986    my $key = $_[0];
987    my $values_ref;
988
989    if(! exists($PARAMETER_TYPES{$key})) {
990       &abort("unknown type: $key");
991    }
992
993    $values_ref = $PARAMETER_TYPES{$key};
994
995    if(ref $values_ref ne 'ARRAY') {
996       $values_ref = undef;
997    }
998
999    return $values_ref;
1000 }
1001
1002 ### get the value of an existing parameter
1003 # parameter 1: a parameter key
1004 # return value: parameter value
1005
1006 sub param_value {
1007    my $key = $_[0];
1008    my $current_value;
1009
1010    exists($CONFIGURATION{$key})
1011       or &abort("unknown parameter: $key");
1012    $current_value = $CONFIGURATION{$key};
1013
1014    return $current_value;
1015 }
1016
1017 ### get the type of an existing parameter
1018 # parameter 1: a parameter key
1019 # return value: parameter value
1020
1021 sub param_type {
1022    my $key = $_[0];
1023    my $def_ref;
1024    my $type;
1025
1026    exists($PARAMETER_LIST{$key})
1027       or &abort("unknown parameter: $key");
1028    $def_ref = $PARAMETER_LIST{$key};
1029    $type = @{$def_ref}[$TYPE];
1030
1031    exists($PARAMETER_TYPES{$type})
1032       or &abort("parameter has unknown type: $key (type: $type)");
1033
1034    return $type;
1035 }
1036
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
1040
1041 sub full_param {
1042    my $key = $_[0];
1043    my @param_def;
1044
1045    exists($PARAMETER_LIST{$key})
1046       or &abort("unknown parameter: $key");
1047    @param_def = @{$PARAMETER_LIST{$key}};
1048
1049    if ($param_def[$TYPE] ne 'action' and defined ($param_def[$QUESTION])) {
1050       return $TRUE;
1051    } else {
1052       return $FALSE;
1053    }
1054 }
1055
1056 ### get the output needed for configuration of this parameter 
1057 # parameter 1: a parameter key
1058 # return value: array - (description, explanation, question) 
1059
1060 sub param_config_output {
1061    my $key = $_[0];
1062    my @param_def;
1063    my $description; 
1064    my $explanation; 
1065    my $question; 
1066
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];
1073    
1074    return ($description, $explanation, $question);
1075 }
1076
1077 ### set the value of an existing parameter
1078 # parameter 1: a parameter key
1079 # parameter 2: the new value
1080 # return value: none
1081
1082 sub set_param_value {
1083    my $key = $_[0];
1084    my $new_value = $_[1];
1085
1086    exists($CONFIGURATION{$key})
1087       or &abort("unknown parameter: $key");
1088    $CONFIGURATION{$key}=$new_value;
1089 }
1090
1091 ### get option specifier for getopts
1092 # parameter 1: option key
1093 # return value: string - option specifier
1094
1095 sub option_specifier {
1096    my $key = $_[0];
1097    my $spec;
1098    my $def_ref;
1099  
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];
1104  
1105    return $spec;
1106 }
1107
1108 ### handle an option
1109 # parameter 1: a parameter/option key
1110 # parameter 2: the option value
1111 # return value: none
1112
1113 sub handle_option {
1114    my $key = $_[0];
1115    my $value = $_[1];
1116    my $type;
1117    
1118    $type = &param_type($key);
1119
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");
1129       }
1130       &set_param_value($key, $value);
1131    } elsif (defined(&type_enum_array($type))){
1132       &set_enum_param($key, $value);
1133    } else {
1134       &set_param_value($key, $value);
1135    }
1136 }
1137
1138 ### handle all action options 
1139 # parameter 1: a option key
1140 # parameter 2: the option value
1141 # return value: none
1142
1143 sub handle_action_opt {
1144    my $key = $_[0];
1145    my $value = $_[1];
1146
1147    if ($key eq 'help') {
1148       &print_help;
1149       
1150    } elsif ($key eq 'version') {
1151       &print_version;
1152       
1153    } elsif ($key eq 'configure') {
1154       if ( -f $RC_FILENAME ) {
1155          &read_configuration($RC_FILENAME);
1156       }
1157       &configure;
1158       &write_configuration($RC_FILENAME);
1159       &print_configuration;
1160       
1161    } elsif ($key eq 'print_config') {
1162       if ( -f $RC_FILENAME ) {
1163          &read_configuration($RC_FILENAME);
1164       }
1165       &print_configuration;
1166
1167    } else {
1168       &print_usage; 
1169       exit 1;
1170    }
1171    exit 0;
1172 }
1173
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
1177
1178 sub set_enum_value {
1179    my ($key, $value) = @_;
1180    my $type;
1181    my $enum_array_ref;
1182    my @allowed_values=();
1183
1184    $type = &param_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));
1188
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);
1194          return;
1195       }
1196    }
1197
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]);
1202    }
1203
1204    &report(2, "\n$key allows: " . @allowed_values . ".\n");
1205    &abort("Illegal value: $value");
1206 }
1207
1208 ### configure an existing parameter interactively
1209 # parameter 1: a parameter key
1210 # return value: none
1211
1212 sub config_param {
1213    my $key = $_[0];
1214    my $type; 
1215    my $new_value;
1216    my $current_value;
1217    my $description;
1218    my $explanation;
1219    my $question;
1220
1221    ### get required information about this parameter
1222    $type = &param_type($key); 
1223    $current_value = &param_value($key);
1224    ($description, $explanation, $question) = &param_config_output($key);
1225
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 "");
1231    
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);  
1244    } else {
1245       my $enum_array_ref; 
1246
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)");
1250       }
1251
1252       $new_value=&choose_value($question,$current_value,$enum_array_ref);
1253    } 
1254
1255    ### store his choice
1256    &set_param_value($key, $new_value);
1257 }
1258
1259 ### save configuration in rc file
1260 # parameter 1: file name
1261 # return value: none
1262
1263 sub write_configuration {
1264    my $file_name = $_[0];
1265    my $date;
1266
1267    open(RCFILE, ">$file_name") or
1268       &abort("Could not open configuration file for writing ($file_name)");
1269    select RCFILE;
1270
1271    $date = `date`;
1272    chomp($date);
1273    
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";
1277    
1278    foreach my $key (@PARAMETER_ORDER) {
1279       my $value = $CONFIGURATION{$key};
1280       if(&full_param($key)) {
1281          print $key.'='.$value."\n";
1282       }
1283    }
1284    
1285    print "# EOF\n";
1286    select STDOUT;
1287    close RCFILE;
1288 }
1289
1290 ### print the configuration parameters
1291
1292 sub print_configuration {
1293    print "\nConfiguration for $MYNAME V$MYRELEASE\n";
1294    
1295    foreach my $key (@PARAMETER_ORDER) {
1296       my $value = $CONFIGURATION{$key};
1297       if(&full_param($key)) {
1298          print $key.'='.$value."\n";
1299       }
1300    }
1301    
1302    print "\n";
1303 }
1304
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
1308
1309 sub read_configuration {
1310    my $file_name = $_[0];
1311    my $file_version= 0;
1312
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)");
1316
1317    while (<RCFILE>) {
1318       chomp;
1319       if( /^([^#=]+)=(.*)$/ ) {
1320          if( exists $CONFIGURATION{$1} ) {
1321             $CONFIGURATION{$1} = $2;
1322          } elsif ( $1 eq $RCVERSION_STRING ) {
1323             $file_version = $2; 
1324          } else {
1325             print "Ignoring unknown parameter in RC file: $1=$2\n";
1326          }
1327       }
1328    }
1329    close RCFILE;
1330
1331    return $file_version;
1332 }
1333
1334 ### print script version
1335
1336 sub print_version {
1337    print "\n$MYNAME Version $MYRELEASE\n";
1338 }
1339
1340 ###################### Specific functions (for use with this script only)
1341
1342 ### print usage of command
1343
1344 sub print_usage {
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";
1351 }
1352
1353 ### print command help
1354
1355 sub print_help {
1356    &print_version;
1357    &print_usage;
1358
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];
1365       
1366       $alias =~ s/\|(([a-zA-Z])(\||$))/ | -$1/g;
1367       $alias =~ s/\|(([a-zA-Z][a-zA-Z0-9_]+)(\||$))/ | --$1/g;
1368
1369       print "--";
1370       print "[no]" if($negation);
1371       print $key.$alias;
1372       print " VALUE" if ($takes_value);
1373       print ":\n   ".$description."\n\n";
1374    }
1375    print "\n";
1376 }
1377
1378 ### configure all tex2pdf parameters interactively
1379 # parameters: none
1380 # return value: none
1381
1382 sub configure {
1383
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";
1394
1395    $NUM_PARAM_MIN=1;
1396    $NUM_PARAM_MAX=9;  
1397
1398    foreach my $key (@PARAMETER_ORDER) {
1399       if(&full_param($key)) {
1400          &config_param($key);
1401       }
1402    }
1403
1404    print "\nConfiguration for $MYNAME finished.\n\n";
1405 }
1406
1407 ### check if the most important executables are installed on the system
1408 # parameters: none
1409
1410 sub check_commands {
1411    my $exec_epstopdf;
1412    ### check for which command
1413    &checkCommand("which","You can switch off all command checks to fix this.");
1414
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    if (&grep_file($exec_epstopdf, "-dCompatibilityLevel=1\\.1", $TRUE) > 0) {
1422       &report(9, "Good: ghostscript option '-dCompatibilityLevel=1.1' detected "
1423          ."in\n'$exec_epstopdf'.");
1424    } else {
1425       &report(4, "\nWARNING: no ghostscript option '-dCompatibilityLevel=1.1' "
1426          ."in\n'$exec_epstopdf'.\n"
1427          ."You might run into trouble with the conversions of bitmaps.\n"
1428          ."Adjusting epstopdf or setting the environment variable GS_OPTIONS "
1429          ."to \n".'"$GS_OPTIONS -dCompatibilityLevel=1.1" before calling this '
1430          ."script\nmight help in this case.\n");
1431    }
1432
1433    if ( &param_value('thumbpdf') eq $YES ) {
1434       &checkCommand("thumbpdf","You can switch off thumbpdf support to fix this.");
1435    }
1436
1437    if ( &param_value('ppower') eq $YES ) {
1438       &checkCommand("ppower","You can switch off ppower support to fix this.");
1439    }
1440
1441    ### authorindex perl script
1442    if ( &param_value('authorindex') eq $YES ) {
1443       &checkCommand("authorindex","You can switch off authorindex support to fix this.");
1444    }
1445
1446    ### bibtex executable
1447    if ( &param_value('bibtex') ne $NO or &param_value('gloss') ne $NO) {
1448    &checkCommand("bibtex","You can switch off BibTeX support to fix this.");
1449    }
1450 }
1451
1452 #### generate the tmp file name from the original tex filename
1453 #### and make sure that they are not the same
1454 # parameter 1: orignal filename (with or without a path or .tex)
1455 # parameter 2: path for the tmp file (default: doc path)
1456 # return value: tmp name
1457
1458 sub reserve_tmp_texname {
1459    my $original_name = $_[0];
1460    my $tmp_path = $_[1];
1461    my $tmp_base_suffix = &param_value('tmp_base_suffix');
1462    my $overwrite = &param_value('overwrite');
1463    my $original_path;
1464    my $original_base;
1465    my $suffix;
1466    my $pathed_tmp_base;
1467    my @existing_files;
1468
1469    # separate path, base and suffix
1470    ($original_base,$original_path,$suffix) = fileparse($original_name, '\.tex');
1471    
1472    # set the path of the tmp file
1473    if(!$tmp_path) {
1474       $tmp_path=$original_path;
1475    } else {
1476       $tmp_path .= '/' if( $tmp_path ne "" and ! ($tmp_path =~ m#/$#) );
1477    }
1478    
1479    # abort if no absolute path is given 
1480    if( index($tmp_path, "/") != 0 ) {
1481       &abort("Internal error: Illegal argument for reserve_tmp_texname:".
1482          "Given file has no absolute path: $original_name");
1483    } 
1484
1485    # make sure that tmp_base_suffix is set correctly
1486    if($tmp_base_suffix eq "") {
1487       &abort("Temporary filename base suffix is empty.");
1488    }
1489
1490    $pathed_tmp_base = $tmp_path.$original_base.$tmp_base_suffix;
1491
1492    # make sure no file with this base exists in this directory
1493    @existing_files = glob "$pathed_tmp_base.*";
1494    if (@existing_files != 0) {
1495       &report(3, "Problems detected while reserving temporay file name!\n",
1496          "In this directory are already files with this basename.\n",
1497          "A list of the conflicting, existing files:\n",
1498          join("\n", @existing_files), "\n");
1499       if ($overwrite eq $YES) {
1500          &report(4, "As you have activated the parameter 'overwrite' I will "
1501                  ."continue.\n",
1502                  "However, in order to protect the existing files I will not\n",
1503                  "delete any files with this basename at the final clean-up.");
1504       } else {
1505          &report(2, "You could activate the parameter 'overwrite' or remove ",
1506          "the\n corresponding files in order to avoid these problems."); 
1507          &abort("No temporary name found for $original_name.");
1508       }
1509    } else {
1510       push(@TMP_TEX_FILES, $pathed_tmp_base); 
1511    }
1512
1513    return $pathed_tmp_base.$suffix;
1514 }
1515
1516 ### generate LaTeX file from LyX document with LyX itself
1517 # parameter ($1): Lyx document
1518 # parameter ($2): Latex document
1519
1520 sub generate_tex_file {
1521    my $lyx_doc = $_[0];
1522    my $tex_doc = $_[1];
1523    my $lyx_dir;
1524    my $lyx_output;
1525    my $lyx_exec=&param_value('lyx_exec');
1526    
1527    $lyx_dir = &param_value('lyxrc_path');
1528    $lyx_dir .= '/' if( ! ($lyx_dir =~ m#/$#) );
1529    $lyx_dir .= '/' if( ! ($lyx_dir =~ m#/$#) );
1530
1531    ### Check if LyX file can be accessed
1532    &check_file($lyx_doc,"Cannot read the specified LyX document!");
1533
1534    ### Check if LaTeX file exists and is newer than the LyX file
1535    if ( -f $tex_doc and -M $tex_doc < -M $lyx_doc ) {
1536       &report(4, "\nLaTeX file is newer than LyX document ($lyx_doc).\n",
1537       "Using existing TeX file: $tex_doc\n",
1538       "Remove it to force its new generation.");
1539    } else {
1540       ### export LaTeX file with LyX (needs a display!)
1541       &checkCommand($lyx_exec, "Cannot generate LaTeX document without LyX!");
1542       &report(6, "\nExporting LaTeX file");
1543       
1544       ### move some files out of the way that stop LyX from exporting
1545       foreach my $file ($lyx_dir."lyxpipe.out",$lyx_dir."lyxpipe.in",$tex_doc) {
1546          if ( -f $file ) { rename($file, $file.'~'); }
1547       }
1548
1549       $lyx_output = `$lyx_exec --export latex $lyx_doc 2>&1`;
1550
1551       ### check if LaTeX file now really exists
1552       if ( ! -f $tex_doc ) {
1553          &report(2, "Lyx Output:\n$lyx_output");
1554          &report(2, "\nSorry. I cannot find '$tex_doc'.");
1555          &abort("The LaTeX document was not generated by LyX!");
1556       } else {
1557          &report(8, "Lyx Output:\n$lyx_output");
1558       }
1559    }
1560 }
1561
1562 #### search TeX document for a certain text tag (e.g. author, title)
1563 # parameter 1: file to parse
1564 # parameter 2: full TeX tag name
1565 # return value: list of the contents strings of all matching tags
1566
1567 sub extract_tag_contents {
1568    my $source=$_[0];
1569    my $tag_name=$_[1];
1570    my $contents;
1571    my @results=();
1572    my $error_message="Could not read TeX document to extract $tag_name";
1573
1574    &check_file($source, $error_message.'.');
1575    open(EXTRACT_SOURCE, "<$source") or
1576       &abort($error_message." ($source).");
1577
1578
1579    while(<EXTRACT_SOURCE>) {
1580       ### ignore comments
1581       s/(^|[^\\])%.*/$1/;
1582       # ignore \thanks{}
1583       s/\\thanks\{.*?\}//g;
1584       # change \and to and
1585       s/\\and/ and/g;
1586
1587       $contents .= $_;
1588    }
1589
1590    close EXTRACT_SOURCE;
1591
1592    $_ = $contents;
1593
1594    # add contents of all occurences of this tag in a line to result list
1595    while ( /\\($tag_name)(\[[^]]*?\])*?{+([^{}]*?)}/s ) {
1596       my $text = $3;
1597       $_ = $';
1598       # remove newlines
1599       $text =~ s/\n//g;
1600       $text="" if (!defined($text));
1601       push(@results, $text);
1602    }
1603
1604    return @results;
1605 }
1606
1607 #### search for filenames in given TeX Tag in entire document
1608 ### skip all comments and duplicates while parsing
1609 # parameter 1: file to parse
1610 # parameter 2: full TeX tag name
1611 # parameter 3: reference to a list of possible filename suffixes (without '.')
1612 # parameter 4: regexp for suffix to ignore when specified in TeX file
1613 #              (undef if not used)
1614 # return value: list of identified files
1615
1616 sub identify_files {
1617    my $source=$_[0];
1618    my $tag_name=$_[1];
1619    my @suffixes=@{$_[2]};
1620    my $ignore_suffix=$_[3];
1621    my @matched_tags;
1622    my @found_files=();
1623    my $regexp_suffixes;
1624
1625    # create one large regexp from given suffixes and escape dots in them
1626    $regexp_suffixes= '.('.join('|', @suffixes).')';
1627    $regexp_suffixes =~ s/\./\\./g;
1628
1629    @matched_tags = &extract_tag_contents($source, $tag_name);
1630
1631    foreach my $tag_contents (@matched_tags) {
1632       my $path;
1633       my $base;
1634       my $suffix;
1635       my $kpse_result;
1636       my $working_dir = cwd."/";
1637
1638       ($base,$path,$suffix) = fileparse($tag_contents, $regexp_suffixes);
1639
1640       # if a suffix is specified in the tag_contents handle it as requested
1641       # 
1642       # 1. $suffix: TRUE if $suffix is defined and not of zero length
1643       #    means: a valid suffix has been found in the filename
1644       # 2. defined($ignore_suffix): TRUE if $ignore_suffix is defined
1645       #    means: a regexp for suffixes to be ignored has been specified as
1646       #          parameter4
1647       # 3. $suffix =~ /$ignore_suffix/: TRUE if $suffix matches the regexp
1648       #    means: the suffix in the filename is wanted to be ignored
1649       #
1650       # The IF statement will be executed when:
1651       #   a valid suffix has been found in the filename (1)
1652       #   AND regexp for suffixes to be ignored has NOT been specified (not 2)
1653       # OR
1654       #   a valid suffix has been found in the filename (1)
1655       #   AND regexp for suffixes to be ignored has been specified (2)
1656       #   AND the suffix in the filename is NOT wanted to be ignored (not 3)
1657       #
1658       # The stuff that is executed if the entire IF statement is TRUE does the
1659       # following: accept the found suffix and consider it as the only possible
1660       # file name.
1661       if($suffix and not (defined($ignore_suffix) and $suffix =~ /$ignore_suffix/)){
1662          $kpse_result=`kpsewhich $tag_contents`;
1663          # print warning and skip this tag if kpsewhich could not find it  
1664          if (!$kpse_result) {
1665             &report(4, "WARNING - Could not identify referenced file:\n",
1666             " Ignoring '$tag_contents'.");
1667             next;
1668          }
1669       } else {
1670          # if there is a '.' in the basename assume that this is a reference
1671          # to a file of another type and skip it
1672          if( $base =~ /\./ ) {
1673             &report(9, "Found an unknown extension. Ignoring '$tag_contents'.");
1674             next;
1675          }
1676
1677          # search for all possible files with allowed suffixes
1678          foreach my $allowed_suffix (@suffixes) {
1679             if (not $allowed_suffix =~ /[\]\)\(\|\[\\]/ ) {
1680                # suffix is not a regexp, but a real extension
1681                my $possible_file= $path.$base.'.'.$allowed_suffix;
1682                $kpse_result=`kpsewhich $possible_file`;
1683                if ($kpse_result) {
1684                   last;
1685                }
1686             }
1687          }
1688       } 
1689       
1690       # if kpsewhich could not find any file with an allowed suffix
1691       # assume that this reference is of a different type and skip it
1692       # quietly   
1693       if (!$kpse_result) {
1694          &report(9, "No suitable file found. Ignoring '$tag_contents'.");
1695          next;
1696       }
1697
1698       # expand '.' in kpsewhich output to the current path
1699       $kpse_result =~ s#^\./#$working_dir#;
1700       
1701       # remove trailing newline
1702       chomp($kpse_result);
1703
1704       # add file to the found file list if it is not already on it
1705       if( &array_index($kpse_result, @found_files) < 0 ) {
1706          push(@found_files, $kpse_result);
1707       }
1708    }
1709
1710    return @found_files;
1711 }
1712
1713 ### Build a list of all files which are included from the root file.
1714 # This function recurses, and is maybe smart enough to detect cycles.
1715 # Be sure to set REF_DOCS to the empty string prior to calling this.
1716 # parameter 1: tex file to start with
1717 # no return value
1718 # result is appended to global variable @REF_DOCS
1719
1720 sub get_file_list {
1721    my $source = $_[0];
1722    my @imports = ();
1723
1724    # This is the cycle avoidance logic.
1725    if ( &array_index($source, @REF_DOCS) < 0 ) {
1726       # Make sure the file can be accessed
1727       &check_file($source, "Included TeX file seems not to be available. Path problem?");
1728
1729       # Save the argument in the list of files.
1730       push(@REF_DOCS, $source);
1731
1732       # Get the list of files included by the argument.
1733       @imports=&identify_files($source, 'include|input', ['tex']);
1734
1735       # Recurse.
1736       foreach my $file (@imports) {
1737          if( ! ($file =~ /\.tex$/) ) { $file .= '.tex'; }
1738          &get_file_list($file);
1739       }
1740    }
1741 }
1742
1743 ### do the required modifications in the LaTeX preamble 
1744 # parameter 1: original preamble from the source file
1745 #              lines before \begin{document} tag (without this tag)
1746 # parameter 2: reference to hyperref parameter list
1747 # return value: adjusted preamble
1748
1749 sub adjust_preamble {
1750    my $preamble = $_[0];
1751    my $hyperref_params_ref = $_[1];
1752    my $extra_code;
1753    my $result;
1754    
1755    $_ = $preamble;
1756
1757    # protect pdflatex execution mode
1758    s/^(\\batchmode)$/% $1/m;
1759
1760    # insert a4paper in the documentclass when a4wide is used 
1761    # fixes problem that hyperref defaults to letter otherwise
1762    if ( /^[^%]*\\usepackage(\[widemargins\])?\{(a4|a4wide)\}/m ) {
1763       # check if package parameters with [] brackets are present
1764       if ( not s/^(\\documentclass\[.*?)\]/$1,a4paper]/m ) {
1765          s/^\\documentclass/$&\[a4paper\]/m;
1766       }
1767    }
1768
1769    ### collect additional LaTeX code
1770    
1771    $extra_code = "\n" . '\usepackage{pslatex}' . "\n";
1772
1773    if ( &param_value('thumbpdf') eq $YES ) {
1774       $extra_code .= '\usepackage{thumbpdf}' . "\n";
1775    } else {
1776       $extra_code .= "% no thumbpdf support\n";
1777    }
1778  
1779 #   if ( &param_value('ppower') eq $YES ) {
1780 #      $extra_code .= '\usepackage{mpmulti}' . "\n";
1781 #   } else {
1782 #      $extra_code .= "% no ppower support\n";
1783 #   }
1784
1785    if ( &param_value('authorindex') eq $YES ) {
1786       $extra_code .= '\usepackage[pages]{authorindex}' . "\n";
1787       $extra_code .= '\let\cite=\aicite' . "\n";
1788    } else {
1789       $extra_code .= "% no authorindex support\n";
1790    }
1791
1792    $extra_code .= '\makeatletter' . "\n";
1793    $extra_code .= '\usepackage[' . join(',', @$hyperref_params_ref)
1794                   . ']{hyperref}' . "\n";
1795    $extra_code .= '\makeatother' . "\n";
1796    
1797    ### insert the extra LaTeX code directly after documentclass
1798    m/^(\\documentclass)(\[[^]]*\])?(\{.*\})/m;
1799    return $` . $& . $extra_code . $';
1800 }
1801
1802 ### adjust all filenames in the LaTeX code to the tmp files
1803 # parameter 1: original LaTeX code from the source file
1804 # return value: adjusted code
1805
1806 sub adjust_filenames {
1807    my $code = $_[0];
1808    my $tmp_suffix = &param_value('tmp_base_suffix');
1809    my $result;
1810    
1811    $_ = $code;
1812
1813    # cut off the suffix of eps, ps, *.gz and pstex graphics
1814    s/((\\includegraphics)(\[[^]]*?\])?(\{[^}]+?))\.(e?ps|pstex|e?ps\.gz)\n?\}/$1}/sg;
1815
1816    # replace the suffix 'pstex_t' with 'pdf_t'
1817    s/(\\input\{[^}]+?\.)pstex_t\n?\}/$1pdf_t}/sg;
1818
1819    if ( &param_value('mtp_preamble') eq $NO ) {
1820       # cut off the suffix of mmp graphics
1821       s/(\\multiinclude(\[[^]]*?\])?\{[^}]+?)\.mmp\n?\}/$1}/sg;
1822    } else {
1823       # replace the suffix '.#' with '-mp.#'
1824       s/(\\includegraphics(\[[^]]*?\])?\{[^}]+?)\.(\d+?)\n?\}/$1$MTP_TMP_BASESUFFIX\.$3}/sg;
1825
1826       # replace the suffix '.#' with '-mp.#'
1827       s/(\\convertMPtoPDF(\[[^]]*?\])?\{[^}]+?)\.(\d+?)\n?\}/$1$MTP_TMP_BASESUFFIX\.$3}/sg;
1828
1829       # cut off optional suffix '.mmp' and append '-mp' in any case
1830       s/(\\multiinclude(\[[^]]*?\])?\{[^}]+?)(\.mmp)?\n?\}/$1$MTP_TMP_BASESUFFIX}/sg;
1831    }
1832
1833    # insert the tmp_suffix in tex filenames
1834    # I assume that files with no extension are TeX files as well; correct?
1835    s#(\\(input|include)\{([^}]*?/)?[^}/.]+?)((\.tex)?\n?\})#$1$tmp_suffix$4#sg;
1836
1837    return $_;
1838 }
1839
1840 ### Convert given tex file to the temp tex file we need for pdftex
1841 ### major task is to change the reference in the tex files to the
1842 ### corresponding tmp files
1843 # parameter 1: tex source file
1844 # parameter 2: tex tmp file
1845 # parameter 3: reference to hyperref parameter list or
1846 #              'undef' if preamble should not be changed
1847
1848 sub convert_tex2tmp {
1849    my $source = $_[0];
1850    my $target = $_[1];
1851    my $hyperref_params_ref = $_[2];
1852    my $contents;
1853    my $preamble;
1854    my $body;
1855    my $adjust_preamble = defined($hyperref_params_ref) ? $YES : $NO;
1856    my $read_err_msg = "Could not read original TeX document to generate temporary document";
1857    
1858    ### open source and target file
1859    &check_file($source, $read_err_msg . '.');
1860    open(SOURCE_FILE, "<$source") or
1861       &abort($read_err_msg . " ($source).");
1862
1863    ### read in the LaTeX source file
1864    $contents = "";
1865    while(<SOURCE_FILE>) {
1866       $contents .= $_;
1867    }
1868
1869    close SOURCE_FILE;
1870
1871    ### prepare the LaTeX code for PDF generation 
1872    if ( $adjust_preamble eq $YES ) {
1873       $contents =~ m/^ *\\begin\{document\} *$/m;
1874       $preamble = $`;
1875       $body = $&.$';
1876       $preamble = &adjust_preamble($preamble, $hyperref_params_ref);
1877       $preamble = &adjust_filenames($preamble);
1878    } else {
1879       $preamble = "";
1880       $body = $contents;
1881    }
1882    
1883    $body = &adjust_filenames($body);
1884       
1885    ### write the new LaTeX target file
1886    open(TARGET_FILE, ">$target") or
1887       &abort("Could not open file to write temporary TeX document ($target).");
1888
1889    print TARGET_FILE $preamble.$body;
1890    
1891    close TARGET_FILE;
1892 }
1893
1894 ### Convert the given EPS image to PDF
1895 # parameters $1: EPS image filename with absolute path
1896 # return value: none
1897
1898 sub convert_eps2pdf {
1899    my $image = $_[0];
1900    my $image_path;
1901    my $image_base;
1902    my $image_name;
1903    my $suffix;
1904    my $image_target;
1905    my $zipped = 0;
1906    my $dummy;
1907
1908    ($image_base,$image_path,$suffix) = fileparse($image, '\.eps', '\.ps', '\.pstex', '\.gz');
1909    if ($suffix eq "\.gz") {
1910         $zipped = 1;
1911         ($image_base,$dummy,$suffix) = fileparse($image_base, '\.eps', '\.ps', '\.pstex');
1912    }
1913    $image_name = $image_base . $suffix;
1914    $image_target = $image_path . $image_base . '.pdf';
1915    
1916    #### check if image file really exists
1917    #&check_file($image, "Could not convert referenced image.");
1918
1919    ### return if image directory is not writeable
1920    if (! -w $image_path) {
1921       &report(4, "WARNING - Image directory not writable: $image_path\n",
1922       " Skipping '$image_name', assume you have converted it manually.");
1923       return;
1924    }
1925
1926    if ( ! -f $image_target or -M $image_target > -M $image ) {
1927       &report(7, "Converting image $image_name to $image_target ...\n");
1928       if ($zipped > 0) {
1929          &system_command("gunzip -c $image | epstopdf -f -outfile=$image_target",
1930          $TRUE, 8, "epstopdf failed on $image_name");
1931       } else {
1932          &system_command("epstopdf -outfile=$image_target $image",
1933          $TRUE, 8, "epstopdf failed on $image_name");
1934       }
1935       if (&param_value('delete_pdf_images') eq $YES) {
1936          push(@TMPFILES, $image_target);
1937       }
1938    } else {
1939       &report(7, "$image_base.pdf newer than $image_name, conversion skipped...");
1940    }
1941 }
1942
1943 ### Convert the given PSTEX_T file to PDF_T
1944 # parameters 1: PSTEX_T filename with absolute path
1945 # return value: none
1946
1947 sub convert_pstex2pdf {
1948    my $pstex_file = $_[0];
1949    my $pstex_path;
1950    my $pstex_base;
1951    my $pstex_name;
1952    my $suffix;
1953    my $pstex_target;
1954    my @eps_images;
1955
1956    ($pstex_base,$pstex_path,$suffix) = fileparse($pstex_file, ('\.pstex_t'));
1957    $pstex_name = $pstex_base . $suffix;
1958    $pstex_target = $pstex_path . $pstex_base . '.pdf_t';
1959    
1960    #### check if image file really exists
1961    #&check_file($pstex_file, "Could not convert referenced file.");
1962
1963    ### return if directory is not writeable
1964    if (! -w $pstex_path) {
1965       &report(4, "WARNING - Directory not writable: $pstex_path\n",
1966       " Skipping '$pstex_name', assume you have converted it manually.");
1967       return;
1968    }
1969
1970    # descend into file
1971    &report(7, "Converting file $pstex_name ...\n");
1972
1973    # find included EPS image(s)
1974    @eps_images=&identify_files($pstex_file, 'includegraphics',
1975       ['pstex', 'pstex\.gz']);
1976
1977    # create .pdf_t file
1978    &convert_tex2tmp($pstex_file, $pstex_target, undef); 
1979
1980    # put tmp file in the tmp file list
1981    push(@TMPFILES, $pstex_target);
1982
1983    # convert image(s) to pdf
1984    foreach my $image (@eps_images) {
1985       &convert_eps2pdf($image);
1986    }
1987 }
1988
1989 ### Convert the given MP image to PDF
1990 # parameters $1: MP image filename with absolute path
1991 # return value: none
1992
1993 sub convert_mp2pdf {
1994    my $image = $_[0];
1995    my $image_path;
1996    my $image_base;
1997    my $image_name;
1998    my $suffix;
1999    my $image_target;
2000    my $image_src;
2001    my @mps_fig=();
2002    my $mp_fig;
2003
2004    ($image_base,$image_path,$suffix) = fileparse($image, '\.mp|\.mmp');
2005    $image_name = $image_base . $suffix;
2006    $image_src=$image_path . $image_base . $suffix;
2007
2008    @mps_fig= &grep_file($image_path.$image_name,'beginfig',$TRUE);
2009    $_=$mps_fig[0];
2010    /(\d)/;
2011    $mp_fig=$1;
2012    if (&param_value('mtp_preamble') eq $YES) {
2013      $image_target = $image_path . $image_base . $MTP_TMP_BASESUFFIX . '.' . $mp_fig;
2014      $image_name=$image_base.$MTP_TMP_BASESUFFIX.$suffix;
2015    } else {
2016      $image_target = $image_path . $image_base . '.' . $mp_fig;
2017    }
2018
2019    #### check if image file really exists
2020    #&check_file($image, "Could not convert referenced image.");
2021
2022    ### return if image directory is not writeable
2023    if (! -w $image_path) {
2024       &report(4, "$MYNAME: WARNING - Image directory not writable: $image_path\n",
2025          " Skipping '$image_name', assume you have converted it manually.");
2026       return;
2027    }
2028
2029    if ( ! -f $image_target 
2030       or  (-M $image_target > -M $image_src)
2031       or  ( ( &param_value('mtp_preamble') eq $YES)
2032       and (-M $image_target > -M $image_path.$MTP_PREAMBLE_FILENAME) ) ) {
2033       &report(7, "Converting image $image_name ...\n");
2034       my $working_dir = cwd."/";
2035       chdir("$image_path") or &abort("cannot cd to $image_path($!)");
2036       if ( &param_value('mtp_preamble') eq $YES ) {
2037          &modify_mp_file($image_base,$suffix);
2038       }
2039       &system_command("mpost $image_name",
2040          $TRUE, 8, "mpost failed on $image_name");
2041       chdir("$working_dir") or &abort("cannot cd to $working_dir($!)");
2042       if (&param_value('delete_pdf_images') eq $YES) {
2043          push(@TMPFILES, $image_target);
2044       }
2045    } else {
2046       if ( &param_value('mtp_preamble') eq $YES ) {
2047         &report(7, "$image_base$MTP_TMP_BASESUFFIX.$mp_fig newer than $image_base$suffix, conversion skipped...");
2048       } else {
2049         &report(7, "$image_base.$mp_fig newer than $image_base$suffix, conversion skipped...");
2050       }
2051    }
2052 }
2053
2054 ### Convert the given MP image to PDF
2055 # parameters $1: MP image filename with absolute path
2056 # return value: none
2057
2058 sub modify_mp_file {
2059    my $base=$_[0];
2060    my $suffix=$_[1];
2061    my $preamble_file=$MTP_PREAMBLE_FILENAME;
2062
2063    my $mp_source=$base.$suffix;
2064    my $mp_target=$base.$MTP_TMP_BASESUFFIX.$suffix;
2065
2066    ### open source and target file
2067    open(SOURCE_FILE, "<$mp_source") or
2068       &abort("Could not open $mp_source to add $preamble_file ($mp_source).");
2069
2070    open(TARGET_FILE, ">$mp_target") or
2071       &abort("Could not open $mp_target to add $preamble_file ($mp_source).");
2072
2073    open(PREAMBLE_FILE, "<$preamble_file") or
2074       &abort("Could not open $preamble_file to be added to metapost files ($mp_source).");
2075
2076    ### set target file as stdout
2077    select TARGET_FILE;
2078    print  'verbatimtex' . "\n";
2079    print  '%&latex' . "\n"; # This forces metapost to use latex in the compilation
2080    print  '\documentclass[english]{article}' . "\n"; # we have to decide if this sentence goes in preamble.cfg or here
2081                                                      # english must be added
2082                                                      # to preamble in order to
2083                                                      # make work mpost, why ???
2084    while(<PREAMBLE_FILE>) {
2085       print $_
2086    }
2087    print  '\begin{document}' . "\n"; # we have to decide if this sentence goes in preamble.cfg or here
2088    print  'etex' . "\n";
2089    while(<SOURCE_FILE>) {
2090       print $_
2091    }
2092    print  'verbatimtex' . "\n";
2093    print  '\end{document}' . "\n";
2094    print  'etex' . "\n";
2095
2096    ### set STDOUT as stdout again
2097    select STDOUT;
2098
2099    ### close files
2100    close SOURCE_FILE;
2101    close TARGET_FILE;
2102    close PREAMBLE_FILE;
2103
2104 }
2105
2106
2107 ### Convert included images to pdf
2108 # parameter 1: tex source file
2109 # no return value
2110
2111 sub convert_images {
2112    my $tex_source=$_[0];
2113    my @pstex_file_list;
2114    my @image_list;
2115    my @mp_image_list;
2116    my @mmp_image_list;
2117    my @major_suffixes;
2118    my $ignore_regexp;
2119
2120    &report(6, "\nConverting images referenced in $tex_source.");
2121
2122    ##### Get images of major type from the source file
2123    @major_suffixes = (@BITMAP_SUFFIXES, $PDF_ORIG_SUFFIX, @EPS_SUFFIXES);
2124    $ignore_regexp = '.('.join('|',@EPS_SUFFIXES).')';
2125    $ignore_regexp =~ s/\./\\./g;
2126
2127    &report(6, "\nScanning for major image types (".join(', ',@major_suffixes)."):");
2128    @image_list = &identify_files($tex_source,'includegraphics',
2129       \@major_suffixes, $ignore_regexp );
2130
2131    if ( @image_list > 0 ) {
2132       &report(7, join("\n", @image_list));
2133    } else {
2134       &report(7, "None.");
2135    }
2136
2137    ##### Get PSTEX_T files from the source file
2138    &report(6, "\nScanning for PSTEX_T files (.pstex_t):");
2139    @pstex_file_list=&identify_files($tex_source, 'input', ['pstex_t']);
2140    if ( @pstex_file_list > 0 ) {
2141       &report(7, join("\n", @pstex_file_list));
2142    } else {
2143       &report(7, "None.");
2144    }
2145
2146    ##### Get MP images from the source file
2147    &report(6, "\nScanning for MP images (.mp):");
2148    @mp_image_list=&identify_files($tex_source,
2149       'convertMPtoPDF|includegraphics',['mp','(\d+)'],'\.(\d+)');
2150    # FIXME
2151    # fixed for now by ignoring strange extension in identify_files
2152    #
2153    # the above could cause problems as identify_files is expecting a list of
2154    # real extensions and not of regexps
2155    # maybe the only way to fix this is to adjust identify_files to ignore
2156    # invalid extension when testing them with kpsewhich
2157    # ALTERNATIVE: design identify_files to use preffered_suffixes instead
2158    # of ignore_suffixes
2159  
2160    if ( @mp_image_list > 0 ) {
2161       &report(7, join("\n", @mp_image_list));
2162    } else {
2163       &report(7, "None.");
2164    }
2165
2166    ##### Get MMP images from the source file
2167    &report(6, "\nScanning for MMP images (.mmp):");
2168    @mmp_image_list=&identify_files($tex_source,'multiinclude',['mmp']);
2169    if ( @mmp_image_list > 0 ) {
2170       &report(7, join("\n", @mmp_image_list));
2171    } else {
2172       &report(7, "None.");
2173    }
2174
2175    ### Convert EPS images to PDF, copy pdf.orig image files to pdf,
2176    ### and simply ignore all other
2177    if ( @image_list > 0) {
2178       my $handled_suffixes;
2179
2180       &report(6, "\nProcessing images of major types:");
2181    
2182       # create one large regexp from suffixes and escape dots in them
2183       $handled_suffixes = '.('.join('|',(@EPS_SUFFIXES, $PDF_ORIG_SUFFIX)).')';
2184       $handled_suffixes =~ s/\./\\./g;
2185
2186       foreach my $image (@image_list) {
2187          my $path;
2188          my $base;
2189          my $suffix;
2190          ($base,$path,$suffix) = fileparse($image, $handled_suffixes);
2191          if (not $suffix) {
2192             &report(7, "No special handling required for image: $base$suffix");
2193          } elsif ($suffix eq ('.'.$PDF_ORIG_SUFFIX) ) {
2194             my $image_target = $path.$base.'.pdf';
2195                
2196             if ( ! -f $image_target or -M $image_target > -M $image ) {
2197                &report(7, "Create temporary PDF file from original: $base$suffix");
2198                copy($image, $image_target)
2199                   or &abort("Could not create tmp file: $!");
2200                if (&param_value('delete_pdf_images') eq $YES) {
2201                   push(@TMPFILES, $image_target);
2202                }
2203             } else {
2204                &report(7, "$base.pdf newer than $base$suffix, copy skipped ...");
2205             }
2206          } else {
2207             &convert_eps2pdf($image);
2208          }
2209       }
2210    }
2211
2212    ### Convert all PSTEX_T files to PDF_T
2213    if ( @pstex_file_list > 0 ) { 
2214       &report(6, "\nConverting pstex_t docs to pdf_t docs");
2215       foreach my $image (@pstex_file_list) {
2216          &convert_pstex2pdf($image);
2217       }
2218    }
2219
2220    ### Convert all MP images to PDF
2221    if ( @mp_image_list > 0) {
2222       &report(6, "\nConverting MP images to PDF");
2223       foreach my $image (@mp_image_list) {
2224          &convert_mp2pdf($image);
2225       }
2226    }
2227
2228    ### Convert all MMP images to PDF
2229    if ( @mmp_image_list > 0) {
2230       &report(6, "\nConverting MMP images to PDF");
2231       foreach my $image (@mmp_image_list) {
2232          &convert_mp2pdf($image);
2233       }
2234    }
2235
2236    &report(6, "\nFinished converting for ${tex_source}.");
2237 }
2238
2239 ### run pdflatex
2240 # parameter 1: LaTeX file without extension
2241 # parameter 2: log-file where the full out put is stored
2242 # return value: 0 - no errors (no rerun); 1 - errors (rerun required)
2243
2244 sub run_pdflatex {
2245    my $texfile=$_[0];
2246    my $logfile=$_[1];
2247    my @errors=();
2248    my $exit_status=0;
2249    my $extra_options=&param_value('pdftex_opts');
2250
2251    if( !defined($extra_options) or $extra_options eq $NIL ) {
2252       $extra_options = "";
2253    }
2254    
2255    &report(7, "Running pdflatex. This may take a while.\n");
2256    system("pdflatex --interaction nonstopmode $extra_options $texfile > $logfile 2>&1");
2257    $exit_status=$?;
2258    &report(7, "Pdflatex finished. Errors:");
2259
2260    ### extract all errors and warnings from the log file
2261    @errors = &grep_file($logfile, '(Emergency stop|Error|Warning).*:');
2262
2263    ### make sure thumbpdf package does not spoil rerun detection
2264    ### as it will be processed very last
2265    if(grep(/Package thumbpdf/, @errors) == @errors) { @errors=(); }
2266    
2267    if ( @errors != 0 or $exit_status != 0 ) {
2268       if ( grep(/Emergency stop/, @errors) != 0 ) {
2269          &report(2, &file_tail($logfile,10));
2270          &report(2, "\nSee $logfile for details.");
2271          &abort("Fatal error occured. I am lost.");
2272       }
2273       if( @errors != 0 ) {
2274          &report(8, @errors);
2275       } else {
2276          &report(8, &file_tail($logfile,10));
2277       }
2278       &report(7, "\nSee $logfile for details.");
2279       return $FALSE;
2280    } else {
2281       &report(7, "None detected (log file: $logfile).");
2282       return $TRUE;
2283    }
2284 }
2285
2286 #### run bibtex if BIBTEX=$YES or a bibliography tag is found
2287 # included tex files are not parsed for a bibliography
2288 # parameter 1: filename of the aux file without .aux suffix
2289 # parameter 2: log-file where the full out put is stored
2290
2291 sub handle_bibtex {
2292    my $auxfile=$_[0];
2293    my $logfile=$_[1];
2294    my $run_bibtex=$FALSE;
2295    my $bibtex_param=&param_value('bibtex');
2296    
2297    if ( $bibtex_param eq $YES ) {
2298       $run_bibtex=$TRUE;
2299       &report(7, "BibTeX parameter set to '$YES':");
2300    } else {
2301       &report(7, "Checking for BibTeX bibliography in main document: ");
2302       if( &grep_file($auxfile.'.tex', '^[^%]*\\\\bibliography{') != 0) {
2303          $run_bibtex=$TRUE;
2304          &report(7, "Bibliography detected.");
2305       } else {
2306          if ( @REF_DOCS > 0 ) {
2307             &report(7, "Checking for BibTeX bibliography in included documents:");
2308             foreach my $file (@REF_DOCS) {
2309                if( &grep_file($file, '^[^%]*\\\\bibliography{') != 0) {
2310                    $run_bibtex=$TRUE;
2311                    &report(7, "Bibliography detected.");
2312                } else {
2313                  &report(7, "No bibliography detected in $file.");
2314                }
2315             }
2316          } else {
2317            &report(7, "No bibliography detected.");
2318         }
2319       }
2320    }
2321
2322    if ( $run_bibtex ) {
2323       my @errors=();
2324       my $exit_status=0;
2325
2326       &report(7, "Running bibtex. This may take a while.\n");
2327       system "bibtex $auxfile > $logfile";
2328       $exit_status=$?;
2329       &report(7, "Bibtex finished. Errors:");
2330
2331       ### extract all errors and warnings from the log file
2332       @errors=&grep_file($logfile, 'error message');
2333
2334       if ( @errors != 0 or $exit_status != 0 ) {
2335          &report(4, &file_tail($logfile));
2336          &report(4, "\nYou can switch off BibTeX support by setting the bibtex parameter accordingly.");
2337       } else {
2338          &report(7, "None detected (log file: $logfile).");
2339       }
2340    }
2341 }
2342
2343 #### run bibtex on file.gls if BIBTEX=$YES or a bibliography tag is found
2344 # included tex files are not parsed for a bibliography
2345 # parameter 1: filename of the aux file without .aux suffix
2346 # parameter 2: log-file where the full out put is stored
2347
2348 sub handle_gloss {
2349    my $auxfile=$_[0];
2350    my $logfile=$_[1];
2351    my $run_gloss=$FALSE;
2352    my $gloss_param=&param_value('gloss');
2353    my $glsfile=$auxfile.'.gls';
2354    
2355    if ( $gloss_param eq $YES ) {
2356       $run_gloss=$TRUE;
2357       &report(7, "Gloss parameter set to '$YES':");
2358    } else {
2359       &report(7, "Checking for Gloss bibliography in main document: ");
2360       if( &grep_file($auxfile.'.tex', '^[^%]*\\\\printgloss{') != 0) {
2361          $run_gloss=$TRUE;
2362          &report(7, "Gloss bibliography detected.");
2363       } else {
2364         if ( @REF_DOCS > 0 ) {
2365            &report(7, "Checking for Gloss bibliography in included documents:");
2366            foreach my $file (@REF_DOCS) {
2367               if( &grep_file($file, '^[^%]*\\\\printgloss') != 0) {
2368                   $run_gloss=$TRUE;
2369                   &report(7, "Gloss bibliography detected.");
2370               } else {
2371                 &report(7, "No gloss database detected in $file.");
2372               }
2373            }
2374         } else {
2375           &report(7, "No gloss database detected.");
2376         }
2377       }
2378    }
2379    if ( $run_gloss ) {
2380       my @errors=();
2381       my $exit_status=0;
2382
2383       &report(7, "Running bibtex on $glsfile. This may take a while.\n");
2384       system "bibtex $glsfile > $logfile 2>&1";
2385       $exit_status=$?;
2386       &report(7, "Bibtex finished. Errors:");
2387
2388       ### extract all errors and warnings from the log file
2389       @errors=&grep_file($logfile, 'error message');
2390
2391       if ( @errors != 0 or $exit_status != 0 ) {
2392          &report(4, &file_tail($logfile));
2393          &report(4, "\nYou can switch off Gloss support by setting the gloss parameter accordingly.");
2394       } else {
2395          &report(7, "None detected (log file: $logfile).");
2396       }
2397    }
2398 }
2399
2400 #### run thumbpdf command to make thumbnails
2401 # more informations: /usr/share/texmf/doc/pdftex/thumbpdf/readme.txt
2402 # parameter 1: LaTeX file without extension
2403 # parameter 2: log-file where the full out put is stored
2404
2405 sub run_thumbpdf {
2406    my $texfile=$_[0];
2407    my $logfile=$_[1];
2408    my $exit_status=0;
2409
2410    &report(7, "\nCreating thumbnails with 'thumbpdf'\n");
2411    &system_command("thumbpdf $texfile", $FALSE, 8,
2412       "thumbpdf failed.\n"
2413       ."I will continue, but maybe there will not be thumbs in the PDF doc.");
2414
2415    if ( -f 'thumbpdf.log' ) {
2416       move('thumbpdf.log', $logfile);
2417       &report(7, "\nSee $logfile for details.");
2418    }
2419
2420    ### store possible tmp files
2421    push(@TMPFILES, glob 'thumb???.png');
2422    push(@TMPFILES, 'thumbpdf.pdf');
2423    push(@TMPFILES, 'thumbdta.tex'); 
2424    push(@TMPFILES, $texfile.'.tpt');
2425 }
2426
2427
2428 #### run ppower command to make presentations
2429 # more informations: 
2430 # parameter 1: LaTeX file without extension
2431 # parameter 2: log-file where the full out put is stored
2432
2433 sub run_ppower {
2434    my $texfile=$_[0];
2435    my $logfile=$_[1];
2436    my $exit_status=0;
2437    my $infile;
2438    my $outfile;
2439    my $texfile_base;
2440    my $texfile_path;
2441    my $texfile_suffix;
2442
2443    ##### Getting document name, suffix and path
2444    ($texfile_base,$texfile_path,$texfile_suffix) = fileparse($texfile,&param_value('tmp_base_suffix'));
2445
2446    $infile=$texfile_base.'.pdf';
2447    $outfile=$texfile_base.'_p4.pdf';
2448
2449    &report(7, "\nPostprocessing PDF file with 'ppower'\n");
2450    if(&system_command("ppower $infile $outfile", $FALSE, 8,
2451       "ppower failed.\nI will continue, "
2452       ."but maybe there will not be pause effects in the PDF doc.")) {
2453       &report(7, "\nThe postprocessed pdf file is: $outfile\n");
2454    }
2455
2456    if ( -f 'ppower.log' ) {
2457       move('ppower.log', $logfile);
2458       &report(7, "See $logfile for details.");
2459    }
2460 }
2461
2462 #### run authorindex command to obtain an author index
2463 # more informations: 
2464 # parameter 1: LaTeX file without extension
2465 # parameter 2: log-file where the full out put is stored
2466
2467 sub run_authorindex {
2468    my $texfile=$_[0];
2469    my $logfile=$_[1];
2470    my $exit_status=0;
2471
2472    &report(7, "\nProcessing file with 'authorindex'\n");
2473    &system_command("authorindex $texfile", $FALSE, 8,
2474       "authorindex failed.\nI will continue, "
2475       ."but maybe there will not be an author index in the PDF doc.");
2476
2477    if ( -f 'authorindex.log' ) {
2478       move('authorindex.log', $logfile);
2479       &report(7, "\nSee $logfile for details.");
2480    }
2481
2482 }
2483
2484
2485 ##### read and analyse configuration and options and adjust basic variables
2486 ##### accordingly
2487 #### The following sources are considered (last value overrides previous)
2488 ##   1. general configuration (global variables in the script)
2489 ##   2. private configuration (in user's RC file)
2490 ##   3. command line options
2491 # parameters: none 
2492 # return value: given document argument
2493
2494 sub adjust_configuration {
2495    my $valid_rcfile = $FALSE;
2496    my %opt_specs =();
2497    
2498    ### Check number of arguments
2499    if ( @ARGV == 0 ) {
2500       &report(1, "\nI need at least one argument!");
2501       &print_usage;
2502       exit 1;
2503    }
2504    
2505    ##### command line options and private configuration files handling
2506    
2507    ### set parameters from rc file
2508    if ( -f $RC_FILENAME ) {
2509       my $rcfile_version;
2510       $rcfile_version = &read_configuration($RC_FILENAME);
2511       if( $rcfile_version == $MYRCFILE_VERSION ) {
2512          $valid_rcfile = $TRUE;
2513       } elsif ( $rcfile_version == 0 ) {
2514          &report(4, "Could not determine version of read RC file.");
2515       } else {
2516          &report(4, "Version of read RC file ($rcfile_version) and ",
2517             "this script ($MYRCFILE_VERSION) differs.");
2518       }
2519    }
2520    
2521    ### scan parameters 
2522    foreach (keys %PARAMETER_LIST) {
2523       $opt_specs{&option_specifier($_)} = \&handle_option;
2524    }
2525    if(! GetOptions(%opt_specs)) {
2526       &print_usage;
2527       &abort("An error occured while processing command line options");
2528    }
2529
2530    if( ! $valid_rcfile ) {
2531       &report(3,"No valid configuration file found. Please run '$MYNAME "
2532          ."--configure'.\nUsing default values for missing parameters in this "
2533          ."session.");
2534    }
2535
2536    ### As the configuration process is done now, it is time to set the
2537    #   global configuration flag
2538    $CONFIGURED = $TRUE;
2539    
2540    #### do some test in order to secure as good as possible that we will
2541    #### succeed before to much work was done and maybe some data as damaged
2542
2543    ### make sure that tmp_base_suffix is not empty
2544    if ( &param_value('tmp_base_suffix') eq "" ) {
2545       &report(2, "\nCAUTION: Empty tmp_base_suffix would destroy the original files!");
2546       &abort("Parameter tmp_base_suffix is not set.");
2547    }
2548    
2549    ##### check for required commands
2550    if (&param_value('check_commands') ne $NO ) {
2551       &check_commands;
2552    }
2553
2554    ### Check number of arguments
2555    if ( @ARGV != 1 ) {
2556       &report(1, "\nWrong number of arguments. I need exactly one file.");
2557       &print_usage;
2558       exit 1;
2559    }
2560    
2561    return $ARGV[0];
2562 }
2563
2564 #### prepare the logdir for the log files of the various called appplications
2565
2566 sub prepare_logdir {
2567    my $log_dir= &param_value('logdir');
2568    my $my_new_log;
2569
2570    ##### Preparing the LOGDIR
2571    if (! &check_dir($log_dir, "Could not create log directory", $YES)) {
2572       &abort("Please, set a different path and restart");
2573    }
2574
2575    # make sure there is a slash at the end of the path
2576    $log_dir .= '/' if( ! ($log_dir =~ m#/$#) );
2577    
2578    if( <$log_dir/*.log> and &param_value('clean_logs') eq $YES ) { 
2579       &report(6, "\nRemoving old log files ($log_dir).");
2580       unlink (<$log_dir/pdflatex-*.log>, <$log_dir/bibtex-*.log>,
2581          <$log_dir/gloss-*.log>, <$log_dir/thumbpdf-*.log>,
2582          <$log_dir/ppower-*.log>, <$log_dir/authorindex-*.log>,
2583          <$log_dir/tex2pdf-*.log>);
2584    } else {
2585       &report(6, "\nAll log files will be stored in ($log_dir).");
2586    }
2587
2588    ### move my pre-configuration log file to specified log directory
2589    $my_new_log = "$log_dir/tex2pdf-$$.log";
2590    if ( move($MYLOGFILE, $my_new_log) ) {
2591       $MYLOGFILE = $my_new_log;
2592    } else {
2593       &report(3, "Could not move '$MYLOGFILE' to logdir: $!");
2594    }
2595 }
2596
2597 ##### analyse document argument
2598 #### process the one and only argument (besides the options) which specifies
2599 #### which LaTeX document the user wants to translate to PDF
2600 #### a lyx file will be translated to LaTeX first
2601 # parameter 1: argument
2602
2603 sub process_doc_argument {
2604    my $argument = $_[0];
2605    my $doc_base;
2606    my $doc_path;
2607    my $arg_suffix;
2608    
2609    ##### Getting document name, suffix and path
2610    ($doc_base,$doc_path,$arg_suffix) = fileparse($argument, ('\.tex', '\.lyx'));
2611
2612    if (! defined($arg_suffix) or $arg_suffix eq "") {
2613       $arg_suffix = '.tex';
2614    }
2615    
2616    ###### change working directory to document directory
2617    if ( $doc_path ne "" ) {
2618       chdir $doc_path;
2619    }
2620    
2621    ###### make DOCPATH an absolute path
2622    $doc_path = cwd.'/';
2623    
2624    ###### Cut off suffix and do lyx or tex specific stuff
2625    if ( $arg_suffix eq '.lyx' ) {
2626       # Lyx document argument: generate Latex document if required
2627       &generate_tex_file($doc_base.'.lyx', $doc_base.'.tex');
2628    } else {
2629       # LaTeX document argument: check access to given LaTeX document
2630       &check_file($doc_base.'.tex', "Cannot read the specified LaTeX document!");
2631    }
2632    
2633    return $doc_path.$doc_base.'.tex';
2634 }
2635
2636 #### handle the dir of the input path if the document has one and
2637 # parameter 1: main tex doc
2638 # return value: absolute input path
2639
2640 sub process_inputpath {
2641    my $texdoc = $_[0];
2642    my $doc_base;
2643    my $doc_path;
2644    my $doc_suffix;
2645    my $input_path;
2646    my @matches;
2647    
2648    ### Maybe the user has given us a different inputpath
2649    $input_path = &param_value('input_path');
2650    if(defined($input_path) and $input_path ne "") {
2651       &report(6, "Setting input path to specified directory: $input_path");
2652       
2653       &report(7, "Change working directory to input path.");
2654       chdir $input_path;
2655       
2656       return $input_path;
2657    }
2658
2659    ##### Getting document name, suffix and path
2660    ($doc_base,$doc_path,$doc_suffix) = fileparse($texdoc, ('\.tex'));
2661
2662    ###### change working directory to input_path if set
2663    # When the files' path (images, included documents, etc.) in your document is
2664    # relative to another directory than the PASSED document's directory.
2665    # This is useful when the calling application (e.g. LyX) generates a
2666    # temporary
2667    # TeX file and calls the tex2pdf with it instead of the original file.
2668    
2669    @matches=&extract_tag_contents($texdoc, 'def\\\\input@path');
2670    $input_path=$matches[0];
2671    
2672    ## check if input_path is ok
2673    if ($input_path) {
2674       &report(7, "Found an input path in the latex document: $input_path");
2675       if( &check_dir($input_path, 'The retrieved input@path seems not to be valid.', $NO)) {
2676          &set_param_value('input_path', $input_path);
2677          &report(7, "Change working directory to input path.");
2678          chdir $input_path;
2679       } else {
2680          &abort ('I am lost.');
2681       }
2682    } else {
2683       &report(4, "No input path in the latex document found.");
2684       &report(7, "Resources are expected to be relative to document's location: $doc_path");
2685          $input_path=$doc_path;
2686    }
2687    
2688    return $input_path;
2689 }
2690
2691 #### set the working dir to the input path if the document has one and
2692 #### and determine the path for the result
2693 # parameter 1: main tex doc
2694 # parameter 2: absolute input path
2695 # return value: absolute path were the resulting pdf doc should be stored
2696
2697 sub get_target_name {
2698    my $texdoc = $_[0];
2699    my $input_path=$_[1];
2700
2701    my $doc_base;
2702    my $doc_path;
2703    my $doc_suffix;
2704    my $destination;
2705    my $pdf_path;
2706    
2707    ##### Getting document name, suffix and path
2708    ($doc_base,$doc_path,$doc_suffix) = fileparse($texdoc, ('\.tex'));
2709  
2710    ##### set the directory where the final pdf will be stored
2711    $destination=&param_value('destination');
2712    $pdf_path=undef;
2713    
2714    if ($destination eq 'custom' ) {
2715       $pdf_path=&param_value('custom_path');
2716    } elsif ($destination eq 'input') {
2717       $pdf_path=$input_path;
2718    } else {
2719       $pdf_path=$doc_path;
2720    }
2721
2722    if( ! defined($pdf_path) or $pdf_path eq "" or ! &check_dir($pdf_path,
2723       'The specified destination directory for the final PDF documents is not valid.', $NO)) {
2724       &report(7, "Using document's instead of destination path: $doc_path");
2725       $pdf_path=$doc_path;
2726    }
2727
2728    # make sure there is a slash at the end of the path
2729    $pdf_path .= '/' if( ! ($pdf_path =~ m#/$#) );
2730    
2731    return $pdf_path.$doc_base.'.pdf';
2732 }
2733
2734 ### generate hyperref parameters from given settings
2735 # parameter 1: main tex doc
2736 # return_value: result
2737
2738 sub generate_hyperref_params {
2739    my $texdoc = $_[0];
2740    my $para;
2741    my @params = ('pdftex');
2742
2743    ##### Set title and author from main LaTeX document or parameters
2744    foreach my $info (('title', 'author')) {
2745       my $value;
2746
2747       $value=&param_value("$info");
2748       if (! defined($value) ) {
2749          my @matches=&extract_tag_contents($texdoc, $info);
2750          $value= $matches[0];
2751          if (! defined($value) ) {
2752             &report(4, "\nWARNING: Could not identify document's $info correctly.");
2753             &report(7, "Maybe you have used a LaTeX tag inside the $info which confuses me.\n",
2754                "Adjust the $info of the LaTeX file in order to avoid the problem or\n",
2755                "you could set the $info parameter manually.");
2756             $value= &param_value("default_$info");
2757             &report(7, "Using default-$info: $value");
2758          }
2759       }
2760       if (! defined($value) or $value eq $NIL ) {
2761          &report(7, "$info field set to $NIL - no value will be passed.");
2762       } else {
2763          &report(7, "Document's $info: $value");
2764          push(@params, "pdf$info={$value}");
2765       }
2766    }
2767    
2768    $para=&param_value('paper');
2769    if ( $para ne $NIL ) { push(@params, $para); }
2770
2771    $para=&param_value('link_toc_page'); 
2772    if ( $para eq $YES ) { push(@params, 'linktocpage'); }
2773
2774    $para=&param_value('colorlinks');
2775    if ( $para ne $NIL ) {
2776       $para= $para eq $YES ? 'true' : 'false';
2777       push(@params, "colorlinks=$para");
2778    }
2779
2780    if ( $para ne 'false' ) {
2781       foreach (('linkcolor', 'pagecolor', 'urlcolor', 'citecolor')) {
2782          $para=&param_value($_);
2783          if ( $para ne $NIL ) { push(@params, "$_={$para}"); }
2784       }
2785    }
2786
2787    $para=&param_value('hyperref_args');
2788    if(defined($para) and $para ne "" and $para ne $NIL) {
2789       push(@params, $para);
2790    }
2791    
2792    return @params;
2793 }
2794
2795 #### Prepare the main document and all referenced ones for the generation
2796 #### of the PDF document (including referenced images)
2797 # parameter 1: top level tex document
2798 # parameter 2: parameter list of hyperref parameters
2799
2800 sub prepare_documents {
2801    my ($main_tex_doc, $input_path, @hyperref_params) = @_;
2802    @REF_DOCS=();
2803
2804    ## get a name for the tmp tex file
2805    my $main_tmp_doc = &reserve_tmp_texname($main_tex_doc, $input_path);
2806
2807    ## Get the list of imported files from the tex file
2808    &get_file_list($main_tex_doc);
2809    
2810    ## remove main file from list (first element; needs special handling)
2811    shift @REF_DOCS;
2812    
2813    ## tell user about the identified refereneced docs
2814    if ( @REF_DOCS > 0 ) {
2815       &report(7, "\nFound the following referenced TeX files:");
2816       foreach my $file (@REF_DOCS) {
2817          &report(7, ">>>>> $file");
2818       }
2819    } else {
2820       &report(7, "\nFound no referenced TeX files.");
2821    }
2822    
2823    ##### Generate adjusted temp tex files and convert all their images
2824    ## main doc
2825    &report(6, "\nGenerating main temporary LaTeX document: $main_tmp_doc");
2826    &convert_tex2tmp($main_tex_doc, $main_tmp_doc, \@hyperref_params);
2827    &convert_images($main_tex_doc);
2828    
2829    ## referenced docs
2830    foreach my $file (@REF_DOCS) {
2831       my $tmp_file = &reserve_tmp_texname($file);
2832    
2833       ### Insert pdf conversation tags in tex file and write it to tmp_file
2834       &report(7, "\nGenerating temporary LaTeX document: $tmp_file");
2835       &convert_tex2tmp($file, $tmp_file, undef);
2836       &convert_images($file);
2837    }
2838
2839    return $main_tmp_doc;
2840 }
2841
2842 ##### Generate the final PDF document
2843 # parameter 1: filename of the source LaTeX document (with extension)
2844
2845 sub generate_pdf_doc {
2846    my $source = $_[0];
2847    my $runno=1;
2848    my $rerun=$TRUE;
2849    my $doc;
2850    my $pdf_doc;
2851    my $base;
2852    my $path;
2853    my $suffix;
2854
2855    my $max_run_no= &param_value('maxrun');
2856    my $min_run_no= &param_value('minrun');
2857    my $log_dir= &param_value('logdir');
2858    $log_dir .= '/' if( ! ($log_dir =~ m#/$#) );
2859    my $makeindex_options=&param_value('makeindex_opts');
2860    
2861    # setting the log files for the output of pdflatex, bibtex, gloss,
2862    # thumbpdf, ppower and authorindex
2863    my $pdflog_base = $log_dir."pdflatex-$$-";
2864    my $bibtex_log = $log_dir."bibtex-$$.log";
2865    my $gloss_log = $log_dir."gloss-$$.log";
2866    my $thumbpdf_log = $log_dir."thumbpdf-$$.log";
2867    my $ppower_log = $log_dir."ppower-$$.log";
2868    my $authorindex_log = $log_dir."authorindex-$$.log";
2869
2870    ##### Getting document name, suffix and path
2871    ($base,$path,$suffix) = fileparse($source, ('\.tex'));
2872    $doc = $path.$base;
2873    $pdf_doc = $base.'.pdf';
2874
2875    ### run pdflatex until no more errors are reported (max MAXRUNNO)
2876    while ( $rerun and $runno <= $max_run_no )
2877    {
2878       &report(6, "\n************ Pdflatex run no. $runno *************");
2879       if ( &run_pdflatex($doc, $pdflog_base.$runno.'.log') == $TRUE 
2880          and ( $min_run_no <= $runno )) {
2881          # no errors detected and min. no. of runs are done
2882          $rerun=$FALSE;
2883       } else {
2884          # errors appeared or max run no. has not been reached
2885          $rerun=$TRUE;
2886       }
2887    
2888       ### Execute BibTeX after first run if set (and required)
2889       if ( $runno == 1 and &param_value('bibtex') ne $NO ) {
2890          &report(6, "\n****************** BibTeX handling ***********************");
2891          &handle_bibtex($doc, $bibtex_log);
2892       }
2893
2894       ### Execute BibTeX on file.gls after first run if set (and required)
2895       if ( $runno == 1 and &param_value('gloss') ne $NO ) {
2896          &report(6, "\n****************** Gloss handling ***********************");
2897          &handle_gloss($doc, $gloss_log);
2898       }
2899
2900       ### generated index file exists
2901       if ( $runno == 1 and -f $doc.'.idx' and &param_value('force_index') ne $NO ) {
2902          if( !defined($makeindex_options) or $makeindex_options eq $NIL ) {
2903             $makeindex_options = "";
2904          }
2905          &report(6, "\n****************** Extra index generation ***************");
2906          &report(7, "Document seems to have an index. Generating ...\n");
2907          &system_command("makeindex $makeindex_options $doc.idx", $FALSE, 8,
2908             "makeindex failed.\nI will continue, "
2909             ."but maybe there will not be an index in the PDF doc.");
2910       }
2911
2912       $runno += 1;
2913    }
2914
2915    $rerun = $FALSE;
2916
2917    ### if the authorindex option is switched on then run authorindex
2918    if ( &param_value('authorindex') eq $YES ) {
2919       &report(6, "\n****************** authorindex generation *****************");
2920       &run_authorindex($doc, $authorindex_log);
2921    }
2922    
2923    ### generated index file exists
2924    if ( -f $doc.'.idx' and &param_value('force_index') ne $NO ) {
2925       if( !defined($makeindex_options) or $makeindex_options eq $NIL ) {
2926          $makeindex_options = "";
2927       }
2928       &report(6, "\n****************** Extra index generation ***************");
2929       &report(7, "Document seems to have an index. Generating ...\n");
2930       &system_command("makeindex $makeindex_options $doc.idx", $FALSE, 8,
2931          "makeindex failed.\nI will continue, "
2932          ."but maybe there will not be an index in the PDF doc.");
2933       $rerun=$TRUE;
2934    }
2935    
2936    ### if the thumbpdf option is switched on then make thumbnails
2937    if ( &param_value('thumbpdf') eq $YES ) {
2938          &report(6, "\n****************** Thumbnail generation *****************");
2939       &run_thumbpdf($doc, $thumbpdf_log);
2940       $rerun=$TRUE;
2941    }
2942
2943    ### One final pdflatex run if requested
2944    if ( $rerun ) {
2945       &report(6, "\n************ One final pdflatex run no. $runno *************");
2946       &run_pdflatex($doc, $pdflog_base.$runno.'.log');
2947    }
2948
2949    ### if the ppower option is switched on then run ppower
2950    if ( &param_value('ppower') eq $YES ) {
2951       &report(6, "\n****************** ppower postprocess *****************");
2952       &run_ppower($doc, $ppower_log);
2953    }
2954
2955    if ( ! -f $pdf_doc ) {
2956       &abort("\nThe new PDF file could not be generated: ".$pdf_doc);
2957    }
2958
2959    return $pdf_doc;
2960 }
2961    
2962 ################## Lift off !!!! (main part) ##################
2963
2964 my $texdoc;
2965 my $doc_argument;
2966 my $input_path;
2967 my $target_name;
2968 my @hyperref_params;
2969 my $new_pdf_doc;
2970 my $tmp_tex_doc;
2971
2972 &report(5, "\nScript starts ($MYRELEASE)");
2973
2974 ##### read and analyse configuration and options and adjust basic variables
2975 ##### accordingly
2976 ##### write RC file on config request
2977 #### use the finished configuration to get all further settings before we
2978 #### actually start doing something
2979
2980 &report(5, "\nProcessing given parameters and arguments.");
2981 $doc_argument = &adjust_configuration;
2982
2983 #### prepare the script to write some information to specified log files
2984
2985 &report(5, "\nPreparing directory for log files.");
2986 &prepare_logdir;
2987
2988 #### process the one and only argument (besides the options) which specifies
2989 #### which LaTeX document the user wants to translate to PDF
2990 #### a lyx file will be translated to LaTeX first
2991
2992 &report(5, "\nAnalysing your document argument.");
2993 $texdoc = &process_doc_argument($doc_argument);
2994
2995 #### we would like to get some more information from the actual
2996 #### main LaTeX document before we really start
2997 #### parse the document and try to get the info
2998
2999 ## translate hyperref settings to the actual package parameters 
3000    
3001 &report(5, "\nSetting up parameters for hyperref.");
3002 @hyperref_params = &generate_hyperref_params($texdoc);
3003
3004 ## set the working dir to the input path if the document has one and
3005
3006 &report(5, "\nProcessing input path for main tex document.");
3007 $input_path = &process_inputpath($texdoc);
3008
3009 ## determine the name for the result
3010
3011 &report(5, "\nSetting the correct name for the result.");
3012 $target_name = &get_target_name($texdoc, $input_path);
3013
3014 ## as much as possible is prepared in advance at this point
3015 ## so hopefully we will succeed in generating the PDF document
3016
3017 ##### real work starts NOW
3018
3019 ##### Generate adjusted temp tex files and convert all their images
3020
3021 &report(5, "\nPreparing all documents and images.");
3022 $tmp_tex_doc = &prepare_documents($texdoc, $input_path, @hyperref_params);
3023
3024 ##### Generate the final PDF document
3025
3026 &report(5, "\nProcessing the actual generation of the PDF document.");
3027 $new_pdf_doc = &generate_pdf_doc($tmp_tex_doc);
3028
3029 ##### Finalize
3030 move($new_pdf_doc, $target_name) or &abort("Could not move PDF file to final destination: $!");
3031
3032 if ( &param_value('debug') eq $NO ) {
3033    &clean_up;
3034 } else {
3035    &print_temp_files;
3036 }
3037
3038 &report(5, "\nThe new pdf file is: $target_name\n");
3039