<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/perl -w
#   HTML::Latex
#   Copyright (C) 2000 Peter Thatcher

#   This program is free software; you can redistribute it and/or
#   modify it under the terms of the GNU General Public License
#   as published by the Free Software Foundation; either version 2
#   of the License, or (at your option) any later version.
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.

#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

package HTML::Latex;
$VERSION = '1.1';

use strict;
# use warnings;
# use diagnostics;
use FileHandle;
use File::Path;
use File::Basename;
use Data::Dumper;
use Carp;
use vars qw($packages $heads $tags $options $pres $banned $LOG $VERSION %present);

#extra
use HTML::TreeBuilder;
use XML::Simple;

################### BEGIN DOCUMENTATIEN #####################

=head1 NAME

HTML::Latex - Creates a Latex file from an HTML file.

=head1 SYNOPSIS

 use HTML::Latex

 my $parser = new HTML::Latex($conffile);
 $parser-&gt;set_option(\%options);
 $parser-&gt;add_package(@packages);
 $parser-&gt;ban_tag(@banned);
 $parser-&gt;set_log($logfile);

 # Option 1:
 foreach my $uri (@ARGV) {
    my ($htmlfile,$latexfile) = $parser-&gt;html2latex($uri);
 }

 # Option 2:
 foreach my $uri (@ARGV) {
    my $in = IO::File-&gt;new("&lt; $uri");
    my $out = IO::File-&gt;new("&gt; $uri.tex");
    $parser-&gt;html2latex($in,$out);
 }

 # Option 3:
 my $html_string = join("\n",&lt;&gt;);
 my $tex_string = $parser-&gt;parse_string($html_string,1);

 # Option 4:
 my $html_string = join("",@ARGV);
 my $tex_string = $parser-&gt;parse_string($html_string);

print $tex_string;

=head1 DESCRIPTION

This class is used to create a text file in Latex format from a file
in HTML format.  Use the class as follows:

1. Create a new HTML::Latex object.

2. Override any options using set_option(), add_package(), ban_tag(), or set_log().

3. Run html2latex() on a file or URL.

4. Do whatever you want with the filename that was returned.

=head1 METHODS

=over

=item B&lt;$p = HTML::Latex-E&lt;gt&gt;new($conffile)&gt;

Creates a new HTML::Latex object.  It parses the configuation file
$conffile to set attributes.  The format of that file can be found in
the CONFIGURATION FILE section.

Example:

    my $parser = HTML::Latex-&gt;new();

=item B&lt;($htmlfile,$latexfile) = $p-E&lt;gt&gt;html2latex($in,$out)&gt;

$in is any URL or filename or FileHandle.  If it is a URL, it is
mirrored locally.  The local location is returned as $htmlfile.  The
method produces a Latex file $latexfile.

Locally mirrored files are all stored in the "store" directory which
can be set with either set_option() or in the configuration file.  See
B&lt;store&gt; under the OPTIONS section for more details.

A mirrored file will automatically be re-downloaded when the URL is
updated.  If it has not been updated, html2latex() will use the local
file only.

Also, html2latex() defaults to index.html when a file is not given.
For instance, if you used C&lt;html2latex(http://slashdot.org)&gt;, then the
url http://slashdot.org/index.html would be used.

Example:

    my($htmlfile,$latexfile) =
       $parser-&gt;html2latex('report01.html');


=item B&lt;$tex_string = $p-E&lt;gt&gt;parse_string($html_string [,$full])&gt;

$html_string is an HTML string.  $tex_string is a LaTeX string.  If
$full is 0, then any &lt;HTML&gt; and &lt;BODY&gt; tags are ignored, and the
string is just plain tex.  If $full is 1, then &lt;HTML&gt; and &lt;BODY&gt; tags
are implicitly added.  Basically, it's a choice as to whether or not
$tex_string has a LaTeX preamble in it.

=item B&lt;my @old_values = $p-E&lt;gt&gt;set_option(\%options)&gt;

Sets on option.  For a description of options, see the OPTION section
below.  Returns an list of all the old values based on the keys of
%options.

Example:

    $parser-&gt;set_option({border =&gt; 0, debug =&gt; 1});

=item B&lt;$p-E&lt;gt&gt;add_package(@packages)&gt;

Adds packages to the list used by \usepackage{} in Latex.  The
defaults are fullpage, graphicx, and url.

Example:

    $parser-&gt;add_package('doublespace');

=item B&lt;$p-E&lt;gt&gt;add_head(@heads)&gt;

Adds options to the list used by \documentclass[OPTIONS]{article} in
Latex.  Font is automatically put there, so don't put it there
yourself.

Example:

    $parser-&gt;add_head('twocolumn');

=item B&lt;$p-E&lt;gt&gt;ban_tag(@banned)&gt;

Add @banned to the list of tags that html2latex() will ignore.  This
overrides tag definitions in the configuration file. By default, the
&lt;CODE&gt; tag is banned.  That is because some people were using
&lt;PRE&gt;&lt;CODE&gt;&lt;/CODE&gt;&lt;/PRE&gt;, which can be really bad if both are parsed.

Example:

    $parser-&gt;ban_tag('code');

=item B&lt;my $filehandle = $p-E&lt;gt&gt;set_log($logfile)&gt;

Have errors and messages printed to the filename or FileHandle or
IO::File $logfile.  By default, things are printed to STDERR.
set_log() returns the FileHandle of the log file.

Example:

    my $filehandle = $parser-&gt;set_log('report01.log');

=back

=head1 CONFIGURATION FILE

The configuration file is a very simple XML file.  The root element is
&lt;conf&gt;.  Nested inside are four tags: &lt;tag&gt; &lt;package&gt; &lt;ban&gt; &lt;options&gt;.

=head2 tag

&lt;tag&gt; has 2 attributes: I&lt;name&gt; and I&lt;type&gt;.  Inside of &lt;tag&gt; is
nested zero to many &lt;tex&gt; tags. Each of these is described below.

=over

=item name

The I&lt;name&gt; attributes assigns the other values (I&lt;type&gt; and I&lt;tex&gt;)
to an HTML tag of a certain name.

=item type

The type of a tag basically tells html2latex() how to handle it.
Internally, this assigns the tag to a certain handler.

=item tex

When handling a tag, html2latex must know what TeX string to replace
the HTML tags with.  This is done with the use of &lt;tex&gt;tex
string&lt;/tex&gt;.  Different types require 0,1,or 2 such tags nested
inside of &lt;tag&gt;.  You can think of &lt;tex&gt; tags as arguments to pass to
a I&lt;type&gt; handler.  Internally, that is what it is.

Extraneous White space is ignored; do not rely upon it.  \N is replaced
with newlines.  Everything else is just as you type it.

=head2 tag examples

For a lot of examples, just look at the default configuration file,
html2latex.xml.  We will go over 1 example in detail.  This example is
for the HTML &lt;B&gt; tag.

    &lt;tag name="b" type="command"&gt;
        &lt;tex&gt;textbf&lt;/tex&gt;
    &lt;/tag&gt;

This text tells html2latex() to treat the &lt;B&gt; tag as a TeX command.
It gives it the additional argument of 'textbf'.  html2latex() will
call the command_handler('textbf') and the output will be \textbf{NESTED DATA}.

=back

=head2 package

For each &lt;package&gt;package_name&lt;/package&gt; given, package_name is added
to the list printed in the Latex file.  For instance, the lines

    &lt;package&gt;fullpage&lt;/package&gt;
    &lt;package&gt;graphicx&lt;/package&gt;
    &lt;package&gt;url&lt;/package&gt;

adds the packages fullpage, graphicx, and url.  The package 'fullpage'
is often recommended.

=head2 head

For each &lt;head&gt;head&lt;/head&gt; given, head is added to the list of options
printed in the \documentclass command.  For instance, the line

    &lt;head&gt;twocolumn&lt;/head&gt;

creates the command \documentclass[10pt,twocolumn]{article}.

=head2 ban

&lt;ban&gt; will make html2latex ignore a tag.  For instance, the line

   &lt;ban&gt;code&lt;/ban&gt;

makes html2latex() ignore &lt;code&gt; even though it has a definition in
the configuration file.  This can be useful to turn on/turn off tags
when trying different configurations.

=head2 options

Inside of &lt;options&gt; are a number of other tags.  Each is described
below in OPTIONS.  The value inside of a given &lt;OPTION&gt; &lt;/OPTION&gt;
provides a default value that can be overridden with command-line
options.  For instance, &lt;font&gt;10&lt;/font&gt; will set the default font size
to 10.

=head1 TYPES

There are a number of different types of HTML tags support by
HTML::Latex.  The list is: command, environment, single, other, table,
image, and ignore.  Each are described below.  TEX1 and TEX2 mean the
first and second value given by &lt;tex&gt;.  NAME is given by the name
attribute.  VALUE is the value nested within an HTML tag.  

=head2 command

 HTML Key:       &lt;NAME&gt;VALUE&lt;/NAME&gt;
 HTML Example:   &lt;B&gt;Foo&lt;/B&gt;
 TeX  Key:       \TEX1{VALUE}
 TeX  Example:   \textbf{Foo}

=head2 environment

 HTML Key:       &lt;NAME&gt;VALUE&lt;/NAME&gt;
 HTML Example:   &lt;OL&gt;Foo&lt;/OL&gt;
 TeX  Key:       \begin{TEX1} VALUE \end{TEX1}
 TeX  Example:   \begin{enumerate} Foo \end{enumerate}

=head2 single

 HTML Key:       &lt;NAME&gt;VALUE
 HTML Example:   &lt;LI&gt;Foo
 TeX  Key:       \TEX1 VALUE
 TeX  Example:   \item Foo

=head2 other

 HTML Key:       &lt;NAME&gt;VALUE&lt;/NAME&gt;
 HTML Example:   &lt;DT&gt;Foo
 TeX  Key:       TEX1 VALUE TEX2
 TeX  Example:   \item[Foo]

=head2 kill

 HTML Key:       &lt;NAME&gt;VALUE&lt;/NAME&gt;
 HTML Example:   &lt;SCRIPT&gt;javascript.garbage()&lt;/SCRIPT&gt;
 TeX  Key:       ""
 TeX  Example:   ""

This is of particular fun because any nested HTML tags are also ignored.  Good for removing unwanted javascript.

=head2 table

This should be applied if and only if a tag is of type TABLE,TR, or TD.

=head2 image

This should be applied if and only if a tag is of type IMG.

=head2 ignore

Do nothing.  Has the same affect as banning a tag.

=head1 OPTIONS

=over

=item B&lt;store&gt;

"store" is the directory that mirrored files are stored in.  It is
~/.html2latex by default.  In side of this directory are
subdirectories representing the HOST in a URL and the path from that
HOST.  For instance, if you used
C&lt;html2latex(http://slashdot.org/path/to/file.html&gt;, it would store
the file as ~/.html2latex/slashdot.org/path/to/file.html.

=item B&lt;cache&gt;

This will force html2latex to use cached files if possible.  It always
caches anyway, and uses the cached file if the network file has not
changed.  This just forces the use of the local file if available.

=item B&lt;document_class&gt;

Set the documentclass to use.  Any valid latex document class is
valid.  Examples are B&lt;report&gt;, B&lt;book&gt;, and B&lt;article&gt;.  B&lt;article&gt;
is the default.  If an invalid document class is used, the output
latex file will not compile.

=item B&lt;paragraph&gt;

True uses HTML-style paragraphs.  They leave a newline between
paragraphs.  False uses TeX-style paragraphs.  They have no newline,
but indent the first line of every paragraph.  Default is true.

=item B&lt;font&gt;

Set the font size.  Can be 10,11, or 12.  Do not try anything else.
html2latex will not check it, but the latex file will not compile (at
least I think not).  Default is 12.

=item B&lt;image&gt;

Set the scale for images in the latex file.  This is useful because
some images in HTML or much to big to fit on a page.  Default is 1.0.
Scale can be any non-zero positive floating point number; large
numbers are not recommended.

=item B&lt;border&gt;

True means table borders are on.  False mean they are off.  This is
always overridden by HTML attributes.

=item B&lt;mbox&gt;

html2latex() will put a tex \mbox around all of the tables it creates.
I do not know why, but with a lot of tables (especially nested ones),
the tex and pdf output will work better.  So, if you do not like your
output with tables, try this.  True means on, false means off.
Default is false.

=item B&lt;debug&gt;

The bigger the number set, the more the debugging info printed.  0
means things relevant to the user.  1 means things that trace some
code.  2 or greater means dumping data structures.

=head1 Extending

Extending HTML::Latex basically means making a new tag work.  Usually,
this would call for writing a new handler.  If a present handler will
suffice, then you can stip to the 3rd step. It's very simple to do so.
There are 3 easy steps:

=head2 Write the function.

Write a function (preferably ending in '_handler').  It's input is 1
HTML::Element and several tex strings.  The type of HTML::Element and
the value of the strings is set in the XML config file.  Your furtions
responsibilty is to return a TeX string representing the HTML::Element
and all of it's children elements.

The children are very easy to take care of.  The string representing
the children elements is obtained by calling C&lt;texify($html_element)&gt;.
So, the function really only has to worry about the current
HTML::Element.

In particular, it must return that comes before and goes after the
string represting the current HTML::Element.  So, if you wanted a
handler that print \TAG as the TeX for any &lt;TAG&gt; in HTML and a special
TEX value given in the config file for &lt;/TAG&gt;, then the handler would
look like this:

 sub my_handler{
     my ($html_element,$tex) = @_;
     return '\' . $html_element-&gt;tag() . texify($html_element) . $tex;
 }

In this example, one TEX parameter was passed in by the XML config
file.  The handler return what comes before the children concatenated
with the texify-ed children texified with what comes after the
children.  See the documentation for HTML::Element for all of the
things you can do with them.

=head2 Assign a tag type to a handler.

Just add an entry to %types below.  It should have a type name as a
key and a reference to your handler as a value.  Following our
example, we could add the line:

    "my_type"     =&gt;    \&amp;my_handler,

To %types.

=head2 Add support in the configuration file.

The format of the configuration file is in XML and can be found above
under CONFIGURATION FILE.  The default XML file is at the bottom of
Latex.pm under __DATA__. Basically, for every tag you want to use your
new handler, use &lt;tag&gt; as follows:

 &lt;tag name="TAG_NAME" type="my_type"&gt;
     &lt;tex&gt;TEX_PARAMATER&lt;/tex&gt;
 &lt;/tap&gt;

TAG_NAME is, of course, the tag name.  "my_type" is the name of the
type you assigned your handler to.  TEX_PARAMATER is the value that
gets placed under $tex in the example handler.


That's it.  Now HTML::Latex should obey the new handler and behave
correctly.

=head1 NOTES

In you call html2latex() on several URLs any filename given after a
URL will continue to use the latest HOST given.  Also, files default
to index.html, regardless of what the server thinks.  So, if you use:

 html2latex(http://slashdot.org)
 html2latex(foo.html)
 html2latex(http://linuxtoday.net)
 html2latex(bar.html)

html2latex() will try to grab http://slashdot.org/index.html,
http://slashdot.org/foo.html, http://linuxtoday.net/index.html, and
http://linuxtoday.net/bar.html

=head1 BUGS

* Anything between &lt;TABLE&gt; and &lt;TR&gt; and &lt;TD&gt; is ignored.  I do not


* Anything between &lt;OL&gt; or &lt;UL&gt; and &lt;LI&gt; will not be ignored, but will
  really mess Latex up.

=cut

################### END DOCUMENTATION #######################

################### BEGIN DEFENITIONS #######################

# Test what modules we can use
eval {require URI};
$present{'URI'} = 1 unless $@;

eval {require LWP::Simple};
$present{'LWP::Simple'} = 1 unless $@;

eval {require Image::Magick};
$present{'Image::Magick'} = 1 unless $@;

# The configuration file gives a "type" to each tag.  This hash tells
# what functions to use on each type
my %types = (
	     "command"     =&gt; \&amp;command_handler,
	     "environment" =&gt; \&amp;environment_handler,
	     "single"      =&gt; \&amp;single_handler,
	     "ignore"      =&gt; \&amp;texify,
	     "other"       =&gt; \&amp;other_handler,
	     "kill"        =&gt; sub {return ""},

	     "image"       =&gt; \&amp;image_handler,
	     "table"       =&gt; \&amp;table_handler,
	     "pre"         =&gt; \&amp;pre_handler,      # Experimental; don't use
	    );

# Some characters typed in HTML need to be altered to be correct in
# Latex.  These must be done this specific order All the foreign
# characters or special ascii characters that need to be altered.  *
# next the comment means it doesn't really work or is faked. If it's
# commented out, that means it doesn't work at all.
my @specials = (
		['&lt;!--.*--&gt;' , ''          ], #comments
		['\$'    ,  '\$'           ], 
	        ['\\\\(?!\$)', "\$\\backslash\$"], #\
		['&lt;'     , '$&lt;$'           ],
 		['&gt;'     , '$&gt;$'           ],
		['&amp;'     , '\&amp;'            ],
		['%'     , '\%'            ],
		['#'     , '\#'            ],
		['{'     , '\{'            ],
		['}'     , '\}'            ],
		['_'     , '\_'            ],
		['\^'    , '\^{}'          ],
		[chr(161), '!`'            ], #¡
	       #[chr(162), ''              ], #¢*
		[chr(163), '{\\pounds}'    ], #£
	       #[chr(164), ''              ], #¤*
 		[chr(165), '{Y\hspace*{-1.4ex}--}'], #¥*
		[chr(166), '$|$'           ], #¦*
 		[chr(167), '{\\S}'         ], #§
		[chr(168), '\\"{}'         ], #¨
		[chr(169), '{\\copyright}' ], #©
		[chr(170), '$^{\underline{a}}$'], #ª*
		[chr(171), '&lt;&lt;'            ], #«
		[chr(172), '$\\neg$'       ], #¬
		[chr(173), '$-$'           ], #­
	       #[chr(174), ''              ], #®*
		[chr(175), '$^-$'          ], #¯
		[chr(176), '$^{\\circ}$'   ], #°
		[chr(177), '$\\pm$'        ], #±
	        [chr(178), '$^2$'          ], #²
		[chr(179), '$^3$'          ], #³
		[chr(180), '$^\\prime$'    ], #´
		[chr(181), '$\\mu$'        ], #µ
		[chr(182), '{\P}'          ], #¶
		[chr(183), '$\cdot$'       ], #·
		[chr(184), ','             ], #¸*
                [chr(185), '$^1$'          ], #¹
                [chr(186), '$^{\\underline{\\circ}}$'],	#º*
                [chr(187), '&gt;&gt;'            ], #»
                [chr(188), '$\frac{1}{4}$' ], #¼
		[chr(189), '$\frac{1}{2}$' ], #½
		[chr(190), '$\frac{3}{4}$' ], #¾
		[chr(191), '?`'            ], #¿
		[chr(192), '\\`A'          ], #À
		[chr(193), '\\\'A'         ], #Á
		[chr(194), '\\^A'          ], #A
		[chr(195), '\\~A'          ], #Ã
		[chr(196), '\\"A'          ], #Ä
		[chr(197), '{\\AA}'        ], #Å
		[chr(198), '{\\AE}'        ], #Æ
		[chr(199), '\\c{C}'        ], #Ç
		[chr(200), '\\`E'          ], #È
		[chr(201), '\\\'E'         ], #É
		[chr(202), '\\^E'          ], #Ê
		[chr(203), '\\"E'          ], #Ë
		[chr(204), '\\`I'          ], #Ì
		[chr(205), '\\\'I'         ], #Í
		[chr(206), '\\^I'          ], #I
		[chr(207), '\\"I'          ], #Ï
		[chr(208), '{D\\hspace*{-1.7ex}-\\hspace{.9ex}}'], #Ð*
		[chr(209), '\\~N'          ], #Ñ
		[chr(210), '\\`O'          ], #Ò
		[chr(211), '\\\'O'         ], #Ó
		[chr(212), '\\^O'          ], #Ô
		[chr(213), '\\~O'          ], #Õ
		[chr(214), '\\"O'          ], #Ö
		[chr(215), '$\chi$'        ], #×
		[chr(216), '{\\O}'         ], #Ø
		[chr(217), '\\`U'          ], #Ù
		[chr(218), '\\\'U'         ], #Ú
		[chr(219), '\\^U'          ], #Û
		[chr(220), '\\"U'          ], #Ü
		[chr(221), '\\\'Y'         ], #Ý*
		[chr(222), 'P'             ], #Þ*
		[chr(223), '"s'            ], #ß
		[chr(224), '\\`a'          ], #á
		[chr(225), '\\\'a'         ], #à
		[chr(226), '\\^a'          ], #â
		[chr(227), '\\~a'          ], #ã
		[chr(228), '\\"a'          ], #ä
		[chr(229), '\\r{a}'        ], #å
		[chr(230), '{\ae}'         ], #æ
		[chr(231), '\\c{c}'        ], #ç
		[chr(232), '\\`e'          ], #é
		[chr(233), '\\\'e'         ], #è
		[chr(234), '\\^e'          ], #ê
		[chr(235), '\\"e'          ], #ë
		[chr(236), '\\`{\i}'       ], #ì
		[chr(237), '\\\'{\\i}'     ], #í
		[chr(238), '\\^{\\i}'      ], #î
		[chr(239), '\\"{\\i}'      ], #ï
		[chr(240), '\\v{o}'        ], #ð
		[chr(241), '\\~n'          ], #ñ
		[chr(242), '\\`o'          ], #ò
		[chr(243), '\\\'o'         ], #ó
		[chr(244), '\\^o'          ], #ô
		[chr(245), '\\~o'          ], #õ
		[chr(246), '\\"o'          ], #ö
		[chr(247), '$\\div$'       ], #÷
		[chr(248), '{\\o}'         ], #ø
		[chr(249), '\\`u'          ], #ù
		[chr(250), '\\\'u'         ], #ú
		[chr(251), '\\^u'          ], #û
		[chr(252), '\\"u'          ], #ü
		[chr(253), '\\\'y'         ], #ý
		[chr(254), 'p'             ], #þ*
		[chr(255), '\\"y'          ], #ÿ
	       );

# complie matchings
foreach my $set (@specials) {
    $set-&gt;[0] = qr|$set-&gt;[0]|;
}

################### END DEFENITIONS #######################

# Paramaters for HANDLERs and SUBs are shown as &lt;N&gt; and [N].  N is the
# number of the parameter, starting with 1.  So, the first paramater
# would be &lt;1&gt;, the second &lt;2&gt;, and so on.  &lt;N&gt; means the paramater is
# mandatory.  [N] means it is optional.

##################### BEGIN METHODS  ######################

# initializes options with optional configuration file
sub new {
    my ($class,$conffilename) = @_;

    my $conffile;
    if(defined($conffilename)){
	$conffile = IO::File-&gt;new("&lt; $conffilename");
    } else {
	$conffile =  \*DATA;
    }

    my $conf = XMLin($conffile,forcearray =&gt; ['tex','pre','ban']);

    # moved @banned from an array to a hash for fast lookup later
    my $banned_ref = $conf-&gt;{ban};
    $conf-&gt;{ban} = {};
    foreach my $banned (@$banned_ref){
	$conf-&gt;{ban}{$banned}++;
    }

    # make any refrences in @tex (see handlers below) to empty strings and new lines
    # Ugly, I know.  Perhaps XML::Simple is too simple.
    foreach my $tag (keys %{$conf-&gt;{tag}}){ 
	foreach my $tex (@{$conf-&gt;{tag}{$tag}{tex}}){ #some derefrence, eh?
	    $tex = (ref($tex) ? '' : $tex);   # {} =&gt; ''
	    $tex =~ s/\\N/\n/g;               # \N =&gt; newline
	    # if it's a verbatim and not banned
	    push @{$conf-&gt;{pre}}, $tag if ($tex eq 'verbatim' &amp;&amp; !$conf-&gt;{ban}{$tag});
	}
    }

    #open logging files
    $conf-&gt;{log} = $conf-&gt;{conf}{options} ? 
	FileHandle-&gt;new($conf-&gt;{options}{log},'w') :
	    \*STDERR;

    return bless $conf,$class;
}

# converts html2latex using &amp;texify.
# &lt;1&gt; The html filename or filehandle
# &lt;2&gt; optional second filehandle
sub html2latex {
    my ($conf,$in,$out) = @_;

    #global to functions called below, which is what we want
    local $packages = $conf-&gt;{package} || [];
    local $heads    = $conf-&gt;{head}    || [];
    local $tags     = $conf-&gt;{tag}     || {};
    local $options  = $conf-&gt;{options} || {};
    local $banned   = $conf-&gt;{ban}     || {};
    local $pres     = $conf-&gt;{pre}     || {};
    local $LOG      = $conf-&gt;{log};
    $options-&gt;{store} =~ s/^\s*~/$ENV{HOME}/ if exists $ENV{HOME};

    print $LOG Dumper $conf if $options-&gt;{debug} &gt; 1;

    #open files.
    my($filenamein,$filenameout);
    unless(ref $in and ref $out){ #filenhadles -- leave them alone.
	($in,$out,$filenamein,$filenameout) = open_files($in,1) if defined($in);
    }

    #if you have a uri and it exists
    #build the HTML tree
    if($in &amp;&amp; $out){
	my $tree = HTML::TreeBuilder-&gt;new;
	$tree-&gt;warn(1);
	my $result = $tree-&gt;parse_file($in);

	#here's where all the big magic happens
	print $out &amp;preamble_handler($tree-&gt;root);

	#destroy the HTML tree
	$tree-&gt;delete;

	return ($filenamein,$filenameout) if ($filenamein &amp;&amp; $filenameout);
	return $result;  #If you recieved filehandles, just return the return of $tree-&gt;parse
    } else {
	# print $LOG "You better give html2latex() a valid filename if you want it to do anything.\n";
	return;
    }
}

sub parse_string {
    my ($conf,$input,$full) = @_;
    return unless defined($input);

    local $packages = $conf-&gt;{package} || [];
    local $heads    = $conf-&gt;{head}    || [];
    local $tags     = $conf-&gt;{tag}     || {};
    local $options  = $conf-&gt;{options} || {};
    local $banned   = $conf-&gt;{ban}     || {};
    local $pres     = $conf-&gt;{pre}     || {};
    local $LOG      = $conf-&gt;{log};
    $options-&gt;{store} =~ s/^\s*~/$ENV{HOME}/ if exists $ENV{HOME};

    print $LOG Dumper $conf if $options-&gt;{debug} &gt; 1;

    my $tree = HTML::TreeBuilder-&gt;new;
    $tree-&gt;warn(1);
    $tree-&gt;parse($input);

    my $result;
    if($full){
	$result = preamble_handler($tree-&gt;root);  # Print whole file
    } else {
	$result = texify($tree-&gt;find_by_tag_name('body'));
    }
    $tree-&gt;delete;

    return $result;
}

# set options for running html2latex
# &lt;1&gt; is a hash refrence of options
sub set_option {
    my ($conf,$options) = @_;
    my @old_values = ();
    while(my ($key,$value) = each %$options){
	if(defined($value)){
	    push @old_values, $conf-&gt;{options}{$key};
	    $conf-&gt;{options}{$key} = $value;
	}
    }
}

sub add_package {
    my $conf = shift;
    push @{$conf-&gt;{package}}, @_;
}

sub add_head {
    my $conf = shift;
    push @{$conf-&gt;{head}}, @_;
}

sub ban_tag {
    my $conf = shift;
    foreach my $banned (@_){
	$conf-&gt;{ban}{$banned}++;
    }
}

#set log file to $logfile
#return FileHandle to log file.
sub set_log {
    my ($conf,$logfile) = @_;
    if(ref $logfile){
	$conf-&gt;{log} = $logfile;
    } else {
	$conf-&gt;{log} = FileHandle-&gt;new($logfile,'w') or 
	  die "FILE: Bad logfile: $logfile";
    }
    return $conf-&gt;{log};
}
##################### END HANDLERS #########################

##################### BEGIN HANDLERS #######################

# All HANDLERs are called like so:
# &amp;HANDLER($html_element,@tex); 

# @tex is a list of latex strings $html_elmemnt is a node in the HTML
# tree.  HTML::ELement man page for more on that.

# Anyway, the comments for each HANDLER represent the starting HTML
# string and the output tex string.  Anything inbetween HTML tags is
# recursivly texified by the big sub &amp;texify, which then calls other
# HANDLERs.

# HTML input form: &lt;FOO&gt; Bar &lt;/FOO&gt;
# Latex output form: \command{bar}
sub command_handler{
    my($html_element,$command) = @_;
    return "\\$command\{" . texify($html_element) . "\}\n";
}

# HTML input form: &lt;FOO&gt; Bar &lt;/FOO&gt;
# Latex output form: tex1 bar tex2
sub other_handler{
    my($html_element,@tex) = @_;
    return $tex[0] . texify($html_element) . $tex[1];
}

# HTML input form: &lt;FOO&gt; Bar &lt;/FOO&gt;
# Latex output form: \begin{tex} Bar \end{tex}
sub environment_handler{
    my($html_element,$environment) = @_;
    return '\begin{' . $environment . '}' . "\n" . 
	texify($html_element) . "\n" . '\end{' .  $environment . '}' . "\n";
}

# HTML input form: &lt;FOO&gt; Bar (implicit end)
# Latex output form: \tex Bar
sub single_handler{
    my($html_element,$single) = @_;
    return $single . " " . texify($html_element) . "\n";
}

# HTML input form: &lt;PRE&gt; Bar &lt;/PRE&gt;
# Latex output has all of the spaces made into hard spaces and
# newlines into hard newlines. It's the best I can do since latex
# doesn't want to respect whitespace.  It's very experimental. One
# should really just use the verbatim environment, but what the heck,
# give people the option.
sub pre_handler{
    my($html_elemnt) = shift;
    my $text = $html_elemnt-&gt;as_text;

    $text =~ s/[ ]/\\ /og;
    $text =~ s/\n/\\\\\n/og;

    return $text;
}

# Does a lot of work to create a table in latex format.
# It takes &lt;TABLE&gt;, &lt;TR&gt;, and &lt;TD&gt;.  It works by finding those tags nested inside
# and then calling texify on them while keepind track of when to print
# latex syntax.  It's messy, I know.  Nested tables are completely
# ignored, and anything inside a table but not inside of a &lt;TD&gt; tag is
# also ignored.  If anyone would like to improve this, that would be
# very cool.
# &lt;3&gt; The HTML::Element representing the table.  It doesn't use
# $content_ref, so you don't really need it.

sub table_handler{
    my($html_element,$tex) = @_;
    my $output = "";
    if($tex eq "table"){
	# It's a table tag
	$output = ($options-&gt;{mbox}? '\mbox{' : '') .
	  create_latex_table($html_element) . ($options-&gt;{mbox}? '}' : '');
    } else { 
	# It's a td or tr, let create_latex_table() take care of "\\" and "&amp;"
	# add the texified text inside
	$output = texify($html_element); 
    }
    return $output;
}

# HTML input form: &lt;IMG src="bar.(jpg|jpeg|gif|png)"&gt;
# Latex output form: \includegraphic{bar.png} 
# In also converts the image to a .png using "convert".
# &lt;3&gt; The HTML::Element representing the tag.  It doesn't use
# $content_ref, so you don't really need it.
sub image_handler{
    my($html_element,$tex) = @_;
    my $source = $html_element-&gt;attr('src') || "";
    my $scale = $html_element-&gt;attr('scale') || $options-&gt;{image};
    my $alt = $html_element-&gt;attr('alt') || "";

    if($scale and my $image = convert_image($source,$scale)){
	# convert worked
	return "\\$tex\[scale=$scale\]\{$image\} ";
    } else { 
	#convert didn't work or images weren't selected.
	print $LOG "IMG: Couldn't convert $source; using alt\n";
	print $LOG "\tRecieved &lt;$image&gt;\n" if $options-&gt;{debug};
	return $alt;
    }
}

# Prints the preamble.  Not to extensize right now, but will become
# very extensive if I decide to parse stuff in the HEAD tag.
sub preamble_handler{
    my($html_element,$tex) = @_;
    my $document_class = $html_element-&gt;attr('class') || $options-&gt;{document_class} || 'article';
    my $font_size = $html_element-&gt;attr('fontsize') || $options-&gt;{font_size} || 10;
    my $output;

    $output .= join ('',
		     '\documentclass[',
		     join (",","${font_size}pt",@$heads),
		     ']{',
		     $document_class,
		     '}',
		     "\n",
		     '\usepackage{',
		     join(", ",@$packages),
		     '}', 
		     "\n"
		     );
    $output .= join ('',
		     '\setlength{\parskip}{1ex}',
		     "\n",
		     '\setlength{\parindent}{0ex}',
		     "\n",
		     ) if $options-&gt;{paragraph};

    $output .= texify($html_element);

    return $output;
}

###################### END HANDLERS #######################


# Takes in an array of HTML::Element-es which calls a handler on all of its
# children, which calls texify recursively, and eventually makes a
# string.

sub texify {
    my $parent_element = shift;
    my $output = "";

    foreach my $html_element ($parent_element-&gt;content_list){
	if(ref $html_element){
	    # If this element is another HTML::Element
	    my $tag = $html_element-&gt;tag();
	    print $LOG "\t" x ($html_element-&gt;depth - 1) . "&lt;$tag&gt; " if $options-&gt;{debug};

	    if(my $tag_hash_ref = $tags-&gt;{$tag} and !$banned-&gt;{$tag}){
		# If the tag is used with a handler and it isn't banned, use it.
		my $handler_ref = $types{$tag_hash_ref-&gt;{type}} or 
		    die "&lt;$tag&gt; needs a proper type (not $tag_hash_ref-&gt;{type})\n";
		my @tex = @{$tag_hash_ref-&gt;{tex} || []}; 
		print $LOG "is of type $tag_hash_ref-&gt;{type}: calling handler with \"" . 
		    join(",",@tex) . "\"\n" if $options-&gt;{debug};
		$output .= $handler_ref-&gt;($html_element,@tex);
	    } else {
		# Otherwise, just texify the contents;
		print $LOG "has no type \n" if $options-&gt;{debug};
		$output .= texify($html_element);
	    }
	} else {
	    # Otherwise, it's just a string 
	    print $LOG "\t" x ($parent_element-&gt;depth + 1), $html_element if $options-&gt;{debug} &gt; 1;
	    unless($parent_element-&gt;is_inside(@$pres)){
		#don't change any characters if inside a tag such as PRE.
		#Quote expansion needs more finese.
		$html_element =~ s/([^\s\[\{\(~])"/$1''/og; #" preceded by character not \s,[,{,or [
		$html_element =~ s/"/``/og;
		foreach my $special (@specials){
		    $html_element =~ s/$special-&gt;[0]/$special-&gt;[1]/g;
		}
	    }
	    $output .= urlify($html_element);
	}
    }
    return $output;
}


# opens necessary files
# &lt;1&gt; The base of the filename
sub open_files {
    return unless (my $htmlfile = get_uri(@_));

    #if filename has anything .*html, then remove the extension
    my ($filename,$path,$suffix) = fileparse($htmlfile,'\.\w*html?');
    my $texfile = "$path$filename.tex";

    check_for_previous_files($texfile);

    my $fh_in = FileHandle-&gt;new("&lt; $htmlfile") or die "Can't open $htmlfile: $!";
    my $fh_out = FileHandle-&gt;new("&gt; $texfile") or die "Can't open $texfile: $!";
    print $LOG "FILE: Processing $htmlfile and writing to $texfile\n";
    return ($fh_in,$fh_out,$htmlfile,$texfile);
}

# checks for existance of file and moves it to name .old .
# &lt;1&gt; The filename
# [2] whether files should be renamed and overridden or just left alone.
# default is rename override 
# returns whether the file exists or not
sub check_for_previous_files {
    my $filename = shift;
    my $override = shift || 1; 

    if(-f $filename &amp;&amp; $override){
	rename $filename, "$filename.old";
	print $LOG "FILE: renamed $filename $filename.old\n"; 
    }
    return $filename;
}

# checks for existance of file and prints that it successfully created it.
# &lt;1&gt; filename
# [2] error to print if didn't create;
sub check_for_current_files {
    my $filename = shift;
    if( -f $filename){
	print $LOG "FILE: Successfully created $filename\n";
	return $filename;
    }
    else{
	print $LOG "FILE: Failed to create $filename\n";
	return;
    }
}
# Creates a latex table from an html table using the other table sub procedures.
# &lt;1&gt; The $html_element that is a table tag.
# Returns the table in latex string form
sub create_latex_table {
    my $table = shift;
    my $output;
    my($latex_table_ref,$row_number,$column_number) = create_latex_table_def($table);
    my $border = $table-&gt;attr('border') || $options-&gt;{border};

    $output .= "\n\n" . '\begin{tabular}{' . $latex_table_ref . '}' . "\n";
    $output .= "\\hline \n" if $border;

    #pay attention to only the TR tags inside the TABLE tag.
    my @rows = grep 'tr', $table-&gt;content_list;
    foreach my $row (@rows){
	#pay attention to only the TD tags inside the TR tags.
	my @columns = grep 'td', $row-&gt;content_list;   

	for my $i (0 .. $column_number - 1){ 
	    # Make Sure to fill in blank ones if necessary
	    my $column = $columns[$i];
	    # Add the td data
	    $output .= texify($column) if $column; 
	    # Add the puncation at the end if not the last one
	    $output .= (($i &lt; $column_number -1)?  " &amp;" : ""); 
	}

	# Add the puncation at the end if not the last one
	$output .= (($row-&gt;pindex() &lt; $row_number -1 or $border)?  " \\\\" : "") . "\n"; 
	$output .= " \\hline \n" if $border;
    }

    $output .= "\n" . '\end{tabular}' . "\n\n";

    return $output;
}

# Based on the alignments of the rows, create a latex table defenition (i.e. "cccc")
# &lt;1&gt; The the number of columns the table has;
# &lt;2&gt; A refrence to an array with alignment defenitions
# &lt;3&gt; Whether it has a border or not;
# Returns the table definition, the number of columns and the number of rows
sub create_latex_table_def {
    # get variables
    my $table = shift;
    my $border = $table-&gt;attr('border') || $options-&gt;{border};
    my ($row_number,$column_number) = find_table_lengths($table);
    my @column_alignments = create_column_alignments($table);

    # define table_def
    my $latex_table_def = ($border? "|" : "");
    for my $i (0 .. $column_number - 1){
	my $align = $column_alignments[$i];
	$latex_table_def .= ($align? ($border? $align . "|" : $align) : ($border? "c|" : "c")); 
    }

    return ($latex_table_def,$row_number,$column_number);
}

# Finds the maximum number of columns that any row in a table has
# and also the number of rows it has.
# &lt;1&gt; the refrence to the HTML::Element table.
sub find_table_lengths {
    my $table = shift;
    #only care about TR children
    my @rows = grep 'tr', $table-&gt;content_list;  
    my $max_row_length = 0;
    foreach my $row (@rows){
	#only care about the TD children
	my @columns = grep 'td', $row-&gt;content_list;  
	if(@columns &gt; $max_row_length){
	    $max_row_length = @columns;
	}
    }

    #        row_number    column_number
    return (scalar(@rows),$max_row_length);
}

# returns an array of column alignments
# &lt;1&gt; the refrence to the HTML::Element table.
sub create_column_alignments {
    my $table = shift;
    my @column_alignments;
    #only care about TR children
    my @rows = grep 'tr', $table-&gt;content_list;  
    if($rows[0]){
	#only care about the TD children
	my @columns = grep 'td', $rows[0]-&gt;content_list;  
	foreach my $column (@columns){
	    my $align = $column-&gt;attr('align');
	    if($align and $align eq 'left'){
		$align = 'l';
	    } elsif($align and $align eq 'right'){
		$align = 'r';
	    } else {
		$align = 'c';
	    }

	    push @column_alignments, $align;
	}
    }

    return @column_alignments;
}


# converts an image from jpeg or gif into png
# returns the name of the new filename is successfull
# &lt;1&gt; filename

sub convert_image {
    my $source = shift;

    my($absolute,$relative) = get_uri($source);
    if ($absolute and $relative){  #If we can find the file
	#if it successfully stores the file
	my ($aname,$apath,$asuffix) = fileparse($absolute,'\.(gif|png|jpe?g)'); 
	my ($rname,$rpath,$rsuffix) = fileparse($relative,'\.(gif|png|jpe?g)'); 

	if($asuffix eq '.gif' || $asuffix eq '.jpg' || $asuffix eq '.jpeg'){ # 
	    # Picture is of a convertable type
	    if($present{'Image::Magick'}){
		# convert it with Image::Magick
		require Image::Magick;

		my $aoutput = "$apath$aname.png"; #write to and return with png
		my $routput = "$rpath$rname.png";
		my $image = Image::Magick-&gt;new();
		$image-&gt;Read("$absolute");
		$image-&gt;Write("$aoutput");
		undef $image;

		print $LOG "IMG: Converted $source to $routput\n";
		return $routput;
	    } else {
		# No Image::Magick.  Warn user and return nothing.
		print $LOG "IMG: Can't convert $source without Image::Magick; using alt\n";
		return;
	    }
	} elsif ($asuffix eq '.png'){
	    # It's a PNG for sure.
	    my $routput = "$rpath$rname.png";
	    return $routput;
	} else {
	    # so, it's not a png,gif, or jpg.  That means it's an invalid.
	    print $LOG "IMG: Invalid picture type: $source; using alt\n";
	    return;
	}
    } else {
	# We can't even get at the file.
	return;
    }
}

# If the filename is really a URL, then go grab it, translate
# the name to the local file directory, and return that file name.
# Otherwise, just return the thing you got in.
# &lt;1&gt; is the URI
# [2] can specify to change the default host for subsiquent calls
# return ($absolute_path_to_file,$relative_path_to_file);
# The relative can be absolute itself (same as $absolute).
{
    #variables to stay the same across calls of get_uri.  It's used in
    #case we get image URLs with no host or scheme or path.
    my $HOST = undef;     #global value of current HOST
    my $PATH = undef;     #path inside host where we start
    my $SCHEME = undef;   #scheme originally used

    sub get_uri {
	my ($uri,$absolute_local,$relative_local);
	$uri = $absolute_local = $relative_local = shift;
	print $LOG "looking for $uri\n" if $options-&gt;{debug};
	my $override = shift || 0;            #absolute means that you replace $HOST and $PATH

	if(-f $uri){ 
	    # it's an absolute local file.  
	    $PATH = dirname($uri) if $override; 
	    print $LOG "returning $uri\n" if $options-&gt;{debug};
	    return ($uri,$uri);
	} elsif(defined($PATH) &amp;&amp; -f "$PATH/$uri") {    
	    #it must be a local relative image
	    print $LOG "returning $PATH/$uri\n" if $options-&gt;{debug};
	    return ("$PATH/$uri",$uri);
	} elsif($uri =~ m|://|){ 
	    #It's a full URL

	    # Load necessary modules if you can.
	    unless($present{'URI'}) {
		print $LOG "NEED: Can't handle request of $uri without module URI\n";
		return;
	    }

	    require URI;
	    URI-&gt;import();

	    unless($present{'LWP::Simple'}) {
	    	print $LOG "NEED: Can't handle request of $uri without module LWP::Simple\n";
		return;
	    }

	    require LWP::Simple;
	    LWP::Simple-&gt;import();

	    $uri = new URI($uri);
	    my ($path,$filename) = ($uri-&gt;path =~ m|(.*/)(.*)|);
	    #replace the host,host_path, and scheme if it doesn't have a value and we're allowed to

	    print $LOG "It's a full URL\n" if $options-&gt;{debug};
	    if($override){
		$HOST = $uri-&gt;host;
		$PATH = $path || '/';
		$SCHEME = $uri-&gt;scheme;
		print $LOG "Setting HOST to $HOST, PATH to $PATH, and SCHEME to $SCHEME\n" if $options-&gt;{debug};
	    }

	    my $absolute = ($options-&gt;{store} || '.') . '/' . ($uri-&gt;host || "") . ($path || "/") . ($filename || "index.html");

	    if(store_uri($uri,$absolute)){    #Now, download the file.  If it fails, return 0.
		print $LOG "returning $absolute\n" if $options-&gt;{debug};
		return ($absolute,$absolute);
	    } else {
		return;
	    }
	} elsif(defined($HOST) &amp;&amp; defined($SCHEME)){                    
	    #It's a partial URL.
	    if($uri =~ m|^/|){
		#it's an absolute partial URL
		my $absolute_uri = $SCHEME . '://' . $HOST . $uri;
		$absolute_local = ($options-&gt;{store} || '.') . '/' . $HOST . $uri;
		if(store_uri($absolute_uri,$absolute_local)){    #Now, download the file.  If it fails, return nothing.
		    return($absolute_local,$absolute_local);
		} else {
		    return;
		}
	    } else {
		#it's a relative partial URL
		my $absolute_uri = $SCHEME . '://' . $HOST . $PATH . $uri;
		$absolute_local = ($options-&gt;{store} || '.') . '/' . $HOST . $PATH . $uri;
		if(store_uri($absolute_uri,$absolute_local)){    #Now, download the file.  If it fails, return nothing.
		    return($absolute_local,$uri);
		} else {
		    return;
		}
	    }
	} else {
	    print $LOG "FILE: Unable to access $uri\n";
	    return;
	}
    }
}

# store a URI as a local file, and create a path if necessary
# &lt;1&gt; The URI
# &lt;2&gt; The file to store it in
# returns the base of a filename
sub store_uri {
    my ($uri,$localfile) = @_;
    my ($name,$path) = fileparse($localfile); 

    if(-f $localfile &amp;&amp; $options-&gt;{cache}){    
	#Use localfile if it's cached and caching is allowed
	print $LOG "URI: Using $localfile for $uri.  See -h to stop cacheing\n";
	return $localfile;
    } else {
	#Override localfile if new.
	mkpath($path,1) if (head($uri));
	if (is_error(mirror($uri,$localfile))){
	    print $LOG "URI: Unable to access $uri\n";
	    return;
	} else {
	    print $LOG "URI: Mirrored $uri in $localfile\n";
	    return $localfile;
	}
    }
}

# replaces URL with \url{URL}.  This code is taken right from the Perl
# Cookbook, which I reccomend.  Honestly, I'm not quite sure how it
# works; but, it does.
# &lt;1&gt; string to urlify.
{

    # I think putting them here will prevent them from needing to be
    # loaded into memory after each function call.  
    my $urls = '(http|telnet|gopher|file|wais|ftp)';
    my $ltrs = '\w';
    my $gunk = '/#~:.?+=&amp;%@!\-';
    my $punc = '.:?\-';
    my $any  = "${ltrs}${gunk}${punc}";
    sub urlify {
	$_[0] =~ s!\b($urls:[$any]+?)(?=[$punc]*[^$any]|$)!\\url{$1}!igox;
        return $_[0];
    }
}
1;  #package must return true.
########################## END SUBS #############################

__DATA__

&lt;!--

Written by Peter Thatcher, 08/2000.

html2latex.xml - the configuration file for HTML::Latex and
html2latex.

Documentation on the file format can be found in the manpage for
HTML::Latex under the section "CONFIGURATION FILE".

--&gt;
&lt;!-- Head Tag needed: DO NOT DELETE!!--&gt;
&lt;conf&gt;
    &lt;!-- Tag description --&gt;
    &lt;tag name="b" type="command"&gt;
        &lt;tex&gt;textbf&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="body" type="environment"&gt;
        &lt;tex&gt;document&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="br" type="single"&gt;
        &lt;tex&gt;\\&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="blockquote" type="environment"&gt;
        &lt;tex&gt;quote&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="center" type="environment"&gt;
        &lt;tex&gt;center&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="code" type="environment"&gt;
        &lt;tex&gt;verbatim&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="dd" type="other"&gt;
        &lt;tex&gt;&lt;/tex&gt;
        &lt;tex&gt;\N&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="dl" type="environment"&gt;
        &lt;tex&gt;description&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="dt" type="other"&gt;
        &lt;tex&gt;\item[&lt;/tex&gt;
        &lt;tex&gt;]&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="em" type="command"&gt;
        &lt;tex&gt;emph&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="h1" type="command"&gt;
        &lt;tex&gt;section*&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="h2" type="command"&gt;
        &lt;tex&gt;subsection*&lt;/tex&gt;7
    &lt;/tag&gt;
    &lt;tag name="h3" type="command"&gt;
        &lt;tex&gt;subsubsection*&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="h4" type="command"&gt;
        &lt;tex&gt;textbf&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="h5" type="command"&gt;
        &lt;tex&gt;textbf&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="h6" type="command"&gt;
        &lt;tex&gt;textbf&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="hr" type="single"&gt;
        &lt;tex&gt;\hline&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="i" type="command"&gt;
        &lt;tex&gt;emph&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="img" type="image"&gt;
        &lt;tex&gt;includegraphics&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="li" type="single"&gt;
        &lt;tex&gt;\item&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="ol" type="environment"&gt;
        &lt;tex&gt;enumerate&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="p" type="single"&gt;
        &lt;tex&gt;\N\N&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="pre" type="environment"&gt;
        &lt;tex&gt;verbatim&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="script" type="kill"&gt;&lt;/tag&gt;
    &lt;tag name="strong" type="command"&gt;
        &lt;tex&gt;textbf&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="table" type="table"&gt;
        &lt;tex&gt;table&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="td" type="table"&gt;
        &lt;tex&gt;tr&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="title" type="command"&gt;
        &lt;tex&gt;title&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="tr" type="table"&gt;
        &lt;tex&gt;td&lt;/tex&gt;
    &lt;/tag&gt;
    &lt;tag name="ul" type="environment"&gt;
        &lt;tex&gt;itemize&lt;/tex&gt;
    &lt;/tag&gt;

    &lt;!-- Options --&gt;
    &lt;options&gt;
        &lt;store&gt;~/.html2latex&lt;/store&gt;
        &lt;cache&gt;0&lt;/cache&gt;
        &lt;document_class&gt;article&lt;/document_class&gt;
	&lt;paragraph&gt;1&lt;/paragraph&gt;
        &lt;font&gt;10&lt;/font&gt;
        &lt;image&gt;1&lt;/image&gt;
        &lt;border&gt;0&lt;/border&gt;
        &lt;mbox&gt;0&lt;/mbox&gt;
        &lt;debug&gt;0&lt;/debug&gt;
    &lt;/options&gt;

    &lt;!-- LaTeX Packages--&gt;
    &lt;package&gt;fullpage&lt;/package&gt;
    &lt;package&gt;graphicx&lt;/package&gt;
    &lt;package&gt;url&lt;/package&gt;

    &lt;!-- Tags to Ignore--&gt;
    &lt;ban&gt;code&lt;/ban&gt;
&lt;/conf&gt;
</pre></body></html>