<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># Copyright (C) 1998-09  Stephane Galland &lt;galland@arakhne.org&gt;
#
# 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; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

=pod

=head1 NAME

Bib2HTML::Parser::Parser - A parser for BibTeX files.

=head1 SYNOPSYS

use Bib2HTML::Parser::Parser ;

my $gen = Bib2HTML::Parser::Parser-&gt;new() ;

=head1 DESCRIPTION

Bib2HTML::Parser::Parser is a Perl module, which parses
a source file to recognize the BibTeX tokens.

=head1 GETTING STARTED

=head2 Initialization

To create a parser, say something like this:

    use Bib2HTML::Parser::Parser;

    my $parser = Bib2HTML::Parser::Parser-&gt;new() ;

...or something similar.
The constructor could take 1 arg:

=over

=item * show_bibtex (boolean)

indicates if the BibTeX code will be generated inside
a verbatim area. This flag permits to this parser
to store (or not) the initial value of each field.
Caution about the memory space.

=head1 METHOD DESCRIPTIONS

This section contains only the methods in Parser.pm itself.

=over

=cut

package Bib2HTML::Parser::Parser;

@ISA = ('Exporter');
@EXPORT = qw();
@EXPORT_OK = qw();

use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
use Exporter;
use Carp ;
use File::Basename ;
use File::Spec ;

use Bib2HTML::General::Misc ;
use Bib2HTML::General::Error ;
use Bib2HTML::General::Verbose ;

use Bib2HTML::Parser::BibScanner ;

use Bib2HTML::Translator::TeX ;
use Bib2HTML::Translator::BibTeXEntry ;

#------------------------------------------------------
#
# Global vars
#
#------------------------------------------------------

# Version number of the parser
my $VERSION = "2.1" ;

#------------------------------------------------------
#
# Constructor
#
#------------------------------------------------------

sub new(;$) : method {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $parent = ref($proto) &amp;&amp; $proto ;

  my $self ;
  if ( $parent ) {
    %{$self} = %{$parent} ;
    bless( $self, $class );
  }
  else {
    $self = { 'CONTENT' =&gt; {},
	      'FILE_PREAMBLES' =&gt; '',
	      'SHOW_BIBTEX' =&gt; $_[0],
	    } ;
    bless( $self, $class );
    $self-&gt;clearcontent() ;
  }
  return $self;
}

#------------------------------------------------------
#
# Getter/setter functions
#
#------------------------------------------------------

=pod

=item * content()

Replies the content of the documentation
read by the parser.

=cut
sub content() : method {
  my $self = shift ;
  return $self-&gt;{'CONTENT'} ;
}

=pod

=item * clearcontent()

Destoys the readed content and sets it
to the empty.

=cut
sub clearcontent() : method {
  my $self = shift ;
  $self-&gt;{'CONTENT'} = { } ;
}

#------------------------------------------------------
#
# Main parsing functions
#
#------------------------------------------------------

=pod

=item * parse()

Parses the files.
Takes 1 arg:

=over

=item * file_list (array ref)

is an array that contains the names of the files and the
directories from which the parser must read the bibtex entries.

=back

=cut
sub parse(\@) : method {
  my $self = shift ;
  $self-&gt;clearcontent() ;
  # Evaluate the TeX expressions
  if ( ( $self-&gt;{'FILE_PREAMBLES'} ) &amp;&amp;
       ( exists( $self-&gt;{'FILE_PREAMBLES'}{'tex'} ) ) &amp;&amp;
       ( $self-&gt;{'FILE_PREAMBLES'}{'tex'} ) ) {
    Bib2HTML::General::Verbose::two( "Evaluate the user's LaTeX definitions...\n" ) ;
    my $trans = Bib2HTML::Translator::TeX-&gt;new( $self-&gt;{'FILE_PREAMBLES'}{'filename'} ) ;
    $trans-&gt;translate( $self-&gt;{'FILE_PREAMBLES'}{'tex'},
		       $self-&gt;{'CONTENT'}{'entries'} ) ;
  }
  # Evaluate each file
  if ( isarray( $_[0] ) ) {
    foreach my $file (@{$_[0]}) {
      $self-&gt;readfile( $file ) ;
    }
  }
  else {
      die("END1");
    $self-&gt;readfile( $_[0] ) ;
  }
  # Save the TeX entries
  if ( $self-&gt;{'SHOW_BIBTEX'} ) {
    $self-&gt;save_bibtex_entries() ;
  }
  # Evalute TeX expressions
  $self-&gt;tex_translation() ;
  # Expand the crossref fields
  $self-&gt;expand_crossref() ;

  return $self-&gt;content() ;
}

=pod

=item * readfile()

Reads the content of a file.
Takes 1 arg:

=over

=item * name (string)

is the name of the file to read.

=back

=cut
sub readfile($) : method {
  my $self = shift ;
  my $filename = $_[0] || confess( 'you must supply the filename' ) ;

  # Read the file content
  Bib2HTML::General::Verbose::two( "Read $filename..." ) ;
  my $scanner = new Bib2HTML::Parser::BibScanner() ;
  if ($self-&gt;{'CONTENT'}) {
      my $content = $scanner-&gt;scanentries($filename) ;
      # Merge the constants
      if ($content-&gt;{'constants'}) {
	  foreach my $constant (keys %{$content-&gt;{'constants'}}) {
	      if (exists $self-&gt;{'CONTENT'}{'constants'}{"$constant"}) {
		  Bib2HTML::General::Error::warm( "multiple definition for the constant '".
						  $constant."'",
						  $filename,
						  extract_line_from_location($content-&gt;{'constants'}{"$constant"}{'location'})) ;
		}
	      $self-&gt;{'CONTENT'}{'constants'}{"$constant"} = $content-&gt;{'constants'}{"$constant"} ;
	  }
      }
      # Merge the preambles
      if ($content-&gt;{'preambles'}) {
	  push @{$self-&gt;{'CONTENT'}{'preambles'}}, @{$content-&gt;{'preambles'}} ;
      }
      # Merge the comments
      if ($content-&gt;{'comments'}) {
	  push @{$self-&gt;{'CONTENT'}{'comments'}}, @{$content-&gt;{'comments'}} ;
      }
      # Merge the red content to the previous content
      if ($content-&gt;{'entries'}) {
	  foreach my $entry (keys %{$content-&gt;{'entries'}}) {
	      if (exists $self-&gt;{'CONTENT'}{'entries'}{"$entry"}) {
		  Bib2HTML::General::Error::warm( "multiple definition for the entry '".
						  $entry."'",
						  $filename,
						  extract_line_from_location($content-&gt;{'entriess'}{"$entry"}{'location'})) ;
		}
	  $self-&gt;{'CONTENT'}{'entries'}{"$entry"} = $content-&gt;{'entries'}{"$entry"} ;
	  }
      }
  }
  else {
      $self-&gt;{'CONTENT'} = $scanner-&gt;scanentries($filename) ;
  }
}

=pod

=item * read_preambles()

Read some LaTeX commands from a file.
There commands are defined previously
any command from the BibTeX files.
Takes 1 arg:

=over

=item * file (string)

=back

=cut
sub read_preambles($) : method {
  my $self = shift ;
  $self-&gt;{'FILE_PREAMBLES'} = '' ;
  if ( $_[0] ) {
    Bib2HTML::General::Verbose::two( "Reading the user's LaTeX definitions...\n" ) ;
    if ( ( -f $_[0] ) &amp;&amp;
	 ( -r $_[0] ) ) {
      my $tex = '' ;
      local *FILE_PREAMBLE ;
      open( *FILE_PREAMBLE, "&lt; $_[0]" )
	or Bib2HTML::General::Error::syserr( "$_[0]: $!" ) ;
      while ( my $line = &lt;FILE_PREAMBLE&gt; ) {
	$tex .= $line ;
      }
      close( *FILE_PREAMBLE ) ;
      $tex =~ s/^[ \t\n\r]+// ;
      $tex =~ s/[ \t\n\r]+$// ;
      if ( $tex ) {
	$self-&gt;{'FILE_PREAMBLES'} = {} ;
	$self-&gt;{'FILE_PREAMBLES'}{'tex'} = $tex ;
	$self-&gt;{'FILE_PREAMBLES'}{'filename'} = $_[0] ;
      }
    }
    else {
      Bib2HTML::General::Error::syserr( "unable to find or read the preamble file '$_[0]'" ) ;
    }
  }
}

=pod

=item * expand_crossref()

Expands crossref fields.

=cut
sub expand_crossref() : method {
  my $self = shift ;

  Bib2HTML::General::Verbose::two( "Expand crossref fields...\n" ) ;

  foreach my $entry (keys %{$self-&gt;{'CONTENT'}{'entries'}}) {

    if ( exists $self-&gt;{'CONTENT'}{'entries'}{"$entry"}{'fields'}{'crossref'} ) {

      my $parent = $self-&gt;{'CONTENT'}{'entries'}{"$entry"}{'fields'}{'crossref'} ;
      if ( exists $self-&gt;{'CONTENT'}{'entries'}{"$parent"} ) {

	foreach my $field (keys %{$self-&gt;{'CONTENT'}{'entries'}{"$parent"}{'fields'}}) {
	  if ( ! exists $self-&gt;{'CONTENT'}{'entries'}{"$entry"}{'fields'}{"$field"} ) {
	    $self-&gt;{'CONTENT'}{'entries'}{"$entry"}{'fields'}{"$field"} =
	      $self-&gt;{'CONTENT'}{'entries'}{"$parent"}{'fields'}{"$field"} ;
	  }
	}

      }
      else {
	my $filename = extract_file_from_location( $self-&gt;{'CONTENT'}{'entries'}{"$entry"}{'location'} ) ;
	my $lineno = extract_line_from_location( $self-&gt;{'CONTENT'}{'entries'}{"$entry"}{'location'} ) ;
	Bib2HTML::General::Error::warm( "unable to find the entry '$parent' required for ".
					"the crossref from '$entry'",
					$filename, $lineno ) ;
      }

    }
  }

}

=pod

=item * tex_translation()

Translates TeX expressions

=cut
sub tex_translation() : method {
  my $self = shift ;

  # Evaluate @preamble
  Bib2HTML::General::Verbose::two( "Evaluate TeX expressions for the preambles...\n" ) ;

  foreach my $preamble (@{$self-&gt;{'CONTENT'}{'preambles'}}) {
    if ( $preamble-&gt;{'tex'} ) {
      my $trans = Bib2HTML::Translator::TeX-&gt;new( extract_file_from_location( $preamble-&gt;{'location'} ) ) ;
      $trans-&gt;translate( $preamble-&gt;{'tex'},
			 $self-&gt;{'CONTENT'}{'entries'},
			 extract_line_from_location( $preamble-&gt;{'location'} ) ) ;
    }
  }

  # Evaluate @string
  Bib2HTML::General::Verbose::two( "Evaluate TeX expressions for the constants...\n" ) ;
  my $be = new Bib2HTML::Translator::BibTeXEntry() ;
  foreach my $const (keys %{$self-&gt;{'CONTENT'}{'constants'}}) {
    $self-&gt;{'CONTENT'}{'constants'}{$const}{'text'} = $be-&gt;expand_bibtex_vars($self-&gt;{'CONTENT'}{'constants'}{$const}{'text'},
									      $self-&gt;{'CONTENT'}{'constants'}) ;
  }

  # Evaluate @preamble
  Bib2HTML::General::Verbose::two( "Evaluate TeX expressions for the preambles...\n" ) ;

  # Evaluate entries' fields
  foreach my $entry (keys %{$self-&gt;{'CONTENT'}{'entries'}}) {

    Bib2HTML::General::Verbose::two( "Evaluate TeX expressions for '$entry'...\n" ) ;
    my $filename = extract_file_from_location( $self-&gt;{'CONTENT'}{'entries'}{$entry}{'location'} ) ;
    my $lineno = extract_line_from_location( $self-&gt;{'CONTENT'}{'entries'}{$entry}{'location'} ) ;
    my $trans = Bib2HTML::Translator::TeX-&gt;new( $filename ) ;

    foreach my $field (keys %{$self-&gt;{'CONTENT'}{'entries'}{$entry}{'fields'}}) {

      if ( ! bibtex_ignore_field_parsing( $field ) ) {

	# Translate the TeX code of this field into HTML source code
	Bib2HTML::General::Verbose::three( "\ttreat field '$field'" ) ;

	my $text = $be-&gt;expand_bibtex_vars($self-&gt;{'CONTENT'}{'entries'}{$entry}{'fields'}{$field},
					   $self-&gt;{'CONTENT'}{'constants'} ) ;

	$self-&gt;{'CONTENT'}{'entries'}{$entry}{'fields'}{$field} = $trans-&gt;translate( $text,
										     $self-&gt;{'CONTENT'}{'entries'},
										     $lineno ) ;

      }
      else {
	
	# Do not translate the TeX code of this field into HTML source code
	# Simply remove the
	if ( $self-&gt;{'CONTENT'}{'entries'}{$entry}{'fields'}{$field} =~ /^{(.*)}$/) {
	  $self-&gt;{'CONTENT'}{'entries'}{$entry}{'fields'}{$field} = "$1" ;
	}

      }
    }

  }

}

=pod

=item * save_bibtex_entries()

Saves the original text for the BibTeX entries

=cut
sub save_bibtex_entries() : method {
  my $self = shift ;

  Bib2HTML::General::Verbose::two( "Save the BibTeX original values for futher verbatim...\n" ) ;

  # Evaluate entries' fields
  foreach my $entry (keys %{$self-&gt;{'CONTENT'}{'entries'}}) {

    foreach my $field (keys %{$self-&gt;{'CONTENT'}{'entries'}{$entry}{'fields'}}) {

      $self-&gt;{'CONTENT'}{'entries'}{$entry}{'original-fields'}{$field} =
	$self-&gt;{'CONTENT'}{'entries'}{$entry}{'fields'}{$field} ;

    }

  }
}

1;
__END__

=back

=head1 COPYRIGHT

(c) Copyright 1998-09 Stéphane Galland &lt;galland@arakhne.org&gt;, under GPL.

=head1 AUTHORS

=over

=item *

Conceived and initially developed by Stéphane Galland E&lt;lt&gt;galland@arakhne.orgE&lt;gt&gt;.

=back

=head1 SEE ALSO

bib2html.pl
</pre></body></html>