fmt_latex2e.pl 17.2 KB
Newer Older
1 2 3
#
#  fmt_latex2e.pl
#
4
# ------------------------------------------------------------------
5 6
#  LaTeX-specific driver stuff
#
7
#  Copyright  1994-1996, Matt Welsh
8
#  Copyright  1996, Cees de Groot
9 10 11
#  Copyright  1999-2002, Taketoshi Sano
#  Copyright  1999, Kazuyuki Okamoto (euc-jp support in sgml2txt, sgml2html, and sgml2latex)
#  Copyright  1999, Tetsu ONO (euc-jp support in sgml2txt, sgml2html, and sgml2latex)
12
#  Copyright  2000, Juan Jose Amor (Support for PDF files)
13
#  Copyright  2006-2009, Agustin Martin
14 15
# ------------------------------------------------------------------

16 17 18 19 20 21 22 23 24 25 26
package LinuxDocTools::fmt_latex2e;
use strict;

use LinuxDocTools::CharEnts;
use LinuxDocTools::Vars;
use LinuxDocTools::Lang;

use File::Copy;

my $latex2e = {};
$latex2e->{NAME} = "latex2e";
27
$latex2e->{HELP} = "
28 29
  Note that this output format requires LaTeX 2e.

30
";
31
$latex2e->{OPTIONS} = [
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
		       { option => "output",
			 type => "l",
			 'values' => [ "dvi", "tex", "ps", "pdf" ],
			 short => "o" },
		       { option => "bibtex",
			 type => "f",
			 short => "b" },
		       { option => "makeindex",
			 type => "f",
			 short => "m" },
		       { option => "pagenumber",
			 type => "i",
			 short => "n" },
		       { option => "quick",
			 type => "f",
			 short => "q" },
		       { option => "dvips",
			 type => "l",
			 'values' => [ "dvips", "dvi2ps", "jdvi2kps" ],
			 short => "s" },
		       { option => "latex",
			 type => "l",
			 'values' => [ "latex", "hlatexp", "platex", "jlatex" ],
			 short => "x" }
		       ];
$latex2e->{output}         = "tex";
$latex2e->{pagenumber}     = 1;
$latex2e->{quick}          = 0;
$latex2e->{bibtex}         = 0;
$latex2e->{makeindex}      = 0;
$latex2e->{latex}          = "unknown";
$latex2e->{dvips}          = "unknown";
64 65
$Formats{$latex2e->{NAME}} = $latex2e;

66
# ------------------------------------------------------------------
67
$latex2e->{preNSGMLS} = sub {
68
# ------------------------------------------------------------------
69 70 71 72
  $global->{NsgmlsOpts} .= " -ifmttex ";

  #  for Japanese jlatex users
  if ($global->{language} eq "ja" && $latex2e->{latex} eq "unknown") {
73 74 75 76 77
    $latex2e->{latex} = "jlatex";
    $latex2e->{dvips} = "dvi2ps";
    # for Japanese platex users
    #	$latex2e->{latex} = "platex";
    #	$latex2e->{dvips} = "dvips";
78 79 80 81
  }

  # for Korean users
  if ($global->{language} eq "ko" && $latex2e->{latex} eq "unknown") {
82
    $latex2e->{latex} = "hlatexp";
83 84 85 86 87 88
  }

  # default process command
  $latex2e->{latex} = "latex" if ($latex2e->{latex} eq "unknown");
  $latex2e->{dvips} = "dvips" if ($latex2e->{dvips} eq "unknown");

89
  $global->{NsgmlsPrePipe} = "cat $global->{file} | sed 's/_/\\_/g' ";
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
};

# extra `\\' here for standard `nsgmls' output
my %latex2e_escapes;
$latex2e_escapes{'#'} = '\\\\#';
$latex2e_escapes{'$'} = '\\\\$';
$latex2e_escapes{'%'} = '\\\\%';
$latex2e_escapes{'&'} = '\\\\&';
$latex2e_escapes{'~'} = '\\\\~{}';
$latex2e_escapes{'_'} = '\\\\_';
$latex2e_escapes{'^'} = '\\\\^{}';
$latex2e_escapes{'\\'} = '\\verb+\\+';
$latex2e_escapes{'{'} = '\\\\{';
$latex2e_escapes{'}'} = '\\\\}';
$latex2e_escapes{'>'} = '{$>$}';
$latex2e_escapes{'<'} = '{$<$}';	# wouldn't happen, but that's what'd be
$latex2e_escapes{'|'} = '{$|$}';

my $in_verb;
my $remove_comment; # added 2000 Jan 25 by t.sano

# passed to `parse_data' below in latex2e_preASP
my $latex2e_escape = sub {
113
  my ($data) = @_;
114

115 116 117 118
  if (!$in_verb) {
    # escape special characters
    $data =~ s|([\#\$%&~_^\\{}<>\|])|$latex2e_escapes{$1}|ge;
  }
119

120
  return ($data);
121 122
};

123 124 125
# ------------------------------------------------------------------
$latex2e->{preASP} = sub {
# ------------------------------------------------------------------
126
#  Translate character entities and escape LaTeX special chars.
127
# ------------------------------------------------------------------
128
  my ($INFILE, $OUTFILE) = @_;
129

130
  # Note: `sdata_dirs' made an anonymous array to have a single argument
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
  my $tex_char_maps = load_char_maps ('.2tex', [ Text::EntityMap::sdata_dirs() ]);

  # ASCII char maps are used in the verbatim environment because TeX
  # ignores all the escapes
  my $ascii_char_maps = load_char_maps ('.2ab', [ Text::EntityMap::sdata_dirs() ]);
  $ascii_char_maps = load_char_maps ('.2l1b', [ Text::EntityMap::sdata_dirs() ]) if $global->{charset} eq "latin";

  my $char_maps = $tex_char_maps;

  # used in `latex2e_escape' anonymous sub to switch between escaping
  # characters from SGML source or not, depending on whether we're in
  # a VERB or CODE environment or not
  $in_verb = 0;

  # switch to remove empty line from TeX source or not, depending
  # on whether we're in a HEADING or ABSTRACT environment or not
  $remove_comment = 0;

149
  while (<$INFILE>) {
150 151 152 153 154 155 156
    if ( s/^-// ){
      chomp;
      s/^\\n/ /;          # Remove spurious leading \n (not real \\n)
      $_ = parse_data ($_, $char_maps, $latex2e_escape);
      if ($remove_comment){
	s/(\s+\\n)+//;
      }
157
      print $OUTFILE "-" . $_ . "\n";
158 159 160 161 162 163 164 165 166 167 168 169
    } elsif (/^A/) {
      /^A(\S+) (IMPLIED|CDATA|NOTATION|ENTITY|TOKEN)( (.*))?$/
	|| die "bad attribute data: $_\n";
      my ($name,$type,$value) = ($1,$2,$4);
      if ($type eq "CDATA") {
	# CDATA attributes get translated also
	if ($name eq "URL" or $name eq "ID" or $name eq "CA") {
	  # URL for url.sty is a kind of verbatim...
	  # CA is used in "tabular" element.
	  # Thanks to Evgeny Stambulchik, he posted this fix
	  # on sgml-tools list. 2000 May 17, t.sano
	  my $old_verb = $in_verb;
170
	  $in_verb = 1;
171 172 173 174 175
	  $value = parse_data ($value, $ascii_char_maps,
			       $latex2e_escape);
	  $in_verb = $old_verb;
	} else {
	  $value = parse_data ($value, $char_maps, $latex2e_escape);
176
	}
177
      }
178
      print $OUTFILE "A$name $type $value\n";
179
    } elsif (/^\((VERB|CODE)/) {
180
      print $OUTFILE $_;
181 182 183 184
      # going into VERB/CODE section
      $in_verb = 1;
      $char_maps = $ascii_char_maps;
    } elsif (/^\)(VERB|CODE)/) {
185
      print $OUTFILE $_;
186 187 188 189
      # leaving VERB/CODE section
      $in_verb = 0;
      $char_maps = $tex_char_maps;
    } elsif (/^\((HEADING|ABSTRACT)/) {
190
      print $OUTFILE $_;
191 192 193 194
      # empty lines (comment in sgml source) do harm
      # in HEADING or ABSTRACT
      $remove_comment = 1;
    } elsif (/^\)(HEADING|ABSTRACT)/) {
195
      print $OUTFILE $_;
196 197 198
      # leaving HEADING or ABSTRACT section
      $remove_comment = 0;
    } else {
199
      print $OUTFILE $_;
200
    }
201
  }
202 203
};

204 205 206
# ------------------------------------------------------------------
sub latex2e_defnam($) {
# ------------------------------------------------------------------
207
# return the string of the name of the macro for urldef
208 209
# ------------------------------------------------------------------
  my ($num) = @_;
210

211 212 213
  if ($num > 26*26*26) {
    die "Too many URLs!\n";
  }
214

215
  my $anum = ord("a");
216

217 218 219
  my $defnam = chr ($anum + ($num / 26 / 26)) .
    chr ($anum + ($num / 26 % 26)) .
    chr ($anum + ($num % 26));
220

221
  return ($defnam);
222 223
};

224
# ------------------------------------------------------------------
225
$latex2e->{postASP} = sub
226 227 228
# ------------------------------------------------------------------
#  Take the sgmlsasp output, and make something useful from it.
# ------------------------------------------------------------------
229
{
230 231 232
  my $INFILE       = shift;
  my $OUTFILE;
  my $SGMLFILE;
233 234 235
  my $filename     = $global->{filename};
  my $tmplatexdir  = $global->{tmpbase} . "-latex-" . $$ . ".dir";
  my $tmplatexnam  = $tmplatexdir . "/" . $filename;
236
  my $msgheader    = "fmt_latex2e::postASP";
237 238 239 240 241
  my @epsfiles     = ();
  my @texlines     = ();
  my @urldefines   = ();
  my @urlnames     = ();
  my $urlnum       = 0;
242
  my $tmpepsf;
243
  my $saved_umask  = umask;
244 245 246
  $ENV{TEXINPUTS} .= ":$main::DataDir";

  umask 0077;
247 248
  mkdir ($tmplatexdir, 0700)
    or die "Could not create \"$tmplatexdir\" directory.\n";
249 250 251

  # check epsfile is specified in source file
  {
252
    my $epsf;
253
    open $SGMLFILE, "<$filename.sgml";
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    while (<$SGMLFILE>){
      # for epsfile
      if ( s/^\s*<eps\s+file=(.*)>/$1/ ) {
	s/\s+angle=.*//;
	s/\s+height=.*//;
	s/\"//g;
	$epsf = $_;
	chop ( $epsf );
	push @epsfiles, $epsf;
      }
      if ($latex2e->{output} eq "pdf") {
	if ( s/^\s*<img\s+src=(.*)>/$1/ ) {
	  s/\"//g;
	  $epsf = $_;
	  chop ( $epsf );
	  push @epsfiles, $epsf;
	}
271
      }
272
    }
273
    close $SGMLFILE;
274
  }
275 276

  # Parse TeX file and check nameurl specified in source file
277
  {
278 279 280
    my $urlid;
    my $urlnam;
    my $urldef;
281 282 283 284 285 286

    while (<$INFILE>){
      # Read TeX file
      push @texlines, $_;
      # and check for nameurl
      if ( /\\nameurl/ ){
287
	($urlid, $urlnam) = ($_ =~ /\\nameurl\{(.*)\}\{(.*)\}/);
288 289 290
	print $urlnum . ": " . $urlid . "\n" if ( $global->{debug} );

	$urldef = latex2e_defnam($urlnum) . "url";
291
	s/\\nameurl\{.*\}\{.*\}/{\\em $urlnam} {\\tt \\$urldef}/;
292 293 294
	push @urlnames, $_;
	push @urldefines, "\\urldef{\\$urldef} \\url{$urlid}\n";
	$urlnum++;
295
      }
296
    }
297
    close $INFILE;
298 299
  }

300 301 302
  # --------------------------------------------------------------------
  #  Set the correct \documentclass and packages options.
  # --------------------------------------------------------------------
303 304 305 306 307 308 309 310 311 312 313 314 315 316
  {
    my $langlit = ISO2English ($global->{language});
    $langlit = ($langlit eq 'english') ? "" : "$langlit";
    my $hlatexopt = "";
    $global->{charset} = "nippon" if ($global->{language} eq "ja");
    $global->{charset} = "euc-kr" if ($global->{language} eq "ko");

    # Getting document class prefix
    my $classprefix = "";
    if ($global->{charset} eq "nippon") {
      if ($latex2e->{latex} eq "platex") {
	$classprefix = "j";
      } elsif ($latex2e->{latex} eq "jlatex") {
	$classprefix = "j-";
317
      }
318
    }
319

320 321 322 323 324
    # Getting class options
    my $classoptions = $global->{papersize} . 'paper';

    # Getting babel options
    my $babeloptions = $langlit || "english";
325 326 327 328 329
    if ( ($global->{charset} eq "nippon")
	 ||
	 ($global->{charset} eq "euc-kr")) {
      $babeloptions = '';
    }
330

331 332 333
    open ($OUTFILE, "> $tmplatexnam.tex")
      or die "fmt_latex2e::postASP: Could not open \"$tmplatexnam.tex\" for write.\n";

334 335
    # Loop over the TeX file
    my $inpreamble = 1;
336 337 338
    while (defined($texlines[0])) {
      $_ = shift @texlines;

339 340 341
      if ( $inpreamble ) {
	if (/%end-preamble/) {
	  $inpreamble = '';
342

343 344 345 346 347 348 349
	  if ($latex2e->{pagenumber}) {
	    $_ = $_ . '\setcounter{page}{' .
	      $latex2e->{pagenumber} .
	      "}\n";
	  } else {
	    $_ = $_ . "\\pagestyle{empty}\n";
	  }
350

351 352
	  # Now include the explicitly added stuff
	  $_ = $_ . $global->{pass} . "\n" if ($global->{pass});
353

354
	  print $OUTFILE $_;
355

356 357 358 359 360
	  # Add to preamble url definitions for \urldef
	  if ($urlnum && $latex2e->{output} ne "pdf") {
	    foreach my $thisurl ( @urldefines ) {
	      print $OUTFILE $thisurl;
	    }
361
	  }
362 363 364 365 366 367 368
	} else {   # -- Not in last line of linuxdoc-tools added preamble
	  # Set correct class name and options in the header
	  if (/^\\documentclass\[\@CLASSOPTIONS\@\]/) {
	    s/\@(ARTICLE|REPORT|BOOK)\@/$classprefix . lc($1)/e;
	    s/\@CLASSOPTIONS\@/$classoptions/;
	    $_ = $_ . "\\makeindex\n" if ($latex2e->{makeindex});
	  }
369
	  # Set correct DTD name
370
	  elsif (/^\\usepackage\{\@LINUXDOC_DTD\@-sgml\}/) {
371 372 373
	    my $dtd = $global->{"dtd"};
	    s/\@LINUXDOC_DTD\@/$dtd/;
	  }
374
	  # Set correct babel options
375
	  elsif (/^\\usepackage\[\@BABELOPTIONS\@\]\{babel\}/) {
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
	    if ( $babeloptions ) {
	      s/\@BABELOPTIONS\@/$babeloptions/;
	    } else {
	      s/^/%%/;
	    }
	  }
	  elsif (/^\\usepackage.epsfig/ && ($global->{charset} eq "euc-kr")) {
	    $hlatexopt = "[noautojosa]" if ($latex2e->{latex} eq "hlatexp");
	    $_ = $_ . "\\usepackage" . "$hlatexopt" . "{hangul}\n";
	  }
	  # Deal with input encoding
	  elsif ( /\\usepackage\[\@CHARSET\@\]\{inputenc\}/ ) {
	    if ( $global->{charset} eq "latin" ) {
	      s/\@CHARSET\@/latin1/;
	    } else {
	      s/^/%%/;
	    }
	  }
	  # nippon or euc-kr do not use T1 encoding
	  elsif ( (/\\usepackage\[T1\]\{fontenc\}/)    &&
		  ( ($global->{charset} eq "nippon")   ||
		    ($global->{charset} eq "euc-kr"))) {
	    s/^/%%/;
	  }
	  print $OUTFILE $_;
	}
      } else {   # -- Not in linuxdocsgml added preamble
	#
	if (/\\nameurl/ && $latex2e->{output} ne "pdf") {
	  $_ = shift @urlnames;
406
	}
407
	print $OUTFILE $_;
408
      }
409
    }
410
  }
411
  close $OUTFILE;
412 413

  #  LaTeX, dvips, and assorted cleanups.
414 415 416 417 418 419 420 421 422 423 424 425
  if ($latex2e->{output} eq "tex") {
    # comment out, because this backup action is not documented yet.
    #
    #      if ( -e "$filename.tex" ) {
    #          rename ("$filename.tex", "$filename.tex.back");
    #      }

    umask $saved_umask;
    copy ("$tmplatexnam.tex", "$filename.tex");
    if ( ! $global->{debug} ) {
      unlink ("$tmplatexnam.tex");
      rmdir ($tmplatexdir) || return -1;
426 427
    }

428 429 430
    return 0;
  }

431 432 433 434 435 436 437 438 439
  # Run LaTeX in nonstop mode so it won't prompt & hang on errors.
  # Suppress the output of LaTeX on all but the last pass, after
  # references have been resolved.  This avoids large numbers of
  # spurious warnings.
  my $current_dir;
  chop ($current_dir = `pwd`);
  print $current_dir . "\n" if ( $global->{debug} );

  # copy epsfiles specified in tex file
440 441 442 443 444
  for my $epsf ( @epsfiles ) {
    $tmpepsf = $tmplatexdir . "/" . $epsf;
    print $epsf . " " . $tmpepsf . "\n" if ( $global->{debug} );
    copy ("$epsf", "$tmpepsf") or die "can not copy graphics\n";
  }
445 446 447 448 449 450 451

  # go to the temporary directory
  chdir ($tmplatexdir);

  my ($latexcommand) = "$latex2e->{latex} '\\nonstopmode\\input{$filename.tex}'";

  # We run pdflatex instead of latex if user selected pdf output
452 453 454
  if ($latex2e->{output} eq "pdf") {
    $latexcommand = "pdflatex '\\nonstopmode\\input{$filename.tex}'";
  }
455 456 457

  # run hlatex if hlatexp is used
  # for pdf: how about status?(for hlatex and hlatexp)
458 459 460 461
  if ($latex2e->{latex} eq "hlatexp") {
    #$latex2e->{output} = "ps" if ($latex2e->{output} eq "pdf");
    $latexcommand = "hlatex '\\nonstopmode\\input{$filename.tex}'";
  }
462 463 464

  # We use jlatex for Japanese encoded (euc-jp) characters.
  # pdf support for Japanese are not yet. use ps for the time being.
465 466 467 468
  if ($global->{charset} eq "nippon") {
    $latex2e->{output} = "ps" if ($latex2e->{output} eq "pdf");
    $latexcommand = "$latex2e->{latex} '\\nonstopmode\\input{$filename.tex}'";
  }
469 470
  my ($suppress) = $latex2e->{quick} ? "" : ' >/dev/null';

471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
  system ($latexcommand . $suppress) == 0
    or die "$msgheader: LaTeX first run problem. Aborting ...\n";

  if ( $latex2e->{bibtex} ) {
    system ( "bibtex $filename" ) == 0
      or print STDERR "$msgheader: Problems when running BibTeX. Ignoring ...\n";
  }

  unless ( $latex2e->{quick} ){
    system ($latexcommand . ' >/dev/null') == 0
      or die "$msgheader: LaTeX second run problem. Aborting ...\n";
    system ( $latexcommand ) == 0
      or die "$msgheader: LaTeX third run problem. Aborting ...\n";
  }

486 487 488 489
  if ( ! $global->{debug} ) {
    my @suffixes = qw(log blg aux toc lof lot dlog bbl out);
    for my $suf (@suffixes) {
      unlink "$tmplatexnam.$suf";
490
    }
491
  }
492

493 494
  # go back to the working directory
  chdir ($current_dir);
495

496
  # output dvi file
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
  if ($latex2e->{output} eq "dvi") {
    # comment out, because this backup action is not documented yet.
    #
    #      if ( -e "$filename.dvi" )
    #        {
    #          rename ("$filename.dvi", "$filename.dvi.back");
    #        }
    umask $saved_umask;
    copy ("$tmplatexnam.dvi", "$filename.dvi");
    if ( $global->{debug} ) {
      print "Temporary files are in $tmplatexdir\n";
      print "Please check there and remove them manually.\n";
    } else {
      unlink ("$tmplatexnam.tex", "$tmplatexnam.dvi");
      for my $epsf ( @epsfiles ) {
	$tmpepsf = $tmplatexdir . "/" . $epsf;
	print $tmpepsf . "\n" if ( $global->{debug} );
	unlink ("$tmpepsf");
      }
      rmdir ($tmplatexdir) || return -1;
517
    }
518 519
    return 0;
  }
520

521
  # output pdf file
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
  if ($latex2e->{output} eq "pdf") {
    # comment out, because this backup action is not documented yet.
    #
    #      if ( -e "$filename.pdf" )
    #         {
    #          rename ("$filename.pdf", "$filename.pdf.back");
    #        }
    umask $saved_umask;
    copy ("$tmplatexnam.pdf", "$filename.pdf");
    if ( $global->{debug} ) {
      print "Temporary files are in $tmplatexdir\n";
      print "Please check there and remove them manually.\n";
    } else {
      unlink ("$tmplatexnam.tex", "$tmplatexnam.pdf");
      for my $epsf ( @epsfiles ) {
	$tmpepsf = $tmplatexdir . "/" . $epsf;
	print $tmpepsf . "\n" if ( $global->{debug} );
	unlink ("$tmpepsf");
      }
      rmdir ($tmplatexdir) || return -1;
542
    }
543 544
    return 0;
  }
545

546 547
  # convert dvi into ps using dvips command
  chdir ($tmplatexdir);
548 549 550 551 552 553 554
  if ($latex2e->{dvips} eq "dvi2ps") {
    `dvi2ps -q -o $global->{papersize} -c $tmplatexnam.ps $filename.dvi`;
  } elsif ($latex2e->{dvips} eq "jdvi2kps") {
    `jdvi2kps -q -pa $global->{papersize} -o $tmplatexnam.ps $filename.dvi`;
  } else {
    `dvips -R -q -t $global->{papersize} -o $tmplatexnam.ps $filename.dvi`;
  }
555 556 557

  chdir ($current_dir);

558 559 560 561 562 563
  # comment out, because this backup action is not documented yet.
  #
  #   if ( -e "$filename.ps" )
  #    {
  #      rename ("$filename.ps", "$filename.ps.back");
  #    }
564 565 566
  umask $saved_umask;
  copy ("$tmplatexnam.ps", "$filename.ps");
  unlink ("$tmplatexnam.ps");
567 568 569 570 571 572 573 574 575
  if ( $global->{debug} ) {
    print "Temporary files are in $tmplatexdir\n";
    print "Please check there and remove them manually.\n";
  } else {
    unlink ("$tmplatexnam.tex", "$tmplatexnam.dvi", "$tmplatexnam.ps");
    for my $epsf ( @epsfiles ) {
      $tmpepsf = $tmplatexdir . "/" . $epsf;
      print $tmpepsf . "\n" if ( $global->{debug} );
      unlink ("$tmpepsf");
576
    }
577 578
    rmdir ($tmplatexdir) || return -1;
  }
579 580 581 582 583
  return 0;

};

1;