Whamcloud - gitweb
LU-925 agl: trigger async glimpse lock when statahead
[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    my $compat = "-dCompatibilityLevel=1\\.1";
1422    if (defined($ENV{'GS_OPTIONS'}) && $ENV{'GS_OPTIONS'} =~ /$compat/o) {
1423       &report(9, "Good: ghostscript option '-dCompatibilityLevel=1.1' detected "
1424          ."in\n'\$GS_OPTIONS'.");
1425    } elsif (&grep_file($exec_epstopdf, $compat, $TRUE) > 0) {
1426       &report(9, "Good: ghostscript option '-dCompatibilityLevel=1.1' detected "
1427          ."in\n'$exec_epstopdf'.");
1428    } else {
1429       &report(4, "\nWARNING: no ghostscript option '-dCompatibilityLevel=1.1' "
1430          ."in\n'$exec_epstopdf'.\n"
1431          ."You might run into trouble with the conversions of bitmaps.\n"
1432          ."Adjusting epstopdf or setting the environment variable GS_OPTIONS "
1433          ."to \n".'"$GS_OPTIONS -dCompatibilityLevel=1.1" before calling this '
1434          ."script\nmight help in this case.\n");
1435    }
1436
1437    if ( &param_value('thumbpdf') eq $YES ) {
1438       &checkCommand("thumbpdf","You can switch off thumbpdf support to fix this.");
1439    }
1440
1441    if ( &param_value('ppower') eq $YES ) {
1442       &checkCommand("ppower","You can switch off ppower support to fix this.");
1443    }
1444
1445    ### authorindex perl script
1446    if ( &param_value('authorindex') eq $YES ) {
1447       &checkCommand("authorindex","You can switch off authorindex support to fix this.");
1448    }
1449
1450    ### bibtex executable
1451    if ( &param_value('bibtex') ne $NO or &param_value('gloss') ne $NO) {
1452    &checkCommand("bibtex","You can switch off BibTeX support to fix this.");
1453    }
1454 }
1455
1456 #### generate the tmp file name from the original tex filename
1457 #### and make sure that they are not the same
1458 # parameter 1: orignal filename (with or without a path or .tex)
1459 # parameter 2: path for the tmp file (default: doc path)
1460 # return value: tmp name
1461
1462 sub reserve_tmp_texname {
1463    my $original_name = $_[0];
1464    my $tmp_path = $_[1];
1465    my $tmp_base_suffix = &param_value('tmp_base_suffix');
1466    my $overwrite = &param_value('overwrite');
1467    my $original_path;
1468    my $original_base;
1469    my $suffix;
1470    my $pathed_tmp_base;
1471    my @existing_files;
1472
1473    # separate path, base and suffix
1474    ($original_base,$original_path,$suffix) = fileparse($original_name, '\.tex');
1475    
1476    # set the path of the tmp file
1477    if(!$tmp_path) {
1478       $tmp_path=$original_path;
1479    } else {
1480       $tmp_path .= '/' if( $tmp_path ne "" and ! ($tmp_path =~ m#/$#) );
1481    }
1482    
1483    # abort if no absolute path is given 
1484    if( index($tmp_path, "/") != 0 ) {
1485       &abort("Internal error: Illegal argument for reserve_tmp_texname:".
1486          "Given file has no absolute path: $original_name");
1487    } 
1488
1489    # make sure that tmp_base_suffix is set correctly
1490    if($tmp_base_suffix eq "") {
1491       &abort("Temporary filename base suffix is empty.");
1492    }
1493
1494    $pathed_tmp_base = $tmp_path.$original_base.$tmp_base_suffix;
1495
1496    # make sure no file with this base exists in this directory
1497    @existing_files = glob "$pathed_tmp_base.*";
1498    if (@existing_files != 0) {
1499       &report(3, "Problems detected while reserving temporay file name!\n",
1500          "In this directory are already files with this basename.\n",
1501          "A list of the conflicting, existing files:\n",
1502          join("\n", @existing_files), "\n");
1503       if ($overwrite eq $YES) {
1504          &report(4, "As you have activated the parameter 'overwrite' I will "
1505                  ."continue.\n",
1506                  "However, in order to protect the existing files I will not\n",
1507                  "delete any files with this basename at the final clean-up.");
1508       } else {
1509          &report(2, "You could activate the parameter 'overwrite' or remove ",
1510          "the\n corresponding files in order to avoid these problems."); 
1511          &abort("No temporary name found for $original_name.");
1512       }
1513    } else {
1514       push(@TMP_TEX_FILES, $pathed_tmp_base); 
1515    }
1516
1517    return $pathed_tmp_base.$suffix;
1518 }
1519
1520 ### generate LaTeX file from LyX document with LyX itself
1521 # parameter ($1): Lyx document
1522 # parameter ($2): Latex document
1523
1524 sub generate_tex_file {
1525    my $lyx_doc = $_[0];
1526    my $tex_doc = $_[1];
1527    my $lyx_dir;
1528    my $lyx_output;
1529    my $lyx_exec=&param_value('lyx_exec');
1530    
1531    $lyx_dir = &param_value('lyxrc_path');
1532    $lyx_dir .= '/' if( ! ($lyx_dir =~ m#/$#) );
1533    $lyx_dir .= '/' if( ! ($lyx_dir =~ m#/$#) );
1534
1535    ### Check if LyX file can be accessed
1536    &check_file($lyx_doc,"Cannot read the specified LyX document!");
1537
1538    ### Check if LaTeX file exists and is newer than the LyX file
1539    if ( -f $tex_doc and -M $tex_doc < -M $lyx_doc ) {
1540       &report(4, "\nLaTeX file is newer than LyX document ($lyx_doc).\n",
1541       "Using existing TeX file: $tex_doc\n",
1542       "Remove it to force its new generation.");
1543    } else {
1544       ### export LaTeX file with LyX (needs a display!)
1545       &checkCommand($lyx_exec, "Cannot generate LaTeX document without LyX!");
1546       &report(6, "\nExporting LaTeX file");
1547       
1548       ### move some files out of the way that stop LyX from exporting
1549       foreach my $file ($lyx_dir."lyxpipe.out",$lyx_dir."lyxpipe.in",$tex_doc) {
1550          if ( -f $file ) { rename($file, $file.'~'); }
1551       }
1552
1553       $lyx_output = `$lyx_exec --export latex $lyx_doc 2>&1`;
1554
1555       ### check if LaTeX file now really exists
1556       if ( ! -f $tex_doc ) {
1557          &report(2, "Lyx Output:\n$lyx_output");
1558          &report(2, "\nSorry. I cannot find '$tex_doc'.");
1559          &abort("The LaTeX document was not generated by LyX!");
1560       } else {
1561          &report(8, "Lyx Output:\n$lyx_output");
1562       }
1563    }
1564 }
1565
1566 #### search TeX document for a certain text tag (e.g. author, title)
1567 # parameter 1: file to parse
1568 # parameter 2: full TeX tag name
1569 # return value: list of the contents strings of all matching tags
1570
1571 sub extract_tag_contents {
1572    my $source=$_[0];
1573    my $tag_name=$_[1];
1574    my $contents;
1575    my @results=();
1576    my $error_message="Could not read TeX document to extract $tag_name";
1577
1578    &check_file($source, $error_message.'.');
1579    open(EXTRACT_SOURCE, "<$source") or
1580       &abort($error_message." ($source).");
1581
1582
1583    while(<EXTRACT_SOURCE>) {
1584       ### ignore comments
1585       s/(^|[^\\])%.*/$1/;
1586       # ignore \thanks{}
1587       s/\\thanks\{.*?\}//g;
1588       # change \and to and
1589       s/\\and/ and/g;
1590
1591       $contents .= $_;
1592    }
1593
1594    close EXTRACT_SOURCE;
1595
1596    $_ = $contents;
1597
1598    # add contents of all occurences of this tag in a line to result list
1599    while ( /\\($tag_name)(\[[^]]*?\])*?{+([^{}]*?)}/s ) {
1600       my $text = $3;
1601       $_ = $';
1602       # remove newlines
1603       $text =~ s/\n//g;
1604       $text="" if (!defined($text));
1605       push(@results, $text);
1606    }
1607
1608    return @results;
1609 }
1610
1611 #### search for filenames in given TeX Tag in entire document
1612 ### skip all comments and duplicates while parsing
1613 # parameter 1: file to parse
1614 # parameter 2: full TeX tag name
1615 # parameter 3: reference to a list of possible filename suffixes (without '.')
1616 # parameter 4: regexp for suffix to ignore when specified in TeX file
1617 #              (undef if not used)
1618 # return value: list of identified files
1619
1620 sub identify_files {
1621    my $source=$_[0];
1622    my $tag_name=$_[1];
1623    my @suffixes=@{$_[2]};
1624    my $ignore_suffix=$_[3];
1625    my @matched_tags;
1626    my @found_files=();
1627    my $regexp_suffixes;
1628
1629    # create one large regexp from given suffixes and escape dots in them
1630    $regexp_suffixes= '.('.join('|', @suffixes).')';
1631    $regexp_suffixes =~ s/\./\\./g;
1632
1633    @matched_tags = &extract_tag_contents($source, $tag_name);
1634
1635    foreach my $tag_contents (@matched_tags) {
1636       my $path;
1637       my $base;
1638       my $suffix;
1639       my $kpse_result;
1640       my $working_dir = cwd."/";
1641
1642       ($base,$path,$suffix) = fileparse($tag_contents, $regexp_suffixes);
1643
1644       # if a suffix is specified in the tag_contents handle it as requested
1645       # 
1646       # 1. $suffix: TRUE if $suffix is defined and not of zero length
1647       #    means: a valid suffix has been found in the filename
1648       # 2. defined($ignore_suffix): TRUE if $ignore_suffix is defined
1649       #    means: a regexp for suffixes to be ignored has been specified as
1650       #          parameter4
1651       # 3. $suffix =~ /$ignore_suffix/: TRUE if $suffix matches the regexp
1652       #    means: the suffix in the filename is wanted to be ignored
1653       #
1654       # The IF statement will be executed when:
1655       #   a valid suffix has been found in the filename (1)
1656       #   AND regexp for suffixes to be ignored has NOT been specified (not 2)
1657       # OR
1658       #   a valid suffix has been found in the filename (1)
1659       #   AND regexp for suffixes to be ignored has been specified (2)
1660       #   AND the suffix in the filename is NOT wanted to be ignored (not 3)
1661       #
1662       # The stuff that is executed if the entire IF statement is TRUE does the
1663       # following: accept the found suffix and consider it as the only possible
1664       # file name.
1665       if($suffix and not (defined($ignore_suffix) and $suffix =~ /$ignore_suffix/)){
1666          $kpse_result=`kpsewhich $tag_contents`;
1667          # print warning and skip this tag if kpsewhich could not find it  
1668          if (!$kpse_result) {
1669             &report(4, "WARNING - Could not identify referenced file:\n",
1670             " Ignoring '$tag_contents'.");
1671             next;
1672          }
1673       } else {
1674          # if there is a '.' in the basename assume that this is a reference
1675          # to a file of another type and skip it
1676          if( $base =~ /\./ ) {
1677             &report(9, "Found an unknown extension. Ignoring '$tag_contents'.");
1678             next;
1679          }
1680
1681          # search for all possible files with allowed suffixes
1682          foreach my $allowed_suffix (@suffixes) {
1683             if (not $allowed_suffix =~ /[\]\)\(\|\[\\]/ ) {
1684                # suffix is not a regexp, but a real extension
1685                my $possible_file= $path.$base.'.'.$allowed_suffix;
1686                $kpse_result=`kpsewhich $possible_file`;
1687                if ($kpse_result) {
1688                   last;
1689                }
1690             }
1691          }
1692       } 
1693       
1694       # if kpsewhich could not find any file with an allowed suffix
1695       # assume that this reference is of a different type and skip it
1696       # quietly   
1697       if (!$kpse_result) {
1698          &report(9, "No suitable file found. Ignoring '$tag_contents'.");
1699          next;
1700       }
1701
1702       # expand '.' in kpsewhich output to the current path
1703       $kpse_result =~ s#^\./#$working_dir#;
1704       
1705       # remove trailing newline
1706       chomp($kpse_result);
1707
1708       # add file to the found file list if it is not already on it
1709       if( &array_index($kpse_result, @found_files) < 0 ) {
1710          push(@found_files, $kpse_result);
1711       }
1712    }
1713
1714    return @found_files;
1715 }
1716
1717 ### Build a list of all files which are included from the root file.
1718 # This function recurses, and is maybe smart enough to detect cycles.
1719 # Be sure to set REF_DOCS to the empty string prior to calling this.
1720 # parameter 1: tex file to start with
1721 # no return value
1722 # result is appended to global variable @REF_DOCS
1723
1724 sub get_file_list {
1725    my $source = $_[0];
1726    my @imports = ();
1727
1728    # This is the cycle avoidance logic.
1729    if ( &array_index($source, @REF_DOCS) < 0 ) {
1730       # Make sure the file can be accessed
1731       &check_file($source, "Included TeX file seems not to be available. Path problem?");
1732
1733       # Save the argument in the list of files.
1734       push(@REF_DOCS, $source);
1735
1736       # Get the list of files included by the argument.
1737       @imports=&identify_files($source, 'include|input', ['tex']);
1738
1739       # Recurse.
1740       foreach my $file (@imports) {
1741          if( ! ($file =~ /\.tex$/) ) { $file .= '.tex'; }
1742          &get_file_list($file);
1743       }
1744    }
1745 }
1746
1747 ### do the required modifications in the LaTeX preamble 
1748 # parameter 1: original preamble from the source file
1749 #              lines before \begin{document} tag (without this tag)
1750 # parameter 2: reference to hyperref parameter list
1751 # return value: adjusted preamble
1752
1753 sub adjust_preamble {
1754    my $preamble = $_[0];
1755    my $hyperref_params_ref = $_[1];
1756    my $extra_code;
1757    my $result;
1758    
1759    $_ = $preamble;
1760
1761    # protect pdflatex execution mode
1762    s/^(\\batchmode)$/% $1/m;
1763
1764    # insert a4paper in the documentclass when a4wide is used 
1765    # fixes problem that hyperref defaults to letter otherwise
1766    if ( /^[^%]*\\usepackage(\[widemargins\])?\{(a4|a4wide)\}/m ) {
1767       # check if package parameters with [] brackets are present
1768       if ( not s/^(\\documentclass\[.*?)\]/$1,a4paper]/m ) {
1769          s/^\\documentclass/$&\[a4paper\]/m;
1770       }
1771    }
1772
1773    ### collect additional LaTeX code
1774    
1775    $extra_code = "\n" . '\usepackage{pslatex}' . "\n";
1776
1777    if ( &param_value('thumbpdf') eq $YES ) {
1778       $extra_code .= '\usepackage{thumbpdf}' . "\n";
1779    } else {
1780       $extra_code .= "% no thumbpdf support\n";
1781    }
1782  
1783 #   if ( &param_value('ppower') eq $YES ) {
1784 #      $extra_code .= '\usepackage{mpmulti}' . "\n";
1785 #   } else {
1786 #      $extra_code .= "% no ppower support\n";
1787 #   }
1788
1789    if ( &param_value('authorindex') eq $YES ) {
1790       $extra_code .= '\usepackage[pages]{authorindex}' . "\n";
1791       $extra_code .= '\let\cite=\aicite' . "\n";
1792    } else {
1793       $extra_code .= "% no authorindex support\n";
1794    }
1795
1796    $extra_code .= '\makeatletter' . "\n";
1797    $extra_code .= '\usepackage[' . join(',', @$hyperref_params_ref)
1798                   . ']{hyperref}' . "\n";
1799    $extra_code .= '\makeatother' . "\n";
1800    
1801    ### insert the extra LaTeX code directly after documentclass
1802    m/^(\\documentclass)(\[[^]]*\])?(\{.*\})/m;
1803    return $` . $& . $extra_code . $';
1804 }
1805
1806 ### adjust all filenames in the LaTeX code to the tmp files
1807 # parameter 1: original LaTeX code from the source file
1808 # return value: adjusted code
1809
1810 sub adjust_filenames {
1811    my $code = $_[0];
1812    my $tmp_suffix = &param_value('tmp_base_suffix');
1813    my $result;
1814    
1815    $_ = $code;
1816
1817    # cut off the suffix of eps, ps, *.gz and pstex graphics
1818    s/((\\includegraphics)(\[[^]]*?\])?(\{[^}]+?))\.(e?ps|pstex|e?ps\.gz)\n?\}/$1}/sg;
1819
1820    # replace the suffix 'pstex_t' with 'pdf_t'
1821    s/(\\input\{[^}]+?\.)pstex_t\n?\}/$1pdf_t}/sg;
1822
1823    if ( &param_value('mtp_preamble') eq $NO ) {
1824       # cut off the suffix of mmp graphics
1825       s/(\\multiinclude(\[[^]]*?\])?\{[^}]+?)\.mmp\n?\}/$1}/sg;
1826    } else {
1827       # replace the suffix '.#' with '-mp.#'
1828       s/(\\includegraphics(\[[^]]*?\])?\{[^}]+?)\.(\d+?)\n?\}/$1$MTP_TMP_BASESUFFIX\.$3}/sg;
1829
1830       # replace the suffix '.#' with '-mp.#'
1831       s/(\\convertMPtoPDF(\[[^]]*?\])?\{[^}]+?)\.(\d+?)\n?\}/$1$MTP_TMP_BASESUFFIX\.$3}/sg;
1832
1833       # cut off optional suffix '.mmp' and append '-mp' in any case
1834       s/(\\multiinclude(\[[^]]*?\])?\{[^}]+?)(\.mmp)?\n?\}/$1$MTP_TMP_BASESUFFIX}/sg;
1835    }
1836
1837    # insert the tmp_suffix in tex filenames
1838    # I assume that files with no extension are TeX files as well; correct?
1839    s#(\\(input|include)\{([^}]*?/)?[^}/.]+?)((\.tex)?\n?\})#$1$tmp_suffix$4#sg;
1840
1841    return $_;
1842 }
1843
1844 ### Convert given tex file to the temp tex file we need for pdftex
1845 ### major task is to change the reference in the tex files to the
1846 ### corresponding tmp files
1847 # parameter 1: tex source file
1848 # parameter 2: tex tmp file
1849 # parameter 3: reference to hyperref parameter list or
1850 #              'undef' if preamble should not be changed
1851
1852 sub convert_tex2tmp {
1853    my $source = $_[0];
1854    my $target = $_[1];
1855    my $hyperref_params_ref = $_[2];
1856    my $contents;
1857    my $preamble;
1858    my $body;
1859    my $adjust_preamble = defined($hyperref_params_ref) ? $YES : $NO;
1860    my $read_err_msg = "Could not read original TeX document to generate temporary document";
1861    
1862    ### open source and target file
1863    &check_file($source, $read_err_msg . '.');
1864    open(SOURCE_FILE, "<$source") or
1865       &abort($read_err_msg . " ($source).");
1866
1867    ### read in the LaTeX source file
1868    $contents = "";
1869    while(<SOURCE_FILE>) {
1870       $contents .= $_;
1871    }
1872
1873    close SOURCE_FILE;
1874
1875    ### prepare the LaTeX code for PDF generation 
1876    if ( $adjust_preamble eq $YES ) {
1877       $contents =~ m/^ *\\begin\{document\} *$/m;
1878       $preamble = $`;
1879       $body = $&.$';
1880       $preamble = &adjust_preamble($preamble, $hyperref_params_ref);
1881       $preamble = &adjust_filenames($preamble);
1882    } else {
1883       $preamble = "";
1884       $body = $contents;
1885    }
1886    
1887    $body = &adjust_filenames($body);
1888       
1889    ### write the new LaTeX target file
1890    open(TARGET_FILE, ">$target") or
1891       &abort("Could not open file to write temporary TeX document ($target).");
1892
1893    print TARGET_FILE $preamble.$body;
1894    
1895    close TARGET_FILE;
1896 }
1897
1898 ### Convert the given EPS image to PDF
1899 # parameters $1: EPS image filename with absolute path
1900 # return value: none
1901
1902 sub convert_eps2pdf {
1903    my $image = $_[0];
1904    my $image_path;
1905    my $image_base;
1906    my $image_name;
1907    my $suffix;
1908    my $image_target;
1909    my $zipped = 0;
1910    my $dummy;
1911
1912    ($image_base,$image_path,$suffix) = fileparse($image, '\.eps', '\.ps', '\.pstex', '\.gz');
1913    if ($suffix eq "\.gz") {
1914         $zipped = 1;
1915         ($image_base,$dummy,$suffix) = fileparse($image_base, '\.eps', '\.ps', '\.pstex');
1916    }
1917    $image_name = $image_base . $suffix;
1918    $image_target = $image_path . $image_base . '.pdf';
1919    
1920    #### check if image file really exists
1921    #&check_file($image, "Could not convert referenced image.");
1922
1923    ### return if image directory is not writeable
1924    if (! -w $image_path) {
1925       &report(4, "WARNING - Image directory not writable: $image_path\n",
1926       " Skipping '$image_name', assume you have converted it manually.");
1927       return;
1928    }
1929
1930    if ( ! -f $image_target or -M $image_target > -M $image ) {
1931       &report(7, "Converting image $image_name to $image_target ...\n");
1932       if ($zipped > 0) {
1933          &system_command("gunzip -c $image | epstopdf -f -outfile=$image_target",
1934          $TRUE, 8, "epstopdf failed on $image_name");
1935       } else {
1936          &system_command("epstopdf -outfile=$image_target $image",
1937          $TRUE, 8, "epstopdf failed on $image_name");
1938       }
1939       if (&param_value('delete_pdf_images') eq $YES) {
1940          push(@TMPFILES, $image_target);
1941       }
1942    } else {
1943       &report(7, "$image_base.pdf newer than $image_name, conversion skipped...");
1944    }
1945 }
1946
1947 ### Convert the given PSTEX_T file to PDF_T
1948 # parameters 1: PSTEX_T filename with absolute path
1949 # return value: none
1950
1951 sub convert_pstex2pdf {
1952    my $pstex_file = $_[0];
1953    my $pstex_path;
1954    my $pstex_base;
1955    my $pstex_name;
1956    my $suffix;
1957    my $pstex_target;
1958    my @eps_images;
1959
1960    ($pstex_base,$pstex_path,$suffix) = fileparse($pstex_file, ('\.pstex_t'));
1961    $pstex_name = $pstex_base . $suffix;
1962    $pstex_target = $pstex_path . $pstex_base . '.pdf_t';
1963    
1964    #### check if image file really exists
1965    #&check_file($pstex_file, "Could not convert referenced file.");
1966
1967    ### return if directory is not writeable
1968    if (! -w $pstex_path) {
1969       &report(4, "WARNING - Directory not writable: $pstex_path\n",
1970       " Skipping '$pstex_name', assume you have converted it manually.");
1971       return;
1972    }
1973
1974    # descend into file
1975    &report(7, "Converting file $pstex_name ...\n");
1976
1977    # find included EPS image(s)
1978    @eps_images=&identify_files($pstex_file, 'includegraphics',
1979       ['pstex', 'pstex\.gz']);
1980
1981    # create .pdf_t file
1982    &convert_tex2tmp($pstex_file, $pstex_target, undef); 
1983
1984    # put tmp file in the tmp file list
1985    push(@TMPFILES, $pstex_target);
1986
1987    # convert image(s) to pdf
1988    foreach my $image (@eps_images) {
1989       &convert_eps2pdf($image);
1990    }
1991 }
1992
1993 ### Convert the given MP image to PDF
1994 # parameters $1: MP image filename with absolute path
1995 # return value: none
1996
1997 sub convert_mp2pdf {
1998    my $image = $_[0];
1999    my $image_path;
2000    my $image_base;
2001    my $image_name;
2002    my $suffix;
2003    my $image_target;
2004    my $image_src;
2005    my @mps_fig=();
2006    my $mp_fig;
2007
2008    ($image_base,$image_path,$suffix) = fileparse($image, '\.mp|\.mmp');
2009    $image_name = $image_base . $suffix;
2010    $image_src=$image_path . $image_base . $suffix;
2011
2012    @mps_fig= &grep_file($image_path.$image_name,'beginfig',$TRUE);
2013    $_=$mps_fig[0];
2014    /(\d)/;
2015    $mp_fig=$1;
2016    if (&param_value('mtp_preamble') eq $YES) {
2017      $image_target = $image_path . $image_base . $MTP_TMP_BASESUFFIX . '.' . $mp_fig;
2018      $image_name=$image_base.$MTP_TMP_BASESUFFIX.$suffix;
2019    } else {
2020      $image_target = $image_path . $image_base . '.' . $mp_fig;
2021    }
2022
2023    #### check if image file really exists
2024    #&check_file($image, "Could not convert referenced image.");
2025
2026    ### return if image directory is not writeable
2027    if (! -w $image_path) {
2028       &report(4, "$MYNAME: WARNING - Image directory not writable: $image_path\n",
2029          " Skipping '$image_name', assume you have converted it manually.");
2030       return;
2031    }
2032
2033    if ( ! -f $image_target 
2034       or  (-M $image_target > -M $image_src)
2035       or  ( ( &param_value('mtp_preamble') eq $YES)
2036       and (-M $image_target > -M $image_path.$MTP_PREAMBLE_FILENAME) ) ) {
2037       &report(7, "Converting image $image_name ...\n");
2038       my $working_dir = cwd."/";
2039       chdir("$image_path") or &abort("cannot cd to $image_path($!)");
2040       if ( &param_value('mtp_preamble') eq $YES ) {
2041          &modify_mp_file($image_base,$suffix);
2042       }
2043       &system_command("mpost $image_name",
2044          $TRUE, 8, "mpost failed on $image_name");
2045       chdir("$working_dir") or &abort("cannot cd to $working_dir($!)");
2046       if (&param_value('delete_pdf_images') eq $YES) {
2047          push(@TMPFILES, $image_target);
2048       }
2049    } else {
2050       if ( &param_value('mtp_preamble') eq $YES ) {
2051         &report(7, "$image_base$MTP_TMP_BASESUFFIX.$mp_fig newer than $image_base$suffix, conversion skipped...");
2052       } else {
2053         &report(7, "$image_base.$mp_fig newer than $image_base$suffix, conversion skipped...");
2054       }
2055    }
2056 }
2057
2058 ### Convert the given MP image to PDF
2059 # parameters $1: MP image filename with absolute path
2060 # return value: none
2061
2062 sub modify_mp_file {
2063    my $base=$_[0];
2064    my $suffix=$_[1];
2065    my $preamble_file=$MTP_PREAMBLE_FILENAME;
2066
2067    my $mp_source=$base.$suffix;
2068    my $mp_target=$base.$MTP_TMP_BASESUFFIX.$suffix;
2069
2070    ### open source and target file
2071    open(SOURCE_FILE, "<$mp_source") or
2072       &abort("Could not open $mp_source to add $preamble_file ($mp_source).");
2073
2074    open(TARGET_FILE, ">$mp_target") or
2075       &abort("Could not open $mp_target to add $preamble_file ($mp_source).");
2076
2077    open(PREAMBLE_FILE, "<$preamble_file") or
2078       &abort("Could not open $preamble_file to be added to metapost files ($mp_source).");
2079
2080    ### set target file as stdout
2081    select TARGET_FILE;
2082    print  'verbatimtex' . "\n";
2083    print  '%&latex' . "\n"; # This forces metapost to use latex in the compilation
2084    print  '\documentclass[english]{article}' . "\n"; # we have to decide if this sentence goes in preamble.cfg or here
2085                                                      # english must be added
2086                                                      # to preamble in order to
2087                                                      # make work mpost, why ???
2088    while(<PREAMBLE_FILE>) {
2089       print $_
2090    }
2091    print  '\begin{document}' . "\n"; # we have to decide if this sentence goes in preamble.cfg or here
2092    print  'etex' . "\n";
2093    while(<SOURCE_FILE>) {
2094       print $_
2095    }
2096    print  'verbatimtex' . "\n";
2097    print  '\end{document}' . "\n";
2098    print  'etex' . "\n";
2099
2100    ### set STDOUT as stdout again
2101    select STDOUT;
2102
2103    ### close files
2104    close SOURCE_FILE;
2105    close TARGET_FILE;
2106    close PREAMBLE_FILE;
2107
2108 }
2109
2110
2111 ### Convert included images to pdf
2112 # parameter 1: tex source file
2113 # no return value
2114
2115 sub convert_images {
2116    my $tex_source=$_[0];
2117    my @pstex_file_list;
2118    my @image_list;
2119    my @mp_image_list;
2120    my @mmp_image_list;
2121    my @major_suffixes;
2122    my $ignore_regexp;
2123
2124    &report(6, "\nConverting images referenced in $tex_source.");
2125
2126    ##### Get images of major type from the source file
2127    @major_suffixes = (@BITMAP_SUFFIXES, $PDF_ORIG_SUFFIX, @EPS_SUFFIXES);
2128    $ignore_regexp = '.('.join('|',@EPS_SUFFIXES).')';
2129    $ignore_regexp =~ s/\./\\./g;
2130
2131    &report(6, "\nScanning for major image types (".join(', ',@major_suffixes)."):");
2132    @image_list = &identify_files($tex_source,'includegraphics',
2133       \@major_suffixes, $ignore_regexp );
2134
2135    if ( @image_list > 0 ) {
2136       &report(7, join("\n", @image_list));
2137    } else {
2138       &report(7, "None.");
2139    }
2140
2141    ##### Get PSTEX_T files from the source file
2142    &report(6, "\nScanning for PSTEX_T files (.pstex_t):");
2143    @pstex_file_list=&identify_files($tex_source, 'input', ['pstex_t']);
2144    if ( @pstex_file_list > 0 ) {
2145       &report(7, join("\n", @pstex_file_list));
2146    } else {
2147       &report(7, "None.");
2148    }
2149
2150    ##### Get MP images from the source file
2151    &report(6, "\nScanning for MP images (.mp):");
2152    @mp_image_list=&identify_files($tex_source,
2153       'convertMPtoPDF|includegraphics',['mp','(\d+)'],'\.(\d+)');
2154    # FIXME
2155    # fixed for now by ignoring strange extension in identify_files
2156    #
2157    # the above could cause problems as identify_files is expecting a list of
2158    # real extensions and not of regexps
2159    # maybe the only way to fix this is to adjust identify_files to ignore
2160    # invalid extension when testing them with kpsewhich
2161    # ALTERNATIVE: design identify_files to use preffered_suffixes instead
2162    # of ignore_suffixes
2163  
2164    if ( @mp_image_list > 0 ) {
2165       &report(7, join("\n", @mp_image_list));
2166    } else {
2167       &report(7, "None.");
2168    }
2169
2170    ##### Get MMP images from the source file
2171    &report(6, "\nScanning for MMP images (.mmp):");
2172    @mmp_image_list=&identify_files($tex_source,'multiinclude',['mmp']);
2173    if ( @mmp_image_list > 0 ) {
2174       &report(7, join("\n", @mmp_image_list));
2175    } else {
2176       &report(7, "None.");
2177    }
2178
2179    ### Convert EPS images to PDF, copy pdf.orig image files to pdf,
2180    ### and simply ignore all other
2181    if ( @image_list > 0) {
2182       my $handled_suffixes;
2183
2184       &report(6, "\nProcessing images of major types:");
2185    
2186       # create one large regexp from suffixes and escape dots in them
2187       $handled_suffixes = '.('.join('|',(@EPS_SUFFIXES, $PDF_ORIG_SUFFIX)).')';
2188       $handled_suffixes =~ s/\./\\./g;
2189
2190       foreach my $image (@image_list) {
2191          my $path;
2192          my $base;
2193          my $suffix;
2194          ($base,$path,$suffix) = fileparse($image, $handled_suffixes);
2195          if (not $suffix) {
2196             &report(7, "No special handling required for image: $base$suffix");
2197          } elsif ($suffix eq ('.'.$PDF_ORIG_SUFFIX) ) {
2198             my $image_target = $path.$base.'.pdf';
2199                
2200             if ( ! -f $image_target or -M $image_target > -M $image ) {
2201                &report(7, "Create temporary PDF file from original: $base$suffix");
2202                copy($image, $image_target)
2203                   or &abort("Could not create tmp file: $!");
2204                if (&param_value('delete_pdf_images') eq $YES) {
2205                   push(@TMPFILES, $image_target);
2206                }
2207             } else {
2208                &report(7, "$base.pdf newer than $base$suffix, copy skipped ...");
2209             }
2210          } else {
2211             &convert_eps2pdf($image);
2212          }
2213       }
2214    }
2215
2216    ### Convert all PSTEX_T files to PDF_T
2217    if ( @pstex_file_list > 0 ) { 
2218       &report(6, "\nConverting pstex_t docs to pdf_t docs");
2219       foreach my $image (@pstex_file_list) {
2220          &convert_pstex2pdf($image);
2221       }
2222    }
2223
2224    ### Convert all MP images to PDF
2225    if ( @mp_image_list > 0) {
2226       &report(6, "\nConverting MP images to PDF");
2227       foreach my $image (@mp_image_list) {
2228          &convert_mp2pdf($image);
2229       }
2230    }
2231
2232    ### Convert all MMP images to PDF
2233    if ( @mmp_image_list > 0) {
2234       &report(6, "\nConverting MMP images to PDF");
2235       foreach my $image (@mmp_image_list) {
2236          &convert_mp2pdf($image);
2237       }
2238    }
2239
2240    &report(6, "\nFinished converting for ${tex_source}.");
2241 }
2242
2243 ### run pdflatex
2244 # parameter 1: LaTeX file without extension
2245 # parameter 2: log-file where the full out put is stored
2246 # return value: 0 - no errors (no rerun); 1 - errors (rerun required)
2247
2248 sub run_pdflatex {
2249    my $texfile=$_[0];
2250    my $logfile=$_[1];
2251    my @errors=();
2252    my $exit_status=0;
2253    my $extra_options=&param_value('pdftex_opts');
2254
2255    if( !defined($extra_options) or $extra_options eq $NIL ) {
2256       $extra_options = "";
2257    }
2258    
2259    &report(7, "Running pdflatex. This may take a while.\n");
2260    system("pdflatex --interaction nonstopmode $extra_options $texfile > $logfile 2>&1");
2261    $exit_status=$?;
2262    &report(7, "Pdflatex finished. Errors:");
2263
2264    ### extract all errors and warnings from the log file
2265    @errors = &grep_file($logfile, '(Emergency stop|Error|Warning).*:');
2266
2267    ### make sure thumbpdf package does not spoil rerun detection
2268    ### as it will be processed very last
2269    if(grep(/Package thumbpdf/, @errors) == @errors) { @errors=(); }
2270    
2271    if ( @errors != 0 or $exit_status != 0 ) {
2272       if ( grep(/Emergency stop/, @errors) != 0 ) {
2273          &report(2, &file_tail($logfile,10));
2274          &report(2, "\nSee $logfile for details.");
2275          &abort("Fatal error occured. I am lost.");
2276       }
2277       if( @errors != 0 ) {
2278          &report(8, @errors);
2279       } else {
2280          &report(8, &file_tail($logfile,10));
2281       }
2282       &report(7, "\nSee $logfile for details.");
2283       return $FALSE;
2284    } else {
2285       &report(7, "None detected (log file: $logfile).");
2286       return $TRUE;
2287    }
2288 }
2289
2290 #### run bibtex if BIBTEX=$YES or a bibliography tag is found
2291 # included tex files are not parsed for a bibliography
2292 # parameter 1: filename of the aux file without .aux suffix
2293 # parameter 2: log-file where the full out put is stored
2294
2295 sub handle_bibtex {
2296    my $auxfile=$_[0];
2297    my $logfile=$_[1];
2298    my $run_bibtex=$FALSE;
2299    my $bibtex_param=&param_value('bibtex');
2300    
2301    if ( $bibtex_param eq $YES ) {
2302       $run_bibtex=$TRUE;
2303       &report(7, "BibTeX parameter set to '$YES':");
2304    } else {
2305       &report(7, "Checking for BibTeX bibliography in main document: ");
2306       if( &grep_file($auxfile.'.tex', '^[^%]*\\\\bibliography{') != 0) {
2307          $run_bibtex=$TRUE;
2308          &report(7, "Bibliography detected.");
2309       } else {
2310          if ( @REF_DOCS > 0 ) {
2311             &report(7, "Checking for BibTeX bibliography in included documents:");
2312             foreach my $file (@REF_DOCS) {
2313                if( &grep_file($file, '^[^%]*\\\\bibliography{') != 0) {
2314                    $run_bibtex=$TRUE;
2315                    &report(7, "Bibliography detected.");
2316                } else {
2317                  &report(7, "No bibliography detected in $file.");
2318                }
2319             }
2320          } else {
2321            &report(7, "No bibliography detected.");
2322         }
2323       }
2324    }
2325
2326    if ( $run_bibtex ) {
2327       my @errors=();
2328       my $exit_status=0;
2329
2330       &report(7, "Running bibtex. This may take a while.\n");
2331       system "bibtex $auxfile > $logfile";
2332       $exit_status=$?;
2333       &report(7, "Bibtex finished. Errors:");
2334
2335       ### extract all errors and warnings from the log file
2336       @errors=&grep_file($logfile, 'error message');
2337
2338       if ( @errors != 0 or $exit_status != 0 ) {
2339          &report(4, &file_tail($logfile));
2340          &report(4, "\nYou can switch off BibTeX support by setting the bibtex parameter accordingly.");
2341       } else {
2342          &report(7, "None detected (log file: $logfile).");
2343       }
2344    }
2345 }
2346
2347 #### run bibtex on file.gls if BIBTEX=$YES or a bibliography tag is found
2348 # included tex files are not parsed for a bibliography
2349 # parameter 1: filename of the aux file without .aux suffix
2350 # parameter 2: log-file where the full out put is stored
2351
2352 sub handle_gloss {
2353    my $auxfile=$_[0];
2354    my $logfile=$_[1];
2355    my $run_gloss=$FALSE;
2356    my $gloss_param=&param_value('gloss');
2357    my $glsfile=$auxfile.'.gls';
2358    
2359    if ( $gloss_param eq $YES ) {
2360       $run_gloss=$TRUE;
2361       &report(7, "Gloss parameter set to '$YES':");
2362    } else {
2363       &report(7, "Checking for Gloss bibliography in main document: ");
2364       if( &grep_file($auxfile.'.tex', '^[^%]*\\\\printgloss{') != 0) {
2365          $run_gloss=$TRUE;
2366          &report(7, "Gloss bibliography detected.");
2367       } else {
2368         if ( @REF_DOCS > 0 ) {
2369            &report(7, "Checking for Gloss bibliography in included documents:");
2370            foreach my $file (@REF_DOCS) {
2371               if( &grep_file($file, '^[^%]*\\\\printgloss') != 0) {
2372                   $run_gloss=$TRUE;
2373                   &report(7, "Gloss bibliography detected.");
2374               } else {
2375                 &report(7, "No gloss database detected in $file.");
2376               }
2377            }
2378         } else {
2379           &report(7, "No gloss database detected.");
2380         }
2381       }
2382    }
2383    if ( $run_gloss ) {
2384       my @errors=();
2385       my $exit_status=0;
2386
2387       &report(7, "Running bibtex on $glsfile. This may take a while.\n");
2388       system "bibtex $glsfile > $logfile 2>&1";
2389       $exit_status=$?;
2390       &report(7, "Bibtex finished. Errors:");
2391
2392       ### extract all errors and warnings from the log file
2393       @errors=&grep_file($logfile, 'error message');
2394
2395       if ( @errors != 0 or $exit_status != 0 ) {
2396          &report(4, &file_tail($logfile));
2397          &report(4, "\nYou can switch off Gloss support by setting the gloss parameter accordingly.");
2398       } else {
2399          &report(7, "None detected (log file: $logfile).");
2400       }
2401    }
2402 }
2403
2404 #### run thumbpdf command to make thumbnails
2405 # more informations: /usr/share/texmf/doc/pdftex/thumbpdf/readme.txt
2406 # parameter 1: LaTeX file without extension
2407 # parameter 2: log-file where the full out put is stored
2408
2409 sub run_thumbpdf {
2410    my $texfile=$_[0];
2411    my $logfile=$_[1];
2412    my $exit_status=0;
2413
2414    &report(7, "\nCreating thumbnails with 'thumbpdf'\n");
2415    &system_command("thumbpdf $texfile", $FALSE, 8,
2416       "thumbpdf failed.\n"
2417       ."I will continue, but maybe there will not be thumbs in the PDF doc.");
2418
2419    if ( -f 'thumbpdf.log' ) {
2420       move('thumbpdf.log', $logfile);
2421       &report(7, "\nSee $logfile for details.");
2422    }
2423
2424    ### store possible tmp files
2425    push(@TMPFILES, glob 'thumb???.png');
2426    push(@TMPFILES, 'thumbpdf.pdf');
2427    push(@TMPFILES, 'thumbdta.tex'); 
2428    push(@TMPFILES, $texfile.'.tpt');
2429 }
2430
2431
2432 #### run ppower command to make presentations
2433 # more informations: 
2434 # parameter 1: LaTeX file without extension
2435 # parameter 2: log-file where the full out put is stored
2436
2437 sub run_ppower {
2438    my $texfile=$_[0];
2439    my $logfile=$_[1];
2440    my $exit_status=0;
2441    my $infile;
2442    my $outfile;
2443    my $texfile_base;
2444    my $texfile_path;
2445    my $texfile_suffix;
2446
2447    ##### Getting document name, suffix and path
2448    ($texfile_base,$texfile_path,$texfile_suffix) = fileparse($texfile,&param_value('tmp_base_suffix'));
2449
2450    $infile=$texfile_base.'.pdf';
2451    $outfile=$texfile_base.'_p4.pdf';
2452
2453    &report(7, "\nPostprocessing PDF file with 'ppower'\n");
2454    if(&system_command("ppower $infile $outfile", $FALSE, 8,
2455       "ppower failed.\nI will continue, "
2456       ."but maybe there will not be pause effects in the PDF doc.")) {
2457       &report(7, "\nThe postprocessed pdf file is: $outfile\n");
2458    }
2459
2460    if ( -f 'ppower.log' ) {
2461       move('ppower.log', $logfile);
2462       &report(7, "See $logfile for details.");
2463    }
2464 }
2465
2466 #### run authorindex command to obtain an author index
2467 # more informations: 
2468 # parameter 1: LaTeX file without extension
2469 # parameter 2: log-file where the full out put is stored
2470
2471 sub run_authorindex {
2472    my $texfile=$_[0];
2473    my $logfile=$_[1];
2474    my $exit_status=0;
2475
2476    &report(7, "\nProcessing file with 'authorindex'\n");
2477    &system_command("authorindex $texfile", $FALSE, 8,
2478       "authorindex failed.\nI will continue, "
2479       ."but maybe there will not be an author index in the PDF doc.");
2480
2481    if ( -f 'authorindex.log' ) {
2482       move('authorindex.log', $logfile);
2483       &report(7, "\nSee $logfile for details.");
2484    }
2485
2486 }
2487
2488
2489 ##### read and analyse configuration and options and adjust basic variables
2490 ##### accordingly
2491 #### The following sources are considered (last value overrides previous)
2492 ##   1. general configuration (global variables in the script)
2493 ##   2. private configuration (in user's RC file)
2494 ##   3. command line options
2495 # parameters: none 
2496 # return value: given document argument
2497
2498 sub adjust_configuration {
2499    my $valid_rcfile = $FALSE;
2500    my %opt_specs =();
2501    
2502    ### Check number of arguments
2503    if ( @ARGV == 0 ) {
2504       &report(1, "\nI need at least one argument!");
2505       &print_usage;
2506       exit 1;
2507    }
2508    
2509    ##### command line options and private configuration files handling
2510    
2511    ### set parameters from rc file
2512    if ( -f $RC_FILENAME ) {
2513       my $rcfile_version;
2514       $rcfile_version = &read_configuration($RC_FILENAME);
2515       if( $rcfile_version == $MYRCFILE_VERSION ) {
2516          $valid_rcfile = $TRUE;
2517       } elsif ( $rcfile_version == 0 ) {
2518          &report(4, "Could not determine version of read RC file.");
2519       } else {
2520          &report(4, "Version of read RC file ($rcfile_version) and ",
2521             "this script ($MYRCFILE_VERSION) differs.");
2522       }
2523    }
2524    
2525    ### scan parameters 
2526    foreach (keys %PARAMETER_LIST) {
2527       $opt_specs{&option_specifier($_)} = \&handle_option;
2528    }
2529    if(! GetOptions(%opt_specs)) {
2530       &print_usage;
2531       &abort("An error occured while processing command line options");
2532    }
2533
2534    if( ! $valid_rcfile ) {
2535       &report(3,"No valid configuration file found. Please run '$MYNAME "
2536          ."--configure'.\nUsing default values for missing parameters in this "
2537          ."session.");
2538    }
2539
2540    ### As the configuration process is done now, it is time to set the
2541    #   global configuration flag
2542    $CONFIGURED = $TRUE;
2543    
2544    #### do some test in order to secure as good as possible that we will
2545    #### succeed before to much work was done and maybe some data as damaged
2546
2547    ### make sure that tmp_base_suffix is not empty
2548    if ( &param_value('tmp_base_suffix') eq "" ) {
2549       &report(2, "\nCAUTION: Empty tmp_base_suffix would destroy the original files!");
2550       &abort("Parameter tmp_base_suffix is not set.");
2551    }
2552    
2553    ##### check for required commands
2554    if (&param_value('check_commands') ne $NO ) {
2555       &check_commands;
2556    }
2557
2558    ### Check number of arguments
2559    if ( @ARGV != 1 ) {
2560       &report(1, "\nWrong number of arguments. I need exactly one file.");
2561       &print_usage;
2562       exit 1;
2563    }
2564    
2565    return $ARGV[0];
2566 }
2567
2568 #### prepare the logdir for the log files of the various called appplications
2569
2570 sub prepare_logdir {
2571    my $log_dir= &param_value('logdir');
2572    my $my_new_log;
2573
2574    ##### Preparing the LOGDIR
2575    if (! &check_dir($log_dir, "Could not create log directory", $YES)) {
2576       &abort("Please, set a different path and restart");
2577    }
2578
2579    # make sure there is a slash at the end of the path
2580    $log_dir .= '/' if( ! ($log_dir =~ m#/$#) );
2581    
2582    if( <$log_dir/*.log> and &param_value('clean_logs') eq $YES ) { 
2583       &report(6, "\nRemoving old log files ($log_dir).");
2584       unlink (<$log_dir/pdflatex-*.log>, <$log_dir/bibtex-*.log>,
2585          <$log_dir/gloss-*.log>, <$log_dir/thumbpdf-*.log>,
2586          <$log_dir/ppower-*.log>, <$log_dir/authorindex-*.log>,
2587          <$log_dir/tex2pdf-*.log>);
2588    } else {
2589       &report(6, "\nAll log files will be stored in ($log_dir).");
2590    }
2591
2592    ### move my pre-configuration log file to specified log directory
2593    $my_new_log = "$log_dir/tex2pdf-$$.log";
2594    if ( move($MYLOGFILE, $my_new_log) ) {
2595       $MYLOGFILE = $my_new_log;
2596    } else {
2597       &report(3, "Could not move '$MYLOGFILE' to logdir: $!");
2598    }
2599 }
2600
2601 ##### analyse document argument
2602 #### process the one and only argument (besides the options) which specifies
2603 #### which LaTeX document the user wants to translate to PDF
2604 #### a lyx file will be translated to LaTeX first
2605 # parameter 1: argument
2606
2607 sub process_doc_argument {
2608    my $argument = $_[0];
2609    my $doc_base;
2610    my $doc_path;
2611    my $arg_suffix;
2612    
2613    ##### Getting document name, suffix and path
2614    ($doc_base,$doc_path,$arg_suffix) = fileparse($argument, ('\.tex', '\.lyx'));
2615
2616    if (! defined($arg_suffix) or $arg_suffix eq "") {
2617       $arg_suffix = '.tex';
2618    }
2619    
2620    ###### change working directory to document directory
2621    if ( $doc_path ne "" ) {
2622       chdir $doc_path;
2623    }
2624    
2625    ###### make DOCPATH an absolute path
2626    $doc_path = cwd.'/';
2627    
2628    ###### Cut off suffix and do lyx or tex specific stuff
2629    if ( $arg_suffix eq '.lyx' ) {
2630       # Lyx document argument: generate Latex document if required
2631       &generate_tex_file($doc_base.'.lyx', $doc_base.'.tex');
2632    } else {
2633       # LaTeX document argument: check access to given LaTeX document
2634       &check_file($doc_base.'.tex', "Cannot read the specified LaTeX document!");
2635    }
2636    
2637    return $doc_path.$doc_base.'.tex';
2638 }
2639
2640 #### handle the dir of the input path if the document has one and
2641 # parameter 1: main tex doc
2642 # return value: absolute input path
2643
2644 sub process_inputpath {
2645    my $texdoc = $_[0];
2646    my $doc_base;
2647    my $doc_path;
2648    my $doc_suffix;
2649    my $input_path;
2650    my @matches;
2651    
2652    ### Maybe the user has given us a different inputpath
2653    $input_path = &param_value('input_path');
2654    if(defined($input_path) and $input_path ne "") {
2655       &report(6, "Setting input path to specified directory: $input_path");
2656       
2657       &report(7, "Change working directory to input path.");
2658       chdir $input_path;
2659       
2660       return $input_path;
2661    }
2662
2663    ##### Getting document name, suffix and path
2664    ($doc_base,$doc_path,$doc_suffix) = fileparse($texdoc, ('\.tex'));
2665
2666    ###### change working directory to input_path if set
2667    # When the files' path (images, included documents, etc.) in your document is
2668    # relative to another directory than the PASSED document's directory.
2669    # This is useful when the calling application (e.g. LyX) generates a
2670    # temporary
2671    # TeX file and calls the tex2pdf with it instead of the original file.
2672    
2673    @matches=&extract_tag_contents($texdoc, 'def\\\\input@path');
2674    $input_path=$matches[0];
2675    
2676    ## check if input_path is ok
2677    if ($input_path) {
2678       &report(7, "Found an input path in the latex document: $input_path");
2679       if( &check_dir($input_path, 'The retrieved input@path seems not to be valid.', $NO)) {
2680          &set_param_value('input_path', $input_path);
2681          &report(7, "Change working directory to input path.");
2682          chdir $input_path;
2683       } else {
2684          &abort ('I am lost.');
2685       }
2686    } else {
2687       &report(4, "No input path in the latex document found.");
2688       &report(7, "Resources are expected to be relative to document's location: $doc_path");
2689          $input_path=$doc_path;
2690    }
2691    
2692    return $input_path;
2693 }
2694
2695 #### set the working dir to the input path if the document has one and
2696 #### and determine the path for the result
2697 # parameter 1: main tex doc
2698 # parameter 2: absolute input path
2699 # return value: absolute path were the resulting pdf doc should be stored
2700
2701 sub get_target_name {
2702    my $texdoc = $_[0];
2703    my $input_path=$_[1];
2704
2705    my $doc_base;
2706    my $doc_path;
2707    my $doc_suffix;
2708    my $destination;
2709    my $pdf_path;
2710    
2711    ##### Getting document name, suffix and path
2712    ($doc_base,$doc_path,$doc_suffix) = fileparse($texdoc, ('\.tex'));
2713  
2714    ##### set the directory where the final pdf will be stored
2715    $destination=&param_value('destination');
2716    $pdf_path=undef;
2717    
2718    if ($destination eq 'custom' ) {
2719       $pdf_path=&param_value('custom_path');
2720    } elsif ($destination eq 'input') {
2721       $pdf_path=$input_path;
2722    } else {
2723       $pdf_path=$doc_path;
2724    }
2725
2726    if( ! defined($pdf_path) or $pdf_path eq "" or ! &check_dir($pdf_path,
2727       'The specified destination directory for the final PDF documents is not valid.', $NO)) {
2728       &report(7, "Using document's instead of destination path: $doc_path");
2729       $pdf_path=$doc_path;
2730    }
2731
2732    # make sure there is a slash at the end of the path
2733    $pdf_path .= '/' if( ! ($pdf_path =~ m#/$#) );
2734    
2735    return $pdf_path.$doc_base.'.pdf';
2736 }
2737
2738 ### generate hyperref parameters from given settings
2739 # parameter 1: main tex doc
2740 # return_value: result
2741
2742 sub generate_hyperref_params {
2743    my $texdoc = $_[0];
2744    my $para;
2745    my @params = ('pdftex');
2746
2747    ##### Set title and author from main LaTeX document or parameters
2748    foreach my $info (('title', 'author')) {
2749       my $value;
2750
2751       $value=&param_value("$info");
2752       if (! defined($value) ) {
2753          my @matches=&extract_tag_contents($texdoc, $info);
2754          $value= $matches[0];
2755          if (! defined($value) ) {
2756             &report(4, "\nWARNING: Could not identify document's $info correctly.");
2757             &report(7, "Maybe you have used a LaTeX tag inside the $info which confuses me.\n",
2758                "Adjust the $info of the LaTeX file in order to avoid the problem or\n",
2759                "you could set the $info parameter manually.");
2760             $value= &param_value("default_$info");
2761             &report(7, "Using default-$info: $value");
2762          }
2763       }
2764       if (! defined($value) or $value eq $NIL ) {
2765          &report(7, "$info field set to $NIL - no value will be passed.");
2766       } else {
2767          &report(7, "Document's $info: $value");
2768          push(@params, "pdf$info={$value}");
2769       }
2770    }
2771    
2772    $para=&param_value('paper');
2773    if ( $para ne $NIL ) { push(@params, $para); }
2774
2775    $para=&param_value('link_toc_page'); 
2776    if ( $para eq $YES ) { push(@params, 'linktocpage'); }
2777
2778    $para=&param_value('colorlinks');
2779    if ( $para ne $NIL ) {
2780       $para= $para eq $YES ? 'true' : 'false';
2781       push(@params, "colorlinks=$para");
2782    }
2783
2784    if ( $para ne 'false' ) {
2785       foreach (('linkcolor', 'pagecolor', 'urlcolor', 'citecolor')) {
2786          $para=&param_value($_);
2787          if ( $para ne $NIL ) { push(@params, "$_={$para}"); }
2788       }
2789    }
2790
2791    $para=&param_value('hyperref_args');
2792    if(defined($para) and $para ne "" and $para ne $NIL) {
2793       push(@params, $para);
2794    }
2795    
2796    return @params;
2797 }
2798
2799 #### Prepare the main document and all referenced ones for the generation
2800 #### of the PDF document (including referenced images)
2801 # parameter 1: top level tex document
2802 # parameter 2: parameter list of hyperref parameters
2803
2804 sub prepare_documents {
2805    my ($main_tex_doc, $input_path, @hyperref_params) = @_;
2806    @REF_DOCS=();
2807
2808    ## get a name for the tmp tex file
2809    my $main_tmp_doc = &reserve_tmp_texname($main_tex_doc, $input_path);
2810
2811    ## Get the list of imported files from the tex file
2812    &get_file_list($main_tex_doc);
2813    
2814    ## remove main file from list (first element; needs special handling)
2815    shift @REF_DOCS;
2816    
2817    ## tell user about the identified refereneced docs
2818    if ( @REF_DOCS > 0 ) {
2819       &report(7, "\nFound the following referenced TeX files:");
2820       foreach my $file (@REF_DOCS) {
2821          &report(7, ">>>>> $file");
2822       }
2823    } else {
2824       &report(7, "\nFound no referenced TeX files.");
2825    }
2826    
2827    ##### Generate adjusted temp tex files and convert all their images
2828    ## main doc
2829    &report(6, "\nGenerating main temporary LaTeX document: $main_tmp_doc");
2830    &convert_tex2tmp($main_tex_doc, $main_tmp_doc, \@hyperref_params);
2831    &convert_images($main_tex_doc);
2832    
2833    ## referenced docs
2834    foreach my $file (@REF_DOCS) {
2835       my $tmp_file = &reserve_tmp_texname($file);
2836    
2837       ### Insert pdf conversation tags in tex file and write it to tmp_file
2838       &report(7, "\nGenerating temporary LaTeX document: $tmp_file");
2839       &convert_tex2tmp($file, $tmp_file, undef);
2840       &convert_images($file);
2841    }
2842
2843    return $main_tmp_doc;
2844 }
2845
2846 ##### Generate the final PDF document
2847 # parameter 1: filename of the source LaTeX document (with extension)
2848
2849 sub generate_pdf_doc {
2850    my $source = $_[0];
2851    my $runno=1;
2852    my $rerun=$TRUE;
2853    my $doc;
2854    my $pdf_doc;
2855    my $base;
2856    my $path;
2857    my $suffix;
2858
2859    my $max_run_no= &param_value('maxrun');
2860    my $min_run_no= &param_value('minrun');
2861    my $log_dir= &param_value('logdir');
2862    $log_dir .= '/' if( ! ($log_dir =~ m#/$#) );
2863    my $makeindex_options=&param_value('makeindex_opts');
2864    
2865    # setting the log files for the output of pdflatex, bibtex, gloss,
2866    # thumbpdf, ppower and authorindex
2867    my $pdflog_base = $log_dir."pdflatex-$$-";
2868    my $bibtex_log = $log_dir."bibtex-$$.log";
2869    my $gloss_log = $log_dir."gloss-$$.log";
2870    my $thumbpdf_log = $log_dir."thumbpdf-$$.log";
2871    my $ppower_log = $log_dir."ppower-$$.log";
2872    my $authorindex_log = $log_dir."authorindex-$$.log";
2873
2874    ##### Getting document name, suffix and path
2875    ($base,$path,$suffix) = fileparse($source, ('\.tex'));
2876    $doc = $path.$base;
2877    $pdf_doc = $base.'.pdf';
2878
2879    ### run pdflatex until no more errors are reported (max MAXRUNNO)
2880    while ( $rerun and $runno <= $max_run_no )
2881    {
2882       &report(6, "\n************ Pdflatex run no. $runno *************");
2883       if ( &run_pdflatex($doc, $pdflog_base.$runno.'.log') == $TRUE 
2884          and ( $min_run_no <= $runno )) {
2885          # no errors detected and min. no. of runs are done
2886          $rerun=$FALSE;
2887       } else {
2888          # errors appeared or max run no. has not been reached
2889          $rerun=$TRUE;
2890       }
2891    
2892       ### Execute BibTeX after first run if set (and required)
2893       if ( $runno == 1 and &param_value('bibtex') ne $NO ) {
2894          &report(6, "\n****************** BibTeX handling ***********************");
2895          &handle_bibtex($doc, $bibtex_log);
2896       }
2897
2898       ### Execute BibTeX on file.gls after first run if set (and required)
2899       if ( $runno == 1 and &param_value('gloss') ne $NO ) {
2900          &report(6, "\n****************** Gloss handling ***********************");
2901          &handle_gloss($doc, $gloss_log);
2902       }
2903
2904       ### generated index file exists
2905       if ( $runno == 1 and -f $doc.'.idx' and &param_value('force_index') ne $NO ) {
2906          if( !defined($makeindex_options) or $makeindex_options eq $NIL ) {
2907             $makeindex_options = "";
2908          }
2909          &report(6, "\n****************** Extra index generation ***************");
2910          &report(7, "Document seems to have an index. Generating ...\n");
2911          &system_command("makeindex $makeindex_options $doc.idx", $FALSE, 8,
2912             "makeindex failed.\nI will continue, "
2913             ."but maybe there will not be an index in the PDF doc.");
2914       }
2915
2916       $runno += 1;
2917    }
2918
2919    $rerun = $FALSE;
2920
2921    ### if the authorindex option is switched on then run authorindex
2922    if ( &param_value('authorindex') eq $YES ) {
2923       &report(6, "\n****************** authorindex generation *****************");
2924       &run_authorindex($doc, $authorindex_log);
2925    }
2926    
2927    ### generated index file exists
2928    if ( -f $doc.'.idx' and &param_value('force_index') ne $NO ) {
2929       if( !defined($makeindex_options) or $makeindex_options eq $NIL ) {
2930          $makeindex_options = "";
2931       }
2932       &report(6, "\n****************** Extra index generation ***************");
2933       &report(7, "Document seems to have an index. Generating ...\n");
2934       &system_command("makeindex $makeindex_options $doc.idx", $FALSE, 8,
2935          "makeindex failed.\nI will continue, "
2936          ."but maybe there will not be an index in the PDF doc.");
2937       $rerun=$TRUE;
2938    }
2939    
2940    ### if the thumbpdf option is switched on then make thumbnails
2941    if ( &param_value('thumbpdf') eq $YES ) {
2942          &report(6, "\n****************** Thumbnail generation *****************");
2943       &run_thumbpdf($doc, $thumbpdf_log);
2944       $rerun=$TRUE;
2945    }
2946
2947    ### One final pdflatex run if requested
2948    if ( $rerun ) {
2949       &report(6, "\n************ One final pdflatex run no. $runno *************");
2950       &run_pdflatex($doc, $pdflog_base.$runno.'.log');
2951    }
2952
2953    ### if the ppower option is switched on then run ppower
2954    if ( &param_value('ppower') eq $YES ) {
2955       &report(6, "\n****************** ppower postprocess *****************");
2956       &run_ppower($doc, $ppower_log);
2957    }
2958
2959    if ( ! -f $pdf_doc ) {
2960       &abort("\nThe new PDF file could not be generated: ".$pdf_doc);
2961    }
2962
2963    return $pdf_doc;
2964 }
2965    
2966 ################## Lift off !!!! (main part) ##################
2967
2968 my $texdoc;
2969 my $doc_argument;
2970 my $input_path;
2971 my $target_name;
2972 my @hyperref_params;
2973 my $new_pdf_doc;
2974 my $tmp_tex_doc;
2975
2976 &report(5, "\nScript starts ($MYRELEASE)");
2977
2978 ##### read and analyse configuration and options and adjust basic variables
2979 ##### accordingly
2980 ##### write RC file on config request
2981 #### use the finished configuration to get all further settings before we
2982 #### actually start doing something
2983
2984 &report(5, "\nProcessing given parameters and arguments.");
2985 $doc_argument = &adjust_configuration;
2986
2987 #### prepare the script to write some information to specified log files
2988
2989 &report(5, "\nPreparing directory for log files.");
2990 &prepare_logdir;
2991
2992 #### process the one and only argument (besides the options) which specifies
2993 #### which LaTeX document the user wants to translate to PDF
2994 #### a lyx file will be translated to LaTeX first
2995
2996 &report(5, "\nAnalysing your document argument.");
2997 $texdoc = &process_doc_argument($doc_argument);
2998
2999 #### we would like to get some more information from the actual
3000 #### main LaTeX document before we really start
3001 #### parse the document and try to get the info
3002
3003 ## translate hyperref settings to the actual package parameters 
3004    
3005 &report(5, "\nSetting up parameters for hyperref.");
3006 @hyperref_params = &generate_hyperref_params($texdoc);
3007
3008 ## set the working dir to the input path if the document has one and
3009
3010 &report(5, "\nProcessing input path for main tex document.");
3011 $input_path = &process_inputpath($texdoc);
3012
3013 ## determine the name for the result
3014
3015 &report(5, "\nSetting the correct name for the result.");
3016 $target_name = &get_target_name($texdoc, $input_path);
3017
3018 ## as much as possible is prepared in advance at this point
3019 ## so hopefully we will succeed in generating the PDF document
3020
3021 ##### real work starts NOW
3022
3023 ##### Generate adjusted temp tex files and convert all their images
3024
3025 &report(5, "\nPreparing all documents and images.");
3026 $tmp_tex_doc = &prepare_documents($texdoc, $input_path, @hyperref_params);
3027
3028 ##### Generate the final PDF document
3029
3030 &report(5, "\nProcessing the actual generation of the PDF document.");
3031 $new_pdf_doc = &generate_pdf_doc($tmp_tex_doc);
3032
3033 ##### Finalize
3034 move($new_pdf_doc, $target_name) or &abort("Could not move PDF file to final destination: $!");
3035
3036 if ( &param_value('debug') eq $NO ) {
3037    &clean_up;
3038 } else {
3039    &print_temp_files;
3040 }
3041
3042 &report(5, "\nThe new pdf file is: $target_name\n");
3043