#! /usr/bin/env perl ################################################### # Combine a bunch of ancillary files into a LaTeX # # document using the filecontents* environment. # # # # By Scott Pakin # ################################################### ######################################################################## # arlatex # # Copyright (C) 2018-2022 Scott Pakin # # # # This program may be distributed and/or modified under the conditions # # of the LaTeX Project Public License, either version 1.3c of this # # license or (at your option) any later version. # # # # The latest version of this license is in: # # # # http://www.latex-project.org/lppl.txt # # # # and version 1.3c or later is part of all distributions of LaTeX # # version 2008/05/04 or later. # # # # This program consists of the file bundledoc and all the files listed # # in the Files section of the associated README file. # ######################################################################## use 5.006; # Fail gracefully if we're not using Perl v5.6.0. our $VERSION = "1.1"; # Specify the version of arlatex. use Getopt::Long; use Pod::Usage; use File::Basename; use File::Find; require File::Spec; use strict; my $progname = basename($0); # Name of this program my $latexfile; # Main LaTeX document my $outfile = "-"; # Output file (default is standard output) my $baseoutfile = "-"; # Base name of output file ###################################################################### # Include a file using the filecontents* environment. sub includefile ($) { my $filename = $_[0]; my $basefilename = basename $filename; next if $basefilename eq $baseoutfile; # Don't let a file overwrite itself. $basefilename = "\"$basefilename\"" if $basefilename =~ /\s/ && substr($basefilename, 0, 1) ne '"'; open (SOMEFILE, "<$filename") || die "${progname}: $! ($filename)\n"; print OUTFILE "\\begin{filecontents*}[overwrite]{$basefilename}\n"; print OUTFILE ; print OUTFILE "\\end{filecontents*}\n"; close SOMEFILE; } ###################################################################### # Parse the command line. GetOptions ('version' => sub { print "arlatex $VERSION\n"; exit -1 }, 'help'=> sub {pod2usage (-exitval => 0, -verbose => 1)}, 'document=s' => \$latexfile, 'outfile=s' => \$outfile) || pod2usage (-exitval => -1, -verbose => 0); pod2usage (-exitval => -1, -verbose => 0) if !defined $latexfile; if (!-e $latexfile) { my $newlatexfile = "$latexfile.tex"; if (!-e $newlatexfile) { die "${progname}: File $latexfile does not exist\n"; } else { $latexfile = $newlatexfile; } } $baseoutfile = basename $outfile if $outfile ne "-"; # Read the entire input file. open (LATEXFILE, "<$latexfile") || die "${progname}: $! ($latexfile)\n"; my @entirefile = ; close LATEXFILE; # Open the output file, write any initial comments, and then include # all of the files specified on the command line using the filecontents* # environment. Finally, include the rest of the input file. open (OUTFILE, ">$outfile") || die "${progname}: $! ($outfile)\n"; while ($entirefile[0] =~ /^\s*(\%.*)?$/) { print OUTFILE (shift @entirefile); } my @expandedARGV; foreach my $filename (@ARGV) { if (-f $filename) { push @expandedARGV, $filename; } else { find ({wanted => sub {push @expandedARGV, File::Spec->rel2abs($_) if -f $_}, follow => 1}, $filename); } } foreach my $filename (@expandedARGV) { includefile ($filename); print OUTFILE "\n"; } print OUTFILE @entirefile; close OUTFILE; exit 0; ###################################################################### =head1 NAME arlatex - archive a number of ancillary LaTeX files into a master F<.tex> file =head1 SYNOPSIS arlatex [B<--outfile>=IF<.tex>] B<--document>=IF<.tex> I ... arlatex B<--version> arlatex B<--help> =head1 DESCRIPTION B is an archiving program like B, B, B, etc. Unlike those other archivers, however, B is designed specifically for use with LaTeX. B takes the name of a master F<.tex> file and a number of ancillary files used by that master file (e.g., F<.tex>, F<.sty>, F<.cls>, and F<.eps> files). From these, B outputs a single file that, when it's run through B, both regenerates the ancillary files and compiles the document into a F<.dvi> file. B has a few advantages over other archiving programs: =over 4 =item * The F<.tex> files produced by B are in a plain-text format. They are therefore perfectly portable and trivial to e-mail to colleagues. =item * B needs only LaTeX to run. There is no dependence on any external tools. =item * There is no explicit extraction step. As the generated document is run through B, it extracts the ancillary files and builds the document in the same step. The user running B may not even notice that additional files are being produced. =back B works by writing a number of S ...> C<\end{filecontents*}> blocks to the output file, followed by the contents of the master file. (In fact, any LaTeX comments at the beginning of the master file are hoisted to the top of the generated file. This enables the author to draw attention, if so desired, to the fact that ancillary files will be generated.) The C environment, part of standard LaTeX2e, writes its contents verbatim to a specified file. =head1 OPTIONS =over 4 =item B<--version> Output the B script's version number. =item B<--help> Output brief B usage information. =item B<--document>=I<.tex file> Specify the master document. The output from B is this file with all of the other files named on the command line prepended to it. Note that C<--document> is a I parameter; B will abort with an error message if C<--document> is not specified. =item B<--outfile>=I<.tex file> Specify the output file. The output file looks just like the master document, but with a number of C environments preceding the C<\documentclass> line. If C<--outfile> is not specified, output will be written to the standard output device. =back =head1 EXAMPLES Suppose you have a paper called F that loads a custom package with C<\usepackage{mypackage}>. You want to submit the paper to a conference, but you want to be absolutely certain that F doesn't get lost as your paper is shuttled from person to person. Here's how B can be of use: arlatex --document=paper.tex mypackage.sty --outfile=paper-submit.tex When F is processed with B, it builds just like the original F, except that it additionally creates a F in the current directory: This is TeX, Version 3.14159 (Web2C 7.3.1) (paper-submit.tex LaTeX2e <1999/12/01> patch level 1 Babel and hyphenation patterns for american, french, german, ngerman, italian, nohyphenation, loaded. LaTeX Warning: Writing file `./mypackage.sty'. (/usr/share/texmf/tex/latex/base/article.cls Document Class: article 1999/09/10 v1.4a Standard LaTeX document class (/usr/share/texmf/tex/latex/base/size12.clo)) (mypackage.sty) . . . As another example, here's how you could bundle together all of the files needed to build a large document for longevity: arlatex --document=thesis.tex abstract.tex introduction.tex background.tex approach.tex experiments.tex relatedwork.tex conclusions.tex before.eps after.eps fast.eps slow.eps podunkUthesis.cls --outfile=thesis-all.tex As the number of files to archive together increases it becomes more cumbersome to run B manually. Fortunately, using B with B is straightforward. B finds all of the files needed to build the document, and B combines them into a single file. The following are examples of the C line you might use in a B configuration file: =over 1 =item Unix: bundle: (arlatex --document=$BDBASE.tex $BDINPUTS \ --outfile=$BDBASE-all.tex) =item Windows: bundle: arlatex --document=%BDBASE%.tex %BDINPUTS% \ --outfile=%BDBASE%-all.tex =back See the B documentation for more information. =head1 CAVEATS B makes use of LaTeX's C environment. It passes C the C option to indicate that existing files with the same name should be overwritten. Be forewarned that building the generated file will overwrite the files used to create it. It is best to avoid bundling binary files (e.g., included graphics) with B. These typically do not extract cleanly. =head1 SEE ALSO bundledoc(1), latex(1), shar(1), tar(1), zip(1) =head1 AUTHOR Scott Pakin, I