View Javadoc
1   package eu.simuline.m2latex.core;
2   
3   import java.io.File;
4   import java.util.Arrays;
5   import java.util.Collection;
6   import java.util.HashMap;
7   import java.util.Map;
8   import java.util.stream.Collectors;
9   
10  /**
11   * Enumeration of all converters used. 
12   * The ones of category {@link ConverterCategory#Unparametrized} 
13   * are special in that they do not occur in the configuration. 
14   * They are programming lanugages and build tools 
15   * in which this piece of software is used. 
16   */
17  enum Converter {
18  
19    Maven {
20      String getCommand() {
21        return "mvn";
22      }
23  
24      String getVersionPattern() {
25        return X_X_X;
26      }
27      String getVersionEnvironment() {
28        return "^Apache Maven %s";
29      }
30      ConverterCategory getCategory() {
31        return ConverterCategory.Unparametrized;
32      }
33    },
34    Ant {
35      String getCommand() {
36        return "ant";
37      }
38  
39      String getVersionOption() {
40        return "-version";
41      }
42  
43      String getVersionPattern() {
44        return X_X_X;
45      }
46  
47      String getVersionEnvironment() {
48        return "^Apache Ant\\(TM\\) version %s";
49      }
50  
51      ConverterCategory getCategory() {
52        return ConverterCategory.Unparametrized;
53      }
54    },
55    Java {
56      String getCommand() {
57        return "java";
58      }
59  
60      String getVersionPattern() {
61        return V_JAVA;
62      }
63      // TBD: research: maybe better use javac because there the version environment is just javac %s 
64      // for java there is more information available 
65      // and also --help is better suited 
66      // and last but not least at runtime java is relevant not javac, so this would be a hack. 
67      String getVersionEnvironment() {
68        return "^openjdk %s \\d{4}-\\d{2}-\\d{2}";
69      }
70      ConverterCategory getCategory() {
71        return ConverterCategory.Unparametrized;
72      }
73    },
74    Python {
75      String getCommand() {
76        return "python";
77      }
78  
79      String getVersionPattern() {
80        return X_X_X;
81      }
82  
83      String getVersionEnvironment() {
84        return "^" + Python + " %s";
85      }
86      ConverterCategory getCategory() {
87        return ConverterCategory.Unparametrized;
88      }
89    },
90    Perl {
91      String getCommand() {
92        return "perl";
93      }
94      String getVersionPattern() {
95        return X_X_X;
96      }
97      // TBD: research: maybe better use javac because there the version environment is just javac %s 
98      // for java there is more information available 
99      // and also --help is better suited 
100     // and last but not least at runtime java is relevant not javac, so this would be a hack. 
101     String getVersionEnvironment() {
102       return "^.*\\RThis is " + getCommand() + " .* \\(v%s\\)";
103     }
104     ConverterCategory getCategory() {
105       return ConverterCategory.Unparametrized;
106     }
107   },
108   Lua {
109     String getCommand() {
110       return "lua";
111     }
112 
113     String getVersionOption() {
114       return "-v";
115     }
116 
117     String getVersionPattern() {
118       return X_X_X;
119     }
120     // TBD: research: maybe better use javac because there the version environment is just javac %s 
121     // for java there is more information available 
122     // and also --help is better suited 
123     // and last but not least at runtime java is relevant not javac, so this would be a hack. 
124     String getVersionEnvironment() {
125       return "^Lua %s  Copyright \\(C\\) \\d{4}-\\d{4} Lua\\.org, PUC-Rio";
126     }
127     ConverterCategory getCategory() {
128       return ConverterCategory.Unparametrized;
129     }
130   },
131   PdfLatex {
132     String getCommand() {
133       return "pdflatex";
134     }
135 
136     /**
137      * The version pattern at a first sight consists of three parts: 
138      * <ul>
139      * <li>the tex version which is an approximation of pi 
140      * and which will be frozen as Donald Knuth will die at $\pi$ 
141      * (meant maybe in double precision)</li>
142      * <li>the etex version which is a two integer version. 
143      * It has to be clarified, whether there is a new release to be expected. </li>
144      * <li>the pdftex version. </li>
145      * </ul>
146      * It is quite sure from the examples found, 
147      * that the latter does not start from the beginning 
148      * when the former is increased. 
149      * This means that the first of the two version numbers are informative only
150      * and must thus be included in the environment. 
151      * @see #getVersionEnvironment()
152      */
153     String getVersionPattern() {
154       // 3.1415926-2.3-1.40.12
155       // 3.14159265-2.6-1.40.21
156       return X_X_X;
157     }
158 
159     /**
160      * For an explanation why part of the version string is in the environment, 
161      * see {@link #getVersionPattern()}. 
162      */
163     String getVersionEnvironment() {
164       return "^pdfTeX 3\\.\\d*-\\d+\\.\\d+-%s \\(TeX Live \\d{4}(?:/.+)?\\)";
165     }
166 
167     ConverterCategory getCategory() {
168       return ConverterCategory.LaTeX;
169     }
170 
171   },
172   // TBC: relation lualatex, luahbtex and so on 
173   LuaLatex {
174     String getCommand() {
175       return "lualatex";
176     }
177 
178     String getVersionPattern() {
179       return X_X_X;
180     }
181 
182     // The last symbol is either `)` indicating tol
183     String getVersionEnvironment() {
184       return "^This is LuaHBTeX, Version %s \\(TeX Live \\d{4}(?:/.+)?\\)";
185     }
186 
187     ConverterCategory getCategory() {
188       return ConverterCategory.LaTeX;
189     }
190   },
191   XeLatex {
192     String getCommand() {
193       return "xelatex";
194     }
195 
196     /**
197      * The version pattern at a first sight consists of three parts: 
198      * <ul>
199      * <li>the tex version which is an approximation of pi 
200      * and which will be frozen as Donald Knuth will die at $\pi$ 
201      * (meant maybe in double precision)</li>
202      * <li>the etex version which is a two integer version. 
203      * It has to be clarified, whether there is a new release to be expected. </li>
204      * <li>the xetex version. </li>
205      * </ul>
206      * It is quite sure from the examples found, 
207      * that the latter does not start from the beginning 
208      * when the former is increased. 
209      * This means that the first of the two version numbers are informative only
210      * and must thus be included in the environment. 
211      * @see #getVersionEnvironment()
212      */
213     String getVersionPattern() {
214       return "((0\\.\\d*))";
215     }
216 
217     /**
218      * For an explanation why part of the version string is in the environment, 
219      * see {@link #getVersionPattern()}. 
220      */
221     String getVersionEnvironment() {
222       return "^XeTeX 3\\.\\d*-\\d+\\.\\d+-%s \\(TeX Live \\d{4}(?:/.+)?\\)";
223     }
224 
225     ConverterCategory getCategory() {
226       return ConverterCategory.LaTeX;
227     }
228   },
229   Latex2rtf {
230     String getCommand() {
231       return "latex2rtf";
232     }
233 
234     String getVersionOption() {
235       return "-v";
236     }
237 
238     String getHelpOption() {
239       return "-h";
240     }
241 
242     String getVersionPattern() {
243       return "((\\d+)\\.(\\d+)\\.(\\d+) r(\\d+))";
244     }
245 
246     String getVersionEnvironment() {
247       return "^" + getCommand()
248           + " %s \\(released [A-Z][a-z]{2} \\d+, \\d{4}\\)\\R";
249     }
250 
251     ConverterCategory getCategory() {
252       return ConverterCategory.LaTeX2Rtf;
253     }
254   },
255   Odt2doc {
256     String getCommand() {
257       return "odt2doc";
258     }
259 
260     // TBC: not clear whether this is the significant version 
261     String getVersionPattern() {
262       return X_X_X;
263     }
264 
265     String getVersionEnvironment() {
266       // The optional first lines contains deprecation information 
267       return "^(?:.*\\R.*\\R)?" + "unoconv %s\\R";
268     }
269 
270     ConverterCategory getCategory() {
271       return ConverterCategory.Odt2Doc;
272     }
273 
274   },
275   Dvips {
276     String getCommand() {
277       return "dvips";
278     }
279 
280     String getVersionOption() {
281       return "-v";
282     }
283 
284     String getVersionPattern() {
285       return "(([0-9\\.]{4})\\.(\\d))";
286     }
287 
288     String getVersionEnvironment() {
289       return "^This is " + getCommand() + "\\(k\\) %s "
290           + "(?:\\(TeX Live \\d+\\)  )?"
291           + "Copyright \\d+ Radical Eye Software \\(www\\.radicaleye\\.com\\)\\R";
292     }
293 
294     ConverterCategory getCategory() {
295       return ConverterCategory.Unspecific;
296     }
297 
298   },
299   /**
300    * Converts dvi to pdf. 
301    * Note that in current texlive distribution, 
302    * this is just linked to {@link #XDvipdfmx}. 
303    * Thus it is able to convert also xdv files. 
304    */
305   Dvipdfm {
306     String getCommand() {
307       return "dvipdfm";
308     }
309 
310     String getVersionPattern() {
311       return VYYYYMMDD;
312     }
313 
314     String getVersionEnvironment() {
315       return "^This is " + getCommand()
316           + " Version %s by the DVIPDFMx project team,\\R";
317     }
318 
319     ConverterCategory getCategory() {
320       return ConverterCategory.Dvi2Pdf;
321     }
322 
323   },
324   /**
325    * Converts dvi to pdf. 
326    * Note that in current texlive distribution, 
327    * this is just linked to {@link #XDvipdfmx}. 
328    * Thus it is able to convert also xdv files. 
329    * Theoretically, the difference to {@link #Dvipdfm} 
330    * is the support for asian languages, 
331    * but because {@link #Dvipdfm} is also linked to {@link #XDvipdfmx}, 
332    * the two programs are the same. 
333    */
334   Dvipdfmx {
335     String getCommand() {
336       return "dvipdfmx";
337     }
338 
339     String getVersionPattern() {
340       return VYYYYMMDD;
341     }
342 
343     String getVersionEnvironment() {
344       return "^This is " + getCommand()
345           + " Version %s by the DVIPDFMx project team,\\R";
346     }
347 
348     ConverterCategory getCategory() {
349       return ConverterCategory.Dvi2Pdf;
350     }
351   },
352   /**
353    * Theoretically converts xdv to pdf; 
354    * it is a backend of {@link #XeLatex} 
355    * which is invoked transparently, unless <code>-no-pdf</code> is specified. 
356    * but in the current texlive distribution 
357    * this is linked from {@link #Dvipdfm} and from {@link #Dvipdfmx} 
358    * and can thus also convert dvi to pdf. 
359   * In fact, if used without file extension it chooses between dvi and xdv; 
360   * if both are present, xdv is converted. 
361   */
362   XDvipdfmx {
363     String getCommand() {
364       return "xdvipdfmx";
365     }
366 
367     String getVersionPattern() {
368       return VYYYYMMDD;
369     }
370 
371     String getVersionEnvironment() {
372       return "^This is " + getCommand()
373           + " Version %s by the DVIPDFMx project team,\\R";
374     }
375 
376     ConverterCategory getCategory() {
377       return ConverterCategory.Dvi2Pdf;
378     }
379   },
380   /**
381     * Converts dvi to pdf. 
382     * Note that in current texlive distribution, 
383     * this is just a wrapper around {@link #Dvipdfm} 
384     * using {@link #GS} to create thumbnails. 
385     * Thus, as  {@link #Dvipdfm} it is able to convert also xdv files. 
386     * <p>
387     * From the docs of the script: 
388     * This script makes a first (fast) run with dvipdfm, then calls gs on
389     * the resulting pdf file to get the thumbnails and finally calls dvipdfm.
390      */
391   Dvipdft {
392     String getCommand() {
393       return "dvipdft";
394     }
395 
396     String getVersionPattern() {
397       return "((\\d{4})(\\d{2})(\\d{2})\\.(\\d{4}))";
398     }
399 
400     String getVersionEnvironment() {
401       return "^" + getCommand() + " version %s by Thomas Esser and others\\R";
402     }
403 
404     ConverterCategory getCategory() {
405       return ConverterCategory.Dvi2Pdf;
406     }
407   },
408   GS {
409     String getCommand() {
410       return "gs";
411     }
412 
413     String getVersionOption() {
414       return "--version";
415     }
416     // String getVersionOption() {
417     //   return "-v";
418     // }
419 
420     String getVersionPattern() {
421       //return VX_X__X;
422       return X_X_X;
423     }
424 
425     String getVersionEnvironment() {
426       //return "^GPL Ghostscript %s \\(\\d{4}-\\d{2}-\\d{2}\\)\\R";
427       return "^%s";
428     }
429 
430     ConverterCategory getCategory() {
431       return ConverterCategory.Unspecific;
432     }
433   },
434   ChkTeX {
435     String getCommand() {
436       return "chktex";
437     }
438 
439     String getVersionPattern() {
440       return X_X_X;
441     }
442 
443     String getVersionEnvironment() {
444       return "^" + ChkTeX + " v%s - "
445           + "Copyright \\d{4}-\\d{2} Jens T. Berger Thielemann.\\R";
446     }
447 
448     ConverterCategory getCategory() {
449       return ConverterCategory.LatexChk;
450     }
451   },
452   VeraPdf {
453     String getCommand() {
454       return "verapdf";
455     }
456 
457     String getVersionPattern() {
458       return X_X_X;
459     }
460 
461     String getVersionEnvironment() {
462       return "^veraPDF %s\\R";
463     }
464 
465     ConverterCategory getCategory() {
466       return ConverterCategory.StandardValidator;
467     }
468 
469   },
470   DiffPdfVisualLy {
471     String getCommand() {
472       return "diff-pdf-visually";
473     }
474 
475     String getVersionPattern() {
476       return X_X_X;
477     }
478 
479     // TBD: rework 
480     String getVersionEnvironment() {
481       //return "default: %s";
482       return "^" + getCommand() + " %s";
483     }
484 
485     // TBD: make specific 
486     ConverterCategory getCategory() {
487       return ConverterCategory.DiffPdf;
488     }
489   },
490   DiffPdf {
491     String getCommand() {
492       return "diff-pdf";
493     }
494 
495     // TBD: bugfix: this is just the help option. 
496     // -v is the verbose option 
497     String getVersionOption() {
498       return "-h";
499     }
500 
501     String getVersionPattern() {
502       return VX;
503     }
504 
505     String getVersionEnvironment() {
506       //return "default: %s";
507       return "^Usage: .*\\R.*\\R.*\\R.*\\R.*\\R.*\\R.*\\R.*\\R"
508           + ".*\\w*rasterization resolution \\(default: %s dpi\\)";
509     }
510 
511     // TBD: make specific 
512     ConverterCategory getCategory() {
513       return ConverterCategory.DiffPdf;
514     }
515   },
516   Diff {
517     String getCommand() {
518       return "diff";
519     }
520 
521     String getVersionPattern() {
522       return VX_X;
523     }
524 
525     String getVersionEnvironment() {
526       //return "default: %s";
527       return "^" + getCommand() + " \\(GNU diffutils\\) %s";
528     }
529 
530     // TBD: make specific 
531     ConverterCategory getCategory() {
532       return ConverterCategory.DiffPdf;
533     }
534   },
535   Pdf2txt {
536     String getCommand() {
537       return "pdftotext";
538     }
539 
540     String getVersionOption() {
541       return "-v";
542     }
543 
544     String getVersionPattern() {
545       return X_X_X;
546     }
547 
548     String getVersionEnvironment() {
549       return "^" + getCommand() + " version %s\\R";
550     }
551 
552     ConverterCategory getCategory() {
553       return ConverterCategory.Pdf2Txt;
554     }
555   },
556   PdfInfo {
557     String getCommand() {
558       return "pdfinfo";
559     }
560 
561     String getVersionOption() {
562       return "-v";
563     }
564 
565     String getVersionPattern() {
566       return X_X_X;
567     }
568 
569     String getVersionEnvironment() {
570       return "^" + getCommand() + " version %s";
571     }
572 
573     // TBD: make specific 
574     ConverterCategory getCategory() {
575       return ConverterCategory.MetaInfoPdf;
576     }
577   },
578   ExifTool {
579     String getCommand() {
580       return "exiftool";
581     }
582 
583     String getVersionOption() {
584       return "-ver";
585     }
586 
587     String getHelpOption() {
588       return "-h";
589     }
590 
591     String getVersionPattern() {
592       return VX_X;
593     }
594 
595     String getVersionEnvironment() {
596       return "^%s";
597     }
598 
599     // TBD: make specific 
600     // could be PdfMetaInfo as pdfinfo 
601     ConverterCategory getCategory() {
602       return ConverterCategory.Unspecific;
603     }
604   },
605   BibTeX {
606     String getCommand() {
607       return "bibtex";
608     }
609 
610     String getVersionPattern() {
611       return "((0\\.\\d*)([a-z]))";
612     }
613 
614     String getVersionEnvironment() {
615       return "^" + BibTeX + " %s \\(TeX Live \\d{4}(?:/.+)?\\)";
616     }
617 
618     ConverterCategory getCategory() {
619       return ConverterCategory.BibTeX;
620     }
621   },
622   BibTeXu {
623     String getCommand() {
624       return "bibtexu";
625     }
626 
627     /**
628      * Returns the pattern for the version string. 
629      * Note that <code>bibtexu -v</code> yields three versions, 
630      * the version of bibtex (something like 0.99d) 
631      * which is something like the specification version, 
632      * the ICU version and the release version (and date). 
633      * What is returned is the latter version.  
634      * 
635      * @return
636      *    the pattern for the version string. 
637      */
638     String getVersionPattern() {
639       return VX_X;
640     }
641 
642     String getVersionEnvironment() {
643       return "^This is " + BibTeXu + ": a UTF-8 Big " + BibTeX
644           + " version .* \\(TeX Live \\d{4}\\)\\R"
645           + "Implementation: .*\\R"
646           + "Release version: %s \\(\\d{2} [a-z]{3} \\d{4}\\)\\R";
647     }
648 
649     ConverterCategory getCategory() {
650       return ConverterCategory.BibTeX;
651     }
652   },
653   BibTeX8 {
654     String getCommand() {
655       return "bibtex8";
656     }
657 
658     // TBD: maybe the line endings are not platform independent.
659     /**
660      * Returns the pattern for the version string. 
661      * Note that <code>bibtex8 -v</code> yields three versions, 
662      * the version of bibtex (something like 0.99d) 
663      * which is something like the specification version, 
664      * the ICU version and the release version (and date). 
665      * What is returned is the latter version.  
666      * 
667      * @return
668      *    the pattern for the version string. 
669      */
670     String getVersionPattern() {
671       return VX_X;
672     }
673 
674     String getVersionEnvironment() {
675       return "^This is 8-bit Big " + BibTeX
676           + " version .* \\(TeX Live \\d{4}\\)\\R"
677           + "Implementation: .*\\R"
678           + "Release version: %s \\(\\d{2} [a-z]{3} \\d{4}\\)\\R";
679     }
680 
681     ConverterCategory getCategory() {
682       return ConverterCategory.BibTeX;
683     }
684   },
685   Makeindex {
686     String getCommand() {
687       return "makeindex";
688     }
689 
690     String getVersionOption() {
691       return TexFileUtils.getEmptyIdx().getName().toString();
692     }
693 
694     String getVersionPattern() {
695       return VX_X;
696     }
697 
698     String getVersionEnvironment() {
699       return "^This is " + getCommand() + ", version %s "
700           + "\\[TeX Live \\d{4}\\] \\(kpathsea \\+ Thai support\\).\\R";
701     }
702 
703     ConverterCategory getCategory() {
704       return ConverterCategory.MakeIndex;
705     }
706 
707   },
708   // TBC: maybe this replaces makeindex 
709   Upmendex {
710     String getCommand() {
711       return "upmendex";
712     }
713 
714     String getVersionOption() {
715       return "-h";// Note: with --version an additional file is scanned. 
716     }
717 
718     String getVersionPattern() {
719       return VD;
720     }
721 
722     String getVersionEnvironment() {
723       return "^" + getCommand()
724           + " - index processor, version %s \\(TeX Live \\d{4}\\).\\R";
725     }
726 
727     ConverterCategory getCategory() {
728       return ConverterCategory.Unspecific;
729     }
730 
731   },
732   Xindex {
733     String getCommand() {
734       return "xindex";
735     }
736 
737     String getVersionPattern() {
738       return VD;
739     }
740 
741     String getVersionEnvironment() {
742       return "^" + getCommand()
743           + " version %s\\R";
744     }
745 
746     ConverterCategory getCategory() {
747       return ConverterCategory.Unspecific;
748     }
749 
750   },
751   // TBC: which of the versions is the relevant one? 
752   Xindy {
753     String getCommand() {
754       return "xindy";
755     }
756 
757     // TBC: not clear whether this is the significant version 
758     String getVersionPattern() {
759       return X_X_X;
760     }
761 
762     String getVersionEnvironment() {
763       return "^" + getCommand() + " release: %s\\R";
764     }
765 
766     ConverterCategory getCategory() {
767       return ConverterCategory.Unspecific;
768     }
769   },
770   Splitindex {
771     String getCommand() {
772       return "splitindex";
773     }
774 
775     String getVersionPattern() {
776       return VX_X;
777     }
778 
779     String getVersionEnvironment() {
780       return "^" + getCommand() + ".pl %s\\R";
781     }
782 
783     ConverterCategory getCategory() {
784       return ConverterCategory.SplitIndex;
785     }
786   },
787   Makeglossaries {
788     String getCommand() {
789       return "makeglossaries";
790     }
791 
792     String getVersionPattern() {
793       return VD;
794     }
795 
796     String getVersionEnvironment() {
797       return "^" + Makeglossaries + " Version %s "
798           + "\\(\\d{4}-\\d{2}-\\d{2}\\)\\R";
799     }
800 
801     ConverterCategory getCategory() {
802       return ConverterCategory.MakeGlossaries;
803     }
804   },
805   Bib2Gls {
806     String getCommand() {
807       return "bib2gls";
808     }
809 
810     String getVersionPattern() {
811       return VD;
812     }
813 
814     String getVersionEnvironment() {
815       return "^" + Bib2Gls.getCommand() + " version %s "
816           + "\\(\\d{4}-\\d{2}-\\d{2}\\)\\R";
817     }
818 
819     ConverterCategory getCategory() {
820       return ConverterCategory.Unspecific;
821     }
822   },
823   // TBD: add a category 
824   PythonTeX {
825     String getCommand() {
826       return "pythontex";
827     }
828 
829     String getVersionPattern() {
830       return VX_X;
831     }
832 
833     String getVersionEnvironment() {
834       return "^" + PythonTeX + " %s\\R";
835     }
836 
837     ConverterCategory getCategory() {
838       return ConverterCategory.Pythontex;
839     }
840   },
841   // TBD: add a category 
842   DePythonTeX {
843     String getCommand() {
844       return "depythontex";
845     }
846 
847     String getVersionPattern() {
848       return VX_X;
849     }
850 
851     String getVersionEnvironment() {
852       return "^" + DePythonTeX + " %s\\R";
853     }
854 
855     // TBD: add a category 
856     ConverterCategory getCategory() {
857       return ConverterCategory.DePythontex;
858     }
859   },
860   // TBD: add a category 
861   Latexmk {
862     String getCommand() {
863       return "latexmk";
864     }
865 
866     String getVersionPattern() {
867       return "((\\d+)\\.(\\d+)([a-z]?))";
868     }
869 
870     String getVersionEnvironment() {
871       return "^(?:.*\\R)*" + Latexmk
872           + ", John Collins, .*\\d+ [A-Z][a-z]+\\.? \\d+. Version %s\\R";
873     }
874 
875     ConverterCategory getCategory() {
876       return ConverterCategory.Latexmk;
877     }
878   },
879   MetaPost {
880     String getCommand() {
881       return "mpost";
882     }
883 
884     String getVersionPattern() {
885       return VX_X;
886     }
887 
888     String getVersionEnvironment() {
889       return "^" + MetaPost + " %s \\(TeX Live \\d{4}(?:/.+)?\\)";
890     }
891 
892     ConverterCategory getCategory() {
893       return ConverterCategory.MetaPost;
894     }
895   },
896   Extractbb {
897     String getCommand() {
898       return "extractbb";
899     }
900 
901     // 2nd line 
902     String getVersionPattern() {
903       return X_X_X;
904       //return VYYYYMMDD; // from original ebb 
905     }
906 
907     String getVersionEnvironment() {
908       return "^" +  Extractbb.getCommand() + ".lua v%s \\(\\d{4}-\\d{2}-\\d{2}\\)";
909       //return "^.*\\RThis is " + getCommand() + " Version %s\\R";// from original ebb 
910     }
911 
912     ConverterCategory getCategory() {
913       return ConverterCategory.EbbCmd;
914     }
915   },
916   Gnuplot {
917     String getCommand() {
918       return "gnuplot";
919     }
920 
921     String getVersionPattern() {
922       return "((\\d+)\\.(\\d+) patchlevel (\\d+))";
923     }
924 
925     String getVersionEnvironment() {
926       return "^" + getCommand() + " %s\\R";
927     }
928 
929     ConverterCategory getCategory() {
930       return ConverterCategory.Gnuplot2Dev;
931     }
932   },
933   Inkscape {
934     String getCommand() {
935       return "inkscape";
936     }
937 
938     String getVersionPattern() {
939       return X_X_X;
940     }
941 
942     // TBD: sometimes the pango line '    Pango version: 1.46.2' comes first. 
943     String getVersionEnvironment() {
944       return "^(?:.*\\R)?" // eliminates pango version popping up sparsely
945       // the 'unknown' is for certain distributions without hash 
946           + Inkscape + " %s \\((?:[0-9a-f]+, \\d{4}-\\d{2}-\\d{2}|unknown)\\)\\R";
947     }
948 
949     ConverterCategory getCategory() {
950       return ConverterCategory.Svg2Dev;
951     }
952   },
953   Fig2Dev {
954     String getCommand() {
955       return "fig2dev";
956     }
957 
958     String getVersionOption() {
959       return "-V";
960       // now works also --version but only from verison 3.2.9 on
961     }
962 
963     String getHelpOption() {
964       return "-h";
965     }
966 
967     String getVersionPattern() {
968       return "((\\d+)\\.(\\d+)\\.(\\d+)([a-z])?)";
969     }
970 
971     String getVersionEnvironment() {
972       return "^" + getCommand() + " Version %s\\R";
973     }
974 
975     ConverterCategory getCategory() {
976       return ConverterCategory.Fig2Dev;
977     }
978 
979   };
980 
981   /**
982    * Version pattern with major, minor and bugfix version. 
983    */
984   private final static String X_X_X = "((\\d+)\\.(\\d+)\\.(\\d+))";
985 
986   /*
987    * Version pattern with major, minor and optional bugfix version. 
988    */
989   //private final static String VX_X__X = "((\\d+)\\.(\\d+)(?:\\.(\\d+))?)";
990 
991   private final static String V_JAVA = "((\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:\\\\.(\\d+))?)";
992 
993   /**
994    * Version pattern with major, version and minor version. 
995    */
996   private final static String VX_X = "((\\d+)\\.(\\d+))";
997 
998   /**
999    * Version pattern with major version only. 
1000    */
1001   private final static String VX = "((\\d+))";
1002 
1003   /**
1004    * Special version pattern where the sequence after dot is considered fractions. 
1005    * Thus 1.3=1.30 which is bigger than 1.104. 
1006    * 
1007    * @see #VX_X
1008    */
1009   private final static String VD = "((\\d+\\.\\d+))";
1010 
1011   /**
1012    * Version signifying a date in standard ISO8601 but without hyphens. 
1013    */
1014   private final static String VYYYYMMDD = "((\\d{4})(\\d{2})(\\d{2}))";
1015 
1016   // TBC: needed? 
1017   private final static Map<String, Converter> cmd2conv;
1018   static {
1019     cmd2conv = new HashMap<String, Converter>();
1020     for (Converter conv : Converter.values()) {
1021       cmd2conv.put(conv.getCommand(), conv);
1022     }
1023   }
1024 
1025   // CAUTION: this may return null also, 
1026   // because the appropriate exception depends on the context. 
1027   /**
1028    * Given a command <code>cmd</code>, returns the according {@link Converter} 
1029    * such that {$link {@link Converter#getCommand()} returns <code>cmd</code> again.
1030    * @param cmd
1031    *    a valid command string.
1032    * @return
1033    *    The converter tied to <code>cmd</code> or <code>null</code>.
1034    */
1035   public static Converter cmd2Conv(String cmd) {
1036     return cmd2conv.get(cmd);
1037   }
1038 
1039   /**
1040    * Returns a comma separated list of command names of converters of <code>convs</code>,
1041    * i.e. for all elements of <code>convs</code> 
1042    * the according command is added to the string returned and the commands are separated 
1043    * by comma plus blank.
1044    *
1045    * @param convs
1046    *    a collection of converters.
1047    * @return
1048    *    a comma separated list of commands of the converters given.
1049    */
1050   static String toCommandsString(Collection<Converter> convs) {
1051     return convs.stream().map(x -> x.getCommand())
1052         .collect(Collectors.joining(", "));
1053   }
1054 
1055   /**
1056    * Returns a comma separated list of command names of alll converters.
1057    * 
1058    * @return
1059    *         a comma separated list of commands of all converters.
1060    */
1061   static String toCommandsString() {
1062     return toCommandsString(Arrays.asList(Converter.values()));
1063   }
1064 
1065 
1066   /**
1067    * Returns the command which which to invoke this converter. 
1068    * 
1069    * @return
1070    *    the command of this converter. 
1071    */
1072   abstract String getCommand();
1073 
1074   /**
1075    * Returns the option which just displays information 
1076    * given by {@link #getVersionEnvironment()} and among that version information 
1077    * as descried by {@link #getVersionPattern()}. 
1078    * 
1079    * @return
1080    *    the option to display (a string containing) version information. 
1081    *    As a default, this is <code>--version</code> which is the posix standard option. 
1082    *    At the same time it is quite frequent and works sometimes although not documented in help. 
1083    *    This is overwritten only because the default does not work 
1084    *    or is considerably worse than the default. 
1085    */
1086   String getVersionOption() {
1087     return "--version";
1088   }
1089 
1090   /**
1091    * Returns the option which just help information. 
1092    * 
1093    * @return
1094    *    the option to display help information. 
1095    *    As a default, this is <code>--help</code> which is the posix standard option. 
1096    *    At the same time it is quite frequent and works sometimes although not documented in help. 
1097    */
1098   String getHelpOption() {
1099     return "--help";
1100   }
1101 
1102   /**
1103    * Returns the pattern of the version for this converter as a regular expression. 
1104    * All is enclosed by brackets indicating a capturing group. 
1105    * Non capturing groups may occur without restriction 
1106    * but capturing groups except the outermost one must come sequential. 
1107    * This patters is part of the converters output 
1108    * as indicated by {@link #getVersionEnvironment()}. 
1109    * 
1110    * @return
1111    *    the pattern of the version for this converter. 
1112    */
1113   abstract String getVersionPattern();
1114 
1115   /**
1116    * Returns the pattern of the output of this converter 
1117    * if invoked with command {@link #getCommand()} and option {@link #getVersionOption()}. 
1118    * Here, the literal <code>%s</code> indicates the location 
1119    * of the proper version pattern given by {@link #getVersionPattern()}.
1120    * If this is included a regular expression emerges. 
1121    * 
1122    * @return
1123    *    the pattern of the output of this converter containing its version. 
1124    */
1125   abstract String getVersionEnvironment();
1126 
1127   // TBD: rework, eliminate Unspecific 
1128   abstract ConverterCategory getCategory();
1129 
1130 
1131   /**
1132    * Runs this converter in <code>executor</code> 
1133    * to determine a string containing version information.
1134    * 
1135    * @param executor
1136    *    the executor to run this converter with: 
1137    *    The executable given by {@link #getCommand()} 
1138    *    is passed options {@link #getVersionOption()} 
1139    *    to get version option and run 
1140    *    in the directory containing {@link TexFileUtils#getEmptyIdx()}. 
1141    * @return
1142    *    the output of the invocation 
1143    *    which matches {@link #getVersionEnvironment()}. 
1144    * @throws BuildFailureException
1145    *    TEX01 if invocation of <code>command</code> fails very basically: 
1146    *    <ul>
1147    *    <li><!-- see Commandline.execute() -->
1148    *    the file expected to be the working directory 
1149    *    does not exist or is not a directory. 
1150    *    <li><!-- see Commandline.execute() -->
1151    *    {@link Runtime#exec(String, String[], File)} fails 
1152    *    throwing an {@link java.io.IOException}. 
1153    *    <li> <!-- see CommandLineCallable.call() -->
1154    *    an error inside systemOut parser occurs 
1155    *    <li> <!-- see CommandLineCallable.call() -->
1156    *    an error inside systemErr parser occurs 
1157    *    <li> Wrapping an {@link InterruptedException} 
1158    *    on the process to be executed thrown by {@link Process#waitFor()}. 
1159    *    </ul>
1160    */
1161   String getVersionInfo(CommandExecutor executor) throws BuildFailureException {
1162     return executor.executeEnvR0(TexFileUtils.getEmptyIdx().getParentFile(), null,
1163         getCommand(), new String[] {getVersionOption()}).output;
1164   }
1165 
1166 }