View Javadoc
1   /*
2    * The akquinet maven-latex-plugin project
3    *
4    * Copyright (c) 2011 by akquinet tech@spree GmbH
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package eu.simuline.m2latex.core;
20  
21  import eu.simuline.m2latex.mojo.CfgLatexMojo;
22  import eu.simuline.m2latex.mojo.GraphicsMojo;
23  import eu.simuline.m2latex.mojo.ClearMojo;
24  import eu.simuline.m2latex.mojo.ChkMojo;
25  
26  import eu.simuline.m2latex.antTask.LatexCfgTask;
27  import eu.simuline.m2latex.antTask.LatexClrTask;
28  
29  import java.io.File;
30  import java.io.FileFilter;
31  
32  import java.util.Collection;
33  import java.util.Arrays;
34  
35  // idea: use latex2rtf and unoconv
36  // idea: targets for latex2html, latex2man, latex2png and many more. 
37  
38  /**
39   * The latex processor creates various output from latex sources 
40   * including also preprocessing of graphic files in several formats. 
41   * This is the core class of this piece of software. 
42   * The main method is {@link #create()} which is executed by the ant task 
43   * and by the maven plugin given by {@link CfgLatexMojo}. 
44   * Also important are {@link #clearAll()} which is executed by 
45   * the maven plugin given by {@link ClearMojo}. 
46   * also {@link #processGraphics()} which is executed by 
47   * the maven plugin given by {@link GraphicsMojo} 
48   * which is helpful for information development. 
49   * <p>
50   * This class delegates preprocessing of the graphic files, 
51   * selection of the latex main files and deleting their targets 
52   * to {@link LatexPreProcessor}. 
53   * Processing of the latex main files is done in {@link #create()} 
54   * according to the target(s) given by the parameters. 
55   * The elements of the enumeration {@link Target} use methods 
56   * {@link #processLatex2rtf(File)}, {@link #processLatex2dvi(File)}, 
57   * {@link #processLatex2pdf(File)}, 
58   * {@link #processLatex2html(File)}, {@link #processLatex2odt(File)}, 
59   * {@link #processLatex2docx(File)} and {@link #processLatex2txt(File)}. 
60   */
61  public class LatexProcessor extends AbstractLatexProcessor {
62  
63      static final String PATTERN_NEED_BIBTEX_RUN = "^\\\\bibdata";
64  
65      // Note that two \\ represent a single \ in the string. 
66      // Thus \\\\ represents '\\' in the pattern, 
67      // which in turn represents a single \. 
68      static final String PATTERN_OUFULL_HVBOX = 
69  	"^(Ov|Und)erfull \\\\[hv]box \\(";
70  
71  
72      // LaTeX (notably, .tex is not needed )
73      final static String SUFFIX_TOC = ".toc";
74      final static String SUFFIX_LOF = ".lof";
75      final static String SUFFIX_LOT = ".lot";
76      final static String SUFFIX_AUX = ".aux";
77      final static String SUFFIX_DVI = ".dvi";
78  
79      // bibtex 
80      final static String SUFFIX_BLG = ".blg";
81      final static String SUFFIX_BBL = ".bbl";
82  
83      // makeindex for index 
84      // unsorted and not unified index created by latex 
85      final static String SUFFIX_IDX = ".idx";
86      // sorted and unified index created by makeindex 
87      final static String SUFFIX_IND = ".ind";
88      // log file created by makeindex 
89      final static String SUFFIX_ILG = ".ilg";
90  
91      // unsorted and not unified glossary created by latex 
92      final static String SUFFIX_GLO = ".glo";
93      // sorted and unified glossary created by makeindex 
94      final static String SUFFIX_GLS = ".gls";
95      // logging file for makeindex used with glossaries 
96      final static String SUFFIX_GLG = ".glg";
97  
98      // latex2rtf 
99      private final static String SUFFIX_RTF = ".rtf";
100 
101     // odt2doc 
102     private final static String SUFFIX_ODT = ".odt";
103 
104     // tex4ht 
105     // FIXME: works for unix only 
106     final static String SUFFIX_HTML = ".html";
107 
108     // pdftotext 
109     private final static String SUFFIX_TXT = ".txt";
110 
111     // ChkTeX: log file 
112     private final static String SUFFIX_CLG = ".clg";
113 
114     /**
115      * The shape of the entries of an index file 
116      * with explicit identifier of the index. 
117      * If not explicitly given, this is just <code>idx</code>. 
118      * Note that this regular expression has three groups 
119      * as in the specification of <code>splitindex</code>. 
120      */
121     private final static String IDX_EXPL = 
122 	"^(\\\\indexentry)\\[([^]]*)\\](.*)$";
123 
124     /**
125      * Index of the group in {@link #IDX_EXPL} 
126      * containing the identifier of the index. 
127      */
128     private final static int GRP_IDENT_IDX = 2;
129 
130     /**
131      * The implicit default identifier of an index 
132      * hardcoded into the package <code>splitidx</code> 
133      * and into the program <code>splitindex</code>. 
134      */
135     private final static String IMPL_IDENT_IDX = "idx";
136 
137     /**
138      * Separator <code>-</code> of the index identifier 
139      * used in files <code>xxx-yy.idx</code>, <code>xxx-yy.ind</code> 
140      * and <code>xxx-yy.ilg</code>. 
141      * This is hardcoded by the package <code>splitidx</code> 
142      * when reading <code>xxx-yy.ind</code> files 
143      * but is configurable as an option in the program <code>splitindex</code>. 
144      */
145     private final static String SEP_IDENT_IDX = "-";
146 
147 
148     private final ParameterAdapter paramAdapt;
149 
150     /**
151      * The graphics preprocessor used by this processor. 
152      */
153     private final LatexPreProcessor preProc;
154 
155     /**
156      * The meta info provider used by this processor. 
157      */
158     private final MetaInfo metaInfo;
159 
160     // also for tests 
161     LatexProcessor(Settings settings, 
162 		   CommandExecutor executor, 
163 		   LogWrapper log, 
164 		   TexFileUtils fileUtils,
165 		   ParameterAdapter paramAdapt) {
166 	super(settings, executor, log, fileUtils);
167 	this.paramAdapt = paramAdapt;
168 	this.preProc = new LatexPreProcessor
169 	    (this.settings, this.executor, this.log, this.fileUtils);
170 	this.metaInfo = new MetaInfo(this.executor, this.log);
171     }
172 
173     /**
174      * Creates a LatexProcessor with parameters given by <code>settings</code> 
175      * which logs onto <code>log</code> and used by <code>paramAdapt</code>. 
176      *
177      * @param settings
178      *    the settings controlling latex processing 
179      * @param log
180      *    the logger to write on events while processing 
181      * @param paramAdapt
182      *    the parameter adapter, refers to maven-plugin or ant-task. 
183      */
184     public LatexProcessor(Settings settings, 
185 			  LogWrapper log, 
186 			  ParameterAdapter paramAdapt) {
187 	this(settings, new CommandExecutor(log), log, 
188 	     new TexFileUtils(log), paramAdapt);
189     }
190 
191     /**
192      * Defines creational ant-task defined in {@link LatexCfgTask} 
193      * and the according goals in {@link CfgLatexMojo} 
194      * and subclasses of the maven plugin. 
195      * <p>
196      * This consists in reading the parameters 
197      * via {@link ParameterAdapter#initialize()} 
198      * processing graphic-files 
199      * via {@link LatexPreProcessor#processGraphicsSelectMain(File, DirNode)} 
200      * and processing the tex main files 
201      * via {@link Target#processSource(LatexProcessor, File)}. 
202      * The resulting files are identified by its suffixes 
203      * via  {@link Target#getPatternOutputFiles(Settings)} 
204      * and copied to the target folder. 
205      * Finally, by default a cleanup is performed 
206      * invoking {@link TexFileUtils#cleanUp(DirNode, File)}. 
207      * <p>
208      * Logging: 
209      * <ul>
210      * <li> WFU01: Cannot read directory... 
211      * <li> WFU03: cannot close file 
212      * <li> EFU05: Cannot delete file 
213      * <li> EFU07, EFU08, EFU09: if filtering a file fails. 
214      * <li> WPP02: tex file may be latex main file 
215      * <li> WPP03: Skipped processing of files with suffixes ... 
216      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
217      *      applications for preprocessing graphic files 
218      *      or processing a latex main file fails. 
219      * </ul>
220      *
221      * FIXME: exceptions not really clear. 
222      * @throws BuildFailureException 
223      *    <ul>
224      *    <li> TSS01 if 
225      *    the tex source directory does either not exist 
226      *    or is not a directory. 
227      *    <li> TSS02 if 
228      *    the tex source processing directory does either not exist 
229      *    or is not a directory. 
230      *    <li> TSS03 if 
231      *    the output directory exists and is no directory. 
232      *    <li> TEX01 if 
233      *    invocation of applications for preprocessing graphic files 
234      *    or processing a latex main file fails 
235      *    <li> TFU01 if 
236      *    the target directory that would be returned 
237      *    exists already as a regular file. 
238      *    <li> TFU03, TFU04, TFU05, TFU06 if 
239      *    copy of output files to target folder fails. 
240      *    For details see 
241      * {@link TexFileUtils#copyOutputToTargetFolder(File, FileFilter, File)}
242      *    </ul>
243      */
244     public void create() throws BuildFailureException {
245 
246         this.paramAdapt.initialize();
247         this.log.debug("Settings: " + this.settings.toString() );
248 
249 	// may throw BuildFailureException TSS01 
250 	File texDir = this.settings.getTexSrcDirectoryFile();
251 	assert texDir.exists() && texDir.isDirectory()
252 	    : "Expected existing tex folder "+texDir;
253 
254 	// may throw BuildFailureException TSS02 
255 	File texProcDir = this.settings.getTexSrcProcDirectoryFile();
256 	assert texProcDir.exists() && texProcDir.isDirectory()
257 	    : "Expected existing tex processing folder "+texDir;
258 
259 	// constructor DirNode may log warning WFU01 Cannot read directory 
260 	DirNode node = new DirNode(texProcDir, this.fileUtils);
261 
262 	try {
263 	    // process graphics and determine latexMainFiles 
264 	    // may throw BuildFailureException TEX01, 
265 	    // log warning WFU03, WPP02, WPP03, 
266 	    // EEX01, EEX02, EEX03, WEX04, WEX05, EFU07, EFU08, EFU09: if filtering a file fails. 
267 	    Collection<File> latexMainFiles = this.preProc
268 		.processGraphicsSelectMain(texProcDir, node);
269 
270 	    for (File texFile : latexMainFiles) {
271 		// throws BuildFailureException TFU01 
272 		// if targetDir would be an existing non-directory 
273 		File targetDir = this.fileUtils.getTargetDirectory
274 		    (texFile, 
275 		     texDir,
276 		     // throws BuildFailureException TSS03 
277 		     // if exists and is no dir 
278 		     this.settings.getOutputDirectoryFile());
279 		assert !targetDir.exists() || targetDir.isDirectory()
280 		    : "Expected target folder "+targetDir+" folder if exists. ";
281 
282 		for (Target target : this.paramAdapt.getTargetSet()) {
283 		    // may throw BuildFailureException TEX01, 
284 		    // log warning EEX01, EEX02, EEX03, WEX04, WEX05 
285 		    target.processSource(this, texFile);
286 		    FileFilter fileFilter = this.fileUtils.getFileFilter
287 			(texFile, target.getPatternOutputFiles(this.settings));
288 		    // may throw BuildFailureException 
289 		    // TFU03, TFU04, TFU05, TFU06 
290 		    // may log warning WFU01 Cannot read directory 
291 		    // FIXME: fileFilter shall not accept directories 
292 		    // and shall not accept texFile 
293 		    this.fileUtils.copyOutputToTargetFolder(texFile,
294 							    fileFilter,
295 							    targetDir);
296 		} // target 
297 	    } // texFile 
298 	} finally {
299 	    if (this.settings.isCleanUp()) {
300 		// may log warning WFU01, EFU05 
301 		this.fileUtils.cleanUp(node, texProcDir);
302             }
303         }
304     }
305 
306     /**
307      * Defines check goal of the maven plugin in {@link ChkMojo}. 
308      * This includes also creation of graphic files. 
309      * <p>
310      * TBD: logging
311      *
312      * @throws BuildFailureException
313      *    <ul>
314      *    <li> 
315      *    TSS02 if the tex source processing directory does either not exist 
316      *    or is not a directory. 
317      *    <li> 
318      *    TEX01 invoking FIXME
319      *    </ul>
320      */
321     // used in ChkMojo.execute() only 
322     // FIXME: maybe sufficient not to create graphics, if no \input. 
323     // Also, maybe good not to remove log file 
324     // maybe good to make suffix configurable rather than hardcoded. 
325     public void checkAll() throws BuildFailureException {
326 
327         this.paramAdapt.initialize();
328         this.log.debug("Settings: " + this.settings.toString() );
329 
330 	// may throw BuildFailureException TSS02 
331 	File texProcDir = this.settings.getTexSrcProcDirectoryFile();
332 	assert texProcDir.exists() && texProcDir.isDirectory()
333 	    : "Expected existing tex processing folder "+texProcDir;
334 
335 	// constructor DirNode may log warning WFU01 Cannot read directory 
336 	DirNode node = new DirNode(texProcDir, this.fileUtils);
337 
338 	try {
339 	    // may throw BuildFailureException TEX01, 
340 	    // log warning WFU03, WPP02, WPP03, 
341 	    // EEX01, EEX02, EEX03, WEX04, WEX05, EFU07, EFU08, EFU09 
342 	    Collection<File> latexMainFiles = this.preProc
343 		.processGraphicsSelectMain(texProcDir, node);
344 
345 	    for (File latexMain : latexMainFiles) {
346 		runCheck(latexMain);
347 	    }
348 	} finally {
349 	    // FIXME: also removes the clg-files 
350 	    if (this.settings.isCleanUp()) {
351 		// may log warning WFU01, EFU05 
352 		this.fileUtils.cleanUp(node, texProcDir);
353             }
354 	}
355     }
356 
357     /**
358      * Defines graphics goal of the maven plugin in {@link GraphicsMojo}. 
359      * <p>
360      * Logging: 
361      * <ul>
362      * <li> WFU01: Cannot read directory 
363      * <li> WFU03: cannot close file 
364      * <li> EFU07, EFU08, EFU09: if filtering a file fails. 
365      * <li> WPP02: tex file may be latex main file 
366      * <li> WPP03: Skipped processing of files with suffixes ... 
367      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
368      * if running graphic processors failed. 
369      * </ul>
370      *
371      * @throws BuildFailureException
372      *    <ul>
373      *    <li> 
374      *    TSS02 if the tex source processing directory does either not exist 
375      *    or is not a directory. 
376      *    <li> 
377      *    TEX01 invoking FIXME
378      *    </ul>
379      */
380     // used in GraphicsMojo.execute() only 
381     public void processGraphics() throws BuildFailureException {
382 		// may throw BuildFailureException TSS02
383 		File texProcDir = this.settings.getTexSrcProcDirectoryFile();
384 		assert texProcDir.exists() && texProcDir.isDirectory() 
385 		: "Expected existing tex processing folder " + texProcDir;
386 
387 		// constructor DirNode may log warning WFU01 Cannot read directory
388 		DirNode node = new DirNode(texProcDir, this.fileUtils);
389 		// may throw BuildFailureException TEX01,
390 		// log warning WFU03, WPP02, WPP03,
391 		// EEX01, EEX02, EEX03, WEX04, WEX05, EFU07, EFU08, EFU09
392 		this.preProc.processGraphicsSelectMain(texProcDir, node);
393     }
394 
395     /**
396      * Defines clearing ant-task defined in {@link LatexClrTask} 
397      * and the according goal in {@link ClearMojo} of the maven plugin. 
398      * Consists in clearing created graphic files 
399      * and created files derived from latex main file. 
400      * <p>
401      * The parameters this method depends on are (currently): 
402      * <ul>
403      * <li>
404      * {@link Settings#getTexSrcProcDirectoryFile()}
405      * <li>
406      * {@link Settings#getPatternLatexMainFile()}
407      * <li>
408      * {@link Settings#getPatternCreatedFromLatexMain()}
409      * </ul>
410      * <p>
411      * Logging: 
412      * <ul>
413      * <li> WPP02: tex file may be latex main file 
414      * <li> WFU01: Cannot read directory...
415      * <li> WFU03: cannot close tex file 
416      * <li> EFU05: Failed to delete file 
417      * </ul>
418      *
419      * @throws BuildFailureException 
420      *    TSS02 if the tex source processing directory does either not exist 
421      *    or is not a directory. 
422      */
423     public void clearAll() throws BuildFailureException {
424         this.paramAdapt.initialize();
425         this.log.debug("Settings: " + this.settings.toString());
426 
427 	// may throw BuildFailureException TSS02 
428         File texProcDir = this.settings.getTexSrcProcDirectoryFile();
429 	assert texProcDir.exists() && texProcDir.isDirectory()
430 	    : "Expected existing tex processing folder "+texProcDir;
431 
432 	// constructor DirNode may log warning WFU01 Cannot read directory 
433 	// clearCreated may log warnings WPP02, WFU01, WFU03, EFU05 
434 	this.preProc.clearCreated(texProcDir);
435    }
436 
437 
438     // FIXME: use the -recorder option to resolve dependencies. 
439     // With that option, a file xxx.fls is generated with form 
440     // PWD /home/ernst/OpenSource/maven-latex-plugin/maven-latex-plugin.git/trunk/maven-latex-plugin/src/site/tex
441     // INPUT /usr/local/texlive/2014/texmf.cnf
442     // INPUT /usr/local/texlive/2014/texmf-dist/web2c/texmf.cnf
443     // INPUT /usr/local/texlive/2014/texmf-var/web2c/pdftex/pdflatex.fmt
444     // INPUT manualLatexMavenPlugin.tex
445     // OUTPUT manualLatexMavenPlugin.log
446     // INPUT /usr/local/texlive/2014/texmf-dist/tex/latex/base/article.cls
447     // INPUT /usr/local/texlive/2014/texmf-dist/tex/latex/base/article.cls
448     // INPUT /usr/local/texlive/2014/texmf-dist/tex/latex/base/size12.clo
449     //
450     // The first line starts has the form 'PWD <working directory>' 
451     // The other lines have the form '(INPUT|OUTPUT) <file>' 
452     // We distinguishe those in the installation, 
453     // here '/usr/local/texlive/2014/...' which do not change ever 
454     // and others. 
455     // In this example, the others are (unified and sorted): 
456 
457 // INPUT manualLatexMavenPlugin.tex
458 
459 // OUTPUT manualLatexMavenPlugin.log
460 // INPUT  manualLatexMavenPlugin.aux
461 // OUTPUT manualLatexMavenPlugin.aux
462 // INPUT  manualLatexMavenPlugin.out
463 // OUTPUT manualLatexMavenPlugin.out
464 // INPUT  manualLatexMavenPlugin.toc
465 // OUTPUT manualLatexMavenPlugin.toc
466 // INPUT  manualLatexMavenPlugin.lof
467 // OUTPUT manualLatexMavenPlugin.lof
468 // INPUT  manualLatexMavenPlugin.lot
469 // OUTPUT manualLatexMavenPlugin.lot
470 
471 // OUTPUT manualLatexMavenPlugin.idx
472 // INPUT  manualLatexMavenPlugin.ind
473 
474 // OUTPUT manualLatexMavenPlugin.pdf
475 
476 // INPUT 1fig2dev.ptx
477 // INPUT 1fig2dev.pdf
478 // INPUT 2plt2pdf.ptx
479 // INPUT 2plt2pdf.pdf
480 // INPUT 4tex2pdf.ptx
481 // INPUT 5aux2bbl.ptx
482 // INPUT 5aux2bbl.pdf
483 // INPUT 6idx2ind.ptx
484 // INPUT 6idx2ind.pdf
485 // INPUT 7tex2xml.ptx
486 // INPUT 7tex2xml.pdf
487 // what is missing is all to do with bibliography, i.e. the bib-file. 
488 
489     // FIXME: determine whether to use latexmk makes sense 
490 
491 
492     /**
493      * Container which comprises, besides the latex main file 
494      * also several files creation of which shall be done once for ever. 
495      */
496     static class LatexMainDesc {
497 	private final File texFile;
498 	final File pdfFile;
499 	final File dviFile;
500 
501 	private final File logFile;
502 
503 	private final File idxFile;
504 	private final File indFile;
505 	private final File ilgFile;
506 
507 	private final File glsFile;
508 	private final File gloFile;
509 	private final File glgFile;
510 	private final File xxxFile;
511 
512 	// TBC: does not depend on dev 
513 	LatexMainDesc(File texFile, TexFileUtils fileUtils, LatexDev dev) {
514 	    this.texFile = texFile;
515 	    // FIXME: easier to create xxxFile first 
516 	    this.xxxFile = fileUtils.replaceSuffix(texFile, SUFFIX_VOID);
517 	    this.pdfFile = fileUtils.replaceSuffix(texFile, SUFFIX_PDF);
518 	    this.dviFile = fileUtils.replaceSuffix(texFile, SUFFIX_DVI);
519 	    this.logFile = fileUtils.replaceSuffix(texFile, SUFFIX_LOG);
520 
521 	    this.idxFile = fileUtils.replaceSuffix(texFile, SUFFIX_IDX);
522 	    this.indFile = fileUtils.replaceSuffix(texFile, SUFFIX_IND);
523 	    this.ilgFile = fileUtils.replaceSuffix(texFile, SUFFIX_ILG);
524 
525 	    this.glsFile = fileUtils.replaceSuffix(texFile, SUFFIX_GLS);
526 	    this.gloFile = fileUtils.replaceSuffix(texFile, SUFFIX_GLO);
527 	    this.glgFile = fileUtils.replaceSuffix(texFile, SUFFIX_GLG);
528 	}
529     } // class LatexMainDesc 
530 
531     private LatexMainDesc getLatexMainDesc(File texFile) {
532 	return new LatexMainDesc
533 	    (texFile, this.fileUtils, this.settings.getPdfViaDvi());
534     }
535 
536 
537 
538 
539 
540     /**
541      * Runs LaTeX on on the latex main file <code>texFile</code> 
542      * described by <code>desc</code> once, 
543      * runs BibTeX, MakeIndex and MakeGlossaries by need 
544      * and returns whether a second LaTeX run is required. 
545      * The latter also holds, if a table of contents, a list of figures 
546      * or a list of tables is specified. 
547      * The output format of the LaTeX run is given by <code>dev</code>, 
548      * to be more precise by {@link LatexDev#getLatexOutputFormat()}. 
549      * <p>
550      * A warning is logged if the LaTeX, a BibTeX run a MakeIndex 
551      * or a MakeGlossaries run fails 
552      * or if a BibTeX run or a MakeIndex or a MakeGlossary run issues a warning
553      * in the according methods 
554      * {@link #runLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)}, 
555      * {@link #runBibtexByNeed(File)}, 
556      * {@link #runMakeIndexByNeed(LatexMainDesc)} and 
557      * {@link #runMakeGlossaryByNeed(LatexMainDesc)}. 
558      * <p>
559      * Logging: 
560      * <ul>
561      * <li> EAP01: Running <code>command</code> failed. For details...
562      * <li> EAP02: Running <code>command</code> failed. No log file 
563      * <li> WAP04: if <code>logFile</code> is not readable. 
564      * <li> WLP04: Cannot read idx file; skip creation of index 
565      * <li> WLP05: Use package 'splitidx' without option 'split' 
566      * <li> WLP02: Cannot read blg file: BibTeX run required? 
567      * <li> WFU03: cannot close log file 
568      * <li> EEX01, EEX02, EEX03, WEX04, WEX05:
569      *      if one of the commands mentioned in the throws-tag fails 
570      * </ul>
571      *
572      * @param desc
573      *    the description of a latex main file <code>texFile</code> 
574      *    to be processed. 
575      * @param dev
576      *    the device describing the output format which is either pdf or dvi. 
577      *    See {@link LatexDev#getLatexOutputFormat()}. 
578      * @return
579      *    the number of LaTeX runs required 
580      *    because bibtex, makeindex or makeglossaries had been run 
581      *    or to update a table of contents or a list figures or tables. 
582      *    <ul>
583      *    <li>
584      *    If neither of these are present, no rerun is required. 
585      *    <li>
586      *    If a bibliography, an index and a glossary is included 
587      *    and a table of contents, 
588      *    we assume that these are in the table of contents. 
589      *    Thus two reruns are required: 
590      *    one to include the bibliography or that like 
591      *    and the second one to make it appear in the table of contents. 
592      *    <li>
593      *    In all other cases, a single rerun suffices 
594      *    </ul>
595      * @throws BuildFailureException
596      *    TEX01 if invocation one of the following commands fails: the 
597      *    <ul>
598      *    <li> latex2pdf command from {@link Settings#getLatex2pdfCommand()} 
599      *    <li> BibTeX    command from {@link Settings#getBibtexCommand()}
600      *    <li> makeindex command from {@link Settings#getMakeIndexCommand()} 
601      *    <li> makeglossaries command 
602      *         from {@link Settings#getMakeGlossariesCommand()} 
603      *    </ul>
604      * @see #processLatex2devCore(LatexProcessor.LatexMainDesc, LatexDev)
605      * @see #processLatex2html(File)
606      * @see #processLatex2odt(File)
607      * @see #processLatex2docx(File)
608      */
609     private int preProcessLatex2dev(LatexMainDesc desc, LatexDev dev) 
610 	throws BuildFailureException {
611 
612 	// initial latex run 
613  	// may throw BuildFailureException TEX01 
614 	// may log warnings EEX01, EEX02, EEX03, WEX04, WEX05, 
615 	// EAP01, EAP02, WAP04, WFU03
616 	runLatex2dev(desc, dev);
617 	File texFile = desc.texFile;
618 
619 	// create bibliography, index and glossary by need 
620 	// may throw BuildFailureException  TEX01 
621 	// may log warnings EEX01, EEX02, EEX03, WEX04, WEX05, 
622 	// EAP01, EAP02, WAP03, WAP04, WLP02, WFU03
623 	boolean hasBib    = runBibtexByNeed      (texFile);
624 	// may both throw BuildFailureException, both TEX01 
625 	// may both log warnings EEX01, EEX02, EEX03, WEX04, WEX05, 
626 	// EAP01, EAP02, WLP04, WLP05, WAP03, WAP04, WFU03
627 	boolean hasIdxGls = runMakeIndexByNeed   (desc)
628 	    |               runMakeGlossaryByNeed(desc);
629 
630 	// rerun LaTeX at least once if bibtex or makeindex had been run 
631 	// or if a toc, a lof or a lot exists. 
632 	if (hasBib) {
633 	    // one run to include the bibliography from xxx.bbl into the pdf 
634 	    // and the lables into the aux file 
635 	    // and another run to put the labels from the aux file 
636 	    // to the locations of the \cite commands. 
637 
638 	    // This suffices also to include a bib in a toc 
639 	    return 2;
640 	}
641 
642 	boolean hasToc = 
643 	    this.fileUtils.replaceSuffix(texFile, SUFFIX_TOC)  .exists();
644 	if (hasIdxGls) {
645 	    // Here, an index or a glossary exists 
646 	    // This requires at least one LaTeX run. 
647 
648 	    // if one of these has to be included in a toc, 
649 	    // a second run is needed. 
650 	    return hasToc ? 2 : 1;
651 	}
652 	// Here, no bib, index or glossary exists. 
653 	// The result is either 0 or 1, 
654 	// depending on whether a toc, lof or lot exists 
655 
656 	boolean needLatexReRun = hasToc 
657 	    || this.fileUtils.replaceSuffix(texFile, SUFFIX_LOF).exists()
658 	    || this.fileUtils.replaceSuffix(texFile, SUFFIX_LOT).exists();
659 
660 	return needLatexReRun ? 1 : 0;
661     }
662 
663     /**
664      * Runs LaTeX on the latex main file <code>texFile</code> 
665      * described by <code>desc</code> once, 
666      * runs BibTeX, MakeIndex and MakeGlossaries by need 
667      * according to {@link #preProcessLatex2dev(LatexMainDesc, LatexDev)} 
668      * and reruns MakeIndex, MakeGlossaries and LaTeX 
669      * as often as needed to get all links satisfied 
670      * or as threshold {@link Settings#maxNumReRunsLatex} specifies. 
671      * <p>
672      * Note that still no logging of warnings from a latex run is done. 
673      * This is done 
674      * in {@link #processLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)}. 
675      * The exclusion of logging of warnings is indicated by the name part 
676      * 'Core'. 
677      * Processing without logging of warnings 
678      * is required by {@link #processLatex2txt(File)}. 
679      * <p>
680      * The output format of the LaTeX run is given by <code>dev</code>, 
681      * to be more precise by {@link LatexDev#getLatexOutputFormat()}. 
682      * <p>
683      * Logging: 
684      * WLP01: if another rerun is required but the maximum number of runs 
685      * {@link Settings#getMaxNumReRunsLatex()} is reached. 
686      * Further logging is inherited by invoked methods: 
687      * <ul>
688      * <li> WLP04: Cannot read idx file; skip creation of index 
689      * <li> WLP05: Use package 'splitidx' without option 'split' 
690      * <li> EAP01: Running <code>command</code> failed. For details...
691      * <li> EAP02: Running <code>command</code> failed. No log file 
692      * <li> WAP04: if <code>logFile</code> is not readable. 
693      * <li> WLP02: Cannot read log file:     run BibTeX/
694      *                                   (re)run MakeIndex/LaTeX required? 
695      * <li> WFU03: cannot close 
696      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: as for 
697      *     {@link #preProcessLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)} 
698      *      maybe caused by subsequent runs. 
699      * </ul>
700      *
701      * @param desc
702      *    the description of a latex main file <code>texFile</code> 
703      *    to be processed. 
704      * @param dev
705      *    the device describing the output format which is either pdf or dvi. 
706      *    See {@link LatexDev#getLatexOutputFormat()}. 
707      * @throws BuildFailureException
708      *    TEX01 as for 
709      *    {@link #preProcessLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)} 
710      *    maybe caused by subsequent runs. 
711      * @see #processLatex2dvi(File)
712      * @see #processLatex2txt(File)
713      */
714     private void processLatex2devCore(LatexMainDesc desc, LatexDev dev) 
715 	throws BuildFailureException {
716 
717 	// may throw BuildFailureException TEX01, 
718 	// log warning WLP04, WLP05, EAP01, EAP02, WAP04, WLP02, WFU03, 
719 	// EEX01, EEX02, EEX03, WEX04, WEX05 
720  	int numLatexReRuns = preProcessLatex2dev(desc, dev);
721 				      
722 	assert numLatexReRuns == 0 
723 	    || numLatexReRuns == 1 
724 	    || numLatexReRuns == 2;
725 	if (numLatexReRuns > 0) {
726 	    // rerun LaTeX without makeindex and makeglossaries 
727 	    this.log.debug("Rerun LaTeX to update table of contents, ... " + 
728 			   "bibliography, index, or that like. ");
729 	    // may throw BuildFailureException TEX01 
730 	    // may log warnings EEX01, EEX02, EEX03, WEX04, WEX05, 
731 	    // EAP01, EAP02, WAP04, WFU03
732 	    runLatex2dev(desc, dev);
733 	    numLatexReRuns--;
734 	}
735 	assert numLatexReRuns == 0 || numLatexReRuns == 1;
736 
737 	// rerun latex by need patternRerunMakeIndex
738 	boolean needMakeIndexReRun;
739 	boolean needLatexReRun = (numLatexReRuns == 1)
740 	    || needRun(true, "LaTeX", desc.logFile, 
741 		       this.settings.getPatternReRunLatex());
742 
743 	int maxNumReruns = this.settings.getMaxNumReRunsLatex();
744 	for (int num = 0; maxNumReruns == -1 || num < maxNumReruns; num++) {
745 	    needMakeIndexReRun = 
746 		needRun(true, "MakeIndex", desc.logFile, 
747 			this.settings.getPatternReRunMakeIndex());
748 	    // FIXME: superfluous since pattern rerunfileckeck 
749 	    // triggering makeindex also fits rerun of LaTeX 
750 	    needLatexReRun |= needMakeIndexReRun;
751 	    if (!needLatexReRun) {
752 		return;
753 	    }
754             this.log.debug("Latex must be rerun. ");
755 	    if (needMakeIndexReRun) {
756 		// FIXME: not by need 
757 		// may throw BuildFailureException TEX01 
758 		// may log warnings EEX01, EEX02, EEX03, WEX04, WEX05, 
759 		// EAP01, EAP02, WLP04, WLP05, WAP03, WAP04, WFU03
760 		runMakeIndexByNeed(desc);
761 	    }
762 
763 	    // may throw BuildFailureException TEX01 
764 	    // may log warnings EEX01, EEX02, EEX03, WEX04, WEX05, 
765 	    // EAP01, EAP02, WAP04, WFU03
766 	    runLatex2dev(desc, dev);
767 	    needLatexReRun = needRun(true, "LaTeX", desc.logFile, 
768 				     this.settings.getPatternReRunLatex());
769         }
770 	this.log.warn("WLP01: LaTeX requires rerun but maximum number " + 
771 		      maxNumReruns + " reached. ");
772     }
773 
774     /**
775      * Returns whether a(n other) run (see <code>another</code>)
776      * of the application <code>application</code> is necessary 
777      * based on a pattern <code>pattern</code> 
778      * matching in the log file <code>logFile</code>. 
779      * Note that only <code>logFile</code> and <code>pattern</code> 
780      * are required unless a warning needs to be issued. 
781      * <p>
782      * Logging: 
783      * <ul>
784      * <li> WLP02: Cannot read log file: (re)run required? 
785      * <li> WFU03: cannot close log file 
786      * </ul>
787      *
788      * @param another
789      *    whether it is requested whether another run (a 'rerun') is required. 
790      *    If false, just a run is required
791      * @param application
792      *    Determines the application to be rerun. 
793      *    This may be <code>LaTeX</code>, <code>MakeIndex</code> 
794      *    but also <code>BibTeX</code>. 
795      * @param logFile
796      *    the log file which determines 
797      *    whether to rerun <code>application</code>. 
798      * @param pattern
799      *    the pattern in the <code>logFile</code> 
800      *    which determines whether to rerun . 
801      * @return
802      *    whether <code>application</code> needs to be rerun 
803      *    based on a pattern <code>pattern</code> 
804      *    matching in the log file <code>logFile</code>. 
805      * @see TexFileUtils#matchInFile(File, String)
806      */
807     // used in processLatex2devCore and in runBibtexByNeed only 
808     private boolean needRun(boolean another, 
809 			    String application, 
810 			    File logFile, 
811 			    String pattern) {
812 	// may log warning WFU03: cannot close 
813 	Boolean needRun = this.fileUtils.matchInFile(logFile, pattern);
814 	if (needRun == null) {
815 	    this.log.warn("WLP02: Cannot read log file '" + 
816 			  logFile.getName() + "'; " + 
817 			  application + " may require " + 
818 			  (another ? "re" : "") + "run. ");
819 	    return false;
820 	}
821 	return needRun;
822     }
823 
824     /**
825      * Runs LaTeX, BibTeX, MakeIndex and MakeGlossaries 
826      * on the latex main file <code>texFile</code> 
827      * described by <code>desc</code> 
828      * repeatedly as described for 
829      * {@link #processLatex2devCore(LatexProcessor.LatexMainDesc, LatexDev)} 
830      * and issue a warning if the last LaTeX run issued a warning. 
831      * </ul>
832      * <p>
833      * Logging: 
834      * <ul>
835      * <li> WFU03: cannot close 
836      * <li> WAP04: if <code>logFile</code> is not readable. 
837      * <li> WLP01: if another rerun is required 
838      *             but the maximum number of runs is reached. 
839      * <li> WLP03: <code>command</code> created bad boxes 
840      * <li> WLP04: <code>command</code> emitted warnings 
841      * <li> WLP04: Cannot read idx file; skip creation of index 
842      * <li> WLP05: Use package 'splitidx' without option 'split' 
843      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
844      * {@link #processLatex2devCore(LatexProcessor.LatexMainDesc, LatexDev)} 
845      *      if running an exernal command fails. 
846      * </ul>
847      *
848      * @param desc
849      *    the description of a latex main file <code>texFile</code> 
850      *    to be processed. 
851      * @param dev
852      *    the device describing the output format which is either pdf or dvi. 
853      *    See {@link LatexDev#getLatexOutputFormat()}. 
854      * @throws BuildFailureException
855      *    TEX01 as for 
856      *    {@link #processLatex2devCore(LatexProcessor.LatexMainDesc, LatexDev)}.
857      * @see #needRun(boolean, String, File, String)
858      * @see Target#pdf
859      */
860     private void processLatex2dev(LatexMainDesc desc, LatexDev dev) 
861 	throws BuildFailureException {
862 	// may throw BuildFailureException TEX01, 
863 	// log warning EAP01, EAP02, WAP04, WLP02, WFU03, WLP04, WLP05, 
864 	// EEX01, EEX02, EEX03, WEX04, WEX05 
865 	processLatex2devCore(desc, dev);
866 
867 	// emit warnings (errors are emitted by runLatex2dev and that like.)
868 	// may log warnings WFU03, WAP04, WLP03, WLP04 
869 	logWarns(desc.logFile, this.settings.getLatex2pdfCommand());
870     }
871 
872     void processLatex2dvi(File texFile) throws BuildFailureException {
873         this.log.info("Converting into dvi:  LaTeX file '" + texFile + "'. ");
874 	LatexMainDesc desc = getLatexMainDesc(texFile);
875 	// may throw BuildFailureException TEX01, 
876 	// log warning EEX01, EEX02, EEX03, WEX04, WEX05 
877 	// WFU03, WAP04, WLP03, WLP04 
878 	processLatex2dev(desc, LatexDev.dvips);
879     }
880 
881     void processLatex2pdf(File texFile) throws BuildFailureException {
882         this.log.info("Converting into pdf:  LaTeX file '" + texFile + "'. ");
883 	LatexMainDesc desc = getLatexMainDesc(texFile);
884 	LatexDev dev = this.settings.getPdfViaDvi();
885 
886 	// may throw BuildFailureException TEX01, 
887 	// log warning EEX01, EEX02, EEX03, WEX04, WEX05, WLP04, WLP05 
888 	processLatex2dev(desc, dev);
889 	// FIXME: certain figures are invisible in the intermediate dvi file, 
890 	// but converstion to pdf shows that the figures are present. 
891 
892 	if (dev.isViaDvi()) {
893 	    // may throw BuildFailureException TEX01, 
894 	    // may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
895  	    runDvi2pdf(desc);
896 	}
897     }
898 
899     /**
900      * Logs errors detected in the according log file: 
901      * The log file is by replacing the ending of <code>texFile</code> 
902      * by <code>log</code>. 
903      * If the log file exists, a <em>warning</em> is logged 
904      * if the error pattern given by {@link Settings#getPatternErrLatex()} 
905      * occurs in the log file. 
906      * If the log file does not exist, an <em>error</em> is logged. 
907      * In both cases, the message logged refers to the <code>command</code> 
908      * which failed. 
909      * <p>
910      * Logging: 
911      * <ul>
912      * <li> EAP01: Running <code>command</code> failed. For details...
913      * <li> EAP02: Running <code>command</code> failed. No log file 
914      * <li> WAP04: if <code>logFile</code> is not readable. 
915      * <li> WFU03: cannot close 
916      * </ul>
917      */
918     private void logErrs(File logFile, String command) {
919 	// may log warnings WFU03, EAP01, EAP02, WAP04
920 	logErrs(logFile, command, this.settings.getPatternErrLatex());
921     }
922 
923     /**
924      * Logs warnings detected in the according log-file <code>logFile</code>: 
925      * Before logging warnings, 
926      * errors are logged via {@link #logErrs(File, String)}. 
927      * So, if the log-file does not exist, 
928      * an error was already shown and so nothing is to be done here. 
929      * If the log-file exists, a <em>warning</em> is logged if 
930      * <ul>
931      * <li>
932      * another LaTeX rerun is required 
933      * beyond {@link Settings#maxNumReRunsLatex}, 
934      * <li>
935      * bad boxes occurred and shall be logged 
936      * according to {@link Settings#getDebugBadBoxes()}. 
937      * <li>
938      * warnings occurred and shall be logged 
939      * according to {@link Settings#getDebugWarnings()}. 
940      * </ul>
941      * Both criteria are based on pattern recognized in the log file: 
942      * {@link #PATTERN_OUFULL_HVBOX} for bad boxes is fixed, 
943      * whereas {@link Settings#getPatternWarnLatex()} is configurable. 
944      * The message logged refers to the <code>command</code> which failed. 
945      * <p>
946      * Logging: 
947      * <ul>
948      * <li> WFU03: cannot close 
949      * <li> WAP04: if <code>logFile</code> is not readable. 
950      * <li> WLP03: <code>command</code> created bad boxes 
951      * <li> WLP04: <code>command</code> emitted warnings 
952      * </ul>
953      *
954      * @param logFile
955      *    the log-file to detect warnings in. 
956      * @param command
957      *    the command which created <code>logFile</code> 
958      *    and which maybe created warnings. 
959      */
960     private void logWarns(File logFile, String command) {
961 	if (!logFile.exists()) {
962 	    return;
963 	}
964 	// hasErrsWarns may log warnings WFU03 cannot close, WAP04 not readable
965 	if (this.settings.getDebugBadBoxes() && 
966 	    hasErrsWarns(logFile, PATTERN_OUFULL_HVBOX)) {
967 	    this.log.warn("WLP03: Running " + command + 
968 			  " created bad boxes logged in '" + 
969 			  logFile.getName() + "'. ");
970 	}
971 
972 	if (this.settings.getDebugWarnings() && 
973 	    hasErrsWarns(logFile, this.settings.getPatternWarnLatex())) {
974 	    // logs warning WAP03: emitted warnings 
975 	    logWarn(logFile, command);
976  	}
977     }
978 
979     /**
980      * Runs conversion of <code>texFile</code> to html or xhtml 
981      * after processing latex to set up the references, 
982      * bibliography, index and that like. 
983      * <p>
984      * Logging: FIXME: incomplete 
985      * <ul>
986       * <li> EAP01: Running <code>command</code> failed. For details...
987      * <li> EAP02: Running <code>command</code> failed. No log file 
988      * <li> WAP04: if <code>logFile</code> is not readable. 
989      * <li> WLP02: Cannot read blg file: BibTeX run required? 
990      * <li> WFU03: cannot close log file 
991      * <li> WLP04: Cannot read idx file; skip creation of index 
992      * <li> WLP05: Use package 'splitidx' without option 'split' 
993      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
994      *      if running an exernal command fails. 
995      * </ul>
996      *
997      * @param texFile
998      *    the tex file to be processed. 
999      * @throws BuildFailureException
1000      *    TEX01 as for 
1001      *    {@link #preProcessLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)} 
1002      *    but also as for {@link #runLatex2html(LatexProcessor.LatexMainDesc)}. 
1003      * @see #preProcessLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)
1004      * @see #runLatex2html(LatexProcessor.LatexMainDesc)
1005      * @see Target#html
1006      */
1007     void processLatex2html(File texFile) throws BuildFailureException {
1008 	this.log.info("Converting into html: LaTeX file '" + texFile + "'. ");
1009 	LatexMainDesc desc = getLatexMainDesc(texFile);
1010 	// may throw BuildFailureException TEX01, 
1011 	// log warning EAP01, EAP02, WLP04, WLP05, WAP04, WLP02, WFU03, 
1012 	// EEX01, EEX02, EEX03, WEX04, WEX05 
1013 	preProcessLatex2dev(desc, this.settings.getPdfViaDvi());
1014 	// may throw BuildFailureException TEX01, 
1015 	// log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1016         runLatex2html      (desc);
1017     }
1018 
1019     /**
1020      * Runs conversion of <code>texFile</code> 
1021      * to odt or other open office formats 
1022      * after processing latex to set up the references, 
1023      * bibliography, index and that like. 
1024      * <p>
1025      * Logging: FIXME: incomplete 
1026      * <ul>
1027      * <li> EAP01: Running <code>command</code> failed. For details...
1028      * <li> EAP02: Running <code>command</code> failed. No log file 
1029      * <li> WAP04: if <code>logFile</code> is not readable. 
1030      * <li> WLP02: Cannot read blg file: BibTeX run required? 
1031      * <li> WFU03: cannot close log file 
1032      * <li> WLP04: Cannot read idx file; skip creation of index 
1033      * <li> WLP05: Use package 'splitidx' without option 'split' 
1034      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1035      *      if running an exernal command fails. 
1036      * </ul>
1037      *
1038      * @param texFile
1039      *    the tex file to be processed. 
1040      * @throws BuildFailureException
1041      *    TEX01 as for 
1042      *    {@link #preProcessLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)} 
1043      *    but also as for {@link #runLatex2odt(LatexProcessor.LatexMainDesc)}. 
1044      * @see #preProcessLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)
1045      * @see #runLatex2odt(LatexProcessor.LatexMainDesc)
1046      * @see Target#odt
1047      */
1048     void processLatex2odt(File texFile) throws BuildFailureException {
1049 	this.log.info("Converting into odt:  LaTeX file '" + texFile + "'. ");
1050 	LatexMainDesc desc = getLatexMainDesc(texFile);
1051 	// may throw BuildFailureException TEX01, 
1052 	// log warning EAP01, EAP02, WAP04, WLP02, WFU03, WLP04, WLP05 
1053 	// EEX01, EEX02, EEX03, WEX04, WEX05 
1054         preProcessLatex2dev(desc, this.settings.getPdfViaDvi());
1055 	// may throw BuildFailureException TEX01, 
1056 	// log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1057         runLatex2odt       (desc);
1058     }
1059 
1060     /**
1061      * Runs conversion of <code>texFile</code> 
1062      * to docx or other MS word formats 
1063      * after processing latex to set up the references, 
1064      * bibliography, index and that like. 
1065      * <p>
1066      * Logging: FIXME: incomplete 
1067      * <ul>
1068      * <li> EAP01: Running <code>command</code> failed. For details...
1069      * <li> EAP02: Running <code>command</code> failed. No log file 
1070      * <li> WAP04: if <code>logFile</code> is not readable. 
1071      * <li> WLP02: Cannot read blg file: BibTeX run required? 
1072      * <li> WFU03: cannot close log file 
1073      * <li> WLP04: Cannot read idx file; skip creation of index 
1074      * <li> WLP05: Use package 'splitidx' without option 'split' 
1075      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1076      *      if running an exernal command fails. 
1077      * </ul>
1078      *
1079      * @param texFile
1080      *    the latex main file to be processed. 
1081      * @throws BuildFailureException
1082      *    TEX01 as for 
1083      *    {@link #preProcessLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)} 
1084      *    but also as for {@link #runLatex2odt(LatexProcessor.LatexMainDesc)} 
1085      *    and for {@link #runOdt2doc(File)}. 
1086      * @see #preProcessLatex2dev(LatexMainDesc, LatexDev)
1087      * @see #runLatex2odt(LatexProcessor.LatexMainDesc)
1088      * @see #runOdt2doc(File)
1089      * @see Target#docx
1090      */
1091     void processLatex2docx(File texFile) throws BuildFailureException {
1092 	this.log.info("Converting into doc(x): LaTeX file '" + texFile + "'. ");
1093 	LatexMainDesc desc = getLatexMainDesc(texFile);
1094 	// may throw BuildFailureException TEX0, 
1095 	// log warning EAP01, EAP02, WAP04, WLP02, WFU03, WLP04, WLP05 
1096 	// EEX01, EEX02, EEX03, WEX04, WEX05 
1097  	preProcessLatex2dev(desc, this.settings.getPdfViaDvi());
1098 	// may throw BuildFailureException TEX0, 
1099 	// log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1100         runLatex2odt       (desc);
1101 	// may throw BuildFailureException TEX01, 
1102 	// log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1103         runOdt2doc         (texFile);
1104     }
1105 
1106     /**
1107      * Runs direct conversion of <code>texFile</code> to rtf format. 
1108      * <p>
1109      * FIXME: Maybe prior invocation of LaTeX MakeIndex and BibTeX 
1110      * after set up the references, bibliography, index and that like 
1111      * would be better. 
1112      * <p>
1113      * Logging: FIXME: incomplete 
1114      * <ul>
1115      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1116      *      if running an exernal command fails. 
1117      * </ul>
1118      *
1119      * @param texFile
1120      *    the tex file to be processed. 
1121      * @throws BuildFailureException
1122      *    TEX01 if running the latex2rtf command 
1123      *    returned by {@link Settings#getLatex2rtfCommand()} failed. 
1124      * @see #runLatex2rtf(File)
1125      * @see Target#rtf
1126      */
1127     void processLatex2rtf(File texFile) throws BuildFailureException {
1128 	this.log.info("Converting into rtf:  LaTeX file '" + texFile + "'. ");
1129 	// may throw BuildFailureException TEX01, 
1130 	// log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1131 	runLatex2rtf(texFile);
1132     }
1133 
1134     /**
1135      * Runs conversion of <code>texFile</code> to txt format via pdf. 
1136      * <p>
1137      * Logging: FIXME: incomplete 
1138      * <ul>
1139      * <li> WLP04: Cannot read idx file; skip creation of index 
1140      * <li> WLP05: Use package 'splitidx' without option 'split' 
1141      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1142      *      if running an exernal command fails. 
1143      * </ul>
1144      *
1145      * @param texFile
1146      *    the tex file to be processed. 
1147      * @throws BuildFailureException
1148      *    TEX01 as for 
1149      *    {@link #processLatex2devCore(LatexProcessor.LatexMainDesc, LatexDev)} 
1150      *    and for {@link #runPdf2txt(File)}. 
1151      * @see #processLatex2devCore(LatexProcessor.LatexMainDesc, LatexDev)
1152      * @see #runPdf2txt(File)
1153      * @see Target#txt
1154      */
1155     void processLatex2txt(File texFile) throws BuildFailureException {
1156 	this.log.info("Converting into txt:  LaTeX file '" + texFile + "'. ");
1157 	LatexMainDesc desc = getLatexMainDesc(texFile);
1158 	LatexDev dev = this.settings.getPdfViaDvi();
1159 
1160 	// may throw BuildFailureException TEX01, 
1161 	// log warning EAP01, EAP02, WAP04, WLP02, WFU03, WLP04, WLP05, 
1162 	// EEX01, EEX02, EEX03, WEX04, WEX05 
1163 	processLatex2devCore(desc, dev);
1164 	if (dev.isViaDvi()) {
1165 	    // may throw BuildFailureException TEX01, 
1166 	    // may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1167  	    runDvi2pdf(desc);
1168 	}
1169 
1170 	// warnings emitted by LaTex are ignored 
1171 	// (errors are emitted by runLatex2dev and that like.)
1172 	// may throw BuildFailureException TEX01, 
1173 	// log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1174 	runPdf2txt      (texFile);
1175     }
1176 
1177 
1178     /**
1179      * Prints meta information, mainly version information 
1180      * on this software and on the converters used. 
1181      * <p>
1182      * WMI01: If the version string of a converter cannot be read. 
1183      * WMI02: If the version of a converter is not as expected. 
1184      * @return
1185      *    whether a warning has been issued. 
1186      * @throws BuildFailureException
1187      *    <ul>
1188      *    <li>TMI01: if the stream to either the manifest file 
1189      *        or to a property file, either {@LINK #VERSION_PROPS_FILE} 
1190      *        or {@link MetaInfo.GitProperties#GIT_PROPS_FILE} could not be created. </li>
1191      *    <li>TMI02: if the properties could not be read 
1192      *        from one of the two property files mentioned above. </li>
1193      *    </ul>
1194      */
1195     public boolean printMetaInfo() throws BuildFailureException {
1196 	return this.metaInfo.printMetaInfo();
1197     }
1198 
1199     /**
1200      * Runs the BibTeX command given by {@link Settings#getBibtexCommand()} 
1201      * on the aux-file corresponding with <code>texFile</code> 
1202      * in the directory containing <code>texFile</code> 
1203      * provided an according pattern in the aux-file indicates 
1204      * that a bibliography shall be created. 
1205      * <p>
1206      * Logging: 
1207      * <ul>
1208      * <li> EAP01: Running <code>bibtex</code> failed. For details...
1209      * <li> EAP02: Running <code>bibtex</code> failed. No log file 
1210      * <li> WAP03: Running <code>bibtex</code> emitted warnings. 
1211      * <li> WAP04: if <code>logFile</code> is not readable. 
1212      * <li> WLP02: Cannot read log file: run required? 
1213      * <li> WFU03: cannot close 
1214      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1215      * if running the BibTeX command failed. 
1216      * </ul>
1217      *
1218      * @param texFile
1219      *    the latex main file BibTeX is to be processed for. 
1220      * @return
1221      *    whether BibTeX has been run. 
1222      *    Equivalently, whether LaTeX has to be rerun because of BibTeX. 
1223      * @throws BuildFailureException
1224      *    TEX01 if invocation of the BibTeX command 
1225      *    returned by {@link Settings#getBibtexCommand()} failed. 
1226      */
1227     private boolean runBibtexByNeed(File texFile) throws BuildFailureException {
1228 	File auxFile    = this.fileUtils.replaceSuffix(texFile, SUFFIX_AUX);
1229 	if (!needRun(false, "BibTeX", auxFile, PATTERN_NEED_BIBTEX_RUN)) {
1230 	    return false;
1231 	}
1232 
1233 	String command = this.settings.getBibtexCommand();
1234 	this.log.debug("Running " + command + 
1235 		       " on '" + auxFile.getName() + "'. ");
1236 	String[] args = buildArguments(this.settings.getBibtexOptions(), 
1237 				       auxFile);
1238 	// may throw BuildFailureException TEX01, 
1239 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1240 	this.executor.execute(texFile.getParentFile(), // workingDir 
1241 			      this.settings.getTexPath(), 
1242 			      command, 
1243 			      args,
1244 			      this.fileUtils.replaceSuffix(texFile,SUFFIX_BBL));
1245 
1246 	File logFile = this.fileUtils.replaceSuffix(texFile, SUFFIX_BLG);
1247 	// may log EAP01, EAP02, WAP04, WFU03
1248 	logErrs (logFile, command, this.settings.getPatternErrBibtex());
1249 	// may log warnings WFU03, WAP03, WAP04
1250 	logWarns(logFile, command, this.settings.getPatternWarnBibtex());
1251 	return true;
1252     }
1253 
1254     /**
1255      * Runs the MakeIndex command 
1256      * given by {@link Settings#getMakeIndexCommand()} 
1257      * on the idx-file corresponding with <code>texFile</code> 
1258      * in the directory containing <code>texFile</code> 
1259      * provided that the existence of an idx-file indicates 
1260      * that an index shall be created. 
1261      * <p>
1262      * Note that {@link Settings#getMakeIndexCommand()} 
1263      * is invoked either directly, or, in case of a multiple index, 
1264      * via {@link Settings#getSplitIndexCommand()}. 
1265      * <p>
1266      * Logging: 
1267      * <ul>
1268      * <li> WLP04: Cannot read idx file; skip creation of index 
1269      * <li> WLP05: Use package 'splitidx' without option 'split' 
1270      * <li> EAP01: Running <code>makeindex</code> failed. For details...
1271      * <li> EAP02: Running <code>makeindex</code> failed. No log file 
1272      * <li> WAP03: Running <code>makeindex</code> emitted warnings. 
1273      * <li> WAP04: .ilg-file is not readable. 
1274      * <li> WFU03: cannot close .ilg-file 
1275      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1276      * if running the makeindex command failed. 
1277      * </ul>
1278      *
1279      * @param desc
1280      *    the description of a latex main file <code>dviFile</code> 
1281      *    including the idx-file MakeIndex is to be run on. 
1282      * @return
1283      *    whether MakeIndex had been run. 
1284      *    Equivalently, whether LaTeX has to be rerun because of MakeIndex. 
1285      * @throws BuildFailureException
1286      *    TEX01 if invocation of the makeindex command 
1287      *    returned by {@link Settings#getMakeIndexCommand()} failed. 
1288      */
1289     // FIXME: bad name since now there are reruns. 
1290     // Suggestion: runMakeIndexInitByNeed 
1291     // Other methods accordingly. 
1292     // maybe better: eliminate altogether 
1293     private boolean runMakeIndexByNeed(LatexMainDesc desc)
1294 	throws BuildFailureException {
1295 
1296 	// raw index file written by pdflatex 
1297 	boolean needRun = desc.idxFile.exists();
1298 	this.log.debug("MakeIndex run required? " + needRun);
1299 
1300 	// determine the explicit given identifiers of indices 
1301 	Collection<String> explIdxIdent = null;
1302 	if (needRun) {
1303 	    explIdxIdent = this.fileUtils
1304 		.collectMatches(desc.idxFile, IDX_EXPL, GRP_IDENT_IDX);
1305 	    if (explIdxIdent == null) {
1306 		this.log.warn("WLP04: Cannot read idx file '" + 
1307 			      desc.idxFile.getName() + 
1308 			      "'; skip creation of index. ");
1309 		return false;
1310 	    }
1311 	}
1312 	assert (explIdxIdent != null) == needRun;
1313 	// Here, explIdxIdent contains the explicit identifiers of all indices 
1314 	// The identifier idx may be missing or not. 
1315 
1316 	// package splitidx is used with option split 
1317 	// is in general not allowed. The criteria are: 
1318 	// - if \jobname-xxx.idx exists for some xxx 
1319 	//   whereas \jobname.idx does not: 
1320 	//   This occurs only for option split 
1321 	//   and does not allow applying splitindex 
1322 	//   as intended in this software. 
1323 	//   This would require applying makeindex separately 
1324 	//   to all \jobname-xxx.idx
1325 	// - if \jobname-xxx.idx exists for some xxx 
1326 	//   and also \jobname.idx exists but has no entry 
1327 	//   \indexentry[xxx]{...}{..}: 
1328 	//   This occurs only for option split 
1329 	//   and applying splitindex yields the wrong result. 
1330 	//   This would require applying makeindex separately 
1331 	//   to all \jobname-xxx.idx and to \jobname.idx 
1332 	// - if \jobname-xxx.idx does not exist for any xxx 
1333 	//   then all is ok, whether \jobname.idx exists or not. 
1334 	//   If it exists, even splitidx with option split is ok. 
1335 
1336 	// so algorithm: 
1337 	// determine list of these xxx for which \jobname-xxx.idx exists
1338 	// if (\jobname-xxx.idx exists for some xxx) {
1339 	//   if (!(\jobname.idx exists && 
1340 	//         \jobname.idx matches some \indexentry[xxx]{...}{.. )) {
1341 	//     log.error(cannot handle splitidx with option split)
1342 	//     return false;
1343 	//   }
1344 	//   // For second condition, 
1345 	//   // determine list of all yyy matching \indexentry[yyy]{...}{..} 
1346 	//   // and make sure that it is non-empty. 
1347 	// }
1348 
1349 	// filter for extended raw idx-files: \jobname-xxx.idx 
1350 	FileFilter filter = this.fileUtils
1351 	    .getFileFilterReplace(desc.idxFile, SEP_IDENT_IDX + ".+");
1352 	// may cause WFU01: Cannot read directory 
1353 	File[] idxFilesExtInDir = this.fileUtils
1354 	    .listFilesOrWarn(desc.idxFile.getParentFile(), filter);
1355 
1356 
1357 	// If the directory compising idxFile is not readable, 
1358 	// idxFilesExtInDir == null
1359 	// Then the check for option split cannot be done. 
1360 	
1361 
1362 	if (idxFilesExtInDir != null && idxFilesExtInDir.length > 0) {
1363 	    // Here, idxFilesExtInDir contains the idx-files \jobname-xxx.idx 
1364 	    if (!needRun || explIdxIdent.isEmpty()) {
1365 		// Here, either \jobname.idx does not exist at all 
1366 		// or does not contain an entry \indexentry[yyy]{...}{..} 
1367 
1368 		this.log.warn("WLP05: Use package 'splitidx' " + 
1369 			      "without option 'split' in '" + 
1370 			      desc.texFile.getName() + "'. ");
1371 		// this.log.warn("WLP05: Found extended idx-file " + 
1372 		// 	      " without (according entry in) '" + 
1373 		// 	      desc.idxFile.getName() +
1374 		// 	      "': use package 'splitidx' " + 
1375 		// 	      "without option 'split'. ");
1376 	    }
1377 	}
1378 
1379 	if (needRun) {
1380 	    // Here, runMakeIndex or runSplitIndex must be performed 
1381 
1382 	    // check whether more than one index has to be created 
1383 	    if (explIdxIdent.isEmpty()) {
1384 		// may throw BuildFailureException TEX01 
1385 		// may log warnings EEX01, EEX02, EEX03, WEX04, WEX05, 
1386 		// EAP01, EAP02, WAP03, WAP04, WFU03
1387 		runMakeIndex(desc);
1388 	    } else {
1389 		// may throw BuildFailureException TEX01 
1390 		// may log warnings EEX01, EEX02, EEX03, WEX04, WEX05, 
1391 		// EAP01, EAP02, WAP03, WAP04, WFU03
1392 		runSplitIndex(desc, explIdxIdent);
1393 	    }
1394 	}
1395 	return needRun;
1396     }
1397 
1398     /**
1399      * Runs the MakeIndex command 
1400      * given by {@link Settings#getMakeIndexCommand()}. 
1401      * <p>
1402      * Logging: 
1403      * <ul>
1404      * <li> EAP01: Running <code>makeindex</code> failed. For details...
1405      * <li> EAP02: Running <code>makeindex</code> failed. No log file 
1406      * <li> WAP03: Running <code>makeindex</code> emitted warnings. 
1407      * <li> WAP04 .ilg-file is not readable. 
1408      * <li> WFU03: cannot close .ilg-file 
1409      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1410      * if running the makeindex command failed. 
1411      * </ul>
1412      *
1413      * @param desc
1414      *    the description of a latex main file <code>texFile</code> 
1415      *    including the idx-file MakeIndex is to be run on. 
1416      * @throws BuildFailureException
1417      *    TEX01 if invocation of the MakeIndex command 
1418      *    returned by {@link Settings#getMakeIndexCommand()} failed. 
1419      */
1420     private void runMakeIndex(LatexMainDesc desc) 
1421 	throws BuildFailureException {
1422 
1423 	String command = this.settings.getMakeIndexCommand();
1424 	File idxFile = desc.idxFile;
1425 	this.log.debug("Running " + command  + 
1426 		       " on '" + idxFile.getName() + "'. ");
1427 	String[] args = buildArguments(this.settings.getMakeIndexOptions(),
1428 				       idxFile);
1429 	// may throw BuildFailureException TEX01, 
1430 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1431 	this.executor.execute(idxFile.getParentFile(), //workingDir 
1432 			      this.settings.getTexPath(), 
1433 			      command, 
1434 			      args,
1435 			      desc.indFile);
1436 
1437 	// detect errors and warnings makeindex wrote into xxx.ilg 
1438 	// may log EAP01, EAP02, WAP04, WFU03
1439  	logErrs (desc.ilgFile, command,this.settings.getPatternErrMakeIndex());
1440 	// may log warnings WFU03, WAP03, WAP04
1441 	logWarns(desc.ilgFile, command,this.settings.getPatternWarnMakeIndex());
1442     }
1443 
1444     /**
1445      * Combines an array of files from a file prefix <code>filePrefix</code>, 
1446      * a collection of intermediate strings <code>variant</code> 
1447      * and of the suffix <code>suffix</code>. 
1448      *
1449      * @param filePrefix
1450      *    prefix of file name; in practice of index file without suffix 
1451      * @param variant
1452      *    collection of strings; in practice set of identifiers of indices 
1453      * @param suffix
1454      *    the suffix of a file; in practice {@link #SUFFIX_IDX}. 
1455      * @return
1456      *    an array of file names of the form 
1457      *    <code>&lt;filePrefix&gt;&lt;ident&gt;&lt;suffix&gt;</code>, 
1458      *    where <code>ident</code> runs in <code>variant</code>. 
1459      */
1460     private File[] files(String filePrefix, 
1461 			 Collection<String> variant, 
1462 			 String suffix) {
1463 	File[] res = new File[variant.size()];
1464 	int idx = 0;
1465 	StringBuilder strb;
1466 	for (String idxIdent : variant) {
1467 	    strb = new StringBuilder();
1468 	    strb.append(filePrefix);
1469 	    strb.append(idxIdent);
1470 	    strb.append(suffix);
1471 
1472 	    res[idx++] = new File(strb.toString());
1473 	}
1474 	return res;
1475     }
1476 
1477     /**
1478      * Runs the SplitIndex command 
1479      * given by {@link Settings#getSplitIndexCommand()}. 
1480      * <p>
1481      * Logging: 
1482      * Note that <code>splitindex</code> neither writes a log file 
1483      * nor may it fail in itself but invoking <code>makeindex</code> 
1484      * or whatever program it uses. 
1485      * <ul>
1486      * <li> EAP01: Running <code>splitindex</code> failed. For details...
1487      * <li> EAP02: Running <code>splitindex</code> failed. No log file 
1488      * <li> WAP03: Running <code>splitindex</code> emitted warnings. 
1489      * <li> WAP04 .ilg-file is not readable. 
1490      * <li> WFU03: cannot close .ilg-file 
1491      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1492      * if running the splitindex command failed. 
1493      * </ul>
1494      *
1495      * @param desc
1496      *    the description of a latex main file <code>texFile</code> 
1497      *    including the idx-file SplitIndex is to be run on. 
1498      * @param explIdxIdent
1499      *    the set of identifiers of indices, 
1500      *    whether explicitly given or not in the idx file. 
1501      * @throws BuildFailureException
1502      *    TEX01 if invocation of the SplitIndex command 
1503      *    returned by {@link Settings#getSplitIndexCommand()} failed. 
1504      */
1505     private void runSplitIndex(LatexMainDesc desc, 
1506 			       Collection<String> explIdxIdent) 
1507 	throws BuildFailureException {
1508 
1509 	String command = this.settings.getSplitIndexCommand();
1510 	File idxFile = desc.idxFile;
1511 	this.log.debug("Running " + command  + 
1512 		       " on '" + idxFile.getName() + "'. ");
1513 	//buildArguments(this.settings.getMakeIndexOptions(), idxFile);
1514 	String[] argsDefault = new String[] {
1515 	    "-m " + this.settings.getMakeIndexCommand(),
1516 	    // **** no splitindex.tlu 
1517 	    // This is hardcoded by splitidx when writing xxx.ind
1518 	    "-i " + IDX_EXPL,
1519 	    // This is hardcoded by makeindex when writing xxx.ind
1520 	    "-r $1$3", // groups in IDX_EXPL: \indexentry{...}
1521 	    // -s -$2 is hardcoded by splitidx when readin in the -xxx.ind-files
1522 	    "-s " + SEP_IDENT_IDX + "$" + GRP_IDENT_IDX  // groups in IDX_EXPL
1523 	    // **** Here, only -V may occur in addition. 
1524 	    //"-V",
1525 	    //desc.xxxFile.getName()
1526 	};
1527 
1528 	String argsOption = this.settings.getMakeIndexOptions();
1529 	String[] args = argsOption.isEmpty() 
1530 	    ? new String[argsDefault.length+1]
1531 	    : new String[argsDefault.length+2];
1532 	System.arraycopy(argsDefault, 0, args, 0, argsDefault.length);
1533 	if (!argsOption.isEmpty()) {
1534 	    args[args.length-2] = argsOption;
1535 	}
1536 	args[args.length-1] = desc.xxxFile.getName();
1537 
1538 	String optionsMakeIndex = this.settings.getMakeIndexOptions();
1539 	if (!optionsMakeIndex.isEmpty()) {
1540 	    String[] optionsMake_IndexArr = optionsMakeIndex.split(" ");
1541 	    String[] optionsSplitIndexArr = args;
1542 	    args = new String[optionsMake_IndexArr.length+1+
1543 			      optionsSplitIndexArr.length];
1544 	    System.arraycopy(optionsSplitIndexArr, 0, args, 0, 
1545 			     optionsSplitIndexArr.length); 
1546 	    args[optionsSplitIndexArr.length] = "--"; 
1547 	    System.arraycopy(optionsMake_IndexArr,  0, args, 
1548 			     optionsSplitIndexArr.length+1, 
1549 			     optionsMake_IndexArr.length);
1550  	}
1551 
1552 	// determine the resulting ind-files 
1553 	explIdxIdent.add(IMPL_IDENT_IDX);
1554 	String filePrefix = desc.xxxFile.toString() + SEP_IDENT_IDX;
1555 	File[] indFiles = files(filePrefix, explIdxIdent, SUFFIX_IND);
1556 
1557 	// may throw BuildFailureException TEX01, 
1558 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1559 	this.executor.execute(idxFile.getParentFile(), //workingDir 
1560 			      this.settings.getTexPath(), 
1561 			      command, 
1562 			      args,
1563 			      indFiles);
1564 
1565 	// detect errors and warnings splitindex, 
1566 	// aka makeindex wrote into xxx.ilg 
1567 	File[] ilgFiles = files(filePrefix, explIdxIdent, SUFFIX_ILG);
1568 	command = this.settings.getMakeIndexCommand();
1569 	for (int idx = 0; idx < explIdxIdent.size(); idx++) {
1570 	    // may log EAP01, EAP02, WAP04, WFU03
1571 	    logErrs (ilgFiles[idx], command, 
1572 		     this.settings.getPatternErrMakeIndex());
1573 	    // may log warnings WFU03, WAP03, WAP04
1574 	    logWarns(ilgFiles[idx], command, 
1575 		     this.settings.getPatternWarnMakeIndex());
1576 	}
1577     }
1578 
1579     /**
1580      * Runs the MakeGlossaries command 
1581      * given by {@link Settings#getMakeGlossariesCommand()} 
1582      * on the aux-file corresponding with <code>texFile</code> 
1583      * in the directory containing <code>texFile</code> 
1584      * provided that the existence of an glo-file indicates 
1585      * that a glossary shall be created. 
1586      * The MakeGlossaries command is just a wrapper 
1587      * arround the programs <code>makeindex</code> and <code>xindy</code>. 
1588      * <p>
1589      * Logging: 
1590      * <ul>
1591      * <li> EAP01: Running <code>makeglossaries</code> failed. For details...
1592      * <li> EAP02 Running <code>makeglossaries</code> failed. No log file 
1593      * <li> WAP03: Running <code>makeglossaries</code> emitted warnings. 
1594      * <li> WAP04: .glg-file is not readable. 
1595      * <li> WFU03: cannot close .glg-file 
1596      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1597      * if running the makeglossaries command failed. 
1598      * </ul>
1599      *
1600      * @param desc
1601      *    the description of a latex main file <code>texFile</code> 
1602      *    including the idx-file MakeGlossaries is to be run on. 
1603      * @return
1604      *    whether MakeGlossaries had been run. 
1605      *    Equivalently, 
1606      *    whether LaTeX has to be rerun because of MakeGlossaries. 
1607      * @throws BuildFailureException
1608      *    TEX01 if invocation of the makeglossaries command 
1609      *    returned by {@link Settings#getMakeGlossariesCommand()} failed. 
1610      */
1611      private boolean runMakeGlossaryByNeed(LatexMainDesc desc)
1612 	throws BuildFailureException {
1613 
1614 	// raw glossaries file created by pdflatex 
1615 	boolean needRun = desc.gloFile.exists();
1616 	this.log.debug("MakeGlossaries run required? " + needRun);
1617 	if (!needRun) {
1618 	    return false;
1619 	}
1620 
1621 	// file name without ending: parameter for makeglossaries 
1622 	File xxxFile = desc.xxxFile;
1623 	String command = this.settings.getMakeGlossariesCommand();
1624 	this.log.debug("Running " + command + 
1625 		       " on '" + xxxFile.getName()+ "'. ");
1626 	String[] args = buildArguments(this.settings.getMakeGlossariesOptions(),
1627 				       xxxFile);
1628 	// may throw BuildFailureException TEX01, 
1629 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1630 	this.executor.execute(xxxFile.getParentFile(), //workingDir 
1631 			      this.settings.getTexPath(), 
1632 			      command, 
1633 			      args,
1634 			      desc.glsFile);
1635 
1636 	// detect errors and warnings makeglossaries wrote into xxx.glg 
1637 	File glgFile = desc.glgFile;
1638 	// may log EAP01, EAP02, WAP04, WFU03
1639 	logErrs (glgFile, command, this.settings.getPatternErrMakeGlossaries());
1640 	// may log warnings WFU03, WAP03, WAP04
1641 	logWarns(glgFile, command, this.settings.getPatternWarnMakeIndex() 
1642 		 +           "|" + this.settings.getPatternWarnXindy());
1643 	return true;
1644     }
1645 
1646     /**
1647      * Runs the LaTeX command given by {@link Settings#getLatex2pdfCommand()} 
1648      * on the latex main file <code>texFile</code> 
1649      * described by <code>desc</code> 
1650      * in the directory containing <code>texFile</code> with arguments 
1651      * given by {@link #buildLatexArguments(Settings, LatexDev, File)}. 
1652      * The output format of the LaTeX run is given by <code>dev</code>, 
1653      * to be more precise by {@link LatexDev#getLatexOutputFormat()}. 
1654      * <p>
1655      * Logs a warning or an error if the latex run failed 
1656      * invoking {@link #logErrs(File, String)}
1657      * but not if bad boxes occurred or if warnings occurred. 
1658      * This is done in 
1659      * {@link #processLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)} 
1660      * after the last LaTeX run only. 
1661      * <p>
1662      * Logging: 
1663      * <ul>
1664      * <li> EAP01: Running <code>latex2pdf</code> failed. For details...
1665      * <li> EAP02: Running <code>latex2pdf</code> failed. No log file 
1666      * <li> WAP04: .log-file is not readable. 
1667      * <li> WFU03: cannot close .log-file 
1668      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1669      * if running the latex2pdf command failed. 
1670      * </ul>
1671      *
1672      * @param desc
1673      *    the description of a latex main file <code>texFile</code> 
1674      *    to be processed. 
1675      * @param dev
1676      *    the device describing the output format which is either pdf or dvi. 
1677      *    See {@link LatexDev#getLatexOutputFormat()}. 
1678      * @throws BuildFailureException
1679      *    TEX01 if invocation of the latex2pdf command 
1680      *    returned by {@link Settings#getLatex2pdfCommand()} failed. 
1681      */
1682     private void runLatex2dev(LatexMainDesc desc, LatexDev dev)
1683 	throws BuildFailureException {
1684 
1685 	File texFile = desc.texFile;
1686 	// FIXME: wrong name; better is latex2dev
1687 	String command = this.settings.getLatex2pdfCommand();
1688 	this.log.debug("Running " + command + 
1689 		       " on '" + texFile.getName() + "'. ");
1690 	String[] args = buildLatexArguments(this.settings, dev, texFile);
1691 	// may throw BuildFailureException TEX01, 
1692 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1693         this.executor.execute(texFile.getParentFile(), // workingDir 
1694 			      this.settings.getTexPath(), 
1695 			      command, 
1696 			      args,
1697 			      dev.latexTargetFile(desc));
1698 
1699 	// logging errors (warnings are done in processLatex2pdf)
1700 	// may log EAP01, EAP02, WAP04, WFU03
1701 	logErrs(desc.logFile, command);
1702 
1703 	// FIXME: documentation that in the dvi file, 
1704 	// png, jpg and svg are not visible, but present. 
1705     }
1706 
1707     // also for tests 
1708     protected static String[] buildLatexArguments(Settings settings,
1709 						  LatexDev dev,
1710 						  File texFile) {
1711 	// FIXME: hack with literal 
1712 	return buildArguments(settings.getLatex2pdfOptions() + 
1713 			      " -output-format=" + dev.getLatexOutputFormat(), 
1714 			      texFile);
1715     }
1716 
1717     /**
1718      * Runs conversion from dvi to pdf-file  
1719      * executing {@link Settings#getDvi2pdfCommand()} 
1720      * on a dvi-file covered by <code>desc</code> with arguments 
1721      * given by {@link #buildLatexArguments(Settings, LatexDev, File)}. 
1722      * <p>
1723      * Logging: 
1724      * <ul>
1725      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1726      * if running the dvi2pdf command failed. 
1727      * </ul>
1728      *
1729      * @param desc
1730      *    the description of a latex main file <code>dviFile</code> 
1731      *    including the dvi-file dvi2pdf is to be run on. 
1732      * @throws BuildFailureException
1733      *    TEX01 if invocation of the dvi2pdf command 
1734      *    returned by {@link Settings#getDvi2pdfCommand()} failed. 
1735      */
1736     // used in processLatex2pdf(File) and processLatex2txt(File) only 
1737     private void runDvi2pdf(LatexMainDesc desc) throws BuildFailureException {
1738 	assert this.settings.getPdfViaDvi().isViaDvi();
1739 
1740 	String command = this.settings.getDvi2pdfCommand();
1741 	this.log.debug("Running " + command + 
1742 		       " on '" + desc.dviFile.getName() + "'. ");
1743 	String[] args = buildArguments(this.settings.getDvi2pdfOptions(), 
1744 				       desc.dviFile);
1745 	// may throw BuildFailureException TEX01, 
1746 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1747  	this.executor.execute(desc.texFile.getParentFile(), // workingDir 
1748 			      this.settings.getTexPath(), 
1749 			      command, 
1750 			      args,
1751 			      desc.pdfFile);
1752 	// FIXME: what about error logging? 
1753 	// Seems not to create a log-file. 
1754     }
1755 
1756     /**
1757      * Runs the tex4ht command given by {@link Settings#getTex4htCommand()} 
1758      * on <code>texFile</code> described by <code>desc</code> 
1759      * in the directory containing <code>texFile</code> 
1760      * with arguments given by {@link #buildHtlatexArguments(Settings, File)}. 
1761      * <p>
1762      * Logging: 
1763      * <ul>
1764      * <li> EAP01: Running <code>htlatex</code> failed. For details...
1765      * <li> EAP02: Running <code>htlatex</code> failed. No log file 
1766      * <li> WLP03: <code>htlatex</code> created bad boxes 
1767      * <li> WLP04: <code>htlatex</code> emitted warnings 
1768      * <li> WAP04: log file is not readable. 
1769      * <li> WFU03: cannot close log file 
1770      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1771      * if running the tex4ht command failed. 
1772      * </ul>
1773      *
1774      * @param desc
1775      *    the description of a latex main file <code>texFile</code> 
1776      *    to be processed. 
1777      * @throws BuildFailureException
1778      *    TEX01 if invocation of the tex4ht command 
1779      *    returned by {@link Settings#getTex4htCommand()} failed. 
1780      */
1781     private void runLatex2html(LatexMainDesc desc)
1782 	throws BuildFailureException {
1783 
1784 	File texFile = desc.texFile;
1785 	String command = this.settings.getTex4htCommand();
1786         this.log.debug("Running " + command + 
1787 		       " on '" + texFile.getName() + "'. ");
1788         String[] args = buildHtlatexArguments(this.settings, texFile);
1789 	// may throw BuildFailureException TEX01, 
1790 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1791         this.executor.execute(texFile.getParentFile(), // workingDir 
1792 			      this.settings.getTexPath(), 
1793 			      command, 
1794 			      args,
1795 			      this.fileUtils.replaceSuffix(texFile, 
1796 							   SUFFIX_HTML));
1797 
1798 	// logging errors and warnings 
1799 	// may log EAP01, EAP02, WAP04, WFU03
1800 	logErrs (desc.logFile, command);
1801 	// may log warnings WFU03, WAP04, WLP03, WLP04 
1802 	logWarns(desc.logFile, command);
1803     }
1804 
1805     protected static String[] buildHtlatexArguments(Settings settings, 
1806 						    File texFile) {
1807         return new String[] {
1808 	    texFile.getName(),
1809 	    settings.getTex4htStyOptions(),
1810 	    settings.getTex4htOptions(),
1811 	    settings.getT4htOptions(),
1812 	    settings.getLatex2pdfOptions()
1813 	};
1814     }
1815 
1816     /**
1817      * Runs the latex2rtf command 
1818      * given by {@link Settings#getLatex2rtfCommand()} 
1819      * on <code>texFile</code> 
1820      * in the directory containing <code>texFile</code> 
1821      * with arguments given by {@link #buildArguments(String, File)}. 
1822      * <p>
1823      * Logging: 
1824      * <ul>
1825      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1826      * if running the latex2rtf command failed. 
1827      * </ul>
1828      *
1829      * @param texFile
1830      *    the latex file to be processed. 
1831      * @throws BuildFailureException
1832      *    TEX01 if invocation of the latex2rtf command 
1833      *    returned by {@link Settings#getLatex2rtfCommand()} failed. 
1834      */
1835     private void runLatex2rtf(File texFile) throws BuildFailureException {
1836 	String command = this.settings.getLatex2rtfCommand();
1837         this.log.debug("Running " + command + 
1838 		       " on '" + texFile.getName() + "'. ");
1839         String[] args = buildArguments(this.settings.getLatex2rtfOptions(), 
1840 				       texFile);
1841 	// may throw BuildFailureException TEX01, 
1842 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1843         this.executor.execute(texFile.getParentFile(), // workingDir
1844 			      this.settings.getTexPath(), 
1845 			      command, 
1846 			      args,
1847 			      this.fileUtils.replaceSuffix(texFile,SUFFIX_RTF));
1848 
1849 	// FIXME: no check: just warning that no output has been created. 
1850 	// Warnings and error messages are output to stderr 
1851 	// and by default listed in the console window. 
1852 	// aThey can be redirected to a file “latex2rtf.log” by
1853 	// appending 2>latex2rtf.log to the command line.
1854    }
1855 
1856     /**
1857      * Runs conversion from latex to odt 
1858      * executing {@link Settings#getTex4htCommand()} 
1859      * on <code>texFile</code> 
1860      * in the directory containing <code>texFile</code> with arguments 
1861      * given by {@link #buildLatexArguments(Settings, LatexDev, File)}. 
1862      * <p>
1863      * Logs a warning or an error if the latex run failed 
1864      * invoking {@link #logErrs(File, String)}
1865      * but not if bad boxes ocurred or if warnings occurred. 
1866      * This is done in 
1867      * {@link #processLatex2dev(LatexProcessor.LatexMainDesc, LatexDev)} 
1868      * after the last LaTeX run only. 
1869      * <p>
1870      * Logging: 
1871      * <ul>
1872      * <li> EAP01: Running <code>htlatex</code> failed. For details...
1873      * <li> EAP02: Running <code>htlatex</code> failed. No log file 
1874      * <li> WLP03: <code>htlatex</code> created bad boxes 
1875      * <li> WLP04: <code>htlatex</code> emitted warnings 
1876      * <li> WAP04: log file is not readable. 
1877      * <li> WFU03: cannot close log file 
1878      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1879      * if running the tex4ht command failed. 
1880      * </ul>
1881      *
1882      * @param desc
1883      *    the descriptor of the latex main file to be processed. 
1884      * @throws BuildFailureException
1885      *    TEX01 if invocation of the tex4ht command 
1886      *    returned by {@link Settings#getTex4htCommand()} failed. 
1887      */
1888     private void runLatex2odt(LatexMainDesc desc) throws BuildFailureException {
1889 	File texFile = desc.texFile;
1890 	String command = this.settings.getTex4htCommand();
1891         this.log.debug("Running " + command + 
1892 		       " on '" + texFile.getName() + "'. ");
1893         String[] args = new String[] {
1894 	    texFile.getName(),
1895 	    "xhtml,ooffice", // there is no choice here 
1896 	    "ooffice/! -cmozhtf",// ooffice/! represents a font direcory 
1897 	    "-coo -cvalidate"// -coo is mandatory, -cvalidate is not 
1898 	};
1899 	// may throw BuildFailureException TEX01, 
1900 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1901         this.executor.execute(texFile.getParentFile(), 
1902 			      this.settings.getTexPath(), 
1903 			      command, 
1904 			      args,
1905 			      this.fileUtils.replaceSuffix(texFile,SUFFIX_ODT));
1906 
1907 	// FIXME: logging refers to latex only, not to tex4ht or t4ht script 
1908 	// may log EAP01, EAP02, WAP04, WFU03
1909 	logErrs (desc.logFile, command);
1910 	// may log warnings WFU03, WAP04, WLP03, WLP04 
1911 	logWarns(desc.logFile, command);
1912     }
1913 
1914 
1915     // FIXME: missing options. 
1916     // above all (input) doctype: -ddoc, -ddocx 
1917     // and (output) doctype: -fdoc, -fdocx, 
1918     // available: odt2doc --show. 
1919     // among those also: latex and rtf !!!!!! 
1920     // This is important to define the copy filter accordingly 
1921     /**
1922      * Runs conversion from odt to doc or docx-file  
1923      * executing {@link Settings#getOdt2docCommand()} 
1924      * on an odt-file created from <code>texFile</code> 
1925      * in the directory containing <code>texFile</code> with arguments 
1926      * given by {@link #buildLatexArguments(Settings, LatexDev, File)}. 
1927      * <p>
1928      * Logging: 
1929      * <ul>
1930      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1931      * if running the odt2doc command failed. 
1932      * </ul>
1933      *
1934      * @param texFile
1935      *    the latex file to be processed. 
1936      * @throws BuildFailureException
1937      *    TEX01 if invocation of the odt2doc command 
1938      *    returned by {@link Settings#getOdt2docCommand()} failed. 
1939      */
1940     private void runOdt2doc(File texFile) throws BuildFailureException {
1941 	File odtFile = this.fileUtils.replaceSuffix(texFile, SUFFIX_ODT);
1942 	String command = this.settings.getOdt2docCommand();
1943 	this.log.debug("Running " + command + 
1944 		       " on '" + odtFile.getName() + "'. ");
1945 	String[] args = buildArguments(this.settings.getOdt2docOptions(),
1946 				       odtFile);
1947 	String suffix = null;
1948 	for (int idx = 0; idx < args.length -1; idx++) {
1949 	    // FIXME: -f is hardcoded 
1950 	    if (args[idx].startsWith("-f")) {
1951 		assert suffix == null;// -f comes once only 
1952 		// without leading '-f'
1953 		suffix = args[idx].substring(2, args[idx].length());
1954 	    }
1955 	}
1956 	assert suffix != null;
1957 	// may throw BuildFailureException TEX01, 
1958 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1959 	this.executor.execute(texFile.getParentFile(), 
1960 			      this.settings.getTexPath(), 
1961 			      command, 
1962 			      args,
1963 			      this.fileUtils.replaceSuffix(texFile, suffix));
1964  	// FIXME: what about error logging? 
1965 	// Seems not to create a log-file. 
1966      }
1967 
1968     /**
1969      * Runs conversion from pdf to txt-file  
1970      * executing {@link Settings#getPdf2txtCommand()} 
1971      * on a pdf-file created from <code>texFile</code> 
1972      * in the directory containing <code>texFile</code> with arguments 
1973      * given by {@link #buildLatexArguments(Settings, LatexDev, File)}. 
1974      * <p>
1975      * Logging: 
1976      * <ul>
1977      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1978      * if running the pdf2txt command failed. 
1979      * </ul>
1980      *
1981      * @param texFile
1982      *    the latex-file to be processed. 
1983      * @throws BuildFailureException
1984      *    TEX01 if invocation of the pdf2txt command 
1985      *    returned by {@link Settings#getPdf2txtCommand()} failed. 
1986      */
1987     private void runPdf2txt(File texFile) throws BuildFailureException {
1988 	File pdfFile = this.fileUtils.replaceSuffix(texFile, SUFFIX_PDF);
1989 	String command = this.settings.getPdf2txtCommand();
1990 	this.log.debug("Running " + command + 
1991 		       " on '" + pdfFile.getName() + "'. ");
1992 	String[] args = buildArguments(this.settings.getPdf2txtOptions(),
1993 				       pdfFile);
1994 	// may throw BuildFailureException TEX01, 
1995 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
1996 	this.executor.execute(texFile.getParentFile(), 
1997 			      this.settings.getTexPath(), 
1998 			      command, 
1999 			      args, 
2000 			      this.fileUtils.replaceSuffix(texFile,SUFFIX_TXT));
2001 	// FIXME: what about error logging? 
2002 	// Seems not to create a log-file. 
2003     }
2004 
2005     /**
2006      * Runs the check command given by {@link Settings#getChkTexCommand()} 
2007      * on the latex main file <code>texFile</code> 
2008      * in the directory containing <code>texFile</code> 
2009      * creating a log file with ending {@link #SUFFIX_CLG} 
2010      * in that directory. 
2011      * <p>
2012      * Logging: 
2013      * <ul>
2014      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
2015      * if running the ChkTeX command failed. 
2016      * </ul>
2017      *
2018      * @param texFile
2019      *    the latex main file to be checked for. 
2020      * @throws BuildFailureException
2021      *    TEX01 if invocation of the check command 
2022      *    returned by {@link Settings#getChkTexCommand()} failed. 
2023      */
2024     private void runCheck(File texFile) throws BuildFailureException {
2025 	// 
2026 	File clgFile = this.fileUtils.replaceSuffix(texFile, SUFFIX_CLG);
2027 	String command = this.settings.getChkTexCommand();
2028 	this.log.debug("Running " + command + 
2029 		       " on '" + texFile.getName() + "'. ");
2030 	String[] args = buildChkTexArguments(this.settings.getChkTexOptions(), 
2031 					     texFile,
2032 					     clgFile);
2033 	// may throw BuildFailureException TEX01, 
2034 	// may log warning EEX01, EEX02, EEX03, WEX04, WEX05 
2035 	this.executor.execute(texFile.getParentFile(), 
2036 			      this.settings.getTexPath(), 
2037 			      command, 
2038 			      args, 
2039 			      clgFile);
2040 	if (!clgFile.exists()) {
2041 	    // Here, chktex could not perform the check 
2042 	    // but the failure is already logged. 
2043 	    return;
2044 	}
2045 	// assert !clgFile.isDirectory();
2046 	if (clgFile.length() != 0) {
2047 	    // FIXME: maybe we shall distinguish errors/warnings/messages
2048 	    this.log.warn("WLP06: Running " + command + 
2049 			  " found issues logged in '" + 
2050 			  texFile.getName() + "'. ");
2051 	}
2052     }
2053 
2054     /**
2055      * Returns an array of strings, 
2056      * each entry with a single option given by <code>options</code> 
2057      * except the last three which represent <code>-o clgFile texFile</code>. 
2058      *
2059      * @param options
2060      *    the options string. The individual options 
2061      *    are expected to be separated by a single blank. 
2062      * @param texFile
2063      *    the latex main file to be checked. 
2064      * @param clgFile
2065      *    the log-file with the result of the check of <code>texFile</code>. 
2066      * @return
2067      *    An array of strings: 
2068      *    If <code>options</code> is not empty, 
2069      *    the first entries are the options in <code>options</code>. 
2070      *    The last three entries are 
2071      *    <code>-o</code>, <code>clgFile</code> and <code>texFile</code>. 
2072      */
2073     protected static String[] buildChkTexArguments(String options, 
2074 						   File texFile, 
2075 						   File clgFile) {
2076     	if (options.isEmpty()) {
2077     	    return new String[] {
2078 		"-o", 
2079 		clgFile.getName(),
2080 		texFile.getName()
2081 	    };
2082     	}
2083         String[] optionsArr = options.split(" ");
2084         String[] args = Arrays.copyOf(optionsArr, optionsArr.length + 3);
2085         args[optionsArr.length ] = "-o";
2086         args[optionsArr.length+1] = clgFile.getName();
2087         args[optionsArr.length+2] = texFile.getName();
2088 	
2089     	return args;
2090      }
2091 
2092  }