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