File-ValueFile

 view release on metacpan or  search on metacpan

lib/File/ValueFile/Simple/Reader.pm  view on Meta::CPAN


sub _handle_special {
    my ($self, $type, $marker, @args) = @_;
    my $line = $self->{fh}->input_line_number;

    if ($marker eq 'ValueFile') {
        @args = @args[0,1] if scalar(@args) == 4 && !defined($args[-1]) && !defined($args[-2]);
        croak 'ValueFile (magic) marker at wrong line' unless $line == 1;
        croak 'ValueFile (magic) marker not marked required' unless $type eq '!';
        croak 'ValueFile (magic) marker with wrong number of arguments' unless scalar(@args) && scalar(@args) <= 2;
        croak 'ValueFile (magic) marker not using supported format' unless $args[0] eq FORMAT_ISE;

        if (scalar(@args) > 1) {
            $self->_check_supported(supported_formats => $self->{format} = Data::Identifier->new(ise => $args[1]));
        }

        $self->_check_utf8($marker => $self->{format}) if $self->{utf8} eq 'auto';

        return;
    } elsif ($marker eq 'Feature') {
        my $id;

        croak 'Feature marker with wrong number of arguments' unless scalar(@args) == 1;

        push(@{$self->{features} //= []}, $id = Data::Identifier->new(ise => $args[0]));

        $self->_check_supported(supported_features => $id) if $type eq '!';
        $self->_check_utf8($marker => $id) if $self->{utf8} eq 'auto';
        $self->{dot_repreat} ||= $id->eq(DOT_REPEAT_ISE);

        return;
    }

    croak 'Invalid marker: '.$marker;
}

sub _check_utf8 {
    my ($self, $marker, $id) = @_;
    if (File::ValueFile->_is_utf8($id)) {
        $self->{unescape} = \&_unescape_utf8;
        $self->{utf8} = 1;
    }
}


sub read_to_cb {
    my ($self, $cb) = @_;
    my $fh = $self->{fh};
    my $unescape = $self->{unescape};
    my @last_line;

    $fh->seek(0, SEEK_SET);
    $fh->input_line_number(0);

    delete $self->{format};
    delete $self->{features};

    while (my $line = <$fh>) {
        $line =~ s/\r?\n$//;
        $line =~ s/#.*$//;
        $line =~ s/^\xEF\xBB\xBF//; # skip BOMs.
        $line =~ s/\s+/ /g;
        $line =~ s/ $//;
        $line =~ s/^ //;

        next unless length $line;

        if ($line =~ s/^\!([\!\?\&])//) {
            my $type = $1;

            if ($self->{dot_repreat}) {
                my @line = split(/\s+/, $line);
                my $x = 0;
                foreach my $e (@line) {
                    if ($e eq '.') {
                        $e = $last_line[$x];
                    } elsif ($e =~ s/^\.\.+$//) {
                        # done in match
                    } elsif ($e =~ KEYWORD_OK) {
                        # no-op
                    } elsif ($e =~ /^\!/) {
                        $e = _special($_);
                    } else {
                        $e = $unescape->($e);
                    }
                    $x++;
                }

                $self->_handle_special($type, @line);
                @last_line = @line;
            } else {
                $self->_handle_special($type, map{
                        $_ =~ KEYWORD_OK ? $_ :
                        $_ =~ /^\!/ ? _special($_) : $unescape->($_)
                    }(split(/\s+/, $line)));
            }

            # Reload:
            $unescape = $self->{unescape};

            next;
        }

        if ($self->{dot_repreat}) {
            my @line = split(/\s+/, $line);
            my $x = 0;
            foreach my $e (@line) {
                if ($e eq '.') {
                    $e = $last_line[$x];
                } elsif ($e =~ /^\.+$/) {
                    $e =~ s/^\.//;
                } elsif ($e =~ KEYWORD_OK) {
                    # no-op
                } elsif ($e =~ /^\!/) {
                    $e = _special($e);
                } else {
                    $e = $unescape->($e);
                }
                $x++;
            }



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