1#! /usr/bin/env perl 2 3########################################################### 4# Prepare a LaTeX run for two-way communication with Perl # 5# By Scott Pakin <scott+pt@pakin.org> # 6########################################################### 7 8#------------------------------------------------------------------- 9# This is file `perltex.pl', 10# generated with the docstrip utility. 11# 12# The original source files were: 13# 14# perltex.dtx (with options: `perltex') 15# 16# This is a generated file. 17# 18# Copyright (C) 2004 by Scott Pakin <scott+pt@pakin.org> 19# 20# This file may be distributed and/or modified under the conditions 21# of the LaTeX Project Public License, either version 1.2 of this 22# license or (at your option) any later version. The latest 23# version of this license is in: 24# 25# http://www.latex-project.org/lppl.txt 26# 27# and version 1.2 or later is part of all distributions of LaTeX 28# version 1999/12/01 or later. 29#------------------------------------------------------------------- 30 31use Safe; 32use Opcode; 33use Getopt::Long; 34use Pod::Usage; 35use File::Basename; 36use POSIX; 37use warnings; 38use strict; 39my $latexprog; 40my $runsafely = 1; 41my @permittedops; 42my $progname = basename $0; 43my $jobname = "texput"; 44my @latexcmdline; 45my $toperl; 46my $fromperl; 47my $toflag; 48my $fromflag; 49my $doneflag; 50my $logfile; 51my $sandbox = new Safe; 52my $latexpid; 53$latexprog = $ENV{"PERLTEX"} || "latex"; 54Getopt::Long::Configure("require_order", "pass_through"); 55GetOptions("help" => sub {pod2usage(-verbose => 1)}, 56 "latex=s" => \$latexprog, 57 "safe!" => \$runsafely, 58 "permit=s" => \@permittedops) || pod2usage(2); 59@latexcmdline = @ARGV; 60my $firstcmd = 0; 61for ($firstcmd=0; $firstcmd<=$#latexcmdline; $firstcmd++) { 62 my $option = $latexcmdline[$firstcmd]; 63 next if substr($option, 0, 1) eq "-"; 64 if (substr ($option, 0, 1) ne "\\") { 65 $jobname = basename $option, ".tex" ; 66 $latexcmdline[$firstcmd] = "\\input $option"; 67 } 68 last; 69} 70push @latexcmdline, "" if $#latexcmdline==-1; 71my $separator = ""; 72foreach (1 .. 20) { 73 $separator .= chr(ord("A") + rand(26)); 74} 75$toperl = $jobname . ".topl"; 76$fromperl = $jobname . ".frpl"; 77$toflag = $jobname . ".tfpl"; 78$fromflag = $jobname . ".ffpl"; 79$doneflag = $jobname . ".dfpl"; 80$logfile = $jobname . ".lgpl"; 81$latexcmdline[$firstcmd] = 82 sprintf '\makeatletter' . '\def%s{%s}' x 6 . '\makeatother%s', 83 '\plmac@tag', $separator, 84 '\plmac@tofile', $toperl, 85 '\plmac@fromfile', $fromperl, 86 '\plmac@toflag', $toflag, 87 '\plmac@fromflag', $fromflag, 88 '\plmac@doneflag', $doneflag, 89 $latexcmdline[$firstcmd]; 90foreach my $file ($toperl, $fromperl, $toflag, $fromflag, $doneflag) { 91 unlink $file while -e $file; 92} 93open (LOGFILE, ">$logfile") || die "open(\"$logfile\"): $!\n"; 94defined ($latexpid = fork) || die "fork: $!\n"; 95unshift @latexcmdline, $latexprog; 96if (!$latexpid) { 97 exec {$latexcmdline[0]} @latexcmdline; 98 die "exec('@latexcmdline'): $!\n"; 99} 100@permittedops=(":browse") if $#permittedops==-1; 101@permittedops=(Opcode::full_opset()) if !$runsafely; 102$sandbox->permit_only (@permittedops); 103while (1) { 104 my $awaitexists = sub { 105 while (!-e $_[0]) { 106 sleep 0; 107 if (waitpid($latexpid, &WNOHANG)==-1) { 108 foreach my $file ($toperl, $fromperl, $toflag, 109 $fromflag, $doneflag) { 110 unlink $file while -e $file; 111 } 112 undef $latexpid; 113 exit 0; 114 } 115 } 116 }; 117 $awaitexists->($toflag); 118 my $entirefile; 119 { 120 local $/ = undef; 121 open (TOPERL, "<$toperl") || die "open($toperl): $!\n"; 122 $entirefile = <TOPERL>; 123 close TOPERL; 124 } 125 my ($optag, $macroname, @otherstuff) = 126 map {chomp; $_} split "$separator\n", $entirefile; 127 $macroname =~ s/^[^A-Za-z]+//; 128 $macroname =~ s/\W/_/g; 129 $macroname = "latex_" . $macroname; 130 if ($optag eq "USE") { 131 foreach (@otherstuff) { 132 s/\\/\\\\/g; 133 s/\'/\\\'/g; 134 $_ = "'$_'"; 135 } 136 } 137 my $perlcode; 138 if ($optag eq "DEF") { 139 $perlcode = 140 sprintf "sub %s {%s}\n", 141 $macroname, $otherstuff[0]; 142 } 143 else { 144 $perlcode = sprintf "%s (%s);\n", $macroname, join(", ", @otherstuff); 145 } 146 print LOGFILE "#" x 31, " PERL CODE ", "#" x 32, "\n"; 147 print LOGFILE $perlcode, "\n"; 148 undef $_; 149 my $result; 150 { 151 my $warningmsg; 152 local $SIG{__WARN__} = 153 sub {chomp ($warningmsg=$_[0]); return 0}; 154 $result = $sandbox->reval ($perlcode); 155 if (defined $warningmsg) { 156 $warningmsg =~ s/at \(eval \d+\) line \d+\W+//; 157 print LOGFILE "# ===> $warningmsg\n\n"; 158 } 159 } 160 $result="" if !$result; 161 if ($@) { 162 my $msg = $@; 163 $msg =~ s/at \(eval \d+\) line \d+\W+//; 164 $msg =~ s/\s+/ /; 165 $result = "\\PackageError{perltex}{$msg}"; 166 my @helpstring; 167 if ($msg =~ /\btrapped by\b/) { 168 @helpstring = 169 ("The preceding error message comes from Perl. Apparently,", 170 "the Perl code you tried to execute attempted to perform an", 171 "`unsafe' operation. If you trust the Perl code (e.g., if", 172 "you wrote it) then you can invoke perltex with the --nosafe", 173 "option to allow arbitrary Perl code to execute.", 174 "Alternatively, you can selectively enable Perl features", 175 "using perltex's --permit option. Don't do this if you don't", 176 "trust the Perl code, however; malicious Perl code can do a", 177 "world of harm to your computer system."); 178 } 179 else { 180 @helpstring = 181 ("The preceding error message comes from Perl. Apparently,", 182 "there's a bug in your Perl code. You'll need to sort that", 183 "out in your document and re-run perltex."); 184 } 185 my $helpstring = join ("\\MessageBreak\n", @helpstring); 186 $helpstring =~ s/\. /.\\space\\space /g; 187 $result .= "{$helpstring}"; 188 } 189 print LOGFILE "%" x 30, " LATEX RESULT ", "%" x 30, "\n"; 190 print LOGFILE $result, "\n\n"; 191 $result .= '\endinput'; 192 open (FROMPERL, ">$fromperl") || die "open($fromperl): $!\n"; 193 syswrite FROMPERL, $result; 194 close FROMPERL; 195 unlink $toflag while -e $toflag; 196 unlink $toperl while -e $toperl; 197 unlink $doneflag while -e $doneflag; 198 open (FROMFLAG, ">$fromflag") || die "open($fromflag): $!\n"; 199 close FROMFLAG; 200 $awaitexists->($toperl); 201 unlink $fromflag while -e $fromflag; 202 open (DONEFLAG, ">$doneflag") || die "open($doneflag): $!\n"; 203 close DONEFLAG; 204} 205END { 206 close LOGFILE; 207 if (defined $latexpid) { 208 kill (9, $latexpid); 209 exit 1; 210 } 211 exit 0; 212} 213 214__END__ 215 216=head1 NAME 217 218perltex - enable LaTeX macros to be defined in terms of Perl code 219 220=head1 SYNOPSIS 221 222perltex 223[B<--help>] 224[B<--latex>=I<program>] 225[B<-->[B<no>]B<safe>] 226[B<--permit>=I<feature>] 227[I<latex options>] 228 229=head1 DESCRIPTION 230 231LaTeX -- through the underlying TeX typesetting system -- produces 232beautifully typeset documents but has a macro language that is 233difficult to program. In particular, support for complex string 234manipulation is largely lacking. Perl is a popular general-purpose 235programming language whose forte is string manipulation. However, it 236has no typesetting capabilities whatsoever. 237 238Clearly, Perl's programmability could complement LaTeX's typesetting 239strengths. B<perltex> is the tool that enables a symbiosis between 240the two systems. All a user needs to do is compile a LaTeX document 241using B<perltex> instead of B<latex>. (B<perltex> is actually a 242wrapper for B<latex>, so no B<latex> functionality is lost.) If the 243document includes a C<\usepackage{perltex}> in its preamble, then 244C<\perlnewcommand> and C<\perlrenewcommand> macros will be made 245available. These behave just like LaTeX's C<\newcommand> and 246C<\renewcommand> except that the macro body contains Perl code instead 247of LaTeX code. 248 249=head1 OPTIONS 250 251B<perltex> accepts the following command-line options: 252 253=over 4 254 255=item B<--help> 256 257Display basic usage information. 258 259=item B<--latex>=I<program> 260 261Specify a program to use instead of B<latex>. For example, 262C<--latex=pdflatex> would typeset the given document using 263B<pdflatex> instead of ordinary B<latex>. 264 265=item B<-->[B<no>]B<safe> 266 267Enable or disable sandboxing. With the default of C<--safe>, 268B<perltex> executes the code from a C<\perlnewcommand> or 269C<\perlrenewcommand> macro within a protected environment that 270prohibits ``unsafe'' operations such as accessing files or executing 271external programs. Specifying C<--nosafe> gives the LaTeX document 272I<carte blanche> to execute any arbitrary Perl code, including that 273which can harm the user's files. See L<Safe> for more information. 274 275=item B<--permit>=I<feature> 276 277Permit particular Perl operations to be performed. The C<--permit> 278option, which can be specified more than once on the command line, 279enables finer-grained control over the B<perltex> sandbox. See 280L<Opcode> for more information. 281 282=back 283 284These options are then followed by whatever options are normally 285passed to B<latex> (or whatever program was specified with 286C<--latex>), including, for instance, the name of the F<.tex> file to 287compile. 288 289=head1 EXAMPLES 290 291In its simplest form, B<perltex> is run just like B<latex>: 292 293 perltex myfile.tex 294 295To use B<pdflatex> instead of regular B<latex>, use the C<--latex> 296option: 297 298 perltex --latex=pdflatex myfile.tex 299 300If LaTeX gives a ``C<trapped by operation mask>'' error and you trust 301the F<.tex> file you're trying to compile not to execute malicious 302Perl code (e.g., because you wrote it yourself), you can disable 303B<perltex>'s safety mechansisms with C<--nosafe>: 304 305 perltex --nosafe myfile.tex 306 307The following command gives documents only B<perltex>'s default 308permissions (C<:browse>) plus the ability to open files and invoke the 309C<time> command: 310 311 perltex --permit=:browse --permit=:filesys_open 312 --permit=time myfile.tex 313 314=head1 ENVIRONMENT 315 316B<perltex> honors the following environment variables: 317 318=over 4 319 320=item PERLTEX 321 322Specify the filename of the LaTeX compiler. The LaTeX compiler 323defaults to ``C<latex>''. The C<PERLTEX> environment variable 324overrides this default, and the C<--latex> command-line option (see 325L</OPTIONS>) overrides that. 326 327=back 328 329=head1 FILES 330 331While compiling F<jobname.tex>, B<perltex> makes use of the following 332files: 333 334=over 4 335 336=item F<jobname.lgpl> 337 338log file written by Perl; helpful for debugging Perl macros 339 340=item F<jobname.topl> 341 342information sent from LaTeX to Perl 343 344=item F<jobname.frpl> 345 346information sent from Perl to LaTeX 347 348=item F<jobname.tfpl> 349 350``flag'' file whose existence indicates that F<jobname.topl> contains 351valid data 352 353=item F<jobname.ffpl> 354 355``flag'' file whose existence indicates that F<jobname.frpl> contains 356valid data 357 358=item F<jobname.dfpl> 359 360``flag'' file whose existence indicates that F<jobname.ffpl> has been 361deleted 362 363=back 364 365=head1 NOTES 366 367B<perltex>'s sandbox defaults to what L<Opcode> calls ``C<:browse>''. 368 369=head1 SEE ALSO 370 371latex(1), pdflatex(1), perl(1), Safe(3pm), Opcode(3pm) 372 373=head1 AUTHOR 374 375Scott Pakin, I<scott+pt@pakin.org> 376