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 <language> <optionsGen> <optionsPdfEps> 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 <language> <optionsGen> <optionsPdfEps> -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 }