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