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 java.io.File;
22  import java.io.FileFilter;
23  
24  import java.util.Iterator;
25  import java.util.Collection;
26  import java.util.TreeSet;
27  import java.util.Map;
28  import java.util.TreeMap;
29  
30  /**
31   * The latex pre-processor is for preprocessing graphic files 
32   * in formats which cannot be included directly into a latex-file 
33   * and in finding the latex main files 
34   * which is done in {@link #processGraphicsSelectMain(File, DirNode)} 
35   * and in clearing the created files from the latex source directory 
36   * in {@link #clearCreated(File)}. 
37   */
38  public class LatexPreProcessor extends AbstractLatexProcessor {
39  
40      /**
41       * Maps the suffix to the according handler. 
42       * If the handler is <code>null</code>, there is no handler. 
43       */
44      private final static Map<String, SuffixHandler> SUFFIX2HANDLER = 
45  	new TreeMap<String, SuffixHandler>();
46  
47      static {
48  	for (SuffixHandler handler : SuffixHandler.values()) {
49  	    SUFFIX2HANDLER.put(handler.getSuffix(), handler);
50  	}
51      } // static 
52  
53   
54      // used in preprocessing only and in TexFileUtils for a workaround 
55      final static String SUFFIX_TEX = ".tex";
56  
57      // home-brewed ending to represent tex including postscript 
58      final static String SUFFIX_PTX = ".ptx";
59      // the next two for preprocessing and in LatexDev only 
60      final static String SUFFIX_PDFTEX = ".pdf_tex";
61      final static String SUFFIX_EPSTEX = ".eps_tex";
62  
63      // suffix for xfig
64      private final static String SUFFIX_FIG = ".fig";
65      // suffix for svg
66      private final static String SUFFIX_SVG = ".svg";
67      // suffix for gnuplot
68      // FIXME: to be made configurable 
69      private final static String SUFFIX_GP = ".gp";
70      // suffix for metapost
71      private final static String SUFFIX_MP  = ".mp";
72      // from xxx.mp creates xxx1.mps, xxx.log and xxx.mpx 
73      private final static String SUFFIX_MPS = ".mps";
74      private final static String SUFFIX_MPX = ".mpx";
75  
76      // just for message 
77      private final static String SUFFIX_JPG = ".jpg";
78      private final static String SUFFIX_PNG = ".png";
79      // just for silently skipping 
80      private final static String SUFFIX_BIB = ".bib";
81      // for latex main file creating html and for graphics. 
82      final static String SUFFIX_EPS = ".eps";
83  
84      private final static String SUFFIX_XBB = ".xbb";
85      private final static String SUFFIX_BB  = ".bb";
86  
87  
88      LatexPreProcessor(Settings settings, 
89  		      CommandExecutor executor, 
90  		      LogWrapper log, 
91  		      TexFileUtils fileUtils) {
92  	super(settings, executor, log, fileUtils);
93       }
94  
95  
96  
97      // Formats that work with LaTeX (dvi mode, using dvips):
98      //     eps
99      // Formats that work with LaTeX (dvi mode, using dvipdfm(x)):
100     //     pdf, png, jpeg, eps (the latter not taken into account) 
101     //     eps-source files handled via package epstopdf: 
102     //     seemingly automatically converted eps-->pdf during latex run 
103     //     also there is a program epstopdf and epspdf 
104     //     There is a lot of experiments to do!! 
105     //     MISSING: pdf and eps 
106     //     NOTE: graphics is typically only included via dvipdfm(x)
107     // Formats that work with pdfLaTeX (pdf mode):
108     //     pdf, png, jpeg, jbig2 (the latter not taken into account)
109     // LuaTeX can also read
110     //     jpeg 2000 (not taken into account)
111     //
112     // Seemingly, it makes sense to distinguish from pdfViaDvi-parameter: 
113     // if set, seemingly, pdf, pgn and jpg is includable only 
114     // creating .bb or .xbb.  
115 
116     // mp: besides mpost we also have mptopdf creating pdf: 
117     // mptopdf 05someMetapost.mp   creates 05someMetapost1.mps
118     // mptopdf 05someMetapost1.mps creates 05someMetapost1-mps.pdf 
119 
120 
121 
122     /**
123      * Handler for each suffix of a source file. 
124      * Mostly, these represent graphic formats 
125      * but also {@link #SUFFIX_TEX} is required 
126      * to detect the latex main files 
127      * and {@link #SUFFIX_TEX} and {@link #SUFFIX_BIB} 
128      * are needed for proper cleaning of the tex souce directory. 
129      */
130     enum SuffixHandler {
131 	/**
132 	 * Handler for .fig-files representing the native xfig format. 
133 	 */
134 	fig {
135 	    // converts a fig-file into pdf and ptx 
136 	    // invoking {@link #runFig2Dev(File, LatexDev)}
137 	    // TEX01, EEX01, EEX02, EEX03, WEX04, WEX05 
138 	    void procSrc(File file, LatexPreProcessor proc) 
139 		throws BuildFailureException {
140 
141 		// may throw BuildFailureException TEX01, 
142 		// may log EEX01, EEX02, EEX03, WEX04, WEX05 
143 		proc.runFig2Dev(file);
144 	    }
145 	    void clearTarget(File file, LatexPreProcessor proc) {
146 		// may log EFU05 
147 		proc.clearTargetPtxPdfEps(file);
148 	    }
149 	    String getSuffix() {
150 		return LatexPreProcessor.SUFFIX_FIG;
151 	    }
152 	},
153 	/**
154 	 * Handler for .gp-files representing the native gnuplot format. 
155 	 */
156 	gp {
157 	    // converts a gnuplot-file into pdf and ptx 
158 	    // invoking {@link #runGnuplot2Dev(File, LatexDev)} 
159 	    // TEX01, EEX01, EEX02, EEX03, WEX04, WEX05 
160 	    void procSrc(File file, LatexPreProcessor proc) 
161 		throws BuildFailureException {
162 		proc.runGnuplot2Dev(file);
163 	    }
164 	    void clearTarget(File file, LatexPreProcessor proc) {
165 		// may log EFU05 
166 		proc.clearTargetPtxPdfEps(file);
167 	    }
168 	    String getSuffix() {
169 		return LatexPreProcessor.SUFFIX_GP;
170 	    }
171 	},
172 	/**
173 	 * Handler for .mp-files representing the metapost format. 
174 	 */
175 	mp {
176 	    // converts a metapost-file into mps-format 
177 	    // invoking {@link #runMetapost2mps(File)} 
178 	    // TEX01, EEX01, EEX02, EEX03, WEX04, WEX05 
179 	    void procSrc(File file, LatexPreProcessor proc) 
180 		throws BuildFailureException {
181 		proc.runMetapost2mps(file);
182 	    }
183 	    void clearTarget(File file, LatexPreProcessor proc) {
184 		// may log WFU01, EFU05 
185 		proc.clearTargetMp(file);
186 	    }
187 	    String getSuffix() {
188 		return LatexPreProcessor.SUFFIX_MP;
189 	    }
190 	},
191 	/**
192 	 * Handler for .svg-files representing scaleable vector graphics. 
193 	 */
194 	svg {
195 	    // converts an svg-file into pdf and ptx 
196 	    // invoking {@link #runFig2Dev(File, LatexDev)}
197 	    // TEX01, EEX01, EEX02, EEX03, WEX04, WEX05 
198 	    // EFU07, EFU08, EFU09 if filtering a file fails. 
199 	    void procSrc(File file, LatexPreProcessor proc) 
200 		throws BuildFailureException {
201 		proc.runSvg2Dev(file);
202 		// proc.log.info("Processing svg-file '" + file + 
203 		//  	      "' deferred to LaTeX run by need. ");
204 		// FIXME: this works for pdf but not for dvi: 
205 		// even in the latter case, .pdf and .pdf_tex are created 
206 	    }
207 	    void clearTarget(File file, LatexPreProcessor proc) {
208 		// may log EFU05 
209 		proc.clearTargetPtxPdfEps(file);
210 	    }
211 	    String getSuffix() {
212 		return LatexPreProcessor.SUFFIX_SVG;
213 	    }
214 	},
215 	/**
216 	 * Handler for .jpg-files representing a format 
217 	 * defined by the Joint Photographic Experts Group (jp(e)g). 
218 	 */
219 	jpg {
220 	    void procSrc(File file, LatexPreProcessor proc) 
221 		throws BuildFailureException {
222 		proc.log.info("Jpg-file '" + file + "' needs no processing. ");
223 		// FIXME: this works for pdf but not for dvi: 
224 		// in the latter case: 
225 		// ! LaTeX Error: Cannot determine size of graphic ...
226 		// FIXME: only for dvi 
227 //		proc.runEbb(file);
228 	    }
229 	    // void clearTarget(File file, 
230 	    // 		     LatexPreProcessor proc, 
231 	    // 		     Map<File, SuffixHandler> file2handler) {
232 	    // 	// do not add to file2handler 
233 	    // }
234 	    void clearTarget(File file, LatexPreProcessor proc) {
235 		// throw new IllegalStateException
236 		//     ("File '" + file + "' has no targets to be cleared. ");
237 		proc.clearTargetJpgPng(file);
238 	    }
239 	    String getSuffix() {
240 		return LatexPreProcessor.SUFFIX_JPG;
241 	    }
242 	},
243 	/**
244 	 * Handler for .png-files 
245 	 * representing the Portable Network Graphics format. 
246 	 */
247 	png {
248 	    void procSrc(File file, LatexPreProcessor proc) 
249 		throws BuildFailureException {
250 		proc.log.info("Png-file '" + file + "' needs no processing. ");
251 		// FIXME: this works for pdf but not for dvi: 
252 		// in the latter case: 
253 		// ! LaTeX Error: Cannot determine size of graphic ...
254 		// FIXME: only for dvi 
255 //		proc.runEbb(file);
256 	    }
257 	    // void clearTarget(File file, 
258 	    // 		     LatexPreProcessor proc, 
259 	    // 		     Map<File, SuffixHandler> file2handler) {
260 	    // 	// do not add to file2handler 
261 	    // }
262 	    void clearTarget(File file, LatexPreProcessor proc) {
263 		// throw new IllegalStateException
264 		//     ("File '" + file + "' has no targets to be cleared. ");
265 		proc.clearTargetJpgPng(file);
266 	    }
267 	    String getSuffix() {
268 		return LatexPreProcessor.SUFFIX_PNG;
269 	    }
270 	},
271 	/**
272 	 * Handler for .tex-files 
273 	 * representing the TeX format, to be more precise the LaTeX format. 
274 	 */
275 	tex {
276 	    void scheduleProcSrc(File file, 
277 				 Map<File, SuffixHandler> file2handler, 
278 				 LatexPreProcessor proc, 
279 				 Collection<File> latexMainFiles) {
280 		file2handler.put(file, this);// super 
281 		// may log WFU03, WPP02 
282 		proc.addIfLatexMain(file, latexMainFiles);
283 	    }
284 
285 
286 	    void procSrc(File file, LatexPreProcessor proc) {
287 		// do nothing: no source 
288 	    }
289 	    void clearTarget(File file, 
290 			     LatexPreProcessor proc, 
291 			     Map<File, SuffixHandler> file2handler) {
292 		// may log WPP02, WFU01, WFU03, EFU05 
293 		proc.clearTargetTexIfLatexMain(file);
294 	    }
295 	    void clearTarget(File file, LatexPreProcessor proc) {
296 		throw new IllegalStateException
297 		    ("Clearing targets of '" + file + 
298 		     "' should have been done already. ");
299 	    }
300 
301 	    String getSuffix() {
302 		return LatexPreProcessor.SUFFIX_TEX;
303 	    }
304 	},
305 	/**
306 	 * Handler for .bib-files 
307 	 * representing the BibTeX format for bibliographies. 
308 	 */
309 	bib {
310 	    void procSrc(File file, LatexPreProcessor proc) {
311 		proc.log.info("Found bibliography file '" + file + "'. ");
312 	    }
313 	    void clearTarget(File file, 
314 			     LatexPreProcessor proc, 
315 			     Map<File, SuffixHandler> file2handler) {
316 		// do not add to file2handler 
317 	    }
318 	    void clearTarget(File file, LatexPreProcessor proc) {
319 		throw new IllegalStateException
320 		    ("File '" + file + "' has no targets to be cleared. ");
321 	    }
322 	    String getSuffix() {
323 		return LatexPreProcessor.SUFFIX_BIB;
324 	    }
325 	};
326 
327 	// essentially, maps file to its handler 
328 	// overwritten for tex: in addition add to latexMainFiles 
329 	void scheduleProcSrc(File file, 
330 			     Map<File, SuffixHandler> file2handler, 
331 			     LatexPreProcessor proc, 
332 			     Collection<File> latexMainFiles) {
333 	    file2handler.put(file, this);
334 	}
335 
336 	// FIXME: to be updated 
337 	// if a graphic format: process source. 
338 	// For tex and for bib: do nothing. 
339 	/**
340 	 * Typically, .i.e. for {@link #fig}-,  {@link #gp}-,  {@link #mp}- 
341 
342 	 * and associates <code>file</code> 
343 	 * Does the transformation of the file <code>file</code> 
344 	 * using <code>proc</code> immediately, except for 
345 	 * <ul>
346 	 * <li>
347 	 * {@link #svg}-files for which an info message is logged, 
348 	 * that transformation is done by need in the course of a LaTeX run. 
349 	 * What occurs are files .pdf and .pdf_tex 
350 	 * even if {@link Settings#pdfViaDvi} indicates creation of dvi files. 
351 	 * <li>
352 	 * {@link #tex}-files which are only scheduled for later translation 
353 	 * just by adding them to <code>latexMainFiles</code> 
354 	 * if they are latex main files, and ignored otherwise 
355 	 * (see {@link LatexPreProcessor#addIfLatexMain(File, Collection)}). 
356 	 * <li>
357 	 * {@link #bib}-files for which just an info message 
358 	 * that a bib file was found is logged. 
359 	 * </ul>
360 	 * <p>
361 	 * Logging: 
362 	 * <ul>
363 	 * <li> WFU03: cannot close 
364 	 * <li> WPP02: tex file may be latex main file 
365 	 * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
366 	 * if applications for preprocessing graphic files failed. 
367 	 * <li> EFU07, EFU08, EFU09 if filtering a file fails. 
368 	 * </ul>
369 	 *
370 	 * @param file
371 	 *    a file with ending given by {@link #getSuffix()}. 
372 	 * @param proc
373 	 *    a latex pre-processor. 
374 	 * @throws BuildFailureException
375 	 *    TEX01 only for {@link #fig}, {@link #gp} and {@link #mp} 
376 	 *    because these invoke external programs. 
377 	 */
378 	abstract void procSrc(File file, LatexPreProcessor proc)
379 	throws BuildFailureException;
380 
381 	/**
382 	 * Typically, .i.e. for {@link #fig}-,  {@link #gp}-,  {@link #mp}- 
383 	 * and {@link #svg}-files just associates <code>file</code> 
384 	 * with this handler in <code>file2handler</code> 
385 	 * to schedule according targets for deletion except for 
386 	 * <ul>
387 	 * <li>
388 	 * {@link #tex}-files for which the target is cleared immediately 
389 	 * if it is a latex main file, otherwise ignoring 
390 	 * by invoking {@link #clearTargetTexIfLatexMain(File)}. 
391 	 * <li>
392 	 * {@link #bib}-files 
393 	 * (maybe appropriate also for jpg-files and for png-files) 
394 	 * for which there are no targets 
395 	 * and so the association is not added to <code>file2handler</code>.  
396 	 * </ul>
397 	 * <p>
398 	 * Logging: 
399 	 * <ul>
400 	 * <li> WPP02: tex file may be latex main file 
401 	 * <li> WFU01: Cannot read directory...
402 	 * <li> WFU03: cannot close tex file 
403 	 * <li> EFU05: Failed to delete file 
404 	 * <ul>
405 	 *
406 	 * @param file
407 	 *    a file with ending given by {@link #getSuffix()}, 
408 	 *    i.e. a file which can be handled by this handler. 
409 	 * @param proc
410 	 *    a latex pre-processor. 
411 	 * @param file2handler
412 	 *    maps <code>file</code> to its handler. 
413 	 *    In general, this method adds 
414 	 *    <code>file</code> to <code>file2handler</code> 
415 	 *    together with its handler which is just <code>this</code>. 
416 	 * @see #clearTarget(File, LatexPreProcessor)
417 	 */
418 	// overwritten for tex, jpg, png and for bib 
419 	// appropriate for svg although file may be removed from map later 
420 	// used in clearCreated(File, DirNode) only 
421 	void clearTarget(File file, 
422 			 LatexPreProcessor proc, 
423 			 Map<File, SuffixHandler> file2handler) {
424 	    file2handler.put(file, this);
425 	}
426 
427 	/**
428 	 * Deletes the files potentially 
429 	 * created from the source file <code>file</code> 
430 	 * using <code>proc</code>. 
431 	 * <p>
432 	 * Logging: 
433 	 * <ul>
434 	 * <li> WFU01: Cannot read directory...
435 	 * <li> EFU05: Failed to delete file 
436 	 * <ul>
437 	 *
438 	 * @param file
439 	 *    a file with ending given by {@link #getSuffix()}. 
440 	 * @param proc
441 	 *    a latex pre-processor. 
442 	 * @throws IllegalStateException
443 	 *    <ul>
444 	 *    <li>
445 	 *    if <code>file</code> has no targets to be deleted 
446 	 *    as for jpg-files, png-files and bib-files. 
447 	 *    <li>
448 	 *    if targets of <code>file</code> should have been cleared already 
449 	 *    by {@link #clearTarget(File, LatexPreProcessor, Map)} 
450 	 *    as for tex-files. 
451 	 *    </ul>
452 	 * @see #clearTarget(File, LatexPreProcessor, Map)
453 	 */
454 	// used in clearCreated(File, DirNode) only 
455 	abstract void clearTarget(File file, LatexPreProcessor proc);
456 
457 	/**
458 	 * Returns the suffix of the file type 
459 	 * of the file type, this is the handler for. 
460 	 */
461 	abstract String getSuffix();
462     } // enum SuffixHandler 
463 
464     // FIXME: CAUTION with including pictures in xfig: 
465     // This is done as reference to included file. 
466     // Thus it breaks depencency chain. 
467 
468 
469 
470     // The following shows the supported formats: 
471 // l.10 \includegraphics{02gp2pdf000}
472 //                                   %
473 // I could not locate the file with any of these extensions:
474 // .pdf,.PDF,.ai,.AI,.png,.PNG,.jpg,.JPG,.jpeg,.JPEG,.bmp,.BMP,.ps,.PS,.eps,.EPS,.
475 // pz,.eps.Z,.ps.Z,.ps.gz,.eps.gz
476 // Try typing  <return>  to proceed.
477 // If that doesn't work, type  X <return>  to quit.
478 
479 // )
480 // :<-
481 // Package srcltx Info: Expanded filename `03someGnuplot.ptx' to `03someGnuplot.pt
482 // x.tex' on input line 949.
483 
484 // FIXME: allow variants: 
485 // - pdfhandler     on .pdf,.PDF,  (includable directly with pdflatex)
486 // - png/jpghandler on .png,.PNG,.jpg,.JPG,.jpeg,.JPEG,
487 // - maybe also for .fig 
488 
489 // FIXME: questions: 
490 // - how to include .pdf into .dvi? 
491 // - how to include .eps into .pdf? 
492 // Question: how to transform ps into eps? 
493 // Research on the following: 
494 // .ai,.AI,.bmp,.BMP,
495 // .ps,.PS,.eps,.EPS,.
496 // pz,.eps.Z,.ps.Z,.ps.gz,.eps.gz
497 
498     // FIXME: decide whether suffix .ptx is replaced by .tex: 
499     // Advantage: because this is what it is. 
500     // Disadvantage: Requires mechanism 
501     // to determine whether tex is created or original 
502     // but this works the same as for pdf and for svg. 
503 
504 
505     /**
506      * Converts the fig-file <code>figFile</code> 
507      * into a tex-file with ending ptx 
508      * including a pdf-file or an eps-file also created. 
509      * To that end, invokes {@link #runFig2DevInTex(File, LatexDev)} twice 
510      * to create a pdf-file and an eps-file 
511      * and invokes {@link #runFig2TexInclDev(File)} (once) 
512      * to create the tex-file. 
513      * <p>
514      * Logging: 
515      * <ul>
516      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
517      * if running the fig2dev command failed. 
518      * </ul>
519      *
520      * @param figFile
521      *    the fig file to be processed. 
522      * @throws BuildFailureException
523      *    TEX01 if invocation of the fig2dev command 
524      *    returned by {@link Settings#getFig2devCommand()} failed. 
525      *    This is invoked twice: once for creating the pdf-file 
526      *    and once for creating the pdf_t-file. 
527      * @see #processGraphicsSelectMain(File, DirNode)
528      */
529     // used in fig.procSrc(File, LatexPreProcessor) only 
530     private void runFig2Dev(File figFile) throws BuildFailureException {
531 	this.log.info("Processing fig-file '" + figFile + "'. ");
532 
533 	// all three 
534 	// may throw BuildFailureException TEX01, 
535 	// may log EEX01, EEX02, EEX03, WEX04, WEX05 
536 	runFig2DevInTex(figFile, LatexDev.pdf);
537 	runFig2DevInTex(figFile, LatexDev.dvips);
538 	runFig2TexInclDev(figFile);
539     }
540 
541     /**
542      * From <code>figFile</code> create pdf/eps-file 
543      * containing graphics without text with special flag set. 
544      * The output format depends on <code>dev</code>. 
545      * The resulting file is included in some tex-file 
546      * created by {@link #runFig2TexInclDev(File)}. 
547      * Conversion is done by {@link Settings#getFig2devCommand()}. 
548      * <p>
549      * Logging: FIXME: 
550      * EEX01, EEX02, EEX03, WEX04, WEX05 
551      *
552      * @param figFile
553      *    the fig-file to be processed 
554      * @param dev
555      *    represents the target: either a pdf-file or an eps-file. 
556      * @throws BuildFailureException 
557      *    FIXME: TEX01, 
558      */
559     private void runFig2DevInTex(File figFile, LatexDev dev) 
560 	throws BuildFailureException {
561 
562 	// Result file: either .pdf or .eps 
563 	File figInTexFile = this.fileUtils
564 	    .replaceSuffix(figFile, dev.getGraphicsInTexSuffix());
565 	String command = this.settings.getFig2devCommand();
566 
567 	//if (update(figFile, pdfFile)) {
568 	String[] args = 
569 	    buildArgumentsFig2PdfEps(dev.getXFigInTexLanguage(),
570 				     this.settings.getFig2devGenOptions(), 
571 				     this.settings.getFig2devPdfEpsOptions(), 
572 				     figFile,
573 				     figInTexFile);
574 	this.log.debug("Running " + command + " -L pdftex/pstex  ... on '" + 
575 		       figFile.getName() + "'. ");
576 	// may throw BuildFailureException TEX01, 
577 	// may log EEX01, EEX02, EEX03, WEX04, WEX05 
578 	this.executor.execute(figFile.getParentFile(), 
579 			      this.settings.getTexPath(), //**** 
580 			      command, 
581 			      args,
582 			      figInTexFile);
583 	//}
584     }
585 
586 
587     // 
588     // PSTEX Options:
589     //   -b width      specify width of blank border around figure (1/72 inch)
590     //            Found: affects clipping path and bounding box only. 
591     //            Not usable if latex text is used because parts no longer fit. 
592     //   -F            use correct font sizes (points instead of 1/80inch)
593     //            Found: no effect 
594     //   -g color      background color
595     //            No idea in which format color is given. 
596     //   -n name       set title part of PostScript output to name
597     //            Found: works. Without it is just the name of xxx.fig 
598     // 
599     // the strange thing is that this is only a subset of the postscript options
600     // to be verified whether all options apply or not. 
601 
602 // The EPS driver has the following differences from PostScript:
603 // o No showpage is generated 
604 //   because the output is meant to be imported 
605 //   into another program or document and not printed
606 // o The landscape/portrait options are ignored
607 // o The centering option is ignored
608 // o The multiple-page option is ignored
609 // o The paper size option is ignored
610 // o The x/y offset options are ignored 
611 
612 
613 // The EPS driver has the following two special options:
614 //
615 // -B 'Wx [Wy X0 Y0]'
616 //     This specifies that the bounding box of the EPS file 
617 //     should have the width Wx and the height Wy. 
618 //     Note that it doesn't scale the figure to this size, 
619 //     it merely sets the bounding box. 
620 //     If a value less than or equal to 0 is specified for Wx or Wy, 
621 //     these are set to the width/height respectively of the figure. 
622 //     Origin is relative to screen (0,0) (upper-left).
623 //      Wx, Wy, X0 and Y0 are interpreted 
624 //     in centimeters or inches depending on the measure 
625 //     given in the fig-file. 
626 //     Remember to put either quotes (") or apostrophes (') 
627 //     to group the arguments to -B. 
628 // -R 'Wx [Wy X0 Y0]'
629 //     Same as the -B option except that X0 and Y0 
630 //     is relative to the lower left corner of the figure. 
631 //     Remember to put either quotes (") or apostrophes (') 
632 //     to group the arguments to -R. 
633 
634 // The PDF driver uses all the PostScript options.
635 
636 
637 
638     // Explanation: many of these options do not make sense. 
639     // Tried: -x, -y to shift: does not work and does not make sense 
640     // What makes sense is 
641     // -a            don't output user's login name (anonymous)
642     //               Found: login name occurs nowhere with and without -a 
643     // -N            convert all colors to grayscale
644     //               Found: works 
645 
646 
647     // No information on PDFTEX options. 
648     // Instead: 
649     //
650     // PDF Options:
651     //   -a            don't output user's login name (anonymous)
652     //   -b width      specify width of blank border around figure (1/72 inch)
653     //   -F            use correct font sizes (points instead of 1/80inch)
654     //   -g color      background color
655     //
656     // seemingly not the same, so maybe separate options required. 
657     // -n is pstex but not in pdf, 
658     // -a is pdf but not pstex... strange: is postscript 
659 
660     /**
661      * Returns an array of options of the form 
662      * <code>-L &lt;language&gt; &lt;optionsGen&gt; &lt;optionsPdfEps&gt; xxx.fig xxx.pdf/xxx.eps 
663      * </code> for invocation of {@link Settings#getFig2devCommand()} 
664      * for creation of the pdf/eps-part of a fig-figure 
665      * as done in {@link #runFig2DevInTex(File, LatexDev)}. 
666      *
667      * @param language
668      *    is the output language 
669      *    which is either <code>pdftex</code> or <code>pstex</code> 
670      * @param optionsGen
671      *    the general options, applying to both the pdf/eps part 
672      *    and the tex part of the figure under consideration. 
673      * @param optionsPdfEps
674      *    the options, specific for the pdf/eps part (which is the same)
675      *    of the figure under consideration. 
676      * @param figFile
677      *    the fig-file to be transformed. 
678      * @param grpFile
679      *    the graphics file (pdf/eps-file) 
680      *    which is the result of the transformation. 
681      */
682     private String[] buildArgumentsFig2PdfEps(String language,
683 					      String optionsGen, 
684 					      String optionsPdfEps, 
685 					      File figFile, 
686 					      File grpFile) {
687 	String[] optionsGenArr    = optionsGen   .isEmpty() 
688 	    ? new String[0] : optionsGen   .split(" ");
689 	String[] optionsPdfEpsArr = optionsPdfEps.isEmpty() 
690 	    ? new String[0] : optionsPdfEps.split(" ");
691 	int lenSum = optionsGenArr.length + optionsPdfEpsArr.length;
692 
693 	// add the four additional options 
694 	String[] args = new String[lenSum + 4];
695 	// language 
696 	args[0] = "-L";
697 	args[1] = language;
698 	// general options 
699 	System.arraycopy(optionsGenArr,    0, args, 2, 
700 			 optionsGenArr   .length);
701 	// language specific options 
702 	System.arraycopy(optionsPdfEpsArr, 0, args, 2+optionsGenArr.length, 
703 			 optionsPdfEpsArr.length);
704 	// input: fig-file 
705         args[2+lenSum] = figFile.getName();
706 	// output: pdf/eps-file 
707 	args[3+lenSum] = grpFile.getName();
708 	return args;
709     }
710 
711     /**
712      * From <code>figFile</code> create tex-file 
713      * containing text with special flag set and 
714      * including a graphic file containing the rest of <code>figFile</code>. 
715      * Inclusion is without file extension and so both possible results 
716      * of {@link #runFig2DevInTex(File, LatexDev)} can be included 
717      * when compiling with latex. 
718      * Conversion is done by {@link Settings#getFig2devCommand()}. 
719      * <p>
720      * Logging: FIXME: 
721      * warning EEX01, EEX02, EEX03, WEX04, WEX05 
722      *
723      * @param figFile
724      *    the fig-file to be processed 
725      * @throws BuildFailureException 
726      *    FIXME: TEX01, 
727      */
728     private void runFig2TexInclDev(File figFile) 
729 	throws BuildFailureException {
730 
731 	// result file: .ptx 
732 	File ptxFile = this.fileUtils.replaceSuffix(figFile, SUFFIX_PTX);
733 	String command = this.settings.getFig2devCommand();
734 
735 	//if (update(figFile, pdf_tFile)) {
736 	String[] args = 
737 	    buildArgumentsFig2Ptx(this.settings.getFig2devGenOptions(), 
738 				  this.settings.getFig2devPtxOptions(), 
739 				  figFile, 
740 				  ptxFile);
741 	this.log.debug("Running " + command + 
742 		       " -L (pdf/ps)tex_t... on '" + figFile.getName() + "'. ");
743 	// may throw BuildFailureException TEX01, 
744 	// may log EEX01, EEX02, EEX03, WEX04, WEX05 
745 	this.executor.execute(figFile.getParentFile(), 
746 			      this.settings.getTexPath(), //**** 
747 			      command, 
748 			      args,
749 			      ptxFile);
750 	//}
751     }
752 
753     /**
754      * The name of the language 
755      * used by the {@link Settings#getFig2devCommand()} 
756      * to specify ``special'' text without graphic of an xfig-picture. 
757      * Note that the languages <code>pdftex_t</code> and <code>pstex_t</code> 
758      * are equivalent. 
759      */
760     private final static String XFIG_TEX_LANGUAGE = "pdftex_t";
761 
762     // Since pstex_t is equivalent with pdftex_t, 
763     // also the options are the same (hopefully) 
764     //
765     // PSTEX_T Options:
766     //   -b width      specify width of blank border around figure (1/72 inch)
767     //   -E num        set encoding for text translation (0 no translation,
768     //                   1 ISO-8859-1, 2 ISO-8859-2)
769     //   -F            don't set font family/series/shape, so you can
770     //                   set it from latex
771     //   -p name       name of the PostScript file to be overlaid
772 
773     /**
774      * Returns an array of options of the form 
775      * <code>-L &lt;language&gt; &lt;optionsGen&gt; &lt;optionsPdfEps&gt; -p xxx xxx.fig xxx.ptx</code> for invocation of {@link Settings#getFig2devCommand()} 
776      * for creation of the tex-part of a fig-figure 
777      * as done in {@link #runFig2TexInclDev(File)}. 
778      * Note that the option <code>-p xxx</code> 
779      * specifies the name of the pdf/eps-file 
780      * included in the result file <code>ptxFile</code> 
781      * without suffix. 
782      *
783      * @param optionsGen
784      *    the general options, applying to both the pdf/eps part 
785      *    and the tex part of the figure under consideration. 
786      * @param optionsPtx
787      *    the options, specific for the tex part 
788      *    of the figure under consideration (for the ptx-file). 
789      * @param figFile
790      *    the fig-file to be transformed. 
791      * @param ptxFile
792      *    the ptx-file which is the result of the transformation. 
793      */
794     private String[] buildArgumentsFig2Ptx(String optionsGen,
795 					   String optionsPtx,
796 					   File figFile, 
797 					   File ptxFile) {
798 	String[] optionsGenArr = optionsGen.isEmpty() 
799 	    ? new String[0] : optionsGen.split(" ");
800 	String[] optionsPtxArr = optionsPtx.isEmpty() 
801 	    ? new String[0] : optionsPtx.split(" ");
802 	int lenSum = optionsGenArr.length +optionsPtxArr.length;
803 
804 	// add the six additional options 
805 	String[] args = new String[lenSum + 6];
806 	// language 
807 	args[0] = "-L";
808 	args[1] = XFIG_TEX_LANGUAGE;
809 	// general options 
810 	System.arraycopy(optionsGenArr, 0, args, 2, 
811 			 optionsGenArr.length);
812 	// language specific options 
813 	System.arraycopy(optionsPtxArr, 0, args, 2+optionsGenArr.length, 
814 			 optionsPtxArr.length);
815 	// -p pdf/eps-file name in ptx-file without suffix 
816 	args[2+lenSum] = "-p";
817 	// full path without suffix 
818 	args[3+lenSum] = this.fileUtils.replaceSuffix(figFile, SUFFIX_VOID)
819 	    .getName();
820 	// input: fig-file 
821         args[4+lenSum] = figFile.getName();
822 	// output: ptx-file 
823 	args[5+lenSum] = ptxFile.getName();
824 	return args;
825     }
826 
827     /**
828      * Deletes the files <code>xxx.ptx</code>, <code>xxx.pdf</code> and 
829      * <code>xxx.eps</code>
830      * created from the graphic file <code>grpFile</code> 
831      * of the form <code>xxx.y</code>. 
832      * <p>
833      * Logging: 
834      * EFU05: Failed to delete file
835      *
836      * @param grpFile
837      *    a graphic file. 
838      */
839     // for formats fig, gp and svg: since all of these create ptx, pdf and eps 
840     private void clearTargetPtxPdfEps(File grpFile) {
841 	this.log.info("Deleting targets of file '" + grpFile + "'. ");
842 	// may log EFU05 
843 	deleteIfExists(grpFile, SUFFIX_PTX);
844 	deleteIfExists(grpFile, LatexDev.pdf  .getGraphicsInTexSuffix());// pdf 
845  	deleteIfExists(grpFile, LatexDev.dvips.getGraphicsInTexSuffix());// eps 
846     }
847 
848     /**
849      * Converts a gnuplot-file into a tex-file with ending ptx 
850      * including a pdf-file or an eps-file also created. 
851      * To that end, invokes {@link #runGnuplot2Dev(File, LatexDev)} twice 
852      * to create a pdf-file and an eps-file 
853      * and to create the tex-file which can include both. 
854      * <p>
855      * Logging: 
856      * <ul>
857      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
858      * if running the ptx/pdf-conversion built-in in gnuplot fails. 
859      * </ul>
860      *
861      * @param gpFile 
862      *    the gp-file (gnuplot format) to be converted to pdf and ptx. 
863      * @throws BuildFailureException
864      *    TEX01 if invocation of the ptx/pdf-conversion built-in 
865      *    in gnuplot fails. 
866      * @see #processGraphicsSelectMain(File, DirNode)
867      */
868     // used in gp.procSrc(File, LatexPreProcessor) only 
869     private void runGnuplot2Dev(File gpFile) throws BuildFailureException {
870 	this.log.info("Processing gnuplot-file '" + gpFile + "'. ");
871 	// both may throw BuildFailureException TEX01, 
872 	// and  may log EEX01, EEX02, EEX03, WEX04, WEX05 
873 	runGnuplot2Dev(gpFile, LatexDev.dvips);
874 	runGnuplot2Dev(gpFile, LatexDev.pdf);
875     }
876 
877     // may throw BuildFailureException TEX01, 
878     // may log EEX01, EEX02, EEX03, WEX04, WEX05 
879     private void runGnuplot2Dev(File gpFile, LatexDev dev) 
880 	throws BuildFailureException {
881 
882 	String command = this.settings.getGnuplotCommand();
883 	File grpFile = this.fileUtils.replaceSuffix
884 	    (gpFile, dev.getGraphicsInTexSuffix());
885 	File ptxFile = this.fileUtils.replaceSuffix(gpFile, SUFFIX_PTX);
886 
887 	String[] args = new String[] {
888 	    "-e",   // run a command string "..." with commands separated by ';' 
889 	    // 
890 	    "set terminal cairolatex " + dev.getGnuplotInTexLanguage() + 
891 	    " " + this.settings.getGnuplotOptions() + 
892 	    ";set output '" + ptxFile.getName() + 
893 	    "';load '" + gpFile.getName() + "'"
894 	};
895 
896 //	if (update(gpFile, ptxFile)) {
897 	    this.log.debug("Running " + command + 
898 			   " -e...  on '" + gpFile.getName() + "'. ");
899 	    // may throw BuildFailureException TEX01, 
900 	    // may log EEX01, EEX02, EEX03, WEX04, WEX05 
901 	    this.executor.execute(gpFile.getParentFile(), //workingDir 
902 				  this.settings.getTexPath(), //**** 
903 				  command, 
904 				  args, 
905 				  grpFile, ptxFile);
906 //	}
907 	// no check: just warning that no output has been created. 
908     }
909 
910     /**
911      * Runs mpost on mp-files to generate mps-files. 
912      * <p>
913      * Logging: 
914      * <ul>
915      * <li> WFU03: cannot close log file 
916      * <li> EAP01: Running <code>command</code> failed. For details...
917      * <li> EAP02: Running <code>command</code> failed. No log file 
918      * <li> WAP04: if log file is not readable. 
919      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
920      * if running the mpost command failed. 
921      * </ul>
922      *
923      * @param mpFile
924      *    the metapost file to be processed. 
925      * @throws BuildFailureException
926      *    TEX01 if invocation of the mpost command failed. 
927      * @see #processGraphicsSelectMain(File, DirNode)
928      */
929     // used in mp.procSrc(File, LatexPreProcessor) only 
930     private void runMetapost2mps(File mpFile) throws BuildFailureException {
931 	this.log.info("Processing metapost-file '" + mpFile + "'. ");
932 	String command = this.settings.getMetapostCommand();
933 	File workingDir = mpFile.getParentFile();
934 	// for more information just type mpost --help 
935 	String[] args = buildArguments(this.settings.getMetapostOptions(), 
936 				       mpFile);
937 	this.log.debug("Running " + command + 
938 		       " on '" + mpFile.getName() + "'. ");
939 	// FIXME: not check on all created files, 
940 	// but this is not worse than with latex 
941 
942 	// may throw BuildFailureException TEX01, 
943 	// may log EEX01, EEX02, EEX03, WEX04, WEX05 
944   	this.executor.execute(workingDir, 
945 			      this.settings.getTexPath(), //**** 
946 			      command, 
947 			      args,
948 			      this.fileUtils.replaceSuffix(mpFile, 
949 							   "1"+SUFFIX_MPS));
950 
951 	// from xxx.mp creates xxx1.mps, xxx.log and xxx.mpx 
952 	// FIXME: what is xxx.mpx for? 
953 	File logFile = this.fileUtils.replaceSuffix(mpFile, SUFFIX_LOG);
954 	// may log WFU03, EAP01, EAP02, WAP04
955 	logErrs(logFile, command, this.settings.getPatternErrMPost());
956 	// FIXME: what about warnings?
957    }
958 
959     /**
960      * Deletes the graphic files 
961      * created from the metapost-file <code>mpFile</code>. 
962      * <p>
963      * Logging: 
964      * <ul>
965      * <li> WFU01: Cannot read directory ...
966      * <li> EFU05: Failed to delete file 
967      * </ul>
968      *
969      * @param mpFile
970      *    a metapost file. 
971      */
972     private void clearTargetMp(File mpFile) {
973 	this.log.info("Deleting targets of graphic-file '" + mpFile + "'. ");
974 	// may log EFU05 
975 	deleteIfExists(mpFile, SUFFIX_LOG);
976 	deleteIfExists(mpFile, SUFFIX_FLS);
977 	deleteIfExists(mpFile, SUFFIX_MPX);
978 	// delete files xxxNumber.mps 
979 	String name1 = mpFile.getName();
980 	final String root = name1.substring(0, name1.lastIndexOf("."));
981 	FileFilter filter = new FileFilter() {
982 		public boolean accept(File file) {
983 		    return !file.isDirectory()
984 			&&  file.getName().matches(root + "\\d+" + SUFFIX_MPS);
985 		}
986 	    };
987 	// may log WFU01, EFU05 
988 	this.fileUtils.deleteX(mpFile, filter);
989     }
990 
991      /**
992      * Converts an svg-file into a tex-file with ending ptx 
993      * including a pdf-file or an eps-file also created. 
994      * To that end, invokes {@link #runSvg2Dev(File, LatexDev, boolean)} twice 
995      * to create a pdf-file and an eps-file 
996      * and to create the tex-file which can include both. 
997      * <p>
998      * Logging: 
999      * <ul>
1000      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1001      * if running the ptx/pdf-conversion built-in in svg2dev fails. 
1002      * <li> EFU07, EFU08, EFU09 if filtering a file fails. 
1003      * </ul>
1004      *
1005      * @param svgFile 
1006      *    the svg-file to be converted to a pdf-file and a ptx-file. 
1007      * @throws BuildFailureException
1008      *    TEX01 if invocation of the ptx/pdf-conversion built-in 
1009      *    in svg2dev fails. 
1010      * @see #processGraphicsSelectMain(File, DirNode)
1011      */
1012     // used in svg.procSrc(File, LatexPreProcessor) only 
1013     private void runSvg2Dev(File svgFile) throws BuildFailureException {
1014 	this.log.info("Processing svg-file '" + svgFile + "'. ");
1015 	// both may throw BuildFailureException TEX01, 
1016 	// and  may log EEX01, EEX02, EEX03, WEX04, WEX05
1017 	// EFU07, EFU08, EFU09
1018 	runSvg2Dev(svgFile, LatexDev.pdf,   false);
1019  	runSvg2Dev(svgFile, LatexDev.dvips, true);
1020     }
1021 
1022     // FIXME: still the included pdf/eps-file does not occur 
1023     // with full path in ptx-file 
1024     // may throw BuildFailureException TEX01, 
1025     // may log EEX01, EEX02, EEX03, WEX04, WEX05, EFU07, EFU08, EFU09
1026     private void runSvg2Dev(File svgFile, 
1027 			    LatexDev dev, 
1028 			    boolean filterTex) throws BuildFailureException {
1029 	// current:
1030 	// inkscape --export-filename=F4_07someSvg     -D F4_07someSvg.svg
1031 	//                                              --export-type=pdf,eps
1032 	// inkscape --export-filename=F4_07someSvg.pdf -D F4_07someSvg.svg
1033 	//
1034 	// --export-pdf-version=1.4 may be nice 
1035 	String command = this.settings.getSvg2devCommand();
1036 
1037 	File grpFile = this.fileUtils.replaceSuffix(svgFile,
1038 						    dev.getGraphicsInTexSuffix());
1039 	File texFile = this.fileUtils.replaceSuffix(svgFile,
1040 						    dev.getInkscapeTexSuffix());
1041 
1042 	String[] args = buildArgumentsInkscp(grpFile,
1043 					     this.settings.getSvg2devOptions(), 
1044 					     svgFile);
1045 	this.log.debug("Running " + command + 
1046 		       " on '" + svgFile.getName() + "'. ");
1047 	// may throw BuildFailureException TEX01, 
1048 	// may log EEX01, EEX02, EEX03, WEX04, WEX05 
1049 	this.executor.execute(svgFile.getParentFile(), 
1050 			      this.settings.getTexPath(), //**** 
1051 			      command, 
1052 			      args,
1053 			      grpFile,
1054 			      texFile);
1055 
1056 	if (filterTex) {
1057 	    // may log EFU07, EFU08, EFU09: cannot fiter
1058 	    // for eps only 
1059 	    this.fileUtils.filterInkscapeIncludeFile(texFile);
1060 	}
1061 	this.fileUtils.deleteOrError(texFile);
1062     }
1063 
1064     protected static String[] buildArgumentsInkscp(File grpFile,
1065 						   String options,
1066 						   File file) {
1067 	String optExp = "--export-filename=" + grpFile.getName();
1068     	if (options.isEmpty()) {
1069     	    return new String[] {optExp, file.getName()};
1070     	}
1071         String[] optionsArr = options.split(" ");
1072 	String[] args = new String[optionsArr.length+2];
1073         System.arraycopy(optionsArr, 0, args, 1, optionsArr.length);
1074         args[args.length-1] = file.getName();
1075 	args[0            ] = optExp;
1076    	return args;
1077      }
1078   
1079 
1080     // Additional research: 
1081     // Documentation says, that this is needed for interface eps, 
1082     // but not for interface pdf. 
1083     // Experiments show, that we can do without it in any case. 
1084 
1085     private void runEbb(File file) throws BuildFailureException {
1086 	String command = this.settings.getEbbCommand();
1087 	File workingDir = file.getParentFile();
1088 	String[] args = buildNullArguments(this.settings.getEbbOptions(), file);
1089 
1090 	// Creation of .xbb files for driver dvipdfmx
1091 	// FIXME: literal 
1092 	args[0] ="-x";
1093 	File resFile = this.fileUtils.replaceSuffix(file, SUFFIX_XBB);
1094 
1095 	this.log.debug("Running " + command + 
1096 		       " twice on '" + file.getName() + "'. ");
1097 	// may throw BuildFailureException TEX01, 
1098 	// may log EEX01, EEX02, EEX03, WEX04, WEX05 
1099 	this.executor.execute(workingDir, 
1100 			      this.settings.getTexPath(), //**** 
1101 			      command, 
1102 			      args,
1103 			      resFile);
1104 
1105 	// Creation of .bb files for driver dvipdfm
1106 	// FIXME: literal 
1107 	args[0] ="-m";
1108 	resFile = this.fileUtils.replaceSuffix(file, SUFFIX_BB);
1109 
1110 	this.executor.execute(workingDir, 
1111 			      this.settings.getTexPath(), //**** 
1112 			      command, 
1113 			      args,
1114 			      resFile);
1115     }
1116 
1117     /**
1118      * Returns an array of strings, 
1119      * where the 0th entry is <code>null</code> 
1120      * and a placeholder for option <code>-x</code> or <code>-m</code> 
1121      * when used by {@link #runEbb(File)} 
1122      * and for the export option 
1123      * when used by {@link #runSvg2Dev(File, LatexDev, boolean)} 
1124      * then follow the options from <code>options</code> 
1125      * and finally comes the name of <code>file</code>. 
1126      */
1127     protected static String[] buildNullArguments(String options, File file) {
1128     	if (options.isEmpty()) {
1129     	    return new String[] {null, file.getName()};
1130     	}
1131         String[] optionsArr = options.split(" ");
1132 	String[] args = new String[optionsArr.length+2];
1133         System.arraycopy(optionsArr, 0, args, 1, optionsArr.length);
1134         args[args.length-1] = file.getName();
1135 	
1136  	assert args[0] == null;
1137    	return args;
1138      }
1139 
1140     /**
1141      * Deletes the graphic files 
1142      * created from the svg-file <code>svgFile</code>. 
1143      * <p>
1144      * Logging: 
1145      * EFU05: Failed to delete file
1146      */
1147     private void clearTargetJpgPng(File file) {
1148        this.log.info("Deleting targets of jpg/png-file '" + file + "'. ");
1149        // may log EFU05 
1150        deleteIfExists(file, SUFFIX_XBB);
1151        deleteIfExists(file, SUFFIX_BB);
1152 //     deleteIfExists(svgFile, SUFFIX_PSTEX );
1153 //       deleteIfExists(file, SUFFIX_PDF   );
1154        // FIXME: this works for pdf but not for dvi: 
1155        // even in the latter case, .pdf and .pdf_tex are created 
1156     }
1157 
1158 
1159     /**
1160      *
1161      * <p>
1162      * Logging: 
1163      * EFU05: Failed to delete file
1164      */
1165     private void deleteIfExists(File file, String suffix) {
1166 	File delFile = this.fileUtils.replaceSuffix(file, suffix);
1167 	if (!delFile.exists()) {
1168 	    return;
1169 	}
1170 	// may log EFU05 
1171 	this.fileUtils.deleteOrError(delFile);
1172     }
1173 
1174     /**
1175      * Returns whether <code>texFile</code> is a latex main file, 
1176      * provided it is readable. 
1177      * Otherwise logs a warning and returns <code>false</code>. 
1178      * <p>
1179      * Logging: 
1180      * <ul>
1181      * <li> WFU03: cannot close 
1182      * <li> WPP02: tex file may be latex main file 
1183      * <ul>
1184      *
1185      * @param texFile
1186      *    the tex-file to decide on whether it is a latex main file. 
1187      * @return
1188      *    whether <code>texFile</code> is definitively a latex main file. 
1189      *    If this is not readable, <code>false</code>. 
1190      */
1191     // used 
1192     // by addIfLatexMain(File, Collection) and 
1193     // by clearTargetTexIfLatexMain(File) 
1194     private boolean isLatexMainFile(File texFile) {
1195 	assert texFile.exists() && !texFile.isDirectory()
1196 	    : "Expected existing regular tex file "+texFile;
1197 	// may log WFU03 cannot close 
1198 	Boolean res = this.fileUtils.matchInFile
1199 	    (texFile, this.settings.getPatternLatexMainFile());
1200 	if (res == null) {
1201 	    this.log.warn("WPP02: Cannot read tex file '" + texFile + 
1202 			  "'; may bear latex main file. ");
1203 	    return false;
1204 	}
1205 	return res;
1206     }
1207 
1208     /**
1209      * If the tex-file <code>texFile</code> is a latex main file, 
1210      * add it to <code>latexMainFiles</code>. 
1211      * <p>
1212      * Logging: 
1213      * <ul>
1214      * <li> WFU03: cannot close 
1215      * <li> WPP02: tex file may be latex main file 
1216      * <ul>
1217      *
1218      * @param texFile
1219      *    the tex-file to be added to <code>latexMainFiles</code>
1220      *    if it is a latex main file. 
1221      * @param latexMainFiles
1222      *    the collection of latex main files found so far. 
1223      */
1224     // invoked only by tex.procSrc(File, LatexPreProcessor)
1225     private void addIfLatexMain(File texFile, Collection<File> latexMainFiles) {
1226 	// may log WFU03, WPP02 
1227 	if (isLatexMainFile(texFile)) {
1228 	    this.log.info("Detected latex-main-file '" + texFile + "'. ");
1229 	    latexMainFiles.add(texFile);
1230 	}
1231     }
1232 
1233     /**
1234      * Deletes the files 
1235      * created from the tex-file <code>texFile</code>, 
1236      * if that is a latex main file. 
1237      * <p>
1238      * Logging: 
1239      * <ul>
1240      * <li> WPP02: tex file may be latex main file 
1241      * <li> WFU01: Cannot read directory...
1242      * <li> WFU03: cannot close tex file 
1243      * <li> EFU05: Failed to delete file 
1244      * </ul>
1245      *
1246      * @param texFile
1247      *    the tex-file of which the created files shall be deleted 
1248      *    if it is a latex main file. 
1249      */
1250     private void clearTargetTexIfLatexMain(File texFile) {
1251 	// exclude files which are no latex main files 
1252 	// may log WFU03, WPP02 
1253 	if (!isLatexMainFile(texFile)) {
1254 	    return;
1255 	}
1256 	this.log.info("Deleting targets of latex main file '" + 
1257 		      texFile + "'. ");
1258 	FileFilter filter = this.fileUtils.getFileFilter
1259 	    (texFile, this.settings.getPatternCreatedFromLatexMain());
1260 	// may log WFU01, EFU05 
1261 	this.fileUtils.deleteX(texFile, filter);
1262     }
1263 
1264     /**
1265      * Detects files in the directory represented by <code>node</code> 
1266      * and in subdirectories recursively: 
1267      * <ul>
1268      * <li>
1269      * those which are in various graphic formats incompatible with LaTeX 
1270      * are converted into formats which can be inputed or included directly 
1271      * into a latex file. 
1272      * <li>
1273      * returns the set of latex main files. 
1274      * </ul>
1275      * <p>
1276      * Logging: 
1277      * <ul>
1278      * <li> WFU03: cannot close 
1279      * <li> WPP02: tex file may be latex main file 
1280      * <li> WPP03: Skipped processing of files with suffixes ... 
1281      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1282      *      if running graphic processors failed. 
1283      * <li> EFU07, EFU08, EFU079: if filtering a file fails. 
1284      * </ul>
1285      *
1286      * @param dir
1287      *    represents the tex source directory or a subdirectory. 
1288      * @param node
1289      *    a node associated with <code>dir</code>. 
1290      * @return
1291      *    the collection of latex main files. 
1292      * @throws BuildFailureException
1293      *    TEX01 invoking 
1294      * {@link #processGraphicsSelectMain(File, DirNode, Collection, Collection)}
1295      */
1296     // used in LatexProcessor.create() 
1297     // and in LatexProcessor.processGraphics() only 
1298     // where 'node' represents the tex source directory 
1299     Collection<File> processGraphicsSelectMain(File dir, DirNode node) 
1300     	throws BuildFailureException {
1301 
1302     	Collection<String> skipped        = new TreeSet<String>();
1303     	Collection<File>   latexMainFiles = new TreeSet<File>();
1304 	if (this.settings.getReadTexSrcProcDirRec()) {
1305 	    // may throw BuildFailureException TEX01, 
1306 	    // may log EEX01, EEX02, EEX03, 
1307 	    // WEX04, WEX05, WFU03, WPP02, EFU06 
1308 	    processGraphicsSelectMainRec(dir, node, skipped, latexMainFiles);
1309 	} else {
1310 	    // may throw BuildFailureException TEX01, 
1311 	    // may log EEX01, EEX02, EEX03, 
1312 	    // WEX04, WEX05, WFU03, WPP02, EFU07, EFU08, EFU09 
1313 	    processGraphicsSelectMain   (dir, node, skipped, latexMainFiles);
1314 	}
1315 
1316     	if (!skipped.isEmpty()) {
1317     	    this.log.warn("WPP03: Skipped processing of files with suffixes " + 
1318     			  skipped + ". ");
1319     	}
1320 
1321     	return latexMainFiles;
1322     }
1323 
1324     /**
1325      * <p>
1326      * Logging: 
1327      * <ul>
1328      * <li> WFU03: cannot close file 
1329      * <li> EFU07, EFU08, EFU09: if filtering of a file fails (svg)
1330      * <li> WPP02: tex file may be latex main file 
1331      * <li> EEX01, EEX02, EEX03, WEX04, WEX05: 
1332      * if applications for preprocessing graphic files failed. 
1333      * </ul>
1334      *
1335      * @param dir
1336      *    represents the tex source directory or a subdirectory. 
1337      * @param node
1338      *    a node associated with <code>dir</code>. 
1339      * @param skipped
1340      *    the collection of suffixes of files with handling skipped so far 
1341      *    because there is no handler. 
1342      *    FIXME: interesting for files without suffix or for hidden files. 
1343      * @param latexMainFiles
1344      *    the collection of latex main files found so far. 
1345      * @throws BuildFailureException
1346      *    TEX01 invoking 
1347      * {@link LatexPreProcessor.SuffixHandler#procSrc(File, LatexPreProcessor)}
1348      *    only for {@link LatexPreProcessor.SuffixHandler#fig}, 
1349      *    {@link LatexPreProcessor.SuffixHandler#gp} and 
1350      *    {@link LatexPreProcessor.SuffixHandler#mp} 
1351      *    because these invoke external programs. 
1352      */
1353     private void processGraphicsSelectMain(File dir, 
1354 					   DirNode node, 
1355     					   Collection<String> skipped, 
1356     					   Collection<File> latexMainFiles) 
1357     	throws BuildFailureException {
1358 
1359    	assert node.isValid();// i.e. node.regularFile != null
1360 	// FIXME: processing of the various graphic files 
1361 	// may lead to overwrite 
1362 	// FIXME: processing of the latex main files 
1363 	// may lead to overwrite of graphic files or their targets 
1364 
1365 	File file;
1366     	String suffix;
1367     	SuffixHandler handler;
1368 	Collection<File> latexMainFilesLocal = new TreeSet<File>();
1369 	Map<File, SuffixHandler> file2handler = 
1370 	    new TreeMap<File, SuffixHandler>();
1371    	for (String fileName : node.getRegularFileNames()) {
1372 	    file = new File(dir, fileName);
1373     	    suffix = this.fileUtils.getSuffix(file);
1374     	    handler = SUFFIX2HANDLER.get(suffix);
1375     	    if (handler == null) {
1376     		this.log.debug("Skipping processing of file '" + file + "'. ");
1377 		// warning on skipped files even on hidden files. 
1378     		skipped.add(suffix);
1379     	    } else {
1380 		// Either performs transformation now 
1381 		// or schedule for later (latex main files) 
1382 		// or do nothing if no targets like bib-files 
1383 		// or tex-files to be inputted. 
1384 
1385     		// may throw BuildFailureException TEX01, 
1386     		// may log EEX01, EEX02, EEX03, WEX04, WEX05 
1387 		// WFU03, WPP02 
1388 		if (!file.isHidden()) {
1389 		    handler.scheduleProcSrc(file, file2handler, 
1390 					    this, latexMainFilesLocal);
1391 		}
1392     	    }
1393     	} // for 
1394 
1395 	latexMainFiles.addAll(latexMainFilesLocal);
1396 
1397 	// remove sources from file2handler.keySet() 
1398 	// if created by local latex main files 
1399 	FileFilter filter;
1400 	for (File lmFile : latexMainFilesLocal) {
1401 	    filter = this.fileUtils.getFileFilter
1402 		(lmFile, this.settings.getPatternCreatedFromLatexMain());
1403 	    Iterator<File> iter = file2handler.keySet().iterator();
1404 	    File src;
1405 	    while (iter.hasNext()) {
1406 		src = iter.next();
1407 		if (filter.accept(src)) {
1408 		    // FIXME: maybe this is too much: 
1409 		    // better just one warning per latex main file 
1410 		    // or just suffixes, i.e. handlers 
1411 		    this.log.warn("WPP04: Skip processing '" + src + 
1412 				  "': interpreted as target of '" + 
1413 				  lmFile + "'. ");
1414 		    iter.remove();
1415 		    continue;
1416 		}
1417 		// Here, src is not overwritten processing lmFile 
1418 		// FIXME: to be checked, whether this is also true 
1419 		// for targets of src 
1420 	    }
1421 	}
1422 
1423 	// Here process file, except tex (bib at least info) 
1424 	// with associated handler 
1425 	// FIXME: How to ensure, that nothing is overwritten? 
1426 	// NO: if a file is overwritten, then it is no source 
1427 	// and needs no processing 
1428 	for (Map.Entry<File, SuffixHandler> entry : file2handler.entrySet()) {
1429 	    // procSrc may throw BuildFailureException TEX01
1430 	    // and may log WFU03, WPP02, 
1431 	    // EEX01, EEX02, EEX03, WEX04, WEX05 and EFU07, EFU08, EFU09 
1432 	    entry.getValue().procSrc(entry.getKey(), this);
1433 	}
1434     }
1435 
1436     /**
1437      * Like 
1438      * {@link #processGraphicsSelectMain(File,DirNode,Collection,Collection)}
1439      * but with recursion to subdirectories. 
1440      */
1441     private void processGraphicsSelectMainRec(File dir, 
1442 					      DirNode node, 
1443 					      Collection<String> skipped, 
1444 					      Collection<File> latexMainFiles) 
1445     	throws BuildFailureException {
1446 	processGraphicsSelectMain(dir, node, skipped, latexMainFiles);
1447 
1448 	// go on recursively with subdirectories 
1449     	for (Map.Entry<String, DirNode> entry : node.getSubdirs().entrySet()) {
1450 	    // may throw BuildFailureException TEX01, 
1451 	    // may log EEX01, EEX02, EEX03, WEX04, WEX05, WPP03 
1452 	    // WFU03, WPP02, EFU06 
1453      	    processGraphicsSelectMainRec(new File(dir, entry.getKey()),
1454 					 entry.getValue(), 
1455 					 skipped, 
1456 					 latexMainFiles);
1457     	}
1458     }
1459 
1460     /**
1461      * Deletes all created files 
1462      * in the directory represented by <code>texDir</code> 
1463      * tracing subdirectories recursively. 
1464      * For details of deletions within a single directory 
1465      * see {@link #clearCreated(File, DirNode)}. 
1466      * <p>
1467      * Logging: 
1468      * <ul>
1469      * <li> WPP02: tex file may be latex main file 
1470      * <li> WFU01: Cannot read directory...
1471      * <li> WFU03: cannot close tex file 
1472      * <li> EFU05: Failed to delete file 
1473      * </ul>
1474      *
1475      * @param texDir
1476      *    represents the tex source directory or a subdirectory. 
1477      */
1478     // invoked in LatexProcessor.clearAll() only 
1479     void clearCreated(File texDir) {
1480 	clearCreated(texDir, new DirNode(texDir, this.fileUtils));
1481     }
1482 
1483     /**
1484      * Deletes all created files 
1485      * in the directory represented by <code>node</code>, recursively. 
1486      * In each directory, the sub-directories are not deleted themselves 
1487      * but cleaned recursively. 
1488      * The other files are cleaned, i.e. 
1489      * their targets are deleted in an ordering reverse to creation 
1490      * proceeding in the following steps: 
1491      * <ul>
1492      * <li>
1493      * First the targets of the latex main files are deleted, 
1494      * whereas the targets of the graphic (source) files 
1495      * are just scheduled for deletion. 
1496      * For details see 
1497      * {@link LatexPreProcessor.SuffixHandler#clearTarget(File, LatexPreProcessor, Map)}. 
1498      * FIXME: what about deletion of a graphic source file in this course? 
1499      * <li>
1500      * Then the graphic source files scheduled are un-scheduled 
1501      * if deleted by some latex main file. 
1502      * <li>
1503      * Finally, the targets of the graphic souce files are deleted. 
1504      * FIXME: what if this results in deletion of a graphic source file? 
1505      * </ul>
1506      * Then the files with handler 
1507      * If a file has a prefix without handler, 
1508      * (see {@link SuffixHandler#getSuffix()}) it is ignored. 
1509      * Else its target is cleared as described in 
1510      * {@link SuffixHandler#clearTarget(File, LatexPreProcessor, Map)}. 
1511      * <p>
1512      * Logging: 
1513      * <ul>
1514      * <li> WPP02: tex file may be latex main file 
1515      * <li> WFU01: Cannot read directory...
1516      * <li> WFU03: cannot close tex file 
1517      * <li> EFU05: Failed to delete file 
1518      * </ul>
1519      *
1520      * @param dir
1521      *    represents the tex source directory or a subdirectory. 
1522      * @param node
1523      *    a node associated with <code>dir</code>. 
1524      */
1525     private void clearCreated(File dir, DirNode node) {
1526 	assert dir.isDirectory()
1527 	    : "Expected existing directory "+dir+" to be cleared. ";
1528 	File file;
1529 	SuffixHandler handler;
1530 	Map<File, SuffixHandler> file2handler = 
1531 	    new TreeMap<File, SuffixHandler>();
1532    	for (String fileName : node.getRegularFileNames()) {
1533 	    file = new File(dir, fileName);
1534 	    handler = SUFFIX2HANDLER.get(this.fileUtils.getSuffix(file));
1535 	    if (handler != null) {
1536 		// either clear targets now or schedule for clearing 
1537 		// (in particular do nothing if no target)
1538 		// may log WPP02, WFU01, WFU03, EFU05 
1539 		handler.clearTarget(file, this, file2handler);
1540 	    }
1541 	}
1542 	// clear targets of all still existing files 
1543 	// which just scheduled for clearing 
1544   	for (Map.Entry<File,SuffixHandler> entry : file2handler.entrySet()) {
1545 	    file = entry.getKey();
1546 	    if (file.exists()) {
1547 		entry.getValue().clearTarget(file, this);
1548 	    }
1549 	}
1550 
1551     	for (Map.Entry<String,DirNode> entry : node.getSubdirs().entrySet()) {
1552 	    // may log WPP02, WFU01, WFU03, EFU05 
1553     	    clearCreated(new File(dir, entry.getKey()), entry.getValue());
1554     	}
1555     }
1556 
1557     // FIXME: suffix for tex files containing text and including pdf 
1558  }