LaTeX-Driver-1.3.1000755001750001750 015127547545 13010 5ustar00erikerik000000000000README100644001750001750 63015127547545 13730 0ustar00erikerik000000000000LaTeX-Driver-1.3.1This archive contains the distribution LaTeX-Driver, version 1.3.1: Run LaTeX/XeLaTeX/LuaTeX and helper programs This software is copyright (c) 2026 by Erik Huelsmann, Chris Travers, Andrew Ford. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. This README file was generated by Dist::Zilla::Plugin::Readme v6.036. Changes100644001750001750 1204415127547545 14405 0ustar00erikerik000000000000LaTeX-Driver-1.3.1Revision history for the LaTeX::Driver module -*- indented-text -*- 1.3.1 2026-01-07 - Fix version numbers 1.3.0 2026-01-07 - Fix RT #152478: program_path() exists even without executable 1.2.0 2020-10-29 - Add Log::Any logging - Use File::Temp to manage deletion of the temp directory - Eliminate manipulation of global state in method invocation - Update documentation and feedback channel 1.1.1 2020-07-29 - Fix version number presented in the POD VERSION section - Remove duplication in listed formats 1.1.0 2020-07-29 - Fix RT #133061: typo in @PROCESSORS ('lulaatex') - Add documentation of the supported processor/format combinations - Add LuaLaTeX as a processor/format combination 1.0.0 2020-05-21 - Improve error reported when invoked external program is missing - Fix RT #127951: failing tests on some installations 0.300.2 2016-04-21 - Added ps support via pdflatex 0.300.1 2016-04-17 - Added ps support for xelatex 0.300.0 2016-04-16 - Fix 0.20 refactoring made stdout 'bleed' into caller's stdout - Add more formats for explicit processor (pdf|xe)latex selection - Win32 fixes 0.200.4 2014-04-12 - Disabled bibtex tests by default due to frequently not found LaTex sty not found. - Disabled t/30 and t/31 unless dvips is found 0.200.3 2014-04-11 - xelatex tests now optional because they add too many external dependencies 0.200.1 2014-04-10 - Fixed stale dependency (unused) in Test::LaTeX::Driver 0.20 2014-04-09 - Removed IPC::ShellCmd dependency since newer versions not on CPAN - Fixed Win32 support 0.20_03 2013-10-31 - switched Makefile.PL to Module::Install 0.20_02 2013-10-29 - added -timeout option (requires IPC::ShellCmd 0.003) - added -capture_stderr option and stderr() method to retrieve captured stderr 0.20_01 2013-10-18 - Now maintained on github - reformatted Changes file - removed MYMETA.{json,yml} from MANIFEST and added to MANIFEST.SKIP (RT89155) - use IPC::ShellCmd to run commands - remove LaTeX::Driver::Paths - paths determined at runtime 0.12 2012-08-31 - fixed typo in settings of ps2pdf/pdf2ps (RT79233) - add missing dependency on Readonly (RT79330) 0.11 2012-08-30 - rewrote loop in run_latex() and need_to_run_bibtex() to use a lexical variable to avoid subtle errors with Template::Plugin::Latex (RT50684) 0.10 2011-09-18 - use system tmp directory rather than hardcoded /tmp - Makefile.PL exits if latex binary is not found (rather than dieing 0.09 2011-08-18 - Tidied up for perlcritic 0.08 2009-01-19 - Added two elements to the stats hash - 'pages' and 'bytes' - Added check for rerun required by use of the longtable package (patch submitted by Yitzchack Scott-Thoennes - cpan id: YSTM), also added test script - also check for generic /rerun to get .* right/ warning - expand documentation for Pod::Coverage 0.07 2007-10-12 - Updated documentation - specifically the diagnostics section for LaTeX::Driver and just expanded LaTeX::Driver::FilterProgram - fixed Makefile.PL, which was using LaTeX::Driver to get the module version, but this broke horribly if the prerequisite modules were not installed. - added missing test and test data files to MANIFEST 0.06 2007-09-27 - rationalized the constructor arguments - now the source and output are controlled just by three arguments: "source" and optionally "output" and "format". - the "source" and "output" parameters can be scalar references, in which case the LaTeX source and formatted output is taken from or output to the variables referenced respectively. This facilitates the creation of Unix filter type scripts. - added the Unix-style filter programs latex2dvi, latex2pdf and latex2ps (these use the common module LaTeX::Driver::FilterProgram) 0.05 2007-09-25 - default output type is now 'pdf' (that is probably what most people are going to want to generate) - added texinputs option - added the following methods: latex_path, pdflatex_path, bibtex_path, makeindex_path, dvips_path, dvipdfm_path, ps2pdf_path and program_path - the program path defaults are now stored in a package-level hash 0.04 2007-09-24 - Expanded documentation a bit more - added option parsing to test library so that test scripts can be run with -d to switch on debug messages - added basic Exception::Class based exceptions (still need to differentiate between exception types. 0.03 2007-09-24 - Expanded documentation - Reorganized testdata so that the directories/files match the names of the test scripts that use them - Added tests for constructor errors, running the module on broken LaTeX files, specifying options to makeindex, and quality metrics 0.02 2007-09-21 - First public release. 0.01 2007-09-20 - Initial version. Code extracted from the Template-Latex distribution. New maintainer: Andrew Ford. INSTALL100644001750001750 324115127547545 14122 0ustar00erikerik000000000000LaTeX-Driver-1.3.1 LaTeX::Driver Version 0.07 13 October 2007 Copyright (C) 2007 Andrew Ford. All Rights Reserved This is free software; you can redistribute it and/or modify it under the same terms as Perl itself. $Id: INSTALL 68 2007-10-12 22:59:52Z andrew $ QUICK INSTALL ------------- The latest version of the LaTeX::Driver module can be retrieved from: http://www.cpan.org/modules/by-module/LaTeX-Driver/ To install the module tar zxf LaTeX-Driver-0.06.tar.gz cd LaTeX-Driver-0.06 perl Makefile.PL make make test make install The Makefile.PL will prompt for the location of the LaTeX binaries. If it can locate the binaries then the paths will be given as defaults. If neither the latex nor the pdflatex binary can be found and no paths are given for these programs then Makefile.PL will ask whether you want to continue with the installation (as the module depends on there being a functional tex installation present on the system). For further details, see the sections below on CONFIGURATION, BUILDING AND TESTING, and INSTALLATION. PREREQUISITES ------------- The LaTeX::Driver module is written entirely in Perl and should run on any platform on which Perl is available (currently only Linux has been tested). It requires Perl 5.006 or later. The following CPAN modules are used: Class::Accessor Cwd from PathTools Exception::Class File::Slurp File::Spec from PathTools IO::File from IO There are no known dependencies on particular versions of these modules. LICENSE100644001750001750 4656115127547545 14132 0ustar00erikerik000000000000LaTeX-Driver-1.3.1This software is copyright (c) 2026 by Erik Huelsmann, Chris Travers, Andrew Ford. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2026 by Erik Huelsmann, Chris Travers, Andrew Ford. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Perl Artistic License 1.0 --- This software is Copyright (c) 2026 by Erik Huelsmann, Chris Travers, Andrew Ford. This is free software, licensed under: The Perl Artistic License 1.0 The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End dist.ini100644001750001750 175115127547545 14541 0ustar00erikerik000000000000LaTeX-Driver-1.3.1name = LaTeX-Driver abstract = Run LaTeX/XeLaTeX/LuaTeX and helper programs version = 1.3.1 author = Erik Huelsmann copyright_holder = Erik Huelsmann, Chris Travers, Andrew Ford main_module = lib/LaTeX/Driver.pm license = Perl_5 [MetaResources] homepage = https://github.com/Template-Toolkit-Latex/LaTeX-Driver bugtracker.web = https://github.com/Template-Toolkit-Latex/LaTeX-Driver/issues repository.url = git://github.com/Template-Toolkit-Latex/LaTeX-Driver.git repository.web = https://github.com/Template-Toolkit-Latex/LaTeX-Driver repository.type = git [@Basic] [MetaJSON] [ContributorsFromGit] [Prereqs] perl = 5.8.1 Capture::Tiny = 0 Class::Accessor = 0 Cwd = 0 Exception::Class = 0 File::pushd = 0 File::Slurp = 0 File::Temp = 0.23 Getopt::Long = 0 IO::File = 0 Log::Any = 0 parent = 0 Readonly = 0 [Prereqs / TestRequires] Test::More = 0.88 [Prereqs / DevelopRequires] Test::NoTabs = 0 [ExtraTests] [PodCoverageTests] [PodSyntaxTests] t000755001750001750 015127547545 13174 5ustar00erikerik000000000000LaTeX-Driver-1.3.1README100644001750001750 154215127547545 14216 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/tThis directory contains unit test scripts for the LaTeX::Driver module. The test scripts invoke the module to format documents in subdirectories of the testdata directory. Each subdirectory corresponds to a single test script (so 14-makeindex.t uses the files in testdata/14-makeindex.t, with the main LaTeX file being 14-makeindex.tex). The subdirectory should be cleaned out at the start of the test script and again at the end of the script. The test documents are structured so that they each test an aspect of LaTeX formatting and the test scripts look for a series of patterns in the generated dvi files. The function test_dvifile uses the dvitype program if found to extract the strings from a DVI file. TODO ==== write test scripts to cover * included graphics * documents with errors (in progress) * test generation of PDF and PostScript files META.yml100644001750001750 272715127547545 14352 0ustar00erikerik000000000000LaTeX-Driver-1.3.1--- abstract: 'Run LaTeX/XeLaTeX/LuaTeX and helper programs' author: - 'Erik Huelsmann ' build_requires: Test::More: '0.88' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.036, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: LaTeX-Driver requires: Capture::Tiny: '0' Class::Accessor: '0' Cwd: '0' Exception::Class: '0' File::Slurp: '0' File::Temp: '0.23' File::pushd: '0' Getopt::Long: '0' IO::File: '0' Log::Any: '0' Readonly: '0' parent: '0' perl: v5.8.1 resources: bugtracker: https://github.com/Template-Toolkit-Latex/LaTeX-Driver/issues homepage: https://github.com/Template-Toolkit-Latex/LaTeX-Driver repository: git://github.com/Template-Toolkit-Latex/LaTeX-Driver.git version: 1.3.1 x_contributors: - 'Andrew Ford ' - 'Andrew Ford ' - 'Chris Travers ' - 'Chris Travers ' - 'Christian Walde ' - 'Erik Huelsmann ' - 'Harrison Chienjo ' - 'Jens Rehsack ' - 'ehuelsmann ' - 'simbabque ' x_generated_by_perl: v5.38.2 x_serialization_backend: 'YAML::Tiny version 1.76' x_spdx_expression: 'Artistic-1.0-Perl OR GPL-1.0-or-later' MANIFEST100644001750001750 304615127547545 14225 0ustar00erikerik000000000000LaTeX-Driver-1.3.1# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.036. Changes INSTALL LICENSE MANIFEST META.json META.yml Makefile.PL README README.md dist.ini lib/LaTeX/Driver.pm lib/LaTeX/Driver.pm~ lib/LaTeX/Driver/FilterProgram.pm lib/LaTeX/Driver/FilterProgram.pm~ script/README script/latex2dvi script/latex2pdf script/latex2ps t/00-basic.t t/01-errors.t t/02-brokendocs.t t/10-simpledoc.t t/11-references.t t/12-includes.t t/13-tableofcontents.t t/14-makeindex.t t/15-bibtex.t t/20-complexdoc.t t/30-output-to-variable.t t/31-input-from-variable.t t/40-pkg-longtable.t t/90-kwalitee.t t/91-pod.t t/93-perl-critic.t t/README t/author-pod-coverage.t t/author-pod-syntax.t t/lib/Test/LaTeX/Driver.pm t/perlcriticrc t/testdata/00-common/testinc2.tex t/testdata/01-errors/01-errors.tex t/testdata/02-brokendocs/02-brokendocs.tex t/testdata/10-simpledoc/10-simpledoc.tex t/testdata/11-references/11-references.tex t/testdata/12-includes/12-includes.tex t/testdata/12-includes/testinc.aux t/testdata/12-includes/testinc.tex t/testdata/13-tableofcontents/13-tableofcontents.tex t/testdata/14-makeindex/14-makeindex.tex t/testdata/14-makeindex/testind.ist t/testdata/15-bibtex/15-bibtex.tex t/testdata/15-bibtex/testbib.bib t/testdata/20-complexdoc/20-complexdoc.tex t/testdata/20-complexdoc/testbib.bib t/testdata/20-complexdoc/testinc.aux t/testdata/20-complexdoc/testinc.tex t/testdata/30-output-to-variable/30-output-to-variable.tex t/testdata/31-input-from-variable/31-input-from-variable.tex t/testdata/40-pkg-longtable/40-pkg-longtable.tex t/testdata/README README.md100644001750001750 62515127547545 14333 0ustar00erikerik000000000000LaTeX-Driver-1.3.1LaTeX-Driver ============ [![Travis Status](https://travis-ci.com/Template-Toolkit-Latex/LaTeX-Driver.svg?branch=master)](https://travis-ci.org/Template-Toolkit-Latex/LaTeX-Driver) [![Coverage Status](https://coveralls.io/repos/github/Template-Toolkit-Latex/LaTeX-Driver/badge.svg?branch=master)](https://coveralls.io/github/Template-Toolkit-Latex/LaTeX-Driver?branch=master) Perl module to drive LaTeX META.json100644001750001750 467215127547545 14523 0ustar00erikerik000000000000LaTeX-Driver-1.3.1{ "abstract" : "Run LaTeX/XeLaTeX/LuaTeX and helper programs", "author" : [ "Erik Huelsmann " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.036, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "LaTeX-Driver", "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "develop" : { "requires" : { "Pod::Coverage::TrustPod" : "0", "Test::NoTabs" : "0", "Test::Pod" : "1.41", "Test::Pod::Coverage" : "1.08" } }, "runtime" : { "requires" : { "Capture::Tiny" : "0", "Class::Accessor" : "0", "Cwd" : "0", "Exception::Class" : "0", "File::Slurp" : "0", "File::Temp" : "0.23", "File::pushd" : "0", "Getopt::Long" : "0", "IO::File" : "0", "Log::Any" : "0", "Readonly" : "0", "parent" : "0", "perl" : "v5.8.1" } }, "test" : { "requires" : { "Test::More" : "0.88" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/Template-Toolkit-Latex/LaTeX-Driver/issues" }, "homepage" : "https://github.com/Template-Toolkit-Latex/LaTeX-Driver", "repository" : { "type" : "git", "url" : "git://github.com/Template-Toolkit-Latex/LaTeX-Driver.git", "web" : "https://github.com/Template-Toolkit-Latex/LaTeX-Driver" } }, "version" : "1.3.1", "x_contributors" : [ "Andrew Ford ", "Andrew Ford ", "Chris Travers ", "Chris Travers ", "Christian Walde ", "Erik Huelsmann ", "Harrison Chienjo ", "Jens Rehsack ", "ehuelsmann ", "simbabque " ], "x_generated_by_perl" : "v5.38.2", "x_serialization_backend" : "Cpanel::JSON::XS version 4.40", "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later" } 91-pod.t100755001750001750 43115127547545 14513 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl use strict; use Test::More; BEGIN { plan( skip_all => 'Author test. Set $ENV{TEST_AUTHOR} to a true value to run.' ) unless $ENV{TEST_AUTHOR}; } eval "use Test::Pod"; plan skip_all => "Test::Pod required for testing POD" if $@; all_pod_files_ok(); Makefile.PL100644001750001750 303015127547545 15037 0ustar00erikerik000000000000LaTeX-Driver-1.3.1# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.036. use strict; use warnings; use 5.008001; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "Run LaTeX/XeLaTeX/LuaTeX and helper programs", "AUTHOR" => "Erik Huelsmann ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "LaTeX-Driver", "LICENSE" => "perl", "MIN_PERL_VERSION" => "5.008001", "NAME" => "LaTeX::Driver", "PREREQ_PM" => { "Capture::Tiny" => 0, "Class::Accessor" => 0, "Cwd" => 0, "Exception::Class" => 0, "File::Slurp" => 0, "File::Temp" => "0.23", "File::pushd" => 0, "Getopt::Long" => 0, "IO::File" => 0, "Log::Any" => 0, "Readonly" => 0, "parent" => 0 }, "TEST_REQUIRES" => { "Test::More" => "0.88" }, "VERSION" => "1.3.1", "test" => { "TESTS" => "t/*.t" } ); my %FallbackPrereqs = ( "Capture::Tiny" => 0, "Class::Accessor" => 0, "Cwd" => 0, "Exception::Class" => 0, "File::Slurp" => 0, "File::Temp" => "0.23", "File::pushd" => 0, "Getopt::Long" => 0, "IO::File" => 0, "Log::Any" => 0, "Readonly" => 0, "Test::More" => "0.88", "parent" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); 00-basic.t100644001750001750 21715127547545 14777 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 00-basic.t 4 2007-09-21 14:51:24Z andrew $ use strict; use blib; use Test::More tests => 1; use_ok("LaTeX::Driver"); script000755001750001750 015127547545 14235 5ustar00erikerik000000000000LaTeX-Driver-1.3.1README100644001750001750 37115127547545 15236 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/scriptThe scripts in this directory provide classic Unix-style filters for LaTeX source to dvi, PostScript and PDF output. The functionality of the three scripts is virtually identical so it is abstracted out into a module: LaTeX::Driver::FilterProgram. 01-errors.t100755001750001750 311715127547545 15260 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # Script to test LaTeX::Driver's error handling # $Id: 01-errors.t 50 2007-09-28 10:51:47Z andrew $ use strict; use blib; use vars qw($testno $basedir $docname $drv $debug $debugprefix $dont_tidy_up); use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More; BEGIN { eval "use Test::Exception"; plan skip_all => "Test::Exception needed" if $@; } use Test::LaTeX::Driver; use LaTeX::Driver; plan tests => 5; # For some of our tests we need a directory that does not exist, we # had better make sure that someone hasn't created it. my $nonexistent_dir = "$basedir/this-directory-should-not-exist"; die "hey, someone created our non-existent directory" if -d $nonexistent_dir; diag("testing constructor error handling"); dies_ok { LaTeX::Driver->new( DEBUG => $debug, DEBUGPREFIX => $debugprefix ) } 'no source specified'; like($@, qr{no source specified}, 'constructor fails without a source'); dies_ok { LaTeX::Driver->new( source => $docpath, format => 'tiff', DEBUG => $debug, DEBUGPREFIX => $debugprefix ) } 'unsupported output type'; like($@, qr{invalid output format}, "'tiff' is not a supported output type"); diag("execution error handling"); $LaTeX::Driver::program_path{'xelatex'} = 'abcdefghijklmnopqrstuvwxyz0123456789'; my $drv = LaTeX::Driver->new( source => 't/testdata/01-errors/01-errors' ); dies_ok { $drv->run_latex; } 'Failure to start abcdefghijklm'; exit(0); 15-bibtex.t100755001750001750 315715127547545 15232 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 15-bibtex.t 62 2007-10-03 14:20:44Z andrew $ use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More; use Test::LaTeX::Driver; use LaTeX::Driver; plan skip_all => 'BIBTEX_TESTS not set. Requires lastpage.sty.' unless $ENV{BIBTEX_TESTS}; plan tests => 8; tidy_directory($basedir, $docname, $debug); my $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', @DEBUGOPTS ); diag("Checking the formatting of a LaTeX document with a bibliography"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{runs}{latex}, 3, "should have run latex three times"); is($drv->stats->{runs}{bibtex}, 1, "should have run bibtex once"); is($drv->stats->{runs}{makeindex}, undef, "should not have run makeindex"); test_dvifile($drv, [ "Simple Test Document $testno", # title 'A.N. Other', # author '20 September 2007', # date 'This is a test document with a bibliography.', 'We reference the Badger book\\[', 'WCC03', '^References$', # bibliography section heading '^\\s*\\[WCC03\\]$', # the bibiographic key 'Andy Wardley, Darren Chamberlain, and Dave Cross.', '^ 1$' ] ); # page number 1 tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); perlcriticrc100644001750001750 42015127547545 15720 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t# perlcriticrc file for our Test::Perl::Critic tests severity = 3 only = 1 force = 0 verbose = 4 top = 50 theme = (pbp || security) && bugs include = NamingConventions ClassHierarchies exclude = Variables Modules::RequirePackage #color = 0 latex2ps100755001750001750 271615127547545 16073 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/script#!/usr/bin/perl -w #======================================================================== # # latex2ps # # DESCRIPTION # Script for processing and rendering a template document using the # Perl Template Toolkit. # # AUTHOR # Andrew Ford # # COPYRIGHT # Copyright (C) 2007 Andrew Ford. All Rights Reserved. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #------------------------------------------------------------------------ # # $Id: latex2ps 59 2007-09-28 14:39:34Z andrew $ # #======================================================================== use strict; use warnings; use LaTeX::Driver::FilterProgram; LaTeX::Driver::FilterProgram->execute(format => 'dvi'); exit(0); __END__ =head1 NAME latex2ps - script to convert LaTeX file to PostScript =head1 SYNOPSIS latex2ps [OPTIONS] [-o output] [sourcefile] =head1 DESCRIPTION C is a simple script to invoke the C module to convert a LaTeX file to PostScript. TO BE EXPANDED =head1 AUTHOR Andrew Ford EA.Ford@ford-mason.co.ukE =head1 LICENSE AND COPYRIGHT Copyright (C) 2007 Andrew Ford. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: 12-includes.t100755001750001750 257215127547545 15560 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 12-includes.t 62 2007-10-03 14:20:44Z andrew $ use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More tests => 8; use Test::LaTeX::Driver; use LaTeX::Driver; tidy_directory($basedir, $docname, $debug); my $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', @DEBUGOPTS ); diag("Checking the formatting of a LaTeX document that includes other files"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{runs}{latex}, 1, "should have run latex once"); is($drv->stats->{runs}{bibtex}, undef, "should not have run bibtex"); is($drv->stats->{runs}{makeindex}, undef, "should not have run makeindex"); test_dvifile($drv, [ "Simple Test Document $testno", # title 'A.N. Other', # author '20 September 2007', # date 'This is a test document that includes another file.', '^ 1$', # page number 1 'This is text from an included file.', '^ 2$' ] ); # page number 2 tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); 90-kwalitee.t100755001750001750 44715127547545 15544 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl use strict; use Test::More; plan( skip_all => 'Author test. Set $ENV{TEST_AUTHOR} to a true value to run.' ) unless $ENV{TEST_AUTHOR}; eval { require Test::Kwalitee; Test::Kwalitee->import() }; plan( skip_all => 'Test::Kwalitee not installed; skipping' ) if $@; latex2pdf100644001750001750 270315127547545 16213 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/script#!/usr/bin/perl -w #======================================================================== # # latex2pdf # # DESCRIPTION # Script for processing and rendering a template document using the # Perl Template Toolkit. # # AUTHOR # Andrew Ford # # COPYRIGHT # Copyright (C) 2007 Andrew Ford. All Rights Reserved. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #------------------------------------------------------------------------ # # $Id: latex2pdf 59 2007-09-28 14:39:34Z andrew $ # #======================================================================== use strict; use warnings; use LaTeX::Driver::FilterProgram; LaTeX::Driver::FilterProgram->execute(format => 'pdf'); exit(0); __END__ =head1 NAME latex2pdf - script to convert LaTeX file to PDF =head1 SYNOPSIS latex2pdf [OPTIONS] [-o output] [sourcefile] =head1 DESCRIPTION C is a simple script to invoke the C module to convert a LaTeX file to PDF. TO BE EXPANDED =head1 AUTHOR Andrew Ford EA.Ford@ford-mason.co.ukE =head1 LICENSE AND COPYRIGHT Copyright (C) 2007 Andrew Ford. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: latex2dvi100755001750001750 501115127547545 16222 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/script#!/usr/bin/perl -w #======================================================================== # # latex2dvi # # DESCRIPTION # Script for processing and rendering a template document using the # Perl Template Toolkit. # # AUTHOR # Andrew Ford # # COPYRIGHT # Copyright (C) 2007 Andrew Ford. All Rights Reserved. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # #------------------------------------------------------------------------ # # $Id: latex2dvi 73 2007-10-12 23:11:27Z andrew $ # #======================================================================== use strict; use warnings; use LaTeX::Driver::FilterProgram; LaTeX::Driver::FilterProgram->execute(format => 'dvi'); exit 0; __END__ =head1 NAME latex2dvi - script to convert LaTeX file to DVI =head1 USAGE latex2dvi [OPTIONS] [-o output] [sourcefile] =head1 DESCRIPTION C is a simple script to invoke the C module to convert a LaTeX file to DVI (TeX's device independent output format). TO BE EXPANDED =head1 REQUIRED ARGUMENTS =head1 OPTIONS =over 4 =item C<-output=FILE> specifies that the formatted file should be written to C. If this option is not specified, or is specified as "C<->" then the file will be written to standard output, otherwise if an input file is specified then the it will be formatted in place and the output file will have the same name as the input file, but with the original extension replaced with C<.dvi>. =item C<-tt2> specifies that the source document should be taken to be a Template Toolkit template and processed through that before being fed to the C module for latex formatting. =item C<-define=I=I> defines the template variable I to have the value I. Multiple template variables may be defined and these are passed to the Template Toolkit processing stage (they are ignored if the C<-tt2> option is not specified). =back =head1 DIAGNOSTICS =head1 EXIT STATUS =head1 CONFIGURATION =head1 DEPENDENCIES =head1 INCOMPATIBILITIES =head1 BUGS AND LIMITATIONS =head1 AUTHOR Andrew Ford EA.Ford@ford-mason.co.ukE =head1 LICENSE AND COPYRIGHT Copyright (C) 2007 Andrew Ford. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: 14-makeindex.t100755001750001750 576715127547545 15732 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 14-makeindex.t 62 2007-10-03 14:20:44Z andrew $ # # Test out invocation of makeindex: # * Tests the default invocation of makeindex # * Tests alternate style (replaces comma after index term with colon) # * Tests index options (uses -l for letter ordering of index entries use strict; use warnings; use vars qw($debug $dont_tidy_up $drv); use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More; use Test::LaTeX::Driver; use LaTeX::Driver; system('makeindex', '--help'); if ($? == -1) { plan skip_all => q{Can't execute "makeindex"}; } else { plan tests => 14; } tidy_directory($basedir, $docname, $debug); $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', @DEBUGOPTS ); diag("Checking the formatting of a LaTeX document with an index"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{runs}{latex}, 2, "should have run latex twice"); is($drv->stats->{runs}{bibtex}, undef, "should not have run bibtex"); is($drv->stats->{runs}{makeindex}, 1, "should have run makeindex once"); test_dvifile($drv, [ "Simple Test Document $testno", # title 'A.N. Other', # author '20 September 2007', # date "This is a test document that defines the index terms `seal' and `sea lion'.", "These are the example terms used in the makeindex man page.", '^ 1$', # page number 1 '^Index$', # Index section heading # word ordering of index entries 'sea lion, 1$', # two-word index term 'seal, 1$', # one-word index term '^ 2$' ] ); # page number 2 tidy_directory($basedir, $docname, $debug); diag("run again with an explicit index style option"); $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', indexstyle => 'testind', @DEBUGOPTS ); isa_ok($drv, 'LaTeX::Driver'); ok($drv->run, "formatting $docname"); test_dvifile($drv, [ '^Index$', # Index section heading # word ordering of index entries 'sea lion: 1$', # two-word index term 'seal: 1$', # one-word index term '^ 2$' ] ); # page number 2 tidy_directory($basedir, $docname, $debug); diag("run again with -l (letter ordering) option"); $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', indexoptions => '-l', @DEBUGOPTS ); isa_ok($drv, 'LaTeX::Driver'); ok($drv->run, "formatting $docname"); test_dvifile($drv, [ '^Index$', # Index section heading # letter ordering of index entries 'seal, 1$', # one-word index term 'sea lion, 1$', # two-word index term '^ 2$' ] ); # page number 2 tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); 10-simpledoc.t100755001750001750 570515127547545 15730 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 10-simpledoc.t 85 2012-08-31 19:08:22Z andrew $ use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More; use Test::LaTeX::Driver; use LaTeX::Driver; tidy_directory($basedir, $docname, $debug); my $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', @DEBUGOPTS ); plan skip_all => 'FORMATTER_TESTING not set' unless $ENV{FORMATTER_TESTING}; plan tests => 24; diag("Checking the formatting of a simple LaTeX document"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{runs}{latex}, 1, "should have run latex once"); is($drv->stats->{runs}{bibtex}, undef, "should not have run bibtex"); is($drv->stats->{runs}{makeindex}, undef, "should not have run makeindex"); test_dvifile($drv, [ "Simple Test Document $testno", # title 'A.N. Other', # author '20 September 2007', # date 'This is a test document with a single line of text.' ] ); tidy_directory($basedir, $docname, $debug); diag("Checking the generation of PDF"); $drv = LaTeX::Driver->new( source => $docpath, format => 'pdf', @DEBUGOPTS ); ok($drv->run, "formatting $docname"); ok(-f ($drv->basepath . '.pdf'), "PDF file exists"); ok(! -f ($drv->basepath . '.dvi'), "but DVI file doesn't"); ok(! -f ($drv->basepath . '.ps'), "but PS file doesn't"); tidy_directory($basedir, $docname, $debug); diag("Checking the generation of PostScript"); $drv = LaTeX::Driver->new( source => $docpath, format => 'ps', @DEBUGOPTS ); ok($drv->run, "formatting $docname to PostScript"); ok(-f ($drv->basepath . '.ps'), "PostScript file exists"); ok(-f ($drv->basepath . '.dvi'), "as does DVI file"); ok(! -f ($drv->basepath . '.pdf'), "but PS file doesn't"); tidy_directory($basedir, $docname, $debug); diag("Checking the generation of PDF, via PostScript"); $drv = LaTeX::Driver->new( source => $docpath, format => 'pdf(ps)', @DEBUGOPTS ); ok($drv->run, "formatting $docname to PDF, via PostScript"); ok(-f ($drv->basepath . '.pdf'), "PDF file exists"); ok(-f ($drv->basepath . '.ps'), "PostScript file exists"); ok(-f ($drv->basepath . '.dvi'), "DVI file exists"); tidy_directory($basedir, $docname, $debug); diag("Checking the generation of PostScript, via PDF"); $drv = LaTeX::Driver->new( source => $docpath, format => 'ps(pdf)', @DEBUGOPTS ); ok($drv->run, "formatting $docname to PostScript, via PDF"); ok(-f ($drv->basepath . '.pdf'), "PDF file exists"); ok(-f ($drv->basepath . '.ps'), "PostScript file exists"); ok(! -f ($drv->basepath . '.dvi'), "DVI file does not exists"); tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); 02-brokendocs.t100755001750001750 253715127547545 16103 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 02-brokendocs.t 62 2007-10-03 14:20:44Z andrew $ use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More; BEGIN { eval "use Test::Exception"; plan skip_all => "Test::Exception needed" if $@; } use Test::LaTeX::Driver; use LaTeX::Driver; plan tests => 8; tidy_directory($basedir, $docname, $debug); my $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', DEBUG => $debug, DEBUGPREFIX => '# [latex]: ' ); diag("Checking the formatting of a simple LaTeX document"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); throws_ok( sub { $drv->run }, 'LaTeX::Driver::Exception', "formatting broken document $docname"); is($drv->stats->{runs}{latex}, 1, "should have run latex once"); is($drv->stats->{runs}{bibtex}, undef, "should not have run bibtex"); is($drv->stats->{runs}{makeindex}, undef, "should not have run makeindex"); test_dvifile($drv, [ 'This is a test document with a broken LaTeX command.' ] ); tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); 11-references.t100755001750001750 270515127547545 16070 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 11-references.t 62 2007-10-03 14:20:44Z andrew $ use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More tests => 8; use Test::LaTeX::Driver; use LaTeX::Driver; tidy_directory($basedir, $docname, $debug); my $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', @DEBUGOPTS ); diag("Checking the formatting of a LaTeX document with forward references"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{runs}{latex}, 2, "should have run latex twice"); is($drv->stats->{runs}{bibtex}, undef, "should not have run bibtex"); is($drv->stats->{runs}{makeindex}, undef, "should not have run makeindex"); test_dvifile($drv, [ "Simple Test Document $testno", # title 'A.N. Other', # author '20 September 2007', # date 'This is a test document containing a forward reference.', 'See page 2.', # second para with page ref '^ 1$', # page number 1 'This is the second page.', # text on second page '^ 2$' ] ); # page number 2 tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); 20-complexdoc.t100755001750001750 616015127547545 16103 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 20-complexdoc.t 79 2009-01-19 13:42:09Z andrew $ use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More; use Test::LaTeX::Driver; use LaTeX::Driver; plan skip_all => 'BIBTEX_TESTS not set. Requires lastpage.sty.' unless $ENV{BIBTEX_TESTS}; plan tests => 10; tidy_directory($basedir, $docname, $debug); my $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', TEXINPUTS => [ "$Bin/testdata/00-common"], @DEBUGOPTS ); diag("Checking the formatting of a complex LaTeX document with references, a bibliography, an index, etc"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{pages}, 12, "should have 12 pages of output"); cmp_ok($drv->stats->{runs}{latex}, '>=', 5, "should have run latex at least five times"); cmp_ok($drv->stats->{runs}{latex}, '<=', 8, "should have run latex not more than eight times"); is($drv->stats->{runs}{bibtex}, 1, "should have run bibtex once"); is($drv->stats->{runs}{makeindex}, 2, "should have run makeindex twice"); test_dvifile($drv, [ "Complex Test Document $testno", # title 'A.N. Other', # author '20 September 2007', # date '^Contents$', # table of contents header 'This is a test document with all features.', 'The document has 12 pages.', 'Forward Reference', # section title 'Here is a reference to page 9.', 'File Inclusion', 'Here we include another file.', 'Included File', # section title 'This is text from an included file.', 'Bibliographic Citations', 'We reference the Badger book\\[', '^WCC03$', '\\] and the Camel book\\[', '^Wal03$', 'Index Term', 'Here is the definition of the index term .xyzzy.', '^References$', # bibliography section heading '^\\s*\\[WCC03\\]$', # the bibiographic key 'Andy Wardley, Darren Chamberlain, and Dave Cross.', '^Index$', # Index section heading '\\bxyzzy, 8$', # the index term '\\bxyzzy2, 12$', # index term from the colophon '11$', # page number 11 'Colophon$' ] ); tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); testdata000755001750001750 015127547545 15005 5ustar00erikerik000000000000LaTeX-Driver-1.3.1/tREADME100644001750001750 21615127547545 16004 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t/testdataThis directory hierachy contains testdata for the LaTeX::Driver unit tests. Each of the subdirectories corresponds with a specific unit test.93-perl-critic.t100755001750001750 105115127547545 16167 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl use strict; use warnings; use FindBin qw($Bin); use File::Spec; use Test::More; use English qw(-no_match_vars); if ( not $ENV{TEST_AUTHOR} ) { my $msg = 'Author test. Set $ENV{TEST_AUTHOR} to a true value to run.'; plan( skip_all => $msg ); } eval { require Test::Perl::Critic; }; if ( $EVAL_ERROR ) { my $msg = 'Test::Perl::Critic required to criticise code'; plan( skip_all => $msg ); } my $rcfile = File::Spec->catfile( $Bin, 'perlcriticrc' ); Test::Perl::Critic->import( -profile => $rcfile ); all_critic_ok(); LaTeX000755001750001750 015127547545 14454 5ustar00erikerik000000000000LaTeX-Driver-1.3.1/libDriver.pm100644001750001750 12072515127547545 16454 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/lib/LaTeX# LaTeX::Driver # # DESCRIPTION # Driver module that encapsulates the details of formatting a LaTeX document # package LaTeX::Driver; use strict; use warnings; use 5.008005; use parent 'Class::Accessor'; use Cwd; # from PathTools use English qw( -no_match_vars ); # standard Perl class use Exception::Class ( 'LaTeX::Driver::Exception' ); use File::Copy; # standard Perl class use File::Compare; # standard Perl class use File::Path; # standard Perl class use File::Slurp; use File::Spec; # from PathTools use File::Temp; use IO::File; # from IO use Readonly; use File::pushd; # temporary cwd changes use Capture::Tiny qw(capture); use Log::Any qw($log); Readonly our $DEFAULT_MAXRUNS => 10; our $VERSION = "1.3.1"; __PACKAGE__->mk_accessors( qw( basename basedir basepath options source output tmpdir format timeout stderr formatter preprocessors postprocessors _program_path maxruns extraruns stats texinputs_path undefined_citations undefined_references labels_changed rerun_required ) ); our $DEBUG; our $DEBUGPREFIX; # LaTeX executable paths set at installation time by the Makefile.PL our @PROCESSORS = qw(xelatex lualatex pdflatex latex); our @AUXILLARY_PROGS = qw(bibtex makeindex); our @POSTPROCESSORS = qw(dvips dvipdfm ps2pdf pdf2ps); our @PROGRAM_NAMES = (@PROCESSORS, @AUXILLARY_PROGS, @POSTPROCESSORS); our %program_path = map { ( $_ => $_ ) } @PROGRAM_NAMES; our @LOGFILE_EXTS = qw( log blg ilg ); our @TMPFILE_EXTS = qw( aux log lot toc bbl ind idx cit cbk ibk ); our $DEFAULT_TMPDIR = 'latexdrv'; our $DEFAULT_DOCNAME = 'latexdoc'; # valid output formats and program alias our $DEFAULT_FORMAT = 'pdf'; our %FORMATTERS = ( dvi => [ 'latex' ], ps => [ 'latex', 'dvips' ], postscript => [ 'latex', 'dvips' ], pdf => [ 'xelatex' ], 'pdf(pdflatex)' => [ 'pdflatex' ], 'pdf(xelatex)' => [ 'xelatex' ], 'pdf(lualatex)' => [ 'lualatex' ], 'pdf(dvi)' => [ 'latex', 'dvipdfm' ], 'pdf(ps)' => [ 'latex', 'dvips', 'ps2pdf' ], 'ps(pdf)' => [ 'pdflatex', 'pdf2ps' ], 'ps(pdflatex)' => [ 'pdflatex', 'pdf2ps' ], 'ps(xelatex)' => [ 'xelatex', 'pdf2ps' ], 'ps(lualatex)' => [ 'lualatex', 'pdf2ps' ], ); #------------------------------------------------------------------------ # new(%options) # # Constructor for the Latex driver #------------------------------------------------------------------------ sub new { my $class = shift; my $options = ref $_[0] ? shift : { @_ }; my ($volume, $basedir, $basename, $basepath, $orig_ext, $cleanup); my ($formatter, @postprocessors); # Sanity check first - check we're running on a supported OS $class->throw("not available on $OSNAME") if $OSNAME =~ m/ ^ ( MacOS | os2 | VMS ) $ /ix; # Examine the options - we need at least a source to work with and # it should be a scalar reference or a valid filename. my $source = delete $options->{source}; $class->throw("no source specified") unless $source; if (ref $source) { $class->throw("source is an invalid reference $source") if ref $source ne 'SCALAR'; } else { $source =~ s/ ( [.] tex ) $ //x; $orig_ext = $1; $class->throw("source file ${source}.tex does not exist") unless -f $source or -f "${source}.tex"; } # Determine how the document is to be processed. Either specified # explicitly in the format parameter or if an output file is # specified it is taken from that, or the default is take. my $output = $options->{output}; my $format; $format = lc($options->{format}) if $options->{format}; if ($output and (!ref $output)) { my ($volume, $dir, $file) = File::Spec->splitpath($output); $class->throw("output directory $dir does not exist") unless $dir and -d $dir; if ((!$format) and ($file =~ / [.] ( \w+ ) $ /x)) { $format = lc($1); } } # There is a formatter and zero or more postprocessors for each # format; there are also special formats 'pdf(dvi)', 'pdf(ps)' and # 'ps(pdf)' that specify alternate routes to generate the format. $format ||= $DEFAULT_FORMAT; $class->throw("invalid output format: '$format'") unless exists $FORMATTERS{$format}; ($formatter, @postprocessors) = @{$FORMATTERS{$format}}; # discard the parenthesized part of special formats $format =~ s/\(.*\)//; # If a temporary directory was specified or the LaTeX source was # given as a scalar reference then a temporary directory is # created and the document source written to that directory or # copied in if the source is a file. my $tmpdir = $options->{tmpdir}; if ($tmpdir or ref $source) { $basedir = $class->_setup_tmpdir($tmpdir); if (ref $source) { $basename = $DEFAULT_DOCNAME; $basepath = File::Spec->catfile($basedir, $basename); write_file($basepath . ".tex", $source) or $class->throw("cannot create temporary latex file"); } else { ($basename = $source) =~ s{.*/}{}; $basepath = File::Spec->catfile($basedir, $basename); copy("$source$orig_ext", "${basepath}.tex") or $class->throw("cannot copy $source$orig_ext to temporary directory"); $output ||= "${source}.$format"; } } # Otherwise the source was given as a filename, so the base name # and directory are taken from the source name. else { ($volume, $basedir, $basename) = File::Spec->splitpath($source); $basename =~ s/\.tex$//; if ($basedir and $volume) { $basedir = File::Spec->catfile($volume, $basedir); } $basedir ||= getcwd; $basedir =~ s{(.)/$}{$1}; $basepath = File::Spec->catfile($basedir, $basename); } # Set up a mapping of program name to full pathname. # This is initialized from the paths detemined at installation # time, but any specified in the paths option override these # values. $options->{paths} ||= {}; my $path = {}; map { $path->{$_} = $program_path{$_}; } @PROGRAM_NAMES; map { $path->{$_} = $options->{paths}->{$_}; } keys %{ $options->{paths} }; # Set up the texinputs path my $texinputs_path = $options->{TEXINPUTS} || $options->{texinputs} || []; $texinputs_path = [ split(/:/, $texinputs_path) ] unless ref $texinputs_path; # see http://tex.stackexchange.com/questions/149714/149865#149865 my $texinputs_sep = $OSNAME eq "MSWin32" ? ';' : ':'; # construct and return the object return $class->SUPER::new( { basename => $basename, basedir => "$basedir", _file_tmp_base => $basedir, # retain ref during object life basepath => $basepath, format => $format, output => $output, cleanup => $cleanup || '', options => $options, maxruns => $options->{maxruns} || $DEFAULT_MAXRUNS, extraruns => $options->{extraruns} || 0, timeout => $options->{timeout}, capture_stderr => $options->{capture_stderr} || 0, formatter => $formatter, _program_path => $path, texinputs_path => join($texinputs_sep, ('.', @{$texinputs_path}, '')), preprocessors => [], postprocessors => \@postprocessors, stats => { runs => {} } }); } #------------------------------------------------------------------------ # run() # # Runs the formatter and other programs to generate the ouptut. #------------------------------------------------------------------------ sub run { my $self = shift; # Check that the file exists $self->throw(sprintf('file %s.tex does not exist', $self->basepath)) unless -f $self->basepath . '.tex'; # Run any preprocessors (none specified yet). map { $self->$_ } @{$self->preprocessors}; # Run LaTeX and friends until an error occurs, the document # stabilizes, or the maximum number of runs is reached. my $maxruns = $self->maxruns; my $extraruns = $self->extraruns; RUN: foreach my $run (1 .. $maxruns) { if ($self->need_to_run_latex or $extraruns-- > 0) { $self->run_latex; } elsif ($self->need_to_run_bibtex) { $self->run_bibtex; } elsif ($self->need_to_run_makeindex) { $self->run_makeindex; } } # Run any postprocessors (e.g.: dvips, ps2pdf, etc). foreach my $postproc (@{$self->postprocessors}) { my $method = $postproc; if ($self->can($method)) { $self->$method(); } else { $method = 'run_' . $postproc; if ($self->can($method)) { $self->$method(); } else { $self->throw("cannot find postprocessor $postproc"); } } } # Return any output $self->copy_to_output if $self->output; return 1; } #------------------------------------------------------------------------ # run_latex() # # Run the latex processor (latex or pdflatex depending on what is configured). #------------------------------------------------------------------------ sub run_latex { my $self = shift; my $basename = $self->basename; my $exitcode = $self->run_command($self->formatter => "\\nonstopmode\\def\\TTLATEX{1}\\input{./$basename}"); # If an error occurred attempt to extract the interesting lines # from the log file. Even without errors the log file may contain # interesting warnings indicating that LaTeX or one of its friends # must be rerun. my $errors = ""; my $logfile = $self->basepath . ".log"; if (my $fh = IO::File->new($logfile, "r")) { $self->reset_latex_required; my $matched = 0; while ( my $line = <$fh> ) { $log->trace($line); # TeX errors start with a "!" at the start of the # line, and followed several lines later by a line # designator of the form "l.nnn" where nnn is the line # number. We make sure we pick up every /^!/ line, # and the first /^l.\d/ line after each /^!/ line. if ( $line =~ /^(!.*)/ ) { $errors .= $1 . "\n"; $matched = 1; } elsif ( $matched && ($line =~ /^(l\.\d.*)/) ) { $errors .= $1 . "\n"; $matched = 0; } elsif ( $line =~ /^Output written on (.*) \((\d+) pages, (\d+) bytes\)./ ) { my ($ofile, $pages, $bytes) = ($1, $2, $3); $self->{stats}{pages} = $pages; $self->{stats}{bytes} = $bytes; } elsif ( $line =~ /^LaTeX Warning: Reference .*? on page \d+ undefined/ ) { $self->undefined_references(1); } elsif ( $line =~ /^LaTeX Warning: Citation .* on page \d+ undefined/ ) { $self->debug('undefined citations detected'); $self->undefined_citations(1); } elsif ( $line =~ /LaTeX Warning: There were undefined references./i ) { $self->debug('undefined reference detected'); $self->undefined_references(1) unless $self->undefined_citations; } elsif ( $line =~ /No file $basename\.(toc|lof|lot)/i ) { $self->debug("missing $1 file"); $self->undefined_references(1); } elsif ( $line =~ /^LaTeX Warning: Label\(s\) may have changed./i ) { $self->debug('labels have changed'); $self->labels_changed(1); } elsif ( $line =~ /^Package longtable Warning: Table widths have changed[.] Rerun LaTeX[.]/i) { $self->debug('table widths changed'); $self->rerun_required(1); } # A number of packages emit 'rerun' warnings (revtex4, # pdfmark, etc); this regexp catches most of those. elsif ( $line =~ /Rerun to get (.*) right/i) { $self->debug("$1 changed"); $self->rerun_required(1); } } } else { $errors = "failed to open $logfile for input"; } if ($exitcode or $errors) { $self->throw($self->formatter . " exited with errors:\n$errors"); } $self->stats->{runs}{formatter}++; return; } sub reset_latex_required { my $self = shift; $self->rerun_required(0); $self->undefined_references(0); $self->labels_changed(0); return; } sub need_to_run_latex { my $self = shift; my $auxfile = $self->basepath . '.aux'; return 1 if $self->undefined_references || $self->labels_changed || $self->rerun_required || ! -f $auxfile; return; } #------------------------------------------------------------------------ # run_bibtex() # # Run bibtex to generate the bibliography # bibtex reads references from the .aux file and writes a .bbl file # It looks for .bib file in BIBINPUTS and TEXBIB # It looks for .bst file in BSTINPUTS #------------------------------------------------------------------------ sub run_bibtex { my $self = shift; my $basename = $self->basename; my $exitcode = $self->run_command(bibtex => $basename, 'BIBINPUTS'); # TODO: extract meaningful error message from .blg file $self->throw("bibtex $basename failed ($exitcode)") if $exitcode; # Make a backup of the citations file for future comparison, reset # the undefined citations flag and mark the driver as needing to # re-run the formatter. my $basepath = $self->basepath; copy("$basepath.cit", "$basepath.cbk"); $self->undefined_citations(0); $self->rerun_required(1); return; } #------------------------------------------------------------------------ # $self->need_to_run_bibtex # # LaTeX reports 'Citation ... undefined' if it sees a citation # (\cite{xxx}, etc) and hasn't read a \bibcite{xxx}{yyy} from the aux # file. Those commands are written by parsing the bbl file, but will # not be seen on the run after bibtex is run as the citations tend to # come before the \bibliography. # # The latex driver sets undefined_citations if it sees the message, # but we need to look at the .aux file and check whether the \citation # lines match those seen before the last time bibtex was run. We # store the citation commands in a .cit file, this is copied to a cbk # file by the bibtex method once bibtex has been run. Doing this # check saves an extra run of bibtex and latex. #------------------------------------------------------------------------ sub need_to_run_bibtex { my $self = shift; if ($self->undefined_citations) { my $auxfile = $self->basepath . '.aux'; my $citfile = $self->basepath . '.cit'; my $cbkfile = $self->basepath . '.cbk'; my $auxfh = IO::File->new($auxfile, 'r') or return; my $citfh = IO::File->new($citfile, 'w') or $self->throw("failed to open $citfile for output: $!"); while ( my $line = <$auxfh> ) { print($citfh $line) if $line =~ /^\\citation/; } undef $auxfh; undef $citfh; return if -e $cbkfile and (compare($citfile, $cbkfile) == 0); return 1; } return; } #------------------------------------------------------------------------ # $self->run_makeindex() # # Run makeindex to generate the index # # makeindex has a '-s style' option which specifies the style file. # The environment variable INDEXSTYLE defines the path where the style # file should be found. # TODO: sanity check the indexoptions? don't want the caller # specifying the output index file name as that might screw things up. #------------------------------------------------------------------------ sub run_makeindex { my $self = shift; my $basename = $self->basename; my @args; if (my $stylename = $self->options->{indexstyle}) { push @args, '-s', $stylename; } if (my $index_options = $self->options->{indexoptions}) { push @args, $index_options; } my $exitcode = $self->run_command(makeindex => [@args, $basename]); # TODO: extract meaningful error message from .ilg file $self->throw("makeindex $basename failed ($exitcode)") if $exitcode; # Make a backup of the raw index file that was just processed, so # that we can determine whether makeindex needs to be rerun later. my $basepath = $self->basepath; copy("$basepath.idx", "$basepath.ibk"); $self->rerun_required(1); return; } #------------------------------------------------------------------------ # $self->need_to_run_makeindex() # # Determine whether makeindex needs to be run. Checks that there is a # raw index file and that it differs from the backup file (if that exists). #------------------------------------------------------------------------ sub need_to_run_makeindex { my $self = shift; my $basepath = $self->basepath; my $raw_index_file = "$basepath.idx"; my $backup_file = "$basepath.ibk"; return unless -e $raw_index_file; return if -e $backup_file and (compare($raw_index_file, $backup_file) == 0); return 1; } #------------------------------------------------------------------------ # $self->run_dvips() # # Run dvips to generate PostScript output #------------------------------------------------------------------------ sub run_dvips { my $self = shift; my $basename = $self->basename; my $exitstatus = $self->run_command(dvips => [$basename, '-o']); $self->throw("dvips $basename failed ($exitstatus)") if $exitstatus; return; } #------------------------------------------------------------------------ # $self->run_ps2pdf() # # Run ps2pdf to generate PDF from PostScript output #------------------------------------------------------------------------ sub run_ps2pdf { my $self = shift; my $basename = $self->basename; my $exitstatus = $self->run_command(ps2pdf => ["$basename.ps", "$basename.pdf"]); $self->throw("ps2pdf $basename failed ($exitstatus)") if $exitstatus; return; } #------------------------------------------------------------------------ # $self->run_pdf2ps() # # Run ps2pdf to generate PostScript from PDF output #------------------------------------------------------------------------ sub run_pdf2ps { my $self = shift; my $basename = $self->basename; my $exitstatus = $self->run_command(pdf2ps => ["$basename.pdf", "$basename.ps"]); $self->throw("pdf2ps $basename failed ($exitstatus)") if $exitstatus; return; } #------------------------------------------------------------------------ # $self->run_command($progname, $config, $dir, $args, $env) # # Run a command in the specified directory, setting up the environment # and allowing for the differences between operating systems. #------------------------------------------------------------------------ sub run_command { my ($self, $progname, $args, $envvars) = @_; $args = [ $args ] unless ref $args; # get the full path to the executable for this output format my $program = $self->program_path($progname) || $self->throw("$progname cannot be found, please specify its location"); my $dir = $self->basedir; my $null = File::Spec->devnull(); my $cmd; $args ||= ''; # Set up localized environment variables in preparation for running the command # Note that the localized hash slice assignment of %ENV ensures that # the localization is done at the same block level as the system(). # Even doing something like local($ENV{$_}) = $val for @{$envvars} # puts the localization in a deeper level block so the previous value # is restored before the system() call is made. $envvars ||= "TEXINPUTS"; $envvars = [ $envvars ] unless ref $envvars; local(@ENV{@{$envvars}}) = map { $self->texinputs_path } @{$envvars}; $self->stats->{runs}{$progname}++; $self->debug("running '$program $args'"); my $cwd = pushd($dir); # Format the command appropriately for our O/S my $exit_status; my $exit_error; my ($stdout, $stderr); if ($OSNAME eq 'MSWin32') { $args = join(' ', @$args); $cmd = "\"$program\" $args"; ($stdout, $stderr) = capture { $exit_status = system($cmd); $exit_error = "$!"; }; } else { $args = "'$args'" if $args =~ / \\ /mx; ($stdout, $stderr) = capture { $exit_status = system($program, @$args); $exit_error = "$!"; }; } if ($exit_status == -1) { $self->throw( "Failure to start $program: $exit_error" ); } $self->{stderr} .= $stderr if $self->{capture_stderr}; return $exit_status; } #------------------------------------------------------------------------ # $self->copy_to_output # #------------------------------------------------------------------------ sub copy_to_output { my $self = shift; my $output = $self->output or return; # construct file name of the generated document my $file = $self->basepath . '.' . $self->format; if (ref $output) { $$output = read_file($file); } else { # see if we can rename the generated file to the desired output # file - this may fail, e.g. across filesystem boundaries (and # it's quite common for /tmp to be a separate filesystem if (rename($file, $output)) { $self->debug("renamed $file to $output"); } elsif (copy($file, $output)) { $self->debug("copied $file to $output"); } else { $self->throw("failed to copy $file to $output"); } } return; } #------------------------------------------------------------------------ # _setup_tmpdir($dirname) # # create a temporary directory #------------------------------------------------------------------------ sub _setup_tmpdir { my ($class, $dirname) = @_; my $tmp; $tmp = File::Spec->catdir(File::Spec->tmpdir(), $dirname . 'XXXXXXX') if ($dirname and ($dirname ne 1)); __PACKAGE__->debug("setting up temporary directory '%s'\n", $dirname || ''); return File::Temp->newdir(TEMPLATE => $tmp); } #------------------------------------------------------------------------ # Destructor (clean up log/temp files) # #------------------------------------------------------------------------ sub DESTROY { local($., $@, $!, $^E, $?); my $self = shift; # Don't log in DESTROY: it has weird interactions with # global destruction; also: don't use other objects here. my $what = $self->{cleanup}; return if (not $what or $what eq 'none' or not -d $self->basedir); unlink $self->basepath . ".$_" for (@LOGFILE_EXTS); return if ($what eq 'logfiles'); unlink $self->basepath . ".$_" for (@TMPFILE_EXTS); return; } #------------------------------------------------------------------------ # $self->program_path($progname, $optional_value) # # #------------------------------------------------------------------------ sub program_path { my $class_or_self = shift; my $href = ref $class_or_self ? $class_or_self->{_program_path} : \%program_path; my $progname = shift; return @_ ? ($href->{$progname} = shift) : $href->{$progname}; } #------------------------------------------------------------------------ # throw($error) # # Throw an error message #------------------------------------------------------------------------ sub throw { my ($self, @args) = @_; LaTeX::Driver::Exception->throw( error => join('', @args) ); return; # not needed - but satisfies perlcritic } sub debug { my ($self, $string, @args) = @_; my $prefix = ref $self ? $self->{DEBUGPREFIX} : $DEBUGPREFIX; $prefix ||= '[latex] '; $log->debugf($prefix . $string, @args) or do { if (ref $self ? $self->{DEBUG} : $DEBUG) { print STDERR $prefix, @args; print STDERR "\n" unless @args and ($args[-1] =~ / \n $ /mx); } }; return; } 1; __END__ =head1 NAME LaTeX::Driver - Latex driver =head1 VERSION 1.3.1 =head1 SYNOPSIS use LaTeX::Driver; $drv = LaTeX::Driver->new( source => \$doc_text, output => $filename, format => 'pdf', %other_params ); $ok = $drv->run; $stats = $drv->stats; =head1 DESCRIPTION The LaTeX::Driver module encapsulates the details of invoking the Latex programs to format a LaTeX document. Formatting with LaTeX is complicated; there are potentially many programs to run and the output of those programs must be monitored to determine whether further processing is required. This module runs the required commands in the directory specified, either explicitly with the C option or implicitly by the directory part of C, or in the current directory. As a result of the processing up to a dozen or more intermediate files are created. These will be removed upon object destruction, given the C argument to C. =head1 SOURCE Source code can be found at L Feel free to fork and add your stuff! =head1 SUBROUTINES/METHODS =over 4 =item C This is the constructor method. It creates a driver object on which the C method is used to format the document specified. The main arguments are C and C; the C argument is required to specify the input document; C is only mandatory if C is a scalar reference. The full list of arguments is as follows: =over 4 =item C This parameter is mandatory; it can either specify the name of the document to be formatted or be a reference to a scalar containing the document source. =item C specifies the output for the formatted document; this may either be a file name or be a scalar reference. In the latter case the contents of the formatted document file is copied into the scalar variable referenced. =item C the format of output required: one of C<"dvi"> (TeX Device Independent format), C<"ps"> (PostScript) or C<"pdf"> (Adobe Portable Document Format). The follow special values are also accepted: C<"pdf(ps)"> (generates PDF via PostScript, using C and C), C<"pdf(dvi)"> (generates PDF via dvi, using C). If not specified then the format is determined from the name of the output document if specified, or defaults to PDF. The following list of formats is supported =over =item * dvi =item * ps =item * postscript =item * pdf =item * pdf(pdflatex) =item * pdf(xelatex) =item * pdf(lualatex) =item * pdf(dvi) =item * pdf(ps) =item * ps(pdf) =item * ps(pdflatex) =item * ps(xelatex) =item * ps(lualatex) =back =item C Specifies whether the formatting should be done in a temporary directory in which case the source document is copied into the directory before formatting. This option can either take the value 1, in which case a temporary directory is automatically generated, or it is taken as the name of a subdirectory of the system temporary directory. A temporary directory is always created if the source document is specified as a scalar reference. =item C Specifies a mapping of program names to full pathname as a hash reference. These paths override the paths determined at installation time. =item C The maximum number of runs of the formatter program (defaults to 10). =item C The number of additional runs of the formatter program after the document has stabilized. =item C Specifies a timeout in seconds within which any commands spawned should finish. =item C Specifies whether temporary files and directories should be automatically removed when the object destructor is called. Accepted values are C (do no cleanup), C (remove log files) and C (remove log and temporary files). By default the destructor will remove the entire contents of any automatically generated temporary directory, but will leave all other files intact. =item C The name of a C index style file that should be passed to C. =item C Specifies additional options that should be passed to C. Useful options are: C<-c> to compress intermediate blanks in index keys, C<-l> to specify letter ordering rather than word ordering, C<-r> to disable implicit range formation. Refer to L for full details. =item C Specifies one or more directories to be searched for LaTeX files. =item C Enables debug statements if set to a non-zero value. =item C Sets the debug prefix, which is prepended to debug output if debug statements. By default there is no prefix. =back The constructor performs sanity checking on the options and will die if the following conditions are detected: =over 4 =item * no source is specified =item * an invalid format is specified =back The constructor method returns a driver object. =item C Format the document. =item C Holds the error output from subcommands, if the C<-capture_stderr> option was passed to C. =item C Returns a reference to a hash containing stats about the processing that was performed, containing the following items: =over 4 =item C number of pages in the formatted document =item C number of bytes in the formatted document =item C hash of the number of times each of the programs was run =back Note: the return value will probably become an object in a future version of the module. =item C Get or set the path to the named program. Can be used as a class method to set the default path or as an object method to set the path for that instance of the driver object. =back There are a number of other methods that are used internally by the driver. Calling these methods directly may lead to unpredictable results. =over 4 =item C Runs the formatter (C or C). =item C Determines whether the formatter needs to be run. =item C Reset the flags that indicate whether latex needs to be re-run (invoked prior to each iteration of running any necessary commands). =item C Runs bibtex to generate the bibliography. =item C Determines whether bibtex needs to be run. =item C Runs makeindex to generate the index. =item C Determines whether makeindex needs to be run. =item C Runs dvips to generate postscript output from an intermediate C<.dvi> file. =item C Runs ps2pdf to generate PDF output from an intermediate PostScript file. =item C Runs pdf2ps to generate PostScript output from an intermediate PDF file. =item C Run a command in a controlled environment, allowing for operating system differences. =item C Copy the output to its final destination. =item C Throw an exception. =item C Print a debug message - the caller should test C<$DEBUG> to determine whether to invoke this function. =back =head1 DIAGNOSTICS The following errors may be detected by the constructor method. =over 4 =item not available on XXX The module is not supported on MacOS, OS/2 or VMS (or on a host of other operating systems but these are the only ones that are explicitly tested for). =item no source specified The C parameter should be specified as the name of a LaTeX source file or it should be a reference to a scalar variable holding the LaTeX source document. =item source is an invalid reference C is a reference, but not a reference to a scalar variable =item source file XXX.tex does not exist The source file specified does not exist =item output directory DIR does not exist An C parameter was specified as a scalar value, which was taken as the name of the output file, but the directory part of the path does not exist. =item invalid output format XXX An output format was specified, either explicitly or implicitly as the extension of the output file, but the output format specified is not supported. =item cannot create temporary directory The module could not create the temporary directory, which is used if the source is not specified as a filename, and the output is not to be left in the same directory as the source, or if a temporary directory name is specified explicitly. =item cannot create temporary latex file The module has determined that it needs to create a temporary file containing the source document but it cannot. =item cannot copy XXX.ext to temporary directory The module was trying to copy the specified source file to the temporary directory but couldn't. Perhaps you specified the temporary directory name explicitly but the directory does not exist or is not writeable. =back The following errors may be detected when the driver's C method is called: =over 4 =item file XXX.tex does not exist The source file does not exist; it may have been removed between the time the constructor was called and the time that the driver was run. =item PROGRAM exited with errors: ERRORS The named program (C or C) exited with the errors listed. You may have errors in your source file. =item bibtex FILE failed (EXITCODE) The C program exited with errors. These are not fully parsed yet. =item failed to open BASEPATH.cit The driver generates its own temporary file listing the citations for a document, so that it can determine whether the citations have changed. This error indicates that it was unable to create the file. =item makeindex FILE failed (EXITCODE) The C program exited with errors. These are not fully parsed yet. =item dvips FILE failed (EXITCODE) The C program exited with errors. These are not fully parsed yet. =item ps2pdf FILE failed (EXITCODE) The C program exited with errors. These are not fully parsed yet. =item PROGNAME cannot be found, please specify its location The pathname for the specified program was not found in the modules configuration. The program may not have been found and the pathname not been explicitly specified when the module was installed. =item failed to copy FILE to OUTPUT The driver failed to copy the formatted file to the specified output location. =back =head1 CONFIGURATION AND ENVIRONMENT When the using application configures L, this module will use it to log C and C level messages to the C category. Please note that the C<$DEBUG> variable does not need to be set to enable this type of logging. When this type of logging is enabled, the value of C<$DEBUG> is ignored. =head1 DEPENDENCIES C depends on latex and friends being installed. =head1 INCOMPATIBILITIES None known. =head1 BUGS AND LIMITATIONS If you have any comments about this software I would be very grateful to hear them; please file your comments as issues at L. Among the things I am aware of are: =over 4 =item * I haven't worked out how I am going to deal with tex-related environment variables. =back =head1 FUTURE DIRECTIONS =over 4 =item * Look at how path variables could be specified to the filter (C, C, C, C, etc), and how these should interact with the system paths. =item * Investigate pre- and post-processors and other auxiliary programs. =back =head1 BACKGROUND This module has its origins in the original C filter that was part of Template Toolkit prior to version 2.16. That code was fairly simplistic; it created a temporary directory, copied the source text to a file in that directory, and ran either C or C on the file once; if postscript output was requested then it would run C after running C. This did not cope with documents that contained forward references, a table of contents, lists of figures or tables, bibliographies, or indexes. The current module does not create a temporary directory for formatting the document; it is given the name and location of an existing LaTeX document and runs the latex programs in the directory specified (the Template Toolkit plugin will be modified to set up a temporary directory, copy the source text in, then run this module, extract the output and remove the temporary directory). =head1 INTERNALS This section is aimed at a technical audience. It documents the internal methods and subroutines as a reference for the module's developers, maintainers and anyone interesting in understanding how it works. You don't need to know anything about them to use the module and can safely skip this section. =head2 Formatting with LaTeX or PDFLaTeX LaTeX documents can be formatted with C or C; the former generates a C<.dvi> file (device independent - TeX's native output format), which can be converted to PostScript or PDF; the latter program generates PDF directly. finds inputs in C, C, C, etc =head2 Generating indexes The standard program for generating indexes is C, is a general purpose hierarchical index generator. C accepts one or more input files (C<.idx>), sorts the entries, and produces an output (C<.ind>) file which can be formatted. The style of the generated index is specified by a style file (C<.ist>), which is found in the path specified by the C environment variable. An alternative to C is C, but that program is not widespread yet. =head2 Generating bibliographies with BiBTeX BiBTeX generates a bibliography for a LaTeX document. It reads the top-level auxiliary file (C<.aux>) output during the running of latex and creates a bibliography file (C<.bbl>) that will be incorporated into the document on subsequent runs of latex. It looks up the entries specified by \cite and \nocite commands in the bibliographic database files (.bib) specified by the \bibliography commands. The entries are formatted according to instructions in a bibliography style file (C<.bst>), specified by the \bibliographystyle command. Bibliography style files are searched for in the path specified by the C environment variable; for bibliography files it uses the C environment variable. System defaults are used if these environment variables are not set. =head2 Running Dvips The C program takes a DVI file produced by TeX and converts it to PostScript. =head2 Running ps2pdf The C program invokes Ghostscript to converts a PostScript file to PDF. =head2 Running on Windows Commands are executed with C. The syntax is: cmd /c "cd $dir && $program $args" This changes to the specified directory and executes the program there, without affecting the working directory of the the Perl process. Need more information on how to set environment variables for the invoked programs. =head2 Miscellaneous Information This is a placeholder for information not yet incorporated into the rest of the document. May want to mention the kpathsea library, the C program, the web2c TeX distribution, TeX live, tetex, TeX on Windows, etc. =head1 AUTHOR Erik Huelsmann (current maintainer) =head1 LICENSE AND COPYRIGHT Copyright (C) 2020 Erik Huelsmann. Copyright (C) 2014 Chris Travers. Copyright (C) 2009-2013 Ford & Mason Ltd. Copyright (C) 2006-2007 Andrew Ford. Portions Copyright (C) 1996-2006 Andy Wardley. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L, L, L, L, The dvips manual There are a number of books and other documents that cover LaTeX: =over 4 =item * The LaTeX Companion =item * Web2c manual =back =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: Driver.pm~100644001750001750 12072515127547545 16652 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/lib/LaTeX# LaTeX::Driver # # DESCRIPTION # Driver module that encapsulates the details of formatting a LaTeX document # package LaTeX::Driver; use strict; use warnings; use 5.008005; use parent 'Class::Accessor'; use Cwd; # from PathTools use English qw( -no_match_vars ); # standard Perl class use Exception::Class ( 'LaTeX::Driver::Exception' ); use File::Copy; # standard Perl class use File::Compare; # standard Perl class use File::Path; # standard Perl class use File::Slurp; use File::Spec; # from PathTools use File::Temp; use IO::File; # from IO use Readonly; use File::pushd; # temporary cwd changes use Capture::Tiny qw(capture); use Log::Any qw($log); Readonly our $DEFAULT_MAXRUNS => 10; our $VERSION = "1.2.0"; __PACKAGE__->mk_accessors( qw( basename basedir basepath options source output tmpdir format timeout stderr formatter preprocessors postprocessors _program_path maxruns extraruns stats texinputs_path undefined_citations undefined_references labels_changed rerun_required ) ); our $DEBUG; our $DEBUGPREFIX; # LaTeX executable paths set at installation time by the Makefile.PL our @PROCESSORS = qw(xelatex lualatex pdflatex latex); our @AUXILLARY_PROGS = qw(bibtex makeindex); our @POSTPROCESSORS = qw(dvips dvipdfm ps2pdf pdf2ps); our @PROGRAM_NAMES = (@PROCESSORS, @AUXILLARY_PROGS, @POSTPROCESSORS); our %program_path = map { ( $_ => $_ ) } @PROGRAM_NAMES; our @LOGFILE_EXTS = qw( log blg ilg ); our @TMPFILE_EXTS = qw( aux log lot toc bbl ind idx cit cbk ibk ); our $DEFAULT_TMPDIR = 'latexdrv'; our $DEFAULT_DOCNAME = 'latexdoc'; # valid output formats and program alias our $DEFAULT_FORMAT = 'pdf'; our %FORMATTERS = ( dvi => [ 'latex' ], ps => [ 'latex', 'dvips' ], postscript => [ 'latex', 'dvips' ], pdf => [ 'xelatex' ], 'pdf(pdflatex)' => [ 'pdflatex' ], 'pdf(xelatex)' => [ 'xelatex' ], 'pdf(lualatex)' => [ 'lualatex' ], 'pdf(dvi)' => [ 'latex', 'dvipdfm' ], 'pdf(ps)' => [ 'latex', 'dvips', 'ps2pdf' ], 'ps(pdf)' => [ 'pdflatex', 'pdf2ps' ], 'ps(pdflatex)' => [ 'pdflatex', 'pdf2ps' ], 'ps(xelatex)' => [ 'xelatex', 'pdf2ps' ], 'ps(lualatex)' => [ 'lualatex', 'pdf2ps' ], ); #------------------------------------------------------------------------ # new(%options) # # Constructor for the Latex driver #------------------------------------------------------------------------ sub new { my $class = shift; my $options = ref $_[0] ? shift : { @_ }; my ($volume, $basedir, $basename, $basepath, $orig_ext, $cleanup); my ($formatter, @postprocessors); # Sanity check first - check we're running on a supported OS $class->throw("not available on $OSNAME") if $OSNAME =~ m/ ^ ( MacOS | os2 | VMS ) $ /ix; # Examine the options - we need at least a source to work with and # it should be a scalar reference or a valid filename. my $source = delete $options->{source}; $class->throw("no source specified") unless $source; if (ref $source) { $class->throw("source is an invalid reference $source") if ref $source ne 'SCALAR'; } else { $source =~ s/ ( [.] tex ) $ //x; $orig_ext = $1; $class->throw("source file ${source}.tex does not exist") unless -f $source or -f "${source}.tex"; } # Determine how the document is to be processed. Either specified # explicitly in the format parameter or if an output file is # specified it is taken from that, or the default is take. my $output = $options->{output}; my $format; $format = lc($options->{format}) if $options->{format}; if ($output and (!ref $output)) { my ($volume, $dir, $file) = File::Spec->splitpath($output); $class->throw("output directory $dir does not exist") unless $dir and -d $dir; if ((!$format) and ($file =~ / [.] ( \w+ ) $ /x)) { $format = lc($1); } } # There is a formatter and zero or more postprocessors for each # format; there are also special formats 'pdf(dvi)', 'pdf(ps)' and # 'ps(pdf)' that specify alternate routes to generate the format. $format ||= $DEFAULT_FORMAT; $class->throw("invalid output format: '$format'") unless exists $FORMATTERS{$format}; ($formatter, @postprocessors) = @{$FORMATTERS{$format}}; # discard the parenthesized part of special formats $format =~ s/\(.*\)//; # If a temporary directory was specified or the LaTeX source was # given as a scalar reference then a temporary directory is # created and the document source written to that directory or # copied in if the source is a file. my $tmpdir = $options->{tmpdir}; if ($tmpdir or ref $source) { $basedir = $class->_setup_tmpdir($tmpdir); if (ref $source) { $basename = $DEFAULT_DOCNAME; $basepath = File::Spec->catfile($basedir, $basename); write_file($basepath . ".tex", $source) or $class->throw("cannot create temporary latex file"); } else { ($basename = $source) =~ s{.*/}{}; $basepath = File::Spec->catfile($basedir, $basename); copy("$source$orig_ext", "${basepath}.tex") or $class->throw("cannot copy $source$orig_ext to temporary directory"); $output ||= "${source}.$format"; } } # Otherwise the source was given as a filename, so the base name # and directory are taken from the source name. else { ($volume, $basedir, $basename) = File::Spec->splitpath($source); $basename =~ s/\.tex$//; if ($basedir and $volume) { $basedir = File::Spec->catfile($volume, $basedir); } $basedir ||= getcwd; $basedir =~ s{(.)/$}{$1}; $basepath = File::Spec->catfile($basedir, $basename); } # Set up a mapping of program name to full pathname. # This is initialized from the paths detemined at installation # time, but any specified in the paths option override these # values. $options->{paths} ||= {}; my $path = {}; map { $path->{$_} = $program_path{$_}; } @PROGRAM_NAMES; map { $path->{$_} = $options->{paths}->{$_}; } keys %{ $options->{paths} }; # Set up the texinputs path my $texinputs_path = $options->{TEXINPUTS} || $options->{texinputs} || []; $texinputs_path = [ split(/:/, $texinputs_path) ] unless ref $texinputs_path; # see http://tex.stackexchange.com/questions/149714/149865#149865 my $texinputs_sep = $OSNAME eq "MSWin32" ? ';' : ':'; # construct and return the object return $class->SUPER::new( { basename => $basename, basedir => "$basedir", _file_tmp_base => $basedir, # retain ref during object life basepath => $basepath, format => $format, output => $output, cleanup => $cleanup || '', options => $options, maxruns => $options->{maxruns} || $DEFAULT_MAXRUNS, extraruns => $options->{extraruns} || 0, timeout => $options->{timeout}, capture_stderr => $options->{capture_stderr} || 0, formatter => $formatter, _program_path => $path, texinputs_path => join($texinputs_sep, ('.', @{$texinputs_path}, '')), preprocessors => [], postprocessors => \@postprocessors, stats => { runs => {} } }); } #------------------------------------------------------------------------ # run() # # Runs the formatter and other programs to generate the ouptut. #------------------------------------------------------------------------ sub run { my $self = shift; # Check that the file exists $self->throw(sprintf('file %s.tex does not exist', $self->basepath)) unless -f $self->basepath . '.tex'; # Run any preprocessors (none specified yet). map { $self->$_ } @{$self->preprocessors}; # Run LaTeX and friends until an error occurs, the document # stabilizes, or the maximum number of runs is reached. my $maxruns = $self->maxruns; my $extraruns = $self->extraruns; RUN: foreach my $run (1 .. $maxruns) { if ($self->need_to_run_latex or $extraruns-- > 0) { $self->run_latex; } elsif ($self->need_to_run_bibtex) { $self->run_bibtex; } elsif ($self->need_to_run_makeindex) { $self->run_makeindex; } } # Run any postprocessors (e.g.: dvips, ps2pdf, etc). foreach my $postproc (@{$self->postprocessors}) { my $method = $postproc; if ($self->can($method)) { $self->$method(); } else { $method = 'run_' . $postproc; if ($self->can($method)) { $self->$method(); } else { $self->throw("cannot find postprocessor $postproc"); } } } # Return any output $self->copy_to_output if $self->output; return 1; } #------------------------------------------------------------------------ # run_latex() # # Run the latex processor (latex or pdflatex depending on what is configured). #------------------------------------------------------------------------ sub run_latex { my $self = shift; my $basename = $self->basename; my $exitcode = $self->run_command($self->formatter => "\\nonstopmode\\def\\TTLATEX{1}\\input{./$basename}"); # If an error occurred attempt to extract the interesting lines # from the log file. Even without errors the log file may contain # interesting warnings indicating that LaTeX or one of its friends # must be rerun. my $errors = ""; my $logfile = $self->basepath . ".log"; if (my $fh = IO::File->new($logfile, "r")) { $self->reset_latex_required; my $matched = 0; while ( my $line = <$fh> ) { $log->trace($line); # TeX errors start with a "!" at the start of the # line, and followed several lines later by a line # designator of the form "l.nnn" where nnn is the line # number. We make sure we pick up every /^!/ line, # and the first /^l.\d/ line after each /^!/ line. if ( $line =~ /^(!.*)/ ) { $errors .= $1 . "\n"; $matched = 1; } elsif ( $matched && ($line =~ /^(l\.\d.*)/) ) { $errors .= $1 . "\n"; $matched = 0; } elsif ( $line =~ /^Output written on (.*) \((\d+) pages, (\d+) bytes\)./ ) { my ($ofile, $pages, $bytes) = ($1, $2, $3); $self->{stats}{pages} = $pages; $self->{stats}{bytes} = $bytes; } elsif ( $line =~ /^LaTeX Warning: Reference .*? on page \d+ undefined/ ) { $self->undefined_references(1); } elsif ( $line =~ /^LaTeX Warning: Citation .* on page \d+ undefined/ ) { $self->debug('undefined citations detected'); $self->undefined_citations(1); } elsif ( $line =~ /LaTeX Warning: There were undefined references./i ) { $self->debug('undefined reference detected'); $self->undefined_references(1) unless $self->undefined_citations; } elsif ( $line =~ /No file $basename\.(toc|lof|lot)/i ) { $self->debug("missing $1 file"); $self->undefined_references(1); } elsif ( $line =~ /^LaTeX Warning: Label\(s\) may have changed./i ) { $self->debug('labels have changed'); $self->labels_changed(1); } elsif ( $line =~ /^Package longtable Warning: Table widths have changed[.] Rerun LaTeX[.]/i) { $self->debug('table widths changed'); $self->rerun_required(1); } # A number of packages emit 'rerun' warnings (revtex4, # pdfmark, etc); this regexp catches most of those. elsif ( $line =~ /Rerun to get (.*) right/i) { $self->debug("$1 changed"); $self->rerun_required(1); } } } else { $errors = "failed to open $logfile for input"; } if ($exitcode or $errors) { $self->throw($self->formatter . " exited with errors:\n$errors"); } $self->stats->{runs}{formatter}++; return; } sub reset_latex_required { my $self = shift; $self->rerun_required(0); $self->undefined_references(0); $self->labels_changed(0); return; } sub need_to_run_latex { my $self = shift; my $auxfile = $self->basepath . '.aux'; return 1 if $self->undefined_references || $self->labels_changed || $self->rerun_required || ! -f $auxfile; return; } #------------------------------------------------------------------------ # run_bibtex() # # Run bibtex to generate the bibliography # bibtex reads references from the .aux file and writes a .bbl file # It looks for .bib file in BIBINPUTS and TEXBIB # It looks for .bst file in BSTINPUTS #------------------------------------------------------------------------ sub run_bibtex { my $self = shift; my $basename = $self->basename; my $exitcode = $self->run_command(bibtex => $basename, 'BIBINPUTS'); # TODO: extract meaningful error message from .blg file $self->throw("bibtex $basename failed ($exitcode)") if $exitcode; # Make a backup of the citations file for future comparison, reset # the undefined citations flag and mark the driver as needing to # re-run the formatter. my $basepath = $self->basepath; copy("$basepath.cit", "$basepath.cbk"); $self->undefined_citations(0); $self->rerun_required(1); return; } #------------------------------------------------------------------------ # $self->need_to_run_bibtex # # LaTeX reports 'Citation ... undefined' if it sees a citation # (\cite{xxx}, etc) and hasn't read a \bibcite{xxx}{yyy} from the aux # file. Those commands are written by parsing the bbl file, but will # not be seen on the run after bibtex is run as the citations tend to # come before the \bibliography. # # The latex driver sets undefined_citations if it sees the message, # but we need to look at the .aux file and check whether the \citation # lines match those seen before the last time bibtex was run. We # store the citation commands in a .cit file, this is copied to a cbk # file by the bibtex method once bibtex has been run. Doing this # check saves an extra run of bibtex and latex. #------------------------------------------------------------------------ sub need_to_run_bibtex { my $self = shift; if ($self->undefined_citations) { my $auxfile = $self->basepath . '.aux'; my $citfile = $self->basepath . '.cit'; my $cbkfile = $self->basepath . '.cbk'; my $auxfh = IO::File->new($auxfile, 'r') or return; my $citfh = IO::File->new($citfile, 'w') or $self->throw("failed to open $citfile for output: $!"); while ( my $line = <$auxfh> ) { print($citfh $line) if $line =~ /^\\citation/; } undef $auxfh; undef $citfh; return if -e $cbkfile and (compare($citfile, $cbkfile) == 0); return 1; } return; } #------------------------------------------------------------------------ # $self->run_makeindex() # # Run makeindex to generate the index # # makeindex has a '-s style' option which specifies the style file. # The environment variable INDEXSTYLE defines the path where the style # file should be found. # TODO: sanity check the indexoptions? don't want the caller # specifying the output index file name as that might screw things up. #------------------------------------------------------------------------ sub run_makeindex { my $self = shift; my $basename = $self->basename; my @args; if (my $stylename = $self->options->{indexstyle}) { push @args, '-s', $stylename; } if (my $index_options = $self->options->{indexoptions}) { push @args, $index_options; } my $exitcode = $self->run_command(makeindex => [@args, $basename]); # TODO: extract meaningful error message from .ilg file $self->throw("makeindex $basename failed ($exitcode)") if $exitcode; # Make a backup of the raw index file that was just processed, so # that we can determine whether makeindex needs to be rerun later. my $basepath = $self->basepath; copy("$basepath.idx", "$basepath.ibk"); $self->rerun_required(1); return; } #------------------------------------------------------------------------ # $self->need_to_run_makeindex() # # Determine whether makeindex needs to be run. Checks that there is a # raw index file and that it differs from the backup file (if that exists). #------------------------------------------------------------------------ sub need_to_run_makeindex { my $self = shift; my $basepath = $self->basepath; my $raw_index_file = "$basepath.idx"; my $backup_file = "$basepath.ibk"; return unless -e $raw_index_file; return if -e $backup_file and (compare($raw_index_file, $backup_file) == 0); return 1; } #------------------------------------------------------------------------ # $self->run_dvips() # # Run dvips to generate PostScript output #------------------------------------------------------------------------ sub run_dvips { my $self = shift; my $basename = $self->basename; my $exitstatus = $self->run_command(dvips => [$basename, '-o']); $self->throw("dvips $basename failed ($exitstatus)") if $exitstatus; return; } #------------------------------------------------------------------------ # $self->run_ps2pdf() # # Run ps2pdf to generate PDF from PostScript output #------------------------------------------------------------------------ sub run_ps2pdf { my $self = shift; my $basename = $self->basename; my $exitstatus = $self->run_command(ps2pdf => ["$basename.ps", "$basename.pdf"]); $self->throw("ps2pdf $basename failed ($exitstatus)") if $exitstatus; return; } #------------------------------------------------------------------------ # $self->run_pdf2ps() # # Run ps2pdf to generate PostScript from PDF output #------------------------------------------------------------------------ sub run_pdf2ps { my $self = shift; my $basename = $self->basename; my $exitstatus = $self->run_command(pdf2ps => ["$basename.pdf", "$basename.ps"]); $self->throw("pdf2ps $basename failed ($exitstatus)") if $exitstatus; return; } #------------------------------------------------------------------------ # $self->run_command($progname, $config, $dir, $args, $env) # # Run a command in the specified directory, setting up the environment # and allowing for the differences between operating systems. #------------------------------------------------------------------------ sub run_command { my ($self, $progname, $args, $envvars) = @_; $args = [ $args ] unless ref $args; # get the full path to the executable for this output format my $program = $self->program_path($progname) || $self->throw("$progname cannot be found, please specify its location"); my $dir = $self->basedir; my $null = File::Spec->devnull(); my $cmd; $args ||= ''; # Set up localized environment variables in preparation for running the command # Note that the localized hash slice assignment of %ENV ensures that # the localization is done at the same block level as the system(). # Even doing something like local($ENV{$_}) = $val for @{$envvars} # puts the localization in a deeper level block so the previous value # is restored before the system() call is made. $envvars ||= "TEXINPUTS"; $envvars = [ $envvars ] unless ref $envvars; local(@ENV{@{$envvars}}) = map { $self->texinputs_path } @{$envvars}; $self->stats->{runs}{$progname}++; $self->debug("running '$program $args'"); my $cwd = pushd($dir); # Format the command appropriately for our O/S my $exit_status; my $exit_error; my ($stdout, $stderr); if ($OSNAME eq 'MSWin32') { $args = join(' ', @$args); $cmd = "\"$program\" $args"; ($stdout, $stderr) = capture { $exit_status = system($cmd); $exit_error = "$!"; }; } else { $args = "'$args'" if $args =~ / \\ /mx; ($stdout, $stderr) = capture { $exit_status = system($program, @$args); $exit_error = "$!"; }; } if ($exit_status == -1) { $self->throw( "Failure to start $program: $exit_error" ); } $self->{stderr} .= $stderr if $self->{capture_stderr}; return $exit_status; } #------------------------------------------------------------------------ # $self->copy_to_output # #------------------------------------------------------------------------ sub copy_to_output { my $self = shift; my $output = $self->output or return; # construct file name of the generated document my $file = $self->basepath . '.' . $self->format; if (ref $output) { $$output = read_file($file); } else { # see if we can rename the generated file to the desired output # file - this may fail, e.g. across filesystem boundaries (and # it's quite common for /tmp to be a separate filesystem if (rename($file, $output)) { $self->debug("renamed $file to $output"); } elsif (copy($file, $output)) { $self->debug("copied $file to $output"); } else { $self->throw("failed to copy $file to $output"); } } return; } #------------------------------------------------------------------------ # _setup_tmpdir($dirname) # # create a temporary directory #------------------------------------------------------------------------ sub _setup_tmpdir { my ($class, $dirname) = @_; my $tmp; $tmp = File::Spec->catdir(File::Spec->tmpdir(), $dirname . 'XXXXXXX') if ($dirname and ($dirname ne 1)); __PACKAGE__->debug("setting up temporary directory '%s'\n", $dirname || ''); return File::Temp->newdir(TEMPLATE => $tmp); } #------------------------------------------------------------------------ # Destructor (clean up log/temp files) # #------------------------------------------------------------------------ sub DESTROY { local($., $@, $!, $^E, $?); my $self = shift; # Don't log in DESTROY: it has weird interactions with # global destruction; also: don't use other objects here. my $what = $self->{cleanup}; return if (not $what or $what eq 'none' or not -d $self->basedir); unlink $self->basepath . ".$_" for (@LOGFILE_EXTS); return if ($what eq 'logfiles'); unlink $self->basepath . ".$_" for (@TMPFILE_EXTS); return; } #------------------------------------------------------------------------ # $self->program_path($progname, $optional_value) # # #------------------------------------------------------------------------ sub program_path { my $class_or_self = shift; my $href = ref $class_or_self ? $class_or_self->{_program_path} : \%program_path; my $progname = shift; return @_ ? ($href->{$progname} = shift) : $href->{$progname}; } #------------------------------------------------------------------------ # throw($error) # # Throw an error message #------------------------------------------------------------------------ sub throw { my ($self, @args) = @_; LaTeX::Driver::Exception->throw( error => join('', @args) ); return; # not needed - but satisfies perlcritic } sub debug { my ($self, $string, @args) = @_; my $prefix = ref $self ? $self->{DEBUGPREFIX} : $DEBUGPREFIX; $prefix ||= '[latex] '; $log->debugf($prefix . $string, @args) or do { if (ref $self ? $self->{DEBUG} : $DEBUG) { print STDERR $prefix, @args; print STDERR "\n" unless @args and ($args[-1] =~ / \n $ /mx); } }; return; } 1; __END__ =head1 NAME LaTeX::Driver - Latex driver =head1 VERSION 1.2.0 =head1 SYNOPSIS use LaTeX::Driver; $drv = LaTeX::Driver->new( source => \$doc_text, output => $filename, format => 'pdf', %other_params ); $ok = $drv->run; $stats = $drv->stats; =head1 DESCRIPTION The LaTeX::Driver module encapsulates the details of invoking the Latex programs to format a LaTeX document. Formatting with LaTeX is complicated; there are potentially many programs to run and the output of those programs must be monitored to determine whether further processing is required. This module runs the required commands in the directory specified, either explicitly with the C option or implicitly by the directory part of C, or in the current directory. As a result of the processing up to a dozen or more intermediate files are created. These will be removed upon object destruction, given the C argument to C. =head1 SOURCE Source code can be found at L Feel free to fork and add your stuff! =head1 SUBROUTINES/METHODS =over 4 =item C This is the constructor method. It creates a driver object on which the C method is used to format the document specified. The main arguments are C and C; the C argument is required to specify the input document; C is only mandatory if C is a scalar reference. The full list of arguments is as follows: =over 4 =item C This parameter is mandatory; it can either specify the name of the document to be formatted or be a reference to a scalar containing the document source. =item C specifies the output for the formatted document; this may either be a file name or be a scalar reference. In the latter case the contents of the formatted document file is copied into the scalar variable referenced. =item C the format of output required: one of C<"dvi"> (TeX Device Independent format), C<"ps"> (PostScript) or C<"pdf"> (Adobe Portable Document Format). The follow special values are also accepted: C<"pdf(ps)"> (generates PDF via PostScript, using C and C), C<"pdf(dvi)"> (generates PDF via dvi, using C). If not specified then the format is determined from the name of the output document if specified, or defaults to PDF. The following list of formats is supported =over =item * dvi =item * ps =item * postscript =item * pdf =item * pdf(pdflatex) =item * pdf(xelatex) =item * pdf(lualatex) =item * pdf(dvi) =item * pdf(ps) =item * ps(pdf) =item * ps(pdflatex) =item * ps(xelatex) =item * ps(lualatex) =back =item C Specifies whether the formatting should be done in a temporary directory in which case the source document is copied into the directory before formatting. This option can either take the value 1, in which case a temporary directory is automatically generated, or it is taken as the name of a subdirectory of the system temporary directory. A temporary directory is always created if the source document is specified as a scalar reference. =item C Specifies a mapping of program names to full pathname as a hash reference. These paths override the paths determined at installation time. =item C The maximum number of runs of the formatter program (defaults to 10). =item C The number of additional runs of the formatter program after the document has stabilized. =item C Specifies a timeout in seconds within which any commands spawned should finish. =item C Specifies whether temporary files and directories should be automatically removed when the object destructor is called. Accepted values are C (do no cleanup), C (remove log files) and C (remove log and temporary files). By default the destructor will remove the entire contents of any automatically generated temporary directory, but will leave all other files intact. =item C The name of a C index style file that should be passed to C. =item C Specifies additional options that should be passed to C. Useful options are: C<-c> to compress intermediate blanks in index keys, C<-l> to specify letter ordering rather than word ordering, C<-r> to disable implicit range formation. Refer to L for full details. =item C Specifies one or more directories to be searched for LaTeX files. =item C Enables debug statements if set to a non-zero value. =item C Sets the debug prefix, which is prepended to debug output if debug statements. By default there is no prefix. =back The constructor performs sanity checking on the options and will die if the following conditions are detected: =over 4 =item * no source is specified =item * an invalid format is specified =back The constructor method returns a driver object. =item C Format the document. =item C Holds the error output from subcommands, if the C<-capture_stderr> option was passed to C. =item C Returns a reference to a hash containing stats about the processing that was performed, containing the following items: =over 4 =item C number of pages in the formatted document =item C number of bytes in the formatted document =item C hash of the number of times each of the programs was run =back Note: the return value will probably become an object in a future version of the module. =item C Get or set the path to the named program. Can be used as a class method to set the default path or as an object method to set the path for that instance of the driver object. =back There are a number of other methods that are used internally by the driver. Calling these methods directly may lead to unpredictable results. =over 4 =item C Runs the formatter (C or C). =item C Determines whether the formatter needs to be run. =item C Reset the flags that indicate whether latex needs to be re-run (invoked prior to each iteration of running any necessary commands). =item C Runs bibtex to generate the bibliography. =item C Determines whether bibtex needs to be run. =item C Runs makeindex to generate the index. =item C Determines whether makeindex needs to be run. =item C Runs dvips to generate postscript output from an intermediate C<.dvi> file. =item C Runs ps2pdf to generate PDF output from an intermediate PostScript file. =item C Runs pdf2ps to generate PostScript output from an intermediate PDF file. =item C Run a command in a controlled environment, allowing for operating system differences. =item C Copy the output to its final destination. =item C Throw an exception. =item C Print a debug message - the caller should test C<$DEBUG> to determine whether to invoke this function. =back =head1 DIAGNOSTICS The following errors may be detected by the constructor method. =over 4 =item not available on XXX The module is not supported on MacOS, OS/2 or VMS (or on a host of other operating systems but these are the only ones that are explicitly tested for). =item no source specified The C parameter should be specified as the name of a LaTeX source file or it should be a reference to a scalar variable holding the LaTeX source document. =item source is an invalid reference C is a reference, but not a reference to a scalar variable =item source file XXX.tex does not exist The source file specified does not exist =item output directory DIR does not exist An C parameter was specified as a scalar value, which was taken as the name of the output file, but the directory part of the path does not exist. =item invalid output format XXX An output format was specified, either explicitly or implicitly as the extension of the output file, but the output format specified is not supported. =item cannot create temporary directory The module could not create the temporary directory, which is used if the source is not specified as a filename, and the output is not to be left in the same directory as the source, or if a temporary directory name is specified explicitly. =item cannot create temporary latex file The module has determined that it needs to create a temporary file containing the source document but it cannot. =item cannot copy XXX.ext to temporary directory The module was trying to copy the specified source file to the temporary directory but couldn't. Perhaps you specified the temporary directory name explicitly but the directory does not exist or is not writeable. =back The following errors may be detected when the driver's C method is called: =over 4 =item file XXX.tex does not exist The source file does not exist; it may have been removed between the time the constructor was called and the time that the driver was run. =item PROGRAM exited with errors: ERRORS The named program (C or C) exited with the errors listed. You may have errors in your source file. =item bibtex FILE failed (EXITCODE) The C program exited with errors. These are not fully parsed yet. =item failed to open BASEPATH.cit The driver generates its own temporary file listing the citations for a document, so that it can determine whether the citations have changed. This error indicates that it was unable to create the file. =item makeindex FILE failed (EXITCODE) The C program exited with errors. These are not fully parsed yet. =item dvips FILE failed (EXITCODE) The C program exited with errors. These are not fully parsed yet. =item ps2pdf FILE failed (EXITCODE) The C program exited with errors. These are not fully parsed yet. =item PROGNAME cannot be found, please specify its location The pathname for the specified program was not found in the modules configuration. The program may not have been found and the pathname not been explicitly specified when the module was installed. =item failed to copy FILE to OUTPUT The driver failed to copy the formatted file to the specified output location. =back =head1 CONFIGURATION AND ENVIRONMENT When the using application configures L, this module will use it to log C and C level messages to the C category. Please note that the C<$DEBUG> variable does not need to be set to enable this type of logging. When this type of logging is enabled, the value of C<$DEBUG> is ignored. =head1 DEPENDENCIES C depends on latex and friends being installed. =head1 INCOMPATIBILITIES None known. =head1 BUGS AND LIMITATIONS If you have any comments about this software I would be very grateful to hear them; please file your comments as issues at L. Among the things I am aware of are: =over 4 =item * I haven't worked out how I am going to deal with tex-related environment variables. =back =head1 FUTURE DIRECTIONS =over 4 =item * Look at how path variables could be specified to the filter (C, C, C, C, etc), and how these should interact with the system paths. =item * Investigate pre- and post-processors and other auxiliary programs. =back =head1 BACKGROUND This module has its origins in the original C filter that was part of Template Toolkit prior to version 2.16. That code was fairly simplistic; it created a temporary directory, copied the source text to a file in that directory, and ran either C or C on the file once; if postscript output was requested then it would run C after running C. This did not cope with documents that contained forward references, a table of contents, lists of figures or tables, bibliographies, or indexes. The current module does not create a temporary directory for formatting the document; it is given the name and location of an existing LaTeX document and runs the latex programs in the directory specified (the Template Toolkit plugin will be modified to set up a temporary directory, copy the source text in, then run this module, extract the output and remove the temporary directory). =head1 INTERNALS This section is aimed at a technical audience. It documents the internal methods and subroutines as a reference for the module's developers, maintainers and anyone interesting in understanding how it works. You don't need to know anything about them to use the module and can safely skip this section. =head2 Formatting with LaTeX or PDFLaTeX LaTeX documents can be formatted with C or C; the former generates a C<.dvi> file (device independent - TeX's native output format), which can be converted to PostScript or PDF; the latter program generates PDF directly. finds inputs in C, C, C, etc =head2 Generating indexes The standard program for generating indexes is C, is a general purpose hierarchical index generator. C accepts one or more input files (C<.idx>), sorts the entries, and produces an output (C<.ind>) file which can be formatted. The style of the generated index is specified by a style file (C<.ist>), which is found in the path specified by the C environment variable. An alternative to C is C, but that program is not widespread yet. =head2 Generating bibliographies with BiBTeX BiBTeX generates a bibliography for a LaTeX document. It reads the top-level auxiliary file (C<.aux>) output during the running of latex and creates a bibliography file (C<.bbl>) that will be incorporated into the document on subsequent runs of latex. It looks up the entries specified by \cite and \nocite commands in the bibliographic database files (.bib) specified by the \bibliography commands. The entries are formatted according to instructions in a bibliography style file (C<.bst>), specified by the \bibliographystyle command. Bibliography style files are searched for in the path specified by the C environment variable; for bibliography files it uses the C environment variable. System defaults are used if these environment variables are not set. =head2 Running Dvips The C program takes a DVI file produced by TeX and converts it to PostScript. =head2 Running ps2pdf The C program invokes Ghostscript to converts a PostScript file to PDF. =head2 Running on Windows Commands are executed with C. The syntax is: cmd /c "cd $dir && $program $args" This changes to the specified directory and executes the program there, without affecting the working directory of the the Perl process. Need more information on how to set environment variables for the invoked programs. =head2 Miscellaneous Information This is a placeholder for information not yet incorporated into the rest of the document. May want to mention the kpathsea library, the C program, the web2c TeX distribution, TeX live, tetex, TeX on Windows, etc. =head1 AUTHOR Erik Huelsmann (current maintainer) =head1 LICENSE AND COPYRIGHT Copyright (C) 2020 Erik Huelsmann. Copyright (C) 2014 Chris Travers. Copyright (C) 2009-2013 Ford & Mason Ltd. Copyright (C) 2006-2007 Andrew Ford. Portions Copyright (C) 1996-2006 Andy Wardley. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L, L, L, L, The dvips manual There are a number of books and other documents that cover LaTeX: =over 4 =item * The LaTeX Companion =item * Web2c manual =back =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: 40-pkg-longtable.t100755001750001750 476015127547545 16502 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 20-complexdoc.t 62 2007-10-03 14:20:44Z andrew $ # TODO: 1. test the output document content # 2. Skip tests when longtable not installed use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More tests => 9; use Test::LaTeX::Driver; use LaTeX::Driver; tidy_directory($basedir, $docname, $debug); my $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', TEXINPUTS => [ "$Bin/testdata/00-common"], @DEBUGOPTS ); diag("Checking the formatting of a LaTeX document that uses 'longtable'"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{pages}, 3, "should have 3 pages of output"); cmp_ok($drv->stats->{runs}{latex}, '>=', 2, "should have run latex at least two times"); cmp_ok($drv->stats->{runs}{latex}, '<=', 4, "should have run latex not more than four times"); ok(!$drv->stats->{runs}{bibtex}, "should not have run bibtex"); ok(!$drv->stats->{runs}{makeindex}, "should not have run makeindex"); if (0) { test_dvifile($drv, [ "Complex Test Document $testno", # title 'A.N. Other', # author '20 September 2007', # date '^Contents$', # table of contents header 'This is a test document with all features.', 'The document has 12 pages.', 'Forward Reference', # section title 'Here is a reference to page 9.', 'File Inclusion', 'Here we include another file.', 'Included File', # section title 'This is text from an included file.', 'Bibliographic Citations', 'We reference the Badger book\\[', '^WCC03$', '\\] and the Camel book\\[', '^Wal03$', 'Index Term', 'Here is the definition of the index term .xyzzy.', '^References$', # bibliography section heading '^\\s*\\[WCC03\\]$', # the bibiographic key 'Andy Wardley, Darren Chamberlain, and Dave Cross.', '^Index$', # Index section heading '\\bxyzzy, 8$', # the index term '\\bxyzzy2, 12$', # index term from the colophon '11$', # page number 11 'Colophon$' ] ); } tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); author-pod-syntax.t100644001750001750 45415127547545 17112 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use strict; use warnings; use Test::More; use Test::Pod 1.41; all_pod_files_ok(); 13-tableofcontents.t100755001750001750 357415127547545 17150 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 13-tableofcontents.t 62 2007-10-03 14:20:44Z andrew $ use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More tests => 8; use Test::LaTeX::Driver; use LaTeX::Driver; tidy_directory($basedir, $docname, $debug); my $drv = LaTeX::Driver->new( source => $docpath, format => 'dvi', @DEBUGOPTS ); diag("Checking the formatting of a LaTeX document with a table of contents"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{runs}{latex}, 2, "should have run latex twice"); is($drv->stats->{runs}{bibtex}, undef, "should not have run bibtex"); is($drv->stats->{runs}{makeindex}, undef, "should not have run makeindex"); test_dvifile($drv, [ "Simple Test Document $testno", # title 'A.N. Other', # author '20 September 2007', # date '^Contents$', # table of contents header '1$', # section 1 - section number 'Introduction', # section 1 - section title '2$', # section 1 - page number '2$', # section 2 - section number 'Section the second', # section 2 - section title '3$', # section 2 - page number '1$', # page number 1 '1$', # section 1 - number 'Introduction', # section 1 - title 'This is a test document with a table of contents.', '2$', # page number 2 '2$', # section 2 - number 'Section the second', # section 2 - title '3$' ] ); # page number 3 tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); author-pod-coverage.t100644001750001750 56715127547545 17364 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests. use strict; use warnings; use Test::Pod::Coverage 1.08; use Pod::Coverage::TrustPod; all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); 30-output-to-variable.t100755001750001750 250715127547545 17513 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 30-output-to-variable.t 62 2007-10-03 14:20:44Z andrew $ use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More; use Test::LaTeX::Driver; use LaTeX::Driver; plan skip_all => 'dvips not installed' if system('dvips -v'); plan tests => 9; tidy_directory($basedir, $docname, $debug); my $output; my $drv = LaTeX::Driver->new( source => $docpath, format => 'ps', output => \$output, @DEBUGOPTS ); diag("Checking the formatting of a simple LaTeX document into a variable"); isa_ok($drv, 'LaTeX::Driver'); #is($drv->basedir, $basedir, "checking basedir"); is($drv->basename, $docname, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $basedir, $docname), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{runs}{latex}, 1, "should have run latex once"); is($drv->stats->{runs}{bibtex}, undef, "should not have run bibtex"); is($drv->stats->{runs}{makeindex}, undef, "should not have run makeindex"); is($drv->stats->{runs}{dvips}, 1, "should have run dvips once"); like($output, qr/^%!PS/, "got postscript in output string"); tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); 31-input-from-variable.t100755001750001750 352615127547545 17636 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t#!/usr/bin/perl # $Id: 31-input-from-variable.t 81 2011-09-18 09:19:03Z andrew $ use strict; use blib; use FindBin qw($Bin); use File::Spec; use lib ("$Bin/../lib", "$Bin/lib"); use Data::Dumper; use Test::More; use Test::LaTeX::Driver; use LaTeX::Driver; use File::Slurp; plan skip_all => 'dvips not installed' if system('dvips -v'); plan tests => 11; tidy_directory($basedir, $docname, $debug); my $source = read_file($docpath) or die "cannot read the source data"; my $output; my $drv = LaTeX::Driver->new( source => \$source, format => 'ps', output => \$output, @DEBUGOPTS ); my $systmpdir = $ENV{TMPDIR} || '/tmp'; diag("Checking the formatting of a simple LaTeX document read from a variable"); isa_ok($drv, 'LaTeX::Driver'); my $tmpbasedir = File::Spec->catdir($systmpdir, $LaTeX::Driver::DEFAULT_TMPDIR); #like($drv->basedir, qr{^$tmpbasedir\w+$}, "checking basedir"); is($drv->basename, $LaTeX::Driver::DEFAULT_DOCNAME, "checking basename"); #is($drv->basepath, File::Spec->catpath('', $drv->basedir, $LaTeX::Driver::DEFAULT_DOCNAME), "checking basepath"); is($drv->formatter, 'latex', "formatter"); ok($drv->run, "formatting $docname"); is($drv->stats->{runs}{latex}, 1, "should have run latex once"); is($drv->stats->{runs}{bibtex}, undef, "should not have run bibtex"); is($drv->stats->{runs}{makeindex}, undef, "should not have run makeindex"); is($drv->stats->{runs}{dvips}, 1, "should have run dvips once"); like($output, qr/^%!PS/, "got postscript in output string"); my $tmpdir = $drv->basedir; ok(-d $tmpdir, "temporary directory exists before undeffing driver"); undef $drv; ok(!-d $tmpdir, "temporary directory deleted after undeffing driver"); tidy_directory($basedir, $docname, $debug) unless $no_cleanup; exit(0); LaTeX000755001750001750 015127547545 15636 5ustar00erikerik000000000000LaTeX-Driver-1.3.1/t/lib/TestDriver.pm100644001750001750 1423115127547545 17610 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t/lib/Test/LaTeX#======================================================================== # # Test::LaTeX::Driver # # DESCRIPTION # Module for testing the LaTeX::Driver module # # AUTHOR # Andrew Ford # # COPYRIGHT # Copyright (C) 2007 Andrew Ford. All Rights Reserved. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # HISTORY # * New file - but portions extracted from the Template::Latex # module (AF, 2007-09-19) # # $Id: Driver.pm 49 2007-09-28 10:50:09Z andrew $ # # TODO # * finish off commenting and documentation # # * integrate with Test::More # #======================================================================== package Test::LaTeX::Driver; use strict; use warnings; use Config; use FindBin qw($Bin); use Getopt::Long; use Test::More; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(get_test_params test_dvifile tidy_directory find_program dvitype $testno $basedir $docname $docpath $debug $debug_prefix @DEBUGOPTS $no_cleanup); our $WIN32 = ($^O eq 'MSWin32'); our $level = 0; our $debug = 0; our $no_cleanup = 0; our $debug_prefix = '# [latex]: '; my $dvitype = find_program($ENV{PATH}, "dvitype"); GetOptions("debug" => \$debug, "level=i" => \$level, "no_cleanup" => \$no_cleanup); $debug = $level if $level; our @DEBUGOPTS = ( DEBUG => $debug, DEBUGPREFIX => $debug_prefix); our ($testno, $basedir, $docname, $docpath) = get_test_params(); sub get_test_params { my $slash = $WIN32 ? "[\\\\/]" : "/"; # both can happen on win32 my $basename = $0; $basename =~ s{ ^ .* $slash }{}x; $basename =~ s/\.t$//; my ($testno) = $basename =~ m/^(\d+)/; die "cannot determine test no from script name $0" unless $testno; my $basedir = "$Bin/testdata/$basename"; my $docpath = "$basedir/${basename}.tex"; return ($testno, $basedir, $basename, $docpath); } sub dvitype { return $dvitype; } #------------------------------------------------------------------------ # find_program($path, $prog) # # Find a program, $prog, by traversing the given directory path, $path. # Returns full path if the program is found. # # Written by Craig Barratt, Richard Tietjen add fixes for Win32. # # abw changed name from studly caps findProgram() to find_program() :-) #------------------------------------------------------------------------ sub find_program { my($path, $prog) = @_; foreach my $dir ( split($Config{path_sep}, $path) ) { my $file = File::Spec->catfile($dir, $prog); if ( !$WIN32 ) { return $file if ( -x $file ); } else { # Windows executables end in .xxx, exe precedes .bat and .cmd foreach my $dx ( qw/exe bat cmd/ ) { return "$file.$dx" if ( -x "$file.$dx" ); } } } } #------------------------------------------------------------------------ # tidy_directory($dir, $docname, $debug) # # Cleans up the temporary files for the document $docname in the # directory $dir. The temporary files are: # # .aux LaTeX auxilliary file # .toc LaTeX table of contents # .lof LaTeX list of figures # .lot LaTeX list of tables # .log LaTeX log file # .idx raw index file # .ibk .idx backup file (generated by LaTeX::Driver) # .ind formatted index # .ilg makeindex log file # .cit citation file (generated by LaTeX::Driver) # .cit backup citation file (generated by LaTeX::Driver) # .bbl # .dvi # .ps # .pdf #------------------------------------------------------------------------ sub tidy_directory { my ($dir, $docname, $debug) = @_; # Suppress undefined value warnings $debug = 0 unless defined($debug); diag("tidying directory '$dir'") if $debug > 1; die "directory $dir does not exist" unless -d $dir; die "filename $docname contains a directory part" if $docname =~ m!/!; foreach my $ext (qw(aux toc lof lot log ind idx ilg ibk bbl blg cit cbk dvi ps pdf)) { my $file = File::Spec->catfile($dir, "${docname}.$ext"); if (-e $file) { diag("removing file '$file'") if $debug > 1; my $rc = unlink($file); diag("unlink returned $rc") if $debug > 2; diag("couldn't remove file '$file'") if $debug > 1 and -e $file; } else { diag("file '$file' does not exist") if $debug > 3; } } } #------------------------------------------------------------------------ # test_dvifile($drv, $pattern_seq) # # Examines the TeX DVI file generated an looks for the sequence of # patterns specified #------------------------------------------------------------------------ sub test_dvifile { my $drv = shift; my @patterns = ref $_[0] ? @{$_[0]} : @_; my $file = $drv->basepath . ".dvi"; if (! -f $file) { fail("dvifile $file does not exist"); return; } SKIP: { skip "cannot find dvitype", 1 unless $dvitype; my $dvioutput = `"$dvitype" "$file"`; my $total = @patterns; my $found = 0; my $pattern = shift @patterns; foreach (split(/\n/, $dvioutput)) { next unless /^\[(.*)\]$/; my $string = $1; if ($string =~ /$pattern/) { if (@patterns) { $pattern = shift @patterns; $found++; } else { pass($drv->basename . ".dvi contains the $total patterns specified"); return 1; } } } fail("pattern '$pattern' not found in " . $drv->basename . ".dvi (found $found of $total patterns)"); } return; } 1; =head1 NAME Test::LaTeX::Driver =head1 SYNOPSIS =head1 DESCRIPTION =head1 AUTHOR Andrew Ford Ea.ford@ford-mason.co.ukE =head1 COPYRIGHT Copyright (C) 2007 Andrew Ford. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: 15-bibtex000755001750001750 015127547545 16505 5ustar00erikerik000000000000LaTeX-Driver-1.3.1/t/testdatatestbib.bib100644001750001750 147215127547545 20763 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/t/testdata/15-bibtex%% This is a test bibliography merely intended for testing Template::Latex @Book{wardley-ptt-2003, title = "Perl Template Toolkit", author = "Andy Wardley and Darren Chamberlain and Dave Cross", publisher = "O'Reilly Media", year = "2003", } @Book{wall-perl-2000, title = "The Perl Programming Language", author = "Larry Wall", publisher = "O'Reilly Media", year = "2003", } @Book{butcher-81, title = "Copy-editing", author = "Judith Butcher", publisher = "Cambridge University Press", year = "1981", edition = "2nd", } @Book{chicago-82, title = "The {C}hicago Manual of Style", author = "`Chicago'", year = "1982", publisher = "University of Chicago Press", edition = "13th", } Driver000755001750001750 015127547545 15707 5ustar00erikerik000000000000LaTeX-Driver-1.3.1/lib/LaTeXFilterProgram.pm100644001750001750 1052715127547545 21207 0ustar00erikerik000000000000LaTeX-Driver-1.3.1/lib/LaTeX/Driver#============================================================= -*-perl-*- # # LaTeX::Driver::FilterProgram # # DESCRIPTION # Implements the guts of the latex2xxx filter programs # # AUTHOR # Andrew Ford # # COPYRIGHT # Copyright (C) 2007 Andrew Ford. All Rights Reserved. # # This module is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # HISTORY # # $Id: Paths.pm 45 2007-09-28 10:33:19Z andrew $ #======================================================================== package LaTeX::Driver::FilterProgram; use strict; use warnings; use Carp; use LaTeX::Driver; use Getopt::Long; use File::Slurp; sub execute { my ($class, %options) = @_; my ($source, $output, $tt2mode, $debug, @vars, %var); GetOptions( 'output:s' => \$output, 'tt2mode' => \$tt2mode, 'define:s' => \@vars, 'debug' => \$debug ); if ( @ARGV ) { $source = shift @ARGV; } else { my $input = join '', ; $source = \$input; } if ($tt2mode) { eval { require Template; }; if ($@) { die "Cannot load the Template Toolkit - tt2 mode is unavailable\n"; } if (!ref $source) { ${$source} = read_file($source); } foreach (@vars) { my ($name, $value) = split / \s* = \s* /mx; printf(STDERR "defining %s as '%s'\n", $name, $value) if $debug; $var{$name} = $value; } my $input; my $tt2 = Template->new({}); $tt2->process($source, \%var, \$input) or die $tt2->error(), "\n"; $source = \$input; } if (!$output or $output eq '-') { my $tmp; $output = \$tmp; } eval { my $drv = LaTeX::Driver->new( source => $source, output => $output, format => $options{format} ); $drv->run; }; if (my $e = LaTeX::Driver::Exception->caught()) { $e->show_trace(1); # my $extra = sprintf("\nat %s line %d (%s)\n%s", $e->file, $e->line, $e->package, $e->trace); die $e; #sprintf("%s\n%s", "$e", $e->trace); } if (ref $output) { print ${$output}; } return; } 1; __END__ =head1 NAME LaTeX::Driver::FilterProgram =head1 VERSION 1.3.1 =head1 SYNOPSIS use LaTeX::Driver::FilterProgram; LaTeX::Driver::FilterProgram->execute(format => $format); =head1 DESCRIPTION This module is not intended to be used except by the programs C, C and C that are included in the LaTeX::Driver distribution. It implements the guts of those filter programs. =head1 SUBROUTINES/METHODS =over 4 =item C This is the only method. It implements the guts of the filter programs, gathering the parameters for the C object constructor from the command line options, along with the options passed from the calling script, which should be the format option. Having constructed a driver object it then runs the driver. If the C<-tt2> option is specified then the source document is taken to be a Template Toolkit template and a Template object is constructed and the template processed through that before being fed to the C module for latex formatting. Template variables may defined with the C<-define> option and these are passed to the Template Toolkit processing stage (they are ignored if the C<-tt2> option is not specified). =back =head1 DIAGNOSTICS The module invokes the C module and optionally the C