package Exporter;

# Извращенческий Exporter для виндового модперла

require 5.004;

# Using strict or vars almost doubles our load time.  Turn them back
# on when debugging.
#use strict 'vars';  # we're going to be doing a lot of sym refs
#use vars qw($VERSION @EXPORT);

$VERSION = 0.02;
@EXPORT = qw(import);   # we'll know pretty fast if it doesn't work :)
$ExportLevel = 0;

sub export_tags {
    my($exporter, @tags)  = @_;
    my %t = %{$exporter.'::EXPORT_TAGS'};
    for (@tags)
    {
        push @{$exporter.'::EXPORT'}, @{$t{$_}};
    }
}

sub export_ok_tags {
    my($exporter, @tags)  = @_;
    my %t = %{$exporter.'::EXPORT_TAGS'};
    for (@tags)
    {
        push @{$exporter.'::EXPORT_OK'}, @{$t{$_}};
    }
}

sub export_to_level {
    my($exporter, $level, $package, @imports)  = @_;
    my($caller, $file, $line) = caller($level);

    unless( @imports ) {        # Default import.
        @imports = @{$exporter.'::EXPORT'};
    }
    else {
        # Because @EXPORT_OK = () would indicate that nothing is
        # to be exported, we cannot simply check the length of @EXPORT_OK.
        # We must to oddness to see if the variable exists at all as
        # well as avoid autovivification.
        # XXX idea stolen from base.pm, this might be all unnecessary
        my $eokglob;
        if( $eokglob = ${$exporter.'::'}{EXPORT_OK} and *$eokglob{ARRAY} ) {
            if( @{$exporter.'::EXPORT_OK'} ) {
                # This can also be cached.
                my %ok = map { s/^&//; $_ => 1 } @{$exporter.'::EXPORT_OK'},
                                                 @{$exporter.'::EXPORT'};

                my($denied) = grep {s/^&//; !/(^\d*(\.\d+)*$|^:|^!)/ && !$ok{$_}} @imports;
                _not_exported($denied, $exporter, $file, $line) if $denied;
            }
            else {      # We don't export anything.
                _not_exported($imports[0], $exporter, $file, $line);
            }
        }
    }

    export($caller, $exporter, @imports);
}

sub import {
    my($exporter, @imports)  = @_;
    my($caller, $file, $line) = caller($ExportLevel);

    unless( @imports ) {        # Default import.
        @imports = @{$exporter.'::EXPORT'};
    }
    else {
        # Because @EXPORT_OK = () would indicate that nothing is
        # to be exported, we cannot simply check the length of @EXPORT_OK.
        # We must to oddness to see if the variable exists at all as
        # well as avoid autovivification.
        # XXX idea stolen from base.pm, this might be all unnecessary
        my $eokglob;
        if( $eokglob = ${$exporter.'::'}{EXPORT_OK} and *$eokglob{ARRAY} ) {
            if( @{$exporter.'::EXPORT_OK'} ) {
                # This can also be cached.
                my %ok = map { s/^&//; $_ => 1 } @{$exporter.'::EXPORT_OK'},
                                                 @{$exporter.'::EXPORT'};

                my($denied) = grep {s/^&//; !/(^\d*(\.\d+)*$|^:|^!)/ && !$ok{$_}} @imports;
                _not_exported($denied, $exporter, $file, $line) if $denied;
            }
            else {      # We don't export anything.
                _not_exported($imports[0], $exporter, $file, $line);
            }
        }
    }

    export($caller, $exporter, @imports);
}



sub export {
    my($caller, $exporter, @imp) = @_;

    my %t = %{$exporter.'::EXPORT_TAGS'};
    my @imports;
    for(@imp)
    {
	if (substr($_,0,1) eq ':')
	{
            push @imports, @{$t{substr($_,1)}};
        }
	elsif (substr($_,0,1) eq '!')
	{
            my $n = substr($_,1);
	    @imports = grep { $_ ne $n } @imports;
	}
        else
	{
	    push @imports, $_;
	}
    }

    # Stole this from Exporter::Heavy.  I'm sure it can be written better
    # but I'm lazy at the moment.
    foreach my $sym (@imports) {
        # shortcut for the common case of no type character
        (*{$caller.'::'.$sym} = \&{$exporter.'::'.$sym}, next)
            unless $sym =~ s/^(\W)//;

        my $type = $1;
        my $caller_sym = $caller.'::'.$sym;
        my $export_sym = $exporter.'::'.$sym;
        *{$caller_sym} =
            $type eq '&' ? \&{$export_sym} :
            $type eq '$' ? \${$export_sym} :
            $type eq '@' ? \@{$export_sym} :
            $type eq '%' ? \%{$export_sym} :
            $type eq '*' ?  *{$export_sym} :
            do { require Carp; Carp::croak("Can't export symbol: $type$sym") };
    }
}


#"#
sub _not_exported {
    my($thing, $exporter, $file, $line) = @_;
    die sprintf qq|"%s" is not exported by the %s module at %s line %d\n|,
        $thing, $exporter, $file, $line;
}

1;
__END__
