SIL-Shoe

 view release on metacpan or  search on metacpan

lib/SIL/Shoe/Control.pm  view on Meta::CPAN

package SIL::Shoe::Control;

=head1 NAME

SIL::Shoe::Control - Abstract superclass for SF Control files in Shoebox

=head1 DETAILS

This class parses a control file based on a parsing model passed by the
subclass. It handles groups and all the vagueries currently encountered in
Shoebox control files.

The following methods are available:

=cut

use strict;
use Carp;
use Symbol;

=head2 SIL::Shoe::Control->new("filename")

This creates a new type object, but only reads the name of the database type.
This allows SIL::Shoe::Settings to read all the type files without filling up
memory. The settings file is only fully read when $s->read is called.

=cut

sub new
{
    my ($class, $file) = @_;
    my ($self, $fh);

    $fh = Symbol->gensym();
    if (not open ($fh, "$file")) {
        croak("Unable to open $file");
        return undef;
    }

    $self->{' INFILE'} = $fh;
    $self->{' fname'} = $file;
    open($fh, "$file") and ($_ = <$fh>);
    s/^\xEF\xBB\xBF//o;        # BOM in UTF8
    chomp;
    if (m/^\\\+(\S+)\s+(.*?)\s*$/o)
    { $self->{'name'} = $2; }
    else
    { croak("Malformed database type file ($file)"); }
    close ($fh);
    bless $self, $class;
}

=head2 $s->read

This reads the type file into memory and readjusts everything to make stuff
easier to find.

=cut

sub read
{
    my ($self) = @_;

    return $self if $self->{' read'};
    
    open ($self->{' INFILE'}, $self->{' fname'})
        || &croak("Unable to re-open $self->{' fname'}");

    $self->parse($self->{' INFILE'});
    close ($self->{' INFILE'});
    $self->{' read'} = 1;
    return $self;
}

sub parse
{
    my ($self, $fh) = @_;
    my ($target, $name, $val, $curr_mark, $info, $new, $inlines, $multiline);
    my ($temp);

    $target = $self;
    while (<$fh>)
    {
#        chomp;
        s/\s+$//o;
        s/^\xEF\xBB\xBF//o;
        next unless $_ ne "";
        if (m/^\\\-(.*?)\s*$/oi)
        {
            $inlines = 0;
            if ($1 ne pop(@{$self->{' hiern'}}))      # ') for editor
            { &croak("Synchronisation error in $self->{' fname'} at $_"); }
            else
            {
                $target = pop(@{$self->{' hier'}});
                return $self if $#{$self->{' hier'}} < 0;
            }
        }           # ( /* for editor
        elsif (m/^\\\+(\S+)\s*(.*?)\s*$/oi)
        {
            $name = $1;
            $val = $2;
            $info = $self->group($name);



( run in 1.206 second using v1.01-cache-2.11-cpan-39bf76dae61 )