1#! /usr/bin/perl -w 2# $Id: texexpand.pin,v 1.12 2004/01/02 08:08:34 RRM Exp $ 3# 4# texexpand for LaTeX2HTML v2K 5 6# Based on texexpand by Robert Thau, MIT AI lab, including modifications by 7# Franz Vojik <vojik@de.tu-muenchen.informatik> 8# Nikos Drakos <nikos@cbl.leeds.ac.uk> 9# Sebastian Rahtz <spqr@uk.ac.tex.ftp> 10# Maximilian Ott <max@com.nec.nj.ccrl> 11# Martin Boyer 12# Herbert Swan 13# Jens Lippmann 14 15# Recognizes \documentclass, \documentstyle, \usepackage, \RequirePackage, 16# \begin{verbatim}...\end{verbatim}, %begin{latexonly}...%end{latexonly}, 17# \begin{latexonly}...\end{latexonly}, \input, \include, \verb, \latex 18# \endinput, \end{document} 19# \includecomment, \excludecomment 20# \begin{"to exclude"}, \end{"to exclude"} 21# %begin{"to exclude"}, %end{"to exclude"} 22 23############################################################################### 24# Notes: 25# 26# General translation mechanism: 27# 28# 29# The main program latex2html calls texexpand with the document name 30# in order to expand some of its \input and \include statements, here 31# also called 'merging', and to write a list of sensitized style, class, 32# input, or include file names. 33# When texexpand has finished, all is contained in one file, TMP_foo. 34# (assumed foo.tex is the name of the document to translate). 35# 36# In this version, texexpand cares for following environments 37# that may span include files / section boundaries: 38# a) \begin{comment} 39# b) %begin{comment} 40# c) \begin{any} introduced with \excludecomment 41# d) %begin{any} 42# e) \begin{verbatim} 43# f) \begin{latexonly} 44# g) %begin{latexonly} 45# 46# a)-d) cause texexpand to drop its contents, it will not show up in the 47# output file. You can use this to 'comment out' a bunch of files, say. 48# 49# e)-g) prevent texexpand from expanding input files, but the environment 50# content goes fully into the output file. 51# 52# Together with each merging of \input etc. there are so-called %%%texexpand 53# markers accompanying the boundary. 54# 55# When latex2html reads in the output file, it uses these markers to write 56# each part to a separate file, and process them further. 57# 58# 59# 60# Detailed technical notes: 61# 62# 1. %begin{latexonly} and %end{latexonly} have to be on a separate line. 63# Anything between these tags (including the tags) is discarded. 64# 2. \begin{latexonly} and \end{latexonly} have to be on a separate line. 65# Anything between these tags (including the tags) is not expanded. 66# 3. [%\]begin{"to exclude"} and [%\]end{"to exclude"} have to be on a 67# separate line. 68# Anything between these tags (including the tags) is discarded. 69# 4. \begin{verbatim/verbatim*} and \end{verbatim/verbatim*} have to be 70# on a separate line. 71# Anything between these tags (including the tags) is not expanded. 72# 5. The scope of any such tags may extend over several files. 73# The opening tag for latexonly may occur on a different include level 74# than the closing tag. 75# The opening tag for verbatim/"to exclude" must occur within the same 76# file than the closing tag. 77# 6. Warnings are printed when the document has been parsed and open 78# tags remain. 79# 7. When in a "to exclude"/verbatim environment, texexpand won't recognize 80# ANY command except the corresponding closing tag. 81# There cannot be any nested constructions. 82# This behaviour is identical to that of LaTeX. 83# 8. \begin{latexonly},\end{latexonly} may be nested, whereas 84# %begin{latexonly},%end{latexonly} may not be nested. 85# 9. A "%" tag cannot close a "\" tag, and vice versa. 86# 10. Every \document(class|style), \usepackage, \input and \include command 87# has to be on a separate line. 88# 11. Everything behind a `%' that isn't preceded by a `\' is regarded as 89# a comment, i.e. it is printed but not interpreted. 90# 12. If any command listed in 10. is preceded by an occurence of `\verb' or 91# `\latex' then it is NOT interpreted. This crashes on lines like this: 92# blah blah \verb+foo foo+ \input{bar} % bar won't be loaded! 93# 13. Packages provided via \usepackage are handled the same way as 94# `options' in \document(class|style), i.e. they are included when 95# -auto_exclude is off, the package isn't in @dont_include *OR* the 96# package is in @do_include (new). They are added to the style file 97# together with their options if the file itself hasn't been merged. 98# \documentclass[options]{class} searches for every option.clo, 99# \documentstyle[options]{style} searches for every option.sty. 100# \usepackage[options]{packages} searches for every package.sty. 101# 14. Each texinputs directory is searched for input files/styles. If it 102# ends in `//', the whole subdirectory tree is searched. 103# 15. \input / \include merge the given file (if found under the given 104# name or with .tex extension) if its basename is in @do_include or if it 105# isn't in @dont_include or if the given filename doesn't end in 106# .sty/.clo/.cls when -auto_exclude is set. 107# 108############################################################################### 109# History: 110# mro = Marek Rouchal <marek@saftsack.fs.uni-bayreuth.de> 111# jcl = Jens Lippmann <lippmann@rbg.informatik.tu-darmstadt.de> 112# 113# $Log: texexpand.pin,v $ 114# Revision 1.12 2004/01/02 08:08:34 RRM 115# -- include support for -out <outfile> switch to avoid incompatibility 116# when POSIXLY_CORRECT is set. 117# Thanks to Juhapekka Tolvanen <juhtolv@iki.fi> for the problem report. 118# 119# Revision 1.11 2000/08/23 04:09:05 RRM 120# -- fixed typo using $latexonlyenv instead of $latexonlytype 121# -- keep $mute=0 for fake-env inside $latexonly envs. 122# -- use \n instead of ',' as delimiter for STYLES lising, 123# with LaTeX-2e documents, starting with \documentclass 124# 125# Revision 1.10 1999/11/03 11:29:50 RRM 126# -- recoded $ignore_cmd_rx , thanks Achim Haertel for reporting problem 127# 128# Revision 1.9 1999/10/06 22:04:13 MRO 129# 130# -- texexpand: latex2html calls texexpand with the -out option instead of 131# output redirection: this is safer on non-UNIX platforms 132# -- pstoimg: now there's no default cropping (useful for standalone 133# conversions). latex2html was changes appropriately 134# -- minor cleanups in latex2html script and documentation 135# 136# Revision 1.8 1999/10/03 18:40:42 MRO 137# 138# -- some cleanups for beta2 139# -- "make check" now checks all Perl code 140# 141# Revision 1.7 1999/09/16 11:27:01 RRM 142# -- $keepcomments environments do not need to start at the beginning 143# of the line 144# -- %begin{latexonly} and $fakeenv environments are now correctly 145# handled inside $keepcomments environments. 146# 147# Revision 1.6 1999/06/24 07:28:59 MRO 148# 149# 150# -- removed L2HMODULE 151# -- fixed processing of -info switch 152# -- changed option order for dvips on win32 (thanks JCL) 153# -- bumped version to 99.2a8 154# 155# Revision 1.5 1999/06/10 23:00:00 MRO 156# 157# 158# -- fixed an artifact in the *ball icons 159# -- cleanups 160# -- option documentation added 161# -- fixed bug in color perl (determining path to rgb/crayola) 162# 163# Revision 1.4 1999/06/02 12:11:23 RRM 164# -- the option 'style_file' should be 'save_styles' ; fixed. 165# -- extended $ignore_cmd_rx to ignore \input commands that are contained 166# within conditional TeX code; (e.g. in macro definitions) 167# -- ignore \usepackage commands in brackets; e.g. [\usepackage] 168# 169# Revision 1.3 1999/05/31 07:49:04 MRO 170# 171# 172# - a lot of cleanups wrt. OS/2 173# - make test now available (TEST.BAT on Win32, TEST.CMD on OS/2) 174# - re-inserted L2HCONFIG environment 175# - added some new subs to L2hos (path2os, path2URL, Cwd) 176# 177# Revision 1.2 1999/05/17 21:31:00 MRO 178# 179# 180# -- make texexpand warning-free and start making it use strict 181# compliant 182# 183# Revision 1.1 1999/05/11 06:10:02 MRO 184# 185# 186# - merged config stuff, did first tries on Linux. Simple document 187# passes! More test required, have to ger rid of Warnings in texexpand 188# 189# Revision 1.30 1999/04/09 18:09:21 JCL 190# changed my e-Mail address 191# 192# Revision 1.29 1998/12/02 07:23:35 RRM 193# -- closedir(SUBDIR) instead of close(SUBDIR) ; thanks Marek Bukowy 194# else can run out of filehandles 195# 196# Revision 1.28 1998/08/14 09:35:21 RRM 197# -- allow the arguments and options to \documentclass (style) 198# and \usepackage commands to extend over several lines 199# 200# Revision 1.27 1998/07/03 11:44:54 RRM 201# -- ignore $keepcomments environments when $latexonly 202# 203# Revision 1.26 1998/06/26 08:16:46 RRM 204# -- quoted $dd for the sake of Win95 and DOS 205# 206# Revision 1.25 1998/05/14 13:34:11 latex2html 207# texexpand for V98.2 208# 209# -- reordered some of the early code to use the $TEXINPUTS variable 210# rather than $ENV{'TEXINPUTS'} 211# -- LaTeX2HTML passes its value via the command-line 212# -- Web2C should *not* be used 213# -- there is no searching along paths for TeX, just for LaTeX2HTML 214# 215# Revision 1.24 1998/05/09 05:34:13 latex2html 216# -- removed local customisation, sorry 217# -- removed the old/commented call to use Override.pm 218# 219# Revision 1.23 1998/05/09 05:29:54 latex2html 220# -- cosmetic changes to $debug messages 221# -- removed duplicated path-searching 222# -- fixed error whereby full path-names got lost 223# -- experimented with the Web2C options 224# Are these actually useful ? 225# 226# Revision 1.22 1998/04/28 11:53:08 latex2html 227# implemented Fabrice Popineau's changes for Win32 compatibility 228# 229# -- more functions defined in Override.pm 230# -- checks for kpsewhich and Web2C 231# 232# Revision 1.21 1998/02/19 22:26:49 latex2html 233# th-darmstadt -> tu-darmstadt 234# 235# Revision 1.20 1997/12/04 07:35:25 RRM 236# -- include a use lib command, to find the Override.pm module 237# -- generalised pattern for matching verbatim-like environments 238# 239# Revision 1.19 1997/11/05 11:31:27 RRM 240# -- changed the way Override.pm is called; this should work better. 241# 242# Revision 1.18 1997/10/14 16:28:16 JCL 243# o added command line option -unsegment and $UNSEGMENT 244# Use latex2html -unsegment, or texexpand -unsegment, or set $UNSEGMENT to 1 245# in latex2html.config. 246# 247# Revision 1.17 1997/10/10 10:40:07 RRM 248# -- Oops, didn't quite get that right last time. 249# 250# Revision 1.15 1997/10/09 07:11:14 RRM 251# -- temporary fix to the Override problem 252# 253# Revision 1.14 1997/10/06 16:02:29 UW 254# override.pm contains now unlink() too. Adapted the call to override.pm 255# accordingly 256# 257# Revision 1.13 1997/10/06 14:49:37 UW 258# Added support for override.pm to texepand. 259# Furthermore, all references to the path-delimiter ':' 260# should now be made via $envkey 261# Texepand used previously the variable $DS as directory delimiter. Since 262# all other modules use $dd, I changed $DS to $dd. 263# 264# Revision 1.12 1997/09/27 10:36:14 JCL 265# o several enhancements to the inline documentation 266# o small fix to &interprete, \input|include now doesn't loose the comment 267# if merging fails 268# o introduced -no_segments switch (or set shell variable $NO_SEGMENTS to 1): 269# This will force a segmented document to expand its segment files, so 270# that it may be processed as a whole with LaTeX2HTML. 271# Use this feature to test a segmented document or whenever a document 272# needs to be fully expanded. 273# XtractFAQ will need this feature to determine the FAQ entries. 274# 275# Revision 1.11 1997/06/15 18:26:00 JCL 276# Now texexpand will only merge files that exist *and* are readable. 277# (Trying to merge a void link caused it to crash on my site.) 278# 279# Revision 1.10 1997/06/06 14:13:54 RRM 280# This is the texexpand for V97.1. 281# 282# only dofference is that it is quieter under -debug . 283# use -verbosity <num> as well, to get all the previous messages, 284# when <num> is at least 2. 285# 286# Revision 1.9 1997/03/24 12:26:15 RRM 287# Implemented a new class of environments: $keepcomments . 288# This allows environments of TeX-like code to be preserved verbatim, 289# and passed to LaTeX for processing: e.g. picture, makeimage, xy etc. 290# Also, fixed the bug which loses any code on the same line as, but preceding 291# an \input or \include command. 292# 293# Revision 1.8 1997/03/03 20:35:42 JCL 294# added some comments 295# 296# Revision 1.7 1996/12/21 20:30:00 JCL 297# - small changes to get verbatim parsed separately from verbatim* 298# - provided expand test for regression suite 299# - bound diagnostic status messages to debug level 300# 301# texexpand is operational 302# 303# Revision 1.6 1996/12/20 20:27:08 JCL 304# fixed severe bug with my $DS variable :-[ 305# 306# Revision 1.5 1996/12/20 18:51:54 JCL 307# *** empty log message *** 308# 309# Revision 1.4 1996/12/20 01:29:39 JCL 310# Moved initialisation tokens for @dont_include to latex2html.config, 311# to have a more central place to control them. 312# 313# Revision 1.3 1996/12/18 04:36:58 JCL 314# substantial changes to allow for environments grouping several files 315# o chunked code into more functions 316# o revised documentation 317# o designed new parsing logic 318# o introduced parsing of \includecomment, \excludecomment to care 319# for self-defined comment environments 320# o handles default "comment" environment as known from html.sty 321# o and much more (see comments) 322# 323# 324# V96.2a6 Fixed bug in recursive directory search for texinputs. Thanks to 325# Marcus Harnisch <harnisch@hhi.de> for reporting the bug. 326# Included possibility of adding extensions to $TEXE_DONT_INCLUDE 327# e.g. '.psfig', so that all files ending in .psfig won't be 328# \input or \include 'ed. Same for $TEXE_DO_INCLUDE. Added `o' 329# option to some regexps. 330# ------- 331# V96.2a5 Followed suggestions by Jens Lippmann regarding file inclusion 332# logic. Added \RequirePackage. Some minor changes. 333# ------- 334# V96.2a4 Fixed severe bugs in comments regexp and usepackage logic. 335# Thanks to Ross Moore <roos@mpce.mq.edu.au> for reporting them. 336# Added support for LaTeX2e .clo filename extension (see 7. above) 337# Cleaned up some code, added more comments 338# Added command line option -do_include 339# ------- 340# V96.2a3 Fixed bugs & typos 341# ------- 342# V96.2a2 Following suggestions made by 343# Jens Lippmann <lippmann@rbg.Informatik.TH-Darmstadt.DE> 344# Added recursive directory search for include files. 345# Added @do_include: Forces inclusion of packages (when found) 346# Some bug fixes 347# ------- 348# V96.2a1 released Thu Oct 24 16:51:36 MET 1996 349# ------- 350# 21-NOV-96 mro 351# Almost complete rewrite by Marek Rouchal <marek@saftsack.fs.uni-bayreuth.de> 352# 353############################################################################### 354 355use vars qw($LATEX2HTMLDIR $SCRIPT); 356 357BEGIN { 358 # print STDERR "scanning for l2hdir\n"; 359 if($ENV{LATEX2HTMLDIR}) { 360 $LATEX2HTMLDIR = $ENV{LATEX2HTMLDIR}; 361 } else { 362 $ENV{LATEX2HTMLDIR} = $LATEX2HTMLDIR = '/home/bsbuild/dev/org-release/bacula-docs-11.0.5/latex2html'; 363 } 364 365 if(-d $LATEX2HTMLDIR) { 366 push(@INC,$LATEX2HTMLDIR); 367 } else { 368 die qq{Fatal: Directory "$LATEX2HTMLDIR" does not exist.\n}; 369 } 370} 371 372use L2hos; 373 374my $RELEASE = '2016'; 375my ($VERSION) = q$Revision: 1.12 $ =~ /:\s*(\S+)/; 376 377my $envkey = L2hos->pathd(); 378 379# $dd is the directory delimiter character 380my $dd = L2hos->dd(); 381 382my $prompt = "\ntexexpand:"; 383 384# Initialize styles to be excluded (if any). 385# This is a sanity setup in case the \d is garbled during shell 386# variable handling. 387# The initialisation really comes from latex2html.config. 388my @dont_include = ('\d+pt'); 389 390# These are the extensions to be auto-excluded 391my $dont_include_ext_rx = 'sty|cls|clo'; 392 393if($ENV{'TEXE_DONT_INCLUDE'}) { 394 &process_dont_include(split(/$envkey/,$ENV{'TEXE_DONT_INCLUDE'})); 395} 396 397# Initialize styles to be included (if any). This overrides @dont_include 398# These are the extensions to be auto-included 399my $do_include_ext_rx = ''; 400 401if($ENV{'TEXE_DO_INCLUDE'}) { 402 &process_do_include(split(/$envkey/,$ENV{'TEXE_DO_INCLUDE'})); 403} 404 405# Parse arguments 406use Getopt::Long; 407my %opt = (); 408unless(GetOptions(\%opt, qw(-help -version -debug -verbose -w 409 -do_include=s@ -dont_include=s@ -auto_exclude -unsegment 410 -save_styles=s -texinputs=s@ -output=s -out=s))) { 411 die "$prompt Error: Invalid option(s) specified.\n"; 412} 413 414if($opt{help}) { 415 print STDERR "-- to be implemented --\n"; 416 exit 0; 417} 418&banner(); 419if($opt{version}) { 420 exit 0; 421} 422 423my $debug = $opt{debug} || 0; # no debug by default 424$debug = 2 if($opt{verbose}); 425 426if($opt{dont_include} && @{$opt{dont_include}}) { 427 &process_dont_include(@{$opt{dont_include}}); 428} 429if($opt{do_include} && @{$opt{do_include}}) { 430 &process_do_include(@{$opt{do_include}}); 431} 432 433my $TEXINPUTS = ''; 434if(@{$opt{texinputs}}) { 435 $TEXINPUTS = join($envkey, @{$opt{texinputs}}); 436} 437 438unless(@ARGV) { 439 die "$prompt Error: No input file specified.\n"; 440} 441my $infile = shift(@ARGV); 442if(@ARGV) { 443 die "$prompt Error: More than one input file specified.\n"; 444} 445 446#FP: Web2C does not use @texinputs at all 447# moreover, it uses kpsewhich to find files, so no need to 448# bother with @texinputs 449 # $Web2C = &find_executable('kpsewhich',$ENV{'PATH'}); 450 451#RRM: I don't think it is a good idea to use kpsewhich this way 452my $Web2C = ''; 453 454# Initialize texinputs 455my @texinputs = qw(.); 456if($TEXINPUTS) { 457 my $dir; 458 foreach $dir (split(/$envkey/, $TEXINPUTS)) { 459 push (@texinputs, $dir) 460 if(($dir =~ /\S+/) && ($dir ne '.')); # save only if non-empty 461 } 462} 463 464## Ignore the environment 465# if((!$TEXINPUTS)&&(defined $ENV{'TEXINPUTS'})) { 466# foreach $dir (split(/$envkey/,$ENV{'TEXINPUTS'})) { 467# push (@texinputs, $dir) 468# if (($dir =~ /\S+/)&&($dir ne '.')); # save only if non-empty 469# } 470# } 471 472 473## Expand paths with `~' 474# $homeDir = (getpwuid($<))[7]; 475# grep(s|^~$dd|$homeDir$dd|, @texinputs); 476# grep((m|^~([^$dd]+)$dd|) && 477# ($homeDir = (getpwnam($1))[7]) && (s||$homeDir$dd|), @texinputs); 478 479&initialise; 480&main; 481exit(0); 482 483sub banner { 484 print STDERR "texexpand V$RELEASE (Revision $VERSION)\n"; 485} 486 487sub initialise { 488# Create generic regexp's: 489# If this matches before a command, the command is ignored. 490 $ignore_cmd_rx = 491# '(\\latex\W|\\verb|\\expandafter|\\ifx|\\else\W|[\|\[\@]$)'; 492 "(\\\\latex\\W|\\\\verb|\\\\expandafter|\\\\ifx|\\\\else\\W|[\\|\\[\\@]\$)"; 493# This matches a square bracket pair (typically an option list). 494 $options_rx = '(\[[^\]]*\]|)'; 495# This matches a single argument. 496 $arg_rx = '\{([^\}]*)\}'; 497 $fakeenv_rx = '(comment)'; 498 $keepcomments_rx = '(picture|makeimage|xy|diagram)'; 499 500# Print environments 501 my $dir; 502 if ($debug) { 503 print STDERR "$prompt LaTeX2HTML inputs are in:"; 504# foreach $dir (@texinputs) { print STDERR "$prompt $dir"; } 505 if ($Web2C) { 506 print STDERR "$prompt " . `kpsewhich -expand-var \$TEXINPUTS` ; 507#RRM: I cannot make this work, to replace the `...` in the line above 508# local($kpse) = "kpsewhich -expand-var=\$TEXINPUTS"; 509# print STDERR "$prompt $kpse"; 510# $kpse = system($kpse); 511# print STDERR "$prompt $kpse"; 512 } else { 513 foreach $dir (@texinputs) { print STDERR "$prompt $dir"; } 514 } 515 516 if ($debug>1) { 517 print STDERR "\n$prompt Special names (not to be input or included):"; 518 foreach $name (@dont_include) { print STDERR "$prompt $name"; } 519 print STDERR "\n$prompt Extensions of files not to be input or included: " 520 . "$dont_include_ext_rx"; 521 522 print STDERR "\n$prompt Special names (to *be* input or included):"; 523 foreach $name (@do_include) { print STDERR "$prompt $name"; } 524 print STDERR "\n$prompt Extensions of files to *be* input or included: " 525 . "$do_include_ext_rx\n"; 526 } 527 } 528 print STDERR "\n$prompt %--- Expanding $infile" if ($debug>1); 529} 530 531 532sub main { 533# Note that verbatim/latexonly may split over different files! 534# $verbatim is 1 if inside a verbatim environment, 535# $latexonly is > 0 if inside latexonly environments 536# $includelevel indicates the depth of include/input 537 local($includelevel) = 0; 538 local($verbatim,$verbatimname) = (0,""); 539 local($latexonly,$latexonlytype) = (0,""); 540 local($fakeenv,$fakeenvname,$fakeenvtype) = (0,"",""); 541 local($keepcomments,$keepcommentsname) = (0,""); 542 local($active,$mute) = (1,0); 543 544# Main procedure 545 $dont_include_rx = join("|",@dont_include); 546 $do_include_rx = join("|",@do_include); 547 548 if($opt{save_styles}) { 549 open(STYLES,">$opt{save_styles}") 550 || die "$prompt Error: Cannot open style file '$opt{save_styles}': $!\n"; 551 } 552 my $out_file = $opt{output}||$opt{out}; 553 if($out_file) { 554 open(OUT,">$out_file") 555 || die "$prompt Error: Cannot open output file '$out_file': $!\n"; 556 } 557 else { 558 open(OUT,">&STDOUT"); 559 } 560 561 &process_file($infile); # the workhorse... 562 563 close(OUT) if $out_file; 564 close(STYLES) if ($opt{save_styles}); 565 566 print STDERR "$prompt Warning: No ${latexonlytype}end\{latexonly\} found." 567 if ($latexonly); 568 print STDERR "$prompt Warning: No ${fakeenvtype}end\{$fakeenvname\} found." 569 if ($fakeenv); 570 print STDERR "$prompt Warning: No \\end\{$keepcommentsname\} found." 571 if ($keepcomments); 572 print STDERR "$prompt Warning: No \\end{verbatim} found." 573 if ($verbatim); 574} 575 576 577# Include and parse a file. 578# This routine is recursive, see also &process_input_include_file, 579# &process_document_header, and &process_package_cmd. 580# 581# Two global flags control the states of texexpand. 582# o $active is true if we should interprete the lines to expand 583# files, check for packages, etc. 584# o $mute is true if we should prevent the lines from going 585# into the out file. 586# 587# We have three general states of texexpand: 588# 1) interprete the lines and pass them to the out file 589# This is the normal case. 590# Corresponding: $active true, $mute false 591# 2) interprete minimal and suppress them 592# This is when parsing inside a comment environment, which 593# also would retain its body from LaTeX. 594# => $active false, $mute true 595# 3) interprete minimal and pass the lines to the out file 596# This is inside a verbatim or latexonly environment. 597# The line of course must be at least interpreted to 598# determine the closing tag. 599# => $active false, $mute false 600# 601# Any environment may extend over several include files. 602# Any environement except verbatim and latexonly may have its 603# opening or closing tag on different input levels. 604# The comment and verbatim environments cannot be nested, as 605# is with LaTeX. 606# We must at least parse verbatim/comment environments in 607# latexonly environments, to catch fake latexonly tags. 608# 609# The work scheme: 610# Five functions influence texexpand's behavior. 611# o &process_file opens the given file and parses the non-comment part in 612# order to set $active and $mute (see above). 613# It calls &interprete to interprete the non-comment content and either 614# continues with the next line of its file or terminates if &interprete 615# detected the \end{document} or an \endinput. 616# o &interprete handles some LaTeX tags with respect to the three states 617# controlled by $active and $mute. 618# Regarding to \input|include, \document(class|style), and 619# \(use|Require)package the functions &process_input_include_file, 620# &process_document_header, and &process_package_cmd are called respectively. 621# o These three functions check if the file name or option files are enabled 622# or disabled for merging (via TEXE_DO_INCLUDE or TEXE_DONT_INCLUDE). 623# Any file that is to include will be 'merged' into the current file, i.e. 624# the function &process_file is called at this place in time (recursively). 625# This will stop interpretation at the current line in file, start with the 626# new file to process and continues with the next line as soon as the new 627# file is interpreted to its end. 628# 629# The call tree (noweb+xy.sty would be handy here): 630# 631# main 632# | 633# v 634# +->process_file 635# | | 636# | v 637# | interprete (with respect to the current line, one of that three) 638# | | | | 639# | v v v 640# | process_input_include_file process_document_header process_package_cmd 641# | | | | 642# | v v v 643# +----+---------------------------+------------------------+ 644# 645# Bugs: 646# o Since the latexonly environment is not parsed, its contents 647# might introduce environments which are not recognized. 648# o The closing tag for latexonly is not found if hidden inside 649# an input file. 650# o One environment tag per line, yet! 651# o If I would have to design test cases for this beast I would 652# immediately desintegrate into a logic cloud. 653# 654# Notes: 655# o Ok, I designed test cases for it. 656# Please refer to test 'expand' of the regression test suite 657# in the developers' module of the l2h repository. 658# o -unsegment feature: 659# In this (rare) case, the user wants to translate a segmented document 660# not in segments but in a whole (for testing, say). 661# We enable this by recognizing the \segment command in &interprete, 662# causing the segment file to be treated like \input but loosing the first 663# lines prior to \startdocument (incl.), as controlled via $segmentfile. 664# On how to segment a document you are best guided by section 665# ``Document Segmentation'' of the LaTeX2HTML manual. 666# 667sub process_file { 668 my ($infile) = @_; 669 local(*IN); 670 local($comments,$before,$orig); 671 672 673 # Keep track of input/include level 674 $includelevel++; 675 676 open(IN,"<$infile") || die "$prompt Cannot open $infile\n"; 677 print STDERR "$prompt %--- Processing $infile" if ($debug > 1); 678 679 # if we don't include this file marker LaTeX2HTML won't split 680 # the document at this point 681 print OUT "%%% TEXEXPAND: INCLUDED FILE MARKER $infile\n" 682 if ($includelevel > 1 && $active); 683 684 if ($segmentfile) { 685 # This variable is set by &interprete to change the behavior of the 686 # next file to merge. 687 while(<IN>) { 688 # strip comments 689 s/(^|[^\\])(\\\\)*(%.*)/$comments = $3; $1.$2/e; 690 last if /^\s*\\startdocument/; 691 } 692 $segmentfile = 0; 693 } 694 695 while(<IN>) { 696 697 #for debugging 698 $orig = $_; 699 700 # lift comments from line 701 $comments = ""; 702 if ($keepcomments) { $comments = '' } 703 else { 704 s/(^|[^\\])((?:\\\\)*)(%.*)/$comments = $3; $1.$2/e 705 } 706 707 # Deal with latexonly environment(s) 708 # begin/end tags must be on single line 709 if (!$fakeenv && !$verbatim && !$latexonly && ( 710 ($comments =~ /%\s*begin\s*\{\s*latexonly\s*\}/)|| 711 ($keepcomments && /%\s*begin\s*\{\s*latexonly\s*\}/))) { 712 713 # A comment latexonly environment. May not be nested. 714 $latexonly = 1; 715 $latexonlytype = "%"; 716 $active = 0; 717 $mute=1; 718 } 719 elsif (!$fakeenv && !$verbatim && 720 (!$latexonly || $latexonlytype eq "\\") && 721 /^\s*\\begin\s*\{\s*latexonly\s*\}/) { 722 723 # A latexonly environment. LaTeX types may be nested, 724 # but discard them as long as we are in a latexonly 725 # comment part. 726 # We definitely don't like to push the "\\", "%" types 727 # onto a stack to keep track of them in alternating types. 728 # On the other hand we won't allow for a comment type 729 # part to close a LaTeX environment, eg. 730 $latexonly++; 731 $latexonlytype = "\\"; 732 $active = 0; 733 } 734 elsif (!$fakeenv && !$verbatim && ( 735 ($comments =~ /%\s*begin\s*\{\s*$fakeenv_rx\s*\}/)|| 736 ($keepcomments && /%\s*begin\s*\{\s*$fakeenv_rx\s*\}/))) { 737 # Begin of a fake comment part. May not be nested. 738 $fakeenv=1; 739 $fakeenvtype="%"; 740 # Remember the part name. 741 $fakeenvname = $1; 742 $active=0; 743 $mute=1 unless $latexonly; 744 } 745 elsif (!$fakeenv && !$verbatim && /^\s*\\begin\s*\{\s*$fakeenv_rx\s*\}/) { 746 # Begin of a fake environment. May not be nested. 747 $fakeenv="1"; 748 $fakeenvtype="\\"; 749 # Remember the environment name. 750 $fakeenvname = $1; 751 $active=0; 752 $mute=1 unless $latexonly; 753 } 754 elsif (!$fakeenv && !$verbatim && !$latexonly && 755 /^\s*\\begin\s*\{\s*$keepcomments_rx\s*\}/) { 756 # Begin of a keepcomments environment. May be nested. 757 if (! $keepcomments) { 758 $keepcomments = 1; 759 # Remember the environment name. 760 $keepcommentsname = $1; 761 } elsif ($keepcommentsname eq $1) { 762 $keepcomments++; 763 } 764 $active=1; 765 $mute=1 unless $latexonly; 766 } 767# elsif (!$fakeenv && !$verbatim && /\\begin\s*\{\s*verbatim(\*)?\s*\}/) { 768 elsif (!$fakeenv && !$verbatim && /\\begin\s*\{\s*(\w*[Vv]erbatim\w*\*?)\s*\}/) { 769 ($before,$verbatimname) = ($`,$1); 770 ($active,$verbatim) = (0,1) 771 unless ($before =~ /$ignore_cmd_rx/o); 772 } 773 774 print STDERR "$prompt %--line::${orig}%-- active=$active mute=$mute ". 775 "latexonly=$latexonly fakeenv=$fakeenv verbatim=$verbatim ". 776 "keepcomments=$keepcomments" 777 if ($debug > 1) && $orig =~ /\\begin|%\s*begin/; 778 779 # Interprete the single line, care for file to merge, 780 # locate new comment environments, etc. 781 # This one does recursive calls. 782 # Stop this file if we are told so. 783 last 784 unless &interprete($_, $comments); 785 786 last if $end_document; 787 788 # Sorry for that ifs... 789 if (!$fakeenv && !$verbatim && $latexonly && $latexonlytype eq "%" && ( 790 ($comments =~ /%\s*end\s*\{\s*latexonly\s*\}/)|| 791 ($keepcomments && /%\s*end\s*\{\s*latexonly\s*\}/))) { 792 793 # only %end{latexonly} can close the part 794 $latexonly=0; 795 $active = 1; 796 $mute = 0; 797 } 798 elsif (!$fakeenv && !$verbatim && $latexonly && $latexonlytype eq "\\" && 799 /^\s*\\end\s*\{\s*latexonly\s*\}/) { 800 801 # only \end{latexonly} can close the environment 802 $latexonly--; 803 $active = ($latexonly ? 0 : 1); 804 } 805 elsif ($fakeenv && $fakeenvtype eq "%" && ( 806 ($comments =~ /%\s*end\s*\{\s*$fakeenv_rx\s*\}/)|| 807 ($keepcomments && /%\s*end\s*\{\s*$fakeenv_rx\s*\}/))) { 808 809 # only a matching %end{name} can close the part 810 if ($1 eq $fakeenvname) { 811 $fakeenv=0; 812 $active = ($latexonly ? 0 : 1); 813 $mute=0 814 unless $latexonly && $latexonlytype eq "%"; 815 } 816 } 817 elsif ($fakeenv && $fakeenvtype eq "\\" && 818 /^\s*\\end\s*\{\s*$fakeenv_rx\s*\}/) { 819 820 # only a matching \end{name} can close the environment 821 if ($1 eq $fakeenvname) { 822 $fakeenv=0; 823 $active = ($latexonly ? 0 : 1); 824 $mute=0 unless $latexonly; 825 } 826 } 827 elsif ($keepcomments && 828 /^[^%]*?\\end\s*\{\s*$keepcomments_rx\s*\}/) { 829 830 # only a matching \end{name} can close the part 831 if ($1 eq $keepcommentsname) { 832 $keepcomments--; 833 $keepcommentsname = '' unless ($keepcomments); 834 $active = ($latexonly ? 0 : 1); 835 $mute=0 836 unless $latexonly && $latexonlytype eq "%"; 837 } 838 } 839# elsif ( /\\end\s*\{\s*verbatim(\*)?\s*\}/) { 840 elsif ( /\\end\s*\{\s*(\w*[Vv]erbatim\w*\*?)\s*\}/) { 841 if ($1 eq $verbatimname) { 842 $verbatim=0; 843 $active = ($latexonly ? 0 : 1); 844 } 845 } 846 print STDERR "$prompt %--line::${orig}%-- active=$active mute=$mute ". 847 "latexonly=$latexonly fakeenv=$fakeenv verbatim=$verbatim" 848 if ($debug > 1) && $orig =~ /\\end|%\s*end/; 849 850 } 851 print OUT "%%% TEXEXPAND: END FILE $infile\n" 852 if ($includelevel > 1 && $active); 853 close(IN); 854 $includelevel--; 855} 856 857 858# Handle the LaTeX tags \input, \include, \endinput, \documentclass, 859# \documentstyle, \usepackage, \RequirePackage, \end{document}, 860# \includecomment, \excludecomment with respect to the three states 861# controlled by $active and $mute. 862# The state 'interprete minimal and suppress' ($active false, $mute true) 863# does not require further actions, just do nothing. 864# When in $active state, call one of &process_input_include_file, 865# &process_document_header, or &process_package_cmd to examine the 866# apropriate line further. 867# 868# Returns 0 if the caller is to stop interpreting the current file (\endinput). 869# Returns 1 otherwise. 870# Set $end_document to 1 if an \end{document} is detected (this stops 871# the whole task of texexpand). 872# 873sub interprete { 874 local($_,$comments) = @_; 875 local($line) = $_; 876 local($before,$after); 877 878 # the default to print to OUT 879 $line =~ s/\n/$comments\n/; 880 881 if ($active) { 882 #looses $comments on successful input/include, document header, 883 #or usepackage/RequirePackage 884 885 if (/\\(input|include)\W/) { 886 ($before,$after) = ($`,$&.$'); 887 if ($before =~ /$ignore_cmd_rx/o) { 888 print OUT $line; 889 } 890 else { 891 if (length($before)) { 892 #put prefix to \\input etc. to single line 893 print OUT $before,"\%\n"; 894 #mask special chars 895 $before =~ s/(\W)/\\$1/g; 896 #strip prefix from total line incl. comments 897 $line =~ s/$before//; 898 } 899 # print total line incl. comments if merging failed 900 print OUT $line 901 #may re-enter &process_file 902 unless &process_input_include_file($after); 903 } 904 } 905# elsif (/\\(usepackage|RequirePackage)\s*$options_rx\s*$arg_rx/s) { 906 elsif (/\\(usepackage|RequirePackage)[^]]/s) { 907 $before = $`; 908 if($before =~ /$ignore_cmd_rx/o) { 909 print OUT $line; 910 } 911 else { 912 while (!/\\(usepackage|RequirePackage)\s*$options_rx\s*$arg_rx/so) { 913 chomp; $_ =~ s/%.*$//; 914 $_ .= <IN>; 915 } 916 &process_package_cmd($_); 917 } 918 } 919# elsif (/\\document(class|style)\s*$options_rx\s*$arg_rx/o) { 920 elsif (/\\document(class|style)/o) { 921 $before = $`; 922 if ($before =~ /$ignore_cmd_rx/o) { 923 print OUT $line; 924 } 925 else { 926 while (!/\\document(class|style)\s*$options_rx\s*$arg_rx/so) { 927 chomp; $_ =~ s/%.*$//; 928 $_ .= <IN>; 929 } 930 &process_document_header($_); 931 } 932 } 933 elsif ($opt{unsegment} && /^\s*\\segment(\*?)\s*$options_rx\s*$arg_rx\s*$arg_rx\s*/) { 934 # We found a segmenting command which must vanish. 935 # Therefore, mutate the \segment into the section command specified 936 # by $4 (section, subsection, ...) and $1 (* or empty) followed by 937 # the section text, and an \input statement with filename $3. 938 # To obtain the section text, we need to take a preview to the next 939 # lines, as it might be truncated with %'s. 940 # Line truncations between the regex above (like \segment%\n) are 941 # not recognized. 942 # There are as much lines fetched as required to satisfy the equality 943 # of the amounts of left and right braces, since we aren't able to 944 # handle nested brace pairs. 945 # If this strategy fails, texexpand is terminated, thereby satisfying 946 # the 'all or nothing' requirement. 947 948 local($file) = $3; 949 print OUT "\\$4$1"; 950 $after = $_ = $'; #get tail 951 local($left,$right) = (tr/\{/\{/,tr/\}/\}/); 952 while (($left != $right) || !$left) { 953 #braces not balanced or no opening brace at all, get next line 954 $_ = <IN>; 955 die "$prompt arguments to \\segment are too complex\n" 956 unless length($_) && length($after) < 500; 957 # strip comments 958 s/(^|[^\\])(\\\\)*(%.*)/$1$2/; 959 $left += tr/\{/\{/; $right += tr/\}/\}/; 960 $after .= $_; 961 } 962 $after =~ /\}([^\}]*)$/; 963 $after = $1; 964 $_ = $`; 965 # Ok we have it. $_ should carry the whole section title plus 966 # opening brace, the original lines squeezed into one. 967 print OUT $_,"}\n"; 968 969 # set this globally to control behavior of next &process_file 970 $segmentfile = 1; 971 die "$prompt segment file <$file> could not be merged" 972 unless &process_input_include_file("\\input\{$file\}$after"); 973 } 974 # Print the first /end{document}, only. Truncate anything after it. 975 elsif (/^(.*\\end\{document\})/) { 976 $before = $1; 977 if ($before =~ /$ignore_cmd_rx/o) { 978 print OUT $line; 979 } 980 else { 981 print OUT "$before\n"; 982 $end_document++; 983 } 984 } 985 elsif (/\\endinput/) { 986 $before=$`; 987 return(0) #stop this file 988 if ($includelevel > 1 && $before !~ /$ignore_cmd_rx/o); 989 } 990 elsif (/\\(in|ex)cludecomment\s*$arg_rx/o) { 991 local($mode,$env) = ($1,$2); 992 993 $env =~ s/\s//g; #strip space 994 # escape special chars (such as "*"), but reject "|" 995 $env =~ s/(\W)/\\$1/g; 996 unless ($env =~ /\|/) { 997 $fakeenv_rx =~ /\((.*)\)/; 998 # might also be empty 999 local(@envs) = split(/\|/,$1); 1000 1001 if ($mode eq "ex") { 1002 push(@envs,$env); 1003 } 1004 else { 1005# a dumb try to forget the comment environment if redefined 1006 $env =~ s/\\/\\\\/g; 1007 #must not use $_ inside grep pattern! 1008 @envs = grep(!/$env/,@envs); 1009 } 1010 $fakeenv_rx = "\(".join("|",@envs)."\)"; 1011 } 1012 } 1013 else { 1014 print OUT $line; 1015 } 1016 } 1017 elsif (! $mute) { 1018 # print line if in verbatim/comment mode 1019 print OUT $line; 1020 } 1021 return(1); #continue if not $end_document 1022} 1023 1024 1025sub process_input_include_file { 1026 local($_) = @_; 1027 local($before,$after,$class,$styles); 1028 $_ =~ s/\n$//; 1029 1030 print STDERR "$prompt %--- Found include at level $includelevel: $_" 1031 if($debug); 1032 1033# Get filename 1034 local($filename) = ""; 1035 1036 # $class serves as temporary storage 1037 if (/(\\input|\\include)\s*$arg_rx/o) { 1038 ($before,$after,$class,$filename) = ($`, $', $&, $2); 1039 $filename =~ s/\s//g; 1040 } 1041 elsif (/(\\input|\\include)\s+(\S+)(?=\s|$)/o) { 1042 ($before,$after,$class,$filename) = ($`, $', $&, $2); 1043 $filename =~ s/\s//g; 1044 } 1045 else { 1046 print STDERR "$prompt %--- COULDN'T FIND FILENAME\n" if($debug); 1047 } 1048 1049 if ($filename) { 1050 # Get base name 1051 $styles = $filename; 1052 $styles =~ s|.*\Q$dd\E||; # strip path 1053 $styles =~ s/\.[^.]*$//; # strip extension 1054 1055 # Sorry for the next if-statement... (hmm,ok) 1056 if ($styles !~ /^($do_include_rx)$/o && 1057 $filename !~ /\.($do_include_ext_rx)$/o && 1058 ($styles =~ /^($dont_include_rx)$/o || 1059 ($opt{auto_exclude} && $filename =~ /\.($dont_include_ext_rx)$/o))) { 1060 print STDERR "$prompt %--- ignoring $filename" if($debug); 1061 print STYLES "$styles\n" if($opt{save_styles}); 1062 } 1063 else { 1064 local($fname) = &find_file($filename); 1065 1066 # notify anyway that a file is found, to allow a Perl 1067 # module loaded for this specific file 1068# print STYLES "$styles\n" if($opt{save_styles}); 1069 1070 if($fname) { 1071 print OUT "$before"; 1072 1073 # recursive call 1074 &process_file($fname); 1075 1076 print OUT $after if($after =~ /\S+/); 1077 print STDERR "$prompt %--- successfully included $filename" 1078 if($debug > 1); 1079 1080 return(1); #merge 1081 } 1082 else { 1083 print STDERR "$prompt include $filename failed. Reinserting $before command\n"; 1084 } 1085 } 1086 } 1087 return(0); #no merge 1088} 1089 1090 1091sub process_document_header { 1092 local($_) = @_; 1093 local(%style_include,@print_styles,$key,$isclass); 1094 1095 local($before, $latextype, $styles, $class, $after); 1096 if(/\\document(class|style)\s*$options_rx\s*$arg_rx/o) { 1097 ($before, $latextype, $styles, $class, $after) = 1098 ($`, $1, $2 || '', $3, $'); 1099 if ($latextype =~ /class/) { $isclass = 1; } 1100 } else { 1101 print OUT $_; 1102 return; 1103 } 1104 1105 $_ =~ s/\n$//; 1106 print STDERR "$prompt %--- Found $latextype: $_\n" if($debug); 1107 $styles =~ s/\[(.*)\]/$1/; # Strip braces 1108 $class =~ s/\s//g; # Strip spaces 1109 # the class cannot be included, so stuff it in the style file 1110 print STYLES "$class".($isclass ? '':"\n") if($opt{save_styles}); 1111 1112 foreach $key (split(/,/, $styles)) { 1113 $key =~ s/\s//g; # strip spaces 1114 push(@print_styles,$key); 1115 if (&should_include($key)) { 1116# mark the style for inclusion and search for the 1117# corresponding .clo (LaTeX2e) or .sty (LaTeX209) 1118# &find_file gives the filename or undef. 1119 $style_include{$key} = 1120 &find_file($key . (($latextype =~ /class/) ? '.clo' : '.sty')); 1121 } 1122 } 1123 $styles = ''; 1124 foreach $key (@print_styles) { 1125 if(!$style_include{$key}) { 1126# put style back into command and save it to the style file 1127 print STYLES ($isclass ? " $key," : "$key\n") if($opt{save_styles}); 1128 $styles .= ',' . $key; 1129 } 1130 } 1131 if ($styles) { 1132 $styles =~ s/^,//; 1133 $styles = '[' . $styles . ']'; 1134 } 1135 print OUT join('', $before, "\\document", $latextype, $styles, 1136 '{', $class, '}', $after); 1137 # Include styles after the \document(class|style) command 1138 foreach $key (@print_styles) { 1139 if($style_include{$key}) { 1140 &process_file($style_include{$key}); 1141 } 1142 } 1143 print STYLES "\n" if($opt{save_styles} && $isclass); 1144} 1145 1146 1147sub process_package_cmd { 1148 local($_) = @_; 1149 local(%style_include,@print_styles,$key); 1150 1151 /\\(usepackage|RequirePackage)\s*$options_rx\s*$arg_rx/o; 1152 local ($before,$class,$options,$styles,$after) = 1153 ($`, $1, $2 || '', $3, $'); 1154 1155 print STDERR "$prompt %--- Found \\$class: $_" if($debug > 1); 1156 $options =~ s/\[(.*)\]/$1/o; # strip braces 1157 1158 foreach $key (split(/,/,$styles)) { 1159 $key =~ s/\s//g; # strip spaces 1160 # Remember each package and check whether to merge it 1161 push(@print_styles,$key); 1162 if (&should_include($key)) { 1163 $style_include{$key}=&find_file($key . '.sty'); 1164 } 1165 } 1166 $styles = ''; 1167 foreach $key (@print_styles) { 1168 if (!$style_include{$key}) { 1169 # print to style file and reinsert into command 1170 # if package is not to be merged 1171 print STYLES "$key $options\n" if($opt{save_styles}); 1172 $styles .= ',' . $key; 1173 } 1174 } 1175 if($styles) { 1176 # Reconstruct command 1177 $styles =~ s/^,//; 1178 $options = '[' . $options . ']' if($options =~ /\S+/); 1179 print OUT $before . '\\' . $class . $options . 1180 '{' . $styles . '}' . $after; 1181 } 1182 else { print OUT $before . $after; } 1183 foreach $key (@print_styles) { 1184 if($style_include{$key}) { 1185 # merge style files 1186 &process_file($style_include{$key}); 1187 } 1188 } 1189} 1190 1191 1192sub process_dont_include { 1193 my @items = @_; 1194 my $item; 1195 foreach $item (@items) { 1196 if($item =~ s/^\.//) { # starts with `.'? Then it's an extension 1197 $dont_include_ext_rx .= "|\Q$item\E"; 1198 } else { 1199 push(@dont_include,$item); 1200 } 1201 } 1202 1; 1203} 1204 1205sub process_do_include { 1206 my @items = @_; 1207 my $item; 1208 foreach $item (@items) { 1209 if($item =~ s/^\.//) { # starts with `.'? Then it's an extension 1210 $do_include_ext_rx .= (($do_include_ext_rx eq '') ? '' : '|') . 1211 "\Q$item\E"; 1212 } else { 1213 push(@do_include,$item); 1214 } 1215 } 1216 1; 1217} 1218 1219# Returns true if style has to be included, i.e.: 1220# 1. The style is found in do_include *or* 1221# 2. Automatic exclusion is disabled and the style is *not* found in 1222# dont_include 1223# 1224sub should_include { 1225 my ($style) = @_; 1226 1227 return($style =~ /^($do_include_rx)$/o || 1228 (!$opt{auto_exclude} && $style !~ /^($dont_include_rx)$/o )); 1229} 1230 1231 1232sub find_file { 1233 local($file) = @_; 1234 local($fname,$dname); 1235 local($found)=0; 1236 print STDERR "$prompt %--- checking for $file" if($debug); 1237 1238# if ($file =~ m|^$dd|) { 1239 if (L2hos->is_absolute_path($file)) { 1240 $fname=$file; 1241 if(&file_or_ext) { $found=1; } 1242 } else { 1243 if ($Web2C) { 1244 $file =~ s/\s+//g; 1245 if ($file =~ s/\.([^\.]+)\Z//) { 1246 @ext = ($1); 1247 } else { 1248 @ext = ('tex', 'ltx', 'sty'); 1249 } 1250 foreach $ext (@ext) { 1251 chop($fname = `kpsewhich -format=.tex $file.$ext`); 1252#RRM: I cannot make this work, to replace the `...` in the line above 1253# $fname = &syswait("kpsewhich -format=.tex $file.$ext"); 1254# chop $fname; 1255 print STDERR "$prompt kpsewhich says : $fname" if $debug; 1256 $found = 1; 1257 last; 1258 } 1259 } else { 1260 # search input directories 1261 foreach $dir (@texinputs) { 1262 ($dname = $dir) =~ s|[\Q$dd\E]+$||; # Remove slashes at the end 1263 if (-d $dname) { 1264 if ($fname = &dir_search($dir,$file)) { 1265 $found = 1; 1266 last; 1267 } 1268 } else { 1269 print STDERR "$prompt %--- Warning: \"$dname\" is no directory" 1270 if ($debug); 1271 } 1272 } 1273 } 1274 } 1275 1276 if ($found) { 1277 print STDERR "$prompt %--- found $fname" if ($debug); 1278 return($fname); 1279 } else { 1280 print STDERR "$prompt %--- file not found" if ($debug); 1281 return(undef); 1282 } 1283} 1284 1285 1286sub dir_search { # search directory recursively 1287 local($dir,$file) = @_; 1288 local(*SUBDIR); # make file pointer local 1289 local($dname,$found,$recursive) =('',0,0); 1290 1291 if ($dir =~ m|\Q$dd$dd\E$|) { # does dir end in `//'? 1292 $recursive = 1; 1293 } 1294 $dir =~ s|[\Q$dd\E]+$||; # Remove any slashes at the end 1295 local($fname) = join ($dd, $dir, $file); 1296 1297 print STDERR "$prompt %--- looking for $fname" if($debug); 1298 # Does file exist in this directory? 1299 if (&file_or_ext) { 1300 return($fname); 1301 } 1302 elsif ($recursive) { # descend into subdirectories? 1303 # search directory for subdirectories 1304 opendir(SUBDIR,$dir); # open directory 1305 while (defined($_=readdir(SUBDIR))) { # read dir-entries 1306 next if(/^\./); # do not check dotfiles 1307 $dname = join ($dd, $dir, $_); 1308 if ((-d $dname) && ($fname = &dir_search($dname.$dd.$dd,$file))) { 1309 $found = 1; 1310 last; 1311 } 1312 } 1313 closedir(SUBDIR); 1314 if ($found) { 1315 return($fname); 1316 } 1317 } 1318 return(0); 1319} 1320 1321 1322sub file_or_ext { 1323 # Modifies $fname 1324 # if $fname exists return success otherwise 1325 # if $fname.tex exists, then bind $fname to $fname.tex and return success 1326 # else fail 1327 1328 return 1 if(!-d $fname && -r $fname); # && -s $fname; 1329 return 0 if $fname =~ /\.tex$/; 1330 $fname .= ".tex"; 1331 return 1 if -f $fname && -r $fname;# && -s $fname; 1332 return 0; 1333} 1334 1335